浏览代码

Enter transport.Utp

/main/staging/Networking_for_GameObjects
当前提交
506f0246
共有 485 个文件被更改,包括 5093 次插入21 次删除
  1. 101
      Assets/Scenes/mainScene.unity
  2. 3
      Assets/Scripts/LobbyRelaySample.asmdef
  3. 37
      Packages/packages-lock.json
  4. 6
      ProjectSettings/ProjectSettings.asset
  5. 44
      Assets/Scripts/Relay/RelayNetcodeHost.cs
  6. 11
      Assets/Scripts/Relay/RelayNetcodeHost.cs.meta
  7. 5
      Packages/com.unity.multiplayer.transport.utp/CHANGELOG.md
  8. 7
      Packages/com.unity.multiplayer.transport.utp/CHANGELOG.md.meta
  9. 5
      Packages/com.unity.multiplayer.transport.utp/Documentation~/Manual.md
  10. 9
      Packages/com.unity.multiplayer.transport.utp/LICENSE.md
  11. 7
      Packages/com.unity.multiplayer.transport.utp/LICENSE.md.meta
  12. 3
      Packages/com.unity.multiplayer.transport.utp/README.md
  13. 7
      Packages/com.unity.multiplayer.transport.utp/README.md.meta
  14. 8
      Packages/com.unity.multiplayer.transport.utp/Runtime.meta
  15. 467
      Packages/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs
  16. 11
      Packages/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs.meta
  17. 64
      Packages/com.unity.multiplayer.transport.utp/Runtime/Utilities.cs
  18. 11
      Packages/com.unity.multiplayer.transport.utp/Runtime/Utilities.cs.meta
  19. 11
      Packages/com.unity.multiplayer.transport.utp/Runtime/com.unity.multiplayer.transport.utp.asmdef
  20. 7
      Packages/com.unity.multiplayer.transport.utp/Runtime/com.unity.multiplayer.transport.utp.asmdef.meta
  21. 8
      Packages/com.unity.multiplayer.transport.utp/Tests.meta
  22. 8
      Packages/com.unity.multiplayer.transport.utp/Tests/Editor.meta
  23. 20
      Packages/com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs
  24. 11
      Packages/com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs.meta
  25. 15
      Packages/com.unity.multiplayer.transport.utp/Tests/Editor/com.unity.multiplayer.transport.utp.editortests.asmdef
  26. 7
      Packages/com.unity.multiplayer.transport.utp/Tests/Editor/com.unity.multiplayer.transport.utp.editortests.asmdef.meta
  27. 8
      Packages/com.unity.multiplayer.transport.utp/Tests/Runtime.meta
  28. 26
      Packages/com.unity.multiplayer.transport.utp/Tests/Runtime/DummyTestScript.cs
  29. 11
      Packages/com.unity.multiplayer.transport.utp/Tests/Runtime/DummyTestScript.cs.meta
  30. 14
      Packages/com.unity.multiplayer.transport.utp/Tests/Runtime/com.unity.multiplayer.transport.utp.runtimetests.asmdef
  31. 7
      Packages/com.unity.multiplayer.transport.utp/Tests/Runtime/com.unity.multiplayer.transport.utp.runtimetests.asmdef.meta
  32. 12
      Packages/com.unity.multiplayer.transport.utp/package.json
  33. 7
      Packages/com.unity.multiplayer.transport.utp/package.json.meta
  34. 120
      Packages/com.unity.netcode.gameobjects/CHANGELOG.md
  35. 7
      Packages/com.unity.netcode.gameobjects/CHANGELOG.md.meta
  36. 30
      Packages/com.unity.netcode.gameobjects/Documentation~/Manual.md
  37. 8
      Packages/com.unity.netcode.gameobjects/Editor.meta
  38. 8
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen.meta
  39. 290
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs
  40. 11
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs.meta
  41. 1001
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs
  42. 11
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs.meta
  43. 137
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorAssemblyResolver.cs
  44. 11
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorAssemblyResolver.cs.meta
  45. 22
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs
  46. 11
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs.meta
  47. 12
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporterProvider.cs
  48. 11
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporterProvider.cs.meta
  49. 130
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs
  50. 11
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs.meta
  51. 19
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/com.unity.netcode.editor.codegen.asmdef
  52. 7
      Packages/com.unity.netcode.gameobjects/Editor/CodeGen/com.unity.netcode.editor.codegen.asmdef.meta
  53. 8
      Packages/com.unity.netcode.gameobjects/Editor/DontShowInTransportDropdownAttribute.cs
  54. 3
      Packages/com.unity.netcode.gameobjects/Editor/DontShowInTransportDropdownAttribute.cs.meta
  55. 211
      Packages/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs
  56. 11
      Packages/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs.meta
  57. 371
      Packages/com.unity.netcode.gameobjects/Editor/NetworkManagerEditor.cs
  58. 11
      Packages/com.unity.netcode.gameobjects/Editor/NetworkManagerEditor.cs.meta
  59. 104
      Packages/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs
  60. 11
      Packages/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs.meta
  61. 118
      Packages/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs
  62. 11
      Packages/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs.meta
  63. 11
      Packages/com.unity.netcode.gameobjects/Editor/com.unity.netcode.editor.asmdef
  64. 7
      Packages/com.unity.netcode.gameobjects/Editor/com.unity.netcode.editor.asmdef.meta
  65. 9
      Packages/com.unity.netcode.gameobjects/LICENSE.md
  66. 7
      Packages/com.unity.netcode.gameobjects/LICENSE.md.meta
  67. 8
      Packages/com.unity.netcode.gameobjects/Prototyping.meta
  68. 10
      Packages/com.unity.netcode.gameobjects/Prototyping/AssemblyInfo.cs
  69. 11
      Packages/com.unity.netcode.gameobjects/Prototyping/AssemblyInfo.cs.meta
  70. 560
      Packages/com.unity.netcode.gameobjects/Prototyping/NetworkAnimator.cs
  71. 11
      Packages/com.unity.netcode.gameobjects/Prototyping/NetworkAnimator.cs.meta
  72. 119
      Packages/com.unity.netcode.gameobjects/Prototyping/NetworkNavMeshAgent.cs
  73. 11
      Packages/com.unity.netcode.gameobjects/Prototyping/NetworkNavMeshAgent.cs.meta
  74. 407
      Packages/com.unity.netcode.gameobjects/Prototyping/NetworkTransform.cs
  75. 11
      Packages/com.unity.netcode.gameobjects/Prototyping/NetworkTransform.cs.meta
  76. 7
      Packages/com.unity.netcode.gameobjects/Prototyping/com.unity.netcode.prototyping.asmdef
  77. 7
      Packages/com.unity.netcode.gameobjects/Prototyping/com.unity.netcode.prototyping.asmdef.meta
  78. 84
      Packages/com.unity.netcode.gameobjects/README.md
  79. 7
      Packages/com.unity.netcode.gameobjects/README.md.meta
  80. 8
      Packages/com.unity.netcode.gameobjects/Runtime.meta
  81. 10
      Packages/com.unity.netcode.gameobjects/Runtime/AssemblyInfo.cs
  82. 11
      Packages/com.unity.netcode.gameobjects/Runtime/AssemblyInfo.cs.meta
  83. 8
      Packages/com.unity.netcode.gameobjects/Runtime/Collections.meta
  84. 77
      Packages/com.unity.netcode.gameobjects/Runtime/Collections/FixedQueue.cs
  85. 11
      Packages/com.unity.netcode.gameobjects/Runtime/Collections/FixedQueue.cs.meta
  86. 8
      Packages/com.unity.netcode.gameobjects/Runtime/Configuration.meta

101
Assets/Scenes/mainScene.unity


m_EditorClassIdentifier:
m_editorLogVerbosity: 0
m_popUp: {fileID: 1228229694}
m_errorReaction:
m_logMessageCallback:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 1095306255}
m_TargetAssemblyTypeName: LobbyRelaySample.LogHandlerSettings, LobbyRelaySample
m_MethodName: SpawnErrorPopup
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
--- !u!224 &1095306259
RectTransform:
m_ObjectHideFlags: 0

m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!1 &1123907084
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1123907087}
- component: {fileID: 1123907086}
- component: {fileID: 1123907085}
m_Layer: 0
m_Name: NetworkManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1123907085
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1123907084}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: adf0b801ebdee8c4b838e20292b36ac4, type: 3}
m_Name:
m_EditorClassIdentifier:
SpreadMethod: 0
Transports:
- {fileID: 0}
--- !u!114 &1123907086
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1123907084}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3}
m_Name:
m_EditorClassIdentifier:
DontDestroy: 1
RunInBackground: 1
LogLevel: 1
NetworkConfig:
ProtocolVersion: 0
NetworkTransport: {fileID: 0}
PlayerPrefab: {fileID: 0}
NetworkPrefabs: []
TickRate: 30
ClientConnectionBufferTimeout: 10
ConnectionApproval: 0
ConnectionData:
EnableTimeResync: 0
TimeResyncInterval: 30
EnableNetworkVariable: 1
EnsureNetworkVariableLengthSafety: 0
EnableSceneManagement: 1
ForceSamePrefabs: 1
RecycleNetworkIds: 1
NetworkIdRecycleDelay: 120
RpcHashSize: 0
LoadSceneTimeOut: 120
MessageBufferTimeout: 20
EnableNetworkLogs: 1
--- !u!4 &1123907087
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1123907084}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 670.05023, y: 399.02173, z: -178.1256}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1217229506 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 354886978664675623, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}

objectReference: {fileID: 0}
- target: {fileID: 2637199316291327119, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchoredPosition.y
value: -12.5
value: -12.499985
objectReference: {fileID: 0}
- target: {fileID: 2637199316850714327, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_PresetInfoIsWorld

3
Assets/Scripts/LobbyRelaySample.asmdef


"GUID:5540e30183c82e84b954c033c388e06c",
"GUID:fe25561d224ed4743af4c60938a59d0b",
"GUID:4c3f49d89436d478ea78315c03159dcc",
"GUID:f2d49d9fa7e7eb3418e39723a7d3b92f"
"GUID:f2d49d9fa7e7eb3418e39723a7d3b92f",
"GUID:1491147abca9d7d4bb7105af628b223e"
],
"includePlatforms": [],
"excludePlatforms": [],

37
Packages/packages-lock.json


"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.jobs": {
"version": "0.2.10-preview.13",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.collections": "0.9.0-preview.6",
"com.unity.mathematics": "1.1.0"
},
"url": "https://packages.unity.com"
},
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.multiplayer.transport.utp": {
"version": "file:com.unity.multiplayer.transport.utp",
"depth": 0,
"source": "embedded",
"dependencies": {
"com.unity.netcode.gameobjects": "0.0.1-preview.1",
"com.unity.transport": "0.4.1-preview.1",
"com.unity.jobs": "0.2.10-preview.13"
}
},
"com.unity.netcode.gameobjects": {
"version": "file:com.unity.netcode.gameobjects",
"depth": 0,
"source": "embedded",
"dependencies": {
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.nuget.mono-cecil": "1.10.1-preview.1"
}
},
"com.unity.nuget.mono-cecil": {
"version": "1.10.1-preview.1",
"depth": 1,
"source": "registry",
"dependencies": {},

6
ProjectSettings/ProjectSettings.asset


m_VersionName:
apiCompatibilityLevel: 6
activeInputHandler: 0
cloudProjectId:
cloudProjectId: 0bf0426b-e1fd-4251-82d0-3eea033ef1ad
projectName:
organizationId:
projectName: com.unity.services.samples.lobby-rooms
organizationId: operate-samples
cloudEnabled: 0
legacyClampBlendShapeWeights: 0
virtualTexturingSupportEnabled: 0

44
Assets/Scripts/Relay/RelayNetcodeHost.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using LobbyRelaySample;
using Unity.Netcode;
using UnityEngine;
public class AsyncNetworkRequest : AsyncRequest
{
private static AsyncNetworkRequest s_instance;
public static AsyncNetworkRequest Instance
{
get
{
if (s_instance == null)
s_instance = new AsyncNetworkRequest();
return s_instance;
}
}
/// <summary>
/// The Relay service will wrap HTTP errors in RelayServiceExceptions. We can filter on RelayServiceException.Reason for custom behavior.
/// </summary>
protected override void ParseServiceException(Exception e)
{
throw e;
}
}
public class RelayNetcodeHost : NetworkBehaviour
{
async void Start()
{
var hostSocket = NetworkManager.Singleton.StartHost();
while (!hostSocket.IsDone)
{
await Task.Yield();
}
}
}

11
Assets/Scripts/Relay/RelayNetcodeHost.cs.meta


fileFormatVersion: 2
guid: cc7678c1f9b7b9c4fac8bac6324007de
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

5
Packages/com.unity.multiplayer.transport.utp/CHANGELOG.md


# Changelog
All notable changes to this package will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
## [0.0.1-preview.1] - 2020-12-20
This is the first release of Unity MLAPI Package

7
Packages/com.unity.multiplayer.transport.utp/CHANGELOG.md.meta


fileFormatVersion: 2
guid: c482292884eb2a14f8d59b4a5c55c62e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

5
Packages/com.unity.multiplayer.transport.utp/Documentation~/Manual.md


# **Unity Transport for Netcode for GameObjects Manual**
# Getting Started
todo @andrews-unity - fill this in

9
Packages/com.unity.multiplayer.transport.utp/LICENSE.md


MIT License
Copyright (c) 2021 Unity Technologies
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

7
Packages/com.unity.multiplayer.transport.utp/LICENSE.md.meta


fileFormatVersion: 2
guid: 5501977e9ab93ad469220f23990177cc
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

3
Packages/com.unity.multiplayer.transport.utp/README.md


com.unity.transport transport for Netcode for GameObjects
WIP: This is not a functional transport just a work in progress and should not be used as any measure of current state a very early proof of concept and place holder package.

7
Packages/com.unity.multiplayer.transport.utp/README.md.meta


fileFormatVersion: 2
guid: 8dcab9a16b9388445a77d3b927b242cf
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.multiplayer.transport.utp/Runtime.meta


fileFormatVersion: 2
guid: d6198c048d7fde84e837ad7b5ae231d9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

467
Packages/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs


using System;
using System.Runtime.InteropServices;
using Unity.Netcode;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Networking.Transport;
using UnityEngine;
using UnityEngine.Assertions;
using NetworkEvent = Unity.Networking.Transport.NetworkEvent;
using NetcodeEvent = Unity.Netcode.NetworkEvent;
[StructLayout(LayoutKind.Explicit)]
public unsafe struct RawNetworkMessage
{
[FieldOffset(0)] public int Length;
[FieldOffset(4)] public uint Type;
[FieldOffset(8)] public int Id;
[FieldOffset(12)] public byte Padding;
[FieldOffset(13)] public byte ChannelId;
[FieldOffset(14)] public fixed byte Data[NetworkParameterConstants.MTU];
}
[BurstCompile]
internal struct ClientUpdateJob : IJob
{
public NetworkDriver Driver;
public NativeArray<NetworkConnection> Connection;
public NativeQueue<RawNetworkMessage> PacketData;
unsafe public void Execute()
{
if (!Connection[0].IsCreated)
{
return;
}
DataStreamReader streamReader;
NetworkEvent.Type cmd;
while ((cmd = Connection[0].PopEvent(Driver, out streamReader)) != NetworkEvent.Type.Empty)
{
if (cmd == NetworkEvent.Type.Connect)
{
var d = new RawNetworkMessage() { Length = 0, Type = (uint)NetcodeEvent.Connect, Id = Connection[0].InternalId };
PacketData.Enqueue(d);
}
else if (cmd == NetworkEvent.Type.Data)
{
byte channelId = streamReader.ReadByte();
int messageSize = streamReader.ReadInt();
var temp = new NativeArray<byte>(messageSize, Allocator.Temp);
streamReader.ReadBytes(temp);
var d = new RawNetworkMessage()
{
Length = messageSize,
Type = (uint)NetcodeEvent.Data,
Id = Connection[0].InternalId,
ChannelId = channelId
};
UnsafeUtility.MemCpy(d.Data, temp.GetUnsafePtr(), d.Length);
PacketData.Enqueue(d);
}
else if (cmd == NetworkEvent.Type.Disconnect)
{
Connection[0] = default;
}
}
}
}
[BurstCompile]
internal struct ServerUpdateJob : IJobParallelForDefer
{
public NetworkDriver.Concurrent Driver;
public NativeArray<NetworkConnection> Connections;
public NativeQueue<RawNetworkMessage>.ParallelWriter PacketData;
private unsafe void QueueMessage(ref DataStreamReader streamReader, int index)
{
byte channelId = streamReader.ReadByte();
int messageSize = streamReader.ReadInt();
var temp = new NativeArray<byte>(messageSize, Allocator.Temp);
streamReader.ReadBytes(temp);
// Debug.Log($"Server: Got a message {channelId} {messageSize} ");
var d = new RawNetworkMessage()
{
Length = messageSize,
Type = (uint)NetcodeEvent.Data,
Id = index,
ChannelId = channelId
};
UnsafeUtility.MemCpy(d.Data, temp.GetUnsafePtr(), d.Length);
PacketData.Enqueue(d);
}
public unsafe void Execute(int index)
{
DataStreamReader streamReader;
Assert.IsTrue(Connections[index].IsCreated);
NetworkEvent.Type command;
while ((command = Driver.PopEventForConnection(Connections[index], out streamReader)) != NetworkEvent.Type.Empty)
{
if (command == NetworkEvent.Type.Data)
{
QueueMessage(ref streamReader, index);
}
else if (command == NetworkEvent.Type.Connect)
{
var d = new RawNetworkMessage() { Length = 0, Type = (uint)NetcodeEvent.Connect, Id = index };
PacketData.Enqueue(d);
}
else if (command == NetworkEvent.Type.Disconnect)
{
var d = new RawNetworkMessage() { Length = 0, Type = (uint)NetcodeEvent.Disconnect, Id = index };
PacketData.Enqueue(d);
Connections[index] = default;
}
}
}
}
[BurstCompile]
internal struct ServerUpdateConnectionsJob : IJob
{
public NetworkDriver Driver;
public NativeList<NetworkConnection> Connections;
public NativeQueue<RawNetworkMessage>.ParallelWriter PacketData;
public void Execute()
{
// Clean up connections
for (int i = 0; i < Connections.Length; i++)
{
if (!Connections[i].IsCreated)
{
Connections.RemoveAtSwapBack(i);
--i;
}
}
// Accept new connections
NetworkConnection c;
while ((c = Driver.Accept()) != default(NetworkConnection))
{
Connections.Add(c);
var d = new RawNetworkMessage() { Length = 0, Type = (uint)NetcodeEvent.Connect, Id = c.InternalId };
PacketData.Enqueue(d);
Debug.Log("Accepted a connection");
}
}
}
public class UTPTransport : NetworkTransport
{
public ushort Port = 7777;
public string Address = "127.0.0.1";
[Serializable]
public struct UTPChannel
{
[HideInInspector]
public byte Id;
public string Name;
public UTPDelivery Flags;
}
public enum UTPDelivery
{
UnreliableSequenced,
ReliableSequenced,
Unreliable
}
public NetworkDriver Driver;
public NativeList<NetworkConnection> Connections;
public NativeQueue<RawNetworkMessage> PacketData;
private NativeArray<byte> m_PacketProcessBuffer;
private JobHandle m_JobHandle;
private bool m_IsClient = false;
private bool m_IsServer = false;
public override ulong ServerClientId => 0;
public override void DisconnectLocalClient() { _ = Driver.Disconnect(Connections[0]); }
public override void DisconnectRemoteClient(ulong clientId)
{
GetUTPConnectionDetails(clientId, out uint peerId);
var con = GetConnection(peerId);
if (con != default)
{
Driver.Disconnect(con);
}
}
private NetworkConnection GetConnection(uint id)
{
foreach (var item in Connections)
{
if (item.InternalId == id)
{
return item;
}
}
return default;
}
private NetworkPipeline[] m_NetworkPipelines = new NetworkPipeline[3];
public override void Init()
{
Driver = NetworkDriver.Create();
// So we have a bunch of different pipelines we can send :D
m_NetworkPipelines[0] = Driver.CreatePipeline(typeof(NullPipelineStage));
m_NetworkPipelines[1] = Driver.CreatePipeline(typeof(ReliableSequencedPipelineStage));
m_NetworkPipelines[2] = Driver.CreatePipeline(typeof(UnreliableSequencedPipelineStage));
PacketData = new NativeQueue<RawNetworkMessage>(Allocator.Persistent);
m_PacketProcessBuffer = new NativeArray<byte>(1000, Allocator.Persistent);
}
[BurstCompile]
public void SendToClient(NativeArray<byte> packet, ulong clientId, int index)
{
for (int i = 0; i < Connections.Length; i++)
{
if (Connections[i].InternalId != (int)clientId)
{
continue;
}
var writer = Driver.BeginSend(m_NetworkPipelines[index], Connections[i]);
if (!writer.IsCreated)
{
continue;
}
writer.WriteBytes(packet);
Driver.EndSend(writer);
}
}
public override unsafe void Send(ulong clientId, ArraySegment<byte> data, NetworkChannel networkChannel)
{
var pipelineIndex = 0;
GetUTPConnectionDetails(clientId, out uint peerId);
var writer = new DataStreamWriter(data.Count + 1 + 4, Allocator.Temp);
writer.WriteByte((byte)networkChannel);
writer.WriteInt(data.Count);
fixed (byte* dataArrayPtr = data.Array)
{
writer.WriteBytes(dataArrayPtr, data.Count);
}
SendToClient(writer.AsNativeArray(), peerId, pipelineIndex);
}
public override NetcodeEvent PollEvent(out ulong clientId, out NetworkChannel networkChannel, out ArraySegment<byte> payload, out float receiveTime)
{
clientId = 0;
networkChannel = NetworkChannel.ChannelUnused;
payload = new ArraySegment<byte>(Array.Empty<byte>());
receiveTime = 0;
return NetcodeEvent.Nothing;
}
public override ulong GetCurrentRtt(ulong clientId) => 0;
private void Update()
{
if (m_IsServer || m_IsClient)
{
RawNetworkMessage message;
while (PacketData.TryDequeue(out message))
{
var data = m_PacketProcessBuffer.Slice(0, message.Length);
unsafe
{
UnsafeUtility.MemClear(data.GetUnsafePtr(), message.Length);
UnsafeUtility.MemCpy(data.GetUnsafePtr(), message.Data, message.Length);
}
var clientId = GetNetcodeClientId((uint)message.Id, false);
switch ((NetcodeEvent)message.Type)
{
case NetcodeEvent.Data:
int size = message.Length;
byte[] arr = new byte[size];
unsafe
{
Marshal.Copy((IntPtr)message.Data, arr, 0, size);
var payload = new ArraySegment<byte>(arr);
InvokeOnTransportEvent((NetcodeEvent)message.Type, clientId, (NetworkChannel)message.ChannelId, payload, Time.realtimeSinceStartup);
}
break;
case NetcodeEvent.Connect:
{
InvokeOnTransportEvent((NetcodeEvent)message.Type, clientId, NetworkChannel.ChannelUnused, new ArraySegment<byte>(), Time.realtimeSinceStartup);
}
break;
case NetcodeEvent.Disconnect:
InvokeOnTransportEvent((NetcodeEvent)message.Type, clientId, NetworkChannel.ChannelUnused, new ArraySegment<byte>(), Time.realtimeSinceStartup);
break;
case NetcodeEvent.Nothing:
InvokeOnTransportEvent((NetcodeEvent)message.Type, clientId, NetworkChannel.ChannelUnused, new ArraySegment<byte>(), Time.realtimeSinceStartup);
break;
}
}
if (m_JobHandle.IsCompleted)
{
if (m_IsServer)
{
var connectionJob = new ServerUpdateConnectionsJob
{
Driver = Driver,
Connections = Connections,
PacketData = PacketData.AsParallelWriter()
};
var serverUpdateJob = new ServerUpdateJob
{
Driver = Driver.ToConcurrent(),
Connections = Connections.AsDeferredJobArray(),
PacketData = PacketData.AsParallelWriter()
};
m_JobHandle = Driver.ScheduleUpdate();
m_JobHandle = connectionJob.Schedule(m_JobHandle);
m_JobHandle = serverUpdateJob.Schedule(Connections, 1, m_JobHandle);
}
if (m_IsClient)
{
var job = new ClientUpdateJob
{
Driver = Driver,
Connection = Connections,
PacketData = PacketData
};
m_JobHandle = Driver.ScheduleUpdate();
m_JobHandle = job.Schedule(m_JobHandle);
}
}
m_JobHandle.Complete();
}
}
public override void Shutdown()
{
m_JobHandle.Complete();
if (PacketData.IsCreated)
{
PacketData.Dispose();
}
if (Connections.IsCreated)
{
Connections.Dispose();
}
Driver.Dispose();
m_PacketProcessBuffer.Dispose();
}
// This is kind of a mess!
public override SocketTasks StartClient()
{
Connections = new NativeList<NetworkConnection>(1, Allocator.Persistent);
var endpoint = NetworkEndPoint.Parse(Address, Port);
Connections.Add(Driver.Connect(endpoint));
m_IsClient = true;
Debug.Log("StartClient");
return SocketTask.Working.AsTasks();
}
public int NetcodeChannelToPipeline(UTPDelivery type)
{
switch (type)
{
case UTPDelivery.UnreliableSequenced:
return 2;
case UTPDelivery.ReliableSequenced:
return 1;
case UTPDelivery.Unreliable:
return 0;
}
return 0;
}
public ulong GetNetcodeClientId(uint peerId, bool isServer)
{
if (isServer)
{
return 0;
}
else
{
return peerId + 1;
}
}
public void GetUTPConnectionDetails(ulong clientId, out uint peerId)
{
if (clientId == 0)
{
peerId = (uint)ServerClientId;
}
else
{
peerId = (uint)clientId - 1;
}
}
public override SocketTasks StartServer()
{
Connections = new NativeList<NetworkConnection>(300, Allocator.Persistent);
var endpoint = NetworkEndPoint.Parse(Address, Port);
m_IsServer = true;
Debug.Log("StartServer");
if (Driver.Bind(endpoint) != 0)
{
Debug.LogError("Failed to bind to port " + Port);
}
else
{
Driver.Listen();
}
return SocketTask.Working.AsTasks();
}
}

11
Packages/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs.meta


fileFormatVersion: 2
guid: fc5ef7b69296d69458910681f29471e6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

64
Packages/com.unity.multiplayer.transport.utp/Runtime/Utilities.cs


using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace Assets.Scripts.Transport
{
public static class Utilities
{
private static unsafe byte[] SerializeUnmanagedArray<T>(NativeArray<T> value) where T : unmanaged
{
var bytes = new byte[UnsafeUtility.SizeOf<T>() * value.Length + sizeof(int)];
fixed (byte* ptr = bytes)
{
var buf = new UnsafeAppendBuffer(ptr, bytes.Length);
buf.Add(value);
}
return bytes;
}
private static unsafe NativeArray<T> DeserializeUnmanagedArray<T>(byte[] buffer, Allocator allocator = Allocator.Temp) where T : unmanaged
{
fixed (byte* ptr = buffer)
{
var buf = new UnsafeAppendBuffer.Reader(ptr, buffer.Length);
buf.ReadNext<T>(out var array, allocator);
return array;
}
}
public unsafe static byte[] SerializeUnmanaged<T>(ref T value) where T : unmanaged
{
var bytes = new byte[UnsafeUtility.SizeOf<T>()];
fixed (byte* ptr = bytes)
{
UnsafeUtility.CopyStructureToPtr(ref value, ptr);
}
return bytes;
}
public unsafe static T DeserializeUnmanaged<T>(byte[] buffer) where T : unmanaged
{
fixed (byte* ptr = buffer)
{
UnsafeUtility.CopyPtrToStructure<T>(ptr, out var value);
return value;
}
}
public unsafe static T DeserializeUnmanaged<T>(ref NativeSlice<byte> buffer) where T : unmanaged
{
int structSize = UnsafeUtility.SizeOf<T>();
long ptr = (long)buffer.GetUnsafePtr();
long size = buffer.Length;
long addr = ptr + size - structSize;
var data = UnsafeUtility.ReadArrayElement<T>((void*)addr, 0);
return data;
}
}
}

11
Packages/com.unity.multiplayer.transport.utp/Runtime/Utilities.cs.meta


fileFormatVersion: 2
guid: 4613e18f31d730a4c908e335ae40f832
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

11
Packages/com.unity.multiplayer.transport.utp/Runtime/com.unity.multiplayer.transport.utp.asmdef


{
"name": "Unity.Multiplayer.Transport.UTP",
"references": [
"Unity.Collections",
"Unity.Networking.Transport",
"Unity.Jobs",
"Unity.Burst",
"Unity.Netcode.Runtime"
],
"allowUnsafeCode": true
}

7
Packages/com.unity.multiplayer.transport.utp/Runtime/com.unity.multiplayer.transport.utp.asmdef.meta


fileFormatVersion: 2
guid: 3ca8b3b66202abc418c13ff7812fb7ef
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.multiplayer.transport.utp/Tests.meta


fileFormatVersion: 2
guid: 6ffe51a727e9e5541a9bcef793f920f2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.multiplayer.transport.utp/Tests/Editor.meta


fileFormatVersion: 2
guid: ff6b9fdc7bae5bf46aad42bf806d50ab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

20
Packages/com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs


using UnityEngine;
using NUnit.Framework;
namespace Unity.Netcode.UTP.EditorTests
{
public class BasicUTPTest : MonoBehaviour
{
[Test]
public void BasicUTPInitializationTest()
{
var o = new GameObject();
var utpTransport = (UTPTransport)o.AddComponent(typeof(UTPTransport));
utpTransport.Init();
Assert.True(utpTransport.ServerClientId == 0);
utpTransport.Shutdown();
}
}
}

11
Packages/com.unity.multiplayer.transport.utp/Tests/Editor/BasicUTPTest.cs.meta


fileFormatVersion: 2
guid: 4d51a9ee9a7131d47acc9ecb8c99dd65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

15
Packages/com.unity.multiplayer.transport.utp/Tests/Editor/com.unity.multiplayer.transport.utp.editortests.asmdef


{
"name": "Unity.Multiplayer.Transport.UTP.EditorTests",
"rootNamespace": "Unity.Netcode.UTP.EditorTests",
"references": [
"Unity.Netcode.Runtime",
"Unity.Networking.Transport",
"Unity.Multiplayer.Transport.UTP"
],
"optionalUnityReferences": [
"TestAssemblies"
],
"includePlatforms": [
"Editor"
]
}

7
Packages/com.unity.multiplayer.transport.utp/Tests/Editor/com.unity.multiplayer.transport.utp.editortests.asmdef.meta


fileFormatVersion: 2
guid: e7d1cf2f203c677459c30bada5c15a9a
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.multiplayer.transport.utp/Tests/Runtime.meta


fileFormatVersion: 2
guid: 8a093c5e4dedd224891d2e8a197de43a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

26
Packages/com.unity.multiplayer.transport.utp/Tests/Runtime/DummyTestScript.cs


using System.Collections;
using NUnit.Framework;
using UnityEngine.TestTools;
namespace Unity.Netcode.UTP.RuntimeTests
{
public class DummyTestScript
{
// A Test behaves as an ordinary method
[Test]
public void DummyTestScriptSimplePasses()
{
// Use the Assert class to test conditions
}
// A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use
// `yield return null;` to skip a frame.
[UnityTest]
public IEnumerator DummyTestScriptWithEnumeratorPasses()
{
// Use the Assert class to test conditions.
// Use yield to skip a frame.
yield return null;
}
}
}

11
Packages/com.unity.multiplayer.transport.utp/Tests/Runtime/DummyTestScript.cs.meta


fileFormatVersion: 2
guid: a4625f3349130440d9879c25654c9862
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

14
Packages/com.unity.multiplayer.transport.utp/Tests/Runtime/com.unity.multiplayer.transport.utp.runtimetests.asmdef


{
"name": "Unity.Multiplayer.Transport.UTP.RuntimeTests",
"rootNamespace": "Unity.Netcode.UTP.RuntimeTests",
"references": [
"Unity.Netcode.Runtime",
"Unity.Networking.Transport"
],
"optionalUnityReferences": [
"TestAssemblies"
],
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
]
}

7
Packages/com.unity.multiplayer.transport.utp/Tests/Runtime/com.unity.multiplayer.transport.utp.runtimetests.asmdef.meta


fileFormatVersion: 2
guid: 05c2d009acf3b36488f0e38dc7ee0e0f
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

12
Packages/com.unity.multiplayer.transport.utp/package.json


{
"name": "com.unity.multiplayer.transport.utp",
"displayName": "Unity Transport for Netcode for GameObjects",
"description": "This package is plugging Unity Transport into Netcode for GameObjects, which is a network transport layer - the low-level interface for sending UDP data",
"version": "0.0.1-preview.1",
"unity": "2020.3",
"dependencies": {
"com.unity.netcode.gameobjects": "0.0.1-preview.1",
"com.unity.transport": "0.4.1-preview.1",
"com.unity.jobs":"0.2.10-preview.13"
}
}

7
Packages/com.unity.multiplayer.transport.utp/package.json.meta


fileFormatVersion: 2
guid: 67a2dba60abbf414584aab568fb56103
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

120
Packages/com.unity.netcode.gameobjects/CHANGELOG.md


# Changelog
This file documents all notable changes to this package. Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).
## [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.
### Changes
* 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.
### New Features
- 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`.
### Changes
- [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` |
### Fixes
- [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 features
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

7
Packages/com.unity.netcode.gameobjects/CHANGELOG.md.meta


fileFormatVersion: 2
guid: d8f80d04925759d41a7bbee0259b3c39
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

30
Packages/com.unity.netcode.gameobjects/Documentation~/Manual.md


# About Netcode for GameObjects
Unity Netcode for GameObjects is a high-level networking library built to abstract networking. This allows developers to focus on the game rather than low level protocols and networking frameworks.
## Guides
See guides below to install Unity Netcode for GameObjects, set up your project, and get started with your first networked game:
* [Documentation](https://docs-multiplayer.unity3d.com/docs/getting-started/about-mlapi)
* [Installation](https://docs-multiplayer.unity3d.com/docs/migration/install)
* [First Steps](https://docs-multiplayer.unity3d.com/docs/tutorials/helloworldintro)
* [API Reference](https://docs-multiplayer.unity3d.com/docs/mlapi-api/introduction)
# Technical details
## Requirements
This version of Netcode for GameObjects is compatible with the following Unity versions and platforms:
* 2020.3 and later
* Windows, Mac, Linux platforms
## Document revision history
|Date|Reason|
|---|---|
|March 10, 2021|Document created. Matches package version 0.1.0|
|June 1, 2021|Update and add links for additional content. Matches patch version 0.1.0 and hotfixes.|
|June 3, 2021|Update document to acknowledge Unity min version change. Matches package version 0.2.0|
|August 5, 2021|Update product/package name|

8
Packages/com.unity.netcode.gameobjects/Editor.meta


fileFormatVersion: 2
guid: 0388707d01c6e18409986ad2fadf6faa
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.netcode.gameobjects/Editor/CodeGen.meta


fileFormatVersion: 2
guid: bbb4974b4302f435b9f4663c64d8f803
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

290
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using Unity.CompilationPipeline.Common.Diagnostics;
using Unity.CompilationPipeline.Common.ILPostProcessing;
using UnityEngine;
namespace Unity.Netcode.Editor.CodeGen
{
internal static class CodeGenHelpers
{
public const string RuntimeAssemblyName = "Unity.Netcode.Runtime";
public static readonly string NetworkBehaviour_FullName = typeof(NetworkBehaviour).FullName;
public static readonly string ServerRpcAttribute_FullName = typeof(ServerRpcAttribute).FullName;
public static readonly string ClientRpcAttribute_FullName = typeof(ClientRpcAttribute).FullName;
public static readonly string ServerRpcParams_FullName = typeof(ServerRpcParams).FullName;
public static readonly string ClientRpcParams_FullName = typeof(ClientRpcParams).FullName;
public static readonly string INetworkSerializable_FullName = typeof(INetworkSerializable).FullName;
public static readonly string INetworkSerializable_NetworkSerialize_Name = nameof(INetworkSerializable.NetworkSerialize);
public static readonly string UnityColor_FullName = typeof(Color).FullName;
public static readonly string UnityColor32_FullName = typeof(Color32).FullName;
public static readonly string UnityVector2_FullName = typeof(Vector2).FullName;
public static readonly string UnityVector3_FullName = typeof(Vector3).FullName;
public static readonly string UnityVector4_FullName = typeof(Vector4).FullName;
public static readonly string UnityQuaternion_FullName = typeof(Quaternion).FullName;
public static readonly string UnityRay_FullName = typeof(Ray).FullName;
public static readonly string UnityRay2D_FullName = typeof(Ray2D).FullName;
public static uint Hash(this MethodDefinition methodDefinition)
{
var sigArr = Encoding.UTF8.GetBytes($"{methodDefinition.Module.Name} / {methodDefinition.FullName}");
var sigLen = sigArr.Length;
unsafe
{
fixed (byte* sigPtr = sigArr)
{
return XXHash.Hash32(sigPtr, sigLen);
}
}
}
public static bool IsSubclassOf(this TypeDefinition typeDefinition, string classTypeFullName)
{
if (!typeDefinition.IsClass)
{
return false;
}
var baseTypeRef = typeDefinition.BaseType;
while (baseTypeRef != null)
{
if (baseTypeRef.FullName == classTypeFullName)
{
return true;
}
try
{
baseTypeRef = baseTypeRef.Resolve().BaseType;
}
catch
{
return false;
}
}
return false;
}
public static bool HasInterface(this TypeReference typeReference, string interfaceTypeFullName)
{
if (typeReference.IsArray)
{
return false;
}
try
{
var typeDef = typeReference.Resolve();
var typeFaces = typeDef.Interfaces;
return typeFaces.Any(iface => iface.InterfaceType.FullName == interfaceTypeFullName);
}
catch
{
return false;
}
}
public static bool IsSerializable(this TypeReference typeReference)
{
var typeSystem = typeReference.Module.TypeSystem;
// C# primitives
if (typeReference == typeSystem.Boolean)
{
return true;
}
if (typeReference == typeSystem.Char)
{
return true;
}
if (typeReference == typeSystem.SByte)
{
return true;
}
if (typeReference == typeSystem.Byte)
{
return true;
}
if (typeReference == typeSystem.Int16)
{
return true;
}
if (typeReference == typeSystem.UInt16)
{
return true;
}
if (typeReference == typeSystem.Int32)
{
return true;
}
if (typeReference == typeSystem.UInt32)
{
return true;
}
if (typeReference == typeSystem.Int64)
{
return true;
}
if (typeReference == typeSystem.UInt64)
{
return true;
}
if (typeReference == typeSystem.Single)
{
return true;
}
if (typeReference == typeSystem.Double)
{
return true;
}
if (typeReference == typeSystem.String)
{
return true;
}
// Unity primitives
if (typeReference.FullName == UnityColor_FullName)
{
return true;
}
if (typeReference.FullName == UnityColor32_FullName)
{
return true;
}
if (typeReference.FullName == UnityVector2_FullName)
{
return true;
}
if (typeReference.FullName == UnityVector3_FullName)
{
return true;
}
if (typeReference.FullName == UnityVector4_FullName)
{
return true;
}
if (typeReference.FullName == UnityQuaternion_FullName)
{
return true;
}
if (typeReference.FullName == UnityRay_FullName)
{
return true;
}
if (typeReference.FullName == UnityRay2D_FullName)
{
return true;
}
// Enum
if (typeReference.GetEnumAsInt() != null)
{
return true;
}
// INetworkSerializable
if (typeReference.HasInterface(INetworkSerializable_FullName))
{
return true;
}
// Static array
if (typeReference.IsArray)
{
return typeReference.GetElementType().IsSerializable();
}
return false;
}
public static TypeReference GetEnumAsInt(this TypeReference typeReference)
{
if (typeReference.IsArray)
{
return null;
}
try
{
var typeDef = typeReference.Resolve();
return typeDef.IsEnum ? typeDef.GetEnumUnderlyingType() : null;
}
catch
{
return null;
}
}
public static void AddError(this List<DiagnosticMessage> diagnostics, string message)
{
diagnostics.AddError((SequencePoint)null, message);
}
public static void AddError(this List<DiagnosticMessage> diagnostics, MethodDefinition methodDefinition, string message)
{
diagnostics.AddError(methodDefinition.DebugInformation.SequencePoints.FirstOrDefault(), message);
}
public static void AddError(this List<DiagnosticMessage> diagnostics, SequencePoint sequencePoint, string message)
{
diagnostics.Add(new DiagnosticMessage
{
DiagnosticType = DiagnosticType.Error,
File = sequencePoint?.Document.Url.Replace($"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}", ""),
Line = sequencePoint?.StartLine ?? 0,
Column = sequencePoint?.StartColumn ?? 0,
MessageData = $" - {message}"
});
}
public static AssemblyDefinition AssemblyDefinitionFor(ICompiledAssembly compiledAssembly)
{
var assemblyResolver = new PostProcessorAssemblyResolver(compiledAssembly);
var readerParameters = new ReaderParameters
{
SymbolStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData),
SymbolReaderProvider = new PortablePdbReaderProvider(),
AssemblyResolver = assemblyResolver,
ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(),
ReadingMode = ReadingMode.Immediate
};
var assemblyDefinition = AssemblyDefinition.ReadAssembly(new MemoryStream(compiledAssembly.InMemoryAssembly.PeData), readerParameters);
//apparently, it will happen that when we ask to resolve a type that lives inside Unity.Netcode.Runtime, and we
//are also postprocessing Unity.Netcode.Runtime, type resolving will fail, because we do not actually try to resolve
//inside the assembly we are processing. Let's make sure we do that, so that we can use postprocessor features inside
//Unity.Netcode.Runtime itself as well.
assemblyResolver.AddAssemblyDefinitionBeingOperatedOn(assemblyDefinition);
return assemblyDefinition;
}
}
}

11
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs.meta


fileFormatVersion: 2
guid: 0e5541b3bca0e43b48c2e694fffef5b3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

1001
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs
文件差异内容过多而无法显示
查看文件

11
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs.meta


fileFormatVersion: 2
guid: cf1c8b78182704372820a586c1c91d97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

137
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorAssemblyResolver.cs


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Mono.Cecil;
using Unity.CompilationPipeline.Common.ILPostProcessing;
namespace Unity.Netcode.Editor.CodeGen
{
internal class PostProcessorAssemblyResolver : IAssemblyResolver
{
private readonly string[] m_AssemblyReferences;
private readonly Dictionary<string, AssemblyDefinition> m_AssemblyCache = new Dictionary<string, AssemblyDefinition>();
private readonly ICompiledAssembly m_CompiledAssembly;
private AssemblyDefinition m_SelfAssembly;
public PostProcessorAssemblyResolver(ICompiledAssembly compiledAssembly)
{
m_CompiledAssembly = compiledAssembly;
m_AssemblyReferences = compiledAssembly.References;
}
public void Dispose() { }
public AssemblyDefinition Resolve(AssemblyNameReference name) => Resolve(name, new ReaderParameters(ReadingMode.Deferred));
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
lock (m_AssemblyCache)
{
if (name.Name == m_CompiledAssembly.Name)
{
return m_SelfAssembly;
}
var fileName = FindFile(name);
if (fileName == null)
{
return null;
}
var lastWriteTime = File.GetLastWriteTime(fileName);
var cacheKey = $"{fileName}{lastWriteTime}";
if (m_AssemblyCache.TryGetValue(cacheKey, out var result))
{
return result;
}
parameters.AssemblyResolver = this;
var ms = MemoryStreamFor(fileName);
var pdb = $"{fileName}.pdb";
if (File.Exists(pdb))
{
parameters.SymbolStream = MemoryStreamFor(pdb);
}
var assemblyDefinition = AssemblyDefinition.ReadAssembly(ms, parameters);
m_AssemblyCache.Add(cacheKey, assemblyDefinition);
return assemblyDefinition;
}
}
private string FindFile(AssemblyNameReference name)
{
var fileName = m_AssemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == $"{name.Name}.dll");
if (fileName != null)
{
return fileName;
}
// perhaps the type comes from an exe instead
fileName = m_AssemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == $"{name.Name}.exe");
if (fileName != null)
{
return fileName;
}
//Unfortunately the current ICompiledAssembly API only provides direct references.
//It is very much possible that a postprocessor ends up investigating a type in a directly
//referenced assembly, that contains a field that is not in a directly referenced assembly.
//if we don't do anything special for that situation, it will fail to resolve. We should fix this
//in the ILPostProcessing API. As a workaround, we rely on the fact here that the indirect references
//are always located next to direct references, so we search in all directories of direct references we
//got passed, and if we find the file in there, we resolve to it.
return m_AssemblyReferences
.Select(Path.GetDirectoryName)
.Distinct()
.Select(parentDir => Path.Combine(parentDir, $"{name.Name}.dll"))
.FirstOrDefault(File.Exists);
}
private static MemoryStream MemoryStreamFor(string fileName)
{
return Retry(10, TimeSpan.FromSeconds(1), () =>
{
byte[] byteArray;
using var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
byteArray = new byte[fileStream.Length];
var readLength = fileStream.Read(byteArray, 0, (int)fileStream.Length);
if (readLength != fileStream.Length)
{
throw new InvalidOperationException("File read length is not full length of file.");
}
return new MemoryStream(byteArray);
});
}
private static MemoryStream Retry(int retryCount, TimeSpan waitTime, Func<MemoryStream> func)
{
try
{
return func();
}
catch (IOException)
{
if (retryCount == 0)
{
throw;
}
Console.WriteLine($"Caught IO Exception, trying {retryCount} more times");
Thread.Sleep(waitTime);
return Retry(retryCount - 1, waitTime, func);
}
}
public void AddAssemblyDefinitionBeingOperatedOn(AssemblyDefinition assemblyDefinition)
{
m_SelfAssembly = assemblyDefinition;
}
}
}

11
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorAssemblyResolver.cs.meta


fileFormatVersion: 2
guid: 2c247f4266b2864eb96e6a9ae6557d31
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

22
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs


using System.Linq;
using System.Reflection;
using Mono.Cecil;
namespace Unity.Netcode.Editor.CodeGen
{
internal class PostProcessorReflectionImporter : DefaultReflectionImporter
{
private const string k_SystemPrivateCoreLib = "System.Private.CoreLib";
private readonly AssemblyNameReference m_CorrectCorlib;
public PostProcessorReflectionImporter(ModuleDefinition module) : base(module)
{
m_CorrectCorlib = module.AssemblyReferences.FirstOrDefault(a => a.Name == "mscorlib" || a.Name == "netstandard" || a.Name == k_SystemPrivateCoreLib);
}
public override AssemblyNameReference ImportReference(AssemblyName reference)
{
return m_CorrectCorlib != null && reference.Name == k_SystemPrivateCoreLib ? m_CorrectCorlib : base.ImportReference(reference);
}
}
}

11
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs.meta


fileFormatVersion: 2
guid: 484e8ad8c4dde382ea67036b32935ef1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

12
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporterProvider.cs


using Mono.Cecil;
namespace Unity.Netcode.Editor.CodeGen
{
internal class PostProcessorReflectionImporterProvider : IReflectionImporterProvider
{
public IReflectionImporter GetReflectionImporter(ModuleDefinition moduleDefinition)
{
return new PostProcessorReflectionImporter(moduleDefinition);
}
}
}

11
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporterProvider.cs.meta


fileFormatVersion: 2
guid: f9273a5dad109ab0783891e36c983080
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

130
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs


using System.Collections.Generic;
using System.IO;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Unity.CompilationPipeline.Common.Diagnostics;
using Unity.CompilationPipeline.Common.ILPostProcessing;
using ILPPInterface = Unity.CompilationPipeline.Common.ILPostProcessing.ILPostProcessor;
namespace Unity.Netcode.Editor.CodeGen
{
internal sealed class RuntimeAccessModifiersILPP : ILPPInterface
{
public override ILPPInterface GetInstance() => this;
public override bool WillProcess(ICompiledAssembly compiledAssembly) => compiledAssembly.Name == CodeGenHelpers.RuntimeAssemblyName;
private readonly List<DiagnosticMessage> m_Diagnostics = new List<DiagnosticMessage>();
public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
{
if (!WillProcess(compiledAssembly))
{
return null;
}
m_Diagnostics.Clear();
// read
var assemblyDefinition = CodeGenHelpers.AssemblyDefinitionFor(compiledAssembly);
if (assemblyDefinition == null)
{
m_Diagnostics.AddError($"Cannot read Netcode Runtime assembly definition: {compiledAssembly.Name}");
return null;
}
// process
var mainModule = assemblyDefinition.MainModule;
if (mainModule != null)
{
foreach (var typeDefinition in mainModule.Types)
{
if (!typeDefinition.IsClass)
{
continue;
}
switch (typeDefinition.Name)
{
case nameof(NetworkManager):
ProcessNetworkManager(typeDefinition, compiledAssembly.Defines);
break;
case nameof(NetworkBehaviour):
ProcessNetworkBehaviour(typeDefinition);
break;
case nameof(__RpcParams):
typeDefinition.IsPublic = true;
break;
}
}
}
else
{
m_Diagnostics.AddError($"Cannot get main module from Netcode Runtime assembly definition: {compiledAssembly.Name}");
}
// write
var pe = new MemoryStream();
var pdb = new MemoryStream();
var writerParameters = new WriterParameters
{
SymbolWriterProvider = new PortablePdbWriterProvider(),
SymbolStream = pdb,
WriteSymbols = true
};
assemblyDefinition.Write(pe, writerParameters);
return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), m_Diagnostics);
}
private void ProcessNetworkManager(TypeDefinition typeDefinition, string[] assemblyDefines)
{
foreach (var fieldDefinition in typeDefinition.Fields)
{
if (fieldDefinition.Name == nameof(NetworkManager.__rpc_func_table))
{
fieldDefinition.IsPublic = true;
}
if (fieldDefinition.Name == nameof(NetworkManager.__rpc_name_table))
{
fieldDefinition.IsPublic = true;
}
}
}
private void ProcessNetworkBehaviour(TypeDefinition typeDefinition)
{
foreach (var nestedType in typeDefinition.NestedTypes)
{
if (nestedType.Name == nameof(NetworkBehaviour.__RpcExecStage))
{
nestedType.IsNestedFamily = true;
}
}
foreach (var fieldDefinition in typeDefinition.Fields)
{
if (fieldDefinition.Name == nameof(NetworkBehaviour.__rpc_exec_stage))
{
fieldDefinition.IsFamily = true;
}
}
foreach (var methodDefinition in typeDefinition.Methods)
{
switch (methodDefinition.Name)
{
case nameof(NetworkBehaviour.__beginSendServerRpc):
case nameof(NetworkBehaviour.__endSendServerRpc):
case nameof(NetworkBehaviour.__beginSendClientRpc):
case nameof(NetworkBehaviour.__endSendClientRpc):
methodDefinition.IsFamily = true;
break;
}
}
}
}
}

11
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs.meta


fileFormatVersion: 2
guid: 2c9f2f4b03d774432be69d4c2f53bd2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

19
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/com.unity.netcode.editor.codegen.asmdef


{
"name": "Unity.Netcode.Editor.CodeGen",
"rootNamespace": "Unity.Netcode.Editor.CodeGen",
"references": [
"Unity.Netcode.Runtime"
],
"includePlatforms": [
"Editor"
],
"allowUnsafeCode": true,
"overrideReferences": true,
"precompiledReferences": [
"Mono.Cecil.dll",
"Mono.Cecil.Mdb.dll",
"Mono.Cecil.Pdb.dll",
"Mono.Cecil.Rocks.dll"
],
"autoReferenced": false
}

7
Packages/com.unity.netcode.gameobjects/Editor/CodeGen/com.unity.netcode.editor.codegen.asmdef.meta


fileFormatVersion: 2
guid: fe4fa159f4a96442ba22af67ddf20c65
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.netcode.gameobjects/Editor/DontShowInTransportDropdownAttribute.cs


using System;
namespace Unity.Netcode.Editor
{
public class DontShowInTransportDropdownAttribute : Attribute
{
}
}

3
Packages/com.unity.netcode.gameobjects/Editor/DontShowInTransportDropdownAttribute.cs.meta


fileFormatVersion: 2
guid: 5f097067d4254dc7ad018d7ad90df7c3
timeCreated: 1620386886

211
Packages/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs


using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEditor;
namespace Unity.Netcode.Editor
{
[CustomEditor(typeof(NetworkBehaviour), true)]
[CanEditMultipleObjects]
public class NetworkBehaviourEditor : UnityEditor.Editor
{
private bool m_Initialized;
private readonly List<string> m_NetworkVariableNames = new List<string>();
private readonly Dictionary<string, FieldInfo> m_NetworkVariableFields = new Dictionary<string, FieldInfo>();
private readonly Dictionary<string, object> m_NetworkVariableObjects = new Dictionary<string, object>();
private GUIContent m_NetworkVariableLabelGuiContent;
private void Init(MonoScript script)
{
m_Initialized = true;
m_NetworkVariableNames.Clear();
m_NetworkVariableFields.Clear();
m_NetworkVariableObjects.Clear();
m_NetworkVariableLabelGuiContent = new GUIContent("NetworkVariable", "This variable is a NetworkVariable. It can not be serialized and can only be changed during runtime.");
var fields = script.GetClass().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
for (int i = 0; i < fields.Length; i++)
{
var ft = fields[i].FieldType;
if (ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(NetworkVariable<>) && !fields[i].IsDefined(typeof(HideInInspector), true))
{
m_NetworkVariableNames.Add(fields[i].Name);
m_NetworkVariableFields.Add(fields[i].Name, fields[i]);
}
}
}
private void RenderNetworkVariable(int index)
{
if (!m_NetworkVariableFields.ContainsKey(m_NetworkVariableNames[index]))
{
serializedObject.Update();
var scriptProperty = serializedObject.FindProperty("m_Script");
if (scriptProperty == null)
{
return;
}
var targetScript = scriptProperty.objectReferenceValue as MonoScript;
Init(targetScript);
}
object value = m_NetworkVariableFields[m_NetworkVariableNames[index]].GetValue(target);
if (value == null)
{
var fieldType = m_NetworkVariableFields[m_NetworkVariableNames[index]].FieldType;
var networkVariable = (NetworkVariableBase)Activator.CreateInstance(fieldType, true);
m_NetworkVariableFields[m_NetworkVariableNames[index]].SetValue(target, networkVariable);
}
var type = m_NetworkVariableFields[m_NetworkVariableNames[index]].GetValue(target).GetType();
var genericType = type.GetGenericArguments()[0];
EditorGUILayout.BeginHorizontal();
if (genericType.IsValueType)
{
var method = typeof(NetworkBehaviourEditor).GetMethod("RenderNetworkVariableValueType", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic);
var genericMethod = method.MakeGenericMethod(genericType);
genericMethod.Invoke(this, new[] { (object)index });
}
else
{
EditorGUILayout.LabelField("Type not renderable");
}
GUILayout.Label(m_NetworkVariableLabelGuiContent, EditorStyles.miniLabel, GUILayout.Width(EditorStyles.miniLabel.CalcSize(m_NetworkVariableLabelGuiContent).x));
EditorGUILayout.EndHorizontal();
}
private void RenderNetworkVariableValueType<T>(int index) where T : unmanaged
{
var networkVariable = (NetworkVariable<T>)m_NetworkVariableFields[m_NetworkVariableNames[index]].GetValue(target);
var type = typeof(T);
object val = networkVariable.Value;
string name = m_NetworkVariableNames[index];
var behaviour = (NetworkBehaviour)target;
if (behaviour.NetworkManager != null && behaviour.NetworkManager.IsListening)
{
if (type == typeof(int))
{
val = EditorGUILayout.IntField(name, (int)val);
}
else if (type == typeof(uint))
{
val = (uint)EditorGUILayout.LongField(name, (long)((uint)val));
}
else if (type == typeof(short))
{
val = (short)EditorGUILayout.IntField(name, (int)((short)val));
}
else if (type == typeof(ushort))
{
val = (ushort)EditorGUILayout.IntField(name, (int)((ushort)val));
}
else if (type == typeof(sbyte))
{
val = (sbyte)EditorGUILayout.IntField(name, (int)((sbyte)val));
}
else if (type == typeof(byte))
{
val = (byte)EditorGUILayout.IntField(name, (int)((byte)val));
}
else if (type == typeof(long))
{
val = EditorGUILayout.LongField(name, (long)val);
}
else if (type == typeof(ulong))
{
val = (ulong)EditorGUILayout.LongField(name, (long)((ulong)val));
}
else if (type == typeof(bool))
{
val = EditorGUILayout.Toggle(name, (bool)val);
}
else if (type == typeof(string))
{
val = EditorGUILayout.TextField(name, (string)val);
}
else if (type.IsEnum)
{
val = EditorGUILayout.EnumPopup(name, (Enum)val);
}
else
{
EditorGUILayout.LabelField("Type not renderable");
}
networkVariable.Value = (T)val;
}
else
{
EditorGUILayout.LabelField(name, EditorStyles.wordWrappedLabel);
EditorGUILayout.SelectableLabel(val.ToString(), EditorStyles.wordWrappedLabel);
}
}
public override void OnInspectorGUI()
{
if (!m_Initialized)
{
serializedObject.Update();
var scriptProperty = serializedObject.FindProperty("m_Script");
if (scriptProperty == null)
{
return;
}
var targetScript = scriptProperty.objectReferenceValue as MonoScript;
Init(targetScript);
}
EditorGUI.BeginChangeCheck();
serializedObject.Update();
if (EditorApplication.isPlaying)
{
for (int i = 0; i < m_NetworkVariableNames.Count; i++)
{
RenderNetworkVariable(i);
}
}
var property = serializedObject.GetIterator();
bool expanded = true;
while (property.NextVisible(expanded))
{
if (property.propertyType == SerializedPropertyType.ObjectReference)
{
if (property.name == "m_Script")
{
EditorGUI.BeginDisabledGroup(true);
}
EditorGUILayout.PropertyField(property, true);
if (property.name == "m_Script")
{
EditorGUI.EndDisabledGroup();
}
}
else
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(property, true);
EditorGUILayout.EndHorizontal();
}
expanded = false;
}
serializedObject.ApplyModifiedProperties();
EditorGUI.EndChangeCheck();
}
}
}

11
Packages/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs.meta


fileFormatVersion: 2
guid: a4a5c9c08a4038e449fd259764bc663f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

371
Packages/com.unity.netcode.gameobjects/Editor/NetworkManagerEditor.cs


using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditorInternal;
namespace Unity.Netcode.Editor
{
[CustomEditor(typeof(NetworkManager), true)]
[CanEditMultipleObjects]
public class NetworkManagerEditor : UnityEditor.Editor
{
// Properties
private SerializedProperty m_DontDestroyOnLoadProperty;
private SerializedProperty m_RunInBackgroundProperty;
private SerializedProperty m_LogLevelProperty;
// NetworkConfig
private SerializedProperty m_NetworkConfigProperty;
// NetworkConfig fields
private SerializedProperty m_PlayerPrefabProperty;
private SerializedProperty m_ProtocolVersionProperty;
private SerializedProperty m_NetworkTransportProperty;
private SerializedProperty m_TickRateProperty;
private SerializedProperty m_MaxObjectUpdatesPerTickProperty;
private SerializedProperty m_ClientConnectionBufferTimeoutProperty;
private SerializedProperty m_ConnectionApprovalProperty;
private SerializedProperty m_EnableNetworkVariableProperty;
private SerializedProperty m_EnsureNetworkVariableLengthSafetyProperty;
private SerializedProperty m_ForceSamePrefabsProperty;
private SerializedProperty m_EnableSceneManagementProperty;
private SerializedProperty m_RecycleNetworkIdsProperty;
private SerializedProperty m_NetworkIdRecycleDelayProperty;
private SerializedProperty m_RpcHashSizeProperty;
private SerializedProperty m_LoadSceneTimeOutProperty;
private ReorderableList m_NetworkPrefabsList;
private NetworkManager m_NetworkManager;
private bool m_Initialized;
private readonly List<Type> m_TransportTypes = new List<Type>();
private string[] m_TransportNames = { "Select transport..." };
private void ReloadTransports()
{
m_TransportTypes.Clear();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(typeof(NetworkTransport)) && type.GetCustomAttributes(typeof(DontShowInTransportDropdownAttribute), true).Length == 0)
{
m_TransportTypes.Add(type);
}
}
}
m_TransportNames = new string[m_TransportTypes.Count + 1];
m_TransportNames[0] = "Select transport...";
for (int i = 0; i < m_TransportTypes.Count; i++)
{
m_TransportNames[i + 1] = m_TransportTypes[i].Name;
}
}
private void Initialize()
{
if (m_Initialized)
{
return;
}
m_Initialized = true;
m_NetworkManager = (NetworkManager)target;
// Base properties
m_DontDestroyOnLoadProperty = serializedObject.FindProperty(nameof(NetworkManager.DontDestroy));
m_RunInBackgroundProperty = serializedObject.FindProperty(nameof(NetworkManager.RunInBackground));
m_LogLevelProperty = serializedObject.FindProperty(nameof(NetworkManager.LogLevel));
m_NetworkConfigProperty = serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig));
// NetworkConfig properties
m_PlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative(nameof(NetworkConfig.PlayerPrefab));
m_ProtocolVersionProperty = m_NetworkConfigProperty.FindPropertyRelative("ProtocolVersion");
m_NetworkTransportProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTransport");
m_TickRateProperty = m_NetworkConfigProperty.FindPropertyRelative("TickRate");
m_ClientConnectionBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("ClientConnectionBufferTimeout");
m_ConnectionApprovalProperty = m_NetworkConfigProperty.FindPropertyRelative("ConnectionApproval");
m_EnableNetworkVariableProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableNetworkVariable");
m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety");
m_ForceSamePrefabsProperty = m_NetworkConfigProperty.FindPropertyRelative("ForceSamePrefabs");
m_EnableSceneManagementProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableSceneManagement");
m_RecycleNetworkIdsProperty = m_NetworkConfigProperty.FindPropertyRelative("RecycleNetworkIds");
m_NetworkIdRecycleDelayProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkIdRecycleDelay");
m_RpcHashSizeProperty = m_NetworkConfigProperty.FindPropertyRelative("RpcHashSize");
m_LoadSceneTimeOutProperty = m_NetworkConfigProperty.FindPropertyRelative("LoadSceneTimeOut");
ReloadTransports();
}
private void CheckNullProperties()
{
// Base properties
m_DontDestroyOnLoadProperty = serializedObject.FindProperty(nameof(NetworkManager.DontDestroy));
m_RunInBackgroundProperty = serializedObject.FindProperty(nameof(NetworkManager.RunInBackground));
m_LogLevelProperty = serializedObject.FindProperty(nameof(NetworkManager.LogLevel));
m_NetworkConfigProperty = serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig));
// NetworkConfig properties
m_PlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative(nameof(NetworkConfig.PlayerPrefab));
m_ProtocolVersionProperty = m_NetworkConfigProperty.FindPropertyRelative("ProtocolVersion");
m_NetworkTransportProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTransport");
m_TickRateProperty = m_NetworkConfigProperty.FindPropertyRelative("TickRate");
m_ClientConnectionBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("ClientConnectionBufferTimeout");
m_ConnectionApprovalProperty = m_NetworkConfigProperty.FindPropertyRelative("ConnectionApproval");
m_EnableNetworkVariableProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableNetworkVariable");
m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety");
m_ForceSamePrefabsProperty = m_NetworkConfigProperty.FindPropertyRelative("ForceSamePrefabs");
m_EnableSceneManagementProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableSceneManagement");
m_RecycleNetworkIdsProperty = m_NetworkConfigProperty.FindPropertyRelative("RecycleNetworkIds");
m_NetworkIdRecycleDelayProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkIdRecycleDelay");
m_RpcHashSizeProperty = m_NetworkConfigProperty.FindPropertyRelative("RpcHashSize");
m_LoadSceneTimeOutProperty = m_NetworkConfigProperty.FindPropertyRelative("LoadSceneTimeOut");
}
private void OnEnable()
{
m_NetworkPrefabsList = new ReorderableList(serializedObject, serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)).FindPropertyRelative(nameof(NetworkConfig.NetworkPrefabs)), true, true, true, true);
m_NetworkPrefabsList.elementHeightCallback = index =>
{
var networkPrefab = m_NetworkPrefabsList.serializedProperty.GetArrayElementAtIndex(index);
var networkOverrideProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.Override));
var networkOverrideInt = networkOverrideProp.enumValueIndex;
return 8 + (networkOverrideInt == 0 ? EditorGUIUtility.singleLineHeight : (EditorGUIUtility.singleLineHeight * 2) + 5);
};
m_NetworkPrefabsList.drawElementCallback = (rect, index, isActive, isFocused) =>
{
rect.y += 5;
var networkPrefab = m_NetworkPrefabsList.serializedProperty.GetArrayElementAtIndex(index);
var networkPrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.Prefab));
var networkSourceHashProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.SourceHashToOverride));
var networkSourcePrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.SourcePrefabToOverride));
var networkTargetPrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.OverridingTargetPrefab));
var networkOverrideProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.Override));
var networkOverrideInt = networkOverrideProp.enumValueIndex;
var networkOverrideEnum = (NetworkPrefabOverride)networkOverrideInt;
EditorGUI.LabelField(new Rect(rect.x + rect.width - 70, rect.y, 60, EditorGUIUtility.singleLineHeight), "Override");
if (networkOverrideEnum == NetworkPrefabOverride.None)
{
if (EditorGUI.Toggle(new Rect(rect.x + rect.width - 15, rect.y, 10, EditorGUIUtility.singleLineHeight), false))
{
networkOverrideProp.enumValueIndex = (int)NetworkPrefabOverride.Prefab;
}
}
else
{
if (!EditorGUI.Toggle(new Rect(rect.x + rect.width - 15, rect.y, 10, EditorGUIUtility.singleLineHeight), true))
{
networkOverrideProp.enumValueIndex = 0;
networkOverrideEnum = NetworkPrefabOverride.None;
}
}
if (networkOverrideEnum == NetworkPrefabOverride.None)
{
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width - 80, EditorGUIUtility.singleLineHeight), networkPrefabProp, GUIContent.none);
}
else
{
networkOverrideProp.enumValueIndex = GUI.Toolbar(new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight), networkOverrideInt - 1, new[] { "Prefab", "Hash" }) + 1;
if (networkOverrideEnum == NetworkPrefabOverride.Prefab)
{
EditorGUI.PropertyField(new Rect(rect.x + 110, rect.y, rect.width - 190, EditorGUIUtility.singleLineHeight), networkSourcePrefabProp, GUIContent.none);
}
else
{
EditorGUI.PropertyField(new Rect(rect.x + 110, rect.y, rect.width - 190, EditorGUIUtility.singleLineHeight), networkSourceHashProp, GUIContent.none);
}
rect.y += EditorGUIUtility.singleLineHeight + 5;
EditorGUI.LabelField(new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight), "Overriding Prefab");
EditorGUI.PropertyField(new Rect(rect.x + 110, rect.y, rect.width - 110, EditorGUIUtility.singleLineHeight), networkTargetPrefabProp, GUIContent.none);
}
};
m_NetworkPrefabsList.drawHeaderCallback = rect => EditorGUI.LabelField(rect, "NetworkPrefabs");
}
public override void OnInspectorGUI()
{
Initialize();
CheckNullProperties();
{
var iterator = serializedObject.GetIterator();
for (bool enterChildren = true; iterator.NextVisible(enterChildren); enterChildren = false)
{
using (new EditorGUI.DisabledScope("m_Script" == iterator.propertyPath))
{
EditorGUILayout.PropertyField(iterator, false);
}
}
}
if (!m_NetworkManager.IsServer && !m_NetworkManager.IsClient)
{
serializedObject.Update();
EditorGUILayout.PropertyField(m_DontDestroyOnLoadProperty);
EditorGUILayout.PropertyField(m_RunInBackgroundProperty);
EditorGUILayout.PropertyField(m_LogLevelProperty);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_PlayerPrefabProperty);
EditorGUILayout.Space();
m_NetworkPrefabsList.DoLayoutList();
EditorGUILayout.Space();
EditorGUILayout.LabelField("General", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_ProtocolVersionProperty);
EditorGUILayout.PropertyField(m_NetworkTransportProperty);
if (m_NetworkTransportProperty.objectReferenceValue == null)
{
EditorGUILayout.HelpBox("You have no transport selected. A transport is required for netcode to work. Which one do you want?", MessageType.Warning);
int selection = EditorGUILayout.Popup(0, m_TransportNames);
if (selection > 0)
{
ReloadTransports();
var transportComponent = m_NetworkManager.gameObject.GetComponent(m_TransportTypes[selection - 1]);
if (transportComponent == null)
{
transportComponent = m_NetworkManager.gameObject.AddComponent(m_TransportTypes[selection - 1]);
}
m_NetworkTransportProperty.objectReferenceValue = transportComponent;
Repaint();
}
}
EditorGUILayout.PropertyField(m_TickRateProperty);
EditorGUILayout.LabelField("Performance", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_EnableNetworkVariableProperty);
using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableNetworkVariable))
{
EditorGUILayout.PropertyField(m_EnsureNetworkVariableLengthSafetyProperty);
}
EditorGUILayout.LabelField("Connection", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_ConnectionApprovalProperty);
using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.ConnectionApproval))
{
EditorGUILayout.PropertyField(m_ClientConnectionBufferTimeoutProperty);
}
EditorGUILayout.LabelField("Spawning", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_ForceSamePrefabsProperty);
EditorGUILayout.PropertyField(m_RecycleNetworkIdsProperty);
using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.RecycleNetworkIds))
{
EditorGUILayout.PropertyField(m_NetworkIdRecycleDelayProperty);
}
EditorGUILayout.LabelField("Bandwidth", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_RpcHashSizeProperty);
EditorGUILayout.LabelField("Scene Management", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_EnableSceneManagementProperty);
using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableSceneManagement))
{
EditorGUILayout.PropertyField(m_LoadSceneTimeOutProperty);
}
serializedObject.ApplyModifiedProperties();
// Start buttons below
{
string buttonDisabledReasonSuffix = "";
if (!EditorApplication.isPlaying)
{
buttonDisabledReasonSuffix = ". This can only be done in play mode";
GUI.enabled = false;
}
if (GUILayout.Button(new GUIContent("Start Host", "Starts a host instance" + buttonDisabledReasonSuffix)))
{
m_NetworkManager.StartHost();
}
if (GUILayout.Button(new GUIContent("Start Server", "Starts a server instance" + buttonDisabledReasonSuffix)))
{
m_NetworkManager.StartServer();
}
if (GUILayout.Button(new GUIContent("Start Client", "Starts a client instance" + buttonDisabledReasonSuffix)))
{
m_NetworkManager.StartClient();
}
if (!EditorApplication.isPlaying)
{
GUI.enabled = true;
}
}
}
else
{
string instanceType = string.Empty;
if (m_NetworkManager.IsHost)
{
instanceType = "Host";
}
else if (m_NetworkManager.IsServer)
{
instanceType = "Server";
}
else if (m_NetworkManager.IsClient)
{
instanceType = "Client";
}
EditorGUILayout.HelpBox("You cannot edit the NetworkConfig when a " + instanceType + " is running.", MessageType.Info);
if (GUILayout.Button(new GUIContent("Stop " + instanceType, "Stops the " + instanceType + " instance.")))
{
if (m_NetworkManager.IsHost)
{
m_NetworkManager.StopHost();
}
else if (m_NetworkManager.IsServer)
{
m_NetworkManager.StopServer();
}
else if (m_NetworkManager.IsClient)
{
m_NetworkManager.StopClient();
}
}
}
}
}
}

11
Packages/com.unity.netcode.gameobjects/Editor/NetworkManagerEditor.cs.meta


fileFormatVersion: 2
guid: 74a8f011a324b7642b69098fe57bf635
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

104
Packages/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs


using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace Unity.Netcode.Editor
{
[CustomEditor(typeof(NetworkObject), true)]
[CanEditMultipleObjects]
public class NetworkObjectEditor : UnityEditor.Editor
{
private bool m_Initialized;
private NetworkObject m_NetworkObject;
private bool m_ShowObservers;
private void Initialize()
{
if (m_Initialized)
{
return;
}
m_Initialized = true;
m_NetworkObject = (NetworkObject)target;
}
public override void OnInspectorGUI()
{
Initialize();
if (EditorApplication.isPlaying && !m_NetworkObject.IsSpawned && m_NetworkObject.NetworkManager != null && m_NetworkObject.NetworkManager.IsServer)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent("Spawn", "Spawns the object across the network"));
if (GUILayout.Toggle(false, "Spawn", EditorStyles.miniButtonLeft))
{
m_NetworkObject.Spawn();
EditorUtility.SetDirty(target);
}
EditorGUILayout.EndHorizontal();
}
else if (EditorApplication.isPlaying && m_NetworkObject.IsSpawned)
{
var guiEnabled = GUI.enabled;
GUI.enabled = false;
EditorGUILayout.TextField(nameof(NetworkObject.GlobalObjectIdHash), m_NetworkObject.GlobalObjectIdHash.ToString());
EditorGUILayout.TextField(nameof(NetworkObject.NetworkObjectId), m_NetworkObject.NetworkObjectId.ToString());
EditorGUILayout.TextField(nameof(NetworkObject.OwnerClientId), m_NetworkObject.OwnerClientId.ToString());
EditorGUILayout.Toggle(nameof(NetworkObject.IsSpawned), m_NetworkObject.IsSpawned);
EditorGUILayout.Toggle(nameof(NetworkObject.IsLocalPlayer), m_NetworkObject.IsLocalPlayer);
EditorGUILayout.Toggle(nameof(NetworkObject.IsOwner), m_NetworkObject.IsOwner);
EditorGUILayout.Toggle(nameof(NetworkObject.IsOwnedByServer), m_NetworkObject.IsOwnedByServer);
EditorGUILayout.Toggle(nameof(NetworkObject.IsPlayerObject), m_NetworkObject.IsPlayerObject);
if (m_NetworkObject.IsSceneObject.HasValue)
{
EditorGUILayout.Toggle(nameof(NetworkObject.IsSceneObject), m_NetworkObject.IsSceneObject.Value);
}
else
{
EditorGUILayout.TextField(nameof(NetworkObject.IsSceneObject), "null");
}
EditorGUILayout.Toggle(nameof(NetworkObject.DestroyWithScene), m_NetworkObject.DestroyWithScene);
EditorGUILayout.TextField(nameof(NetworkObject.NetworkManager), m_NetworkObject.NetworkManager == null ? "null" : m_NetworkObject.NetworkManager.gameObject.name);
GUI.enabled = guiEnabled;
if (m_NetworkObject.NetworkManager != null && m_NetworkObject.NetworkManager.IsServer)
{
m_ShowObservers = EditorGUILayout.Foldout(m_ShowObservers, "Observers");
if (m_ShowObservers)
{
HashSet<ulong>.Enumerator observerClientIds = m_NetworkObject.GetObservers();
EditorGUI.indentLevel += 1;
while (observerClientIds.MoveNext())
{
if (m_NetworkObject.NetworkManager.ConnectedClients[observerClientIds.Current].PlayerObject != null)
{
EditorGUILayout.ObjectField($"ClientId: {observerClientIds.Current}", m_NetworkObject.NetworkManager.ConnectedClients[observerClientIds.Current].PlayerObject, typeof(GameObject), false);
}
else
{
EditorGUILayout.TextField($"ClientId: {observerClientIds.Current}", EditorStyles.label);
}
}
EditorGUI.indentLevel -= 1;
}
}
}
else
{
base.OnInspectorGUI();
var guiEnabled = GUI.enabled;
GUI.enabled = false;
EditorGUILayout.TextField(nameof(NetworkObject.GlobalObjectIdHash), m_NetworkObject.GlobalObjectIdHash.ToString());
EditorGUILayout.TextField(nameof(NetworkObject.NetworkManager), m_NetworkObject.NetworkManager == null ? "null" : m_NetworkObject.NetworkManager.gameObject.name);
GUI.enabled = guiEnabled;
}
}
}
}

11
Packages/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs.meta


fileFormatVersion: 2
guid: 36e4b519d287d0f4e8bfb7d088a9275f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

118
Packages/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs


using Unity.Netcode.Prototyping;
using UnityEditor;
using UnityEngine;
namespace Unity.Netcode.Editor
{
[CustomEditor(typeof(NetworkTransform))]
public class NetworkTransformEditor : UnityEditor.Editor
{
private SerializedProperty m_SyncPositionXProperty;
private SerializedProperty m_SyncPositionYProperty;
private SerializedProperty m_SyncPositionZProperty;
private SerializedProperty m_SyncRotationXProperty;
private SerializedProperty m_SyncRotationYProperty;
private SerializedProperty m_SyncRotationZProperty;
private SerializedProperty m_SyncScaleXProperty;
private SerializedProperty m_SyncScaleYProperty;
private SerializedProperty m_SyncScaleZProperty;
private SerializedProperty m_PositionThresholdProperty;
private SerializedProperty m_RotAngleThresholdProperty;
private SerializedProperty m_ScaleThresholdProperty;
private SerializedProperty m_InLocalSpaceProperty;
private SerializedProperty m_InterpolateProperty;
private static int s_ToggleOffset = 45;
private static float s_MaxRowWidth = EditorGUIUtility.labelWidth + EditorGUIUtility.fieldWidth + 5;
private static GUIContent s_PositionLabel = EditorGUIUtility.TrTextContent("Position");
private static GUIContent s_RotationLabel = EditorGUIUtility.TrTextContent("Rotation");
private static GUIContent s_ScaleLabel = EditorGUIUtility.TrTextContent("Scale");
public void OnEnable()
{
m_SyncPositionXProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncPositionX));
m_SyncPositionYProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncPositionY));
m_SyncPositionZProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncPositionZ));
m_SyncRotationXProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncRotAngleX));
m_SyncRotationYProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncRotAngleY));
m_SyncRotationZProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncRotAngleZ));
m_SyncScaleXProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncScaleX));
m_SyncScaleYProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncScaleY));
m_SyncScaleZProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncScaleZ));
m_PositionThresholdProperty = serializedObject.FindProperty(nameof(NetworkTransform.PositionThreshold));
m_RotAngleThresholdProperty = serializedObject.FindProperty(nameof(NetworkTransform.RotAngleThreshold));
m_ScaleThresholdProperty = serializedObject.FindProperty(nameof(NetworkTransform.ScaleThreshold));
m_InLocalSpaceProperty = serializedObject.FindProperty(nameof(NetworkTransform.InLocalSpace));
m_InterpolateProperty = serializedObject.FindProperty(nameof(NetworkTransform.Interpolate));
}
public override void OnInspectorGUI()
{
EditorGUILayout.LabelField("Syncing", EditorStyles.boldLabel);
{
GUILayout.BeginHorizontal();
var rect = GUILayoutUtility.GetRect(EditorGUIUtility.fieldWidth, s_MaxRowWidth, EditorGUIUtility.singleLineHeight, EditorGUIUtility.singleLineHeight, EditorStyles.numberField);
var ctid = GUIUtility.GetControlID(7231, FocusType.Keyboard, rect);
rect = EditorGUI.PrefixLabel(rect, ctid, s_PositionLabel);
rect.width = s_ToggleOffset;
m_SyncPositionXProperty.boolValue = EditorGUI.ToggleLeft(rect, "X", m_SyncPositionXProperty.boolValue);
rect.x += s_ToggleOffset;
m_SyncPositionYProperty.boolValue = EditorGUI.ToggleLeft(rect, "Y", m_SyncPositionYProperty.boolValue);
rect.x += s_ToggleOffset;
m_SyncPositionZProperty.boolValue = EditorGUI.ToggleLeft(rect, "Z", m_SyncPositionZProperty.boolValue);
GUILayout.EndHorizontal();
}
{
GUILayout.BeginHorizontal();
var rect = GUILayoutUtility.GetRect(EditorGUIUtility.fieldWidth, s_MaxRowWidth, EditorGUIUtility.singleLineHeight, EditorGUIUtility.singleLineHeight, EditorStyles.numberField);
var ctid = GUIUtility.GetControlID(7231, FocusType.Keyboard, rect);
rect = EditorGUI.PrefixLabel(rect, ctid, s_RotationLabel);
rect.width = s_ToggleOffset;
m_SyncRotationXProperty.boolValue = EditorGUI.ToggleLeft(rect, "X", m_SyncRotationXProperty.boolValue);
rect.x += s_ToggleOffset;
m_SyncRotationYProperty.boolValue = EditorGUI.ToggleLeft(rect, "Y", m_SyncRotationYProperty.boolValue);
rect.x += s_ToggleOffset;
m_SyncRotationZProperty.boolValue = EditorGUI.ToggleLeft(rect, "Z", m_SyncRotationZProperty.boolValue);
GUILayout.EndHorizontal();
}
{
GUILayout.BeginHorizontal();
var rect = GUILayoutUtility.GetRect(EditorGUIUtility.fieldWidth, s_MaxRowWidth, EditorGUIUtility.singleLineHeight, EditorGUIUtility.singleLineHeight, EditorStyles.numberField);
var ctid = GUIUtility.GetControlID(7231, FocusType.Keyboard, rect);
rect = EditorGUI.PrefixLabel(rect, ctid, s_ScaleLabel);
rect.width = s_ToggleOffset;
m_SyncScaleXProperty.boolValue = EditorGUI.ToggleLeft(rect, "X", m_SyncScaleXProperty.boolValue);
rect.x += s_ToggleOffset;
m_SyncScaleYProperty.boolValue = EditorGUI.ToggleLeft(rect, "Y", m_SyncScaleYProperty.boolValue);
rect.x += s_ToggleOffset;
m_SyncScaleZProperty.boolValue = EditorGUI.ToggleLeft(rect, "Z", m_SyncScaleZProperty.boolValue);
GUILayout.EndHorizontal();
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Thresholds", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_PositionThresholdProperty);
EditorGUILayout.PropertyField(m_RotAngleThresholdProperty);
EditorGUILayout.PropertyField(m_ScaleThresholdProperty);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Configurations", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_InLocalSpaceProperty);
EditorGUILayout.PropertyField(m_InterpolateProperty);
serializedObject.ApplyModifiedProperties();
}
}
}

11
Packages/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs.meta


fileFormatVersion: 2
guid: 17891488cb32d4243b0710884463d70f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

11
Packages/com.unity.netcode.gameobjects/Editor/com.unity.netcode.editor.asmdef


{
"name": "Unity.Netcode.Editor",
"rootNamespace": "Unity.Netcode.Editor",
"references": [
"Unity.Netcode.Runtime",
"Unity.Netcode.Prototyping"
],
"includePlatforms": [
"Editor"
]
}

7
Packages/com.unity.netcode.gameobjects/Editor/com.unity.netcode.editor.asmdef.meta


fileFormatVersion: 2
guid: 9f4f5bf029cebb64f983b7bdc29f62a1
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

9
Packages/com.unity.netcode.gameobjects/LICENSE.md


MIT License
Copyright (c) 2021 Unity Technologies
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

7
Packages/com.unity.netcode.gameobjects/LICENSE.md.meta


fileFormatVersion: 2
guid: a850895ba88aa114f804fefa31faf4d2
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.netcode.gameobjects/Prototyping.meta


fileFormatVersion: 2
guid: 4f9f645c043894b81ab326fe4703f4c8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

10
Packages/com.unity.netcode.gameobjects/Prototyping/AssemblyInfo.cs


using System.Runtime.CompilerServices;
#if UNITY_EDITOR
[assembly: InternalsVisibleTo("Unity.Netcode.EditorTests")]
[assembly: InternalsVisibleTo("Unity.Netcode.Editor.CodeGen")]
[assembly: InternalsVisibleTo("Unity.Netcode.Editor")]
[assembly: InternalsVisibleTo("TestProject.EditorTests")]
[assembly: InternalsVisibleTo("TestProject.RuntimeTests")]
#endif
[assembly: InternalsVisibleTo("Unity.Netcode.RuntimeTests")]

11
Packages/com.unity.netcode.gameobjects/Prototyping/AssemblyInfo.cs.meta


fileFormatVersion: 2
guid: 5b8086dc75d86473f9e3c928dd773733
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

560
Packages/com.unity.netcode.gameobjects/Prototyping/NetworkAnimator.cs


using System.Linq;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.Netcode.Prototyping
{
/// <summary>
/// A prototype component for syncing animations
/// </summary>
[AddComponentMenu("Netcode/" + nameof(NetworkAnimator))]
public class NetworkAnimator : NetworkBehaviour
{
private class AnimatorSnapshot : INetworkSerializable
{
public Dictionary<int, bool> BoolParameters;
public Dictionary<int, float> FloatParameters;
public Dictionary<int, int> IntParameters;
public HashSet<int> TriggerParameters;
public LayerState[] LayerStates;
public AnimatorSnapshot(Dictionary<int, bool> boolParameters, Dictionary<int, float> floatParameters, Dictionary<int, int> intParameters, HashSet<int> triggerParameters, LayerState[] layerStates)
{
BoolParameters = boolParameters;
FloatParameters = floatParameters;
IntParameters = intParameters;
TriggerParameters = triggerParameters;
LayerStates = layerStates;
}
public AnimatorSnapshot()
{
BoolParameters = new Dictionary<int, bool>(0);
FloatParameters = new Dictionary<int, float>(0);
IntParameters = new Dictionary<int, int>(0);
TriggerParameters = new HashSet<int>();
LayerStates = new LayerState[0];
}
public bool SetInt(int key, int value)
{
if (IntParameters.TryGetValue(key, out var existingValue) && existingValue == value)
{
return false;
}
IntParameters[key] = value;
return true;
}
public bool SetBool(int key, bool value)
{
if (BoolParameters.TryGetValue(key, out var existingValue) && existingValue == value)
{
return false;
}
BoolParameters[key] = value;
return true;
}
public bool SetFloat(int key, float value)
{
if (FloatParameters.TryGetValue(key, out var existingValue) &&
Mathf.Abs(existingValue - value) < Mathf.Epsilon)
{
return false;
}
FloatParameters[key] = value;
return true;
}
public bool SetTrigger(int key)
{
return TriggerParameters.Add(key);
}
public void NetworkSerialize(NetworkSerializer serializer)
{
SerializeIntParameters(serializer);
SerializeFloatParameters(serializer);
SerializeBoolParameters(serializer);
SerializeTriggerParameters(serializer);
SerializeAnimatorLayerStates(serializer);
}
private void SerializeAnimatorLayerStates(NetworkSerializer serializer)
{
int layerCount = serializer.IsReading ? 0 : LayerStates.Length;
serializer.Serialize(ref layerCount);
if (serializer.IsReading && LayerStates.Length != layerCount)
{
LayerStates = new LayerState[layerCount];
}
for (int paramIndex = 0; paramIndex < layerCount; paramIndex++)
{
var stateHash = serializer.IsReading ? 0 : LayerStates[paramIndex].StateHash;
serializer.Serialize(ref stateHash);
var layerWeight = serializer.IsReading ? 0 : LayerStates[paramIndex].LayerWeight;
serializer.Serialize(ref layerWeight);
var normalizedStateTime = serializer.IsReading ? 0 : LayerStates[paramIndex].NormalizedStateTime;
serializer.Serialize(ref normalizedStateTime);
if (serializer.IsReading)
{
LayerStates[paramIndex] = new LayerState()
{
LayerWeight = layerWeight,
StateHash = stateHash,
NormalizedStateTime = normalizedStateTime
};
}
}
}
private void SerializeTriggerParameters(NetworkSerializer serializer)
{
int paramCount = serializer.IsReading ? 0 : TriggerParameters.Count;
serializer.Serialize(ref paramCount);
var paramArray = serializer.IsReading ? new int[paramCount] : TriggerParameters.ToArray();
for (int i = 0; i < paramCount; i++)
{
var paramId = serializer.IsReading ? 0 : paramArray[i];
serializer.Serialize(ref paramId);
if (serializer.IsReading)
{
paramArray[i] = paramId;
}
}
if (serializer.IsReading)
{
TriggerParameters = new HashSet<int>(paramArray);
}
}
private void SerializeBoolParameters(NetworkSerializer serializer)
{
int paramCount = serializer.IsReading ? 0 : BoolParameters.Count;
serializer.Serialize(ref paramCount);
var paramArray = serializer.IsReading ? new KeyValuePair<int, bool>[paramCount] : BoolParameters.ToArray();
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++)
{
var paramId = serializer.IsReading ? 0 : paramArray[paramIndex].Key;
serializer.Serialize(ref paramId);
var paramBool = serializer.IsReading ? false : paramArray[paramIndex].Value;
serializer.Serialize(ref paramBool);
if (serializer.IsReading)
{
paramArray[paramIndex] = new KeyValuePair<int, bool>(paramId, paramBool);
}
}
if (serializer.IsReading)
{
BoolParameters = paramArray.ToDictionary(pair => pair.Key, pair => pair.Value);
}
}
private void SerializeFloatParameters(NetworkSerializer serializer)
{
int paramCount = serializer.IsReading ? 0 : FloatParameters.Count;
serializer.Serialize(ref paramCount);
var paramArray = serializer.IsReading ? new KeyValuePair<int, float>[paramCount] : FloatParameters.ToArray();
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++)
{
var paramId = serializer.IsReading ? 0 : paramArray[paramIndex].Key;
serializer.Serialize(ref paramId);
var paramFloat = serializer.IsReading ? 0 : paramArray[paramIndex].Value;
serializer.Serialize(ref paramFloat);
if (serializer.IsReading)
{
paramArray[paramIndex] = new KeyValuePair<int, float>(paramId, paramFloat);
}
}
if (serializer.IsReading)
{
FloatParameters = paramArray.ToDictionary(pair => pair.Key, pair => pair.Value);
}
}
private void SerializeIntParameters(NetworkSerializer serializer)
{
int paramCount = serializer.IsReading ? 0 : IntParameters.Count;
serializer.Serialize(ref paramCount);
var paramArray = serializer.IsReading ? new KeyValuePair<int, int>[paramCount] : IntParameters.ToArray();
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++)
{
var paramId = serializer.IsReading ? 0 : paramArray[paramIndex].Key;
serializer.Serialize(ref paramId);
var paramInt = serializer.IsReading ? 0 : paramArray[paramIndex].Value;
serializer.Serialize(ref paramInt);
if (serializer.IsReading)
{
paramArray[paramIndex] = new KeyValuePair<int, int>(paramId, paramInt);
}
}
if (serializer.IsReading)
{
IntParameters = paramArray.ToDictionary(pair => pair.Key, pair => pair.Value);
}
}
}
private struct LayerState
{
public int StateHash;
public float NormalizedStateTime;
public float LayerWeight;
}
/// <summary>
/// Server authority only allows the server to update this animator
/// Client authority only allows the client owner to update this animator
/// </summary>
public enum Authority
{
Server = 0,
Owner
}
/// <summary>
/// This constant is used to force the resync if the delta between current
/// and last synced normalized state time goes above it
/// </summary>
private const float k_NormalizedTimeResyncThreshold = 0.15f;
/// <summary>
/// Specifies who can update this animator
/// </summary>
[Tooltip("Defines who can update this animator.")]
public Authority AnimatorAuthority = Authority.Owner;
[SerializeField]
private float m_SendRate = 0.1f;
private double m_NextSendTime = 0.0f;
private bool m_ServerRequestsAnimationResync = false;
[SerializeField]
private Animator m_Animator;
private AnimatorSnapshot m_AnimatorSnapshot;
private List<(int, AnimatorControllerParameterType)> m_CachedAnimatorParameters;
public bool IsAuthorityOverAnimator => (IsClient && AnimatorAuthority == Authority.Owner && IsOwner) || (IsServer && AnimatorAuthority == Authority.Server);
public override void OnNetworkSpawn()
{
var parameters = m_Animator.parameters;
m_CachedAnimatorParameters = new List<(int, AnimatorControllerParameterType)>(parameters.Length);
int intCount = 0;
int floatCount = 0;
int boolCount = 0;
for (var i = 0; i < parameters.Length; i++)
{
var parameter = parameters[i];
if (m_Animator.IsParameterControlledByCurve(parameter.nameHash))
{
//we are ignoring parameters that are controlled by animation curves - syncing the layer states indirectly syncs the values that are driven by the animation curves
continue;
}
m_CachedAnimatorParameters.Add((parameter.nameHash, parameter.type));
switch (parameter.type)
{
case AnimatorControllerParameterType.Float:
++floatCount;
break;
case AnimatorControllerParameterType.Int:
++intCount;
break;
case AnimatorControllerParameterType.Bool:
++boolCount;
break;
}
}
var intParameters = new Dictionary<int, int>(intCount);
var floatParameters = new Dictionary<int, float>(floatCount);
var boolParameters = new Dictionary<int, bool>(boolCount);
var triggerParameters = new HashSet<int>();
var states = new LayerState[m_Animator.layerCount];
m_AnimatorSnapshot = new AnimatorSnapshot(boolParameters, floatParameters, intParameters, triggerParameters, states);
if (!IsAuthorityOverAnimator)
{
m_Animator.StopPlayback();
}
}
private void OnEnable()
{
if (IsServer)
{
NetworkManager.OnClientConnectedCallback += ServerOnClientConnectedCallback;
}
}
private void OnDisable()
{
if (IsServer)
{
NetworkManager.OnClientConnectedCallback -= ServerOnClientConnectedCallback;
}
}
private void ServerOnClientConnectedCallback(ulong clientId)
{
if (IsAuthorityOverAnimator)
{
m_ServerRequestsAnimationResync = true;
}
var clientRpcParams = new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = NetworkManager.ConnectedClientsList
.Where(c => c.ClientId != NetworkManager.ServerClientId)
.Select(c => c.ClientId)
.ToArray()
}
};
RequestResyncClientRpc(clientRpcParams);
}
[ClientRpc]
private void RequestResyncClientRpc(ClientRpcParams clientRpcParams = default)
{
if (!IsAuthorityOverAnimator)
{
return;
}
m_ServerRequestsAnimationResync = true;
}
private void FixedUpdate()
{
if (!NetworkObject.IsSpawned)
{
return;
}
if (IsAuthorityOverAnimator)
{
bool shouldSendBasedOnTime = CheckSendRate();
bool shouldSendBasedOnChanges = StoreState();
if (m_ServerRequestsAnimationResync || shouldSendBasedOnTime || shouldSendBasedOnChanges)
{
SendAllParamsAndState();
m_AnimatorSnapshot.TriggerParameters.Clear();
m_ServerRequestsAnimationResync = false;
}
}
}
private bool CheckSendRate()
{
var networkTime = NetworkManager.LocalTime.FixedTime;
if (m_SendRate != 0 && m_NextSendTime < networkTime)
{
m_NextSendTime = networkTime + m_SendRate;
return true;
}
return false;
}
private bool StoreState()
{
bool layerStateChanged = StoreLayerState();
bool animatorParametersChanged = StoreParameters();
return layerStateChanged || animatorParametersChanged;
}
private bool StoreLayerState()
{
bool changed = false;
for (int i = 0; i < m_AnimatorSnapshot.LayerStates.Length; i++)
{
var animStateInfo = m_Animator.GetCurrentAnimatorStateInfo(i);
var snapshotAnimStateInfo = m_AnimatorSnapshot.LayerStates[i];
bool didStateChange = snapshotAnimStateInfo.StateHash != animStateInfo.fullPathHash;
bool enoughDelta = !didStateChange &&
Mathf.Abs(animStateInfo.normalizedTime - snapshotAnimStateInfo.NormalizedStateTime) >= k_NormalizedTimeResyncThreshold;
float newLayerWeight = m_Animator.GetLayerWeight(i);
bool layerWeightChanged = Mathf.Abs(snapshotAnimStateInfo.LayerWeight - newLayerWeight) > Mathf.Epsilon;
if (didStateChange || enoughDelta || layerWeightChanged || m_ServerRequestsAnimationResync)
{
m_AnimatorSnapshot.LayerStates[i] = new LayerState
{
StateHash = animStateInfo.fullPathHash,
NormalizedStateTime = animStateInfo.normalizedTime,
LayerWeight = newLayerWeight
};
changed = true;
}
}
return changed;
}
private bool StoreParameters()
{
bool changed = false;
foreach (var animParam in m_CachedAnimatorParameters)
{
var animParamHash = animParam.Item1;
var animParamType = animParam.Item2;
switch (animParamType)
{
case AnimatorControllerParameterType.Float:
changed = changed || m_AnimatorSnapshot.SetFloat(animParamHash, m_Animator.GetFloat(animParamHash));
break;
case AnimatorControllerParameterType.Int:
changed = changed || m_AnimatorSnapshot.SetInt(animParamHash, m_Animator.GetInteger(animParamHash));
break;
case AnimatorControllerParameterType.Bool:
changed = changed || m_AnimatorSnapshot.SetBool(animParamHash, m_Animator.GetBool(animParamHash));
break;
case AnimatorControllerParameterType.Trigger:
if (m_Animator.GetBool(animParamHash))
{
changed = changed || m_AnimatorSnapshot.SetTrigger(animParamHash);
}
break;
}
}
return changed;
}
private void SendAllParamsAndState()
{
if (IsServer)
{
var clientRpcParams = new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = NetworkManager.ConnectedClientsList
.Where(c => c.ClientId != NetworkManager.ServerClientId)
.Select(c => c.ClientId)
.ToArray()
}
};
SendParamsAndLayerStatesClientRpc(m_AnimatorSnapshot, clientRpcParams);
}
else
{
SendParamsAndLayerStatesServerRpc(m_AnimatorSnapshot);
}
}
[ServerRpc]
private void SendParamsAndLayerStatesServerRpc(AnimatorSnapshot animSnapshot, ServerRpcParams serverRpcParams = default)
{
if (!IsAuthorityOverAnimator)
{
ApplyAnimatorSnapshot(animSnapshot);
}
var clientRpcParams = new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = NetworkManager.ConnectedClientsList
.Where(c => c.ClientId != serverRpcParams.Receive.SenderClientId)
.Select(c => c.ClientId)
.ToArray()
}
};
SendParamsAndLayerStatesClientRpc(animSnapshot, clientRpcParams);
}
[ClientRpc]
private void SendParamsAndLayerStatesClientRpc(AnimatorSnapshot animSnapshot, ClientRpcParams clientRpcParams = default)
{
if (!IsAuthorityOverAnimator)
{
ApplyAnimatorSnapshot(animSnapshot);
}
}
private void ApplyAnimatorSnapshot(AnimatorSnapshot animatorSnapshot)
{
foreach (var intParameter in animatorSnapshot.IntParameters)
{
m_Animator.SetInteger(intParameter.Key, intParameter.Value);
}
foreach (var floatParameter in animatorSnapshot.FloatParameters)
{
m_Animator.SetFloat(floatParameter.Key, floatParameter.Value);
}
foreach (var boolParameter in animatorSnapshot.BoolParameters)
{
m_Animator.SetBool(boolParameter.Key, boolParameter.Value);
}
foreach (var triggerParameter in animatorSnapshot.TriggerParameters)
{
m_Animator.SetTrigger(triggerParameter);
}
for (var layerIndex = 0; layerIndex < animatorSnapshot.LayerStates.Length; layerIndex++)
{
var layerState = animatorSnapshot.LayerStates[layerIndex];
m_Animator.SetLayerWeight(layerIndex, layerState.LayerWeight);
var currentAnimatorState = m_Animator.GetCurrentAnimatorStateInfo(layerIndex);
bool stateChanged = currentAnimatorState.fullPathHash != layerState.StateHash;
bool forceAnimationCatchup = !stateChanged &&
Mathf.Abs(layerState.NormalizedStateTime - currentAnimatorState.normalizedTime) >= k_NormalizedTimeResyncThreshold;
if (stateChanged || forceAnimationCatchup)
{
m_Animator.Play(layerState.StateHash, layerIndex, layerState.NormalizedStateTime);
}
}
}
}
}

11
Packages/com.unity.netcode.gameobjects/Prototyping/NetworkAnimator.cs.meta


fileFormatVersion: 2
guid: e8d0727d5ae3244e3b569694d3912374
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

119
Packages/com.unity.netcode.gameobjects/Prototyping/NetworkNavMeshAgent.cs


using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
namespace Unity.Netcode.Prototyping
{
/// <summary>
/// A prototype component for syncing NavMeshAgents
/// </summary>
[AddComponentMenu("Netcode/" + nameof(NetworkNavMeshAgent))]
[RequireComponent(typeof(NavMeshAgent))]
public class NetworkNavMeshAgent : NetworkBehaviour
{
private NavMeshAgent m_Agent;
/// <summary>
/// Is proximity enabled
/// </summary>
public bool EnableProximity = false;
/// <summary>
/// The proximity range
/// </summary>
public float ProximityRange = 50f;
/// <summary>
/// The delay in seconds between corrections
/// </summary>
public float CorrectionDelay = 3f;
//TODO rephrase.
/// <summary>
/// The percentage to lerp on corrections
/// </summary>
[Tooltip("Everytime a correction packet is received. This is the percentage (between 0 & 1) that we will move towards the goal.")]
public float DriftCorrectionPercentage = 0.1f;
/// <summary>
/// Should we warp on destination change
/// </summary>
public bool WarpOnDestinationChange = false;
private void Awake()
{
m_Agent = GetComponent<NavMeshAgent>();
}
private Vector3 m_LastDestination = Vector3.zero;
private double m_LastCorrectionTime = 0d;
private void Update()
{
if (!IsOwner)
{
return;
}
if (m_Agent.destination != m_LastDestination)
{
m_LastDestination = m_Agent.destination;
if (!EnableProximity)
{
OnNavMeshStateUpdateClientRpc(m_Agent.destination, m_Agent.velocity, transform.position);
}
else
{
var proximityClients = new List<ulong>();
foreach (KeyValuePair<ulong, NetworkClient> client in NetworkManager.ConnectedClients)
{
if (client.Value.PlayerObject == null || Vector3.Distance(client.Value.PlayerObject.transform.position, transform.position) <= ProximityRange)
{
proximityClients.Add(client.Key);
}
}
OnNavMeshStateUpdateClientRpc(m_Agent.destination, m_Agent.velocity, transform.position, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = proximityClients.ToArray() } });
}
}
if (NetworkManager.LocalTime.Time - m_LastCorrectionTime >= CorrectionDelay) // TODO this is not aliased correctly, is this an issue?
{
if (!EnableProximity)
{
OnNavMeshCorrectionUpdateClientRpc(m_Agent.velocity, transform.position);
}
else
{
var proximityClients = new List<ulong>();
foreach (KeyValuePair<ulong, NetworkClient> client in NetworkManager.ConnectedClients)
{
if (client.Value.PlayerObject == null || Vector3.Distance(client.Value.PlayerObject.transform.position, transform.position) <= ProximityRange)
{
proximityClients.Add(client.Key);
}
}
OnNavMeshCorrectionUpdateClientRpc(m_Agent.velocity, transform.position, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = proximityClients.ToArray() } });
}
m_LastCorrectionTime = NetworkManager.LocalTime.Time;
}
}
[ClientRpc]
private void OnNavMeshStateUpdateClientRpc(Vector3 destination, Vector3 velocity, Vector3 position, ClientRpcParams rpcParams = default)
{
m_Agent.Warp(WarpOnDestinationChange ? position : Vector3.Lerp(transform.position, position, DriftCorrectionPercentage));
m_Agent.SetDestination(destination);
m_Agent.velocity = velocity;
}
[ClientRpc]
private void OnNavMeshCorrectionUpdateClientRpc(Vector3 velocity, Vector3 position, ClientRpcParams rpcParams = default)
{
m_Agent.Warp(Vector3.Lerp(transform.position, position, DriftCorrectionPercentage));
m_Agent.velocity = velocity;
}
}
}

11
Packages/com.unity.netcode.gameobjects/Prototyping/NetworkNavMeshAgent.cs.meta


fileFormatVersion: 2
guid: 43b86c65774f4494ba4e5878d5df9bcd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

407
Packages/com.unity.netcode.gameobjects/Prototyping/NetworkTransform.cs


using System;
using UnityEngine;
namespace Unity.Netcode.Prototyping
{
/// <summary>
/// A prototype component for syncing transforms
/// </summary>
[AddComponentMenu("Netcode/" + nameof(NetworkTransform))]
public class NetworkTransform : NetworkBehaviour
{
internal struct NetworkState : INetworkSerializable
{
internal const int InLocalSpaceBit = 0;
internal const int PositionXBit = 1;
internal const int PositionYBit = 2;
internal const int PositionZBit = 3;
internal const int RotAngleXBit = 4;
internal const int RotAngleYBit = 5;
internal const int RotAngleZBit = 6;
internal const int ScaleXBit = 7;
internal const int ScaleYBit = 8;
internal const int ScaleZBit = 9;
// 10-15: <unused>
public ushort Bitset;
public bool InLocalSpace
{
get => (Bitset & (1 << InLocalSpaceBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << InLocalSpaceBit);
}
// Position
public bool HasPositionX
{
get => (Bitset & (1 << PositionXBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << PositionXBit);
}
public bool HasPositionY
{
get => (Bitset & (1 << PositionYBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << PositionYBit);
}
public bool HasPositionZ
{
get => (Bitset & (1 << PositionZBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << PositionZBit);
}
// RotAngles
public bool HasRotAngleX
{
get => (Bitset & (1 << RotAngleXBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << RotAngleXBit);
}
public bool HasRotAngleY
{
get => (Bitset & (1 << RotAngleYBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << RotAngleYBit);
}
public bool HasRotAngleZ
{
get => (Bitset & (1 << RotAngleZBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << RotAngleZBit);
}
// Scale
public bool HasScaleX
{
get => (Bitset & (1 << ScaleXBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << ScaleXBit);
}
public bool HasScaleY
{
get => (Bitset & (1 << ScaleYBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << ScaleYBit);
}
public bool HasScaleZ
{
get => (Bitset & (1 << ScaleZBit)) != 0;
set => Bitset |= (ushort)((value ? 1 : 0) << ScaleZBit);
}
public float PositionX, PositionY, PositionZ;
public float RotAngleX, RotAngleY, RotAngleZ;
public float ScaleX, ScaleY, ScaleZ;
public void NetworkSerialize(NetworkSerializer serializer)
{
// InLocalSpace + HasXXX Bits
serializer.Serialize(ref Bitset);
// Position Values
if (HasPositionX)
{
serializer.Serialize(ref PositionX);
}
if (HasPositionY)
{
serializer.Serialize(ref PositionY);
}
if (HasPositionZ)
{
serializer.Serialize(ref PositionZ);
}
// RotAngle Values
if (HasRotAngleX)
{
serializer.Serialize(ref RotAngleX);
}
if (HasRotAngleY)
{
serializer.Serialize(ref RotAngleY);
}
if (HasRotAngleZ)
{
serializer.Serialize(ref RotAngleZ);
}
// Scale Values
if (HasScaleX)
{
serializer.Serialize(ref ScaleX);
}
if (HasScaleY)
{
serializer.Serialize(ref ScaleY);
}
if (HasScaleZ)
{
serializer.Serialize(ref ScaleZ);
}
}
}
public bool SyncPositionX = true, SyncPositionY = true, SyncPositionZ = true;
public bool SyncRotAngleX = true, SyncRotAngleY = true, SyncRotAngleZ = true;
public bool SyncScaleX = true, SyncScaleY = true, SyncScaleZ = true;
public float PositionThreshold, RotAngleThreshold, ScaleThreshold;
/// <summary>
/// Sets whether this transform should sync in local space or in world space.
/// This is important to set since reparenting this transform could have issues,
/// if using world position (depending on who gets synced first: the parent or the child)
/// Having a child always at position 0,0,0 for example will have less possibilities of desync than when using world positions
/// </summary>
[Tooltip("Sets whether this transform should sync in local space or in world space")]
public bool InLocalSpace = false;
// todo: revisit after MTT-876
public bool Interpolate = true;
/// <summary>
/// The base amount of sends per seconds to use when range is disabled
/// </summary>
[SerializeField, Range(0, 120), Tooltip("The base amount of sends per seconds to use when range is disabled")]
public float FixedSendsPerSecond = 30f;
private Transform m_Transform; // cache the transform component to reduce unnecessary bounce between managed and native
internal NetworkState LocalNetworkState;
internal readonly NetworkVariable<NetworkState> ReplNetworkState = new NetworkVariable<NetworkState>(new NetworkState());
internal NetworkState PrevNetworkState;
// updates `NetworkState` properties if they need to and returns a `bool` indicating whether or not there was any changes made
// returned boolean would be useful to change encapsulating `NetworkVariable<NetworkState>`'s dirty state, e.g. ReplNetworkState.SetDirty(isDirty);
internal bool UpdateNetworkState(ref NetworkState networkState)
{
var position = InLocalSpace ? m_Transform.localPosition : m_Transform.position;
var rotAngles = InLocalSpace ? m_Transform.localEulerAngles : m_Transform.eulerAngles;
var scale = InLocalSpace ? m_Transform.localScale : m_Transform.lossyScale;
bool isDirty = false;
if (InLocalSpace != networkState.InLocalSpace)
{
networkState.InLocalSpace = InLocalSpace;
isDirty |= true;
}
if (SyncPositionX &&
Mathf.Abs(networkState.PositionX - position.x) >= PositionThreshold &&
!Mathf.Approximately(networkState.PositionX, position.x))
{
networkState.PositionX = position.x;
networkState.HasPositionX = true;
isDirty |= true;
}
if (SyncPositionY &&
Mathf.Abs(networkState.PositionY - position.y) >= PositionThreshold &&
!Mathf.Approximately(networkState.PositionY, position.y))
{
networkState.PositionY = position.y;
networkState.HasPositionY = true;
isDirty |= true;
}
if (SyncPositionZ &&
Mathf.Abs(networkState.PositionZ - position.z) >= PositionThreshold &&
!Mathf.Approximately(networkState.PositionZ, position.z))
{
networkState.PositionZ = position.z;
networkState.HasPositionZ = true;
isDirty |= true;
}
if (SyncRotAngleX &&
Mathf.Abs(networkState.RotAngleX - rotAngles.x) >= RotAngleThreshold &&
!Mathf.Approximately(networkState.RotAngleX, rotAngles.x))
{
networkState.RotAngleX = rotAngles.x;
networkState.HasRotAngleX = true;
isDirty |= true;
}
if (SyncRotAngleY &&
Mathf.Abs(networkState.RotAngleY - rotAngles.y) >= RotAngleThreshold &&
!Mathf.Approximately(networkState.RotAngleY, rotAngles.y))
{
networkState.RotAngleY = rotAngles.y;
networkState.HasRotAngleY = true;
isDirty |= true;
}
if (SyncRotAngleZ &&
Mathf.Abs(networkState.RotAngleZ - rotAngles.z) >= RotAngleThreshold &&
!Mathf.Approximately(networkState.RotAngleZ, rotAngles.z))
{
networkState.RotAngleZ = rotAngles.z;
networkState.HasRotAngleZ = true;
isDirty |= true;
}
if (SyncScaleX &&
Mathf.Abs(networkState.ScaleX - scale.x) >= ScaleThreshold &&
!Mathf.Approximately(networkState.ScaleX, scale.x))
{
networkState.ScaleX = scale.x;
networkState.HasScaleX = true;
isDirty |= true;
}
if (SyncScaleY &&
Mathf.Abs(networkState.ScaleY - scale.y) >= ScaleThreshold &&
!Mathf.Approximately(networkState.ScaleY, scale.y))
{
networkState.ScaleY = scale.y;
networkState.HasScaleY = true;
isDirty |= true;
}
if (SyncScaleZ &&
Mathf.Abs(networkState.ScaleZ - scale.z) >= ScaleThreshold &&
!Mathf.Approximately(networkState.ScaleZ, scale.z))
{
networkState.ScaleZ = scale.z;
networkState.HasScaleZ = true;
isDirty |= true;
}
return isDirty;
}
// TODO: temporary! the function body below probably needs to be rewritten later with interpolation in mind
internal void ApplyNetworkState(NetworkState networkState)
{
PrevNetworkState = networkState;
var position = InLocalSpace ? m_Transform.localPosition : m_Transform.position;
var rotAngles = InLocalSpace ? m_Transform.localEulerAngles : m_Transform.eulerAngles;
var scale = InLocalSpace ? m_Transform.localScale : m_Transform.lossyScale;
// InLocalSpace Read
InLocalSpace = networkState.InLocalSpace;
// Position Read
if (networkState.HasPositionX)
{
position.x = networkState.PositionX;
}
if (networkState.HasPositionY)
{
position.y = networkState.PositionY;
}
if (networkState.HasPositionZ)
{
position.z = networkState.PositionZ;
}
// RotAngles Read
if (networkState.HasRotAngleX)
{
rotAngles.x = networkState.RotAngleX;
}
if (networkState.HasRotAngleY)
{
rotAngles.y = networkState.RotAngleY;
}
if (networkState.HasRotAngleZ)
{
rotAngles.z = networkState.RotAngleZ;
}
// Scale Read
if (networkState.HasScaleX)
{
scale.x = networkState.ScaleX;
}
if (networkState.HasScaleY)
{
scale.y = networkState.ScaleY;
}
if (networkState.HasScaleZ)
{
scale.z = networkState.ScaleZ;
}
// Position Apply
if (networkState.HasPositionX || networkState.HasPositionY || networkState.HasPositionZ)
{
if (InLocalSpace)
{
m_Transform.localPosition = position;
}
else
{
m_Transform.position = position;
}
}
// RotAngles Apply
if (networkState.HasRotAngleX || networkState.HasRotAngleY || networkState.HasRotAngleZ)
{
if (InLocalSpace)
{
m_Transform.localEulerAngles = rotAngles;
}
else
{
m_Transform.eulerAngles = rotAngles;
}
}
// Scale Apply
if (networkState.HasScaleX || networkState.HasScaleY || networkState.HasScaleZ)
{
if (InLocalSpace)
{
m_Transform.localScale = scale;
}
else
{
m_Transform.localScale = Vector3.one;
var lossyScale = m_Transform.lossyScale;
m_Transform.localScale = new Vector3(networkState.ScaleX / lossyScale.x, networkState.ScaleY / lossyScale.y, networkState.ScaleZ / lossyScale.z);
}
}
}
private void OnNetworkStateChanged(NetworkState oldState, NetworkState newState)
{
if (!NetworkObject.IsSpawned)
{
// todo MTT-849 should never happen but yet it does! maybe revisit/dig after NetVar updates and snapshot system lands?
return;
}
ApplyNetworkState(newState);
}
private void Awake()
{
m_Transform = transform;
ReplNetworkState.OnValueChanged += OnNetworkStateChanged;
}
private void OnDestroy()
{
ReplNetworkState.OnValueChanged -= OnNetworkStateChanged;
}
private void FixedUpdate()
{
if (!NetworkObject.IsSpawned)
{
return;
}
if (IsServer)
{
// try to update local NetworkState
if (UpdateNetworkState(ref LocalNetworkState))
{
// if updated (dirty), change NetVar, mark it dirty
ReplNetworkState.Value = LocalNetworkState;
ReplNetworkState.SetDirty(true);
}
}
// try to update previously consumed NetworkState
// if we have any changes, that means made some updates locally
// we apply the latest ReplNetworkState again to revert our changes
else if (UpdateNetworkState(ref PrevNetworkState))
{
ApplyNetworkState(ReplNetworkState.Value);
}
}
/// <summary>
/// Teleports the transform to the given values without interpolating
/// </summary>
public void Teleport(Vector3 newPosition, Quaternion newRotation, Vector3 newScale)
{
throw new NotImplementedException(); // TODO MTT-769
}
}
}

11
Packages/com.unity.netcode.gameobjects/Prototyping/NetworkTransform.cs.meta


fileFormatVersion: 2
guid: e96cb6065543e43c4a752faaa1468eb1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

7
Packages/com.unity.netcode.gameobjects/Prototyping/com.unity.netcode.prototyping.asmdef


{
"name": "Unity.Netcode.Prototyping",
"rootNamespace": "Unity.Netcode.Prototyping",
"references": [
"Unity.Netcode.Runtime"
]
}

7
Packages/com.unity.netcode.gameobjects/Prototyping/com.unity.netcode.prototyping.asmdef.meta


fileFormatVersion: 2
guid: 3b8ed52f1b5c64994af4c4e0aa4b6c4b
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

84
Packages/com.unity.netcode.gameobjects/README.md


[![](https://i.imgur.com/d0amtqs.png)](https://mlapi.network/)
[![GitHub Release](https://img.shields.io/github/release/MidLevel/MLAPI.svg?logo=github)](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/releases/latest)
[![Github All Releases](https://img.shields.io/github/downloads/MidLevel/MLAPI/total.svg?logo=github&color=informational)](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/releases)
[![Forums](https://img.shields.io/badge/unity--forums-multiplayer-blue)](https://forum.unity.com/forums/multiplayer.26/)
[![Discord](https://img.shields.io/discord/449263083769036810.svg?label=discord&logo=discord&color=informational)](https://discord.gg/FM8SE9E)
[![Licence](https://img.shields.io/github/license/midlevel/mlapi.svg?color=informational)](https://github.com/MidLevel/MLAPI/blob/master/LICENSE)
[![Website](https://img.shields.io/badge/docs-website-informational.svg)](https://docs-multiplayer.unity3d.com/)
[![Api](https://img.shields.io/badge/docs-api-informational.svg)](https://docs-multiplayer.unity3d.com/docs/mlapi-api/introduction)
The Unity MLAPI (Mid level API) is a framework that simplifies building networked games in Unity. It offers **low level** access to core networking while at the same time providing **high level** abstractions. The MLAPI aims to remove the repetitive tasks and reduces the network code dramatically, no matter how many of the **modular** features you use.
### Getting Started
To get started, check the [Multiplayer Docs Site](https://docs-multiplayer.unity3d.com/).
### Community and Feedback
For general questions, networking advice or discussions about MLAPI, please join our [Discord Community](https://discord.gg/FM8SE9E) or create a post in the [Unity Multiplayer Forum](https://forum.unity.com/forums/multiplayer.26/).
### Compatibility
The MLAPI supports all major Unity platforms. To use the WebGL platform a custom WebGL transport based on web sockets is needed.
MLAPI is compatible with Unity 2019 and newer versions.
### Development
We follow the [Gitflow Workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow). The master branch contains our latest stable release version while the develop branch tracks our current work.
This repository is broken into multiple components, each one implemented as a Unity Package.
```
.
├── com.unity.multiplayer.mlapi # The core netcode SDK unity package (source + tests)
├── com.unity.multiplayer.transport.utp # Transport wrapper for com.unity.transport experimental package (not currently supported)
└── testproject # A Unity project with various test implementations & scenes which exercise the features in the above package(s).
```
### Contributing
The MLAPI is an open-source project and we encourage and welcome
contributions. If you wish to contribute, be sure to review our
[contribution guidelines](CONTRIBUTING.md)
### Issues and missing features
If you have an issue, bug or feature request, please follow the information in our [contribution guidelines](CONTRIBUTING.md) to submit an issue.
### Example
Here is a sample MonoBehaviour showing a chat script where everyone can write and read from. This shows the basis of the MLAPI and the abstractions it adds.
```csharp
public class Chat : NetworkBehaviour
{
private NetworkList<string> ChatMessages = new NetworkList<string>(new MLAPI.NetworkVariable.NetworkVariableSettings()
{
ReadPermission = MLAPI.NetworkVariable.NetworkVariablePermission.Everyone,
WritePermission = MLAPI.NetworkVariable.NetworkVariablePermission.Everyone,
SendTickrate = 5
}, new List<string>());
private string textField = "";
private void OnGUI()
{
if (IsClient)
{
textField = GUILayout.TextField(textField, GUILayout.Width(200));
if (GUILayout.Button("Send") && !string.IsNullOrWhiteSpace(textField))
{
ChatMessages.Add(textField);
textField = "";
}
for (int i = ChatMessages.Count - 1; i >= 0; i--)
{
GUILayout.Label(ChatMessages[i]);
}
}
}
}
```
### License
[MIT License](LICENSE)

7
Packages/com.unity.netcode.gameobjects/README.md.meta


fileFormatVersion: 2
guid: 7a8193086d1cd7d4dadc6a324430350b
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.netcode.gameobjects/Runtime.meta


fileFormatVersion: 2
guid: c83905999e4e71246b5a3ebf2565faf7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

10
Packages/com.unity.netcode.gameobjects/Runtime/AssemblyInfo.cs


using System.Runtime.CompilerServices;
#if UNITY_EDITOR
[assembly: InternalsVisibleTo("Unity.Netcode.EditorTests")]
[assembly: InternalsVisibleTo("Unity.Netcode.Editor.CodeGen")]
[assembly: InternalsVisibleTo("Unity.Netcode.Editor")]
[assembly: InternalsVisibleTo("TestProject.EditorTests")]
[assembly: InternalsVisibleTo("TestProject.RuntimeTests")]
#endif
[assembly: InternalsVisibleTo("Unity.Netcode.RuntimeTests")]

11
Packages/com.unity.netcode.gameobjects/Runtime/AssemblyInfo.cs.meta


fileFormatVersion: 2
guid: c9fd74adf4a0f6e479be3978543dc6a0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.netcode.gameobjects/Runtime/Collections.meta


fileFormatVersion: 2
guid: f2ef964afcae91248b2298b479ed1b53
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

77
Packages/com.unity.netcode.gameobjects/Runtime/Collections/FixedQueue.cs


using System;
namespace Unity.Netcode
{
/// <summary>
/// Queue with a fixed size
/// </summary>
/// <typeparam name="T">The type of the queue</typeparam>
public sealed class FixedQueue<T>
{
private readonly T[] m_Queue;
private int m_QueueCount = 0;
private int m_QueueStart;
/// <summary>
/// The amount of enqueued objects
/// </summary>
public int Count => m_QueueCount;
/// <summary>
/// Gets the element at a given virtual index
/// </summary>
/// <param name="index">The virtual index to get the item from</param>
/// <returns>The element at the virtual index</returns>
public T this[int index] => m_Queue[(m_QueueStart + index) % m_Queue.Length];
/// <summary>
/// Creates a new FixedQueue with a given size
/// </summary>
/// <param name="maxSize">The size of the queue</param>
public FixedQueue(int maxSize)
{
m_Queue = new T[maxSize];
m_QueueStart = 0;
}
/// <summary>
/// Enqueues an object
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public bool Enqueue(T t)
{
m_Queue[(m_QueueStart + m_QueueCount) % m_Queue.Length] = t;
if (++m_QueueCount > m_Queue.Length)
{
--m_QueueCount;
return true;
}
return false;
}
/// <summary>
/// Dequeues an object
/// </summary>
/// <returns></returns>
public T Dequeue()
{
if (--m_QueueCount == -1)
{
throw new IndexOutOfRangeException("Cannot dequeue empty queue!");
}
T res = m_Queue[m_QueueStart];
m_QueueStart = (m_QueueStart + 1) % m_Queue.Length;
return res;
}
/// <summary>
/// Gets the element at a given virtual index
/// </summary>
/// <param name="index">The virtual index to get the item from</param>
/// <returns>The element at the virtual index</returns>
public T ElementAt(int index) => m_Queue[(m_QueueStart + index) % m_Queue.Length];
}
}

11
Packages/com.unity.netcode.gameobjects/Runtime/Collections/FixedQueue.cs.meta


fileFormatVersion: 2
guid: a8514b4eca0c7044d9b92faf9407ec93
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Packages/com.unity.netcode.gameobjects/Runtime/Configuration.meta


fileFormatVersion: 2
guid: d3cc7700dfd03ee4397858710461d179
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存