This repository has been archived on 2025-04-22. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
com.unity.netcode.gameobjects/Runtime/Messaging/Messages/DestroyObjectMessage.cs
Unity Technologies 63c7e4c78a com.unity.netcode.gameobjects@2.0.0-exp.4
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).

## [2.0.0-exp.4] - 2024-05-31

### Added

- Added `NetworkRigidbodyBase.AttachToFixedJoint` and `NetworkRigidbodyBase.DetachFromFixedJoint` to replace parenting for rigid bodies that have `NetworkRigidbodyBase.UseRigidBodyForMotion` enabled. (#2933)
- Added `NetworkBehaviour.OnNetworkPreSpawn` and `NetworkBehaviour.OnNetworkPostSpawn` methods that provide the ability to handle pre and post spawning actions during the `NetworkObject` spawn sequence. (#2912)
- Added a client-side only `NetworkBehaviour.OnNetworkSessionSynchronized` convenience method that is invoked on all `NetworkBehaviour`s after a newly joined client has finished synchronizing with the network session in progress. (#2912)
- Added `NetworkBehaviour.OnInSceneObjectsSpawned` convenience method that is invoked when all in-scene `NetworkObject`s have been spawned after a scene has been loaded or upon a host or server starting. (#2912)

### Fixed

- Fixed issue where non-authoritative rigid bodies with `NetworkRigidbodyBase.UseRigidBodyForMotion` enabled would constantly log errors about the renderTime being before `StartTimeConsumed`. (#2933)
- Fixed issue where in-scene placed NetworkObjects could be destroyed if a client disconnects early and/or before approval. (#2924)
- Fixed issue where a `NetworkObject` component's associated `NetworkBehaviour` components would not be detected if scene loading is disabled in the editor and the currently loaded scene has in-scene placed `NetworkObject`s. (#2912)
- Fixed issue where an in-scene placed `NetworkObject` with `NetworkTransform` that is also parented under a `GameObject` would not properly synchronize when the parent `GameObject` had a world space position other than 0,0,0. (#2898)

### Changed

- Change all the access modifiers of test class from Public to Internal (#2930)
- Changed messages are now sorted by enum values as opposed to ordinally sorting the messages by their type name. (#2929)
- Changed `NetworkClient.SessionModeTypes` to `NetworkClient.NetworkTopologyTypes`. (#2875)
- Changed `NetworkClient.SessionModeType` to `NetworkClient.NetworkTopologyType`. (#2875)
- Changed `NetworkConfig.SessionMode` to `NeworkConfig.NetworkTopology`. (#2875)
2024-05-31 00:00:00 +00:00

175 lines
7.0 KiB
C#

using System.Linq;
namespace Unity.Netcode
{
internal struct DestroyObjectMessage : INetworkMessage, INetworkSerializeByMemcpy
{
public int Version => 0;
private const string k_Name = "DestroyObjectMessage";
public ulong NetworkObjectId;
public bool DestroyGameObject;
private byte m_DestroyFlags;
internal int DeferredDespawnTick;
// Temporary until we make this a list
internal ulong TargetClientId;
internal bool IsDistributedAuthority;
internal const byte ClientTargetedDestroy = 0x01;
internal bool IsTargetedDestroy
{
get
{
return GetFlag(ClientTargetedDestroy);
}
set
{
SetFlag(value, ClientTargetedDestroy);
}
}
private bool GetFlag(int flag)
{
return (m_DestroyFlags & flag) != 0;
}
private void SetFlag(bool set, byte flag)
{
if (set) { m_DestroyFlags = (byte)(m_DestroyFlags | flag); }
else { m_DestroyFlags = (byte)(m_DestroyFlags & ~flag); }
}
public void Serialize(FastBufferWriter writer, int targetVersion)
{
BytePacker.WriteValueBitPacked(writer, NetworkObjectId);
if (IsDistributedAuthority)
{
writer.WriteByteSafe(m_DestroyFlags);
if (IsTargetedDestroy)
{
BytePacker.WriteValueBitPacked(writer, TargetClientId);
}
BytePacker.WriteValueBitPacked(writer, DeferredDespawnTick);
}
writer.WriteValueSafe(DestroyGameObject);
}
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
{
var networkManager = (NetworkManager)context.SystemOwner;
if (!networkManager.IsClient)
{
return false;
}
ByteUnpacker.ReadValueBitPacked(reader, out NetworkObjectId);
if (networkManager.DistributedAuthorityMode)
{
reader.ReadByteSafe(out m_DestroyFlags);
if (IsTargetedDestroy)
{
ByteUnpacker.ReadValueBitPacked(reader, out TargetClientId);
}
ByteUnpacker.ReadValueBitPacked(reader, out DeferredDespawnTick);
}
reader.ReadValueSafe(out DestroyGameObject);
if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out var networkObject))
{
// 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;
}
public void Handle(ref NetworkContext context)
{
var networkManager = (NetworkManager)context.SystemOwner;
var networkObject = (NetworkObject)null;
if (!networkManager.DistributedAuthorityMode)
{
// If this NetworkObject does not exist on this instance then exit early
if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out networkObject))
{
return;
}
}
else
{
networkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out networkObject);
if (!networkManager.DAHost && networkObject == null)
{
// If this NetworkObject does not exist on this instance then exit early
return;
}
}
// DANGO-TODO: This is just a quick way to foward despawn messages to the remaining clients
if (networkManager.DistributedAuthorityMode && networkManager.DAHost)
{
var message = new DestroyObjectMessage
{
NetworkObjectId = NetworkObjectId,
DestroyGameObject = DestroyGameObject,
IsDistributedAuthority = true,
IsTargetedDestroy = IsTargetedDestroy,
TargetClientId = TargetClientId, // Just always populate this value whether we write it or not
DeferredDespawnTick = DeferredDespawnTick,
};
var ownerClientId = networkObject == null ? context.SenderId : networkObject.OwnerClientId;
var clientIds = networkObject == null ? networkManager.ConnectedClientsIds.ToList() : networkObject.Observers.ToList();
foreach (var clientId in clientIds)
{
if (clientId == networkManager.LocalClientId || clientId == ownerClientId)
{
continue;
}
networkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, clientId);
}
}
// If we are deferring the despawn, then add it to the deferred despawn queue
if (networkManager.DistributedAuthorityMode)
{
if (DeferredDespawnTick > 0)
{
// Clients always add it to the queue while DAHost will only add it to the queue if it is not a targeted destroy or it is and the target is the
// DAHost client.
if (!networkManager.DAHost || (networkManager.DAHost && (!IsTargetedDestroy || (IsTargetedDestroy && TargetClientId == 0))))
{
networkObject.DeferredDespawnTick = DeferredDespawnTick;
var hasCallback = networkObject.OnDeferredDespawnComplete != null;
networkManager.SpawnManager.DeferDespawnNetworkObject(NetworkObjectId, DeferredDespawnTick, hasCallback);
return;
}
}
// If this is targeted and we are not the target, then just update our local observers for this object
if (IsTargetedDestroy && TargetClientId != networkManager.LocalClientId && networkObject != null)
{
networkObject.Observers.Remove(TargetClientId);
return;
}
}
if (networkObject != null)
{
// Otherwise just despawn the NetworkObject right now
networkManager.SpawnManager.OnDespawnObject(networkObject, DestroyGameObject);
networkManager.NetworkMetrics.TrackObjectDestroyReceived(context.SenderId, networkObject, context.MessageSize);
}
}
}
}