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?
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.
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;
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:
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.
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.).
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.
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!