Making module replicate from server to client

Im currently working on a module that should contain values that both the server and client has access to (except only the server can change the values), and these values are stored via a module.

The problem is that modules values dont replicate from server to client.
A work around might be using attributes, the only problem with that is the lack of values you can save via attributes, such as and not limited too, instances, tables, etc…

Sending a remote event every time a player wants to see a value seems like it could be bad for performance, so are there any options? What can I do?

1 Like

if you want the client to see a value that’s on the server you will have to send it over one way or another. Setting an attribute and having roblox replicate it automatically would be almost the same as sending it through a remote event manually.

If the clients need to access the information a lot and it doesn’t change that frequently have the server send over every change it makes to the table in the module to every client.

3 Likes

You could use:

p2.OnClientEvent:Connect(function(eventType, isSuccessful, data, requestedData, updateData)
	if eventType == "PlayerData" and isSuccessful == true then
		PLAYER_DATA_READY = true;
		PLAYER_DATA = data;
	elseif eventType == "SessionData" and isSuccessful == true then
		SESSION_DATA_READY = true;
		SESSION_DATA = data;
	elseif eventType == "PlayerProfile" and isSuccessful == true then
		PLAYER_PROFILE_READY = true;
		PLAYER_PROFILE = data;
	elseif eventType == "PlayerDataRequest" then
		if type(PLAYER_DATA) ~= nil then
			if require(script.Parent.CommonFunctions).DeepEqual(PLAYER_DATA, requestedData) then
				 
			else
				PLAYER_DATA = requestedData;
				PlayerDataUpdated:Fire(PLAYER_DATA);
			end;
		else
			warn("PLAYERDATA /// NOT READY YET");
			return;
		end;
	elseif eventType == "SessionDataRequest" then
		if type(SESSION_DATA) ~= nil then
			if require(script.Parent.CommonFunctions).DeepEqual(SESSION_DATA, requestedData) then

			else
				SESSION_DATA = requestedData;
				SessionDataUpdated:Fire(SESSION_DATA);
			end;
		else
			warn("SESSIONDATA /// NOT READY YET");
		end
	elseif eventType == "PlayerProfileRequest" then
		if type(PLAYER_PROFILE) ~= nil then
			if require(script.Parent.CommonFunctions).DeepEqual(PLAYER_PROFILE, requestedData) then
				
			else
				PLAYER_PROFILE = requestedData;
				PlayerProfileUpdated:Fire(PLAYER_PROFILE);
			end;
		else
			warn("PLAYERPROFILE /// NOT READY YET");
		end;
	elseif eventType == "CustomDataRequest" then
		if type(CUSTOM_DATA) ~= nil then
			if require(script.Parent.CommonFunctions).DeepEqual(CUSTOM_DATA, requestedData) then
				
			else
				CUSTOM_DATA = requestedData;
				CustomDataUpdated:Fire(CUSTOM_DATA)
			end;
		else
			warn("CUSTOMDATA /// NOT READY YET");
		end;
	end;
end);

as an example.

DeepEqual function:

function DeepEqual(table1, table2)
	if type(table1) ~= "table" then
		if type(table2) ~= "table" then
			return table1 == table2;
		else
			return false;
		end;
	end;
	if type(table2) ~= "table" then
		return false;
	end;
	local iterator1, key1, value1 = pairs(table1);
	local iterator2, key2, value2 = pairs(table2);
	while true do
		local currentKey1, currentValue1 = iterator1(key1, value1);
		local currentKey2, currentValue2 = iterator2(key2, value2);
		if currentKey1 then
			if currentKey2 then
				if type(currentValue1) == "table" then
					if type(currentValue2) == "table" then
						if not DeepEqual(currentValue1, currentValue2) then
							return false;
						end;
					else
						return false;
					end;
				elseif currentValue1 ~= currentValue2 then
					return false;
				end;
			else
				return false;
			end;
		else
			if currentKey2 then
				return false;
			end;
			break;
		end;
		value1 = currentKey1;
		value2 = currentKey2;
	end;
	return true;
end;

1 Like

May I ask how this works and what it actually does?

1 Like
  • First 3 if statements:
    • These handle the initialization of player, session, and profile data when the event is fired.
    • When the server sends this data (with eventType as "PlayerData", "SessionData", or "PlayerProfile"), if the request is successful (isSuccessful == true), the data is stored and marked as ready (READY variables).Example:
if eventType == "PlayerData" and isSuccessful == true then
    PLAYER_DATA_READY = true
    PLAYER_DATA = data

Handling Data Requests:

  • Last 4 if statements:
    • These handle cases where the client needs to update or request specific data from the server (e.g., player data, session data, etc.).
    • When the client sends a request (such as "PlayerDataRequest"), it checks if the requested data matches the current data using the DeepEqual function.
    • If the data is different, it updates the corresponding data and fires an update event to notify other parts of the client.Example:
elseif eventType == "PlayerDataRequest" then
    if type(PLAYER_DATA) ~= nil then
        if require(script.Parent.CommonFunctions).DeepEqual(PLAYER_DATA, requestedData) then
            -- No update needed
        else
            PLAYER_DATA = requestedData
            PlayerDataUpdated:Fire(PLAYER_DATA)
        end
    else
        warn("PLAYERDATA /// NOT READY YET")
        return
    end

DeepEqual Function:

  • The DeepEqual function is used to compare two tables (both types). It checks every key-value pair in the tables to ensure they are identical.
  • It avoids a shallow comparison (which only checks the references or top-level equality) by recursively comparing all nested elements within the tables.

Explanation of Flow:

  1. When the server sends data (e.g., PlayerData), the first set of checks ensures that the client has received the data and marks it as ready.
  2. When the server sends updated data, the script compares it to the current data using DeepEqual. If the data has changed, it updates the local data and triggers a corresponding event (PlayerDataUpdated, SessionDataUpdated, etc.).
  3. If the data hasn’t been received yet (e.g., PLAYER_DATA is nil), the script warns that the data isn’t ready.

Basically what it does:

This script manages different types of data (player data, session data, etc.), ensuring that the client updates its state only when the data changes. It does this by using DeepEqual to compare the existing data with the newly sent data and triggers updates accordingly.

(Apologies if this is hard to understand😅)

2 Likes

So I took inspiration from your ideas but made my own changes.

Such as any values that can be saved as attributes are saved as attributes that way we dont have to send remote events.

In the case it doesnt it does your DeepEqual function (which I remade and made it much simpler), in order to tell if it actually changed, if it did we notify the players.

Since your answer isnt exactly what I did I think I’ll mark this as the solution.
Thanks for your help though!

2 Likes

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