Skip to content

Commit c3ad039

Browse files
merge stuff
1 parent c85c6fb commit c3ad039

File tree

4 files changed

+306
-277
lines changed

4 files changed

+306
-277
lines changed

com.unity.netcode.gameobjects/Prototyping/NetworkTransform.cs

Lines changed: 255 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,122 @@ namespace Unity.Netcode.Prototyping
99
[AddComponentMenu("Netcode/" + nameof(NetworkTransform))]
1010
public class NetworkTransform : NetworkBehaviour
1111
{
12-
private struct NetworkState : INetworkSerializable
12+
internal struct NetworkState : INetworkSerializable
1313
{
14-
public bool InLocalSpace;
15-
public Vector3 Position;
16-
public Quaternion Rotation;
17-
public Vector3 Scale;
14+
internal const int InLocalSpaceBit = 0;
15+
internal const int PositionXBit = 1;
16+
internal const int PositionYBit = 2;
17+
internal const int PositionZBit = 3;
18+
internal const int RotAngleXBit = 4;
19+
internal const int RotAngleYBit = 5;
20+
internal const int RotAngleZBit = 6;
21+
internal const int ScaleXBit = 7;
22+
internal const int ScaleYBit = 8;
23+
internal const int ScaleZBit = 9;
24+
// 10-15: <unused>
25+
public ushort Bitset;
26+
27+
public bool InLocalSpace
28+
{
29+
get => (Bitset & (1 << InLocalSpaceBit)) != 0;
30+
set => Bitset |= (ushort)((value ? 1 : 0) << InLocalSpaceBit);
31+
}
32+
// Position
33+
public bool HasPositionX
34+
{
35+
get => (Bitset & (1 << PositionXBit)) != 0;
36+
set => Bitset |= (ushort)((value ? 1 : 0) << PositionXBit);
37+
}
38+
public bool HasPositionY
39+
{
40+
get => (Bitset & (1 << PositionYBit)) != 0;
41+
set => Bitset |= (ushort)((value ? 1 : 0) << PositionYBit);
42+
}
43+
public bool HasPositionZ
44+
{
45+
get => (Bitset & (1 << PositionZBit)) != 0;
46+
set => Bitset |= (ushort)((value ? 1 : 0) << PositionZBit);
47+
}
48+
// RotAngles
49+
public bool HasRotAngleX
50+
{
51+
get => (Bitset & (1 << RotAngleXBit)) != 0;
52+
set => Bitset |= (ushort)((value ? 1 : 0) << RotAngleXBit);
53+
}
54+
public bool HasRotAngleY
55+
{
56+
get => (Bitset & (1 << RotAngleYBit)) != 0;
57+
set => Bitset |= (ushort)((value ? 1 : 0) << RotAngleYBit);
58+
}
59+
public bool HasRotAngleZ
60+
{
61+
get => (Bitset & (1 << RotAngleZBit)) != 0;
62+
set => Bitset |= (ushort)((value ? 1 : 0) << RotAngleZBit);
63+
}
64+
// Scale
65+
public bool HasScaleX
66+
{
67+
get => (Bitset & (1 << ScaleXBit)) != 0;
68+
set => Bitset |= (ushort)((value ? 1 : 0) << ScaleXBit);
69+
}
70+
public bool HasScaleY
71+
{
72+
get => (Bitset & (1 << ScaleYBit)) != 0;
73+
set => Bitset |= (ushort)((value ? 1 : 0) << ScaleYBit);
74+
}
75+
public bool HasScaleZ
76+
{
77+
get => (Bitset & (1 << ScaleZBit)) != 0;
78+
set => Bitset |= (ushort)((value ? 1 : 0) << ScaleZBit);
79+
}
80+
81+
public float PositionX, PositionY, PositionZ;
82+
public float RotAngleX, RotAngleY, RotAngleZ;
83+
public float ScaleX, ScaleY, ScaleZ;
1884

1985
public void NetworkSerialize(NetworkSerializer serializer)
2086
{
21-
serializer.Serialize(ref InLocalSpace);
22-
serializer.Serialize(ref Position);
23-
serializer.Serialize(ref Rotation);
24-
serializer.Serialize(ref Scale);
87+
// InLocalSpace + HasXXX Bits
88+
serializer.Serialize(ref Bitset);
89+
// Position Values
90+
if (HasPositionX)
91+
{
92+
serializer.Serialize(ref PositionX);
93+
}
94+
if (HasPositionY)
95+
{
96+
serializer.Serialize(ref PositionY);
97+
}
98+
if (HasPositionZ)
99+
{
100+
serializer.Serialize(ref PositionZ);
101+
}
102+
// RotAngle Values
103+
if (HasRotAngleX)
104+
{
105+
serializer.Serialize(ref RotAngleX);
106+
}
107+
if (HasRotAngleY)
108+
{
109+
serializer.Serialize(ref RotAngleY);
110+
}
111+
if (HasRotAngleZ)
112+
{
113+
serializer.Serialize(ref RotAngleZ);
114+
}
115+
// Scale Values
116+
if (HasScaleX)
117+
{
118+
serializer.Serialize(ref ScaleX);
119+
}
120+
if (HasScaleY)
121+
{
122+
serializer.Serialize(ref ScaleY);
123+
}
124+
if (HasScaleZ)
125+
{
126+
serializer.Serialize(ref ScaleZ);
127+
}
25128
}
26129
}
27130

@@ -40,82 +143,170 @@ public void NetworkSerialize(NetworkSerializer serializer)
40143
[Tooltip("Sets whether this transform should sync in local space or in world space")]
41144
public bool InLocalSpace = false;
42145

146+
public bool SyncPositionX = true, SyncPositionY = true, SyncPositionZ = true;
147+
public bool SyncRotAngleX = true, SyncRotAngleY = true, SyncRotAngleZ = true;
148+
public bool SyncScaleX = true, SyncScaleY = true, SyncScaleZ = true;
149+
43150
/// <summary>
44151
/// The base amount of sends per seconds to use when range is disabled
45152
/// </summary>
46153
[SerializeField, Range(0, 120), Tooltip("The base amount of sends per seconds to use when range is disabled")]
47154
public float FixedSendsPerSecond = 30f;
48155

49156
private Transform m_Transform; // cache the transform component to reduce unnecessary bounce between managed and native
50-
private readonly NetworkVariable<NetworkState> m_NetworkState = new NetworkVariable<NetworkState>(new NetworkState());
51-
private NetworkState? m_PrevNetworkState;
157+
internal readonly NetworkVariable<NetworkState> ReplNetworkState = new NetworkVariable<NetworkState>(new NetworkState());
158+
internal NetworkState? PrevNetworkState;
52159

53-
private bool IsNetworkStateDirty(NetworkState? networkStateIn)
160+
internal bool IsNetworkStateDirty(NetworkState? networkStateIn)
54161
{
55162
if (networkStateIn == null)
56163
{
57164
return false;
58165
}
59166

60-
NetworkState networkState = (NetworkState)networkStateIn;
167+
var networkState = (NetworkState)networkStateIn;
61168

62-
bool isDirty = false;
169+
var position = InLocalSpace ? m_Transform.localPosition : m_Transform.position;
170+
var rotAngles = InLocalSpace ? m_Transform.localEulerAngles : m_Transform.eulerAngles;
171+
var scale = InLocalSpace ? m_Transform.localScale : m_Transform.lossyScale;
63172

64-
isDirty |= networkState.InLocalSpace != InLocalSpace;
65-
if (InLocalSpace)
66-
{
67-
isDirty |= networkState.Position != m_Transform.localPosition;
68-
isDirty |= networkState.Rotation != m_Transform.localRotation;
69-
isDirty |= networkState.Scale != m_Transform.localScale;
70-
}
71-
else
72-
{
73-
isDirty |= networkState.Position != m_Transform.position;
74-
isDirty |= networkState.Rotation != m_Transform.rotation;
75-
isDirty |= networkState.Scale != m_Transform.lossyScale;
76-
}
173+
return
174+
// InLocalSpace Check
175+
(InLocalSpace != networkState.InLocalSpace) ||
176+
// Position Check
177+
(SyncPositionX && !Mathf.Approximately(position.x, networkState.PositionX)) ||
178+
(SyncPositionY && !Mathf.Approximately(position.y, networkState.PositionY)) ||
179+
(SyncPositionZ && !Mathf.Approximately(position.z, networkState.PositionZ)) ||
180+
// RotAngles Check
181+
(SyncRotAngleX && !Mathf.Approximately(rotAngles.x, networkState.RotAngleX)) ||
182+
(SyncRotAngleY && !Mathf.Approximately(rotAngles.y, networkState.RotAngleY)) ||
183+
(SyncRotAngleZ && !Mathf.Approximately(rotAngles.z, networkState.RotAngleZ)) ||
184+
// Scale Check
185+
(SyncScaleX && !Mathf.Approximately(scale.x, networkState.ScaleX)) ||
186+
(SyncScaleY && !Mathf.Approximately(scale.y, networkState.ScaleY)) ||
187+
(SyncScaleZ && !Mathf.Approximately(scale.z, networkState.ScaleZ));
188+
}
189+
190+
internal void UpdateNetworkState()
191+
{
192+
var position = InLocalSpace ? m_Transform.localPosition : m_Transform.position;
193+
var rotAngles = InLocalSpace ? m_Transform.localEulerAngles : m_Transform.eulerAngles;
194+
var scale = InLocalSpace ? m_Transform.localScale : m_Transform.lossyScale;
195+
196+
// InLocalSpace Bit
197+
ReplNetworkState.ValueRef.InLocalSpace = InLocalSpace;
198+
// Position Bits
199+
(ReplNetworkState.ValueRef.HasPositionX, ReplNetworkState.ValueRef.HasPositionY, ReplNetworkState.ValueRef.HasPositionZ) =
200+
(SyncPositionX, SyncPositionY, SyncPositionZ);
201+
// RotAngle Bits
202+
(ReplNetworkState.ValueRef.HasRotAngleX, ReplNetworkState.ValueRef.HasRotAngleY, ReplNetworkState.ValueRef.HasRotAngleZ) =
203+
(SyncRotAngleX, SyncRotAngleY, SyncRotAngleZ);
204+
// Scale Bits
205+
(ReplNetworkState.ValueRef.HasScaleX, ReplNetworkState.ValueRef.HasScaleY, ReplNetworkState.ValueRef.HasScaleZ) =
206+
(SyncScaleX, SyncScaleY, SyncScaleZ);
77207

78-
return isDirty;
208+
// Position Values
209+
(ReplNetworkState.ValueRef.PositionX, ReplNetworkState.ValueRef.PositionY, ReplNetworkState.ValueRef.PositionZ) =
210+
(position.x, position.y, position.z);
211+
// RotAngle Values
212+
(ReplNetworkState.ValueRef.RotAngleX, ReplNetworkState.ValueRef.RotAngleY, ReplNetworkState.ValueRef.RotAngleZ) =
213+
(rotAngles.x, rotAngles.y, rotAngles.z);
214+
// Scale Values
215+
(ReplNetworkState.ValueRef.ScaleX, ReplNetworkState.ValueRef.ScaleY, ReplNetworkState.ValueRef.ScaleZ) =
216+
(scale.x, scale.y, scale.z);
217+
218+
ReplNetworkState.SetDirty(true);
79219
}
80220

81-
private void UpdateNetworkState()
221+
// TODO: temporary! the function body below probably needs to be rewritten later with interpolation in mind
222+
internal void ApplyNetworkState(NetworkState networkState)
82223
{
83-
m_NetworkState.ValueRef.InLocalSpace = InLocalSpace;
84-
if (InLocalSpace)
224+
PrevNetworkState = networkState;
225+
226+
var position = InLocalSpace ? m_Transform.localPosition : m_Transform.position;
227+
var rotAngles = InLocalSpace ? m_Transform.localEulerAngles : m_Transform.eulerAngles;
228+
var scale = InLocalSpace ? m_Transform.localScale : m_Transform.lossyScale;
229+
230+
// InLocalSpace Read
231+
InLocalSpace = networkState.InLocalSpace;
232+
// Position Read
233+
if (networkState.HasPositionX)
85234
{
86-
m_NetworkState.ValueRef.Position = m_Transform.localPosition;
87-
m_NetworkState.ValueRef.Rotation = m_Transform.localRotation;
88-
m_NetworkState.ValueRef.Scale = m_Transform.localScale;
235+
position.x = networkState.PositionX;
89236
}
90-
else
237+
if (networkState.HasPositionY)
91238
{
92-
m_NetworkState.ValueRef.Position = m_Transform.position;
93-
m_NetworkState.ValueRef.Rotation = m_Transform.rotation;
94-
m_NetworkState.ValueRef.Scale = m_Transform.lossyScale;
239+
position.y = networkState.PositionY;
95240
}
96-
97-
m_NetworkState.SetDirty(true);
98-
}
99-
100-
private void ApplyNetworkState(NetworkState netState)
101-
{
102-
InLocalSpace = netState.InLocalSpace;
103-
if (InLocalSpace)
241+
if (networkState.HasPositionZ)
104242
{
105-
m_Transform.localPosition = netState.Position;
106-
m_Transform.localRotation = netState.Rotation;
107-
m_Transform.localScale = netState.Scale;
243+
position.z = networkState.PositionZ;
108244
}
109-
else
245+
// RotAngles Read
246+
if (networkState.HasRotAngleX)
247+
{
248+
rotAngles.x = networkState.RotAngleX;
249+
}
250+
if (networkState.HasRotAngleY)
110251
{
111-
m_Transform.position = netState.Position;
112-
m_Transform.rotation = netState.Rotation;
113-
m_Transform.localScale = Vector3.one;
114-
var lossyScale = m_Transform.lossyScale;
115-
m_Transform.localScale = new Vector3(netState.Scale.x / lossyScale.x, netState.Scale.y / lossyScale.y, netState.Scale.z / lossyScale.z);
252+
rotAngles.y = networkState.RotAngleY;
253+
}
254+
if (networkState.HasRotAngleZ)
255+
{
256+
rotAngles.z = networkState.RotAngleZ;
257+
}
258+
// Scale Read
259+
if (networkState.HasScaleX)
260+
{
261+
scale.x = networkState.ScaleX;
262+
}
263+
if (networkState.HasScaleY)
264+
{
265+
scale.y = networkState.ScaleY;
266+
}
267+
if (networkState.HasScaleZ)
268+
{
269+
scale.z = networkState.ScaleZ;
116270
}
117271

118-
m_PrevNetworkState = netState;
272+
// Position Apply
273+
if (networkState.HasPositionX || networkState.HasPositionY || networkState.HasPositionZ)
274+
{
275+
if (InLocalSpace)
276+
{
277+
m_Transform.localPosition = position;
278+
}
279+
else
280+
{
281+
m_Transform.position = position;
282+
}
283+
}
284+
// RotAngles Apply
285+
if (networkState.HasRotAngleX || networkState.HasRotAngleY || networkState.HasRotAngleZ)
286+
{
287+
if (InLocalSpace)
288+
{
289+
m_Transform.localEulerAngles = rotAngles;
290+
}
291+
else
292+
{
293+
m_Transform.eulerAngles = rotAngles;
294+
}
295+
}
296+
// Scale Apply
297+
if (networkState.HasScaleX || networkState.HasScaleY || networkState.HasScaleZ)
298+
{
299+
if (InLocalSpace)
300+
{
301+
m_Transform.localScale = scale;
302+
}
303+
else
304+
{
305+
m_Transform.localScale = Vector3.one;
306+
var lossyScale = m_Transform.lossyScale;
307+
m_Transform.localScale = new Vector3(networkState.ScaleX / lossyScale.x, networkState.ScaleY / lossyScale.y, networkState.ScaleZ / lossyScale.z);
308+
}
309+
}
119310
}
120311

121312
private void OnNetworkStateChanged(NetworkState oldState, NetworkState newState)
@@ -134,20 +325,20 @@ private void Awake()
134325
{
135326
m_Transform = transform;
136327

137-
m_NetworkState.Settings.SendNetworkChannel = Channel;
138-
m_NetworkState.Settings.SendTickrate = FixedSendsPerSecond;
328+
ReplNetworkState.Settings.SendNetworkChannel = Channel;
329+
ReplNetworkState.Settings.SendTickrate = FixedSendsPerSecond;
139330

140-
m_NetworkState.OnValueChanged += OnNetworkStateChanged;
331+
ReplNetworkState.OnValueChanged += OnNetworkStateChanged;
141332
}
142333

143334
public override void OnNetworkSpawn()
144335
{
145-
m_PrevNetworkState = null;
336+
PrevNetworkState = null;
146337
}
147338

148339
private void OnDestroy()
149340
{
150-
m_NetworkState.OnValueChanged -= OnNetworkStateChanged;
341+
ReplNetworkState.OnValueChanged -= OnNetworkStateChanged;
151342
}
152343

153344
private void FixedUpdate()
@@ -157,18 +348,18 @@ private void FixedUpdate()
157348
return;
158349
}
159350

160-
if (IsServer && IsNetworkStateDirty(m_NetworkState.Value))
351+
if (IsServer && IsNetworkStateDirty(ReplNetworkState.Value))
161352
{
162353
UpdateNetworkState();
163354
}
164355
else
165356
{
166-
if (IsNetworkStateDirty(m_PrevNetworkState))
357+
if (IsNetworkStateDirty(PrevNetworkState))
167358
{
168359
Debug.LogWarning("A local change without authority detected, revert back to latest network state!");
169360
}
170361

171-
ApplyNetworkState(m_NetworkState.Value);
362+
ApplyNetworkState(ReplNetworkState.Value);
172363
}
173364
}
174365

0 commit comments

Comments
 (0)