com.unity.netcode.gameobjects@1.0.0-pre.2

# Changelog

All notable changes to this project will be documented in this file.

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).

## [1.0.0-pre.2] - 2020-12-20

### Added

- Associated Known Issues for the 1.0.0-pre.1 release in the changelog

### Changed

- Updated label for `1.0.0-pre.1` changelog section

## [1.0.0-pre.1] - 2020-12-20

### Added

- Added `ClientNetworkTransform` sample to the SDK package (#1168)
- Added `Bootstrap` sample to the SDK package (#1140)
- Enhanced `NetworkSceneManager` implementation with additive scene loading capabilities (#1080, #955, #913)
  - `NetworkSceneManager.OnSceneEvent` provides improved scene event notificaitons
- Enhanced `NetworkTransform` implementation with per axis/component based and threshold based state replication (#1042, #1055, #1061, #1084, #1101)
- Added a jitter-resistent `BufferedLinearInterpolator<T>` for `NetworkTransform` (#1060)
- Implemented `NetworkPrefabHandler` that provides support for object pooling and `NetworkPrefab` overrides (#1073, #1004, #977, #905,#749, #727)
- Implemented auto `NetworkObject` transform parent synchronization at runtime over the network (#855)
- Adopted Unity C# Coding Standards in the codebase with `.editorconfig` ruleset (#666, #670)
- When a client tries to spawn a `NetworkObject` an exception is thrown to indicate unsupported behavior. (#981)
- Added a `NetworkTime` and `NetworkTickSystem` which allows for improved control over time and ticks. (#845)
- Added a `OnNetworkDespawn` function to `NetworkObject` which gets called when a `NetworkObject` gets despawned and can be overriden. (#865)
- Added `SnapshotSystem` that would allow variables and spawn/despawn messages to be sent in blocks (#805, #852, #862, #963, #1012, #1013, #1021, #1040, #1062, #1064, #1083, #1091, #1111, #1129, #1166, #1192)
  - Disabled by default for now, except spawn/despawn messages
  - Will leverage unreliable messages with eventual consistency
- `NetworkBehaviour` and `NetworkObject`'s `NetworkManager` instances can now be overriden (#762)
- Added metrics reporting for the new network profiler if the Multiplayer Tools package is present (#1104, #1089, #1096, #1086, #1072, #1058, #960, #897, #891, #878)
- `NetworkBehaviour.IsSpawned` a quick (and stable) way to determine if the associated NetworkObject is spawned (#1190)
- Added `NetworkRigidbody` and `NetworkRigidbody2D` components to support networking `Rigidbody` and `Rigidbody2D` components (#1202, #1175)
- Added `NetworkObjectReference` and `NetworkBehaviourReference` structs which allow to sending `NetworkObject/Behaviours` over RPCs/`NetworkVariable`s (#1173)
- Added `NetworkAnimator` component to support networking `Animator` component (#1281, #872)

### Changed

- Bumped minimum Unity version, renamed package as "Unity Netcode for GameObjects", replaced `MLAPI` namespace and its variants with `Unity.Netcode` namespace and per asm-def variants (#1007, #1009, #1015, #1017, #1019, #1025, #1026, #1065)
  - Minimum Unity version:
    - 2019.4 → 2020.3+
  - Package rename:
    - Display name: `MLAPI Networking Library` → `Netcode for GameObjects`
    - Name: `com.unity.multiplayer.mlapi` → `com.unity.netcode.gameobjects`
    - Updated package description
  - All `MLAPI.x` namespaces are replaced with `Unity.Netcode`
    - `MLAPI.Messaging` → `Unity.Netcode`
    - `MLAPI.Connection` → `Unity.Netcode`
    - `MLAPI.Logging` → `Unity.Netcode`
    - `MLAPI.SceneManagement` → `Unity.Netcode`
    - and other `MLAPI.x` variants to `Unity.Netcode`
  - All assembly definitions are renamed with `Unity.Netcode.x` variants
    - `Unity.Multiplayer.MLAPI.Runtime` → `Unity.Netcode.Runtime`
    - `Unity.Multiplayer.MLAPI.Editor` → `Unity.Netcode.Editor`
    - and other `Unity.Multiplayer.MLAPI.x` variants to `Unity.Netcode.x` variants
- Renamed `Prototyping` namespace and assembly definition to `Components` (#1145)
- Changed `NetworkObject.Despawn(bool destroy)` API to default to `destroy = true` for better usability (#1217)
- Scene registration in `NetworkManager` is now replaced by Build Setttings → Scenes in Build List (#1080)
- `NetworkSceneManager.SwitchScene` has been replaced by `NetworkSceneManager.LoadScene` (#955)
- `NetworkManager, NetworkConfig, and NetworkSceneManager` scene registration replaced with scenes in build list (#1080)
- `GlobalObjectIdHash` replaced `PrefabHash` and `PrefabHashGenerator` for stability and consistency (#698)
- `NetworkStart` has been renamed to `OnNetworkSpawn`. (#865)
- Network variable cleanup - eliminated shared mode, variables are server-authoritative (#1059, #1074)
- `NetworkManager` and other systems are no longer singletons/statics (#696, #705, #706, #737, #738, #739, #746, #747, #763, #765, #766, #783, #784, #785, #786, #787, #788)
- Changed `INetworkSerializable.NetworkSerialize` method signature to use `BufferSerializer<T>` instead of `NetworkSerializer` (#1187)
- Changed `CustomMessagingManager`'s methods to use `FastBufferWriter` and `FastBufferReader` instead of `Stream` (#1187)
- Reduced internal runtime allocations by removing LINQ calls and replacing managed lists/arrays with native collections (#1196)

### Removed

- Removed `NetworkNavMeshAgent` (#1150)
- Removed `NetworkDictionary`, `NetworkSet` (#1149)
- Removed `NetworkVariableSettings` (#1097)
- Removed predefined `NetworkVariable<T>` types (#1093)
    - Removed `NetworkVariableBool`, `NetworkVariableByte`, `NetworkVariableSByte`, `NetworkVariableUShort`, `NetworkVariableShort`, `NetworkVariableUInt`, `NetworkVariableInt`, `NetworkVariableULong`, `NetworkVariableLong`, `NetworkVariableFloat`, `NetworkVariableDouble`, `NetworkVariableVector2`, `NetworkVariableVector3`, `NetworkVariableVector4`, `NetworkVariableColor`, `NetworkVariableColor32`, `NetworkVariableRay`, `NetworkVariableQuaternion`
- Removed `NetworkChannel` and `MultiplexTransportAdapter` (#1133)
- Removed ILPP backend for 2019.4, minimum required version is 2020.3+ (#895)
- `NetworkManager.NetworkConfig` had the following properties removed: (#1080)
  - Scene Registrations no longer exists
  - Allow Runtime Scene Changes was no longer needed and was removed
- Removed the NetworkObject.Spawn payload parameter (#1005)
- Removed `ProfilerCounter`, the original MLAPI network profiler, and the built-in network profiler module (2020.3). A replacement can now be found in the Multiplayer Tools package. (#1048)
- Removed UNet RelayTransport and related relay functionality in UNetTransport (#1081)
- Removed `UpdateStage` parameter from `ServerRpcSendParams` and `ClientRpcSendParams` (#1187)
- Removed `NetworkBuffer`, `NetworkWriter`, `NetworkReader`, `NetworkSerializer`, `PooledNetworkBuffer`, `PooledNetworkWriter`, and `PooledNetworkReader` (#1187)
- Removed `EnableNetworkVariable` in `NetworkConfig`, it is always enabled now (#1179)
- Removed `NetworkTransform`'s FixedSendsPerSecond, AssumeSyncedSends, InterpolateServer, ExtrapolatePosition, MaxSendsToExtrapolate, Channel, EnableNonProvokedResendChecks, DistanceSendrate (#1060) (#826) (#1042, #1055, #1061, #1084, #1101)
- Removed `NetworkManager`'s `StopServer()`, `StopClient()` and `StopHost()` methods and replaced with single `NetworkManager.Shutdown()` method for all (#1108)

### Fixed

- Fixed ServerRpc ownership check to `Debug.LogError` instead of `Debug.LogWarning` (#1126)
- Fixed `NetworkObject.OwnerClientId` property changing before `NetworkBehaviour.OnGainedOwnership()` callback (#1092)
- Fixed `NetworkBehaviourILPP` to iterate over all types in an assembly (#803)
- Fixed cross-asmdef RPC ILPP by importing types into external assemblies (#678)
- Fixed `NetworkManager` shutdown when quitting the application or switching scenes (#1011)
  - Now `NetworkManager` shutdowns correctly and despawns existing `NetworkObject`s
- Fixed Only one `PlayerPrefab` can be selected on `NetworkManager` inspector UI in the editor (#676)
- Fixed connection approval not being triggered for host (#675)
- Fixed various situations where messages could be processed in an invalid order, resulting in errors (#948, #1187, #1218)
- Fixed `NetworkVariable`s being default-initialized on the client instead of being initialized with the desired value (#1266)
- Improved runtime performance and reduced GC pressure (#1187)
- Fixed #915 - clients are receiving data from objects not visible to them (#1099)
- Fixed `NetworkTransform`'s "late join" issues, `NetworkTransform` now uses `NetworkVariable`s instead of RPCs (#826)
- Throw an exception for silent failure when a client tries to get another player's `PlayerObject`, it is now only allowed on the server-side (#844)

### Known Issues

- `NetworkVariable` does not serialize `INetworkSerializable` types through their `NetworkSerialize` implementation
- `NetworkObjects` marked as `DontDestroyOnLoad` are disabled during some network scene transitions
- `NetworkTransform` interpolates from the origin when switching Local Space synchronization
- Exceptions thrown in `OnNetworkSpawn` user code for an object will prevent the callback in other objects
- Cannot send an array of `INetworkSerializable` in RPCs
- ILPP generation fails with special characters in project path

## [0.2.0] - 2021-06-03

WIP version increment to pass package validation checks. Changelog & final version number TBD.

## [0.1.1] - 2021-06-01

This is hotfix v0.1.1 for the initial experimental Unity MLAPI Package.

### Changed

- Fixed issue with the Unity Registry package version missing some fixes from the v0.1.0 release.

## [0.1.0] - 2021-03-23

This is the initial experimental Unity MLAPI Package, v0.1.0.

### Added

- Refactored a new standard for Remote Procedure Call (RPC) in MLAPI which provides increased performance, significantly reduced boilerplate code, and extensibility for future-proofed code. MLAPI RPC includes `ServerRpc` and `ClientRpc` to execute logic on the server and client-side. This provides a single performant unified RPC solution, replacing MLAPI Convenience and Performance RPC (see [here](#removed-features)).
- Added standarized serialization types, including built-in and custom serialization flows. See [RFC #2](https://github.com/Unity-Technologies/com.unity.multiplayer.rfcs/blob/master/text/0002-serializable-types.md) for details.
- `INetworkSerializable` interface replaces `IBitWritable`.
- Added `NetworkSerializer`..., which is the main aggregator that implements serialization code for built-in supported types and holds `NetworkReader` and `NetworkWriter` instances internally.
- Added a Network Update Loop infrastructure that aids Netcode systems to update (such as RPC queue and transport) outside of the standard `MonoBehaviour` event cycle. See [RFC #8](https://github.com/Unity-Technologies/com.unity.multiplayer.rfcs/blob/master/text/0008-network-update-loop.md) and the following details:
  - It uses Unity's [low-level Player Loop API](https://docs.unity3d.com/ScriptReference/LowLevel.PlayerLoop.html) and allows for registering `INetworkUpdateSystem`s with `NetworkUpdate` methods to be executed at specific `NetworkUpdateStage`s, which may also be before or after `MonoBehaviour`-driven game logic execution.
  - You will typically interact with `NetworkUpdateLoop` for registration and `INetworkUpdateSystem` for implementation.
  - `NetworkVariable`s are now tick-based using the `NetworkTickSystem`, tracking time through network interactions and syncs.
- Added message batching to handle consecutive RPC requests sent to the same client. `RpcBatcher` sends batches based on requests from the `RpcQueueProcessing`, by batch size threshold or immediately.
- [GitHub 494](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/494): Added a constraint to allow one `NetworkObject` per `GameObject`, set through the `DisallowMultipleComponent` attribute.
- Integrated MLAPI with the Unity Profiler for versions 2020.2 and later:
  - Added new profiler modules for MLAPI that report important network data.
  - Attached the profiler to a remote player to view network data over the wire.
- A test project is available for building and experimenting with MLAPI features. This project is available in the MLAPI GitHub [testproject folder](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/tree/release/0.1.0/testproject).
- Added a [MLAPI Community Contributions](https://github.com/Unity-Technologies/mlapi-community-contributions/tree/master/com.mlapi.contrib.extensions) new GitHub repository to accept extensions from the MLAPI community. Current extensions include moved MLAPI features for lag compensation (useful for Server Authoritative actions) and `TrackedObject`.

### Changed

- [GitHub 520](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/520): MLAPI now uses the Unity Package Manager for installation management.
- Added functionality and usability to `NetworkVariable`, previously called `NetworkVar`. Updates enhance options and fully replace the need for `SyncedVar`s.
- [GitHub 507](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/507): Reimplemented `NetworkAnimator`, which synchronizes animation states for networked objects.
- GitHub [444](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/444) and [455](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/455): Channels are now represented as bytes instead of strings.

For users of previous versions of MLAPI, this release renames APIs due to refactoring. All obsolete marked APIs have been removed as per [GitHub 513](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/513) and [GitHub 514](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/514).

| Previous MLAPI Versions | V 0.1.0 Name |
| -- | -- |
| `NetworkingManager` | `NetworkManager` |
| `NetworkedObject` | `NetworkObject` |
| `NetworkedBehaviour` | `NetworkBehaviour` |
| `NetworkedClient` | `NetworkClient` |
| `NetworkedPrefab` | `NetworkPrefab` |
| `NetworkedVar` | `NetworkVariable` |
| `NetworkedTransform` | `NetworkTransform` |
| `NetworkedAnimator` | `NetworkAnimator` |
| `NetworkedAnimatorEditor` | `NetworkAnimatorEditor` |
| `NetworkedNavMeshAgent` | `NetworkNavMeshAgent` |
| `SpawnManager` | `NetworkSpawnManager` |
| `BitStream` | `NetworkBuffer` |
| `BitReader` | `NetworkReader` |
| `BitWriter` | `NetworkWriter` |
| `NetEventType` | `NetworkEventType` |
| `ChannelType` | `NetworkDelivery` |
| `Channel` | `NetworkChannel` |
| `Transport` | `NetworkTransport` |
| `NetworkedDictionary` | `NetworkDictionary` |
| `NetworkedList` | `NetworkList` |
| `NetworkedSet` | `NetworkSet` |
| `MLAPIConstants` | `NetworkConstants` |
| `UnetTransport` | `UNetTransport` |

### Fixed

- [GitHub 460](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/460): Fixed an issue for RPC where the host-server was not receiving RPCs from the host-client and vice versa without the loopback flag set in `NetworkingManager`.
- Fixed an issue where data in the Profiler was incorrectly aggregated and drawn, which caused the profiler data to increment indefinitely instead of resetting each frame.
- Fixed an issue the client soft-synced causing PlayMode client-only scene transition issues, caused when running the client in the editor and the host as a release build. Users may have encountered a soft sync of `NetworkedInstanceId` issues in the `SpawnManager.ClientCollectSoftSyncSceneObjectSweep` method.
- [GitHub 458](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/458): Fixed serialization issues in `NetworkList` and `NetworkDictionary` when running in Server mode.
- [GitHub 498](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/498): Fixed numerical precision issues to prevent not a number (NaN) quaternions.
- [GitHub 438](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/438): Fixed booleans by reaching or writing bytes instead of bits.
- [GitHub 519](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/519): Fixed an issue where calling `Shutdown()` before making `NetworkManager.Singleton = null` is null on `NetworkManager.OnDestroy()`.

### Removed

With a new release of MLAPI in Unity, some features have been removed:

- SyncVars have been removed from MLAPI. Use `NetworkVariable`s in place of this functionality. <!-- MTT54 -->
- [GitHub 527](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/527): Lag compensation systems and `TrackedObject` have moved to the new [MLAPI Community Contributions](https://github.com/Unity-Technologies/mlapi-community-contributions/tree/master/com.mlapi.contrib.extensions) repo.
- [GitHub 509](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/509): Encryption has been removed from MLAPI. The `Encryption` option in `NetworkConfig` on the `NetworkingManager` is not available in this release. This change will not block game creation or running. A current replacement for this functionality is not available, and may be developed in future releases. See the following changes:
    - Removed `SecuritySendFlags` from all APIs.
    - Removed encryption, cryptography, and certificate configurations from APIs including `NetworkManager` and `NetworkConfig`.
    - Removed "hail handshake", including `NetworkManager` implementation and `NetworkConstants` entries.
    - Modified `RpcQueue` and `RpcBatcher` internals to remove encryption and authentication from reading and writing.
- Removed the previous MLAPI Profiler editor window from Unity versions 2020.2 and later.
- Removed previous MLAPI Convenience and Performance RPC APIs with the new standard RPC API. See [RFC #1](https://github.com/Unity-Technologies/com.unity.multiplayer.rfcs/blob/master/text/0001-std-rpc-api.md) for details.
- [GitHub 520](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/520): Removed the MLAPI Installer.

### Known Issues

- `NetworkNavMeshAgent` does not synchronize mesh data, Agent Size, Steering, Obstacle Avoidance, or Path Finding settings. It only synchronizes the destination and velocity, not the path to the destination.
- For `RPC`, methods with a `ClientRpc` or `ServerRpc` suffix which are not marked with [ServerRpc] or [ClientRpc] will cause a compiler error.
- For `NetworkAnimator`, Animator Overrides are not supported. Triggers do not work.
- For `NetworkVariable`, the `NetworkDictionary` `List` and `Set` must use the `reliableSequenced` channel.
- `NetworkObjects`s are supported but when spawning a prefab with nested child network objects you have to manually call spawn on them
- `NetworkTransform` have the following issues:
  - Replicated objects may have jitter.
  - The owner is always authoritative about the object's position.
  - Scale is not synchronized.
- Connection Approval is not called on the host client.
- For `NamedMessages`, always use `NetworkBuffer` as the underlying stream for sending named and unnamed messages.
- For `NetworkManager`, connection management is limited. Use `IsServer`, `IsClient`, `IsConnectedClient`, or other code to check if MLAPI connected correctly.

## [0.0.1-preview.1] - 2020-12-20

This was an internally-only-used version of the Unity MLAPI Package
This commit is contained in:
Unity Technologies
2020-12-20 00:00:00 +00:00
commit 22d877d1b2
489 changed files with 43246 additions and 0 deletions

View File

@@ -0,0 +1,769 @@
using System.Collections.Generic;
using System;
using System.Linq;
using Unity.Collections;
using UnityEngine.SceneManagement;
namespace Unity.Netcode
{
/// <summary>
/// The different types of scene events communicated between a server and client.
/// Used by <see cref="NetworkSceneManager"/> for <see cref="SceneEventMessage"/> messages
/// Note: This is only when <see cref="NetworkConfig.EnableSceneManagement"/> is enabled
/// See also: <see cref="SceneEvent"/>
/// </summary>
public enum SceneEventType : byte
{
/// <summary>
/// Load a scene
/// Invocation: Server Side
/// Message Flow: Server to client
/// Event Notification: Both server and client are notified a load scene event started
/// </summary>
Load,
/// <summary>
/// Unload a scene
/// Invocation: Server Side
/// Message Flow: Server to client
/// Event Notification: Both server and client are notified an unload scene event started
/// </summary>
Unload,
/// <summary>
/// Synchronize current game session state for approved clients
/// Invocation: Server Side
/// Message Flow: Server to client
/// Event Notification: Server and Client receives a local notification (server receives the ClientId being synchronized)
/// </summary>
Synchronize,
/// <summary>
/// Game session re-synchronization of NetworkObjects that were destroyed during a <see cref="Synchronize"/> event
/// Invocation: Server Side
/// Message Flow: Server to client
/// Event Notification: Both server and client receive a local notification
/// Note: This will be removed once snapshot and buffered messages are finalized as it will no longer be needed at that point
/// </summary>
ReSynchronize,
/// <summary>
/// All clients have finished loading a scene
/// Invocation: Server Side
/// Message Flow: Server to Client
/// Event Notification: Both server and client receive a local notification containing the clients that finished
/// as well as the clients that timed out (if any).
/// </summary>
LoadEventCompleted,
/// <summary>
/// All clients have unloaded a scene
/// Invocation: Server Side
/// Message Flow: Server to Client
/// Event Notification: Both server and client receive a local notification containing the clients that finished
/// as well as the clients that timed out (if any).
/// </summary>
UnloadEventCompleted,
/// <summary>
/// A client has finished loading a scene
/// Invocation: Client Side
/// Message Flow: Client to Server
/// Event Notification: Both server and client receive a local notification
/// </summary>
LoadComplete,
/// <summary>
/// A client has finished unloading a scene
/// Invocation: Client Side
/// Message Flow: Client to Server
/// Event Notification: Both server and client receive a local notification
/// </summary>
UnloadComplete,
/// <summary>
/// A client has finished synchronizing from a <see cref="Synchronize"/> event
/// Invocation: Client Side
/// Message Flow: Client to Server
/// Event Notification: Both server and client receive a local notification
/// </summary>
SynchronizeComplete,
}
/// <summary>
/// Used by <see cref="NetworkSceneManager"/> for <see cref="SceneEventMessage"/> messages
/// Note: This is only when <see cref="NetworkConfig.EnableSceneManagement"/> is enabled
/// </summary>
internal class SceneEventData : IDisposable
{
internal SceneEventType SceneEventType;
internal LoadSceneMode LoadSceneMode;
internal Guid SceneEventProgressId;
internal uint SceneEventId;
internal uint SceneHash;
internal int SceneHandle;
/// Only used for <see cref="SceneEventType.Synchronize"/> scene events, this assures permissions when writing
/// NetworkVariable information. If that process changes, then we need to update this
internal ulong TargetClientId;
private Dictionary<uint, List<NetworkObject>> m_SceneNetworkObjects;
private Dictionary<uint, long> m_SceneNetworkObjectDataOffsets;
/// <summary>
/// Client or Server Side:
/// Client side: Generates a list of all NetworkObjects by their NetworkObjectId that was spawned during th synchronization process
/// Server side: Compares list from client to make sure client didn't drop a message about a NetworkObject being despawned while it
/// was synchronizing (if so server will send another message back to the client informing the client of NetworkObjects to remove)
/// spawned during an initial synchronization.
/// </summary>
private List<NetworkObject> m_NetworkObjectsSync = new List<NetworkObject>();
/// <summary>
/// Server Side Re-Synchronization:
/// If there happens to be NetworkObjects in the final Event_Sync_Complete message that are no longer spawned,
/// the server will compile a list and send back an Event_ReSync message to the client.
/// </summary>
private List<ulong> m_NetworkObjectsToBeRemoved = new List<ulong>();
private bool m_HasInternalBuffer;
internal FastBufferReader InternalBuffer;
private NetworkManager m_NetworkManager;
internal List<ulong> ClientsCompleted;
internal List<ulong> ClientsTimedOut;
internal Queue<uint> ScenesToSynchronize;
internal Queue<uint> SceneHandlesToSynchronize;
/// <summary>
/// Server Side:
/// Add a scene and its handle to the list of scenes the client should load before synchronizing
/// Since scene handles are not the same per instance, the client builds a server scene handle to
/// client scene handle lookup table.
/// Why include the scene handle? In order to support loading of the same additive scene more than once
/// we must distinguish which scene we are talking about when the server tells the client to unload a scene.
/// The server will always communicate its local relative scene's handle and the client will determine its
/// local relative handle from the table being built.
/// Look for <see cref="NetworkSceneManager.m_ServerSceneHandleToClientSceneHandle"/> usage to see where
/// entries are being added to or removed from the table
/// </summary>
/// <param name="sceneIndex"></param>
/// <param name="sceneHandle"></param>
internal void AddSceneToSynchronize(uint sceneHash, int sceneHandle)
{
ScenesToSynchronize.Enqueue(sceneHash);
SceneHandlesToSynchronize.Enqueue((uint)sceneHandle);
}
/// <summary>
/// Client Side:
/// Gets the next scene hash to be loaded for approval and/or late joining
/// </summary>
/// <returns></returns>
internal uint GetNextSceneSynchronizationHash()
{
return ScenesToSynchronize.Dequeue();
}
/// <summary>
/// Client Side:
/// Gets the next scene handle to be loaded for approval and/or late joining
/// </summary>
/// <returns></returns>
internal int GetNextSceneSynchronizationHandle()
{
return (int)SceneHandlesToSynchronize.Dequeue();
}
/// <summary>
/// Client Side:
/// Determines if all scenes have been processed during the synchronization process
/// </summary>
/// <returns>true/false</returns>
internal bool IsDoneWithSynchronization()
{
if (ScenesToSynchronize.Count == 0 && SceneHandlesToSynchronize.Count == 0)
{
return true;
}
else if (ScenesToSynchronize.Count != SceneHandlesToSynchronize.Count)
{
// This should never happen, but in the event it does...
throw new Exception($"[{nameof(SceneEventData)}-Internal Mismatch Error] {nameof(ScenesToSynchronize)} count != {nameof(SceneHandlesToSynchronize)} count!");
}
return false;
}
/// <summary>
/// Server Side:
/// Called just before the synchronization process
/// </summary>
internal void InitializeForSynch()
{
if (m_SceneNetworkObjects == null)
{
m_SceneNetworkObjects = new Dictionary<uint, List<NetworkObject>>();
}
else
{
m_SceneNetworkObjects.Clear();
}
if (ScenesToSynchronize == null)
{
ScenesToSynchronize = new Queue<uint>();
}
else
{
ScenesToSynchronize.Clear();
}
if (SceneHandlesToSynchronize == null)
{
SceneHandlesToSynchronize = new Queue<uint>();
}
else
{
SceneHandlesToSynchronize.Clear();
}
}
internal void AddSpawnedNetworkObjects()
{
m_NetworkObjectsSync = m_NetworkManager.SpawnManager.SpawnedObjectsList.ToList();
m_NetworkObjectsSync.Sort(SortNetworkObjects);
}
/// <summary>
/// Server Side:
/// Used during the synchronization process to associate NetworkObjects with scenes
/// </summary>
/// <param name="sceneIndex"></param>
/// <param name="networkObject"></param>
internal void AddNetworkObjectForSynch(uint sceneIndex, NetworkObject networkObject)
{
if (!m_SceneNetworkObjects.ContainsKey(sceneIndex))
{
m_SceneNetworkObjects.Add(sceneIndex, new List<NetworkObject>());
}
m_SceneNetworkObjects[sceneIndex].Add(networkObject);
}
/// <summary>
/// Client and Server:
/// Determines if the scene event type was intended for the client ( or server )
/// </summary>
/// <returns>true (client should handle this message) false (server should handle this message)</returns>
internal bool IsSceneEventClientSide()
{
switch (SceneEventType)
{
case SceneEventType.Load:
case SceneEventType.Unload:
case SceneEventType.Synchronize:
case SceneEventType.ReSynchronize:
case SceneEventType.LoadEventCompleted:
case SceneEventType.UnloadEventCompleted:
{
return true;
}
}
return false;
}
/// <summary>
/// Server Side:
/// Sorts the NetworkObjects to assure proper instantiation order of operations for
/// registered INetworkPrefabInstanceHandler implementations
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
private int SortNetworkObjects(NetworkObject first, NetworkObject second)
{
var doesFirstHaveHandler = m_NetworkManager.PrefabHandler.ContainsHandler(first);
var doesSecondHaveHandler = m_NetworkManager.PrefabHandler.ContainsHandler(second);
if (doesFirstHaveHandler != doesSecondHaveHandler)
{
if (doesFirstHaveHandler)
{
return 1;
}
else
{
return -1;
}
}
return 0;
}
/// <summary>
/// Client and Server Side:
/// Serializes data based on the SceneEvent type (<see cref="SceneEventType"/>)
/// </summary>
/// <param name="writer"><see cref="FastBufferWriter"/> to write the scene event data</param>
internal void Serialize(FastBufferWriter writer)
{
// Write the scene event type
writer.WriteValueSafe(SceneEventType);
// Write the scene loading mode
writer.WriteValueSafe(LoadSceneMode);
// Write the scene event progress Guid
if (SceneEventType != SceneEventType.Synchronize)
{
writer.WriteValueSafe(SceneEventProgressId);
}
// Write the scene index and handle
writer.WriteValueSafe(SceneHash);
writer.WriteValueSafe(SceneHandle);
switch (SceneEventType)
{
case SceneEventType.Synchronize:
{
WriteSceneSynchronizationData(writer);
break;
}
case SceneEventType.Load:
{
SerializeScenePlacedObjects(writer);
break;
}
case SceneEventType.SynchronizeComplete:
{
WriteClientSynchronizationResults(writer);
break;
}
case SceneEventType.ReSynchronize:
{
WriteClientReSynchronizationData(writer);
break;
}
case SceneEventType.LoadEventCompleted:
case SceneEventType.UnloadEventCompleted:
{
WriteSceneEventProgressDone(writer);
break;
}
}
}
/// <summary>
/// Server Side:
/// Called at the end of a <see cref="SceneEventType.Load"/> event once the scene is loaded and scene placed NetworkObjects
/// have been locally spawned
/// </summary>
internal void WriteSceneSynchronizationData(FastBufferWriter writer)
{
// Write the scenes we want to load, in the order we want to load them
writer.WriteValueSafe(ScenesToSynchronize.ToArray());
writer.WriteValueSafe(SceneHandlesToSynchronize.ToArray());
// Store our current position in the stream to come back and say how much data we have written
var positionStart = writer.Position;
// Size Place Holder -- Start
// !!NOTE!!: Since this is a placeholder to be set after we know how much we have written,
// for stream offset purposes this MUST not be a packed value!
writer.WriteValueSafe((int)0);
int totalBytes = 0;
// Write the number of NetworkObjects we are serializing
writer.WriteValueSafe(m_NetworkObjectsSync.Count());
for (var i = 0; i < m_NetworkObjectsSync.Count(); ++i)
{
var noStart = writer.Position;
var sceneObject = m_NetworkObjectsSync[i].GetMessageSceneObject(TargetClientId);
writer.WriteValueSafe(m_NetworkObjectsSync[i].gameObject.scene.handle);
sceneObject.Serialize(writer);
var noStop = writer.Position;
totalBytes += (int)(noStop - noStart);
}
// Size Place Holder -- End
var positionEnd = writer.Position;
var bytesWritten = (uint)(positionEnd - (positionStart + sizeof(uint)));
writer.Seek(positionStart);
// Write the total size written to the stream by NetworkObjects being serialized
writer.WriteValueSafe(bytesWritten);
writer.Seek(positionEnd);
}
/// <summary>
/// Server Side:
/// Called at the end of a <see cref="SceneEventType.Load"/> event once the scene is loaded and scene placed NetworkObjects
/// have been locally spawned
/// Maximum number of objects that could theoretically be synchronized is 65536
/// </summary>
internal void SerializeScenePlacedObjects(FastBufferWriter writer)
{
var numberOfObjects = (ushort)0;
var headPosition = writer.Position;
// Write our count place holder (must not be packed!)
writer.WriteValueSafe((ushort)0);
foreach (var keyValuePairByGlobalObjectIdHash in m_NetworkManager.SceneManager.ScenePlacedObjects)
{
foreach (var keyValuePairBySceneHandle in keyValuePairByGlobalObjectIdHash.Value)
{
if (keyValuePairBySceneHandle.Value.Observers.Contains(TargetClientId))
{
// Write our server relative scene handle for the NetworkObject being serialized
writer.WriteValueSafe(keyValuePairBySceneHandle.Key);
// Serialize the NetworkObject
var sceneObject = keyValuePairBySceneHandle.Value.GetMessageSceneObject(TargetClientId);
sceneObject.Serialize(writer);
numberOfObjects++;
}
}
}
var tailPosition = writer.Position;
// Reposition to our count position to the head before we wrote our object count
writer.Seek(headPosition);
// Write number of NetworkObjects serialized (must not be packed!)
writer.WriteValueSafe(numberOfObjects);
// Set our position back to the tail
writer.Seek(tailPosition);
}
/// <summary>
/// Client and Server Side:
/// Deserialize data based on the SceneEvent type.
/// </summary>
/// <param name="reader"></param>
internal void Deserialize(FastBufferReader reader)
{
reader.ReadValueSafe(out SceneEventType);
reader.ReadValueSafe(out LoadSceneMode);
if (SceneEventType != SceneEventType.Synchronize)
{
reader.ReadValueSafe(out SceneEventProgressId);
}
reader.ReadValueSafe(out SceneHash);
reader.ReadValueSafe(out SceneHandle);
switch (SceneEventType)
{
case SceneEventType.Synchronize:
{
CopySceneSynchronizationData(reader);
break;
}
case SceneEventType.SynchronizeComplete:
{
CheckClientSynchronizationResults(reader);
break;
}
case SceneEventType.Load:
{
unsafe
{
// We store off the trailing in-scene placed serialized NetworkObject data to
// be processed once we are done loading.
m_HasInternalBuffer = true;
// We use Allocator.Persistent since scene loading could take longer than 4 frames
InternalBuffer = new FastBufferReader(reader.GetUnsafePtrAtCurrentPosition(), Allocator.Persistent, reader.Length - reader.Position);
}
break;
}
case SceneEventType.ReSynchronize:
{
ReadClientReSynchronizationData(reader);
break;
}
case SceneEventType.LoadEventCompleted:
case SceneEventType.UnloadEventCompleted:
{
ReadSceneEventProgressDone(reader);
break;
}
}
}
/// <summary>
/// Client Side:
/// Prepares for a scene synchronization event and copies the scene synchronization data
/// into the internal buffer to be used throughout the synchronization process.
/// </summary>
/// <param name="reader"></param>
internal void CopySceneSynchronizationData(FastBufferReader reader)
{
m_NetworkObjectsSync.Clear();
reader.ReadValueSafe(out uint[] scenesToSynchronize);
reader.ReadValueSafe(out uint[] sceneHandlesToSynchronize);
ScenesToSynchronize = new Queue<uint>(scenesToSynchronize);
SceneHandlesToSynchronize = new Queue<uint>(sceneHandlesToSynchronize);
// is not packed!
reader.ReadValueSafe(out int sizeToCopy);
unsafe
{
if (!reader.TryBeginRead(sizeToCopy))
{
throw new OverflowException("Not enough space in the buffer to read recorded synchronization data size.");
}
m_HasInternalBuffer = true;
// We use Allocator.Persistent since scene synchronization will most likely take longer than 4 frames
InternalBuffer = new FastBufferReader(reader.GetUnsafePtrAtCurrentPosition(), Allocator.Persistent, sizeToCopy);
}
}
/// <summary>
/// Client Side:
/// This needs to occur at the end of a <see cref="SceneEventType.Load"/> event when the scene has finished loading
/// Maximum number of objects that could theoretically be synchronized is 65536
/// </summary>
internal void DeserializeScenePlacedObjects()
{
try
{
// is not packed!
InternalBuffer.ReadValueSafe(out ushort newObjectsCount);
for (ushort i = 0; i < newObjectsCount; i++)
{
InternalBuffer.ReadValueSafe(out int sceneHandle);
// Set our relative scene to the NetworkObject
m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(sceneHandle);
// Deserialize the NetworkObject
var sceneObject = new NetworkObject.SceneObject();
sceneObject.Deserialize(InternalBuffer);
NetworkObject.AddSceneObject(sceneObject, InternalBuffer, m_NetworkManager);
}
}
finally
{
InternalBuffer.Dispose();
m_HasInternalBuffer = false;
}
}
/// <summary>
/// Client Side:
/// If there happens to be NetworkObjects in the final Event_Sync_Complete message that are no longer spawned,
/// the server will compile a list and send back an Event_ReSync message to the client. This is where the
/// client handles any returned values by the server.
/// </summary>
/// <param name="reader"></param>
internal void ReadClientReSynchronizationData(FastBufferReader reader)
{
reader.ReadValueSafe(out uint[] networkObjectsToRemove);
if (networkObjectsToRemove.Length > 0)
{
var networkObjects = UnityEngine.Object.FindObjectsOfType<NetworkObject>();
var networkObjectIdToNetworkObject = new Dictionary<ulong, NetworkObject>();
foreach (var networkObject in networkObjects)
{
if (!networkObjectIdToNetworkObject.ContainsKey(networkObject.NetworkObjectId))
{
networkObjectIdToNetworkObject.Add(networkObject.NetworkObjectId, networkObject);
}
}
foreach (var networkObjectId in networkObjectsToRemove)
{
if (networkObjectIdToNetworkObject.ContainsKey(networkObjectId))
{
var networkObject = networkObjectIdToNetworkObject[networkObjectId];
networkObjectIdToNetworkObject.Remove(networkObjectId);
networkObject.IsSpawned = false;
if (m_NetworkManager.PrefabHandler.ContainsHandler(networkObject))
{
// Since this is the client side and we have missed the delete message, until the Snapshot system is in place for spawn and despawn handling
// we have to remove this from the list of spawned objects manually or when a NetworkObjectId is recycled the client will throw an error
// about the id already being assigned.
if (m_NetworkManager.SpawnManager.SpawnedObjects.ContainsKey(networkObjectId))
{
m_NetworkManager.SpawnManager.SpawnedObjects.Remove(networkObjectId);
}
if (m_NetworkManager.SpawnManager.SpawnedObjectsList.Contains(networkObject))
{
m_NetworkManager.SpawnManager.SpawnedObjectsList.Remove(networkObject);
}
NetworkManager.Singleton.PrefabHandler.HandleNetworkPrefabDestroy(networkObject);
}
else
{
UnityEngine.Object.DestroyImmediate(networkObject.gameObject);
}
}
}
}
}
/// <summary>
/// Server Side:
/// If there happens to be NetworkObjects in the final Event_Sync_Complete message that are no longer spawned,
/// the server will compile a list and send back an Event_ReSync message to the client.
/// </summary>
/// <param name="writer"></param>
internal void WriteClientReSynchronizationData(FastBufferWriter writer)
{
//Write how many objects need to be removed
writer.WriteValueSafe(m_NetworkObjectsToBeRemoved.ToArray());
}
/// <summary>
/// Server Side:
/// Determines if the client needs to be slightly re-synchronized if during the deserialization
/// process the server finds NetworkObjects that the client still thinks are spawned.
/// </summary>
/// <returns></returns>
internal bool ClientNeedsReSynchronization()
{
return (m_NetworkObjectsToBeRemoved.Count > 0);
}
/// <summary>
/// Server Side:
/// Determines if the client needs to be re-synchronized if during the deserialization
/// process the server finds NetworkObjects that the client still thinks are spawned but
/// have since been despawned.
/// </summary>
/// <param name="reader"></param>
internal void CheckClientSynchronizationResults(FastBufferReader reader)
{
m_NetworkObjectsToBeRemoved.Clear();
reader.ReadValueSafe(out uint networkObjectIdCount);
for (int i = 0; i < networkObjectIdCount; i++)
{
reader.ReadValueSafe(out uint networkObjectId);
if (!m_NetworkManager.SpawnManager.SpawnedObjects.ContainsKey(networkObjectId))
{
m_NetworkObjectsToBeRemoved.Add(networkObjectId);
}
}
}
/// <summary>
/// Client Side:
/// During the deserialization process of the servers Event_Sync, the client builds a list of
/// all NetworkObjectIds that were spawned. Upon responding to the server with the Event_Sync_Complete
/// this list is included for the server to review over and determine if the client needs a minor resynchronization
/// of NetworkObjects that might have been despawned while the client was processing the Event_Sync.
/// </summary>
/// <param name="writer"></param>
internal void WriteClientSynchronizationResults(FastBufferWriter writer)
{
//Write how many objects were spawned
writer.WriteValueSafe((uint)m_NetworkObjectsSync.Count);
foreach (var networkObject in m_NetworkObjectsSync)
{
writer.WriteValueSafe((uint)networkObject.NetworkObjectId);
}
}
/// <summary>
/// Client Side:
/// During the processing of a server sent Event_Sync, this method will be called for each scene once
/// it is finished loading. The client will also build a list of NetworkObjects that it spawned during
/// this process which will be used as part of the Event_Sync_Complete response.
/// </summary>
/// <param name="networkManager"></param>
internal void SynchronizeSceneNetworkObjects(NetworkManager networkManager)
{
try
{
// Process all NetworkObjects for this scene
InternalBuffer.ReadValueSafe(out int newObjectsCount);
for (int i = 0; i < newObjectsCount; i++)
{
// We want to make sure for each NetworkObject we have the appropriate scene selected as the scene that is
// currently being synchronized. This assures in-scene placed NetworkObjects will use the right NetworkObject
// from the list of populated <see cref="NetworkSceneManager.ScenePlacedObjects"/>
InternalBuffer.ReadValueSafe(out int handle);
m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(handle);
var sceneObject = new NetworkObject.SceneObject();
sceneObject.Deserialize(InternalBuffer);
var spawnedNetworkObject = NetworkObject.AddSceneObject(sceneObject, InternalBuffer, networkManager);
if (!m_NetworkObjectsSync.Contains(spawnedNetworkObject))
{
m_NetworkObjectsSync.Add(spawnedNetworkObject);
}
}
}
finally
{
InternalBuffer.Dispose();
m_HasInternalBuffer = false;
}
}
/// <summary>
/// Writes the all clients loaded or unloaded completed and timed out lists
/// </summary>
/// <param name="writer"></param>
internal void WriteSceneEventProgressDone(FastBufferWriter writer)
{
writer.WriteValueSafe((ushort)ClientsCompleted.Count);
foreach (var clientId in ClientsCompleted)
{
writer.WriteValueSafe(clientId);
}
writer.WriteValueSafe((ushort)ClientsTimedOut.Count);
foreach (var clientId in ClientsTimedOut)
{
writer.WriteValueSafe(clientId);
}
}
/// <summary>
/// Reads the all clients loaded or unloaded completed and timed out lists
/// </summary>
/// <param name="reader"></param>
internal void ReadSceneEventProgressDone(FastBufferReader reader)
{
reader.ReadValueSafe(out ushort completedCount);
ClientsCompleted = new List<ulong>();
for (int i = 0; i < completedCount; i++)
{
reader.ReadValueSafe(out ulong clientId);
ClientsCompleted.Add(clientId);
}
reader.ReadValueSafe(out ushort timedOutCount);
ClientsTimedOut = new List<ulong>();
for (int i = 0; i < timedOutCount; i++)
{
reader.ReadValueSafe(out ulong clientId);
ClientsTimedOut.Add(clientId);
}
}
/// <summary>
/// Used to release the pooled network buffer
/// </summary>
public void Dispose()
{
if (m_HasInternalBuffer)
{
InternalBuffer.Dispose();
m_HasInternalBuffer = false;
}
}
/// <summary>
/// Constructor for SceneEventData
/// </summary>
internal SceneEventData(NetworkManager networkManager)
{
m_NetworkManager = networkManager;
SceneEventId = XXHash.Hash32(Guid.NewGuid().ToString());
}
}
}