-
Notifications
You must be signed in to change notification settings - Fork 463
feat: NetworkTransform with blittable states and handled in jobs #4123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop-3.x.x
Are you sure you want to change the base?
Changes from all commits
8a7f227
0c58dc8
331f295
e3267b7
9856dea
a578c34
202190c
1854d2d
20d9ccd
03966e5
8398dc3
3415b51
363c94d
e7031a8
6bf1ba9
2b383b8
e945333
dad9cd8
6100893
1bbdfdb
36f66ec
c7d3ecd
ad3c564
cd0422f
d9d6658
43ce4d9
e0a0191
d06eead
9bdcd9b
92c8052
d6f5649
038311b
0de0857
19ef4f2
504fc1f
c745f7d
8773a34
5ed0118
f4914d3
595ceb5
05d7c7f
d1d0e04
06ce699
99c61dc
c7cccef
5894d94
c884fed
ea4f91f
2c7322f
dfa358c
c737a43
e37263e
4e5837f
112b302
6b8df1d
533c5d4
cde309a
63dab32
87a1da4
13494da
44dd3f1
c1cc3fc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -218,6 +218,11 @@ private void DisplayNetworkTransformProperties() | |
| EditorGUILayout.Space(); | ||
| EditorGUILayout.LabelField("Delivery", EditorStyles.boldLabel); | ||
| EditorGUILayout.PropertyField(m_TickSyncChildren); | ||
|
|
||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto on the notes, if deprecated this would change and no need to call it out. |
||
| // UseUnreliableDeltas only applies to per instance synchronization mode, but the mode is authored on | ||
| // the NetworkManager that will run this instance, which a prefab cannot know. So it is always drawn | ||
| // and the runtime ignores it under the batched mode, where delivery is determined per state update | ||
| // as opposed to per component. | ||
| // If both are set from a previous configuration, then SwitchTransformSpaceWhenParented takes | ||
| // precedence. | ||
| if (networkTransform.UseUnreliableDeltas && networkTransform.SwitchTransformSpaceWhenParented) | ||
|
|
@@ -242,6 +247,7 @@ private void DisplayNetworkTransformProperties() | |
| EditorGUILayout.Space(); | ||
| EditorGUILayout.LabelField("Configurations", EditorStyles.boldLabel); | ||
|
|
||
| // SwitchTransformSpaceWhenParented is only constrained by UseUnreliableDeltas while the latter applies. | ||
| SetGUIActive(!networkTransform.UseUnreliableDeltas); | ||
| if (networkTransform.UseUnreliableDeltas) | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| using Unity.Burst; | ||
| using Unity.Collections; | ||
| using UnityEngine.Jobs; | ||
| using static Unity.Netcode.Components.NetworkTransform; | ||
|
|
||
| namespace Unity.Netcode.Components | ||
| { | ||
| /// <summary> | ||
| /// Motion Authority Only: | ||
| /// Detects <see cref="NetworkTransform"/> state changes for every registered instance in a parallel job. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// <see cref="CheckForStateChange(ref NetworkTransformState, ref NetworkDeltaPosition, ref TransformDeltaConfig, in TransformSample, bool, bool, bool)"/> | ||
| /// is the common method used for both per instance, runs on the main thread, and batched modes. This assures both paths detect changes in state identically. | ||
| /// </remarks> | ||
| [BurstCompile] | ||
| internal struct DetectTransformDeltaJob : IJobParallelForTransform | ||
| { | ||
| /// <summary> | ||
| /// The per instance input and output, parallel to the job's scheduled transforms. | ||
| /// </summary> | ||
| public NativeArray<TransformDeltaEntry> Entries; | ||
|
|
||
| /// <summary> | ||
| /// This job's primary entry point. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// TODO: Investigate ways to work around the fact that a Rigidbody's position and rotation cannot | ||
| /// be sampled from a job. As such, any NetworkTransform that is using Rigidbody for motion will | ||
| /// use the <see cref="UnityEngine.GameObject.transform"/> to detect changes in position and rotation | ||
| /// states on the authority side. | ||
| /// </remarks> | ||
| /// <param name="index">Index for the transform in question.</param> | ||
| /// <param name="transform">The job safe <see cref="TransformAccess"/></param> | ||
| public void Execute(int index, TransformAccess transform) | ||
| { | ||
| if (!transform.isValid) | ||
| { | ||
| return; | ||
|
Check warning on line 39 in com.unity.netcode.gameobjects/Runtime/Components/DetectTransformDeltaJob.cs
|
||
| } | ||
|
|
||
| var entry = Entries[index]; | ||
| var flagStates = entry.State.FlagStates; | ||
| // Only ResolveTransformSpace can raise this on the batched path. The one caller that forces a full | ||
| // state update does so from CommitDetectedState on the main thread, after this job has run. | ||
| var forceState = false; | ||
|
|
||
| // Resolve the transform space before sampling, otherwise the wrong set of values gets compared. | ||
| var transformSpaceChanged = ResolveTransformSpace(ref entry.Config, ref flagStates, entry.TransformHasParent, false, ref forceState); | ||
| entry.State.FlagStates = flagStates; | ||
|
|
||
| var rotation = entry.Config.InLocalSpace ? transform.localRotation : transform.rotation; | ||
| entry.Sample.Position = entry.Config.InLocalSpace ? transform.localPosition : transform.position; | ||
| entry.Sample.Rotation = rotation; | ||
| entry.Sample.RotAngles = NetworkTransformMath.EulerAngles(rotation); | ||
| entry.Sample.Scale = transform.localScale; | ||
|
|
||
| entry.IsDirty = CheckForStateChange(ref entry.State, ref entry.HalfPositionState, ref entry.Config, | ||
| entry.Sample, false, forceState, transformSpaceChanged); | ||
|
|
||
| Entries[index] = entry; | ||
| } | ||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| using Unity.Burst; | ||
| using Unity.Collections; | ||
| using Unity.Jobs; | ||
| using Unity.Mathematics; | ||
|
|
||
| namespace Unity.Netcode.Components | ||
| { | ||
| /// <summary> | ||
| /// The NGO non-authority instance's transform state used by <see cref="InterpolateTransformJob"/>. | ||
| /// See also: | ||
| /// - <see cref="NativeInterpolator"/> | ||
| /// - <see cref="NativeInterpolatorState"/> | ||
| /// </summary> | ||
| internal struct InterpolationEntry | ||
| { | ||
| internal NativeInterpolatorState Position; | ||
| internal NativeInterpolatorState Rotation; | ||
| internal NativeInterpolatorState Scale; | ||
|
|
||
| /// <summary> | ||
| /// The delta frame time whether fixed or standard delta. | ||
| /// </summary> | ||
| internal float DeltaTime; | ||
|
|
||
| /// <summary> | ||
| /// The "ticks ago" time used to decide which buffered measurements are ready to consume. | ||
| /// </summary> | ||
| internal double TickLatencyAsTime; | ||
|
|
||
| /// <summary> | ||
| /// The render time used by <see cref="NetworkTransform.InterpolationTypes.LegacyLerp"/> only. | ||
| /// </summary> | ||
| internal double LegacyRenderTime; | ||
|
|
||
| internal double CurrentTime; | ||
| internal double MinDeltaTime; | ||
| internal double MaxDeltaTime; | ||
|
|
||
| internal NetworkTransform.InterpolationTypes PositionInterpolationType; | ||
| internal NetworkTransform.InterpolationTypes RotationInterpolationType; | ||
| internal NetworkTransform.InterpolationTypes ScaleInterpolationType; | ||
|
|
||
| internal bool SynchronizePosition; | ||
| internal bool SynchronizeRotation; | ||
| internal bool SynchronizeScale; | ||
|
|
||
| // Results, read back on the main thread and applied to the transform there. | ||
| internal float4 InterpolatedPosition; | ||
| internal float4 InterpolatedRotation; | ||
| internal float4 InterpolatedScale; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Non-Authority Only: | ||
| /// Handles interpolation for every registered non-authority <see cref="NetworkTransform"/> in | ||
| /// a parallel job. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// This performs the buffer consumption and interpolation between two state updates only.<br /> | ||
| /// Applying the results to the transforms stays on the main thread, which keeps this job free | ||
| /// of hierarchy write ordering.<br /> | ||
| /// Each entry owns its own slice of <see cref="BufferedItems"/>, so no two indices address the same items.<br /> | ||
| /// The whole array can be written without aliasing (access is to a distinct, independent memory region). | ||
| /// </remarks> | ||
| [BurstCompile] | ||
| internal struct InterpolateTransformJob : IJobParallelFor | ||
| { | ||
| public NativeArray<InterpolationEntry> Entries; | ||
|
|
||
| /// <summary> | ||
| /// The shared state measurement storage. Disabling the safety restriction is what allows each index to write | ||
| /// into its own slice of one array; <see cref="NativeInterpolatorState.BufferOffset"/> keeps those | ||
| /// slices disjoint. | ||
| /// </summary> | ||
| [NativeDisableParallelForRestriction] | ||
| public NativeArray<BufferedItemNative> BufferedItems; | ||
|
|
||
| public void Execute(int index) | ||
| { | ||
| var entry = Entries[index]; | ||
|
|
||
| if (entry.SynchronizePosition) | ||
| { | ||
| entry.InterpolatedPosition = Advance(ref entry.Position, ref entry, entry.PositionInterpolationType); | ||
| } | ||
|
|
||
| if (entry.SynchronizeRotation) | ||
| { | ||
| entry.InterpolatedRotation = Advance(ref entry.Rotation, ref entry, entry.RotationInterpolationType); | ||
| } | ||
|
|
||
| if (entry.SynchronizeScale) | ||
| { | ||
| entry.InterpolatedScale = Advance(ref entry.Scale, ref entry, entry.ScaleInterpolationType); | ||
| } | ||
|
|
||
| Entries[index] = entry; | ||
| } | ||
|
|
||
| private float4 Advance(ref NativeInterpolatorState state, ref InterpolationEntry entry, NetworkTransform.InterpolationTypes interpolationType) | ||
| { | ||
| if (interpolationType == NetworkTransform.InterpolationTypes.LegacyLerp) | ||
| { | ||
| return NativeInterpolator.UpdateLegacy(ref state, ref BufferedItems, entry.DeltaTime, entry.LegacyRenderTime, entry.CurrentTime); | ||
| } | ||
|
|
||
| return NativeInterpolator.Update(ref state, ref BufferedItems, entry.DeltaTime, entry.TickLatencyAsTime, | ||
|
Check warning on line 107 in com.unity.netcode.gameobjects/Runtime/Components/Interpolator/InterpolateTransformJob.cs
|
||
| entry.MinDeltaTime, entry.MaxDeltaTime, interpolationType == NetworkTransform.InterpolationTypes.Lerp); | ||
| } | ||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we deprecate UseUnreliableDeltas, then we can remove this, but if we do not then we have to make sure users know this (even though I doubt there are many users actually using that feature).