Skip to content

Commit 3a82fef

Browse files
author
Unity Technologies
committed
com.unity.netcode@0.6.0-preview.7
## [0.6.0] - 2020-11-26 ### New features * Added DynamicBuffers serialization support to ghosts. Like IComponentData, is now possible to annotate IBufferElementData with GhostComponentAttribute and members with GhostFieldAttribute and having the buffers replicated through the network. * ICommandData are now serializable and can be sent to the remote players. * Added new SendToOwner property to the GhostComponentAttribute that can be used to configure to witch subset of players the component should be sent to: only to the owner, only to the non owner, or all. * Ghost Component Serialization Variant. A new GhostComponentVariation attribute has been introduced that let you to specify different serialization options for a component or buffer, by overriding the `[GhostField]` and `[GhostComponent]` properties present in the original type definition. * It is possible to prevent a component to support variation by using the `[DontSupportVariation]` attribute. When present, if a GhostComponentVariation is defined for that type, an exception is triggered. * Ghost components attributes and serialization variants can be customized per prefabs. For every component in a ghost prefab, it is possible to change: * PrefabType * GhostSendType * The variant to use, if variants for that component exist. * Is possible to prevent a component to support per-prefab overrides by using the [DontSupportPrefabOverride] attribute. When present, the component can't be further customized in the inspector. * It's now possible to register a prediction smoothing function, by calling the `GhostPredictionSmoothingSystem.RegisterSmoothingAction<ComponentType>(SmoothingActionDelegate)` and supplying a `ComponentType` and `GhostPredictionSmoothingSystem.SmoothingActionDelegate` (see Runtime/Snapshot/DefaultUserParams.cs for an example). * Added a new `ClientTickRate` component which when added to a singleton entity controls the interpolation times used to calculate time on the client. The default values can be accessed through the static `NetworkTimeSystem.DefaultClientTickRate`. * Added support for extrapolation when the tick being applied to interpolated ghosts on the client has not been received yet and is outside the interpolation delay. Set the new `Smoothing` field in the `GhostField` attribute to `SmoothingAction.InterpolateAndExtrapolate` to enable extrapolation. * Added a `MaxSmoothingDistance` parameter to the `[GhostField]` attribute. If specified interpolation will be disabled when the values change more than that limit between two snapshots. This is useful for dealing with teleportation and similar changes which should not be interpolated. ### Changes * It is no longer required to create a ghost collection, as long as there is a prefab for a ghost it will be picked up automatically. You can create a prefab by referencing it in a spawner component or by placing a pre spawned instance of a ghost. ### Fixes * Fixed an issue where the elapsed time was not using the max simulation rate - causing the fixed time step physics to take more and more time. * Fixed an issue causing time rollbacks when running client and server in the editor if performance is too low. ### Upgrade guide The `Interpolate` bool in the `GhostField` attribute has been replaced with `Smoothing`. Replace `Interpolate=true` with `Smoothing=SmoothingAction.Interpolate` to keep the old value, or set it to `SmoothingAction.InterpolateAndExtrapolate` to enable extrapolation. ## [0.5.0] - 2020-10-01 ### New features * Added RpcSystem.DynamicAssemblyList which can be used to delay the checksums for RPCs and ghost components when the set of assemblies are different on the client and server. * Added to RPC and Command the possiblity to send Entity reference from both client and server. ### Changes * Change the system ordering to be compatible with latest physics. `NetworkTimeSystem` has moved to `ClientInitializationSystemGroup`. The SimulationSystemGroup runs `GhostSpawnSystemGroup` (client), `GhostReceiveSystemGroup` and `GhostSimulationSystemGroup` before `FixedStepSimulationSystemGroup` where physics is running. `RpcCommandRequestSystemGroup`, `RpcSystem` and `GhostSendSystem` (server) is running at the end of the frame, after all simulation code. Other systems has been moved into one of the groups. * Created a new `GhostInputSystemGroup` where systems adding inputs to the input buffer should run. ### Fixes ### Upgrade guide * The systems adding input to the `ICommandData` buffer needs to be moved to `GhostInputSystemGroup`
1 parent f317cc3 commit 3a82fef

File tree

89 files changed

+7636
-1491
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+7636
-1491
lines changed

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,35 @@
11
# Change log
22

3+
## [0.6.0] - 2020-11-26
4+
### New features
5+
* Added DynamicBuffers serialization support to ghosts. Like IComponentData, is now possible to annotate IBufferElementData with GhostComponentAttribute and members with GhostFieldAttribute
6+
and having the buffers replicated through the network.
7+
* ICommandData are now serializable and can be sent to the remote players.
8+
* Added new SendToOwner property to the GhostComponentAttribute that can be used to configure to witch
9+
subset of players the component should be sent to: only to the owner, only to the non owner, or all.
10+
* Ghost Component Serialization Variant. A new GhostComponentVariation attribute has been introduced that let you to specify different serialization options for a component or buffer, by overriding
11+
the `[GhostField]` and `[GhostComponent]` properties present in the original type definition.
12+
* It is possible to prevent a component to support variation by using the `[DontSupportVariation]` attribute. When present, if a GhostComponentVariation is defined for that type, an exception is triggered.
13+
* Ghost components attributes and serialization variants can be customized per prefabs. For every component in a ghost prefab, it is possible to change:
14+
* PrefabType
15+
* GhostSendType
16+
* The variant to use, if variants for that component exist.
17+
* Is possible to prevent a component to support per-prefab overrides by using the [DontSupportPrefabOverride] attribute. When present, the component can't be further customized in the inspector.
18+
* It's now possible to register a prediction smoothing function, by calling the `GhostPredictionSmoothingSystem.RegisterSmoothingAction<ComponentType>(SmoothingActionDelegate)` and supplying a `ComponentType` and `GhostPredictionSmoothingSystem.SmoothingActionDelegate` (see Runtime/Snapshot/DefaultUserParams.cs for an example).
19+
* Added a new `ClientTickRate` component which when added to a singleton entity controls the interpolation times used to calculate time on the client. The default values can be accessed through the static `NetworkTimeSystem.DefaultClientTickRate`.
20+
* Added support for extrapolation when the tick being applied to interpolated ghosts on the client has not been received yet and is outside the interpolation delay. Set the new `Smoothing` field in the `GhostField` attribute to `SmoothingAction.InterpolateAndExtrapolate` to enable extrapolation.
21+
* Added a `MaxSmoothingDistance` parameter to the `[GhostField]` attribute. If specified interpolation will be disabled when the values change more than that limit between two snapshots. This is useful for dealing with teleportation and similar changes which should not be interpolated.
22+
23+
### Changes
24+
* It is no longer required to create a ghost collection, as long as there is a prefab for a ghost it will be picked up automatically. You can create a prefab by referencing it in a spawner component or by placing a pre spawned instance of a ghost.
25+
26+
### Fixes
27+
* Fixed an issue where the elapsed time was not using the max simulation rate - causing the fixed time step physics to take more and more time.
28+
* Fixed an issue causing time rollbacks when running client and server in the editor if performance is too low.
29+
30+
### Upgrade guide
31+
The `Interpolate` bool in the `GhostField` attribute has been replaced with `Smoothing`. Replace `Interpolate=true` with `Smoothing=SmoothingAction.Interpolate` to keep the old value, or set it to `SmoothingAction.InterpolateAndExtrapolate` to enable extrapolation.
32+
333
## [0.5.0] - 2020-10-01
434
### New features
535
* Added RpcSystem.DynamicAssemblyList which can be used to delay the checksums for RPCs and ghost components when the set of assemblies are different on the client and server.

Documentation~/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ public class SampleCubeInput : ComponentSystem
182182
return;
183183
}
184184
var input = default(CubeInput);
185-
input.tick = World.GetExistingSystem<ClientSimulationSystemGroup>().ServerTick;
185+
input.Tick = World.GetExistingSystem<ClientSimulationSystemGroup>().ServerTick;
186186
if (Input.GetKey("a"))
187187
input.horizontal -= 1;
188188
if (Input.GetKey("d"))

Documentation~/ghost-snapshots.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ For example, if you add `[GhostComponent(PrefabType=GhostPrefabType.Client)]` to
4545
A component can set __OwnerPredictedSendType__ in the __GhostComponentAttribute__ to control which clients the component is sent to when it is owner predicted. The available modes are:
4646
* __Interpolated__ - the component is only sent to clients which are interpolating the ghost.
4747
* __Predicted__ - the component is only sent to clients which are predicting the ghost.
48-
* __Interpolated__ - the component is sent to all clients.
48+
* __All__ - the component is sent to all clients.
4949

5050
If a component is not sent to a client NetCode will not modify the component on the client which did not receive it.
5151

@@ -55,7 +55,7 @@ For each component, you need to add an attribute to the values you want to sent.
5555
The __GhostFieldAttribute__ also has a `Interpolate` property which controls if the field will be interpolated or not on clients which are not predicting the ghost.
5656
Finally the __GhostFieldAttribute__ has a `SubType` property which can be set to an integer value to use special serialization rules supplied by the game for that specific field.
5757

58-
As well as adding attributes, you can specify rules for components which you do not have source access to by creating an assembly with a name ending with `.NetCodeGen`. This assembly should contain a class implementing the interface __IGhostDefaultOverridesModifier__. Implement the method `public void Modify(Dictionary<string, GhostAuthoringComponentEditor.GhostComponent> overrides)` and add an entry to the ictionary with the full name of the component as key and a value containing the desired override attributes.
58+
As well as adding attributes, you can specify rules for components which you do not have source access to by creating an assembly with a name ending with `.NetCodeGen`. This assembly should contain a class implementing the interface __IGhostDefaultOverridesModifier__. Implement the method `public void Modify(Dictionary<string, GhostAuthoringComponentEditor.GhostComponent> overrides)` and add an entry to the dictionary with the full name of the component as key and a value containing the desired override attributes.
5959

6060

6161
## Ghost collection
@@ -140,6 +140,6 @@ To look at an example of a scene using prespawn ghosts, see the test in *Assets/
140140

141141
## Snapshot visualization tool
142142

143-
To understand what is being put on the wire in the netcode, you can use the prototype snapshot visualization tool, __NetDbg__ in the Stats folder. To open the tool, go to menu: __Multiplayer &gt; Open NetDbg__, and the tool opens in a browser window. It displays a vertical bar for each snapshot Unity receives, with a breakdown of the snapshot’s ghost types. To see more detailed information about the snapshot, click on one of the bars.
143+
To understand what is being put on the wire in the netcode, you can use the prototype snapshot visualization tool, __NetDbg__ in the Stats folder. To open the tool, go to menu: __Multiplayer &gt; Open NetDbg__, and the tool opens in a browser window. It displays a vertical bar for each snapshot Unity receives, with a breakdown of the snapshot’s ghost types. To see more detailed information about the snapshot, click on one of the bars.
144144
> [!NOTE]
145145
> 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.

Editor/CecilExtensions.cs

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ public static bool IsIComponentData(this Mono.Cecil.TypeReference typeReference)
4141
i.InterfaceType.Name == typeof(IComponentData).Name &&
4242
i.InterfaceType.Namespace == typeof(IComponentData).Namespace);
4343
}
44+
public static bool IsBufferElementData(this Mono.Cecil.TypeReference typeReference)
45+
{
46+
var resolvedType = typeReference.Resolve();
47+
if (resolvedType == null)
48+
return false;
49+
return resolvedType.Interfaces.Any(i =>
50+
i.InterfaceType.Name == typeof(IBufferElementData).Name &&
51+
i.InterfaceType.Namespace == typeof(IBufferElementData).Namespace);
52+
}
4453
public static bool IsIRpcCommand(this Mono.Cecil.TypeReference typeReference)
4554
{
4655
var resolvedType = typeReference.Resolve();
@@ -60,9 +69,9 @@ public static bool IsICommandData(this Mono.Cecil.TypeReference typeReference)
6069
i.InterfaceType.Namespace == typeof(ICommandData).Namespace);
6170
}
6271

63-
public static bool HasGhostFieldAttribute(Mono.Cecil.TypeReference parentType, Mono.Cecil.FieldDefinition componentField)
72+
public static bool HasGhostFieldAttribute(Mono.Cecil.TypeReference parentType, Mono.Cecil.IMemberDefinition componentField)
6473
{
65-
if (!GhostAuthoringComponentEditor.GhostDefaultOverrides.TryGetValue(parentType.FullName.Replace('/','+'), out var newComponent))
74+
if (!GhostAuthoringModifiers.GhostDefaultOverrides.TryGetValue(parentType.FullName.Replace('/','+'), out var newComponent))
6675
{
6776
return componentField.HasAttribute<GhostFieldAttribute>();
6877
}
@@ -72,9 +81,9 @@ public static bool HasGhostFieldAttribute(Mono.Cecil.TypeReference parentType, M
7281
}
7382
}
7483

75-
public static GhostFieldAttribute GetGhostFieldAttribute(Mono.Cecil.TypeReference parentType, Mono.Cecil.FieldDefinition componentField)
84+
public static GhostFieldAttribute GetGhostFieldAttribute(Mono.Cecil.TypeReference parentType, Mono.Cecil.IMemberDefinition componentField)
7685
{
77-
if (GhostAuthoringComponentEditor.GhostDefaultOverrides.TryGetValue(parentType.FullName.Replace('/','+'), out var newComponent))
86+
if (parentType != null && GhostAuthoringModifiers.GhostDefaultOverrides.TryGetValue(parentType.FullName.Replace('/','+'), out var newComponent))
7887
{
7988
foreach (var field in newComponent.fields)
8089
{
@@ -103,10 +112,6 @@ public static GhostFieldAttribute GetGhostFieldAttribute(Mono.Cecil.TypeReferenc
103112

104113
public static GhostComponentAttribute GetGhostComponentAttribute(Mono.Cecil.TypeDefinition managedType)
105114
{
106-
if (GhostAuthoringComponentEditor.GhostDefaultOverrides.TryGetValue(managedType.FullName.Replace('/', '+'), out var newComponent))
107-
{
108-
return newComponent.attribute;
109-
}
110115
var attribute = managedType.GetAttribute<GhostComponentAttribute>();
111116
if (attribute != null)
112117
{
@@ -125,6 +130,16 @@ public static GhostComponentAttribute GetGhostComponentAttribute(Mono.Cecil.Type
125130
return null;
126131
}
127132

133+
public static ulong ComputeVariantHash(Mono.Cecil.TypeReference variantType, Mono.Cecil.CustomAttribute attribute)
134+
{
135+
var hash = TypeHash.FNV1A64(attribute.AttributeType.FullName);
136+
var componentType = attribute.ConstructorArguments[0].Value as Mono.Cecil.TypeReference;
137+
var variantName = variantType.FullName;
138+
hash = TypeHash.CombineFNV1A64(hash, TypeHash.FNV1A64(componentType.FullName));
139+
hash = TypeHash.CombineFNV1A64(hash, TypeHash.FNV1A64(variantName));
140+
return hash;
141+
}
142+
128143
public static bool IsStruct(this Mono.Cecil.TypeDefinition type)
129144
{
130145
return !type.IsPrimitive && type.IsValueType && !type.IsEnum;
@@ -140,23 +155,46 @@ public static bool IsBlittable(this Mono.Cecil.TypeReference type)
140155

141156
public static string GetFieldTypeName(this Mono.Cecil.TypeReference type)
142157
{
143-
if (type.IsTypeOf<System.Byte>()) return "byte";
144-
if (type.IsTypeOf<System.SByte>()) return "sbyte";
145-
if (type.IsTypeOf<System.Int16>()) return "short";
146-
if (type.IsTypeOf<System.UInt16>()) return "ushort";
147-
if (type.IsTypeOf<System.Int32>()) return "int";
148-
if (type.IsTypeOf<System.UInt32>()) return "uint";
149-
if (type.IsTypeOf<System.Int64>()) return "long";
150-
if (type.IsTypeOf<System.UInt64>()) return "ulong";
158+
if (type.IsTypeOf<Byte>()) return "byte";
159+
if (type.IsTypeOf<SByte>()) return "sbyte";
160+
if (type.IsTypeOf<Int16>()) return "short";
161+
if (type.IsTypeOf<UInt16>()) return "ushort";
162+
if (type.IsTypeOf<Int32>()) return "int";
163+
if (type.IsTypeOf<UInt32>()) return "uint";
164+
if (type.IsTypeOf<Int64>()) return "long";
165+
if (type.IsTypeOf<UInt64>()) return "ulong";
151166

152-
if (type.IsTypeOf<System.IntPtr>()) return "iptr";
153-
if (type.IsTypeOf<System.UIntPtr>()) return "uptr";
167+
if (type.IsTypeOf<IntPtr>()) return "iptr";
168+
if (type.IsTypeOf<UIntPtr>()) return "uptr";
154169

155-
if (type.IsTypeOf<System.Single>()) return "float";
156-
if (type.IsTypeOf<System.Double>()) return "double";
170+
if (type.IsTypeOf<Single>()) return "float";
171+
if (type.IsTypeOf<Double>()) return "double";
157172

158173
return type.ToString().Replace("/", ".");
159174
}
160175

176+
static public bool HasAttributeOnMemberOImplementedInterfaces<T>(this Mono.Cecil.FieldDefinition member) where T: Attribute
177+
{
178+
foreach (var m in member.DeclaringType.Interfaces)
179+
{
180+
var prop = m.InterfaceType.Resolve().Fields.FirstOrDefault(p => p.Name == member.Name);
181+
if (prop != null && prop.GetAttribute<T>() != null)
182+
return true;
183+
}
184+
185+
return false;
186+
}
187+
static public bool HasAttributeOnMemberOImplementedInterfaces<T>(this Mono.Cecil.PropertyDefinition member) where T: Attribute
188+
{
189+
foreach (var m in member.DeclaringType.Interfaces)
190+
{
191+
var prop = m.InterfaceType.Resolve().Properties.FirstOrDefault(p => p.Name == member.Name);
192+
if (prop != null && prop.GetAttribute<T>() != null)
193+
return true;
194+
}
195+
196+
return false;
197+
}
198+
161199
}
162200
}

Editor/CodeGenTemplates/DefaultTypes/GhostSnapshotValueFloat.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,15 @@ public unsafe void CopyFromSnapshot(ref Snapshot snapshot, ref IComponentData co
5555
component.__GHOST_FIELD_REFERENCE__ = snapshotBefore.__GHOST_FIELD_NAME__ * __GHOST_DEQUANTIZE_SCALE__;
5656
#endregion
5757

58+
#region __GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_SETUP__
59+
var __GHOST_FIELD_NAME___Before = snapshotBefore.__GHOST_FIELD_NAME__ * __GHOST_DEQUANTIZE_SCALE__;
60+
var __GHOST_FIELD_NAME___After = snapshotAfter.__GHOST_FIELD_NAME__ * __GHOST_DEQUANTIZE_SCALE__;
61+
#endregion
62+
#region __GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_DISTSQ__
63+
var __GHOST_FIELD_NAME___DistSq = math.distancesq(__GHOST_FIELD_NAME___Before, __GHOST_FIELD_NAME___After);
64+
#endregion
5865
#region __GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE__
59-
component.__GHOST_FIELD_REFERENCE__ =
60-
math.lerp(snapshotBefore.__GHOST_FIELD_NAME__ * __GHOST_DEQUANTIZE_SCALE__,
61-
snapshotAfter.__GHOST_FIELD_NAME__ * __GHOST_DEQUANTIZE_SCALE__, snapshotInterpolationFactor);
66+
component.__GHOST_FIELD_REFERENCE__ = math.lerp(__GHOST_FIELD_NAME___Before, __GHOST_FIELD_NAME___After, snapshotInterpolationFactor);
6267
#endregion
6368
}
6469
}

Editor/CodeGenTemplates/DefaultTypes/GhostSnapshotValueFloat2.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ public unsafe void CopyFromSnapshot(ref GhostDeserializerState deserializerState
1010
component.__GHOST_FIELD_REFERENCE__ = new float2(snapshotBefore.__GHOST_FIELD_NAME___x * __GHOST_DEQUANTIZE_SCALE__, snapshotBefore.__GHOST_FIELD_NAME___y * __GHOST_DEQUANTIZE_SCALE__);
1111
#endregion
1212

13+
#region __GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_SETUP__
14+
var __GHOST_FIELD_NAME___Before = new float2(snapshotBefore.__GHOST_FIELD_NAME___x * __GHOST_DEQUANTIZE_SCALE__, snapshotBefore.__GHOST_FIELD_NAME___y * __GHOST_DEQUANTIZE_SCALE__);
15+
var __GHOST_FIELD_NAME___After = new float2(snapshotAfter.__GHOST_FIELD_NAME___x * __GHOST_DEQUANTIZE_SCALE__, snapshotAfter.__GHOST_FIELD_NAME___y * __GHOST_DEQUANTIZE_SCALE__);
16+
#endregion
17+
#region __GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_DISTSQ__
18+
var __GHOST_FIELD_NAME___DistSq = math.distancesq(__GHOST_FIELD_NAME___Before, __GHOST_FIELD_NAME___After);
19+
#endregion
1320
#region __GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE__
14-
component.__GHOST_FIELD_REFERENCE__ = math.lerp(
15-
new float2(snapshotBefore.__GHOST_FIELD_NAME___x * __GHOST_DEQUANTIZE_SCALE__, snapshotBefore.__GHOST_FIELD_NAME___y * __GHOST_DEQUANTIZE_SCALE__),
16-
new float2(snapshotAfter.__GHOST_FIELD_NAME___x * __GHOST_DEQUANTIZE_SCALE__, snapshotAfter.__GHOST_FIELD_NAME___y * __GHOST_DEQUANTIZE_SCALE__),
17-
snapshotInterpolationFactor);
21+
component.__GHOST_FIELD_REFERENCE__ = math.lerp(__GHOST_FIELD_NAME___Before, __GHOST_FIELD_NAME___After, snapshotInterpolationFactor);
1822
#endregion
1923
}
2024
}

Editor/CodeGenTemplates/DefaultTypes/GhostSnapshotValueFloat2Unquantized.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ public unsafe void CopyFromSnapshot(ref GhostDeserializerState deserializerState
1010
component.__GHOST_FIELD_REFERENCE__ = new float2(snapshotBefore.__GHOST_FIELD_NAME___x, snapshotBefore.__GHOST_FIELD_NAME___y);
1111
#endregion
1212

13+
#region __GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_SETUP__
14+
var __GHOST_FIELD_NAME___Before = new float2(snapshotBefore.__GHOST_FIELD_NAME___x, snapshotBefore.__GHOST_FIELD_NAME___y);
15+
var __GHOST_FIELD_NAME___After = new float2(snapshotAfter.__GHOST_FIELD_NAME___x, snapshotAfter.__GHOST_FIELD_NAME___y);
16+
#endregion
17+
#region __GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_DISTSQ__
18+
var __GHOST_FIELD_NAME___DistSq = math.distancesq(__GHOST_FIELD_NAME___Before, __GHOST_FIELD_NAME___After);
19+
#endregion
1320
#region __GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE__
14-
component.__GHOST_FIELD_REFERENCE__ = math.lerp(
15-
new float2(snapshotBefore.__GHOST_FIELD_NAME___x, snapshotBefore.__GHOST_FIELD_NAME___y),
16-
new float2(snapshotAfter.__GHOST_FIELD_NAME___x, snapshotAfter.__GHOST_FIELD_NAME___y),
17-
snapshotInterpolationFactor);
21+
component.__GHOST_FIELD_REFERENCE__ = math.lerp(__GHOST_FIELD_NAME___Before, __GHOST_FIELD_NAME___After, snapshotInterpolationFactor);
1822
#endregion
1923
}
2024
}

0 commit comments

Comments
 (0)