Skip to content

feat: Optimize DestroyObject message #3304

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

Merged
merged 3 commits into from
Feb 19, 2025
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 @@ -24,6 +24,7 @@ Additional documentation and release notes are available at [Multiplayer Documen

### Changed

- Changed the `DestroyObject` message to reduce the serialized message size and remove the unnecessary message field. (#3304)
- Changed the `NetworkTimeSystem.Sync` method to use half RTT to calculate the desired local time offset as opposed to the full RTT. (#3212)

## [2.2.0] - 2024-12-12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ namespace Unity.Netcode
{
internal struct DestroyObjectMessage : INetworkMessage, INetworkSerializeByMemcpy
{
public int Version => 0;
private const int k_OptimizeDestroyObjectMessage = 1;
public int Version => k_OptimizeDestroyObjectMessage;

private const string k_Name = "DestroyObjectMessage";

public ulong NetworkObjectId;

/// <summary>
/// Used to communicate whether to destroy the associated game object.
/// Should be false if the object is InScenePlaced and true otherwise
/// </summary>
public bool DestroyGameObject;
private byte m_DestroyFlags;

Expand All @@ -19,19 +25,21 @@ internal struct DestroyObjectMessage : INetworkMessage, INetworkSerializeByMemcp

internal bool IsDistributedAuthority;

internal const byte ClientTargetedDestroy = 0x01;
private const byte k_ClientTargetedDestroy = 0x01;
private const byte k_DeferredDespawn = 0x02;

internal bool IsTargetedDestroy
{
get
{
return GetFlag(ClientTargetedDestroy);
}
get => GetFlag(k_ClientTargetedDestroy);

set
{
SetFlag(value, ClientTargetedDestroy);
}
set => SetFlag(value, k_ClientTargetedDestroy);
}

private bool IsDeferredDespawn
{
get => GetFlag(k_DeferredDespawn);

set => SetFlag(value, k_DeferredDespawn);
}

private bool GetFlag(int flag)
Expand All @@ -47,7 +55,11 @@ private void SetFlag(bool set, byte flag)

public void Serialize(FastBufferWriter writer, int targetVersion)
{
// Set deferred despawn flag
IsDeferredDespawn = DeferredDespawnTick > 0;

BytePacker.WriteValueBitPacked(writer, NetworkObjectId);

if (IsDistributedAuthority)
{
writer.WriteByteSafe(m_DestroyFlags);
Expand All @@ -56,9 +68,17 @@ public void Serialize(FastBufferWriter writer, int targetVersion)
{
BytePacker.WriteValueBitPacked(writer, TargetClientId);
}
BytePacker.WriteValueBitPacked(writer, DeferredDespawnTick);

if (targetVersion < k_OptimizeDestroyObjectMessage || IsDeferredDespawn)
{
BytePacker.WriteValueBitPacked(writer, DeferredDespawnTick);
}
}

if (targetVersion < k_OptimizeDestroyObjectMessage)
{
writer.WriteValueSafe(DestroyGameObject);
}
writer.WriteValueSafe(DestroyGameObject);
}

public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
Expand All @@ -77,18 +97,27 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
{
ByteUnpacker.ReadValueBitPacked(reader, out TargetClientId);
}
ByteUnpacker.ReadValueBitPacked(reader, out DeferredDespawnTick);

if (receivedMessageVersion < k_OptimizeDestroyObjectMessage || IsDeferredDespawn)
{
ByteUnpacker.ReadValueBitPacked(reader, out DeferredDespawnTick);
}
}

reader.ReadValueSafe(out DestroyGameObject);
if (receivedMessageVersion < k_OptimizeDestroyObjectMessage)
{
reader.ReadValueSafe(out DestroyGameObject);
}

if (!networkManager.SpawnManager.SpawnedObjects.ContainsKey(NetworkObjectId))
if (networkManager.SpawnManager.SpawnedObjects.ContainsKey(NetworkObjectId))
{
// Client-Server mode we always defer where in distributed authority mode we only defer if it is not a targeted destroy
if (!networkManager.DistributedAuthorityMode || (networkManager.DistributedAuthorityMode && !IsTargetedDestroy))
{
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnSpawn, NetworkObjectId, reader, ref context, k_Name);
}
return true;
}

// Client-Server mode we always defer where in distributed authority mode we only defer if it is not a targeted destroy
if (!networkManager.DistributedAuthorityMode || (networkManager.DistributedAuthorityMode && !IsTargetedDestroy))
{
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnSpawn, NetworkObjectId, reader, ref context, k_Name);
}
return true;
}
Expand Down