I’m working on a inventory system and I want to send the client their inventory as soon as they join, and then update changes when removing or adding a item
this is an example on how I’d do it
-- Server
-- player joins
Event:FireClient(Player, Inventory)
-- localscript in player
Event.OnClientEvent:Connect(function(inventory)
-- will the client always recieve this event?
end)
will the client always recieve the event if its fired when they join, or would it be better for the client to request the inventory when they join?
You could use a RemoteFunction instead, where the server returns the inventory after the client requests it. This will make sure that the client gets the data when it is needed and when it can do something with it.
RemoteFunctions work but I wanted to shorten the code a bit, it seems so far with testing that the client always receives the event but it’s just slightly delayed so any code accessing the inventory locally right before the event is received will error
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
local inventory
RemoteEvent.OnClientEvent:Connect(function(inventory)
inventory = inventory
for i, v in pairs(inventory) do -- works
print(v)
end
end)
for i, v in pairs(inventory) do -- error
print(v)
end
but yeah I’ll use a RemoteFunction just in case, unless someone knows 100% that the event will always be received
That’s an issue that using a RemoteFunction will solve because it pauses the code until a response is received. Mitigating this issue without a RemoteFunction would be more complicated and long than just using a RemoteFunction (which I think is more robust). This behaviour does show us that it is likely scripts run before the player added event is called, but it is still best to use a RemoteFunction in this case to ensure you have the data.
Should of mentioned this before but yielding is not a issue with how I’m going to write the script
stuff will only happen whenever a inventory is updated
I was just worried if the event wouldn’t fire because I’d never get the data, but it seems that it will always fire so I don’t have to request the data then add to inventory and setup an additonal update inventory function
I could do it all with one event
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
local inventory = {}
function PrintInventory()
for i, v in pairs(inventory) do
print(i .. " " .. v)
end
end
function UpdateInventory(NewInventory)
for i, v in pairs(NewInventory) do
if not inventory[i] then
inventory[i] = v
end
end
PrintInventory()
end
RemoteEvent.OnClientEvent:Connect(UpdateInventory)
Oh right. When you said the code produces an error I thought you were relying on the inventory to be loaded for your code to work. But why is it set up like this? The client should know what the inventory is because all edits to it would be sent from the client to the server (except for initial loading) right?
It was just a basic example on how yielding wasn’t an issue, my actual script is not like that
and I’m not sure what you mean by the second part but the inventory should never be edited like that by the client as exploiters could just add their own items
but the general idea of what I’m going for is to be able to update stuff (gui inventory slots) on client only when something changes or is added/removed because looping through an entire inventory and checking if it exists or if it needs to be changed could cause performance issues especially if a player has a massive inventory
The idea is that the client requests a change and the server validates it, returning if it was a success (so the client inventory is consistent and the player is aware no changes were made). It would almost always be in exchange for something else e.g. points or finding something in game.
Events in playeradded are guaranteed to be received only by the first client listener, so if you have two scripts listening on that event and they don’t manage to both connect before receiving the event, then only the first one to load will receive it.
I tested the fact that it’s guaranteed by adding a task.wait(60*5) before the localscript listener and having the event be called on playeradded, it fired correctly, even after a 5 minutes delay
I tested the race condition by having two localscripts listening, one on a wait of 5 and the other on a wait of 10, only the wait 5 was correctly received.
Hopefully this clears out the large amount of misinformation around this topic