@@ -765,6 +765,13 @@ public virtual void OnGainedOwnership() { }
765
765
internal void InternalOnGainedOwnership ( )
766
766
{
767
767
UpdateNetworkProperties ( ) ;
768
+ // New owners need to assure any NetworkVariables they have write permissions
769
+ // to are updated so the previous and original values are aligned with the
770
+ // current value (primarily for collections).
771
+ if ( OwnerClientId == NetworkManager . LocalClientId )
772
+ {
773
+ UpdateNetworkVariableOnOwnershipChanged ( ) ;
774
+ }
768
775
OnGainedOwnership ( ) ;
769
776
}
770
777
@@ -946,20 +953,20 @@ internal void PreVariableUpdate()
946
953
PreNetworkVariableWrite ( ) ;
947
954
}
948
955
949
- internal void VariableUpdate ( ulong targetClientId )
950
- {
951
- NetworkVariableUpdate ( targetClientId , NetworkBehaviourId ) ;
952
- }
953
-
954
956
internal readonly List < int > NetworkVariableIndexesToReset = new List < int > ( ) ;
955
957
internal readonly HashSet < int > NetworkVariableIndexesToResetSet = new HashSet < int > ( ) ;
956
958
957
- private void NetworkVariableUpdate ( ulong targetClientId , int behaviourIndex )
959
+ internal void NetworkVariableUpdate ( ulong targetClientId , int behaviourIndex , bool forceSend = false )
958
960
{
959
- if ( ! CouldHaveDirtyNetworkVariables ( ) )
961
+ if ( ! forceSend && ! CouldHaveDirtyNetworkVariables ( ) )
960
962
{
961
963
return ;
962
964
}
965
+ // Getting these ahead of time actually improves performance
966
+ var networkManager = NetworkManager ;
967
+ var networkObject = NetworkObject ;
968
+ var messageManager = networkManager . MessageManager ;
969
+ var connectionManager = networkManager . ConnectionManager ;
963
970
964
971
for ( int j = 0 ; j < m_DeliveryMappedNetworkVariableIndices . Count ; j ++ )
965
972
{
@@ -982,10 +989,14 @@ private void NetworkVariableUpdate(ulong targetClientId, int behaviourIndex)
982
989
var message = new NetworkVariableDeltaMessage
983
990
{
984
991
NetworkObjectId = NetworkObjectId ,
985
- NetworkBehaviourIndex = NetworkObject . GetNetworkBehaviourOrderIndex ( this ) ,
992
+ NetworkBehaviourIndex = networkObject . GetNetworkBehaviourOrderIndex ( this ) ,
986
993
NetworkBehaviour = this ,
987
994
TargetClientId = targetClientId ,
988
- DeliveryMappedNetworkVariableIndex = m_DeliveryMappedNetworkVariableIndices [ j ]
995
+ DeliveryMappedNetworkVariableIndex = m_DeliveryMappedNetworkVariableIndices [ j ] ,
996
+ // By sending the network delivery we can forward messages immediately as opposed to processing them
997
+ // at the end. While this will send updates to clients that cannot read, the handler will ignore anything
998
+ // sent to a client that does not have read permissions.
999
+ NetworkDelivery = m_DeliveryTypesForNetworkVariableGroups [ j ]
989
1000
} ;
990
1001
// TODO: Serialization is where the IsDirty flag gets changed.
991
1002
// Messages don't get sent from the server to itself, so if we're host and sending to ourselves,
@@ -994,15 +1005,15 @@ private void NetworkVariableUpdate(ulong targetClientId, int behaviourIndex)
994
1005
// so we don't have to do this serialization work if we're not going to use the result.
995
1006
if ( IsServer && targetClientId == NetworkManager . ServerClientId )
996
1007
{
997
- var tmpWriter = new FastBufferWriter ( NetworkManager . MessageManager . NonFragmentedMessageMaxSize , Allocator . Temp , NetworkManager . MessageManager . FragmentedMessageMaxSize ) ;
1008
+ var tmpWriter = new FastBufferWriter ( messageManager . NonFragmentedMessageMaxSize , Allocator . Temp , messageManager . FragmentedMessageMaxSize ) ;
998
1009
using ( tmpWriter )
999
1010
{
1000
1011
message . Serialize ( tmpWriter , message . Version ) ;
1001
1012
}
1002
1013
}
1003
1014
else
1004
1015
{
1005
- NetworkManager . ConnectionManager . SendMessage ( ref message , m_DeliveryTypesForNetworkVariableGroups [ j ] , targetClientId ) ;
1016
+ connectionManager . SendMessage ( ref message , m_DeliveryTypesForNetworkVariableGroups [ j ] , targetClientId ) ;
1006
1017
}
1007
1018
}
1008
1019
}
@@ -1029,6 +1040,26 @@ private bool CouldHaveDirtyNetworkVariables()
1029
1040
return false ;
1030
1041
}
1031
1042
1043
+ /// <summary>
1044
+ /// Invoked on a new client to assure the previous and original values
1045
+ /// are synchronized with the current known value.
1046
+ /// </summary>
1047
+ /// <remarks>
1048
+ /// Primarily for collections to assure the previous value(s) is/are the
1049
+ /// same as the current value(s) in order to not re-send already known entries.
1050
+ /// </remarks>
1051
+ internal void UpdateNetworkVariableOnOwnershipChanged ( )
1052
+ {
1053
+ for ( int j = 0 ; j < NetworkVariableFields . Count ; j ++ )
1054
+ {
1055
+ // Only invoke OnInitialize on NetworkVariables the owner can write to
1056
+ if ( NetworkVariableFields [ j ] . CanClientWrite ( OwnerClientId ) )
1057
+ {
1058
+ NetworkVariableFields [ j ] . OnInitialize ( ) ;
1059
+ }
1060
+ }
1061
+ }
1062
+
1032
1063
internal void MarkVariablesDirty ( bool dirty )
1033
1064
{
1034
1065
for ( int j = 0 ; j < NetworkVariableFields . Count ; j ++ )
@@ -1037,6 +1068,17 @@ internal void MarkVariablesDirty(bool dirty)
1037
1068
}
1038
1069
}
1039
1070
1071
+ internal void MarkOwnerReadVariablesDirty ( )
1072
+ {
1073
+ for ( int j = 0 ; j < NetworkVariableFields . Count ; j ++ )
1074
+ {
1075
+ if ( NetworkVariableFields [ j ] . ReadPerm == NetworkVariableReadPermission . Owner )
1076
+ {
1077
+ NetworkVariableFields [ j ] . SetDirty ( true ) ;
1078
+ }
1079
+ }
1080
+ }
1081
+
1040
1082
/// <summary>
1041
1083
/// Synchronizes by setting only the NetworkVariable field values that the client has permission to read.
1042
1084
/// Note: This is only invoked when first synchronizing a NetworkBehaviour (i.e. late join or spawned NetworkObject)
@@ -1067,15 +1109,23 @@ internal void WriteNetworkVariableData(FastBufferWriter writer, ulong targetClie
1067
1109
// The way we do packing, any value > 63 in a ushort will use the full 2 bytes to represent.
1068
1110
writer . WriteValueSafe ( ( ushort ) 0 ) ;
1069
1111
var startPos = writer . Position ;
1070
- NetworkVariableFields [ j ] . WriteField ( writer ) ;
1112
+ // Write the NetworkVariable field value
1113
+ // WriteFieldSynchronization will write the current value only if there are no pending changes.
1114
+ // Otherwise, it will write the previous value if there are pending changes since the pending
1115
+ // changes will be sent shortly after the client's synchronization.
1116
+ NetworkVariableFields [ j ] . WriteFieldSynchronization ( writer ) ;
1071
1117
var size = writer . Position - startPos ;
1072
1118
writer . Seek ( writePos ) ;
1073
1119
writer . WriteValueSafe ( ( ushort ) size ) ;
1074
1120
writer . Seek ( startPos + size ) ;
1075
1121
}
1076
1122
else
1077
1123
{
1078
- NetworkVariableFields [ j ] . WriteField ( writer ) ;
1124
+ // Write the NetworkVariable field value
1125
+ // WriteFieldSynchronization will write the current value only if there are no pending changes.
1126
+ // Otherwise, it will write the previous value if there are pending changes since the pending
1127
+ // changes will be sent shortly after the client's synchronization.
1128
+ NetworkVariableFields [ j ] . WriteFieldSynchronization ( writer ) ;
1079
1129
}
1080
1130
}
1081
1131
else // Only if EnsureNetworkVariableLengthSafety, otherwise just skip
0 commit comments