Attribute Syncing

Communicating between the client and the server is currently very difficult, especially when working with information that is crucial to gameplay such as replicating the aim directions of users, or sharing the current state of gameplay with all clients.
The current options (for client to server communication) are to either constantly send events to the server and responding to them individually, or to use systems like physics which are automatically replicated to the server anyway.

This topic proposes the addition of a system capable of syncing Attributes on objects from client to server. One of the ways this could be achieved would be to either create a separate Instance in charge of giving users “network ownership” over the attributes, or to allow any form of attribute to have an additional property that indicates if it can be manipulated client-side. Another approach would also be to manually grant attribute change permissions to players individually with a separate method.
From there, callbacks can also be introduced. If a callback is attached to an attribute, it can verify if the value (or the person it came from) is appropriate, and either update the value (editing / clamping it if necessary), or rejecting the edit by throwing an error or returning a special enum.

This takes a lot of effort away from developers by being able to sync information much easier to the server, without having to use RemoteEvents or create a system to network such information themselves, and any changes can be queued and sent alongside regular client information like physics.

An example of what this feature could look like:

-- server

--[[
Enum.AttributeSync.Fail for fail state, erroring to client and server
Enum.AttributeSync.Ignore to silently ignore this change
Enum.AttributeSync.Update to update the value on server
]]
-- called when the attribute is synced from client
player:SetSyncAttributeCallback(
    "AimVector", 
    -- if multiple owners can be set, add an extra parameter for the player who sent the change
    function(requested: Vector3)
        local d = requested.Magnitude
        -- check for suspicious values, NaN and large vectors
        if d ~= d or d > 1.5 then
            return Enum.AttributeSync.Fail, "invalid vector3 supplied"
        end
        -- output empty vector or unit vector
        return Enum.AttributeSync.Update, 
            if d == 0 then Vector3.zero else requested.Unit
    end
)

-- give partial ownership to the client to update this attribute
player:SetAttributeOwner("AimVector", player) -- maybe allow for multiple owners?


--client

-- update the aim vector locally
player:SetAttribute("AimVector", CURRENT_AIM)
-- request syncing of the attribute to server
player:SyncAttribute("AimVector") -- maybe add an Async version to check the response / error?

The other issues regarding the use of RemoteEvents to replicate data are:

  1. Spam

The current method of constantly sending data to the server whenever possible creates many situations where you are using more remote event invokes than necessary. This leads to the server also receiving unnecessary amounts of OnClientEvents that will queue up and require the same portion of code to execute over and over. For users with a poor connection to the server, or in the case of the server lagging, this will greatly multiply the severity of the issue.

  1. Unnecessary Bandwidth Usage

As well as sending / queuing more RemoteEvents, this also contributes to the total bandwidth of data sent by the client. In cases of extreme lag, this can result in abnormally large bandwidth when connection is re-established, as well as a lot of completely unnecessary data being transmitted to the server. It is also not possible to “Update” the content within a RemoteEvent. The data that is placed on invoke is the data that will be sent, so there is no way to just push the current value of the data as soon as possible, and to know when exactly to send this data.

  1. Consistency

RemoteEvents for data replication will usually come in one of three forms. Either the developer sends individual pieces of data into individual remote events, the developer creates a large structure to encompass all data that needs to be synced through a very few number of remote events, or the developer creates smaller chunks of structures to sync across only a couple of remote events. This is very inconsistent, and each application has major tradeoffs with efficiency, bandwidth, and complexity. Implementation of a system that is designed specifically for performing this task will improve all 3 aspects by introducing a fast, bandwidth efficient, and simple solution to the problem.

If possible, also, it would be useful to have an event for when the client has received information from the server (in order to sync attributes manually, or use remote events in a more efficient manner)

9 Likes

This would be a good shortcut for a lot of people yuh :pray:

1 Like

Good idea in theory, but it isn’t the best in practice. There’s one reason to that:

Replication.

Your attributes that will be synced to the server will also have to be replicated to clients. This may be one of the only use cases where disabling replication would be quite suitable, but there’d be other issues.

Then, there’s the fact that automatic replication is an order of magnitude less in priority than remote events. Physics are delayed by over 100ms during replication likely because of this.


To summarize, while this is a good idea in theory, it will use unnecessary bandwidth and is based on a bad coding practice: replicate everything even if unnecessary.

1 Like

Perhaps a similar system to remote events then where parameters can be sent over a channel, but instead of all changes being queued, they are dropped in favor of only the last update, as well as automatic updates applied whenever possible.

That would be similar to unreliable remote events, which already has its dedicated feature request: