You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The component is now replicated. Great! However, if you have an entity that is replicated, but you don't want to replicate one of its components, you have no way of preventing that.
This is (as far as I'm aware) one of the reasons that Bevy components don't have Replicate implemented by Naia. If, in the current state of the system, you have a replicated entity with a Replicate-implementing component, and the entity is set to be replicated, it will be replicated whether you like it or not.
A solution
A potential solution is having typed marker components that tell Naia whether or not the component should be replicated.
Let's create a hypothetical struct, Foo. Foo stores some information that is useful to both the server, and the client, but only in some circumstances. Sometimes, the server may want to hide Foo from the client. In this case, the server will add a special marker component that indicates that Foo is not to be replicated.
Let's get out two of our hypothetical marker components, AllowReplication<T> and PreventReplication<T>
Both will have the generic type T, with the trait bound of Replicate, but won't store anything themselves.
If the server doesn't want to tell the client about Foo on a specific entity, it will add PreventReplication<Foo> as a component.
The fact PreventReplication has Foo as T will let the replication code know to no longer replicate the Foo component.
Let's create another hypothetical component, Bar. Bar should not be replicated in most circumstances, but it may need to be occasionally. In this case, when defining our protocol, we would say it is not replicated by default, even though it implements Replicate. Then, on entities where the server wants it to be replicated, it would add AllowReplication<Bar> as a component.
There should also be a third value for whether or not a component is replicated by default, which is "yes and ignore the prevent marker component". This could be useful if you have something very important that must be replicated and you don't want anything interfering with that. Naia should probably send some kind of log if a PreventReplication component exists on the entity for that type, too.
In cases where both marker components are present, it should probably go to the protocol default for the component being replicated, or another value passed when the protocol is being set up. Or it just panics, that works too.
Here's a table of all the outcomes, to make this clearer.
Neither component is present
AllowReplication is present
PreventReplication is present
Both are present
Replicated by default
Replicated
Replicated
Not replicated
Replicated
Not replicated by default
Not replicated
Replicated
Not replicated
Not replicated
Always replicated
Replicated
Replicated
Replicated
Replicated
Why like this
Using components is much more in line with ECS architecture and Bevy's design.
Replication status can be changed easily using Commands in any Bevy system.
Replicate can be implemented for Bevy components.
Somewhat fine control of whether or not components are replicated.
The developer remains in control of if things should be replicated.
In this new system for replication, if I wanted to have a component that was replicated by default, I could do the following.
Add a component with Replicate to the protocol, setting it to replicate by default.
Add the component to an entity.
Mark that entity to be replicated.
A component replicated by default but I want to block it:
Add component to protocol, set it to replicate by default.
Add the component to an entity along with PreventReplication
Mark that entity to be replicated.
And denied by default but allowed by the marker:
Add component to protocol, set it to not replicate by default.
Add that component to an entity and add AllowReplication
Mark that entity to be replicated.
Some extra thoughts
Should the other side of the transaction be alerted to if replication of a component stops/starts? Should it just be removed or should the other side handle it with a system? Should this be configurable in the protocol? (most likely)
Should components be part of scope instead of this system? Probably not, it's likely a better solution to add them as child entities that are scoped to the right people. That would also probably get confusing fast.
Will this make writing prediction code harder, being that two sides may be aware of different components on the same entity?
Another solution
Snen on discord mentioned having two entities, one exclusively on the server with all information, and one that's replicated over Naia and components can be removed and added freely. This is a potentially better solution, but it sounds potentially annoying to juggle two entities and their components instead of one.
The text was updated successfully, but these errors were encountered:
connorcarpenter
changed the title
Per-Component Replication
[suggestion] enable/disable replication on a per-component basis
Jan 13, 2024
The problem
The current state of replication is this:
Replicate
to the Protocol.The component is now replicated. Great! However, if you have an entity that is replicated, but you don't want to replicate one of its components, you have no way of preventing that.
This is (as far as I'm aware) one of the reasons that Bevy components don't have
Replicate
implemented by Naia. If, in the current state of the system, you have a replicated entity with aReplicate
-implementing component, and the entity is set to be replicated, it will be replicated whether you like it or not.A solution
A potential solution is having typed marker components that tell Naia whether or not the component should be replicated.
Let's create a hypothetical struct,
Foo
.Foo
stores some information that is useful to both the server, and the client, but only in some circumstances. Sometimes, the server may want to hideFoo
from the client. In this case, the server will add a special marker component that indicates thatFoo
is not to be replicated.Let's get out two of our hypothetical marker components,
AllowReplication<T>
andPreventReplication<T>
Both will have the generic type T, with the trait bound of
Replicate
, but won't store anything themselves.If the server doesn't want to tell the client about
Foo
on a specific entity, it will addPreventReplication<Foo>
as a component.The fact
PreventReplication
hasFoo
asT
will let the replication code know to no longer replicate theFoo
component.Let's create another hypothetical component,
Bar
.Bar
should not be replicated in most circumstances, but it may need to be occasionally. In this case, when defining our protocol, we would say it is not replicated by default, even though it implementsReplicate
. Then, on entities where the server wants it to be replicated, it would addAllowReplication<Bar>
as a component.There should also be a third value for whether or not a component is replicated by default, which is "yes and ignore the prevent marker component". This could be useful if you have something very important that must be replicated and you don't want anything interfering with that. Naia should probably send some kind of log if a
PreventReplication
component exists on the entity for that type, too.In cases where both marker components are present, it should probably go to the protocol default for the component being replicated, or another value passed when the protocol is being set up. Or it just panics, that works too.
Here's a table of all the outcomes, to make this clearer.
AllowReplication
is presentPreventReplication
is presentWhy like this
Commands
in any Bevy system.Replicate
can be implemented forBevy
components.Bundle
The ideal outcome
In this new system for replication, if I wanted to have a component that was replicated by default, I could do the following.
Replicate
to the protocol, setting it to replicate by default.A component replicated by default but I want to block it:
PreventReplication
And denied by default but allowed by the marker:
AllowReplication
Some extra thoughts
Should the other side of the transaction be alerted to if replication of a component stops/starts? Should it just be removed or should the other side handle it with a system? Should this be configurable in the protocol? (most likely)
Should components be part of scope instead of this system? Probably not, it's likely a better solution to add them as child entities that are scoped to the right people. That would also probably get confusing fast.
Will this make writing prediction code harder, being that two sides may be aware of different components on the same entity?
Another solution
Snen on discord mentioned having two entities, one exclusively on the server with all information, and one that's replicated over Naia and components can be removed and added freely. This is a potentially better solution, but it sounds potentially annoying to juggle two entities and their components instead of one.
The text was updated successfully, but these errors were encountered: