How to update Data From Server to Client without firing too much remote function

Hello, I was told that firing too much remote function can be bad for the game performance, so as much as possible im trying to avoid scripts that repeatedly calls a remote functions/events a lot

–MAIN PROBLEM–
Im pretty new to OOP and im experimenting around it by creating inventory system, so i have players as my objects, when a player joins it creates new object assign to that player id, and the player object have data such as inventory data, now i have a function to player object that gives items to self and its pretty self explanatory

--This is a module script, OOP
function PlayerObject:GiveItems(loot)
	if not self.data then
		warn("Player Have no Data, This shouldn't be printed") -- just being paranoid lol
	end
	
	local inv = self.data['Inventory']
	for id,quantity in ipairs(loot) do
		if inv[id] then
			inv[id] += quantity
		else
			inv[id] = quantity
		end
	end
	
	--TEMPORARY, Update player inventory update every time it gains an item
	Rfiles['functions'].UpdateClient:InvokeClient(Players:GetPlayerByUserId(self.plr_id))
end

Now you can see why this is bad, there might be 10 players in the game and each are constantly updating their inventory when they grind mobs, which might cause lag

–SOLUTIONS I TRIED–
Well i could FIRE the remotefunctions from CLIENT to SERVER , which where the client will fire the remotefunctions and in the server, it gets the player inventory data and returns it to the client.

but it might still fires a lot, not to mention the :GiveItems() command is on server side , the client has no way of detecting if new item is added to the player inventory data , because only updating the player inventory WHEN new item is added seems more resourceful than checking every second.

–MAIN QUESTIONS–

Is there an alternative options to solve this?
How can i make this reduce potential lag?

Thank you for your time.

Hey Gabrielle,

Starting right off, good question! Fast lanes of updating your client-side state to keep the performance of your game in check could really be delicate; say, when working with an inventory system specifically, because of the frequency of updates. Below are several ways to reduce the potential lag caused by frequent remote calls.

Update Rate Limiting

One could do this instead: update with debounce—gather changes over a short period and then fire them in one batch. This will only result in a very small number of remote function calls.

-- Add debounce time
local debounceTime = 0.5
local pendingUpdates = {}

function PlayerObject:GiveItems(loot)
    if not self.data then GOES HERE
     endif
warn "Player Have no Data, This shouldn't be printed" -- just being paranoid lol
    end

    local inv = self.data['Inventory']
    for id, quantity in pairs(loot) do
        if inv[id] then
            inv[id] += quantity
else
            inv[id] = quantity
        end
    end

    -- Add to pending updates
    if not pendingUpdates[self.plr_id] then
        pendingUpdates[self.plr_id] = {}
    end
    table.insert(pendingUpdates[self.plr_id], loot)

-- Debounce the update
    if not self.updateScheduled then
        self.updateScheduled = true
        task.delay(debounceTime, function()
            -- Send the update to the client
            Rfiles['functions'].UpdateClient:InvokeClient(Players:GetPlayerByUserId(self.plr_id), pendingUpdates[self.plr_id])
```lua
-- Clear finished updates
            pendingUpdates[self.plr_id] = nil
            self.updateScheduled = false
        end
    )
end

Using Remote Events Instead of Remote Functions

In general, remote events are more efficient than remote functions for frequently occurring updates. Remote functions will wait for a response to the server, while remote events just fire and forget.

-- Use RemoteEvent instead of RemoteFunction
Rfiles['events'].UpdateClient:FireClient(Players:GetPlayerByUserId(self.plr_id), pendingUpdates[self.plr_id])

Streaming Inventory Data

If you have large inventory data, you might want to stream it in smaller portions rather than sending it as one huge bulk. This is significantly more complicated but can vastly improve performance.

-- Stream inventory data in chunks
function PlayerObject:StreamInventoryToClient()

local inv = self.data['Inventory']
    local chunkSize = 10
    local chunks = {}
    for id, quantity in pairs(inv) do
        table.insert(chunks, {id = id, quantity = quantity})
        if #chunks >= chunkSize then
Rfiles['events'].UpdateClient:FireClient(Players:GetPlayerByUserId(self.plr_id), chunks)
            chunks = {}
        end
    end
    if #chunks > 0 then
        Rfiles['events'].UpdateClient:FireClient(Players:GetPlayerByUserId(self.plr_id), chunks)
    end
end

Updating Only Changed Items

Only sends what changes, instead of the whole inventory. This saves a lot of bandwidth.

function PlayerObject:GiveItems(loot)
    if not self.data then
        warn("Player Have no Data, This shouldn't be printed") -- just being paranoid lol
    end

    local inv = self.data['Inventory']
    local changes = {}
for id, quantity in pairs(loot) do
        if inv[id] then
            inv[id] += quantity
        else
            inv[id] = quantity
        end
changes[id] = inv[id]
    end

    -- Add to pending updates
    if not pendingUpdates[self.plr_id] then
        pendingUpdates[self.plr_id] = {}
    end
    table.insert(pendingUpdates[self.plr_id], changes)

    -- Debounce the update
    if not self.updateScheduled then
self.updateScheduled = true
        task.delay(debounceTime, function()
            -- Send the update to the client
            Rfiles['events'].UpdateClient:FireClient(Players:GetPlayerByUserId(self.plr_id), pendingUpdates[self.plr_id])
            -- Clear pending updates
pendingUpdates[self.plr_id] = nil
            self.updateScheduled = false
        end)
    end
end

Summary

  • Debounce Updates: Collect updates within an ultra-short time and fire them in one batch.
  • Use Remote Events: In scenarios with high frequency of updates, prefer using Remote Events.
  • Streaming Data: In case of big inventory, send it in parts.
  • Only Send Changes: Send only changes instead of sending the whole stock.

These methods should help reduce further remote calls and improve your inventory system performance. Good luck with your OOP experiments and your game development!

Cheers,
Patch
(Edited because code blocks are weird.)

1 Like

Thank you so much for your time and for the solution!!

the concept of 1st and 4th one is incredibly useful and easy to understand, though I’m having hard time grasping the idea of the 3rd one, I think the 4th one is enough to solve my problems.

again, thanks so much!

1 Like

You’re welcome! If you need more help let me know!

1 Like