Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Additional documentation and release notes are available at [Multiplayer Documen

### Added

- Added support for serializing `NativeArray<>` and `NativeList<>` in `FastBufferReader`/`FastBufferWriter`, `BufferSerializer`, `NetworkVariable`, and RPCs. (#2375)
- The location of the automatically-created default network prefab list can now be configured (#2544)
- Added: Message size limits (max single message and max fragmented message) can now be set using NetworkManager.SetMaxSingleMessageSize() and NetworkManager.SetMaxFragmentedMessageSize() for transports that don't work with the default values (#2530)
- Added `NetworkObject.SpawnWithObservers` property (default is true) that when set to false will spawn a `NetworkObject` with no observers and will not be spawned on any client until `NetworkObject.NetworkShow` is invoked. (#2568)
Expand Down
269 changes: 238 additions & 31 deletions com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ private void ProcessNetworkBehaviour(TypeDefinition typeDefinition)
if (methodDefinition.Name == nameof(NetworkBehaviour.__beginSendServerRpc) ||
methodDefinition.Name == nameof(NetworkBehaviour.__endSendServerRpc) ||
methodDefinition.Name == nameof(NetworkBehaviour.__beginSendClientRpc) ||
methodDefinition.Name == nameof(NetworkBehaviour.__endSendClientRpc) || methodDefinition.Name == nameof(NetworkBehaviour.__initializeVariables) || methodDefinition.Name == nameof(NetworkBehaviour.__nameNetworkVariable))
methodDefinition.Name == nameof(NetworkBehaviour.__endSendClientRpc) ||
methodDefinition.Name == nameof(NetworkBehaviour.__initializeVariables) ||
methodDefinition.Name == nameof(NetworkBehaviour.__nameNetworkVariable) ||
methodDefinition.Name == nameof(NetworkBehaviour.__createNativeList))
{
methodDefinition.IsFamily = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,14 @@ internal void __endSendClientRpc(ref FastBufferWriter bufferWriter, uint rpcMeth
#endif
}

#pragma warning disable IDE1006 // disable naming rule violation check
// RuntimeAccessModifiersILPP will make this `protected`
internal static NativeList<T> __createNativeList<T>() where T : unmanaged
#pragma warning restore IDE1006 // restore naming rule violation check
{
return new NativeList<T>(Allocator.Temp);
}

internal string GenerateObserverErrorMessage(ClientRpcParams clientRpcParams, ulong targetClientId)
{
var containerNameHoldingId = clientRpcParams.Send.TargetClientIds != null ? nameof(ClientRpcParams.Send.TargetClientIds) : nameof(ClientRpcParams.Send.TargetClientIdsNativeArray);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ public NetworkVariable(T value = default,
: base(readPerm, writePerm)
{
m_InternalValue = value;
// Since we start with IsDirty = true, this doesn't need to be duplicated
// right away. It won't get read until after ResetDirty() is called, and
// the duplicate will be made there. Avoiding calling
// NetworkVariableSerialization<T>.Duplicate() is important because calling
// it in the constructor might not give users enough time to set the
// DuplicateValue callback if they're using UserNetworkVariableSerialization
m_PreviousValue = default;
}

/// <summary>
Expand All @@ -41,6 +48,11 @@ public NetworkVariable(T value = default,
[SerializeField]
private protected T m_InternalValue;

private protected T m_PreviousValue;

private bool m_HasPreviousValue;
private bool m_IsDisposed;

/// <summary>
/// The value of the NetworkVariable container
/// </summary>
Expand All @@ -61,9 +73,83 @@ public virtual T Value
}

Set(value);
m_IsDisposed = false;
}
}

internal ref T RefValue()
{
return ref m_InternalValue;
}

public override void Dispose()
{
if (m_IsDisposed)
{
return;
}

m_IsDisposed = true;
if (m_InternalValue is IDisposable internalValueDisposable)
{
internalValueDisposable.Dispose();
}

m_InternalValue = default;
if (m_HasPreviousValue && m_PreviousValue is IDisposable previousValueDisposable)
{
m_HasPreviousValue = false;
previousValueDisposable.Dispose();
}

m_PreviousValue = default;
}

~NetworkVariable()
{
Dispose();
}

/// <summary>
/// Gets Whether or not the container is dirty
/// </summary>
/// <returns>Whether or not the container is dirty</returns>
public override bool IsDirty()
{
// For most cases we can use the dirty flag.
// This doesn't work for cases where we're wrapping more complex types
// like INetworkSerializable, NativeList, NativeArray, etc.
// Changes to the values in those types don't call the Value.set method,
// so we can't catch those changes and need to compare the current value
// against the previous one.
if (base.IsDirty())
{
return true;
}

// Cache the dirty value so we don't perform this again if we already know we're dirty
// Unfortunately we can't cache the NOT dirty state, because that might change
// in between to checks... but the DIRTY state won't change until ResetDirty()
// is called.
var dirty = !NetworkVariableSerialization<T>.AreEqual(ref m_PreviousValue, ref m_InternalValue);
SetDirty(dirty);
return dirty;
}

/// <summary>
/// Resets the dirty state and marks the variable as synced / clean
/// </summary>
public override void ResetDirty()
{
base.ResetDirty();
// Resetting the dirty value declares that the current value is not dirty
// Therefore, we set the m_PreviousValue field to a duplicate of the current
// field, so that our next dirty check is made against the current "not dirty"
// value.
m_HasPreviousValue = true;
NetworkVariableSerialization<T>.Serializer.Duplicate(m_InternalValue, ref m_PreviousValue);
}

/// <summary>
/// Sets the <see cref="Value"/>, marks the <see cref="NetworkVariable{T}"/> dirty, and invokes the <see cref="OnValueChanged"/> callback
/// if there are subscribers to that event.
Expand Down
Loading