diff --git a/MLAPI/Attributes/FieldType.cs b/MLAPI/Attributes/FieldType.cs new file mode 100644 index 0000000..49621be --- /dev/null +++ b/MLAPI/Attributes/FieldType.cs @@ -0,0 +1,22 @@ +namespace MLAPI.Attributes +{ + internal enum FieldType + { + Bool, + Byte, + Char, + Double, + Single, + Int, + Long, + SByte, + Short, + UInt, + ULong, + UShort, + String, + Vector3, + Vector2, + Quaternion + } +} 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..8bc0fde 100644 --- a/MLAPI/MLAPI.csproj +++ b/MLAPI/MLAPI.csproj @@ -1,5 +1,5 @@  - + Debug @@ -41,7 +41,7 @@ AnyCPU prompt MinimumRecommendedRules.ruleset - Off + Auto @@ -56,6 +56,8 @@ + + diff --git a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs index 8c1f608..2348cbd 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,419 @@ 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; + 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 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"); + } + } + } + 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) + { + 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(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; + 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()); + } + } + } + + private float lastSyncTime = 0f; + internal void SyncVarUpdate() + { + 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(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; + 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; + } + } + 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; + 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; + } + } + } + #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..96a6cba 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 @@ -63,41 +64,85 @@ 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) + 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() + { + for (int i = 0; i < NetworkedBehaviours.Count; i++) + { + NetworkedBehaviours[i].SyncVarUpdate(); + } + } + + //Flushes all syncVars to client + internal void FlushToClient(int clientId) + { + for (int i = 0; i < childNetworkedBehaviours.Count; i++) + { + childNetworkedBehaviours[i].FlushToClient(clientId); + } + } + + internal ushort GetOrderIndex(NetworkedBehaviour instance) + { + for (ushort i = 0; i < childNetworkedBehaviours.Count; i++) + { + if (childNetworkedBehaviours[i] == instance) + return i; + } + return 0; + } + + internal NetworkedBehaviour GetBehaviourAtOrderIndex(ushort index) + { + //TODO index out of bounds + return childNetworkedBehaviours[index]; + } } } diff --git a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs index 3e7dd18..d54061d 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; @@ -117,6 +118,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"); @@ -360,7 +362,10 @@ namespace MLAPI } if (isServer) + { LagCompensationManager.AddFrames(); + NetworkedObject.InvokeSyncvarUpdate(); + } } private IEnumerator ApprovalTimeout(int clientId) @@ -677,6 +682,93 @@ 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(); + 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; + 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; + } + } + } + } + } + } + break; } } } @@ -1065,6 +1157,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 {