A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://docs.unity3d.com/Packages/com.unity.netcode@1.2/manual/ghost-snapshots.html below:

Ghost snapshots

A ghost is a networked object that the server simulates. During every frame, the server sends a snapshot of the current state of all ghosts to the client. The client presents them, but cannot directly control or affect them because the server owns them.

The ghost snapshot system synchronizes entities which exist on the server to all clients. To make it perform properly, the server processes per ECS chunk rather than per entity. On the receiving side the processing is done per entity. This is because it is not possible to process per chunk on both sides, and the server has more connections than clients.

Why use Ghosts? Ghosts vs. RPCs Ghost Snapshot Synchronization ("Eventual Consistency") Use-Cases RPC Use-Cases Key Differences:

Ghost can be authored in the editor by creating a Prefab with a GhostAuthoringComponent.

The GhostAuthoringComponent has a small editor which you can use to configure how Netcode synchronizes the Prefab.
You must set the Name, Importance, Supported Ghost Mode, Default Ghost Mode and Optimization Mode property on each ghost.
Netcode for Entities uses the Importance property to control which entities are sent when there is not enough bandwidth to send all. A higher value makes it more likely that the ghost will be sent.

You can select from three different Supported Ghost Mode types:

You can select from three different Default Ghost Mode types:

You can select from two different Optimization Mode types:

Replicating Components and Buffers

Netcode for Entities uses C# attributes to configure which components and fields are synchronized as part of a ghost. There are three fundamental attributes you can use:

NetCode Attribute Usage GhostFieldAttribute The GhostFieldAttribute should be used to mark which component (or buffer) fields should be serialised.
The attribute can be added to struct fields and properties.
Once a component has at least one field marked with [GhostField], it becomes replicated, and will be transmitted as part of the ghost data. GhostEnabledBitAttribute Similarly, the GhostEnabledBitAttribute should be used on an IEnableableComponent struct definition, to denote that the enabled bit for this component should be serialized.
Once a component is flagged with [GhostEnabledBit], its enabled-bit will be replicated, and thus transmitted as part of the ghost data. GhostComponentAttribute The GhostComponentAttribute should be used on a ComponentType struct definition to:
- Declare for which version of the Prefab the component should be present.
- Declare if the component should be serialised also for child entities.
- Declare to which subset of clients a component should be replicated. Authoring component serialization

To signal the Netcode for Entities that a component should be serialised, you need to add a [GhostField] attribute to the values you want to send.

public struct MySerialisedComponent : IComponentData
{
    [GhostField]public int MyIntField;
    [GhostField(Quantization=1000)]public float MyFloatField;
    [GhostField(Quantization=1000, Smoothing=SmoothingAction.Interpolate)]public float2 Position;
    public float2 NonSerialisedField;
    ...
}

For a component to support serialization, the following conditions must be met:

[!NOTE] Speaking of teleportation: To support short range teleportation, you'd need some other replicated bit to distinguish a teleport from a move (lerp).

Authoring dynamic buffer serialization

Dynamic buffers serialization is natively supported. Unlike components, to replicate a buffer, all public fields must be marked with at [GhostField] attribute.

[!NOTE] This restriction has been added to guarantee that: In the case where an element is added to the buffer, when it is replicated to the client, all fields on said element will have meaningful values. This restriction may be removed in the future (e.g. by instead, defaulting this undefined behaviour to default(T)).

public struct SerialisedBuffer : IBufferElementData
{
    [GhostField]public int Field0;
    [GhostField(Quantization=1000)]public float Field1;
    [GhostField(Quantization=1000)]public float2 Position;
    public float2 NonSerialisedField; // This is an explicit error!
    private float2 NonSerialisedField; // We allow this. Ensure you set this on the client, before reading from it.
    [GhostField(SendData=false)]public int NotSentAndUninitialised; // We allow this. Ensure you set this on the client, before reading from it.
    ...
}

Furthermore, in line with the IComponentData:

Dynamic buffers fields don't support SmoothingActions. Thus, the GhostFieldAttribute.Smoothing and GhostFieldAttribute.MaxSmoothingDistance properties will be ignored when used on buffers.

ICommandData and IInputComponentData serialization

ICommandData, being a subclass of IBufferElementData, can also be serialized from the server to clients. As such, the same rules for buffers apply: if the command buffer must be serialized, then all fields must be annotated.

    [GhostComponent()]
    public struct MyCommand : ICommandData
    {
        [GhostField] public NetworkTick Tick {get; set;}
        [GhostField] public int Value;
    }

The same applies when using automated input synchronization with IInputComponentData.

    public struct MyCommand : IInputComponentData
    {
        [GhostField] public int Value;
    }

The command data serialization is particularly useful for implementing RemotePlayerPrediction.

Ghost Field Inheritance

If a [GhostField] is specified for a non primitive field type, the attribute (and some of its properties) are automatically inherited by all the sub-fields which do not themselves implement a [GhostField] attribute. For example:


public struct Vector2
{
    public float x;
    [GhostField(Quantization=100)] public float y;
}

public struct MyComponent : IComponentData
{
    //Value.x will inherit the quantization value specified by the parent definition (1000).
    //Value.y will maintain its original quantization value (100).
    [GhostField(Quantized=1000)] public Vector2 Value;
}

The following properties are not inherited:

Using the GhostComponentAttribute

The GhostComponentAttribue does not indicate or signal that a component is replicated (that's what the other two attributes are for). Instead, it should be used to instruct the runtime how to handle the component when it comes to:

[GhostComponent(PrefabType=GhostPrefabType.All, SendTypeOptimization=GhostSendType.OnlyInterpolatedClients, SendDataForChildEntity=false)]
public struct MyComponent : IComponentData
{  
    [GhostField(Quantized=1000)] public float3 Value;
}
PrefabType Details

To change which versions of a Ghost Prefab a component is available on, use PrefabType in a GhostComponentAttribute on the component. PrefabType can be on of the these types:

For example, if you add [GhostComponent(PrefabType=GhostPrefabType.Client)] to RenderMesh, the ghost won’t have a RenderMesh when it is instantiated on the server world, but it will have it when instantiated on the client world.

[!NOTE] Runtime Prediction Switching therefore has the potential to add and remove components on a ghost, live.

SendTypeOptimization Details

A component can set SendTypeOptimization in the GhostComponentAttribute to control which clients the component is sent to, whenever a ghost type is known at compile time. The available modes are:

A component can also set SendDataForChildEntity to true in order to change the default (of not serializing children), allowing this component to be serialized when on a child.

A component can also set SendToOwner in the GhostComponentAttribute to specify if the component should be sent to client who owns the entity. The available values are:

[!NOTE] By setting either the SendTypeOptimisation and/or SendToOwner (to specify to which types of client(s) the component should be replicated to), will not affect the presence of the component on the prefab, nor modify the component on the clients which did not receive it.

How to add serialization support for custom Types

The types you can serialize via GhostFieldAttribute are specified via templates. You can see the default supported types [here](ghost-types-templates.md#Supported Types)

In addition to the default out-of-the-box types you can also:

Please check how to [use and write templates](ghost-types-templates.md#Defining additional templates) for more information on the topic.

[!NOTE] Writing templates is non-trivial. If it is possible to replicate the type simply by adding GhostFields, it's often easier to just do so. If you do not have access to a type, create a Variant instead (see section below).

Ghost Component Variants

The GhostComponentVariationAttribute is special attribute tha can be used to declare at compile time a "replication schema" for a type, without the need to markup the fields in the original type, or the original type itself.

[!NOTE]This new declared type act as proxy from a code-generation perspective. Instead of using the original type, the code-generation system use the declared "variant" to generate a specific version of the serialization code.

[!NOTE] Ghost components variants for IBufferElementData are not fully supported.

The GhostComponentVariationAttribute has some specific use-cases in mind:

    [GhostComponentVariation(typeof(LocalTransform), "Transform - 2D")]
    [GhostComponent(PrefabType=GhostPrefabType.All, SendTypeOptimization=GhostSendType.AllClients)]
    public struct PositionRotation2d
    {
        [GhostField(Quantization=1000, Smoothing=SmoothingAction.InterpolateAndExtrapolate, SubType=GhostFieldSubType.Translation2D)]
        public float3 Position;
        [GhostField(Quantization=1000, Smoothing=SmoothingAction.InterpolateAndExtrapolate, SubType=GhostFieldSubType.Rotation2D)]
        public quaternion Rotation;
    }

In the example above, the PositionRotation2d Variation will generate serialization code for LocalTransform, using the properties and the attribute present in the variant declaration.

The attribute constructor takes a few arguments:

Then, for each field in the original struct (in this case, LocalTransform) that you wish to replicate, you should add a GhostField attribute like you usually do, and define the field identically to that of the base struct.

[!NOTE] Only members that are present in the component type are allowed. Validation occurs at compile time, and exceptions are thrown in case this rule is not respected.

An optional GhostComponentAttribute attribute can be added to the variant to further specify the component serialization properties.

It is possible to declare multiple serialization variant for a component (example: 2D and 3D variations for LocalRotation).

[!NOTE] If you only define only one Variant for a ComponentType, it becomes the default serialization strategy for that type automatically.

Preventing a component from supporting Variations

There are cases where you'd like to prevent a component from having its serialization modified via Variants. Example: From the NetCode package itself, we must always replicate the GhostComponent for netcode systems to work properly, so we don't let user-code (you) modify serialization rules for it).

Thus, to prevent a component from supporting variation, use the DontSupportPrefabOverridesAttribute attribute. An error will be reported at compile time, if a GhostComponentVariation is defined for that type.

Specify which variant to use on a Ghost Prefab

Using the GhostAuthoringInspectionComponent MonoBehaviour in conjunction with the GhostAuthoringComponent MonoBehaviour, it is possible to select what serialization variants to use on a per-prefab basis. You can choose a Variant for each individual component (including the ability to set the special-case variant: DontSerializeVariant).

All variants for that specific component type present in the project will be show in a dropbox selection.
To modify how children of Ghost prefabs are replicated, add a GhostAuthoringInspectionComponent to each individual child.

[!NOTE] The GhostAuthoringInspectionComponent is also an incredibly valuable debugging tool. Add it to a Ghost Prefab (or one of its children) to view all replicated types on said Ghost, and to diagnose why a specific type is not replicating in the way you'd expect.

Assigning a default variant to use for a Type

In cases where multiple variants are present for a type, Netcode may be unable to infer which Variant should be used. If the "Default Serializer" for the Type is replicated, it'll default to it. If not, it is considered a conflict, and you'll get runtime exceptions when creating any netcode world (including Baking worlds). We use a built-in, deterministic, fallback method to guess which variant you likely want, but, in general, it is the users responsibility to indicate what Variant should be the default here.

To setup which variant to use as the default for a given type, you need to create a system that inherits from DefaultVariantSystemBase class, and implements the RegisterDefaultVariants method.

using System.Collections.Generic;
using Unity.Entities;
using Unity.Transforms;

namespace Unity.NetCode.Samples
{
    sealed class DefaultVariantSystem : DefaultVariantSystemBase
    {
        protected override void RegisterDefaultVariants(Dictionary<ComponentType, Rule> defaultVariants)
        {
            defaultVariants.Add(typeof(LocalTransform), Rule.OnlyParents(typeof(TransformDefaultVariant)));
        }
    }
}

This example code would make sure the default LocalTransform variant to us as default is the TransformDefaultVariant. For more information, please refer to the DefaultVariantSystemBase documentation.

[!NOTE] This is the recommended approach to setup the default Variant for a Ghost "project-wide". Prefer DefaultVariantSystemBase over direct Variant manipulation (via the GhostAuthoringInspectionComponent overrides).

Special Variant Types Special Built-in Variant Details ClientOnlyVariant Use this to specify that a given ComponentType should only appear on client worlds. ServerOnlyVariant The inverse. DontSerializeVariant Use this to disable serialization of a Type entirely. I.e. Use it to ignore replication attributes ([GhostField] and [GhostEnabledBit]).
using System.Collections.Generic;
using Unity.Entities;
using Unity.Transforms;

namespace Unity.NetCode.Samples
{
    sealed class DefaultVariantSystem : DefaultVariantSystemBase
    {
        protected override void RegisterDefaultVariants(Dictionary<ComponentType, Rule> defaultVariants)
        {
            defaultVariants.Add(typeof(SomeClientOnlyThing), Rule.ForAll(typeof(ClientOnlyVariant)));
            defaultVariants.Add(typeof(SomeServerOnlyThing), Rule.ForAll(typeof(ServerOnlyVariant)));
            defaultVariants.Add(typeof(NoNeedToSyncThis), Rule.ForAll(typeof(DontSerializeVariant)));
        }
    }
}

You can also manually pick the DontSerializeVariant in the ghost component on ghost prefabs (via the GhostAuthoringInspectionComponent).

Assign variants and override GhostComponentAttribute settings on ghost prefabs

It is possible to override the following meta-data on per-prefab basis, by using the GhostAuthoringInspectionComponent editor.

The GhostAuthoringInspectionComponent should be added to the GameObject you would like to customise. Once added, the editor will show which components present in the runtime entity are replicated.
The editor allow you to: change the following properties:

It is possible to prevent a component from supporting per-prefab overrides by using the DontSupportPrefabOverrides attribute.
When present, the component can't be customized in the inspector, nor can a programmer add custom or default variants for this type (as that will trigger errors during ghost validation).

For example: The Netcode for Entities package requires the GhostOwner to be added to all ghost types, sent for all ghost types, and serialized using the default variant. Thus, we add the [DontSupportPrefabOverride] attribute to it.

[!NOTE] Components on child entities are not serialised by default, thus by default when you look to GhostAuthoringInspectionComponent on a child GameObject you will see that the selected variant for the type is the DontSerializeVariant.

To understand what is being put on the wire in the Netcode, you can use the snapshot visualization tool, NetDbg tool.

To open the tool, go to menu: Multiplayer > Open NetDbg, and the tool opens in a browser window. It displays a vertical bar for each received snapshot, with a breakdown of the snapshot’s ghost types, size etc.

To see more detailed information about the snapshot, click on one of the bars.

[!NOTE] This tool is a prototype. In future versions of the package, it will integrate with the Unity Profiler so you can easily correlate network traffic with memory usage and CPU performance.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4