From dc6afc13313ee43e33988953b8481c9d88572afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albin=20Cor=C3=A9n?= <2108U9@gmail.com> Date: Wed, 7 Mar 2018 20:56:24 +0100 Subject: [PATCH 1/5] Added Reflection based SyncVar system --- MLAPI/Attributes/FieldType.cs | 19 ++ MLAPI/Attributes/SyncedVar.cs | 10 + MLAPI/MLAPI.csproj | 5 +- .../MonoBehaviours/Core/NetworkedBehaviour.cs | 296 ++++++++++++++++++ MLAPI/MonoBehaviours/Core/NetworkedObject.cs | 28 ++ .../MonoBehaviours/Core/NetworkingManager.cs | 72 ++++- .../SyncedVarManager.cs | 35 +++ 7 files changed, 463 insertions(+), 2 deletions(-) create mode 100644 MLAPI/Attributes/FieldType.cs create mode 100644 MLAPI/Attributes/SyncedVar.cs create mode 100644 MLAPI/NetworkingManagerComponents/SyncedVarManager.cs diff --git a/MLAPI/Attributes/FieldType.cs b/MLAPI/Attributes/FieldType.cs new file mode 100644 index 0000000..916c77f --- /dev/null +++ b/MLAPI/Attributes/FieldType.cs @@ -0,0 +1,19 @@ +namespace MLAPI.Attributes +{ + internal enum FieldType + { + Bool, + Byte, + Char, + Double, + Single, + Int, + Long, + SByte, + Short, + UInt, + ULong, + UShort, + String + } +} diff --git a/MLAPI/Attributes/SyncedVar.cs b/MLAPI/Attributes/SyncedVar.cs new file mode 100644 index 0000000..f01705c --- /dev/null +++ b/MLAPI/Attributes/SyncedVar.cs @@ -0,0 +1,10 @@ +using System; + +namespace MLAPI.Attributes +{ + [AttributeUsage(AttributeTargets.Field)] + public class SyncedVar : Attribute + { + + } +} diff --git a/MLAPI/MLAPI.csproj b/MLAPI/MLAPI.csproj index 63b2af0..948bd46 100644 --- a/MLAPI/MLAPI.csproj +++ b/MLAPI/MLAPI.csproj @@ -41,7 +41,7 @@ AnyCPU prompt MinimumRecommendedRules.ruleset - Off + Auto @@ -56,6 +56,8 @@ + + @@ -71,6 +73,7 @@ + diff --git a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs index 8c1f608..64f342e 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs @@ -2,11 +2,16 @@ using System.Collections.Generic; using UnityEngine; using MLAPI.NetworkingManagerComponents; +using System.Reflection; +using MLAPI.Attributes; +using System.Linq; +using System.IO; namespace MLAPI { public abstract class NetworkedBehaviour : MonoBehaviour { + public float SyncVarSyncDelay = 0.1f; public bool isLocalPlayer { get @@ -79,6 +84,7 @@ namespace MLAPI { _networkedObject = GetComponentInParent(); } + NetworkedObject.networkedBehaviours.Add(this); } internal bool networkedStartInvoked = false; @@ -109,6 +115,11 @@ namespace MLAPI MessageManager.RemoveIncomingMessageHandler(name, counter, networkId); } + private void OnDisable() + { + NetworkedObject.networkedBehaviours.Remove(this); + } + private void OnDestroy() { foreach (KeyValuePair pair in registeredMessageHandlers) @@ -117,6 +128,291 @@ namespace MLAPI } } + #region SYNC_VAR + private List syncedFields = new List(); + internal List syncedFieldTypes = new List(); + private List syncedFieldValues = new List(); + //A dirty field is a field that's not synced. + public bool[] dirtyFields; + protected static ushort networkedBehaviourId; + //This is just for the unity editor. if you turn the editor to DEBUG mode you can see what the networkedBehaviourId is. + private ushort _networkedBehaviourId = networkedBehaviourId; + internal void SyncVarInit() + { + FieldInfo[] sortedFields = GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance).OrderBy(x => x.Name).ToArray(); + for (byte i = 0; i < sortedFields.Length; i++) + { + if(sortedFields[i].IsDefined(typeof(SyncedVar), true)) + { + if (sortedFields[i].FieldType == typeof(bool)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Bool); + } + else if(sortedFields[i].FieldType == typeof(byte)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Byte); + } + else if (sortedFields[i].FieldType == typeof(char)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Char); + } + else if (sortedFields[i].FieldType == typeof(double)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Double); + } + else if (sortedFields[i].FieldType == typeof(float)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Single); + } + else if (sortedFields[i].FieldType == typeof(int)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Int); + } + else if (sortedFields[i].FieldType == typeof(long)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Long); + } + else if (sortedFields[i].FieldType == typeof(sbyte)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.SByte); + } + else if (sortedFields[i].FieldType == typeof(short)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Short); + } + else if (sortedFields[i].FieldType == typeof(uint)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.UInt); + } + else if (sortedFields[i].FieldType == typeof(ulong)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.ULong); + } + else if (sortedFields[i].FieldType == typeof(ushort)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.UShort); + } + else if(sortedFields[i].FieldType == typeof(string)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.String); + } + else + { + Debug.LogError("MLAPI: The type " + sortedFields[i].FieldType.ToString() + " can not be used as a syncvar"); + } + } + } + if(dirtyFields.Length > 255) + { + Debug.LogError("MLAPI: You can not have more than 255 SyncVar's per NetworkedBehaviour!"); + } + dirtyFields = new bool[syncedFields.Count]; + } + + internal void OnSyncVarUpdate(object value, byte fieldIndex) + { + if (isServer) + return; + syncedFields[fieldIndex].SetValue(this, value); + } + + private float lastSyncTime = 0f; + internal void SyncvarUpdate() + { + if (!isServer) + return; + SetDirtyness(); + if(Time.time - lastSyncTime >= SyncVarSyncDelay) + { + byte dirtyCount = (byte)dirtyFields.Count(x => x == true); + if (dirtyCount == 0) + return; //All up to date! + //It's sync time! + using (MemoryStream stream = new MemoryStream()) + { + using(BinaryWriter writer = new BinaryWriter(stream)) + { + //Write all indexes + writer.Write(dirtyCount); + for (byte i = 0; i < dirtyFields.Length; i++) + { + //Writes all the indexes of the dirty syncvars. + if (dirtyFields[i] == true) + { + writer.Write(networkId); + writer.Write(networkedObject.GetOrderIndex(this)); + writer.Write(networkedBehaviourId); + writer.Write(i); //Index + switch (syncedFieldTypes[i]) + { + case FieldType.Bool: + writer.Write((bool)syncedFields[i].GetValue(this)); + break; + case FieldType.Byte: + writer.Write((byte)syncedFields[i].GetValue(this)); + break; + case FieldType.Char: + writer.Write((char)syncedFields[i].GetValue(this)); + break; + case FieldType.Double: + writer.Write((double)syncedFields[i].GetValue(this)); + break; + case FieldType.Single: + writer.Write((float)syncedFields[i].GetValue(this)); + break; + case FieldType.Int: + writer.Write((int)syncedFields[i].GetValue(this)); + break; + case FieldType.Long: + writer.Write((long)syncedFields[i].GetValue(this)); + break; + case FieldType.SByte: + writer.Write((sbyte)syncedFields[i].GetValue(this)); + break; + case FieldType.Short: + writer.Write((short)syncedFields[i].GetValue(this)); + break; + case FieldType.UInt: + writer.Write((uint)syncedFields[i].GetValue(this)); + break; + case FieldType.ULong: + writer.Write((ulong)syncedFields[i].GetValue(this)); + break; + case FieldType.UShort: + writer.Write((ushort)syncedFields[i].GetValue(this)); + break; + case FieldType.String: + writer.Write((string)syncedFields[i].GetValue(this)); + break; + } + syncedFieldValues[i] = syncedFields[i].GetValue(this); + dirtyFields[i] = false; + } + } + NetworkingManager.singleton.Send("MLAPI_SYNC_VAR_UPDATE", "MLAPI_RELIABLE_FRAGMENTED_SEQUENCED", stream.ToArray(), ownerClientId); + } + } + lastSyncTime = Time.time; + } + } + + private void SetDirtyness() + { + if (!isServer) + return; + for (int i = 0; i < syncedFields.Count; i++) + { + switch (syncedFieldTypes[i]) + { + case FieldType.Bool: + if ((bool)syncedFields[i].GetValue(this) != (bool)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.Byte: + if ((byte)syncedFields[i].GetValue(this) != (byte)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.Char: + if ((char)syncedFields[i].GetValue(this) != (char)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.Double: + if ((double)syncedFields[i].GetValue(this) != (double)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.Single: + if ((float)syncedFields[i].GetValue(this) != (float)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.Int: + if ((int)syncedFields[i].GetValue(this) != (int)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.Long: + if ((long)syncedFields[i].GetValue(this) != (long)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.SByte: + if ((sbyte)syncedFields[i].GetValue(this) != (sbyte)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.Short: + if ((short)syncedFields[i].GetValue(this) != (short)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.UInt: + if ((uint)syncedFields[i].GetValue(this) != (uint)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.ULong: + if ((ulong)syncedFields[i].GetValue(this) != (ulong)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.UShort: + if ((ushort)syncedFields[i].GetValue(this) != (ushort)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.String: + if ((string)syncedFields[i].GetValue(this) != (string)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + } + } + } + #endregion + protected void SendToServer(string messageType, string channelName, byte[] data) { if(MessageManager.messageTypes[messageType] < 32) diff --git a/MLAPI/MonoBehaviours/Core/NetworkedObject.cs b/MLAPI/MonoBehaviours/Core/NetworkedObject.cs index d7ba9ee..aaf4332 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedObject.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedObject.cs @@ -1,4 +1,5 @@ using MLAPI.NetworkingManagerComponents; +using System.Collections.Generic; using UnityEngine; namespace MLAPI @@ -96,8 +97,35 @@ namespace MLAPI if(netBehaviours[i].networkedObject == this && !netBehaviours[i].networkedStartInvoked) { netBehaviours[i].NetworkStart(); + netBehaviours[i].SyncVarInit(); } } } + + internal static List networkedBehaviours = new List(); + internal static void InvokeSyncvarUpdate() + { + for (int i = 0; i < networkedBehaviours.Count; i++) + { + networkedBehaviours[i].SyncvarUpdate(); + } + } + + internal ushort GetOrderIndex(NetworkedBehaviour instance) + { + NetworkedBehaviour[] behaviours = GetComponentsInChildren(); + for (ushort i = 0; i < behaviours.Length; i++) + { + if (behaviours[i].networkedObject == this && behaviours[i] == instance) + return i; + } + return 0; + } + + internal NetworkedBehaviour GetBehaviourAtOrderIndex(ushort index) + { + NetworkedBehaviour[] behaviours = GetComponentsInChildren(); + return behaviours[index]; + } } } diff --git a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs index 3e7dd18..8b98885 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs @@ -1,4 +1,5 @@ -using MLAPI.NetworkingManagerComponents; +using MLAPI.Attributes; +using MLAPI.NetworkingManagerComponents; using System; using System.Collections; using System.Collections.Generic; @@ -73,6 +74,7 @@ namespace MLAPI { NetworkConfig = netConfig; + SyncedVarManager.Init(); pendingClients = new HashSet(); connectedClients = new Dictionary(); messageBuffer = new byte[NetworkConfig.MessageBufferSize]; @@ -117,6 +119,7 @@ namespace MLAPI MessageManager.messageTypes.Add("MLAPI_SPAWN_POOL_OBJECT", 6); MessageManager.messageTypes.Add("MLAPI_DESTROY_POOL_OBJECT", 7); MessageManager.messageTypes.Add("MLAPI_CHANGE_OWNER", 8); + MessageManager.messageTypes.Add("MLAPI_SYNC_VAR_UPDATE", 9); NetworkConfig.MessageTypes.Add("MLAPI_OnRecieveTransformFromClient"); NetworkConfig.MessageTypes.Add("MLAPI_OnRecieveTransformFromServer"); NetworkConfig.MessageTypes.Add("MLAPI_HandleAnimationMessage"); @@ -361,6 +364,8 @@ namespace MLAPI } if (isServer) LagCompensationManager.AddFrames(); + + NetworkedObject.InvokeSyncvarUpdate(); } private IEnumerator ApprovalTimeout(int clientId) @@ -677,6 +682,71 @@ namespace MLAPI } } break; + case 9: + if (isClient) + { + using (MemoryStream messageReadStream = new MemoryStream(incommingData)) + { + using (BinaryReader messageReader = new BinaryReader(messageReadStream)) + { + byte dirtyCount = messageReader.ReadByte(); + if(dirtyCount > 0) + { + for (int i = 0; i < dirtyCount; i++) + { + uint netId = messageReader.ReadUInt32(); //NetId the syncvar is from + ushort orderIndex = messageReader.ReadUInt16(); + ushort networkBehaviourId = messageReader.ReadUInt16(); + byte fieldIndex = messageReader.ReadByte(); + FieldType type = SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).syncedFieldTypes[fieldIndex]; + switch (type) + { + case FieldType.Bool: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadBoolean(), fieldIndex); + break; + case FieldType.Byte: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadByte(), fieldIndex); + break; + case FieldType.Char: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadChar(), fieldIndex); + break; + case FieldType.Double: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadDouble(), fieldIndex); + break; + case FieldType.Single: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadSingle(), fieldIndex); + break; + case FieldType.Int: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadInt32(), fieldIndex); + break; + case FieldType.Long: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadInt64(), fieldIndex); + break; + case FieldType.SByte: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadSByte(), fieldIndex); + break; + case FieldType.Short: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadInt16(), fieldIndex); + break; + case FieldType.UInt: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadUInt32(), fieldIndex); + break; + case FieldType.ULong: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadUInt64(), fieldIndex); + break; + case FieldType.UShort: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadUInt16(), fieldIndex); + break; + case FieldType.String: + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadString(), fieldIndex); + break; + } + } + } + } + } + } + break; } } } diff --git a/MLAPI/NetworkingManagerComponents/SyncedVarManager.cs b/MLAPI/NetworkingManagerComponents/SyncedVarManager.cs new file mode 100644 index 0000000..a9dcf6d --- /dev/null +++ b/MLAPI/NetworkingManagerComponents/SyncedVarManager.cs @@ -0,0 +1,35 @@ +using MLAPI.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; + +namespace MLAPI.NetworkingManagerComponents +{ + internal static class SyncedVarManager + { + internal static void Init() + { + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + Assembly assembly = Assembly.GetExecutingAssembly(); + for (int i = 0; i < assemblies.Length; i++) + { + if (assemblies[i].FullName == "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null") + { + assembly = assemblies[i]; + break; + } + } + IEnumerable types = from t in assembly.GetTypes() + where t.IsClass && t.IsSubclassOf(typeof(NetworkedBehaviour)) + select t; + List behaviourTypes = types.OrderBy(x => x.FullName).ToList(); + for (ushort i = 0; i < behaviourTypes.Count; i++) + { + FieldInfo networkedBehaviourId = behaviourTypes[i].GetField("networkedBehaviourId", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); + networkedBehaviourId.SetValue(null, i); + } + } + } +} From c1e6e6cbf9357dba62708b3490898813b3fada84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albin=20Cor=C3=A9n?= <2108U9@gmail.com> Date: Wed, 7 Mar 2018 21:42:33 +0100 Subject: [PATCH 2/5] Cleaned up SyncVar system slightly --- MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs | 10 +++------- MLAPI/MonoBehaviours/Core/NetworkedObject.cs | 9 +++++---- MLAPI/MonoBehaviours/Core/NetworkingManager.cs | 5 +++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs index 64f342e..08c7ca5 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs @@ -84,7 +84,7 @@ namespace MLAPI { _networkedObject = GetComponentInParent(); } - NetworkedObject.networkedBehaviours.Add(this); + NetworkedObject.NetworkedBehaviours.Add(this); } internal bool networkedStartInvoked = false; @@ -117,7 +117,7 @@ namespace MLAPI private void OnDisable() { - NetworkedObject.networkedBehaviours.Remove(this); + NetworkedObject.NetworkedBehaviours.Remove(this); } private void OnDestroy() @@ -237,16 +237,12 @@ namespace MLAPI internal void OnSyncVarUpdate(object value, byte fieldIndex) { - if (isServer) - return; syncedFields[fieldIndex].SetValue(this, value); } private float lastSyncTime = 0f; - internal void SyncvarUpdate() + internal void SyncVarUpdate() { - if (!isServer) - return; SetDirtyness(); if(Time.time - lastSyncTime >= SyncVarSyncDelay) { diff --git a/MLAPI/MonoBehaviours/Core/NetworkedObject.cs b/MLAPI/MonoBehaviours/Core/NetworkedObject.cs index aaf4332..4d691aa 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedObject.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedObject.cs @@ -97,17 +97,18 @@ namespace MLAPI if(netBehaviours[i].networkedObject == this && !netBehaviours[i].networkedStartInvoked) { netBehaviours[i].NetworkStart(); - netBehaviours[i].SyncVarInit(); + if (NetworkingManager.singleton.isServer) + netBehaviours[i].SyncVarInit(); } } } - internal static List networkedBehaviours = new List(); + internal static List NetworkedBehaviours = new List(); internal static void InvokeSyncvarUpdate() { - for (int i = 0; i < networkedBehaviours.Count; i++) + for (int i = 0; i < NetworkedBehaviours.Count; i++) { - networkedBehaviours[i].SyncvarUpdate(); + NetworkedBehaviours[i].SyncVarUpdate(); } } diff --git a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs index 8b98885..facffc3 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs @@ -363,9 +363,10 @@ namespace MLAPI } if (isServer) + { LagCompensationManager.AddFrames(); - - NetworkedObject.InvokeSyncvarUpdate(); + NetworkedObject.InvokeSyncvarUpdate(); + } } private IEnumerator ApprovalTimeout(int clientId) From 7b9d2d14a7bb64eded4347f103204e3ce6abdee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albin=20Cor=C3=A9n?= <2108U9@gmail.com> Date: Wed, 7 Mar 2018 21:52:55 +0100 Subject: [PATCH 3/5] Added Sync to new players functionality to syncvars --- .../MonoBehaviours/Core/NetworkedBehaviour.cs | 66 +++++++++++++++++++ MLAPI/MonoBehaviours/Core/NetworkedObject.cs | 9 +++ .../MonoBehaviours/Core/NetworkingManager.cs | 5 ++ 3 files changed, 80 insertions(+) diff --git a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs index 08c7ca5..1201be6 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs @@ -240,6 +240,72 @@ namespace MLAPI syncedFields[fieldIndex].SetValue(this, value); } + internal void FlushToClient(int clientId) + { + //This NetworkedBehaviour has no SyncVars + if (dirtyFields.Length == 0) + return; + + using (MemoryStream stream = new MemoryStream()) + { + using (BinaryWriter writer = new BinaryWriter(stream)) + { + //Write all indexes + writer.Write(dirtyFields.Length); + for (byte i = 0; i < dirtyFields.Length; i++) + { + writer.Write(networkId); + writer.Write(networkedObject.GetOrderIndex(this)); + writer.Write(networkedBehaviourId); + writer.Write(i); //Index + switch (syncedFieldTypes[i]) + { + case FieldType.Bool: + writer.Write((bool)syncedFields[i].GetValue(this)); + break; + case FieldType.Byte: + writer.Write((byte)syncedFields[i].GetValue(this)); + break; + case FieldType.Char: + writer.Write((char)syncedFields[i].GetValue(this)); + break; + case FieldType.Double: + writer.Write((double)syncedFields[i].GetValue(this)); + break; + case FieldType.Single: + writer.Write((float)syncedFields[i].GetValue(this)); + break; + case FieldType.Int: + writer.Write((int)syncedFields[i].GetValue(this)); + break; + case FieldType.Long: + writer.Write((long)syncedFields[i].GetValue(this)); + break; + case FieldType.SByte: + writer.Write((sbyte)syncedFields[i].GetValue(this)); + break; + case FieldType.Short: + writer.Write((short)syncedFields[i].GetValue(this)); + break; + case FieldType.UInt: + writer.Write((uint)syncedFields[i].GetValue(this)); + break; + case FieldType.ULong: + writer.Write((ulong)syncedFields[i].GetValue(this)); + break; + case FieldType.UShort: + writer.Write((ushort)syncedFields[i].GetValue(this)); + break; + case FieldType.String: + writer.Write((string)syncedFields[i].GetValue(this)); + break; + } + } + NetworkingManager.singleton.Send(clientId, "MLAPI_SYNC_VAR_UPDATE", "MLAPI_RELIABLE_FRAGMENTED_SEQUENCED", stream.ToArray()); + } + } + } + private float lastSyncTime = 0f; internal void SyncVarUpdate() { diff --git a/MLAPI/MonoBehaviours/Core/NetworkedObject.cs b/MLAPI/MonoBehaviours/Core/NetworkedObject.cs index 4d691aa..4704b56 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedObject.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedObject.cs @@ -112,6 +112,15 @@ namespace MLAPI } } + //Flushes all syncVars to client + internal void FlushToClient(int clientId) + { + for (int i = 0; i < NetworkedBehaviours.Count; i++) + { + NetworkedBehaviours[i].FlushToClient(clientId); + } + } + internal ushort GetOrderIndex(NetworkedBehaviour instance) { NetworkedBehaviour[] behaviours = GetComponentsInChildren(); diff --git a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs index facffc3..42f441a 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs @@ -1136,6 +1136,11 @@ namespace MLAPI } Send("MLAPI_ADD_OBJECT", "MLAPI_RELIABLE_FRAGMENTED_SEQUENCED", stream.GetBuffer(), clientId); } + //Flush syncvars: + foreach (KeyValuePair networkedObject in SpawnManager.spawnedObjects) + { + networkedObject.Value.FlushToClient(clientId); + } } else { From 0d47c6980bc4a63b8749a95acd8816d9c7efcb9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albin=20Cor=C3=A9n?= <2108U9@gmail.com> Date: Wed, 7 Mar 2018 22:52:44 +0100 Subject: [PATCH 4/5] Added support for Vector3,Vector2 and Quaternion's in SyncVars --- MLAPI/Attributes/FieldType.cs | 5 +- .../MonoBehaviours/Core/NetworkedBehaviour.cs | 71 +++++++++++++++++++ .../MonoBehaviours/Core/NetworkingManager.cs | 23 ++++++ 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/MLAPI/Attributes/FieldType.cs b/MLAPI/Attributes/FieldType.cs index 916c77f..49621be 100644 --- a/MLAPI/Attributes/FieldType.cs +++ b/MLAPI/Attributes/FieldType.cs @@ -14,6 +14,9 @@ UInt, ULong, UShort, - String + String, + Vector3, + Vector2, + Quaternion } } diff --git a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs index 1201be6..0429961 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs @@ -222,6 +222,24 @@ namespace MLAPI syncedFieldValues.Add(sortedFields[i].GetValue(this)); syncedFieldTypes.Add(FieldType.String); } + else if(sortedFields[i].FieldType == typeof(Vector3)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Vector3); + } + else if(sortedFields[i].FieldType == typeof(Vector2)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Vector2); + } + else if (sortedFields[i].FieldType == typeof(Quaternion)) + { + syncedFields.Add(sortedFields[i]); + syncedFieldValues.Add(sortedFields[i].GetValue(this)); + syncedFieldTypes.Add(FieldType.Quaternion); + } else { Debug.LogError("MLAPI: The type " + sortedFields[i].FieldType.ToString() + " can not be used as a syncvar"); @@ -299,6 +317,23 @@ namespace MLAPI case FieldType.String: writer.Write((string)syncedFields[i].GetValue(this)); break; + case FieldType.Vector3: + Vector3 vector3 = (Vector3)syncedFields[i].GetValue(this); + writer.Write(vector3.x); + writer.Write(vector3.y); + writer.Write(vector3.z); + break; + case FieldType.Vector2: + Vector2 vector2 = (Vector2)syncedFields[i].GetValue(this); + writer.Write(vector2.x); + writer.Write(vector2.y); + break; + case FieldType.Quaternion: + Vector3 euler = ((Quaternion)syncedFields[i].GetValue(this)).eulerAngles; + writer.Write(euler.x); + writer.Write(euler.y); + writer.Write(euler.z); + break; } } NetworkingManager.singleton.Send(clientId, "MLAPI_SYNC_VAR_UPDATE", "MLAPI_RELIABLE_FRAGMENTED_SEQUENCED", stream.ToArray()); @@ -372,6 +407,24 @@ namespace MLAPI case FieldType.String: writer.Write((string)syncedFields[i].GetValue(this)); break; + case FieldType.Vector3: + Vector3 vector3 = (Vector3)syncedFields[i].GetValue(this); + writer.Write(vector3.x); + writer.Write(vector3.y); + writer.Write(vector3.z); + break; + case FieldType.Vector2: + Vector2 vector2 = (Vector2)syncedFields[i].GetValue(this); + writer.Write(vector2.x); + writer.Write(vector2.y); + break; + case FieldType.Quaternion: + Vector3 euler = ((Quaternion)syncedFields[i].GetValue(this)).eulerAngles; + writer.Write(euler.x); + writer.Write(euler.y); + writer.Write(euler.z); + break; + } syncedFieldValues[i] = syncedFields[i].GetValue(this); dirtyFields[i] = false; @@ -470,6 +523,24 @@ namespace MLAPI else dirtyFields[i] = false; //Up to date break; + case FieldType.Vector3: + if ((Vector3)syncedFields[i].GetValue(this) != (Vector3)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.Vector2: + if ((Vector2)syncedFields[i].GetValue(this) != (Vector2)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; + case FieldType.Quaternion: + if ((Quaternion)syncedFields[i].GetValue(this) != (Quaternion)syncedFieldValues[i]) + dirtyFields[i] = true; //This fields value is out of sync! + else + dirtyFields[i] = false; //Up to date + break; } } } diff --git a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs index 42f441a..83092d7 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs @@ -741,6 +741,29 @@ namespace MLAPI case FieldType.String: SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(messageReader.ReadString(), fieldIndex); break; + case FieldType.Vector3: + { //Cases aren't their own scope. Therefor we create a scope for them as they share the X,Y,Z local variables otherwise. + float x = messageReader.ReadSingle(); + float y = messageReader.ReadSingle(); + float z = messageReader.ReadSingle(); + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(new Vector3(x, y, z), fieldIndex); + } + break; + case FieldType.Vector2: + { + float x = messageReader.ReadSingle(); + float y = messageReader.ReadSingle(); + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(new Vector2(x, y), fieldIndex); + } + break; + case FieldType.Quaternion: + { + float x = messageReader.ReadSingle(); + float y = messageReader.ReadSingle(); + float z = messageReader.ReadSingle(); + SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(Quaternion.Euler(x, y, z), fieldIndex); + } + break; } } } From fe88778c88e06129b4d2e755e08cc1da1286eff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albin=20Cor=C3=A9n?= Date: Thu, 8 Mar 2018 09:47:57 +0100 Subject: [PATCH 5/5] Removed networkedBehaviourId --- MLAPI/MLAPI.csproj | 3 +- .../MonoBehaviours/Core/NetworkedBehaviour.cs | 5 -- MLAPI/MonoBehaviours/Core/NetworkedObject.cs | 59 +++++++++++-------- .../MonoBehaviours/Core/NetworkingManager.cs | 2 - .../SyncedVarManager.cs | 35 ----------- 5 files changed, 34 insertions(+), 70 deletions(-) delete mode 100644 MLAPI/NetworkingManagerComponents/SyncedVarManager.cs diff --git a/MLAPI/MLAPI.csproj b/MLAPI/MLAPI.csproj index 948bd46..8bc0fde 100644 --- a/MLAPI/MLAPI.csproj +++ b/MLAPI/MLAPI.csproj @@ -1,5 +1,5 @@  - + Debug @@ -73,7 +73,6 @@ - diff --git a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs index 0429961..2348cbd 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs @@ -134,9 +134,6 @@ namespace MLAPI private List syncedFieldValues = new List(); //A dirty field is a field that's not synced. public bool[] dirtyFields; - protected static ushort networkedBehaviourId; - //This is just for the unity editor. if you turn the editor to DEBUG mode you can see what the networkedBehaviourId is. - private ushort _networkedBehaviourId = networkedBehaviourId; internal void SyncVarInit() { FieldInfo[] sortedFields = GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance).OrderBy(x => x.Name).ToArray(); @@ -274,7 +271,6 @@ namespace MLAPI { writer.Write(networkId); writer.Write(networkedObject.GetOrderIndex(this)); - writer.Write(networkedBehaviourId); writer.Write(i); //Index switch (syncedFieldTypes[i]) { @@ -364,7 +360,6 @@ namespace MLAPI { writer.Write(networkId); writer.Write(networkedObject.GetOrderIndex(this)); - writer.Write(networkedBehaviourId); writer.Write(i); //Index switch (syncedFieldTypes[i]) { diff --git a/MLAPI/MonoBehaviours/Core/NetworkedObject.cs b/MLAPI/MonoBehaviours/Core/NetworkedObject.cs index 4704b56..96a6cba 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedObject.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedObject.cs @@ -64,45 +64,53 @@ namespace MLAPI internal void InvokeBehaviourOnLostOwnership() { - NetworkedBehaviour[] netBehaviours = GetComponentsInChildren(); - for (int i = 0; i < netBehaviours.Length; i++) + for (int i = 0; i < childNetworkedBehaviours.Count; i++) { - //We check if we are it's networkedObject owner incase a networkedObject exists as a child of our networkedObject. - if (netBehaviours[i].networkedObject == this) - { - netBehaviours[i].OnLostOwnership(); - } + childNetworkedBehaviours[i].OnLostOwnership(); } } internal void InvokeBehaviourOnGainedOwnership() { - NetworkedBehaviour[] netBehaviours = GetComponentsInChildren(); - for (int i = 0; i < netBehaviours.Length; i++) + for (int i = 0; i < childNetworkedBehaviours.Count; i++) { - //We check if we are it's networkedObject owner incase a networkedObject exists as a child of our networkedObject. - if (netBehaviours[i].networkedObject == this) - { - netBehaviours[i].OnGainedOwnership(); - } + childNetworkedBehaviours[i].OnGainedOwnership(); } } internal void InvokeBehaviourNetworkSpawn() { - NetworkedBehaviour[] netBehaviours = GetComponentsInChildren(); - for (int i = 0; i < netBehaviours.Length; i++) + for (int i = 0; i < childNetworkedBehaviours.Count; i++) { //We check if we are it's networkedObject owner incase a networkedObject exists as a child of our networkedObject. - if(netBehaviours[i].networkedObject == this && !netBehaviours[i].networkedStartInvoked) + if(!childNetworkedBehaviours[i].networkedStartInvoked) { - netBehaviours[i].NetworkStart(); + childNetworkedBehaviours[i].NetworkStart(); if (NetworkingManager.singleton.isServer) - netBehaviours[i].SyncVarInit(); + childNetworkedBehaviours[i].SyncVarInit(); } } } + private List _childNetworkedBehaviours; + internal List childNetworkedBehaviours + { + get + { + if(_childNetworkedBehaviours == null) + { + _childNetworkedBehaviours = new List(); + NetworkedBehaviour[] behaviours = GetComponentsInChildren(); + for (int i = 0; i < behaviours.Length; i++) + { + if (behaviours[i].networkedObject == this) + _childNetworkedBehaviours.Add(behaviours[i]); + } + } + return _childNetworkedBehaviours; + } + } + internal static List NetworkedBehaviours = new List(); internal static void InvokeSyncvarUpdate() { @@ -115,18 +123,17 @@ namespace MLAPI //Flushes all syncVars to client internal void FlushToClient(int clientId) { - for (int i = 0; i < NetworkedBehaviours.Count; i++) + for (int i = 0; i < childNetworkedBehaviours.Count; i++) { - NetworkedBehaviours[i].FlushToClient(clientId); + childNetworkedBehaviours[i].FlushToClient(clientId); } } internal ushort GetOrderIndex(NetworkedBehaviour instance) { - NetworkedBehaviour[] behaviours = GetComponentsInChildren(); - for (ushort i = 0; i < behaviours.Length; i++) + for (ushort i = 0; i < childNetworkedBehaviours.Count; i++) { - if (behaviours[i].networkedObject == this && behaviours[i] == instance) + if (childNetworkedBehaviours[i] == instance) return i; } return 0; @@ -134,8 +141,8 @@ namespace MLAPI internal NetworkedBehaviour GetBehaviourAtOrderIndex(ushort index) { - NetworkedBehaviour[] behaviours = GetComponentsInChildren(); - return behaviours[index]; + //TODO index out of bounds + return childNetworkedBehaviours[index]; } } } diff --git a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs index 83092d7..d54061d 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs @@ -74,7 +74,6 @@ namespace MLAPI { NetworkConfig = netConfig; - SyncedVarManager.Init(); pendingClients = new HashSet(); connectedClients = new Dictionary(); messageBuffer = new byte[NetworkConfig.MessageBufferSize]; @@ -697,7 +696,6 @@ namespace MLAPI { uint netId = messageReader.ReadUInt32(); //NetId the syncvar is from ushort orderIndex = messageReader.ReadUInt16(); - ushort networkBehaviourId = messageReader.ReadUInt16(); byte fieldIndex = messageReader.ReadByte(); FieldType type = SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).syncedFieldTypes[fieldIndex]; switch (type) diff --git a/MLAPI/NetworkingManagerComponents/SyncedVarManager.cs b/MLAPI/NetworkingManagerComponents/SyncedVarManager.cs deleted file mode 100644 index a9dcf6d..0000000 --- a/MLAPI/NetworkingManagerComponents/SyncedVarManager.cs +++ /dev/null @@ -1,35 +0,0 @@ -using MLAPI.Attributes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using UnityEngine; - -namespace MLAPI.NetworkingManagerComponents -{ - internal static class SyncedVarManager - { - internal static void Init() - { - Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); - Assembly assembly = Assembly.GetExecutingAssembly(); - for (int i = 0; i < assemblies.Length; i++) - { - if (assemblies[i].FullName == "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null") - { - assembly = assemblies[i]; - break; - } - } - IEnumerable types = from t in assembly.GetTypes() - where t.IsClass && t.IsSubclassOf(typeof(NetworkedBehaviour)) - select t; - List behaviourTypes = types.OrderBy(x => x.FullName).ToList(); - for (ushort i = 0; i < behaviourTypes.Count; i++) - { - FieldInfo networkedBehaviourId = behaviourTypes[i].GetField("networkedBehaviourId", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); - networkedBehaviourId.SetValue(null, i); - } - } - } -}