merge
commit
997c2d5738
|
|
@ -0,0 +1,48 @@
|
|||
#if UNITY_EDITOR
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace VelNet.Editor
|
||||
{
|
||||
public class EditorUtils : MonoBehaviour
|
||||
{
|
||||
[MenuItem("VelNet/Check For Duplicate NetworkIds", false, 10)]
|
||||
private static void CheckDuplicateNetworkIds()
|
||||
{
|
||||
NetworkObject[] objs = FindObjectsOfType<NetworkObject>();
|
||||
Dictionary<int, NetworkObject> ids = new Dictionary<int, NetworkObject>();
|
||||
foreach (NetworkObject o in objs)
|
||||
{
|
||||
if (!o.isSceneObject) continue;
|
||||
|
||||
if (ids.ContainsKey(o.sceneNetworkId) || o.sceneNetworkId < 100)
|
||||
{
|
||||
if (ids.ContainsKey(o.sceneNetworkId))
|
||||
{
|
||||
Debug.Log($"Found duplicated id: {o.name} {ids[o.sceneNetworkId].name}", o);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"Found duplicated id: {o.name} {o.sceneNetworkId}", o);
|
||||
}
|
||||
|
||||
o.sceneNetworkId = 100;
|
||||
while (ids.ContainsKey(o.sceneNetworkId))
|
||||
{
|
||||
o.sceneNetworkId += 1;
|
||||
}
|
||||
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(o);
|
||||
EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
|
||||
}
|
||||
|
||||
ids.Add(o.sceneNetworkId, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8f2f5f489d44f614c96bcf8f493c787d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "VelNet.Editor",
|
||||
"rootNamespace": "VelNet.Editor",
|
||||
"references": [
|
||||
"GUID:1e55e2c4387020247a1ae212bbcbd381"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ae0703a992a8fe347978b1cd2dd2d7a9
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -62,7 +62,7 @@ namespace VelNet
|
|||
}
|
||||
else
|
||||
{
|
||||
owner.SendMessage(this, index.ToString(), message, reliable);
|
||||
VelNetPlayer.SendMessage(this, (byte)index, message, reliable);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,15 +76,15 @@ namespace VelNet
|
|||
|
||||
// send the message and an identifier for which component it belongs to
|
||||
int index = syncedComponents.IndexOf(component);
|
||||
owner.SendGroupMessage(this, group, index.ToString(), message, reliable);
|
||||
VelNetPlayer.SendGroupMessage(this, group, (byte)index, message, reliable);
|
||||
}
|
||||
|
||||
public void ReceiveBytes(string identifier, byte[] message)
|
||||
public void ReceiveBytes(byte componentIdx, byte[] message)
|
||||
{
|
||||
// send the message to the right component
|
||||
try
|
||||
{
|
||||
syncedComponents[int.Parse(identifier)].ReceiveBytes(message);
|
||||
syncedComponents[componentIdx].ReceiveBytes(message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -128,6 +128,7 @@ namespace VelNet
|
|||
foreach (NetworkComponent c in comps)
|
||||
{
|
||||
c.networkObject = t;
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(c);
|
||||
}
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(t);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ namespace VelNet
|
|||
{
|
||||
public static class BinaryWriterExtensions
|
||||
{
|
||||
#region Writers
|
||||
|
||||
public static void Write(this BinaryWriter writer, Vector3 v)
|
||||
{
|
||||
writer.Write(v.x);
|
||||
|
|
@ -23,6 +25,18 @@ namespace VelNet
|
|||
writer.Write(q.w);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter writer, Color c)
|
||||
{
|
||||
writer.Write(c.r);
|
||||
writer.Write(c.g);
|
||||
writer.Write(c.b);
|
||||
writer.Write(c.a);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Readers
|
||||
|
||||
public static Vector3 ReadVector3(this BinaryReader reader)
|
||||
{
|
||||
return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
|
|
@ -38,6 +52,35 @@ namespace VelNet
|
|||
);
|
||||
}
|
||||
|
||||
public static Color ReadColor(this BinaryReader reader)
|
||||
{
|
||||
return new Color(
|
||||
reader.ReadSingle(),
|
||||
reader.ReadSingle(),
|
||||
reader.ReadSingle(),
|
||||
reader.ReadSingle()
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public static bool BytesSame(byte[] b1, byte[] b2)
|
||||
{
|
||||
if (b1 == null && b2 != null) return false; // only one null
|
||||
if (b1 != null && b2 == null) return false; // only one null
|
||||
if (b1 == null) return true; // both null
|
||||
|
||||
// length doesn't match
|
||||
if (b1.Length != b2.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if any bytes are different
|
||||
return !b1.Where((t, i) => t != b2[i]).Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compresses the list of bools into bytes using a bitmask
|
||||
/// </summary>
|
||||
|
|
@ -88,6 +131,5 @@ namespace VelNet
|
|||
{
|
||||
return (b & (1 << index)) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace VelNet
|
||||
{
|
||||
|
|
@ -9,6 +9,15 @@ namespace VelNet
|
|||
[Tooltip("Send rate of this object. This caps out at the framerate of the game.")]
|
||||
public float serializationRateHz = 30;
|
||||
|
||||
/// <summary>
|
||||
/// If the data hasn't changed, only sends updates across the network at 1Hz
|
||||
/// </summary>
|
||||
public bool hybridOnChangeCompression = true;
|
||||
|
||||
private byte[] lastSentBytes;
|
||||
private double lastSendTime;
|
||||
private const double slowSendInterval = 2;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
StartCoroutine(SendMessageUpdate());
|
||||
|
|
@ -18,9 +27,31 @@ namespace VelNet
|
|||
{
|
||||
while (true)
|
||||
{
|
||||
if (IsMine)
|
||||
try
|
||||
{
|
||||
SendBytes(SendState());
|
||||
if (IsMine && enabled)
|
||||
{
|
||||
byte[] newBytes = SendState();
|
||||
if (hybridOnChangeCompression)
|
||||
{
|
||||
if (Time.timeAsDouble - lastSendTime > slowSendInterval || !BinaryWriterExtensions.BytesSame(lastSentBytes, newBytes))
|
||||
{
|
||||
SendBytes(newBytes);
|
||||
lastSendTime = Time.timeAsDouble;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SendBytes(newBytes);
|
||||
lastSendTime = Time.timeAsDouble;
|
||||
}
|
||||
|
||||
lastSentBytes = newBytes;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(1f / serializationRateHz);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace VelNet
|
||||
{
|
||||
|
|
@ -11,6 +10,16 @@ namespace VelNet
|
|||
[Tooltip("Send rate of this object. This caps out at the framerate of the game.")]
|
||||
public float serializationRateHz = 30;
|
||||
|
||||
/// <summary>
|
||||
/// If the data hasn't changed, only sends updates across the network at 1Hz
|
||||
/// </summary>
|
||||
public bool hybridOnChangeCompression = true;
|
||||
|
||||
private byte[] lastSentBytes;
|
||||
private double lastSendTime;
|
||||
private const double slowSendInterval = 2;
|
||||
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
StartCoroutine(SendMessageUpdate());
|
||||
|
|
@ -22,12 +31,28 @@ namespace VelNet
|
|||
{
|
||||
try
|
||||
{
|
||||
if (IsMine)
|
||||
if (IsMine && enabled)
|
||||
{
|
||||
using MemoryStream mem = new MemoryStream();
|
||||
using BinaryWriter writer = new BinaryWriter(mem);
|
||||
SendState(writer);
|
||||
SendBytes(mem.ToArray());
|
||||
|
||||
byte[] newBytes = mem.ToArray();
|
||||
if (hybridOnChangeCompression)
|
||||
{
|
||||
if (Time.timeAsDouble - lastSendTime > slowSendInterval || !BinaryWriterExtensions.BytesSame(lastSentBytes, newBytes))
|
||||
{
|
||||
SendBytes(newBytes);
|
||||
lastSendTime = Time.timeAsDouble;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SendBytes(newBytes);
|
||||
lastSendTime = Time.timeAsDouble;
|
||||
}
|
||||
|
||||
lastSentBytes = newBytes;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 03a4d4e1a7fd74c7ab2eccca4ce168db
|
||||
guid: 233344de094f11341bdb834d564708dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VelNet
|
||||
{
|
||||
|
|
@ -39,7 +42,12 @@ namespace VelNet
|
|||
{
|
||||
if (kvp.Value.owner == this && kvp.Value.prefabName != "")
|
||||
{
|
||||
VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, "7," + kvp.Value.networkId + "," + kvp.Value.prefabName);
|
||||
using MemoryStream mem = new MemoryStream();
|
||||
using BinaryWriter writer = new BinaryWriter(mem);
|
||||
writer.Write((byte)VelNetManager.MessageType.Instantiate);
|
||||
writer.Write(kvp.Value.networkId);
|
||||
writer.Write(kvp.Value.prefabName);
|
||||
VelNetManager.SendToRoom(mem.ToArray(), false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -53,77 +61,87 @@ namespace VelNet
|
|||
|
||||
/// <summary>
|
||||
/// These are generally things that come from the "owner" and should be enacted locally, where appropriate
|
||||
///
|
||||
/// Message encoding:
|
||||
/// byte: message type
|
||||
/// byte[]: message
|
||||
///
|
||||
/// The length of the byte[] for message is fixed according to the message type
|
||||
/// </summary>
|
||||
public void HandleMessage(VelNetManager.Message m)
|
||||
public void HandleMessage(VelNetManager.DataMessage m)
|
||||
{
|
||||
//we need to parse the message
|
||||
using MemoryStream mem = new MemoryStream(m.data);
|
||||
using BinaryReader reader = new BinaryReader(mem);
|
||||
|
||||
//types of messages
|
||||
string[] messages = m.text.Split(';'); //messages are split by ;
|
||||
foreach (string s in messages)
|
||||
//individual message parameters separated by comma
|
||||
VelNetManager.MessageType messageType = (VelNetManager.MessageType)reader.ReadByte();
|
||||
|
||||
switch (messageType)
|
||||
{
|
||||
//individual message parameters separated by comma
|
||||
string[] sections = s.Split(',');
|
||||
|
||||
switch (sections[0])
|
||||
case VelNetManager.MessageType.ObjectSync: // sync update for an object I may own
|
||||
{
|
||||
case "5": // sync update for an object I may own
|
||||
string objectKey = reader.ReadString();
|
||||
byte componentIdx = reader.ReadByte();
|
||||
int messageLength = reader.ReadInt32();
|
||||
byte[] syncMessage = reader.ReadBytes(messageLength);
|
||||
if (manager.objects.ContainsKey(objectKey))
|
||||
{
|
||||
string objectKey = sections[1];
|
||||
string identifier = sections[2];
|
||||
string syncMessage = sections[3];
|
||||
byte[] messageBytes = Convert.FromBase64String(syncMessage);
|
||||
if (manager.objects.ContainsKey(objectKey))
|
||||
if (manager.objects[objectKey].owner == this)
|
||||
{
|
||||
if (manager.objects[objectKey].owner == this)
|
||||
{
|
||||
manager.objects[objectKey].ReceiveBytes(identifier, messageBytes);
|
||||
}
|
||||
manager.objects[objectKey].ReceiveBytes(componentIdx, syncMessage);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "6": // I'm trying to take ownership of an object
|
||||
{
|
||||
string networkId = sections[1];
|
||||
|
||||
if (manager.objects.ContainsKey(networkId))
|
||||
{
|
||||
manager.objects[networkId].owner = this;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "7": // I'm trying to instantiate an object
|
||||
{
|
||||
string networkId = sections[1];
|
||||
string prefabName = sections[2];
|
||||
if (manager.objects.ContainsKey(networkId))
|
||||
{
|
||||
break; //we already have this one, ignore
|
||||
}
|
||||
|
||||
VelNetManager.SomebodyInstantiatedNetworkObject(networkId, prefabName, this);
|
||||
|
||||
break;
|
||||
}
|
||||
case "8": // I'm trying to destroy a gameobject I own
|
||||
{
|
||||
string networkId = sections[1];
|
||||
|
||||
VelNetManager.NetworkDestroy(networkId);
|
||||
break;
|
||||
}
|
||||
case "9": //deleted scene objects
|
||||
{
|
||||
for (int k = 1; k < sections.Length; k++)
|
||||
{
|
||||
VelNetManager.NetworkDestroy(sections[k]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VelNetManager.MessageType.TakeOwnership: // I'm trying to take ownership of an object
|
||||
{
|
||||
string networkId = reader.ReadString();
|
||||
|
||||
if (manager.objects.ContainsKey(networkId))
|
||||
{
|
||||
manager.objects[networkId].owner = this;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case VelNetManager.MessageType.Instantiate: // I'm trying to instantiate an object
|
||||
{
|
||||
string networkId = reader.ReadString();
|
||||
string prefabName = reader.ReadString();
|
||||
if (manager.objects.ContainsKey(networkId))
|
||||
{
|
||||
break; //we already have this one, ignore
|
||||
}
|
||||
|
||||
VelNetManager.SomebodyInstantiatedNetworkObject(networkId, prefabName, this);
|
||||
|
||||
break;
|
||||
}
|
||||
case VelNetManager.MessageType.Destroy: // I'm trying to destroy a gameobject I own
|
||||
{
|
||||
string networkId = reader.ReadString();
|
||||
|
||||
VelNetManager.NetworkDestroy(networkId);
|
||||
break;
|
||||
}
|
||||
case VelNetManager.MessageType.DeleteSceneObjects: //deleted scene objects
|
||||
{
|
||||
int len = reader.ReadInt32();
|
||||
for (int k = 1; k < len; k++)
|
||||
{
|
||||
VelNetManager.NetworkDestroy(reader.ReadString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VelNetManager.MessageType.Custom: // custom packets
|
||||
{
|
||||
int len = reader.ReadInt32();
|
||||
VelNetManager.CustomMessageReceived?.Invoke(reader.ReadBytes(len));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -134,19 +152,42 @@ namespace VelNet
|
|||
//FindObjectsOfType<NetworkObject>();
|
||||
}
|
||||
|
||||
public void SendGroupMessage(NetworkObject obj, string group, string identifier, byte[] data, bool reliable = true)
|
||||
public static void SendGroupMessage(NetworkObject obj, string group, byte componentIdx, byte[] data, bool reliable = true)
|
||||
{
|
||||
VelNetManager.SendToGroup(group, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable);
|
||||
using MemoryStream mem = new MemoryStream();
|
||||
using BinaryWriter writer = new BinaryWriter(mem);
|
||||
writer.Write((byte)VelNetManager.MessageType.ObjectSync);
|
||||
writer.Write(obj.networkId);
|
||||
writer.Write(componentIdx);
|
||||
writer.Write(data.Length);
|
||||
writer.Write(data);
|
||||
VelNetManager.SendToGroup(group, mem.ToArray(), reliable);
|
||||
}
|
||||
|
||||
public void SendMessage(NetworkObject obj, string identifier, byte[] data, bool reliable = true)
|
||||
public static void SendMessage(NetworkObject obj, byte componentIdx, byte[] data, bool reliable = true)
|
||||
{
|
||||
VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable);
|
||||
using MemoryStream mem = new MemoryStream();
|
||||
using BinaryWriter writer = new BinaryWriter(mem);
|
||||
writer.Write((byte)VelNetManager.MessageType.ObjectSync);
|
||||
writer.Write(obj.networkId);
|
||||
writer.Write(componentIdx);
|
||||
writer.Write(data.Length);
|
||||
writer.Write(data);
|
||||
VelNetManager.SendToRoom(mem.ToArray(), false, reliable);
|
||||
}
|
||||
|
||||
public void SendSceneUpdate()
|
||||
{
|
||||
VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, "9," + string.Join(",", manager.deletedSceneObjects));
|
||||
using MemoryStream mem = new MemoryStream();
|
||||
using BinaryWriter writer = new BinaryWriter(mem);
|
||||
writer.Write((byte)VelNetManager.MessageType.DeleteSceneObjects);
|
||||
writer.Write(manager.deletedSceneObjects.Count);
|
||||
foreach (string o in manager.deletedSceneObjects)
|
||||
{
|
||||
writer.Write(o);
|
||||
}
|
||||
|
||||
VelNetManager.SendToRoom(mem.ToArray());
|
||||
}
|
||||
|
||||
[Obsolete("Use VelNetManager.NetworkDestroy() instead.")]
|
||||
|
|
@ -156,7 +197,12 @@ namespace VelNet
|
|||
if (!manager.objects.ContainsKey(networkId) || manager.objects[networkId].owner != this || !isLocal) return;
|
||||
|
||||
// send to all, which will make me delete as well
|
||||
VelNetManager.SendTo(VelNetManager.MessageType.ALL_ORDERED, "8," + networkId);
|
||||
|
||||
using MemoryStream mem = new MemoryStream();
|
||||
using BinaryWriter writer = new BinaryWriter(mem);
|
||||
writer.Write((byte)VelNetManager.MessageType.Destroy);
|
||||
writer.Write(networkId);
|
||||
VelNetManager.SendToRoom(mem.ToArray(), true, true);
|
||||
}
|
||||
|
||||
/// <returns>True if successful, False if failed to transfer ownership</returns>
|
||||
|
|
@ -172,8 +218,13 @@ namespace VelNet
|
|||
// immediately successful
|
||||
manager.objects[networkId].owner = this;
|
||||
|
||||
// must be ordered, so that ownership transfers are not confused. Also sent to all players, so that multiple simultaneous requests will result in the same outcome.
|
||||
VelNetManager.SendTo(VelNetManager.MessageType.ALL_ORDERED, "6," + networkId);
|
||||
// must be ordered, so that ownership transfers are not confused.
|
||||
// Also sent to all players, so that multiple simultaneous requests will result in the same outcome.
|
||||
using MemoryStream mem = new MemoryStream();
|
||||
using BinaryWriter writer = new BinaryWriter(mem);
|
||||
writer.Write((byte)VelNetManager.MessageType.TakeOwnership);
|
||||
writer.Write(networkId);
|
||||
VelNetManager.SendToRoom(mem.ToArray(), true, true, ordered: true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "edu.uga.engr.vel.velnet",
|
||||
"displayName": "VelNet",
|
||||
"version": "1.0.7",
|
||||
"version": "1.0.8",
|
||||
"unity": "2019.1",
|
||||
"description": "A custom networking library for Unity.",
|
||||
"keywords": [
|
||||
|
|
|
|||
Loading…
Reference in New Issue