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:
13
Runtime/Messaging/BatchHeader.cs
Normal file
13
Runtime/Messaging/BatchHeader.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// Header placed at the start of each message batch
|
||||
/// </summary>
|
||||
internal struct BatchHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Total number of messages in the batch.
|
||||
/// </summary>
|
||||
public ushort BatchSize;
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/BatchHeader.cs.meta
Normal file
11
Runtime/Messaging/BatchHeader.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 941fcfe2222f8734ab5bfb9bc4787717
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
281
Runtime/Messaging/CustomMessageManager.cs
Normal file
281
Runtime/Messaging/CustomMessageManager.cs
Normal file
@@ -0,0 +1,281 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// The manager class to manage custom messages, note that this is different from the NetworkManager custom messages.
|
||||
/// These are named and are much easier to use.
|
||||
/// </summary>
|
||||
public class CustomMessagingManager
|
||||
{
|
||||
private readonly NetworkManager m_NetworkManager;
|
||||
|
||||
internal CustomMessagingManager(NetworkManager networkManager)
|
||||
{
|
||||
m_NetworkManager = networkManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delegate used for incoming unnamed messages
|
||||
/// </summary>
|
||||
/// <param name="clientId">The clientId that sent the message</param>
|
||||
/// <param name="reader">The stream containing the message data</param>
|
||||
public delegate void UnnamedMessageDelegate(ulong clientId, FastBufferReader reader);
|
||||
|
||||
/// <summary>
|
||||
/// Event invoked when unnamed messages arrive
|
||||
/// </summary>
|
||||
public event UnnamedMessageDelegate OnUnnamedMessage;
|
||||
|
||||
internal void InvokeUnnamedMessage(ulong clientId, FastBufferReader reader)
|
||||
{
|
||||
if (OnUnnamedMessage != null)
|
||||
{
|
||||
var pos = reader.Position;
|
||||
var delegates = OnUnnamedMessage.GetInvocationList();
|
||||
foreach (var handler in delegates)
|
||||
{
|
||||
reader.Seek(pos);
|
||||
((UnnamedMessageDelegate)handler).Invoke(clientId, reader);
|
||||
}
|
||||
}
|
||||
m_NetworkManager.NetworkMetrics.TrackUnnamedMessageReceived(clientId, reader.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends unnamed message to all clients
|
||||
/// </summary>
|
||||
/// <param name="messageBuffer">The message stream containing the data</param>
|
||||
/// <param name="networkDelivery">The delivery type (QoS) to send data with</param>
|
||||
public void SendUnnamedMessageToAll(FastBufferWriter messageBuffer, NetworkDelivery networkDelivery = NetworkDelivery.ReliableSequenced)
|
||||
{
|
||||
SendUnnamedMessage(m_NetworkManager.ConnectedClientsIds, messageBuffer, networkDelivery);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sends unnamed message to a list of clients
|
||||
/// </summary>
|
||||
/// <param name="clientIds">The clients to send to, sends to everyone if null</param>
|
||||
/// <param name="messageBuffer">The message stream containing the data</param>
|
||||
/// <param name="networkDelivery">The delivery type (QoS) to send data with</param>
|
||||
public void SendUnnamedMessage(IReadOnlyList<ulong> clientIds, FastBufferWriter messageBuffer, NetworkDelivery networkDelivery = NetworkDelivery.ReliableSequenced)
|
||||
{
|
||||
if (!m_NetworkManager.IsServer)
|
||||
{
|
||||
throw new InvalidOperationException("Can not send unnamed messages to multiple users as a client");
|
||||
}
|
||||
|
||||
if (clientIds == null)
|
||||
{
|
||||
throw new ArgumentNullException("You must pass in a valid clientId List");
|
||||
}
|
||||
|
||||
var message = new UnnamedMessage
|
||||
{
|
||||
Data = messageBuffer
|
||||
};
|
||||
var size = m_NetworkManager.SendMessage(message, networkDelivery, clientIds);
|
||||
|
||||
// Size is zero if we were only sending the message to ourself in which case it isn't sent.
|
||||
if (size != 0)
|
||||
{
|
||||
m_NetworkManager.NetworkMetrics.TrackUnnamedMessageSent(clientIds, size);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a unnamed message to a specific client
|
||||
/// </summary>
|
||||
/// <param name="clientId">The client to send the message to</param>
|
||||
/// <param name="messageBuffer">The message stream containing the data</param>
|
||||
/// <param name="networkDelivery">The delivery type (QoS) to send data with</param>
|
||||
public void SendUnnamedMessage(ulong clientId, FastBufferWriter messageBuffer, NetworkDelivery networkDelivery = NetworkDelivery.ReliableSequenced)
|
||||
{
|
||||
var message = new UnnamedMessage
|
||||
{
|
||||
Data = messageBuffer
|
||||
};
|
||||
var size = m_NetworkManager.SendMessage(message, networkDelivery, clientId);
|
||||
// Size is zero if we were only sending the message to ourself in which case it isn't sent.
|
||||
if (size != 0)
|
||||
{
|
||||
m_NetworkManager.NetworkMetrics.TrackUnnamedMessageSent(clientId, size);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delegate used to handle named messages
|
||||
/// </summary>
|
||||
public delegate void HandleNamedMessageDelegate(ulong senderClientId, FastBufferReader messagePayload);
|
||||
|
||||
private Dictionary<ulong, HandleNamedMessageDelegate> m_NamedMessageHandlers32 = new Dictionary<ulong, HandleNamedMessageDelegate>();
|
||||
private Dictionary<ulong, HandleNamedMessageDelegate> m_NamedMessageHandlers64 = new Dictionary<ulong, HandleNamedMessageDelegate>();
|
||||
|
||||
private Dictionary<ulong, string> m_MessageHandlerNameLookup32 = new Dictionary<ulong, string>();
|
||||
private Dictionary<ulong, string> m_MessageHandlerNameLookup64 = new Dictionary<ulong, string>();
|
||||
|
||||
internal void InvokeNamedMessage(ulong hash, ulong sender, FastBufferReader reader)
|
||||
{
|
||||
var bytesCount = reader.Length;
|
||||
|
||||
if (m_NetworkManager == null)
|
||||
{
|
||||
// We dont know what size to use. Try every (more collision prone)
|
||||
if (m_NamedMessageHandlers32.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler32))
|
||||
{
|
||||
messageHandler32(sender, reader);
|
||||
m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup32[hash], bytesCount);
|
||||
}
|
||||
|
||||
if (m_NamedMessageHandlers64.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler64))
|
||||
{
|
||||
messageHandler64(sender, reader);
|
||||
m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup64[hash], bytesCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only check the right size.
|
||||
switch (m_NetworkManager.NetworkConfig.RpcHashSize)
|
||||
{
|
||||
case HashSize.VarIntFourBytes:
|
||||
if (m_NamedMessageHandlers32.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler32))
|
||||
{
|
||||
messageHandler32(sender, reader);
|
||||
m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup32[hash], bytesCount);
|
||||
}
|
||||
break;
|
||||
case HashSize.VarIntEightBytes:
|
||||
if (m_NamedMessageHandlers64.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler64))
|
||||
{
|
||||
messageHandler64(sender, reader);
|
||||
m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup64[hash], bytesCount);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a named message handler delegate.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the message.</param>
|
||||
/// <param name="callback">The callback to run when a named message is received.</param>
|
||||
public void RegisterNamedMessageHandler(string name, HandleNamedMessageDelegate callback)
|
||||
{
|
||||
var hash32 = XXHash.Hash32(name);
|
||||
var hash64 = XXHash.Hash64(name);
|
||||
|
||||
m_NamedMessageHandlers32[hash32] = callback;
|
||||
m_NamedMessageHandlers64[hash64] = callback;
|
||||
|
||||
m_MessageHandlerNameLookup32[hash32] = name;
|
||||
m_MessageHandlerNameLookup64[hash64] = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters a named message handler.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the message.</param>
|
||||
public void UnregisterNamedMessageHandler(string name)
|
||||
{
|
||||
var hash32 = XXHash.Hash32(name);
|
||||
var hash64 = XXHash.Hash64(name);
|
||||
|
||||
m_NamedMessageHandlers32.Remove(hash32);
|
||||
m_NamedMessageHandlers64.Remove(hash64);
|
||||
|
||||
m_MessageHandlerNameLookup32.Remove(hash32);
|
||||
m_MessageHandlerNameLookup64.Remove(hash64);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a named message to all clients
|
||||
/// </summary>
|
||||
/// <param name="messageStream">The message stream containing the data</param>
|
||||
/// <param name="networkDelivery">The delivery type (QoS) to send data with</param>
|
||||
public void SendNamedMessageToAll(string messageName, FastBufferWriter messageStream, NetworkDelivery networkDelivery = NetworkDelivery.ReliableSequenced)
|
||||
{
|
||||
SendNamedMessage(messageName, m_NetworkManager.ConnectedClientsIds, messageStream, networkDelivery);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a named message
|
||||
/// </summary>
|
||||
/// <param name="messageName">The message name to send</param>
|
||||
/// <param name="clientId">The client to send the message to</param>
|
||||
/// <param name="messageStream">The message stream containing the data</param>
|
||||
/// <param name="networkDelivery">The delivery type (QoS) to send data with</param>
|
||||
public void SendNamedMessage(string messageName, ulong clientId, FastBufferWriter messageStream, NetworkDelivery networkDelivery = NetworkDelivery.ReliableSequenced)
|
||||
{
|
||||
ulong hash = 0;
|
||||
switch (m_NetworkManager.NetworkConfig.RpcHashSize)
|
||||
{
|
||||
case HashSize.VarIntFourBytes:
|
||||
hash = XXHash.Hash32(messageName);
|
||||
break;
|
||||
case HashSize.VarIntEightBytes:
|
||||
hash = XXHash.Hash64(messageName);
|
||||
break;
|
||||
}
|
||||
|
||||
var message = new NamedMessage
|
||||
{
|
||||
Hash = hash,
|
||||
Data = messageStream
|
||||
};
|
||||
var size = m_NetworkManager.SendMessage(message, networkDelivery, clientId);
|
||||
|
||||
// Size is zero if we were only sending the message to ourself in which case it isn't sent.
|
||||
if (size != 0)
|
||||
{
|
||||
m_NetworkManager.NetworkMetrics.TrackNamedMessageSent(clientId, messageName, size);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the named message
|
||||
/// </summary>
|
||||
/// <param name="messageName">The message name to send</param>
|
||||
/// <param name="clientIds">The clients to send to, sends to everyone if null</param>
|
||||
/// <param name="messageStream">The message stream containing the data</param>
|
||||
/// <param name="networkDelivery">The delivery type (QoS) to send data with</param>
|
||||
public void SendNamedMessage(string messageName, IReadOnlyList<ulong> clientIds, FastBufferWriter messageStream, NetworkDelivery networkDelivery = NetworkDelivery.ReliableSequenced)
|
||||
{
|
||||
if (!m_NetworkManager.IsServer)
|
||||
{
|
||||
throw new InvalidOperationException("Can not send unnamed messages to multiple users as a client");
|
||||
}
|
||||
|
||||
if (clientIds == null)
|
||||
{
|
||||
throw new ArgumentNullException("You must pass in a valid clientId List");
|
||||
}
|
||||
|
||||
ulong hash = 0;
|
||||
switch (m_NetworkManager.NetworkConfig.RpcHashSize)
|
||||
{
|
||||
case HashSize.VarIntFourBytes:
|
||||
hash = XXHash.Hash32(messageName);
|
||||
break;
|
||||
case HashSize.VarIntEightBytes:
|
||||
hash = XXHash.Hash64(messageName);
|
||||
break;
|
||||
}
|
||||
var message = new NamedMessage
|
||||
{
|
||||
Hash = hash,
|
||||
Data = messageStream
|
||||
};
|
||||
var size = m_NetworkManager.SendMessage(message, networkDelivery, clientIds);
|
||||
|
||||
// Size is zero if we were only sending the message to ourself in which case it isn't sent.
|
||||
if (size != 0)
|
||||
{
|
||||
m_NetworkManager.NetworkMetrics.TrackNamedMessageSent(clientIds, messageName, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/CustomMessageManager.cs.meta
Normal file
11
Runtime/Messaging/CustomMessageManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15c647dad40a44d46886dca112cfd524
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
17
Runtime/Messaging/ILPPMessageProvider.cs
Normal file
17
Runtime/Messaging/ILPPMessageProvider.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct ILPPMessageProvider : IMessageProvider
|
||||
{
|
||||
#pragma warning disable IDE1006 // disable naming rule violation check
|
||||
// This is NOT modified by RuntimeAccessModifiersILPP right now, but is populated by ILPP.
|
||||
internal static readonly List<MessagingSystem.MessageWithHandler> __network_message_types = new List<MessagingSystem.MessageWithHandler>();
|
||||
#pragma warning restore IDE1006 // restore naming rule violation check
|
||||
|
||||
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
||||
{
|
||||
return __network_message_types;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/ILPPMessageProvider.cs.meta
Normal file
11
Runtime/Messaging/ILPPMessageProvider.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5bfc2b13811eb5429a0eef59dd88b71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Runtime/Messaging/IMessageProvider.cs
Normal file
9
Runtime/Messaging/IMessageProvider.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal interface IMessageProvider
|
||||
{
|
||||
List<MessagingSystem.MessageWithHandler> GetMessages();
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/IMessageProvider.cs.meta
Normal file
11
Runtime/Messaging/IMessageProvider.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ed41def88d712c4b9c115310e6b0127
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
Runtime/Messaging/IMessageSender.cs
Normal file
7
Runtime/Messaging/IMessageSender.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal interface IMessageSender
|
||||
{
|
||||
void Send(ulong clientId, NetworkDelivery delivery, FastBufferWriter batchData);
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/IMessageSender.cs.meta
Normal file
11
Runtime/Messaging/IMessageSender.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15b54cd88eba22648ade4240523b8c65
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
97
Runtime/Messaging/INetworkHooks.cs
Normal file
97
Runtime/Messaging/INetworkHooks.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to react to different events in the messaging system. Primary use case is for
|
||||
/// collecting profiling data and metrics data. Additionally, it provides OnVerifyCanSend and OnVerifyCanReceive
|
||||
/// to allow for networking implementations to put limits on when certain messages can or can't be sent or received.
|
||||
/// </summary>
|
||||
internal interface INetworkHooks
|
||||
{
|
||||
/// <summary>
|
||||
/// Called before an individual message is sent.
|
||||
/// </summary>
|
||||
/// <param name="clientId">The destination clientId</param>
|
||||
/// <param name="messageType">The type of the message being sent</param>
|
||||
/// <param name="delivery"></param>
|
||||
void OnBeforeSendMessage(ulong clientId, Type messageType, NetworkDelivery delivery);
|
||||
|
||||
/// <summary>
|
||||
/// Called after an individual message is sent.
|
||||
/// </summary>
|
||||
/// <param name="clientId">The destination clientId</param>
|
||||
/// <param name="messageType">The type of the message being sent</param>
|
||||
/// <param name="delivery"></param>
|
||||
/// <param name="messageSizeBytes">Number of bytes in the message, not including the message header</param>
|
||||
void OnAfterSendMessage(ulong clientId, Type messageType, NetworkDelivery delivery, int messageSizeBytes);
|
||||
|
||||
/// <summary>
|
||||
/// Called before an individual message is received.
|
||||
/// </summary>
|
||||
/// <param name="senderId">The source clientId</param>
|
||||
/// <param name="messageType">The type of the message being sent</param>
|
||||
/// <param name="messageSizeBytes">Number of bytes in the message, not including the message header</param>
|
||||
void OnBeforeReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes);
|
||||
|
||||
/// <summary>
|
||||
/// Called after an individual message is received.
|
||||
/// </summary>
|
||||
/// <param name="senderId">The source clientId</param>
|
||||
/// <param name="messageType">The type of the message being sent</param>
|
||||
/// <param name="messageSizeBytes">Number of bytes in the message, not including the message header</param>
|
||||
void OnAfterReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes);
|
||||
|
||||
/// <summary>
|
||||
/// Called before a batch of messages is sent
|
||||
/// </summary>
|
||||
/// <param name="clientId">The destination clientId</param>
|
||||
/// <param name="messageCount">Number of messages in the batch</param>
|
||||
/// <param name="batchSizeInBytes">Number of bytes in the batch, including the batch header</param>
|
||||
/// <param name="delivery"></param>
|
||||
void OnBeforeSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery);
|
||||
|
||||
/// <summary>
|
||||
/// Called after a batch of messages is sent
|
||||
/// </summary>
|
||||
/// <param name="clientId">The destination clientId</param>
|
||||
/// <param name="messageCount">Number of messages in the batch</param>
|
||||
/// <param name="batchSizeInBytes">Number of bytes in the batch, including the batch header</param>
|
||||
/// <param name="delivery"></param>
|
||||
void OnAfterSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery);
|
||||
|
||||
/// <summary>
|
||||
/// Called before a batch of messages is received
|
||||
/// </summary>
|
||||
/// <param name="senderId">The source clientId</param>
|
||||
/// <param name="messageCount">Number of messages in the batch</param>
|
||||
/// <param name="batchSizeInBytes">Number of bytes in the batch, including the batch header</param>
|
||||
void OnBeforeReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes);
|
||||
|
||||
/// <summary>
|
||||
/// Called after a batch of messages is received
|
||||
/// </summary>
|
||||
/// <param name="senderId">The source clientId</param>
|
||||
/// <param name="messageCount">Number of messages in the batch</param>
|
||||
/// <param name="batchSizeInBytes">Number of bytes in the batch, including the batch header</param>
|
||||
void OnAfterReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called before a message is sent. If this returns false, the message will be discarded.
|
||||
/// </summary>
|
||||
/// <param name="destinationId">The destination clientId</param>
|
||||
/// <param name="messageType">The type of the message</param>
|
||||
/// <param name="delivery"></param>
|
||||
/// <returns></returns>
|
||||
bool OnVerifyCanSend(ulong destinationId, Type messageType, NetworkDelivery delivery);
|
||||
|
||||
/// <summary>
|
||||
/// Called before a message is received. If this returns false, the message will be discarded.
|
||||
/// </summary>
|
||||
/// <param name="senderId">The source clientId</param>
|
||||
/// <param name="messageType">The type of the message</param>
|
||||
/// <returns></returns>
|
||||
bool OnVerifyCanReceive(ulong senderId, Type messageType);
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/INetworkHooks.cs.meta
Normal file
11
Runtime/Messaging/INetworkHooks.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b199c5a160beabb47bd6b0e4f06cfcd2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
49
Runtime/Messaging/INetworkMessage.cs
Normal file
49
Runtime/Messaging/INetworkMessage.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// Base building block for creating a message. Any struct (or class) that implements INetworkMessage
|
||||
/// will automatically be found by the system and all the proper mechanisms for sending and receiving
|
||||
/// that message will be hooked up automatically.
|
||||
///
|
||||
/// It's generally recommended to implement INetworkMessage types as structs, and define your messages
|
||||
/// as close as you can to the network transport format. For messages with no dynamic-length or optional
|
||||
/// data, FastBufferWriter allows for serializing the entire struct at once via writer.WriteValue(this)
|
||||
///
|
||||
/// In addition to the specified Serialize method, all INetworkMessage types must also have a
|
||||
/// static message handler for receiving messages of the following name and signature:
|
||||
///
|
||||
/// <code>
|
||||
/// public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
/// </code>
|
||||
///
|
||||
/// It is the responsibility of the Serialize and Receive methods to ensure there is enough buffer space
|
||||
/// to perform the serialization/deserialization, either via <see cref="FastBufferWriter.TryBeginWrite"/> and
|
||||
/// <see cref="FastBufferReader.TryBeginRead"/>, or via <see cref="FastBufferWriter.WriteValueSafe{T}(T)"/> and
|
||||
/// <see cref="FastBufferReader.ReadValueSafe{T}(T)"/>. The former is more efficient when it can be used
|
||||
/// for bounds checking for multiple values at once.
|
||||
///
|
||||
/// When bandwidth is a bigger concern than CPU usage, values can be packed with <see cref="BytePacker"/>
|
||||
/// and <see cref="ByteUnpacker"/>.
|
||||
///
|
||||
/// Note that for messages sent using non-fragmenting delivery modes (anything other than
|
||||
/// <see cref="NetworkDelivery.ReliableFragmentedSequenced"/>), there is a hard limit of 1300 bytes per message.
|
||||
/// With the fragmenting delivery mode, the limit is 64000 bytes per message. If your messages exceed that limit,
|
||||
/// you will have to split them into multiple smaller messages.
|
||||
///
|
||||
/// Messages are sent with:
|
||||
/// <see cref="NetworkManager.SendMessage{T}(T, NetworkDelivery, ulong, bool)"/>
|
||||
/// <see cref="NetworkManager.SendMessage{T}(T, NetworkDelivery, ulong*, int, bool)"/>
|
||||
/// <see cref="NetworkManager.SendMessage{T, U}(T, NetworkDelivery, U, bool)"/>
|
||||
/// <see cref="NetworkManager.SendMessage{T}(T, NetworkDelivery, NativeArray{ulong}, bool)"/>
|
||||
/// </summary>
|
||||
internal interface INetworkMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to serialize the message.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
void Serialize(FastBufferWriter writer);
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/INetworkMessage.cs.meta
Normal file
11
Runtime/Messaging/INetworkMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16079de8d8821a24c91db930bc892b5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Runtime/Messaging/MessageHeader.cs
Normal file
21
Runtime/Messaging/MessageHeader.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the header data that's serialized to the network when sending an <see cref="INetworkMessage"/>
|
||||
/// </summary>
|
||||
internal struct MessageHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// The byte representation of the message type. This is automatically assigned to each message
|
||||
/// by the MessagingSystem. This value is deterministic only so long as the list of messages remains
|
||||
/// unchanged - if new messages are added or messages are removed, MessageType assignments may be
|
||||
/// calculated differently.
|
||||
/// </summary>
|
||||
public byte MessageType;
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the message, NOT including the header.
|
||||
/// </summary>
|
||||
public ushort MessageSize;
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/MessageHeader.cs.meta
Normal file
11
Runtime/Messaging/MessageHeader.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74fa727ddec342c48ab49156a32b977b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Runtime/Messaging/Messages.meta
Normal file
8
Runtime/Messaging/Messages.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd834639d7f09614fa4f3296921871d8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
49
Runtime/Messaging/Messages/ChangeOwnershipMessage.cs
Normal file
49
Runtime/Messaging/Messages/ChangeOwnershipMessage.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct ChangeOwnershipMessage : INetworkMessage
|
||||
{
|
||||
public ulong NetworkObjectId;
|
||||
public ulong OwnerClientId;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValueSafe(this);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
{
|
||||
return;
|
||||
}
|
||||
reader.ReadValueSafe(out ChangeOwnershipMessage message);
|
||||
message.Handle(reader, context, context.SenderId, networkManager, reader.Length);
|
||||
}
|
||||
|
||||
public void Handle(FastBufferReader reader, in NetworkContext context, ulong senderId, NetworkManager networkManager, int messageSize)
|
||||
{
|
||||
if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out var networkObject))
|
||||
{
|
||||
networkManager.SpawnManager.TriggerOnSpawn(NetworkObjectId, reader, context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (networkObject.OwnerClientId == networkManager.LocalClientId)
|
||||
{
|
||||
//We are current owner.
|
||||
networkObject.InvokeBehaviourOnLostOwnership();
|
||||
}
|
||||
|
||||
networkObject.OwnerClientId = OwnerClientId;
|
||||
|
||||
if (OwnerClientId == networkManager.LocalClientId)
|
||||
{
|
||||
//We are new owner.
|
||||
networkObject.InvokeBehaviourOnGainedOwnership();
|
||||
}
|
||||
|
||||
networkManager.NetworkMetrics.TrackOwnershipChangeReceived(senderId, networkObject, messageSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/ChangeOwnershipMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/ChangeOwnershipMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 841becdc46b20d5408a81bc30ac950f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
94
Runtime/Messaging/Messages/ConnectionApprovedMessage.cs
Normal file
94
Runtime/Messaging/Messages/ConnectionApprovedMessage.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct ConnectionApprovedMessage : INetworkMessage
|
||||
{
|
||||
public ulong OwnerClientId;
|
||||
public int NetworkTick;
|
||||
public int SceneObjectCount;
|
||||
|
||||
// Not serialized, held as references to serialize NetworkVariable data
|
||||
public HashSet<NetworkObject> SpawnedObjectsList;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
if (!writer.TryBeginWrite(sizeof(ulong) + sizeof(int) + sizeof(int)))
|
||||
{
|
||||
throw new OverflowException(
|
||||
$"Not enough space in the write buffer to serialize {nameof(ConnectionApprovedMessage)}");
|
||||
}
|
||||
writer.WriteValue(OwnerClientId);
|
||||
writer.WriteValue(NetworkTick);
|
||||
writer.WriteValue(SceneObjectCount);
|
||||
|
||||
if (SceneObjectCount != 0)
|
||||
{
|
||||
// Serialize NetworkVariable data
|
||||
foreach (var sobj in SpawnedObjectsList)
|
||||
{
|
||||
if (sobj.CheckObjectVisibility == null || sobj.CheckObjectVisibility(OwnerClientId))
|
||||
{
|
||||
sobj.Observers.Add(OwnerClientId);
|
||||
var sceneObject = sobj.GetMessageSceneObject(OwnerClientId);
|
||||
sceneObject.Serialize(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reader.TryBeginRead(sizeof(ulong) + sizeof(int) + sizeof(int)))
|
||||
{
|
||||
throw new OverflowException(
|
||||
$"Not enough space in the buffer to read {nameof(ConnectionApprovedMessage)}");
|
||||
}
|
||||
|
||||
var message = new ConnectionApprovedMessage();
|
||||
reader.ReadValue(out message.OwnerClientId);
|
||||
reader.ReadValue(out message.NetworkTick);
|
||||
reader.ReadValue(out message.SceneObjectCount);
|
||||
message.Handle(reader, context.SenderId, networkManager);
|
||||
}
|
||||
|
||||
public void Handle(FastBufferReader reader, ulong clientId, NetworkManager networkManager)
|
||||
{
|
||||
networkManager.LocalClientId = OwnerClientId;
|
||||
networkManager.NetworkMetrics.SetConnectionId(networkManager.LocalClientId);
|
||||
|
||||
var time = new NetworkTime(networkManager.NetworkTickSystem.TickRate, NetworkTick);
|
||||
networkManager.NetworkTimeSystem.Reset(time.Time, 0.15f); // Start with a constant RTT of 150 until we receive values from the transport.
|
||||
networkManager.NetworkTickSystem.Reset(networkManager.NetworkTimeSystem.LocalTime, networkManager.NetworkTimeSystem.ServerTime);
|
||||
|
||||
networkManager.LocalClient = new NetworkClient() { ClientId = networkManager.LocalClientId };
|
||||
|
||||
// Only if scene management is disabled do we handle NetworkObject synchronization at this point
|
||||
if (!networkManager.NetworkConfig.EnableSceneManagement)
|
||||
{
|
||||
networkManager.SpawnManager.DestroySceneObjects();
|
||||
|
||||
// Deserializing NetworkVariable data is deferred from Receive() to Handle to avoid needing
|
||||
// to create a list to hold the data. This is a breach of convention for performance reasons.
|
||||
for (ushort i = 0; i < SceneObjectCount; i++)
|
||||
{
|
||||
var sceneObject = new NetworkObject.SceneObject();
|
||||
sceneObject.Deserialize(reader);
|
||||
NetworkObject.AddSceneObject(sceneObject, reader, networkManager);
|
||||
}
|
||||
|
||||
// Mark the client being connected
|
||||
networkManager.IsConnectedClient = true;
|
||||
// When scene management is disabled we notify after everything is synchronized
|
||||
networkManager.InvokeOnClientConnectedCallback(clientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/ConnectionApprovedMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/ConnectionApprovedMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebbc74ce01b073340aa445f3bd59ff62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
115
Runtime/Messaging/Messages/ConnectionRequestMessage.cs
Normal file
115
Runtime/Messaging/Messages/ConnectionRequestMessage.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct ConnectionRequestMessage : INetworkMessage
|
||||
{
|
||||
public ulong ConfigHash;
|
||||
|
||||
public byte[] ConnectionData;
|
||||
|
||||
public bool ShouldSendConnectionData;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
if (ShouldSendConnectionData)
|
||||
{
|
||||
writer.WriteValueSafe(ConfigHash);
|
||||
writer.WriteValueSafe(ConnectionData);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteValueSafe(ConfigHash);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsServer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var message = new ConnectionRequestMessage();
|
||||
if (networkManager.NetworkConfig.ConnectionApproval)
|
||||
{
|
||||
if (!reader.TryBeginRead(FastBufferWriter.GetWriteSize(message.ConfigHash) +
|
||||
FastBufferWriter.GetWriteSize<int>()))
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning($"Incomplete connection request message given config - possible {nameof(NetworkConfig)} mismatch.");
|
||||
}
|
||||
|
||||
networkManager.DisconnectClient(context.SenderId);
|
||||
return;
|
||||
}
|
||||
reader.ReadValue(out message.ConfigHash);
|
||||
|
||||
if (!networkManager.NetworkConfig.CompareConfig(message.ConfigHash))
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning($"{nameof(NetworkConfig)} mismatch. The configuration between the server and client does not match");
|
||||
}
|
||||
|
||||
networkManager.DisconnectClient(context.SenderId);
|
||||
return;
|
||||
}
|
||||
|
||||
reader.ReadValueSafe(out message.ConnectionData);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!reader.TryBeginRead(FastBufferWriter.GetWriteSize(message.ConfigHash)))
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning($"Incomplete connection request message.");
|
||||
}
|
||||
|
||||
networkManager.DisconnectClient(context.SenderId);
|
||||
return;
|
||||
}
|
||||
reader.ReadValue(out message.ConfigHash);
|
||||
|
||||
if (!networkManager.NetworkConfig.CompareConfig(message.ConfigHash))
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning($"{nameof(NetworkConfig)} mismatch. The configuration between the server and client does not match");
|
||||
}
|
||||
|
||||
networkManager.DisconnectClient(context.SenderId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
message.Handle(networkManager, context.SenderId);
|
||||
}
|
||||
|
||||
public void Handle(NetworkManager networkManager, ulong senderId)
|
||||
{
|
||||
if (networkManager.PendingClients.TryGetValue(senderId, out PendingClient client))
|
||||
{
|
||||
// Set to pending approval to prevent future connection requests from being approved
|
||||
client.ConnectionState = PendingClient.State.PendingApproval;
|
||||
}
|
||||
|
||||
if (networkManager.NetworkConfig.ConnectionApproval)
|
||||
{
|
||||
// Note: Delegate creation allocates.
|
||||
// Note: ToArray() also allocates. :(
|
||||
networkManager.InvokeConnectionApproval(ConnectionData, senderId,
|
||||
(createPlayerObject, playerPrefabHash, approved, position, rotation) =>
|
||||
{
|
||||
var localCreatePlayerObject = createPlayerObject;
|
||||
networkManager.HandleApproval(senderId, localCreatePlayerObject, playerPrefabHash, approved,
|
||||
position, rotation);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
networkManager.HandleApproval(senderId, networkManager.NetworkConfig.PlayerPrefab != null, null, true, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/ConnectionRequestMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/ConnectionRequestMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd160468676e06049ad81dcfb22c3dc2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
30
Runtime/Messaging/Messages/CreateObjectMessage.cs
Normal file
30
Runtime/Messaging/Messages/CreateObjectMessage.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct CreateObjectMessage : INetworkMessage
|
||||
{
|
||||
public NetworkObject.SceneObject ObjectInfo;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
ObjectInfo.Serialize(writer);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var message = new CreateObjectMessage();
|
||||
message.ObjectInfo.Deserialize(reader);
|
||||
message.Handle(context.SenderId, reader, networkManager);
|
||||
}
|
||||
|
||||
public void Handle(ulong senderId, FastBufferReader reader, NetworkManager networkManager)
|
||||
{
|
||||
var networkObject = NetworkObject.AddSceneObject(ObjectInfo, reader, networkManager);
|
||||
networkManager.NetworkMetrics.TrackObjectSpawnReceived(senderId, networkObject, reader.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/CreateObjectMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/CreateObjectMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff075de988adf5a4294620aa2d85fcd0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
41
Runtime/Messaging/Messages/DestroyObjectMessage.cs
Normal file
41
Runtime/Messaging/Messages/DestroyObjectMessage.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct DestroyObjectMessage : INetworkMessage
|
||||
{
|
||||
public ulong NetworkObjectId;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValueSafe(this);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
{
|
||||
return;
|
||||
}
|
||||
reader.ReadValueSafe(out DestroyObjectMessage message);
|
||||
message.Handle(context.SenderId, networkManager, reader.Length);
|
||||
}
|
||||
|
||||
public void Handle(ulong senderId, NetworkManager networkManager, int messageSize)
|
||||
{
|
||||
if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out var networkObject))
|
||||
{
|
||||
// This is the same check and log message that happens inside OnDespawnObject, but we have to do it here
|
||||
// while we still have access to the network ID, otherwise the log message will be less useful.
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning($"Trying to destroy {nameof(NetworkObject)} #{NetworkObjectId} but it does not exist in {nameof(NetworkSpawnManager.SpawnedObjects)} anymore!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
networkManager.NetworkMetrics.TrackObjectDestroyReceived(senderId, networkObject, messageSize);
|
||||
networkManager.SpawnManager.OnDespawnObject(networkObject, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/DestroyObjectMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/DestroyObjectMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18473ed11c97e7241aecb0c72d4bffb2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
Runtime/Messaging/Messages/NamedMessage.cs
Normal file
22
Runtime/Messaging/Messages/NamedMessage.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct NamedMessage : INetworkMessage
|
||||
{
|
||||
public ulong Hash;
|
||||
public FastBufferWriter Data;
|
||||
|
||||
public unsafe void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValueSafe(Hash);
|
||||
writer.WriteBytesSafe(Data.GetUnsafePtr(), Data.Length);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var message = new NamedMessage();
|
||||
reader.ReadValueSafe(out message.Hash);
|
||||
|
||||
((NetworkManager)context.SystemOwner).CustomMessagingManager.InvokeNamedMessage(message.Hash, context.SenderId, reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/NamedMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/NamedMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b6bcd41dcce65743ba387fc4e2c6fa8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
223
Runtime/Messaging/Messages/NetworkVariableDeltaMessage.cs
Normal file
223
Runtime/Messaging/Messages/NetworkVariableDeltaMessage.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// This particular struct is a little weird because it doesn't actually contain the data
|
||||
/// it's serializing. Instead, it contains references to the data it needs to do the
|
||||
/// serialization. This is due to the generally amorphous nature of network variable
|
||||
/// deltas, since they're all driven by custom virtual method overloads.
|
||||
/// </summary>
|
||||
internal struct NetworkVariableDeltaMessage : INetworkMessage
|
||||
{
|
||||
public ulong NetworkObjectId;
|
||||
public ushort NetworkBehaviourIndex;
|
||||
|
||||
public HashSet<int> DeliveryMappedNetworkVariableIndex;
|
||||
public ulong ClientId;
|
||||
public NetworkBehaviour NetworkBehaviour;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
if (!writer.TryBeginWrite(FastBufferWriter.GetWriteSize(NetworkObjectId) +
|
||||
FastBufferWriter.GetWriteSize(NetworkBehaviourIndex)))
|
||||
{
|
||||
throw new OverflowException(
|
||||
$"Not enough space in the buffer to write {nameof(NetworkVariableDeltaMessage)}");
|
||||
}
|
||||
writer.WriteValue(NetworkObjectId);
|
||||
writer.WriteValue(NetworkBehaviourIndex);
|
||||
for (int k = 0; k < NetworkBehaviour.NetworkVariableFields.Count; k++)
|
||||
{
|
||||
if (!DeliveryMappedNetworkVariableIndex.Contains(k))
|
||||
{
|
||||
// This var does not belong to the currently iterating delivery group.
|
||||
if (NetworkBehaviour.NetworkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
|
||||
{
|
||||
writer.WriteValueSafe((short)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteValueSafe(false);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// if I'm dirty AND a client, write (server always has all permissions)
|
||||
// if I'm dirty AND the server AND the client can read me, send.
|
||||
bool shouldWrite = NetworkBehaviour.NetworkVariableFields[k].ShouldWrite(ClientId, NetworkBehaviour.NetworkManager.IsServer);
|
||||
|
||||
if (NetworkBehaviour.NetworkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
|
||||
{
|
||||
if (!shouldWrite)
|
||||
{
|
||||
writer.WriteValueSafe((ushort)0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteValueSafe(shouldWrite);
|
||||
}
|
||||
|
||||
if (shouldWrite)
|
||||
{
|
||||
if (NetworkBehaviour.NetworkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
|
||||
{
|
||||
var tmpWriter = new FastBufferWriter(MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.Temp, short.MaxValue);
|
||||
NetworkBehaviour.NetworkVariableFields[k].WriteDelta(tmpWriter);
|
||||
|
||||
writer.WriteValueSafe((ushort)tmpWriter.Length);
|
||||
tmpWriter.CopyTo(writer);
|
||||
}
|
||||
else
|
||||
{
|
||||
NetworkBehaviour.NetworkVariableFields[k].WriteDelta(writer);
|
||||
}
|
||||
|
||||
if (!NetworkBehaviour.NetworkVariableIndexesToResetSet.Contains(k))
|
||||
{
|
||||
NetworkBehaviour.NetworkVariableIndexesToResetSet.Add(k);
|
||||
NetworkBehaviour.NetworkVariableIndexesToReset.Add(k);
|
||||
}
|
||||
|
||||
NetworkBehaviour.NetworkManager.NetworkMetrics.TrackNetworkVariableDeltaSent(
|
||||
ClientId,
|
||||
NetworkBehaviour.NetworkObject,
|
||||
NetworkBehaviour.NetworkVariableFields[k].Name,
|
||||
NetworkBehaviour.__getTypeName(),
|
||||
writer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
|
||||
var message = new NetworkVariableDeltaMessage();
|
||||
if (!reader.TryBeginRead(FastBufferWriter.GetWriteSize(message.NetworkObjectId) +
|
||||
FastBufferWriter.GetWriteSize(message.NetworkBehaviourIndex)))
|
||||
{
|
||||
throw new OverflowException(
|
||||
$"Not enough data in the buffer to read {nameof(NetworkVariableDeltaMessage)}");
|
||||
}
|
||||
reader.ReadValue(out message.NetworkObjectId);
|
||||
reader.ReadValue(out message.NetworkBehaviourIndex);
|
||||
message.Handle(context.SenderId, reader, context, networkManager);
|
||||
}
|
||||
|
||||
public void Handle(ulong senderId, FastBufferReader reader, in NetworkContext context, NetworkManager networkManager)
|
||||
{
|
||||
if (networkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out NetworkObject networkObject))
|
||||
{
|
||||
NetworkBehaviour behaviour = networkObject.GetNetworkBehaviourAtOrderIndex(NetworkBehaviourIndex);
|
||||
|
||||
if (behaviour == null)
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning($"Network variable delta message received for a non-existent behaviour. {nameof(NetworkObjectId)}: {NetworkObjectId}, {nameof(NetworkBehaviourIndex)}: {NetworkBehaviourIndex}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < behaviour.NetworkVariableFields.Count; i++)
|
||||
{
|
||||
ushort varSize = 0;
|
||||
|
||||
if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
|
||||
{
|
||||
reader.ReadValueSafe(out varSize);
|
||||
|
||||
if (varSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.ReadValueSafe(out bool deltaExists);
|
||||
if (!deltaExists)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (networkManager.IsServer)
|
||||
{
|
||||
// we are choosing not to fire an exception here, because otherwise a malicious client could use this to crash the server
|
||||
if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning($"Client wrote to {typeof(NetworkVariable<>).Name} without permission. => {nameof(NetworkObjectId)}: {NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {networkObject.GetNetworkBehaviourOrderIndex(behaviour)} - VariableIndex: {i}");
|
||||
NetworkLog.LogError($"[{behaviour.NetworkVariableFields[i].GetType().Name}]");
|
||||
}
|
||||
|
||||
reader.Seek(reader.Position + varSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
//This client wrote somewhere they are not allowed. This is critical
|
||||
//We can't just skip this field. Because we don't actually know how to dummy read
|
||||
//That is, we don't know how many bytes to skip. Because the interface doesn't have a
|
||||
//Read that gives us the value. Only a Read that applies the value straight away
|
||||
//A dummy read COULD be added to the interface for this situation, but it's just being too nice.
|
||||
//This is after all a developer fault. A critical error should be fine.
|
||||
// - TwoTen
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
|
||||
{
|
||||
NetworkLog.LogError($"Client wrote to {typeof(NetworkVariable<>).Name} without permission. No more variables can be read. This is critical. => {nameof(NetworkObjectId)}: {NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {networkObject.GetNetworkBehaviourOrderIndex(behaviour)} - VariableIndex: {i}");
|
||||
NetworkLog.LogError($"[{behaviour.NetworkVariableFields[i].GetType().Name}]");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
int readStartPos = reader.Position;
|
||||
|
||||
behaviour.NetworkVariableFields[i].ReadDelta(reader, networkManager.IsServer);
|
||||
|
||||
networkManager.NetworkMetrics.TrackNetworkVariableDeltaReceived(
|
||||
senderId,
|
||||
networkObject,
|
||||
behaviour.NetworkVariableFields[i].Name,
|
||||
behaviour.__getTypeName(),
|
||||
reader.Length);
|
||||
|
||||
|
||||
if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
|
||||
{
|
||||
if (reader.Position > (readStartPos + varSize))
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning(
|
||||
$"Var delta read too far. {reader.Position - (readStartPos + varSize)} bytes. => {nameof(NetworkObjectId)}: {NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {networkObject.GetNetworkBehaviourOrderIndex(behaviour)} - VariableIndex: {i}");
|
||||
}
|
||||
|
||||
reader.Seek(readStartPos + varSize);
|
||||
}
|
||||
else if (reader.Position < (readStartPos + varSize))
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning(
|
||||
$"Var delta read too little. {(readStartPos + varSize) - reader.Position} bytes. => {nameof(NetworkObjectId)}: {NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {networkObject.GetNetworkBehaviourOrderIndex(behaviour)} - VariableIndex: {i}");
|
||||
}
|
||||
|
||||
reader.Seek(readStartPos + varSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
networkManager.SpawnManager.TriggerOnSpawn(NetworkObjectId, reader, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfa1a454cc9fdb647ba89479fa6b8299
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
67
Runtime/Messaging/Messages/ParentSyncMessage.cs
Normal file
67
Runtime/Messaging/Messages/ParentSyncMessage.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct ParentSyncMessage : INetworkMessage
|
||||
{
|
||||
public ulong NetworkObjectId;
|
||||
|
||||
public bool IsReparented;
|
||||
|
||||
//If(Metadata.IsReparented)
|
||||
public bool IsLatestParentSet;
|
||||
|
||||
//If(IsLatestParentSet)
|
||||
public ulong? LatestParent;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValueSafe(NetworkObjectId);
|
||||
writer.WriteValueSafe(IsReparented);
|
||||
if (IsReparented)
|
||||
{
|
||||
writer.WriteValueSafe(IsLatestParentSet);
|
||||
if (IsLatestParentSet)
|
||||
{
|
||||
writer.WriteValueSafe((ulong)LatestParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var message = new ParentSyncMessage();
|
||||
reader.ReadValueSafe(out message.NetworkObjectId);
|
||||
reader.ReadValueSafe(out message.IsReparented);
|
||||
if (message.IsReparented)
|
||||
{
|
||||
reader.ReadValueSafe(out message.IsLatestParentSet);
|
||||
if (message.IsLatestParentSet)
|
||||
{
|
||||
reader.ReadValueSafe(out ulong latestParent);
|
||||
message.LatestParent = latestParent;
|
||||
}
|
||||
}
|
||||
|
||||
message.Handle(reader, context, networkManager);
|
||||
}
|
||||
|
||||
public void Handle(FastBufferReader reader, in NetworkContext context, NetworkManager networkManager)
|
||||
{
|
||||
if (networkManager.SpawnManager.SpawnedObjects.ContainsKey(NetworkObjectId))
|
||||
{
|
||||
var networkObject = networkManager.SpawnManager.SpawnedObjects[NetworkObjectId];
|
||||
networkObject.SetNetworkParenting(IsReparented, LatestParent);
|
||||
networkObject.ApplyNetworkParenting();
|
||||
}
|
||||
else
|
||||
{
|
||||
networkManager.SpawnManager.TriggerOnSpawn(NetworkObjectId, reader, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/ParentSyncMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/ParentSyncMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 237bfa46868f1ff48863f3a6df2f5506
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
109
Runtime/Messaging/Messages/RpcMessage.cs
Normal file
109
Runtime/Messaging/Messages/RpcMessage.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct RpcMessage : INetworkMessage
|
||||
{
|
||||
public enum RpcType : byte
|
||||
{
|
||||
Server,
|
||||
Client
|
||||
}
|
||||
|
||||
public struct HeaderData
|
||||
{
|
||||
public RpcType Type;
|
||||
public ulong NetworkObjectId;
|
||||
public ushort NetworkBehaviourId;
|
||||
public uint NetworkMethodId;
|
||||
}
|
||||
|
||||
public HeaderData Header;
|
||||
public FastBufferWriter RpcData;
|
||||
|
||||
|
||||
public unsafe void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
if (!writer.TryBeginWrite(FastBufferWriter.GetWriteSize(Header) + RpcData.Length))
|
||||
{
|
||||
throw new OverflowException("Not enough space in the buffer to store RPC data.");
|
||||
}
|
||||
writer.WriteValue(Header);
|
||||
writer.WriteBytes(RpcData.GetUnsafePtr(), RpcData.Length);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var message = new RpcMessage();
|
||||
if (!reader.TryBeginRead(FastBufferWriter.GetWriteSize(message.Header)))
|
||||
{
|
||||
throw new OverflowException("Not enough space in the buffer to read RPC data.");
|
||||
}
|
||||
reader.ReadValue(out message.Header);
|
||||
message.Handle(reader, context, (NetworkManager)context.SystemOwner, context.SenderId, true);
|
||||
}
|
||||
|
||||
public void Handle(FastBufferReader reader, in NetworkContext context, NetworkManager networkManager, ulong senderId, bool canDefer)
|
||||
{
|
||||
if (NetworkManager.__rpc_func_table.ContainsKey(Header.NetworkMethodId))
|
||||
{
|
||||
if (!networkManager.SpawnManager.SpawnedObjects.ContainsKey(Header.NetworkObjectId))
|
||||
{
|
||||
if (canDefer)
|
||||
{
|
||||
networkManager.SpawnManager.TriggerOnSpawn(Header.NetworkObjectId, reader, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
NetworkLog.LogError($"Tried to invoke an RPC on a non-existent {nameof(NetworkObject)} with {nameof(canDefer)}=false");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var networkObject = networkManager.SpawnManager.SpawnedObjects[Header.NetworkObjectId];
|
||||
|
||||
var networkBehaviour = networkObject.GetNetworkBehaviourAtOrderIndex(Header.NetworkBehaviourId);
|
||||
if (networkBehaviour == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var rpcParams = new __RpcParams();
|
||||
switch (Header.Type)
|
||||
{
|
||||
case RpcType.Server:
|
||||
rpcParams.Server = new ServerRpcParams
|
||||
{
|
||||
Receive = new ServerRpcReceiveParams
|
||||
{
|
||||
SenderClientId = senderId
|
||||
}
|
||||
};
|
||||
break;
|
||||
case RpcType.Client:
|
||||
rpcParams.Client = new ClientRpcParams
|
||||
{
|
||||
Receive = new ClientRpcReceiveParams
|
||||
{
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
NetworkManager.__rpc_func_table[Header.NetworkMethodId](networkBehaviour, reader, rpcParams);
|
||||
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
if (NetworkManager.__rpc_name_table.TryGetValue(Header.NetworkMethodId, out var rpcMethodName))
|
||||
{
|
||||
networkManager.NetworkMetrics.TrackRpcReceived(
|
||||
senderId,
|
||||
networkObject,
|
||||
rpcMethodName,
|
||||
networkBehaviour.__getTypeName(),
|
||||
reader.Length);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/RpcMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/RpcMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8fc9f8cca6a18b428460b62bce2d8f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
19
Runtime/Messaging/Messages/SceneEventMessage.cs
Normal file
19
Runtime/Messaging/Messages/SceneEventMessage.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
// Todo: Would be lovely to get this one nicely formatted with all the data it sends in the struct
|
||||
// like most of the other messages when we have some more time and can come back and refactor this.
|
||||
internal struct SceneEventMessage : INetworkMessage
|
||||
{
|
||||
public SceneEventData EventData;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
EventData.Serialize(writer);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
((NetworkManager)context.SystemOwner).SceneManager.HandleSceneEvent(context.SenderId, reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/SceneEventMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/SceneEventMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 152f6ccef0320cf4abcf19099c1997e3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
50
Runtime/Messaging/Messages/ServerLogMessage.cs
Normal file
50
Runtime/Messaging/Messages/ServerLogMessage.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct ServerLogMessage : INetworkMessage
|
||||
{
|
||||
public NetworkLog.LogType LogType;
|
||||
// It'd be lovely to be able to replace this with FixedString or NativeArray...
|
||||
// But it's not really practical. On the sending side, the user is likely to want
|
||||
// to work with strings and would need to convert, and on the receiving side,
|
||||
// we'd have to convert it to a string to be able to pass it to the log system.
|
||||
// So an allocation is unavoidable here on both sides.
|
||||
public string Message;
|
||||
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValueSafe(LogType);
|
||||
BytePacker.WriteValuePacked(writer, Message);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (networkManager.IsServer && networkManager.NetworkConfig.EnableNetworkLogs)
|
||||
{
|
||||
var message = new ServerLogMessage();
|
||||
reader.ReadValueSafe(out message.LogType);
|
||||
ByteUnpacker.ReadValuePacked(reader, out message.Message);
|
||||
message.Handle(context.SenderId, networkManager, reader.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ulong senderId, NetworkManager networkManager, int messageSize)
|
||||
{
|
||||
networkManager.NetworkMetrics.TrackServerLogReceived(senderId, (uint)LogType, messageSize);
|
||||
|
||||
switch (LogType)
|
||||
{
|
||||
case NetworkLog.LogType.Info:
|
||||
NetworkLog.LogInfoServerLocal(Message, senderId);
|
||||
break;
|
||||
case NetworkLog.LogType.Warning:
|
||||
NetworkLog.LogWarningServerLocal(Message, senderId);
|
||||
break;
|
||||
case NetworkLog.LogType.Error:
|
||||
NetworkLog.LogErrorServerLocal(Message, senderId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/ServerLogMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/ServerLogMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d1c8aae1f7b7194eb3ab1cab260f34f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
161
Runtime/Messaging/Messages/SnapshotDataMessage.cs
Normal file
161
Runtime/Messaging/Messages/SnapshotDataMessage.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct SnapshotDataMessage : INetworkMessage
|
||||
{
|
||||
public int CurrentTick;
|
||||
public ushort Sequence;
|
||||
|
||||
public ushort Range;
|
||||
|
||||
public byte[] SendMainBuffer;
|
||||
public NativeArray<byte> ReceiveMainBuffer;
|
||||
|
||||
public struct AckData
|
||||
{
|
||||
public ushort LastReceivedSequence;
|
||||
public ushort ReceivedSequenceMask;
|
||||
}
|
||||
|
||||
public AckData Ack;
|
||||
|
||||
public struct EntryData
|
||||
{
|
||||
public ulong NetworkObjectId;
|
||||
public ushort BehaviourIndex;
|
||||
public ushort VariableIndex;
|
||||
public int TickWritten;
|
||||
public ushort Position;
|
||||
public ushort Length;
|
||||
}
|
||||
|
||||
public NativeList<EntryData> Entries;
|
||||
|
||||
public struct SpawnData
|
||||
{
|
||||
public ulong NetworkObjectId;
|
||||
public uint Hash;
|
||||
public bool IsSceneObject;
|
||||
|
||||
public bool IsPlayerObject;
|
||||
public ulong OwnerClientId;
|
||||
public ulong ParentNetworkId;
|
||||
public Vector3 Position;
|
||||
public Quaternion Rotation;
|
||||
public Vector3 Scale;
|
||||
|
||||
public int TickWritten;
|
||||
}
|
||||
|
||||
public NativeList<SpawnData> Spawns;
|
||||
|
||||
public struct DespawnData
|
||||
{
|
||||
public ulong NetworkObjectId;
|
||||
public int TickWritten;
|
||||
}
|
||||
|
||||
public NativeList<DespawnData> Despawns;
|
||||
|
||||
public unsafe void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
if (!writer.TryBeginWrite(
|
||||
FastBufferWriter.GetWriteSize(CurrentTick) +
|
||||
FastBufferWriter.GetWriteSize(Sequence) +
|
||||
FastBufferWriter.GetWriteSize(Range) + Range +
|
||||
FastBufferWriter.GetWriteSize(Ack) +
|
||||
FastBufferWriter.GetWriteSize<ushort>() +
|
||||
Entries.Length * sizeof(EntryData) +
|
||||
FastBufferWriter.GetWriteSize<ushort>() +
|
||||
Spawns.Length * sizeof(SpawnData) +
|
||||
FastBufferWriter.GetWriteSize<ushort>() +
|
||||
Despawns.Length * sizeof(DespawnData)
|
||||
))
|
||||
{
|
||||
Entries.Dispose();
|
||||
Spawns.Dispose();
|
||||
Despawns.Dispose();
|
||||
throw new OverflowException($"Not enough space to serialize {nameof(SnapshotDataMessage)}");
|
||||
}
|
||||
writer.WriteValue(CurrentTick);
|
||||
writer.WriteValue(Sequence);
|
||||
|
||||
writer.WriteValue(Range);
|
||||
writer.WriteBytes(SendMainBuffer, Range);
|
||||
writer.WriteValue(Ack);
|
||||
|
||||
writer.WriteValue((ushort)Entries.Length);
|
||||
writer.WriteBytes((byte*)Entries.GetUnsafePtr(), Entries.Length * sizeof(EntryData));
|
||||
|
||||
writer.WriteValue((ushort)Spawns.Length);
|
||||
writer.WriteBytes((byte*)Spawns.GetUnsafePtr(), Spawns.Length * sizeof(SpawnData));
|
||||
|
||||
writer.WriteValue((ushort)Despawns.Length);
|
||||
writer.WriteBytes((byte*)Despawns.GetUnsafePtr(), Despawns.Length * sizeof(DespawnData));
|
||||
|
||||
Entries.Dispose();
|
||||
Spawns.Dispose();
|
||||
Despawns.Dispose();
|
||||
}
|
||||
|
||||
public static unsafe void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
var message = new SnapshotDataMessage();
|
||||
if (!reader.TryBeginRead(
|
||||
FastBufferWriter.GetWriteSize(message.CurrentTick) +
|
||||
FastBufferWriter.GetWriteSize(message.Sequence) +
|
||||
FastBufferWriter.GetWriteSize(message.Range)
|
||||
))
|
||||
{
|
||||
throw new OverflowException($"Not enough space to deserialize {nameof(SnapshotDataMessage)}");
|
||||
}
|
||||
reader.ReadValue(out message.CurrentTick);
|
||||
reader.ReadValue(out message.Sequence);
|
||||
|
||||
reader.ReadValue(out message.Range);
|
||||
message.ReceiveMainBuffer = new NativeArray<byte>(message.Range, Allocator.Temp);
|
||||
reader.ReadBytesSafe((byte*)message.ReceiveMainBuffer.GetUnsafePtr(), message.Range);
|
||||
reader.ReadValueSafe(out message.Ack);
|
||||
|
||||
reader.ReadValueSafe(out ushort length);
|
||||
message.Entries = new NativeList<EntryData>(length, Allocator.Temp);
|
||||
message.Entries.Length = length;
|
||||
reader.ReadBytesSafe((byte*)message.Entries.GetUnsafePtr(), message.Entries.Length * sizeof(EntryData));
|
||||
|
||||
reader.ReadValueSafe(out length);
|
||||
message.Spawns = new NativeList<SpawnData>(length, Allocator.Temp);
|
||||
message.Spawns.Length = length;
|
||||
reader.ReadBytesSafe((byte*)message.Spawns.GetUnsafePtr(), message.Spawns.Length * sizeof(SpawnData));
|
||||
|
||||
reader.ReadValueSafe(out length);
|
||||
message.Despawns = new NativeList<DespawnData>(length, Allocator.Temp);
|
||||
message.Despawns.Length = length;
|
||||
reader.ReadBytesSafe((byte*)message.Despawns.GetUnsafePtr(), message.Despawns.Length * sizeof(DespawnData));
|
||||
|
||||
using (message.ReceiveMainBuffer)
|
||||
using (message.Entries)
|
||||
using (message.Spawns)
|
||||
using (message.Despawns)
|
||||
{
|
||||
message.Handle(context.SenderId, networkManager);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ulong senderId, NetworkManager networkManager)
|
||||
{
|
||||
// todo: temporary hack around bug
|
||||
if (!networkManager.IsServer)
|
||||
{
|
||||
senderId = networkManager.ServerClientId;
|
||||
}
|
||||
|
||||
var snapshotSystem = networkManager.SnapshotSystem;
|
||||
snapshotSystem.HandleSnapshot(senderId, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/SnapshotDataMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/SnapshotDataMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5cf75026c2ab86646aac16b39d7259ad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
29
Runtime/Messaging/Messages/TimeSyncMessage.cs
Normal file
29
Runtime/Messaging/Messages/TimeSyncMessage.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct TimeSyncMessage : INetworkMessage
|
||||
{
|
||||
public int Tick;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValueSafe(this);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
{
|
||||
return;
|
||||
}
|
||||
reader.ReadValueSafe(out TimeSyncMessage message);
|
||||
message.Handle(context.SenderId, networkManager);
|
||||
}
|
||||
|
||||
public void Handle(ulong senderId, NetworkManager networkManager)
|
||||
{
|
||||
var time = new NetworkTime(networkManager.NetworkTickSystem.TickRate, Tick);
|
||||
networkManager.NetworkTimeSystem.Sync(time.Time, networkManager.NetworkConfig.NetworkTransport.GetCurrentRtt(senderId) / 1000d);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/TimeSyncMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/TimeSyncMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94afa081c8f5e0a4fb05e0643a968c46
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
17
Runtime/Messaging/Messages/UnnamedMessage.cs
Normal file
17
Runtime/Messaging/Messages/UnnamedMessage.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct UnnamedMessage : INetworkMessage
|
||||
{
|
||||
public FastBufferWriter Data;
|
||||
|
||||
public unsafe void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteBytesSafe(Data.GetUnsafePtr(), Data.Length);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
((NetworkManager)context.SystemOwner).CustomMessagingManager.InvokeUnnamedMessage(context.SenderId, reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/Messages/UnnamedMessage.cs.meta
Normal file
11
Runtime/Messaging/Messages/UnnamedMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7cece0a7c7653648a7bc8fa920843be
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
474
Runtime/Messaging/MessagingSystem.cs
Normal file
474
Runtime/Messaging/MessagingSystem.cs
Normal file
@@ -0,0 +1,474 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
|
||||
internal class InvalidMessageStructureException : SystemException
|
||||
{
|
||||
public InvalidMessageStructureException() { }
|
||||
public InvalidMessageStructureException(string issue) : base(issue) { }
|
||||
}
|
||||
|
||||
internal class MessagingSystem : IDisposable
|
||||
{
|
||||
private struct ReceiveQueueItem
|
||||
{
|
||||
public FastBufferReader Reader;
|
||||
public MessageHeader Header;
|
||||
public ulong SenderId;
|
||||
public float Timestamp;
|
||||
}
|
||||
|
||||
private struct SendQueueItem
|
||||
{
|
||||
public BatchHeader BatchHeader;
|
||||
public FastBufferWriter Writer;
|
||||
public readonly NetworkDelivery NetworkDelivery;
|
||||
|
||||
public SendQueueItem(NetworkDelivery delivery, int writerSize, Allocator writerAllocator, int maxWriterSize = -1)
|
||||
{
|
||||
Writer = new FastBufferWriter(writerSize, writerAllocator, maxWriterSize);
|
||||
NetworkDelivery = delivery;
|
||||
BatchHeader = default;
|
||||
}
|
||||
}
|
||||
|
||||
internal delegate void MessageHandler(FastBufferReader reader, in NetworkContext context);
|
||||
|
||||
private NativeList<ReceiveQueueItem> m_IncomingMessageQueue = new NativeList<ReceiveQueueItem>(16, Allocator.Persistent);
|
||||
|
||||
private MessageHandler[] m_MessageHandlers = new MessageHandler[255];
|
||||
private Type[] m_ReverseTypeMap = new Type[255];
|
||||
|
||||
private Dictionary<Type, byte> m_MessageTypes = new Dictionary<Type, byte>();
|
||||
private Dictionary<ulong, NativeList<SendQueueItem>> m_SendQueues = new Dictionary<ulong, NativeList<SendQueueItem>>();
|
||||
|
||||
private List<INetworkHooks> m_Hooks = new List<INetworkHooks>();
|
||||
|
||||
private byte m_HighMessageType;
|
||||
private object m_Owner;
|
||||
private IMessageSender m_MessageSender;
|
||||
private bool m_Disposed;
|
||||
|
||||
internal Type[] MessageTypes => m_ReverseTypeMap;
|
||||
internal MessageHandler[] MessageHandlers => m_MessageHandlers;
|
||||
internal int MessageHandlerCount => m_HighMessageType;
|
||||
|
||||
internal byte GetMessageType(Type t)
|
||||
{
|
||||
return m_MessageTypes[t];
|
||||
}
|
||||
|
||||
public const int NON_FRAGMENTED_MESSAGE_MAX_SIZE = 1300;
|
||||
public const int FRAGMENTED_MESSAGE_MAX_SIZE = 64000;
|
||||
|
||||
internal struct MessageWithHandler
|
||||
{
|
||||
public Type MessageType;
|
||||
public MessageHandler Handler;
|
||||
}
|
||||
|
||||
public MessagingSystem(IMessageSender messageSender, object owner, IMessageProvider provider = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_MessageSender = messageSender;
|
||||
m_Owner = owner;
|
||||
|
||||
if (provider == null)
|
||||
{
|
||||
provider = new ILPPMessageProvider();
|
||||
}
|
||||
var allowedTypes = provider.GetMessages();
|
||||
|
||||
allowedTypes.Sort((a, b) => string.CompareOrdinal(a.MessageType.FullName, b.MessageType.FullName));
|
||||
foreach (var type in allowedTypes)
|
||||
{
|
||||
RegisterMessageType(type);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Can't just iterate SendQueues or SendQueues.Keys because ClientDisconnected removes
|
||||
// from the queue.
|
||||
foreach (var kvp in m_SendQueues)
|
||||
{
|
||||
CleanupDisconnectedClient(kvp.Key);
|
||||
}
|
||||
m_IncomingMessageQueue.Dispose();
|
||||
m_Disposed = true;
|
||||
}
|
||||
|
||||
~MessagingSystem()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Hook(INetworkHooks hooks)
|
||||
{
|
||||
m_Hooks.Add(hooks);
|
||||
}
|
||||
|
||||
private void RegisterMessageType(MessageWithHandler messageWithHandler)
|
||||
{
|
||||
m_MessageHandlers[m_HighMessageType] = messageWithHandler.Handler;
|
||||
m_ReverseTypeMap[m_HighMessageType] = messageWithHandler.MessageType;
|
||||
m_MessageTypes[messageWithHandler.MessageType] = m_HighMessageType++;
|
||||
}
|
||||
|
||||
internal void HandleIncomingData(ulong clientId, ArraySegment<byte> data, float receiveTime)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* nativeData = data.Array)
|
||||
{
|
||||
var batchReader =
|
||||
new FastBufferReader(nativeData, Allocator.None, data.Count, data.Offset);
|
||||
if (!batchReader.TryBeginRead(sizeof(BatchHeader)))
|
||||
{
|
||||
NetworkLog.LogWarning("Received a packet too small to contain a BatchHeader. Ignoring it.");
|
||||
return;
|
||||
}
|
||||
|
||||
batchReader.ReadValue(out BatchHeader batchHeader);
|
||||
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
m_Hooks[hookIdx].OnBeforeReceiveBatch(clientId, batchHeader.BatchSize, batchReader.Length);
|
||||
}
|
||||
|
||||
for (var messageIdx = 0; messageIdx < batchHeader.BatchSize; ++messageIdx)
|
||||
{
|
||||
if (!batchReader.TryBeginRead(sizeof(MessageHeader)))
|
||||
{
|
||||
NetworkLog.LogWarning("Received a batch that didn't have enough data for all of its batches, ending early!");
|
||||
return;
|
||||
}
|
||||
batchReader.ReadValue(out MessageHeader messageHeader);
|
||||
|
||||
if (!batchReader.TryBeginRead(messageHeader.MessageSize))
|
||||
{
|
||||
NetworkLog.LogWarning("Received a message that claimed a size larger than the packet, ending early!");
|
||||
return;
|
||||
}
|
||||
m_IncomingMessageQueue.Add(new ReceiveQueueItem
|
||||
{
|
||||
Header = messageHeader,
|
||||
SenderId = clientId,
|
||||
Timestamp = receiveTime,
|
||||
// Copy the data for this message into a new FastBufferReader that owns that memory.
|
||||
// We can't guarantee the memory in the ArraySegment stays valid because we don't own it,
|
||||
// so we must move it to memory we do own.
|
||||
Reader = new FastBufferReader(batchReader.GetUnsafePtrAtCurrentPosition(), Allocator.TempJob, messageHeader.MessageSize)
|
||||
});
|
||||
batchReader.Seek(batchReader.Position + messageHeader.MessageSize);
|
||||
}
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
m_Hooks[hookIdx].OnAfterReceiveBatch(clientId, batchHeader.BatchSize, batchReader.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanReceive(ulong clientId, Type messageType)
|
||||
{
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
if (!m_Hooks[hookIdx].OnVerifyCanReceive(clientId, messageType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void HandleMessage(in MessageHeader header, FastBufferReader reader, ulong senderId, float timestamp)
|
||||
{
|
||||
if (header.MessageType >= m_HighMessageType)
|
||||
{
|
||||
Debug.LogWarning($"Received a message with invalid message type value {header.MessageType}");
|
||||
reader.Dispose();
|
||||
return;
|
||||
}
|
||||
var context = new NetworkContext
|
||||
{
|
||||
SystemOwner = m_Owner,
|
||||
SenderId = senderId,
|
||||
Timestamp = timestamp,
|
||||
Header = header
|
||||
};
|
||||
var type = m_ReverseTypeMap[header.MessageType];
|
||||
if (!CanReceive(senderId, type))
|
||||
{
|
||||
reader.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
m_Hooks[hookIdx].OnBeforeReceiveMessage(senderId, type, reader.Length);
|
||||
}
|
||||
var handler = m_MessageHandlers[header.MessageType];
|
||||
using (reader)
|
||||
{
|
||||
// No user-land message handler exceptions should escape the receive loop.
|
||||
// If an exception is throw, the message is ignored.
|
||||
// Example use case: A bad message is received that can't be deserialized and throws
|
||||
// an OverflowException because it specifies a length greater than the number of bytes in it
|
||||
// for some dynamic-length value.
|
||||
try
|
||||
{
|
||||
handler.Invoke(reader, context);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
m_Hooks[hookIdx].OnAfterReceiveMessage(senderId, type, reader.Length);
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe void ProcessIncomingMessageQueue()
|
||||
{
|
||||
for (var i = 0; i < m_IncomingMessageQueue.Length; ++i)
|
||||
{
|
||||
// Avoid copies...
|
||||
ref var item = ref m_IncomingMessageQueue.GetUnsafeList()->ElementAt(i);
|
||||
HandleMessage(item.Header, item.Reader, item.SenderId, item.Timestamp);
|
||||
}
|
||||
|
||||
m_IncomingMessageQueue.Clear();
|
||||
}
|
||||
|
||||
internal void ClientConnected(ulong clientId)
|
||||
{
|
||||
if (m_SendQueues.ContainsKey(clientId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_SendQueues[clientId] = new NativeList<SendQueueItem>(16, Allocator.Persistent);
|
||||
}
|
||||
|
||||
internal void ClientDisconnected(ulong clientId)
|
||||
{
|
||||
if (!m_SendQueues.ContainsKey(clientId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
CleanupDisconnectedClient(clientId);
|
||||
m_SendQueues.Remove(clientId);
|
||||
}
|
||||
|
||||
private unsafe void CleanupDisconnectedClient(ulong clientId)
|
||||
{
|
||||
var queue = m_SendQueues[clientId];
|
||||
for (var i = 0; i < queue.Length; ++i)
|
||||
{
|
||||
queue.GetUnsafeList()->ElementAt(i).Writer.Dispose();
|
||||
}
|
||||
|
||||
queue.Dispose();
|
||||
}
|
||||
|
||||
private bool CanSend(ulong clientId, Type messageType, NetworkDelivery delivery)
|
||||
{
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
if (!m_Hooks[hookIdx].OnVerifyCanSend(clientId, messageType, delivery))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal unsafe int SendMessage<TMessageType, TClientIdListType>(in TMessageType message, NetworkDelivery delivery, in TClientIdListType clientIds)
|
||||
where TMessageType : INetworkMessage
|
||||
where TClientIdListType : IReadOnlyList<ulong>
|
||||
{
|
||||
var maxSize = delivery == NetworkDelivery.ReliableFragmentedSequenced ? FRAGMENTED_MESSAGE_MAX_SIZE : NON_FRAGMENTED_MESSAGE_MAX_SIZE;
|
||||
var tmpSerializer = new FastBufferWriter(NON_FRAGMENTED_MESSAGE_MAX_SIZE - sizeof(MessageHeader), Allocator.Temp, maxSize - sizeof(MessageHeader));
|
||||
using (tmpSerializer)
|
||||
{
|
||||
message.Serialize(tmpSerializer);
|
||||
|
||||
for (var i = 0; i < clientIds.Count; ++i)
|
||||
{
|
||||
var clientId = clientIds[i];
|
||||
|
||||
if (!CanSend(clientId, typeof(TMessageType), delivery))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
m_Hooks[hookIdx].OnBeforeSendMessage(clientId, typeof(TMessageType), delivery);
|
||||
}
|
||||
|
||||
var sendQueueItem = m_SendQueues[clientId];
|
||||
if (sendQueueItem.Length == 0)
|
||||
{
|
||||
sendQueueItem.Add(new SendQueueItem(delivery, NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.TempJob,
|
||||
maxSize));
|
||||
sendQueueItem.GetUnsafeList()->ElementAt(0).Writer.Seek(sizeof(BatchHeader));
|
||||
}
|
||||
else
|
||||
{
|
||||
ref var lastQueueItem = ref sendQueueItem.GetUnsafeList()->ElementAt(sendQueueItem.Length - 1);
|
||||
if (lastQueueItem.NetworkDelivery != delivery ||
|
||||
lastQueueItem.Writer.MaxCapacity - lastQueueItem.Writer.Position
|
||||
< tmpSerializer.Length + sizeof(MessageHeader))
|
||||
{
|
||||
sendQueueItem.Add(new SendQueueItem(delivery, NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.TempJob,
|
||||
maxSize));
|
||||
sendQueueItem.GetUnsafeList()->ElementAt(sendQueueItem.Length - 1).Writer.Seek(sizeof(BatchHeader));
|
||||
}
|
||||
}
|
||||
|
||||
ref var writeQueueItem = ref sendQueueItem.GetUnsafeList()->ElementAt(sendQueueItem.Length - 1);
|
||||
writeQueueItem.Writer.TryBeginWrite(sizeof(MessageHeader) + tmpSerializer.Length);
|
||||
var header = new MessageHeader
|
||||
{
|
||||
MessageSize = (ushort)tmpSerializer.Length,
|
||||
MessageType = m_MessageTypes[typeof(TMessageType)],
|
||||
};
|
||||
|
||||
writeQueueItem.Writer.WriteValue(header);
|
||||
writeQueueItem.Writer.WriteBytes(tmpSerializer.GetUnsafePtr(), tmpSerializer.Length);
|
||||
writeQueueItem.BatchHeader.BatchSize++;
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
m_Hooks[hookIdx].OnAfterSendMessage(clientId, typeof(TMessageType), delivery, tmpSerializer.Length + sizeof(MessageHeader));
|
||||
}
|
||||
}
|
||||
|
||||
return tmpSerializer.Length;
|
||||
}
|
||||
}
|
||||
|
||||
private struct PointerListWrapper<T> : IReadOnlyList<T>
|
||||
where T : unmanaged
|
||||
{
|
||||
private unsafe T* m_Value;
|
||||
private int m_Length;
|
||||
|
||||
internal unsafe PointerListWrapper(T* ptr, int length)
|
||||
{
|
||||
m_Value = ptr;
|
||||
m_Length = length;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => m_Length;
|
||||
}
|
||||
|
||||
public unsafe T this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => m_Value[index];
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe int SendMessage<T>(in T message, NetworkDelivery delivery,
|
||||
ulong* clientIds, int numClientIds)
|
||||
where T : INetworkMessage
|
||||
{
|
||||
return SendMessage(message, delivery, new PointerListWrapper<ulong>(clientIds, numClientIds));
|
||||
}
|
||||
|
||||
internal unsafe int SendMessage<T>(in T message, NetworkDelivery delivery, ulong clientId)
|
||||
where T : INetworkMessage
|
||||
{
|
||||
ulong* clientIds = stackalloc ulong[] { clientId };
|
||||
return SendMessage(message, delivery, new PointerListWrapper<ulong>(clientIds, 1));
|
||||
}
|
||||
|
||||
internal unsafe int SendMessage<T>(in T message, NetworkDelivery delivery, in NativeArray<ulong> clientIds)
|
||||
where T : INetworkMessage
|
||||
{
|
||||
return SendMessage(message, delivery, new PointerListWrapper<ulong>((ulong*)clientIds.GetUnsafePtr(), clientIds.Length));
|
||||
}
|
||||
|
||||
internal unsafe void ProcessSendQueues()
|
||||
{
|
||||
foreach (var kvp in m_SendQueues)
|
||||
{
|
||||
var clientId = kvp.Key;
|
||||
var sendQueueItem = kvp.Value;
|
||||
for (var i = 0; i < sendQueueItem.Length; ++i)
|
||||
{
|
||||
ref var queueItem = ref sendQueueItem.GetUnsafeList()->ElementAt(i);
|
||||
if (queueItem.BatchHeader.BatchSize == 0)
|
||||
{
|
||||
queueItem.Writer.Dispose();
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
m_Hooks[hookIdx].OnBeforeSendBatch(clientId, queueItem.BatchHeader.BatchSize, queueItem.Writer.Length, queueItem.NetworkDelivery);
|
||||
}
|
||||
|
||||
queueItem.Writer.Seek(0);
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
// Skipping the Verify and sneaking the write mark in because we know it's fine.
|
||||
queueItem.Writer.Handle->AllowedWriteMark = 2;
|
||||
#endif
|
||||
queueItem.Writer.WriteValue(queueItem.BatchHeader);
|
||||
|
||||
try
|
||||
{
|
||||
m_MessageSender.Send(clientId, queueItem.NetworkDelivery, queueItem.Writer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
queueItem.Writer.Dispose();
|
||||
}
|
||||
|
||||
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
m_Hooks[hookIdx].OnAfterSendBatch(clientId, queueItem.BatchHeader.BatchSize, queueItem.Writer.Length, queueItem.NetworkDelivery);
|
||||
}
|
||||
}
|
||||
sendQueueItem.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/MessagingSystem.cs.meta
Normal file
11
Runtime/Messaging/MessagingSystem.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a6de3c592caa3a41bdfe9b1e818bcf4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
29
Runtime/Messaging/NetworkContext.cs
Normal file
29
Runtime/Messaging/NetworkContext.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// Metadata passed into the Receive handler for <see cref="INetworkMessage"/>.
|
||||
/// </summary>
|
||||
internal ref struct NetworkContext
|
||||
{
|
||||
/// <summary>
|
||||
/// An opaque object used to represent the owner of the MessagingSystem that's receiving the message.
|
||||
/// Outside of testing environments, the type of this variable will be <see cref="NetworkManager"/>
|
||||
/// </summary>
|
||||
public object SystemOwner;
|
||||
|
||||
/// <summary>
|
||||
/// The originator of the message
|
||||
/// </summary>
|
||||
public ulong SenderId;
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp at which the message was received
|
||||
/// </summary>
|
||||
public float Timestamp;
|
||||
|
||||
/// <summary>
|
||||
/// The header data that was sent with the message
|
||||
/// </summary>
|
||||
public MessageHeader Header;
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/NetworkContext.cs.meta
Normal file
11
Runtime/Messaging/NetworkContext.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9a4d028b61e2b140927b5ebee04d384
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
51
Runtime/Messaging/RpcAttributes.cs
Normal file
51
Runtime/Messaging/RpcAttributes.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC delivery types
|
||||
/// </summary>
|
||||
public enum RpcDelivery
|
||||
{
|
||||
/// <summary>
|
||||
/// Reliable delivery
|
||||
/// </summary>
|
||||
Reliable = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Unreliable delivery
|
||||
/// </summary>
|
||||
Unreliable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Represents the common base class for Rpc attributes.</para>
|
||||
/// </summary>
|
||||
public abstract class RpcAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of RPC delivery method
|
||||
/// </summary>
|
||||
public RpcDelivery Delivery = RpcDelivery.Reliable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Marks a method as ServerRpc.</para>
|
||||
/// <para>A ServerRpc marked method will be fired by a client but executed on the server.</para>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class ServerRpcAttribute : RpcAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether or not the ServerRpc should only be run if executed by the owner of the object
|
||||
/// </summary>
|
||||
public bool RequireOwnership = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Marks a method as ClientRpc.</para>
|
||||
/// <para>A ClientRpc marked method will be fired by the server but executed on clients.</para>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class ClientRpcAttribute : RpcAttribute { }
|
||||
}
|
||||
11
Runtime/Messaging/RpcAttributes.cs.meta
Normal file
11
Runtime/Messaging/RpcAttributes.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac745c8131b811e4887a83fa9e65b4af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
55
Runtime/Messaging/RpcParams.cs
Normal file
55
Runtime/Messaging/RpcParams.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
public struct ServerRpcSendParams
|
||||
{
|
||||
}
|
||||
|
||||
public struct ServerRpcReceiveParams
|
||||
{
|
||||
public ulong SenderClientId;
|
||||
}
|
||||
|
||||
public struct ServerRpcParams
|
||||
{
|
||||
public ServerRpcSendParams Send;
|
||||
public ServerRpcReceiveParams Receive;
|
||||
}
|
||||
|
||||
public struct ClientRpcSendParams
|
||||
{
|
||||
/// <summary>
|
||||
/// IEnumerable version of target id list - use either this OR TargetClientIdsNativeArray
|
||||
/// Note: Even if you provide a value type such as NativeArray, enumerating it will cause boxing.
|
||||
/// If you want to avoid boxing, use TargetClientIdsNativeArray
|
||||
/// </summary>
|
||||
public IReadOnlyList<ulong> TargetClientIds;
|
||||
|
||||
/// <summary>
|
||||
/// NativeArray version of target id list - use either this OR TargetClientIds
|
||||
/// This option avoids any GC allocations but is a bit trickier to use.
|
||||
/// </summary>
|
||||
public NativeArray<ulong>? TargetClientIdsNativeArray;
|
||||
}
|
||||
|
||||
public struct ClientRpcReceiveParams
|
||||
{
|
||||
}
|
||||
|
||||
public struct ClientRpcParams
|
||||
{
|
||||
public ClientRpcSendParams Send;
|
||||
public ClientRpcReceiveParams Receive;
|
||||
}
|
||||
|
||||
#pragma warning disable IDE1006 // disable naming rule violation check
|
||||
// RuntimeAccessModifiersILPP will make this `public`
|
||||
internal struct __RpcParams
|
||||
#pragma warning restore IDE1006 // restore naming rule violation check
|
||||
{
|
||||
public ServerRpcParams Server;
|
||||
public ClientRpcParams Client;
|
||||
}
|
||||
}
|
||||
11
Runtime/Messaging/RpcParams.cs.meta
Normal file
11
Runtime/Messaging/RpcParams.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: accabc5a65e8a45dda9207fac37d1b24
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user