Help to replicate data from server to client

Hi there guys,
I’m currently creating a script to create a store for the player using OOP and it’s been very efficient, especially in the datastore part, but I found myself in a slightly controversial situation.

I’m not able to find a viable way to send data from the server to the client efficiently - by that I mean without using remote events because they would probably be called several times.

Server:

local StoreManager = require(game.ReplicatedStorage:WaitForChild("StoreManipulationSystem"):WaitForChild("Modules"):WaitForChild("StoreModule"))

local ItemManipulation = game.ReplicatedStorage:WaitForChild("StoreManipulationSystem"):WaitForChild("Functions"):WaitForChild("ItemManipulation")

local Players = game:GetService("Players")
local Stores = {}

Players.PlayerAdded:Connect(function(player)
	local store = StoreManager.new(player)
	Stores[player.UserId] = store
	
	print("print stores",Stores)
	
end)

Players.PlayerRemoving:Connect(function(player)
	if Stores[player.UserId] then
		Stores[player.UserId]:SaveData()
		Stores[player.UserId] = nil
	end
end)
-- (...)

Module stuff:

local StoreManager = {}
StoreManager.__index = StoreManager

local DataStoreService = game:GetService("DataStoreService")
local StoreData = DataStoreService:GetDataStore("PlayerStoreData")

function StoreManager.new(player)
	local self = setmetatable({}, StoreManager)

	self.Player = player
	self.StorageCapacity = 50
	self.Items = {}

	local success, data = pcall(function()
		return StoreData:GetAsync(player.UserId)
	end)

	if success and data then
		self.StorageCapacity = data.StorageCapacity or 50
		self.Items = data.Items or {}
	end

	return self
end

return StoreManager 

-- (...)

image

some things like the current storage capacity and the items I need to display in a bar that is obviously on the client, but I can’t access it any other way other than through remote events or functions, which ends up weighing down my game because these requests are made almost every time.
any ideas?

1 Like

This is a common dilemma, of which the common shortcuts are attaching Attributes or ValueObjects to the player object, and listening to property changes on the client. Very valid solution. Only minor change needed is to include the update to these values on your server code which is straightforward.

More elaborate solutions use networking libraries that allow you to cross communicate updates of state to the client, but underneath the hood these are just remote handshakes that feed this data.

Any of these options is fine, player data state changes aren’t frequent enough for you to be concerned about in regards to remotes and your network requests.

I think the best thing to do in this case would be to add the attributes, I think it’s a valid solution at least for now, thank you.

If you have slots, items and count of item, you can send SlotId, ItemId and Count, you can send Those 3, even if you want to optimize it further, you can send only ItemId and Count if you update the value, not change item

For further compression, you can turn those 8 bit numbers into strings, most of the time they wouldn’t pass 1000, so each string will have 4 bytes, which is 2x less than normal

Example:

--/ On client event
local DecompressedSlotId = tonumber(SlotId)
local DecompressedItemAmount = tonumber(ItemAmount)
local DecompressedItemId = tonumber(ItemId or 0)

if not DecompressedItemId then
    Slots[DecompressedSlotId].Amount = DecompressedAmount
else
    Slots[DecompressedSlotId].Item = DecompressedItemId
    Slots[DecompressedSlotId].Amount = DecompressedAmount
end

If you have something player related, you should store remotes in player’s object, for organization and security + you don’t need to direct functions for specific players, only retrieve needed data

Other remotes that aren’t used very often or are simply global, use them in replicated storage

Remember that instances or remotes, bandwidth will still exist here, there is no difference in programming langugae either

2 Likes