diff --git a/Runtime/NetworkComponent.cs b/Runtime/NetworkComponent.cs
new file mode 100644
index 0000000..0dead22
--- /dev/null
+++ b/Runtime/NetworkComponent.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+
+namespace VelNetUnity
+{
+ public abstract class NetworkComponent : MonoBehaviour
+ {
+ public NetworkObject networkObject;
+ protected bool IsMine => networkObject != null && networkObject.owner != null && networkObject.owner.isLocal;
+ protected NetworkPlayer Owner => networkObject != null ? networkObject.owner : null;
+
+ ///
+ /// call this in child classes to send a message to other people
+ ///
+ protected void SendBytes(byte[] message, bool reliable = true)
+ {
+ networkObject.SendBytes(this, message, reliable);
+ }
+
+ ///
+ /// call this in child classes to send a message to other people
+ ///
+ protected void SendBytesToGroup(string group, byte[] message, bool reliable = true)
+ {
+ networkObject.SendBytesToGroup(this, group, message, reliable);
+ }
+
+ //
+ ///
+ /// This is called by when messages are received for this component
+ ///
+ public abstract void ReceiveBytes(byte[] message);
+ }
+}
\ No newline at end of file
diff --git a/Runtime/NetworkComponent.cs.meta b/Runtime/NetworkComponent.cs.meta
new file mode 100644
index 0000000..ba86217
--- /dev/null
+++ b/Runtime/NetworkComponent.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 52c3bc18f2284ca28a9d2095e77330d2
+timeCreated: 1641527089
\ No newline at end of file
diff --git a/Runtime/NetworkObject.cs b/Runtime/NetworkObject.cs
index ce0520a..e4139db 100644
--- a/Runtime/NetworkObject.cs
+++ b/Runtime/NetworkObject.cs
@@ -1,3 +1,5 @@
+using System.Collections.Generic;
+using System.Linq;
using UnityEngine;
namespace VelNetUnity
@@ -5,20 +7,57 @@ namespace VelNetUnity
///
/// This is a base class for all objects that a player can instantiated/owned
///
- public abstract class NetworkObject : MonoBehaviour
+ public class NetworkObject : MonoBehaviour
{
- [Header("NetworkObject properties")]
+ [Header("NetworkObject properties")]
public NetworkPlayer owner;
- public bool IsMine => owner !=null && owner.isLocal;
+ public bool ownershipLocked;
+ public bool IsMine => owner != null && owner.isLocal;
+
///
/// This is forged from the combination of the creator's id (-1 in the case of a scene object) and an object id, so it's always unique for a room
///
public string networkId;
+
///
/// This may be empty if it's not a prefab (scene object)
///
public string prefabName;
+
public bool isSceneObject;
- public abstract void HandleMessage(string identifier, byte[] message);
+
+ public List syncedComponents;
+
+ public void SendBytes(NetworkComponent component, byte[] message, bool reliable = true)
+ {
+ if (!IsMine)
+ {
+ Debug.LogError("Can't send message if owner is null or not local", this);
+ return;
+ }
+
+ // send the message and an identifier for which component it belongs to
+ int index = syncedComponents.IndexOf(component);
+ owner.SendMessage(this, index.ToString(), message, reliable);
+ }
+
+ public void SendBytesToGroup(NetworkComponent component, string group, byte[] message, bool reliable = true)
+ {
+ if (owner == null || !owner.isLocal)
+ {
+ Debug.LogError("Can't send message if owner is null or not local", this);
+ return;
+ }
+
+ // 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);
+ }
+
+ public void ReceiveBytes(string identifier, byte[] message)
+ {
+ // send the message to the right component
+ syncedComponents[int.Parse(identifier)].ReceiveBytes(message);
+ }
}
}
\ No newline at end of file
diff --git a/Runtime/NetworkObject.cs.meta b/Runtime/NetworkObject.cs.meta
index 6a1a6e9..29df2e6 100644
--- a/Runtime/NetworkObject.cs.meta
+++ b/Runtime/NetworkObject.cs.meta
@@ -1,11 +1,3 @@
-fileFormatVersion: 2
-guid: dd77ffdf919cc444f863d7bf0cda29ea
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
+fileFormatVersion: 2
+guid: 5515094c5c544b6b8ed7fd51a86548d4
+timeCreated: 1641527700
\ No newline at end of file
diff --git a/Runtime/NetworkPlayer.cs b/Runtime/NetworkPlayer.cs
index b59d089..448c6b2 100644
--- a/Runtime/NetworkPlayer.cs
+++ b/Runtime/NetworkPlayer.cs
@@ -1,18 +1,13 @@
using System.Collections.Generic;
-using UnityEngine;
using System;
-
namespace VelNetUnity
{
///
- /// One of these will be instantiated for each player that joins the "room".
+ /// Represents a network player
///
- [RequireComponent(typeof(NetworkObject))]
- [AddComponentMenu("VelNetUnity/VelNet Network Player")]
- public class NetworkPlayer : MonoBehaviour
+ public class NetworkPlayer
{
- private NetworkObject myObject;
public int userid;
public string username;
@@ -20,7 +15,7 @@ namespace VelNetUnity
public bool isLocal;
- private NetworkManager manager;
+ private VelNetManager manager;
///
/// For instantiation
@@ -30,11 +25,10 @@ namespace VelNetUnity
private bool isMaster;
- private void Start()
+
+ public NetworkPlayer()
{
- myObject = GetComponent();
- myObject.owner = this;
- manager = NetworkManager.instance;
+ manager = VelNetManager.instance;
manager.OnPlayerJoined += HandlePlayerJoined;
}
@@ -47,7 +41,7 @@ namespace VelNetUnity
{
if (kvp.Value.owner == this && kvp.Value.prefabName != "")
{
- manager.SendTo(NetworkManager.MessageType.OTHERS, "7," + kvp.Value.networkId + "," + kvp.Value.prefabName);
+ manager.SendTo(VelNetManager.MessageType.OTHERS, "7," + kvp.Value.networkId + "," + kvp.Value.prefabName);
}
}
@@ -60,27 +54,20 @@ namespace VelNetUnity
}
- public void HandleMessage(NetworkManager.Message m)
+ public void HandleMessage(VelNetManager.Message m)
{
//these are generally things that come from the "owner" and should be enacted locally, where appropriate
//we need to parse the message
//types of messages
string[] messages = m.text.Split(';'); //messages are split by ;
- for (int i = 0; i < messages.Length; i++)
+ foreach (string s in messages)
{
//individual message parameters separated by comma
- string[] sections = messages[i].Split(',');
+ string[] sections = s.Split(',');
switch (sections[0])
{
- case "1": //update my object's data
- {
- string identifier = sections[1];
- byte[] message = Convert.FromBase64String(sections[2]);
- myObject.HandleMessage(identifier, message);
- break;
- }
case "5": //sync update for an object I may own
{
string objectKey = sections[1];
@@ -91,7 +78,7 @@ namespace VelNetUnity
{
if (manager.objects[objectKey].owner == this)
{
- manager.objects[objectKey].HandleMessage(identifier, messageBytes);
+ manager.objects[objectKey].ReceiveBytes(identifier, messageBytes);
}
}
@@ -108,7 +95,7 @@ namespace VelNetUnity
break;
}
- case "7": //I'm trying to instantiate an object
+ case "7": // I'm trying to instantiate an object
{
string networkId = sections[1];
string prefabName = sections[2];
@@ -117,19 +104,11 @@ namespace VelNetUnity
break; //we already have this one, ignore
}
- NetworkObject temp = manager.prefabs.Find((prefab) => prefab.name == prefabName);
- if (temp != null)
- {
- NetworkObject instance = Instantiate(temp);
- instance.networkId = networkId;
- instance.prefabName = prefabName;
- instance.owner = this;
- manager.objects.Add(instance.networkId, instance);
- }
+ VelNetManager.InstantiateNetworkObject(networkId, prefabName, this);
break;
}
- case "8": //I'm trying to destroy a gameobject I own
+ case "8": // I'm trying to destroy a gameobject I own
{
string networkId = sections[1];
@@ -158,71 +137,50 @@ namespace VelNetUnity
public void SendGroupMessage(NetworkObject obj, string group, string identifier, byte[] data, bool reliable = true)
{
- if (obj == myObject)
- {
- manager.SendToGroup(group, "1," + identifier + "," + Convert.ToBase64String(data), reliable);
- }
- else
- {
- manager.SendToGroup(group, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable);
- }
+ manager.SendToGroup(group, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable);
}
public void SendMessage(NetworkObject obj, string identifier, byte[] data, bool reliable = true)
{
- if (obj == myObject)
- {
- manager.SendTo(NetworkManager.MessageType.OTHERS, "1," + identifier + "," + Convert.ToBase64String(data), reliable);
- }
- else
- {
- manager.SendTo(NetworkManager.MessageType.OTHERS, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable);
- }
- }
-
- public NetworkObject NetworkInstantiate(string prefabName)
- {
- if (!isLocal)
- {
- return null; //must be the local player to call instantiate
- }
-
- string networkId = userid + "-" + lastObjectId++;
-
-
- NetworkObject temp = manager.prefabs.Find((prefab) => prefab.name == prefabName);
- if (temp != null)
- {
- NetworkObject instance = Instantiate(temp);
- instance.networkId = networkId;
- instance.prefabName = prefabName;
- instance.owner = this;
- manager.objects.Add(instance.networkId, instance);
-
- manager.SendTo(NetworkManager.MessageType.OTHERS, "7," + networkId + "," + prefabName); //only sent to others, as I already instantiated this. Nice that it happens immediately.
- return instance;
- }
-
- return null;
+ manager.SendTo(VelNetManager.MessageType.OTHERS, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable);
}
+ ///
+ /// TODO could move this to a static method in VelNetManager
+ ///
public void NetworkDestroy(string networkId)
{
- if (!manager.objects.ContainsKey(networkId) || manager.objects[networkId].owner != this || !isLocal) return; //must be the local owner of the object to destroy it
- manager.SendTo(NetworkManager.MessageType.ALL_ORDERED, "8," + networkId); //send to all, which will make me delete as well
+ // must be the local owner of the object to destroy it
+ if (!manager.objects.ContainsKey(networkId) || manager.objects[networkId].owner != this || !isLocal) return;
+
+ // send to all, which will make me delete as well
+ manager.SendTo(VelNetManager.MessageType.ALL_ORDERED, "8," + networkId);
}
- public void TakeOwnership(string networkId)
+ ///
+ /// TODO could move this to a static method in VelNetManager
+ ///
+ /// True if successful, False if failed to transfer ownership
+ public bool TakeOwnership(string networkId)
{
- if (!manager.objects.ContainsKey(networkId) || !isLocal) return; //must exist and be the the local player
+ // must exist and be the the local player
+ if (!manager.objects.ContainsKey(networkId) || !isLocal) return false;
- manager.objects[networkId].owner = this; //immediately successful
- manager.SendTo(NetworkManager.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.
+ // if the ownership is locked, fail
+ if (manager.objects[networkId].ownershipLocked) return false;
+
+ // 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.
+ manager.SendTo(VelNetManager.MessageType.ALL_ORDERED, "6," + networkId);
+
+ return true;
}
public void SendSceneUpdate()
{
- manager.SendTo(NetworkManager.MessageType.OTHERS, "9," + string.Join(",", manager.deletedSceneObjects));
+ manager.SendTo(VelNetManager.MessageType.OTHERS, "9," + string.Join(",", manager.deletedSceneObjects));
}
}
}
\ No newline at end of file
diff --git a/Runtime/NetworkSerializedObject.cs b/Runtime/NetworkSerializedObject.cs
index 18ac263..162ced2 100644
--- a/Runtime/NetworkSerializedObject.cs
+++ b/Runtime/NetworkSerializedObject.cs
@@ -1,39 +1,40 @@
-using System;
-using System.Timers;
+using System.Collections;
using UnityEngine;
using UnityEngine.Serialization;
namespace VelNetUnity
{
- public abstract class NetworkSerializedObject : NetworkObject
+ public abstract class NetworkSerializedObject : NetworkComponent
{
- [FormerlySerializedAs("updateRateHz")] [Tooltip("Send rate of this object")] public float serializationRateHz = 30;
+ [FormerlySerializedAs("updateRateHz")] [Tooltip("Send rate of this object")]
+ public float serializationRateHz = 30;
private void Start()
{
- Timer timer = new Timer();
- timer.Interval = serializationRateHz;
- timer.Elapsed += SendMessageUpdate;
+ StartCoroutine(SendMessageUpdate());
}
- private void SendMessageUpdate(object sender, ElapsedEventArgs e)
+ private IEnumerator SendMessageUpdate()
{
- if (owner != null && owner.isLocal)
+ while (true)
{
- owner.SendMessage(this, "s", SendState());
+ if (IsMine)
+ {
+ SendBytes(SendState());
+ }
+
+ yield return new WaitForSeconds(1 / serializationRateHz);
}
+ // ReSharper disable once IteratorNeverReturns
+ }
+
+ public override void ReceiveBytes(byte[] message)
+ {
+ ReceiveState(message);
}
protected abstract byte[] SendState();
- public override void HandleMessage(string identifier, byte[] message)
- {
- if (identifier == "s")
- {
- ReceiveState(message);
- }
- }
-
protected abstract void ReceiveState(byte[] message);
}
}
\ No newline at end of file
diff --git a/Runtime/Util/SyncTransform.cs b/Runtime/Util/SyncTransform.cs
index fe8cbc4..5cb2b50 100644
--- a/Runtime/Util/SyncTransform.cs
+++ b/Runtime/Util/SyncTransform.cs
@@ -1,4 +1,3 @@
-using System.Collections;
using System.IO;
using UnityEngine;
@@ -13,6 +12,7 @@ namespace VelNetUnity
{
public Vector3 targetPosition;
public Quaternion targetRotation;
+ public float smoothness = .1f;
protected override byte[] SendState()
{
@@ -36,9 +36,9 @@ namespace VelNetUnity
private void Update()
{
- if (owner == null || owner.isLocal) return;
- transform.position = Vector3.Lerp(transform.position, targetPosition, .1f);
- transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, .1f);
+ if (IsMine) return;
+ transform.position = Vector3.Lerp(transform.position, targetPosition, 1 / smoothness / serializationRateHz);
+ transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 1 / smoothness / serializationRateHz);
}
}
}
\ No newline at end of file
diff --git a/Runtime/NetworkManager.cs b/Runtime/VelNetManager.cs
similarity index 78%
rename from Runtime/NetworkManager.cs
rename to Runtime/VelNetManager.cs
index 65bb271..140d231 100644
--- a/Runtime/NetworkManager.cs
+++ b/Runtime/VelNetManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
@@ -8,8 +9,8 @@ using System.Net;
namespace VelNetUnity
{
- [AddComponentMenu("VelNetUnity/VelNet Network Manager")]
- public class NetworkManager : MonoBehaviour
+ [AddComponentMenu("VelNetUnity/VelNet Manager")]
+ public class VelNetManager : MonoBehaviour
{
public enum MessageType
{
@@ -22,9 +23,7 @@ namespace VelNetUnity
public string host;
public int port;
- public static NetworkManager instance;
-
- #region private members
+ public static VelNetManager instance;
private TcpClient socketConnection;
private Socket udpSocket;
@@ -36,8 +35,7 @@ namespace VelNetUnity
public string room;
private int messagesReceived = 0;
- public GameObject playerPrefab;
- public Dictionary players = new Dictionary();
+ public readonly Dictionary players = new Dictionary();
public Action OnJoinedRoom;
public Action OnPlayerJoined;
@@ -48,8 +46,9 @@ namespace VelNetUnity
public List deletedSceneObjects = new List();
public readonly Dictionary objects = new Dictionary(); //maintains a list of all known objects on the server (ones that have ids)
private NetworkPlayer masterPlayer;
+ public static NetworkPlayer LocalPlayer => instance.players.Where(p => p.Value.isLocal).Select(p=>p.Value).FirstOrDefault();
+
- #endregion
// Use this for initialization
public class Message
@@ -67,6 +66,7 @@ namespace VelNetUnity
{
Debug.LogError("Multiple NetworkManagers detected! Bad!", this);
}
+
instance = this;
}
@@ -106,85 +106,92 @@ namespace VelNetUnity
if (m.type == 2)
{
- //if this message is for me, that means I joined a new room...
+ // if this message is for me, that means I joined a new room...
if (userid == m.sender)
{
- foreach (KeyValuePair kvp in players)
- {
- Destroy(kvp.Value.gameObject);
- }
+ // TODO delete all old objects when joining a new room
players.Clear(); //we clear the list, but will recreate as we get messages from people in our room
if (m.text != "")
{
- NetworkPlayer player = Instantiate(playerPrefab).GetComponent();
+ NetworkPlayer player = new NetworkPlayer
+ {
+ isLocal = true,
+ userid = m.sender,
+ room = m.text
+ };
- player.isLocal = true;
- player.userid = m.sender;
players.Add(userid, player);
- player.room = m.text;
OnJoinedRoom?.Invoke(player);
}
}
- else //not for me, a player is joining or leaving
+ else // not for me, a player is joining or leaving
{
NetworkPlayer me = players[userid];
if (me.room != m.text)
{
- //we got a left message, kill it
- //change ownership of all objects to master
-
+ // we got a left message, kill it
+ // change ownership of all objects to master
foreach (KeyValuePair kvp in objects)
{
- if (kvp.Value.owner == players[m.sender]) //the owner is the player that left
+ if (kvp.Value.owner == players[m.sender]) // the owner is the player that left
{
- if (me.isLocal && me == masterPlayer) //I'm the local master player, so can take ownership immediately
+ // if this object has locked ownership, delete it
+ if (kvp.Value.ownershipLocked)
+ {
+ // TODO this may check for ownership in the future. We don't need ownership here
+ DeleteNetworkObject(kvp.Value.networkId);
+ }
+ // I'm the local master player, so can take ownership immediately
+ else if (me.isLocal && me == masterPlayer)
{
me.TakeOwnership(kvp.Key);
}
- else if (players[m.sender] == masterPlayer) //the master player left, so everyone should set the owner null (we should get a new master shortly)
+ // the master player left, so everyone should set the owner null (we should get a new master shortly)
+ else if (players[m.sender] == masterPlayer)
{
kvp.Value.owner = null;
}
}
}
- Destroy(players[m.sender].gameObject);
players.Remove(m.sender);
}
else
{
- //we got a join mesage, create it
- NetworkPlayer player = Instantiate(playerPrefab).GetComponent();
- player.isLocal = false;
- player.room = m.text;
- player.userid = m.sender;
+ // we got a join message, create it
+ NetworkPlayer player = new NetworkPlayer
+ {
+ isLocal = false,
+ room = m.text,
+ userid = m.sender
+ };
players.Add(m.sender, player);
OnPlayerJoined?.Invoke(player);
}
}
}
- if (m.type == 3) //generic message
+ if (m.type == 3) // generic message
{
players[m.sender]?.HandleMessage(m);
}
- if (m.type == 4) //change master player (this should only happen when the first player joins or if the master player leaves)
+ if (m.type == 4) // change master player (this should only happen when the first player joins or if the master player leaves)
{
if (masterPlayer == null)
{
masterPlayer = players[m.sender];
- //no master player yet, add the scene objects
+ // no master player yet, add the scene objects
for (int i = 0; i < sceneObjects.Length; i++)
{
sceneObjects[i].networkId = -1 + "-" + i;
sceneObjects[i].owner = masterPlayer;
- sceneObjects[i].isSceneObject = true; //needed for special handling when deleted
+ sceneObjects[i].isSceneObject = true; // needed for special handling when deleted
objects.Add(sceneObjects[i].networkId, sceneObjects[i]);
}
}
@@ -195,7 +202,7 @@ namespace VelNetUnity
masterPlayer.SetAsMasterPlayer();
- //master player should take over any objects that do not have an owner
+ // master player should take over any objects that do not have an owner
foreach (KeyValuePair kvp in objects)
{
@@ -515,6 +522,34 @@ namespace VelNetUnity
{
SendNetworkMessage($"5:{groupName}:{string.Join(":", userIds)}");
}
+
+
+ public static void InstantiateNetworkObject(string prefabName)
+ {
+ NetworkPlayer localPlayer = LocalPlayer;
+ NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName);
+ if (prefab == null)
+ {
+ Debug.LogError("Couldn't find a prefab with that name: " + prefabName);
+ return;
+ }
+ NetworkObject newObject = Instantiate(prefab);
+ newObject.networkId = localPlayer.userid + "-" + localPlayer.lastObjectId++;;
+ newObject.prefabName = prefabName;
+ newObject.owner = localPlayer;
+ instance.objects.Add(newObject.networkId, newObject);
+ }
+
+ public static void InstantiateNetworkObject(string networkId, string prefabName, NetworkPlayer owner)
+ {
+ NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName);
+ if (prefab == null) return;
+ NetworkObject newObject = Instantiate(prefab);
+ newObject.networkId = networkId;
+ newObject.prefabName = prefabName;
+ newObject.owner = owner;
+ instance.objects.Add(newObject.networkId, newObject);
+ }
public void DeleteNetworkObject(string networkId)
{
diff --git a/Runtime/NetworkManager.cs.meta b/Runtime/VelNetManager.cs.meta
similarity index 100%
rename from Runtime/NetworkManager.cs.meta
rename to Runtime/VelNetManager.cs.meta
diff --git a/Samples~/DissonanceIntegration/VelCommsNetwork.cs b/Samples~/DissonanceIntegration/VelCommsNetwork.cs
index b1defa8..5633ee4 100644
--- a/Samples~/DissonanceIntegration/VelCommsNetwork.cs
+++ b/Samples~/DissonanceIntegration/VelCommsNetwork.cs
@@ -7,6 +7,10 @@ using UnityEngine.Serialization;
namespace VelNetUnity
{
+ ///
+ /// Added to the same object as DissonanceComms component. Only one in the scene.
+ ///
+ [RequireComponent(typeof(DissonanceComms))]
[AddComponentMenu("VelNetUnity/Dissonance/VelNet Comms Network")]
public class VelCommsNetwork : MonoBehaviour, ICommsNetwork
{
@@ -26,8 +30,8 @@ namespace VelNetUnity
private ConnectionStatus _status = ConnectionStatus.Disconnected;
private CodecSettings initSettings;
public string dissonanceId;
- [FormerlySerializedAs("comms")] public DissonanceComms dissonanceComms;
- private NetworkManager manager;
+ [HideInInspector] public DissonanceComms dissonanceComms;
+ private VelNetManager manager;
///
/// listen to this if you want to send voice
@@ -40,7 +44,7 @@ namespace VelNetUnity
{
_status = ConnectionStatus.Connected;
dissonanceComms = GetComponent();
- manager = NetworkManager.instance;
+ manager = VelNetManager.instance;
}
public void Initialize(string playerName, Rooms rooms, PlayerChannels playerChannels, RoomChannels roomChannels, CodecSettings codecSettings)
diff --git a/Samples~/DissonanceIntegration/VelNetDissonancePlayer.cs b/Samples~/DissonanceIntegration/VelNetDissonancePlayer.cs
index 9bf72c0..0ea2dba 100644
--- a/Samples~/DissonanceIntegration/VelNetDissonancePlayer.cs
+++ b/Samples~/DissonanceIntegration/VelNetDissonancePlayer.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Text;
using Dissonance;
using UnityEngine;
@@ -12,7 +11,7 @@ namespace VelNetUnity
/// This should be added to your player object
///
[AddComponentMenu("VelNetUnity/Dissonance/VelNet Dissonance Player")]
- public class VelNetDissonancePlayer : NetworkObject, IDissonancePlayer
+ public class VelNetDissonancePlayer : NetworkComponent, IDissonancePlayer
{
private VelCommsNetwork comms;
private bool isSpeaking;
@@ -25,20 +24,24 @@ namespace VelNetUnity
public string PlayerId => dissonanceID;
public Vector3 Position => transform.position;
public Quaternion Rotation => transform.rotation;
- public NetworkPlayerType Type => owner.isLocal ? NetworkPlayerType.Local : NetworkPlayerType.Remote;
+ public NetworkPlayerType Type => IsMine ? NetworkPlayerType.Local : NetworkPlayerType.Remote;
public bool IsTracking => true;
- public Vector3 targetPosition;
- public Quaternion targetRotation;
-
private static readonly List allPlayers = new List();
public List closePlayers = new List();
[Tooltip("Maximum distance to transmit voice data. 0 to always send voice to all players.")]
public float maxDistance;
- // Start is called before the first frame update
- private void Start()
+ private enum MessageType : byte
+ {
+ AudioData,
+ DissonanceId,
+ SpeakingState
+ }
+
+ // This object should not be in the scene at the start.
+ private void Awake()
{
comms = FindObjectOfType();
if (comms == null)
@@ -53,76 +56,37 @@ namespace VelNetUnity
allPlayers.Add(this);
}
- if (owner.isLocal)
+ if (IsMine)
{
SetDissonanceID(comms.dissonanceId);
comms.VoiceQueued += SendVoiceData;
//we also need to know when other players join, so we can send the dissonance ID again
- NetworkManager.instance.OnPlayerJoined += (player) =>
+ VelNetManager.instance.OnPlayerJoined += (player) =>
{
- byte[] b = Encoding.UTF8.GetBytes(dissonanceID);
- owner.SendMessage(this, "d", b);
+ using MemoryStream mem = new MemoryStream();
+ using BinaryWriter writer = new BinaryWriter(mem);
+ writer.Write((byte)MessageType.DissonanceId);
+ writer.Write(dissonanceID);
+ SendBytes(mem.ToArray());
};
- NetworkManager.instance.SetupMessageGroup("close", closePlayers.ToArray());
- }
- }
-
- public override void HandleMessage(string identifier, byte[] message)
- {
- switch (identifier)
- {
- case "a": //audio data
- {
- if (isSpeaking)
- {
- comms.VoiceReceived(dissonanceID, message);
- }
-
- break;
- }
- case "d": //dissonance id (player joined)
- {
- if (dissonanceID == "") // I don't have this yet
- {
- dissonanceID = Encoding.UTF8.GetString(message);
- // tell the comms network that this player joined the channel
- comms.SetPlayerJoined(dissonanceID); // tell dissonance
- comms.dissonanceComms.TrackPlayerPosition(this); // tell dissonance to track the remote player
- }
-
- break;
- }
- case "x": // speaking state
- {
- if (message[0] == 0)
- {
- comms.SetPlayerStoppedSpeaking(dissonanceID);
- isSpeaking = false;
- }
- else
- {
- comms.SetPlayerStartedSpeaking(dissonanceID);
- isSpeaking = true;
- }
-
- break;
- }
+ VelNetManager.instance.SetupMessageGroup("close", closePlayers.ToArray());
}
}
private void SendVoiceData(ArraySegment data)
{
// need to send it
- if (owner == null || !owner.isLocal) return;
+ if (!IsMine) return;
using MemoryStream mem = new MemoryStream();
using BinaryWriter writer = new BinaryWriter(mem);
+ writer.Write((byte)MessageType.AudioData);
writer.Write(BitConverter.GetBytes(lastAudioId++));
writer.Write(data.ToArray());
// send voice data unreliably
- owner.SendGroupMessage(this, "close", "a", mem.ToArray(), false);
+ SendBytesToGroup("close", mem.ToArray(), false);
}
///
@@ -132,8 +96,12 @@ namespace VelNetUnity
public void SetDissonanceID(string id)
{
dissonanceID = id;
- byte[] b = Encoding.UTF8.GetBytes(dissonanceID);
- owner.SendMessage(this, "d", b);
+
+ using MemoryStream mem = new MemoryStream();
+ using BinaryWriter writer = new BinaryWriter(mem);
+ writer.Write((byte)MessageType.DissonanceId);
+ writer.Write(dissonanceID);
+ SendBytes(mem.ToArray());
comms.dissonanceComms.TrackPlayerPosition(this);
}
@@ -151,8 +119,7 @@ namespace VelNetUnity
// Update is called once per frame
private void Update()
{
- if (owner == null) return;
- if (!owner.isLocal) return;
+ if (!IsMine) return;
// handle nearness cutoff
if (maxDistance > 0)
@@ -166,21 +133,21 @@ namespace VelNetUnity
}
float dist = Vector3.Distance(p.transform.position, transform.position);
- if (dist < maxDistance && !closePlayers.Contains(p.owner.userid))
+ if (dist < maxDistance && !closePlayers.Contains(p.Owner.userid))
{
- closePlayers.Add(p.owner.userid);
+ closePlayers.Add(p.Owner.userid);
closePlayerListChanged = true;
}
- else if (dist >= maxDistance && closePlayers.Contains(p.owner.userid))
+ else if (dist >= maxDistance && closePlayers.Contains(p.Owner.userid))
{
- closePlayers.Remove(p.owner.userid);
+ closePlayers.Remove(p.Owner.userid);
closePlayerListChanged = true;
}
}
if (closePlayerListChanged)
{
- NetworkManager.instance.SetupMessageGroup("close", closePlayers);
+ VelNetManager.instance.SetupMessageGroup("close", closePlayers);
}
}
@@ -191,8 +158,12 @@ namespace VelNetUnity
if (comms.dissonanceComms.FindPlayer(dissonanceID)?.IsSpeaking != isSpeaking) //unfortunately, there does not seem to be an event for this
{
isSpeaking = !isSpeaking;
- byte[] toSend = { isSpeaking ? (byte)1 : (byte)0 };
- owner.SendMessage(this, "x", toSend);
+
+ using MemoryStream mem = new MemoryStream();
+ using BinaryWriter writer = new BinaryWriter(mem);
+ writer.Write((byte)MessageType.SpeakingState);
+ writer.Write(isSpeaking ? (byte)1 : (byte)0);
+ SendBytes(mem.ToArray());
if (!isSpeaking)
{
@@ -200,5 +171,52 @@ namespace VelNetUnity
}
}
}
+
+ public override void ReceiveBytes(byte[] message)
+ {
+ using MemoryStream mem = new MemoryStream(message);
+ using BinaryReader reader = new BinaryReader(mem);
+
+ byte identifier = reader.ReadByte();
+ switch (identifier)
+ {
+ case 0: //audio data
+ {
+ if (isSpeaking)
+ {
+ comms.VoiceReceived(dissonanceID, message.Skip(1).ToArray());
+ }
+
+ break;
+ }
+ case 1: //dissonance id (player joined)
+ {
+ if (dissonanceID == "") // I don't have this yet
+ {
+ dissonanceID = reader.ReadString();
+ // tell the comms network that this player joined the channel
+ comms.SetPlayerJoined(dissonanceID); // tell dissonance
+ comms.dissonanceComms.TrackPlayerPosition(this); // tell dissonance to track the remote player
+ }
+
+ break;
+ }
+ case 2: // speaking state
+ {
+ if (message[0] == 0)
+ {
+ comms.SetPlayerStoppedSpeaking(dissonanceID);
+ isSpeaking = false;
+ }
+ else
+ {
+ comms.SetPlayerStartedSpeaking(dissonanceID);
+ isSpeaking = true;
+ }
+
+ break;
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Samples~/Example/NetworkGUI.cs b/Samples~/Example/NetworkGUI.cs
index b5ed7af..034466f 100644
--- a/Samples~/Example/NetworkGUI.cs
+++ b/Samples~/Example/NetworkGUI.cs
@@ -1,12 +1,13 @@
using System.Collections.Generic;
using UnityEngine;
+using UnityEngine.Serialization;
using UnityEngine.UI;
namespace VelNetUnity
{
public class NetworkGUI : MonoBehaviour
{
- public NetworkManager networkManager;
+ [FormerlySerializedAs("networkManager")] public VelNetManager velNetManager;
public InputField userInput;
public InputField sendInput;
public InputField roomInput;
@@ -19,7 +20,7 @@ namespace VelNetUnity
{
if (sendInput.text != "")
{
- networkManager.SendTo(NetworkManager.MessageType.OTHERS, sendInput.text);
+ velNetManager.SendTo(VelNetManager.MessageType.OTHERS, sendInput.text);
}
}
@@ -27,7 +28,7 @@ namespace VelNetUnity
{
if (userInput.text != "")
{
- networkManager.Login(userInput.text, "nopass");
+ velNetManager.Login(userInput.text, "nopass");
}
}
@@ -35,7 +36,7 @@ namespace VelNetUnity
{
if (roomInput.text != "")
{
- networkManager.Join(roomInput.text);
+ velNetManager.Join(roomInput.text);
}
}
@@ -44,7 +45,7 @@ namespace VelNetUnity
{
comms = FindObjectOfType();
microphones.AddOptions(new List(Microphone.devices));
- networkManager.MessageReceived += (m) =>
+ velNetManager.MessageReceived += (m) =>
{
string s = m.type + ":" + m.sender + ":" + m.text;
messageBuffer.Add(s);
diff --git a/Samples~/Example/PlayerController.cs b/Samples~/Example/PlayerController.cs
index 5f72100..aebafb5 100644
--- a/Samples~/Example/PlayerController.cs
+++ b/Samples~/Example/PlayerController.cs
@@ -1,16 +1,60 @@
-using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace VelNetUnity
{
- public class PlayerController : NetworkObject
+ public class PlayerController : NetworkSerializedObject
{
public Vector3 targetPosition;
public Quaternion targetRotation;
- public byte[] GetSyncMessage()
+
+ // Update is called once per frame
+ private void Update()
+ {
+ if (!IsMine)
+ {
+ transform.position = Vector3.Lerp(transform.position, targetPosition, .1f);
+ transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, .1f);
+ }
+ else
+ {
+ Vector3 movement = new Vector3();
+ movement.x += Input.GetAxis("Horizontal");
+ movement.y += Input.GetAxis("Vertical");
+ movement.z = 0;
+ transform.Translate(movement * Time.deltaTime);
+
+ if (Input.GetKeyDown(KeyCode.Space))
+ {
+ VelNetManager.InstantiateNetworkObject("TestNetworkedGameObject");
+ }
+
+ if (Input.GetKeyDown(KeyCode.BackQuote))
+ {
+ foreach (KeyValuePair kvp in VelNetManager.instance.objects)
+ {
+ Owner.TakeOwnership(kvp.Key);
+ }
+ }
+
+ if (Input.GetKeyDown(KeyCode.Backspace))
+ {
+ foreach (KeyValuePair kvp in VelNetManager.instance.objects)
+ {
+ // don't destroy player objects
+ if (!kvp.Value.ownershipLocked)
+ {
+ Owner.NetworkDestroy(kvp.Key);
+ }
+ }
+ }
+ }
+ }
+
+
+ protected override byte[] SendState()
{
using MemoryStream mem = new MemoryStream();
using BinaryWriter writer = new BinaryWriter(mem);
@@ -21,80 +65,13 @@ namespace VelNetUnity
return mem.ToArray();
}
- public override void HandleMessage(string identifier, byte[] message)
+ protected override void ReceiveState(byte[] message)
{
- switch (identifier)
- {
- case "s": // sync message
- {
- using MemoryStream mem = new MemoryStream(message);
- using BinaryReader reader = new BinaryReader(mem);
+ using MemoryStream mem = new MemoryStream(message);
+ using BinaryReader reader = new BinaryReader(mem);
- targetPosition = reader.ReadVector3();
- targetRotation = reader.ReadQuaternion();
-
- break;
- }
- }
- }
-
- // Start is called before the first frame update
- private void Start()
- {
- // player controller shouldn't change ownership, so we can check here once
- if (owner.isLocal)
- {
- StartCoroutine(SyncBehavior());
- }
- }
-
-
- private IEnumerator SyncBehavior()
- {
- while (true)
- {
- owner.SendMessage(this, "s", GetSyncMessage());
- yield return new WaitForSeconds(.1f);
- }
- }
-
- // Update is called once per frame
- private void Update()
- {
- if (owner != null && !owner.isLocal)
- {
- transform.position = Vector3.Lerp(transform.position, targetPosition, .1f);
- transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, .1f);
- }
- else if (owner != null && owner.isLocal)
- {
- Vector3 movement = new Vector3();
- movement.x += Input.GetAxis("Horizontal");
- movement.y += Input.GetAxis("Vertical");
- movement.z = 0;
- transform.Translate(movement * Time.deltaTime);
-
- if (Input.GetKeyDown(KeyCode.Space))
- {
- owner.NetworkInstantiate("TestNetworkedGameObject");
- }
-
- if (Input.GetKeyDown(KeyCode.BackQuote))
- {
- foreach (KeyValuePair kvp in NetworkManager.instance.objects)
- {
- owner.TakeOwnership(kvp.Key);
- }
- }
-
- if (Input.GetKeyDown(KeyCode.Backspace))
- {
- foreach (KeyValuePair kvp in NetworkManager.instance.objects)
- {
- owner.NetworkDestroy(kvp.Key);
- }
- }
- }
+ targetPosition = reader.ReadVector3();
+ targetRotation = reader.ReadQuaternion();
}
}
}
\ No newline at end of file
diff --git a/Samples~/Example/PlayerPrefab.prefab b/Samples~/Example/PlayerPrefab.prefab
index d590dc3..e4b77af 100644
--- a/Samples~/Example/PlayerPrefab.prefab
+++ b/Samples~/Example/PlayerPrefab.prefab
@@ -12,7 +12,7 @@ GameObject:
- component: {fileID: 8527011532923434593}
- component: {fileID: 6854617867369839}
- component: {fileID: 5845716565458182149}
- - component: {fileID: 5713671764962751473}
+ - component: {fileID: 9102273340480352682}
- component: {fileID: -4404668399269848200}
- component: {fileID: 1181612843795795320}
m_Layer: 0
@@ -98,7 +98,7 @@ BoxCollider:
serializedVersion: 2
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
---- !u!114 &5713671764962751473
+--- !u!114 &9102273340480352682
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -107,14 +107,16 @@ MonoBehaviour:
m_GameObject: {fileID: 6139051692386484099}
m_Enabled: 1
m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: d8d3b6de660834e3e898725928251405, type: 3}
+ m_Script: {fileID: 11500000, guid: 5515094c5c544b6b8ed7fd51a86548d4, type: 3}
m_Name:
m_EditorClassIdentifier:
- userid: 0
- username:
- room:
- isLocal: 0
- lastObjectId: 0
+ ownershipLocked: 1
+ networkId:
+ prefabName:
+ isSceneObject: 0
+ syncedComponents:
+ - {fileID: -4404668399269848200}
+ - {fileID: 1181612843795795320}
--- !u!114 &-4404668399269848200
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -127,10 +129,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 89e3af759df774692a566a166b4bf69b, type: 3}
m_Name:
m_EditorClassIdentifier:
- owner: {fileID: 5713671764962751473}
- networkId:
- prefabName:
- isSceneObject: 0
+ networkObject: {fileID: 9102273340480352682}
+ serializationRateHz: 30
targetPosition: {x: 0, y: 0, z: 0}
targetRotation: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &1181612843795795320
@@ -145,13 +145,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: c773e094326d413bb1bca7f91cbf7f8c, type: 3}
m_Name:
m_EditorClassIdentifier:
- owner: {fileID: 5713671764962751473}
- networkId:
- prefabName:
- isSceneObject: 0
+ networkObject: {fileID: 9102273340480352682}
dissonanceID:
targetPosition: {x: 0, y: 0, z: 0}
targetRotation: {x: 0, y: 0, z: 0, w: 0}
- allPlayers: []
closePlayers:
maxDistance: 0
diff --git a/Samples~/Example/TestNetworkedGameObject.prefab b/Samples~/Example/TestNetworkedGameObject.prefab
index bac19d3..e08d947 100644
--- a/Samples~/Example/TestNetworkedGameObject.prefab
+++ b/Samples~/Example/TestNetworkedGameObject.prefab
@@ -9,10 +9,11 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 8565720275311462455}
+ - component: {fileID: 3951900052977689805}
- component: {fileID: 8565720275311462452}
m_Layer: 0
m_Name: TestNetworkedGameObject
- m_TagString: Untagged
+ m_TagString: TestSphere
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
@@ -32,6 +33,24 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &3951900052977689805
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 8565720275311462453}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5515094c5c544b6b8ed7fd51a86548d4, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ ownershipLocked: 0
+ networkId:
+ prefabName:
+ isSceneObject: 0
+ syncedComponents:
+ - {fileID: 8565720275311462452}
--- !u!114 &8565720275311462452
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -44,10 +63,11 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 3f1f9b0bbd93a484a987c51f1107ebe5, type: 3}
m_Name:
m_EditorClassIdentifier:
- owner: {fileID: 0}
- networkId:
+ networkObject: {fileID: 3951900052977689805}
+ serializationRateHz: 30
targetPosition: {x: 0, y: 0, z: 0}
targetRotation: {x: 0, y: 0, z: 0, w: 0}
+ smoothness: 0.1
--- !u!1 &8565720276181857625
GameObject:
m_ObjectHideFlags: 0
diff --git a/Samples~/Example/VelNetMan.cs b/Samples~/Example/VelNetMan.cs
new file mode 100644
index 0000000..00bf9e7
--- /dev/null
+++ b/Samples~/Example/VelNetMan.cs
@@ -0,0 +1,18 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using VelNetUnity;
+
+public class VelNetMan : MonoBehaviour
+{
+ public GameObject playerPrefab;
+
+ // Start is called before the first frame update
+ private void Start()
+ {
+ VelNetManager.instance.OnJoinedRoom += player =>
+ {
+ VelNetManager.InstantiateNetworkObject(playerPrefab.name);
+ };
+ }
+}
\ No newline at end of file
diff --git a/Samples~/Example/VelNetMan.cs.meta b/Samples~/Example/VelNetMan.cs.meta
new file mode 100644
index 0000000..225d370
--- /dev/null
+++ b/Samples~/Example/VelNetMan.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2fcf036844b060b47b23ad9a1e49eec2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples~/Example/test.unity b/Samples~/Example/test.unity
index 2fcffdb..bda34bd 100644
--- a/Samples~/Example/test.unity
+++ b/Samples~/Example/test.unity
@@ -38,7 +38,7 @@ RenderSettings:
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
- m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748172, a: 1}
+ m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
@@ -624,7 +624,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 7a7db5bc792cd471dbd8039664359eee, type: 3}
m_Name:
m_EditorClassIdentifier:
- networkManager: {fileID: 1099803616}
+ velNetManager: {fileID: 1099803616}
userInput: {fileID: 626742069}
sendInput: {fileID: 945446555}
roomInput: {fileID: 711524768}
@@ -1787,6 +1787,7 @@ GameObject:
m_Component:
- component: {fileID: 1099803615}
- component: {fileID: 1099803616}
+ - component: {fileID: 1099803613}
m_Layer: 0
m_Name: NetworkManager
m_TagString: Untagged
@@ -1794,6 +1795,19 @@ GameObject:
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
+--- !u!114 &1099803613
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1099803612}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 2fcf036844b060b47b23ad9a1e49eec2, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ playerPrefab: {fileID: 6139051692386484099, guid: d4158ab9c4a204cdbba28d3273fc1fb3, type: 3}
--- !u!4 &1099803615
Transform:
m_ObjectHideFlags: 0
@@ -1825,9 +1839,9 @@ MonoBehaviour:
udpConnected: 0
userid: -1
room:
- playerPrefab: {fileID: 6139051692386484099, guid: d4158ab9c4a204cdbba28d3273fc1fb3, type: 3}
prefabs:
- - {fileID: 8565720275311462452, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3}
+ - {fileID: 3951900052977689805, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3}
+ - {fileID: 9102273340480352682, guid: d4158ab9c4a204cdbba28d3273fc1fb3, type: 3}
sceneObjects: []
deletedSceneObjects: []
connected: 0
@@ -2281,8 +2295,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
dissonanceId:
- comms: {fileID: 1434745021}
- manager: {fileID: 1099803616}
+ dissonanceComms: {fileID: 1434745021}
--- !u!4 &1434745020
Transform:
m_ObjectHideFlags: 0
diff --git a/package.json b/package.json
index 50f6464..fcdbec8 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "edu.uga.engr.vel.velnetunity",
"displayName": "VelNetUnity",
- "version": "1.0.2",
+ "version": "1.0.3",
"unity": "2019.1",
"description": "A custom networking library for Unity.",
"keywords": [