@@ -9,19 +9,122 @@ namespace Unity.Netcode.Prototyping
9
9
[ AddComponentMenu ( "Netcode/" + nameof ( NetworkTransform ) ) ]
10
10
public class NetworkTransform : NetworkBehaviour
11
11
{
12
- private struct NetworkState : INetworkSerializable
12
+ internal struct NetworkState : INetworkSerializable
13
13
{
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 ;
18
84
19
85
public void NetworkSerialize ( NetworkSerializer serializer )
20
86
{
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
+ }
25
128
}
26
129
}
27
130
@@ -40,82 +143,170 @@ public void NetworkSerialize(NetworkSerializer serializer)
40
143
[ Tooltip ( "Sets whether this transform should sync in local space or in world space" ) ]
41
144
public bool InLocalSpace = false ;
42
145
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
+
43
150
/// <summary>
44
151
/// The base amount of sends per seconds to use when range is disabled
45
152
/// </summary>
46
153
[ SerializeField , Range ( 0 , 120 ) , Tooltip ( "The base amount of sends per seconds to use when range is disabled" ) ]
47
154
public float FixedSendsPerSecond = 30f ;
48
155
49
156
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 ;
52
159
53
- private bool IsNetworkStateDirty ( NetworkState ? networkStateIn )
160
+ internal bool IsNetworkStateDirty ( NetworkState ? networkStateIn )
54
161
{
55
162
if ( networkStateIn == null )
56
163
{
57
164
return false ;
58
165
}
59
166
60
- NetworkState networkState = ( NetworkState ) networkStateIn ;
167
+ var networkState = ( NetworkState ) networkStateIn ;
61
168
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 ;
63
172
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 ) ;
77
207
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 ) ;
79
219
}
80
220
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 )
82
223
{
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 )
85
234
{
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 ;
89
236
}
90
- else
237
+ if ( networkState . HasPositionY )
91
238
{
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 ;
95
240
}
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 )
104
242
{
105
- m_Transform . localPosition = netState . Position ;
106
- m_Transform . localRotation = netState . Rotation ;
107
- m_Transform . localScale = netState . Scale ;
243
+ position . z = networkState . PositionZ ;
108
244
}
109
- else
245
+ // RotAngles Read
246
+ if ( networkState . HasRotAngleX )
247
+ {
248
+ rotAngles . x = networkState . RotAngleX ;
249
+ }
250
+ if ( networkState . HasRotAngleY )
110
251
{
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 ;
116
270
}
117
271
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
+ }
119
310
}
120
311
121
312
private void OnNetworkStateChanged ( NetworkState oldState , NetworkState newState )
@@ -134,20 +325,20 @@ private void Awake()
134
325
{
135
326
m_Transform = transform ;
136
327
137
- m_NetworkState . Settings . SendNetworkChannel = Channel ;
138
- m_NetworkState . Settings . SendTickrate = FixedSendsPerSecond ;
328
+ ReplNetworkState . Settings . SendNetworkChannel = Channel ;
329
+ ReplNetworkState . Settings . SendTickrate = FixedSendsPerSecond ;
139
330
140
- m_NetworkState . OnValueChanged += OnNetworkStateChanged ;
331
+ ReplNetworkState . OnValueChanged += OnNetworkStateChanged ;
141
332
}
142
333
143
334
public override void OnNetworkSpawn ( )
144
335
{
145
- m_PrevNetworkState = null ;
336
+ PrevNetworkState = null ;
146
337
}
147
338
148
339
private void OnDestroy ( )
149
340
{
150
- m_NetworkState . OnValueChanged -= OnNetworkStateChanged ;
341
+ ReplNetworkState . OnValueChanged -= OnNetworkStateChanged ;
151
342
}
152
343
153
344
private void FixedUpdate ( )
@@ -157,18 +348,18 @@ private void FixedUpdate()
157
348
return ;
158
349
}
159
350
160
- if ( IsServer && IsNetworkStateDirty ( m_NetworkState . Value ) )
351
+ if ( IsServer && IsNetworkStateDirty ( ReplNetworkState . Value ) )
161
352
{
162
353
UpdateNetworkState ( ) ;
163
354
}
164
355
else
165
356
{
166
- if ( IsNetworkStateDirty ( m_PrevNetworkState ) )
357
+ if ( IsNetworkStateDirty ( PrevNetworkState ) )
167
358
{
168
359
Debug . LogWarning ( "A local change without authority detected, revert back to latest network state!" ) ;
169
360
}
170
361
171
- ApplyNetworkState ( m_NetworkState . Value ) ;
362
+ ApplyNetworkState ( ReplNetworkState . Value ) ;
172
363
}
173
364
}
174
365
0 commit comments