big reorganization to make NetworkObjects pass messages on to NetworkComponent, which do the actual syncing. Removed the need for a Player gameobject, added a ownershipLocked option for possible player objects, simplified instantiation process - but it doesn't seem to work all the time

upm
Anton Franzluebbers 2022-01-07 02:33:10 -05:00
parent 37d818b5e2
commit 70dcf597c4
19 changed files with 454 additions and 335 deletions

View File

@ -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;
/// <summary>
/// call this in child classes to send a message to other people
/// </summary>
protected void SendBytes(byte[] message, bool reliable = true)
{
networkObject.SendBytes(this, message, reliable);
}
/// <summary>
/// call this in child classes to send a message to other people
/// </summary>
protected void SendBytesToGroup(string group, byte[] message, bool reliable = true)
{
networkObject.SendBytesToGroup(this, group, message, reliable);
}
//
/// <summary>
/// This is called by <see cref="NetworkObject"/> when messages are received for this component
/// </summary>
public abstract void ReceiveBytes(byte[] message);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 52c3bc18f2284ca28a9d2095e77330d2
timeCreated: 1641527089

View File

@ -1,3 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine; using UnityEngine;
namespace VelNetUnity namespace VelNetUnity
@ -5,20 +7,57 @@ namespace VelNetUnity
/// <summary> /// <summary>
/// This is a base class for all objects that a player can instantiated/owned /// This is a base class for all objects that a player can instantiated/owned
/// </summary> /// </summary>
public abstract class NetworkObject : MonoBehaviour public class NetworkObject : MonoBehaviour
{ {
[Header("NetworkObject properties")] [Header("NetworkObject properties")]
public NetworkPlayer owner; public NetworkPlayer owner;
public bool IsMine => owner !=null && owner.isLocal; public bool ownershipLocked;
public bool IsMine => owner != null && owner.isLocal;
/// <summary> /// <summary>
/// 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 /// 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
/// </summary> /// </summary>
public string networkId; public string networkId;
/// <summary> /// <summary>
/// This may be empty if it's not a prefab (scene object) /// This may be empty if it's not a prefab (scene object)
/// </summary> /// </summary>
public string prefabName; public string prefabName;
public bool isSceneObject; public bool isSceneObject;
public abstract void HandleMessage(string identifier, byte[] message);
public List<NetworkComponent> 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);
}
} }
} }

View File

@ -1,11 +1,3 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: dd77ffdf919cc444f863d7bf0cda29ea guid: 5515094c5c544b6b8ed7fd51a86548d4
MonoImporter: timeCreated: 1641527700
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,18 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine;
using System; using System;
namespace VelNetUnity namespace VelNetUnity
{ {
/// <summary> /// <summary>
/// One of these will be instantiated for each player that joins the "room". /// Represents a network player
/// </summary> /// </summary>
[RequireComponent(typeof(NetworkObject))] public class NetworkPlayer
[AddComponentMenu("VelNetUnity/VelNet Network Player")]
public class NetworkPlayer : MonoBehaviour
{ {
private NetworkObject myObject;
public int userid; public int userid;
public string username; public string username;
@ -20,7 +15,7 @@ namespace VelNetUnity
public bool isLocal; public bool isLocal;
private NetworkManager manager; private VelNetManager manager;
/// <summary> /// <summary>
/// For instantiation /// For instantiation
@ -30,11 +25,10 @@ namespace VelNetUnity
private bool isMaster; private bool isMaster;
private void Start()
public NetworkPlayer()
{ {
myObject = GetComponent<NetworkObject>(); manager = VelNetManager.instance;
myObject.owner = this;
manager = NetworkManager.instance;
manager.OnPlayerJoined += HandlePlayerJoined; manager.OnPlayerJoined += HandlePlayerJoined;
} }
@ -47,7 +41,7 @@ namespace VelNetUnity
{ {
if (kvp.Value.owner == this && kvp.Value.prefabName != "") 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 //these are generally things that come from the "owner" and should be enacted locally, where appropriate
//we need to parse the message //we need to parse the message
//types of messages //types of messages
string[] messages = m.text.Split(';'); //messages are split by ; 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 //individual message parameters separated by comma
string[] sections = messages[i].Split(','); string[] sections = s.Split(',');
switch (sections[0]) 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 case "5": //sync update for an object I may own
{ {
string objectKey = sections[1]; string objectKey = sections[1];
@ -91,7 +78,7 @@ namespace VelNetUnity
{ {
if (manager.objects[objectKey].owner == this) 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; break;
} }
case "7": //I'm trying to instantiate an object case "7": // I'm trying to instantiate an object
{ {
string networkId = sections[1]; string networkId = sections[1];
string prefabName = sections[2]; string prefabName = sections[2];
@ -117,19 +104,11 @@ namespace VelNetUnity
break; //we already have this one, ignore break; //we already have this one, ignore
} }
NetworkObject temp = manager.prefabs.Find((prefab) => prefab.name == prefabName); VelNetManager.InstantiateNetworkObject(networkId, prefabName, this);
if (temp != null)
{
NetworkObject instance = Instantiate(temp);
instance.networkId = networkId;
instance.prefabName = prefabName;
instance.owner = this;
manager.objects.Add(instance.networkId, instance);
}
break; 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]; string networkId = sections[1];
@ -157,72 +136,51 @@ namespace VelNetUnity
} }
public void SendGroupMessage(NetworkObject obj, string group, string identifier, byte[] data, bool reliable = true) 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) public void SendMessage(NetworkObject obj, string identifier, byte[] data, bool reliable = true)
{ {
if (obj == myObject) manager.SendTo(VelNetManager.MessageType.OTHERS, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable);
{
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;
} }
/// <summary>
/// TODO could move this to a static method in VelNetManager
/// </summary>
public void NetworkDestroy(string networkId) 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 // 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 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) /// <summary>
/// TODO could move this to a static method in VelNetManager
/// </summary>
/// <returns>True if successful, False if failed to transfer ownership</returns>
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 // if the ownership is locked, fail
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 (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() public void SendSceneUpdate()
{ {
manager.SendTo(NetworkManager.MessageType.OTHERS, "9," + string.Join(",", manager.deletedSceneObjects)); manager.SendTo(VelNetManager.MessageType.OTHERS, "9," + string.Join(",", manager.deletedSceneObjects));
} }
} }
} }

View File

@ -1,39 +1,40 @@
using System; using System.Collections;
using System.Timers;
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization; using UnityEngine.Serialization;
namespace VelNetUnity 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() private void Start()
{ {
Timer timer = new Timer(); StartCoroutine(SendMessageUpdate());
timer.Interval = serializationRateHz;
timer.Elapsed += 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(); protected abstract byte[] SendState();
public override void HandleMessage(string identifier, byte[] message)
{
if (identifier == "s")
{
ReceiveState(message);
}
}
protected abstract void ReceiveState(byte[] message); protected abstract void ReceiveState(byte[] message);
} }
} }

View File

@ -1,4 +1,3 @@
using System.Collections;
using System.IO; using System.IO;
using UnityEngine; using UnityEngine;
@ -13,6 +12,7 @@ namespace VelNetUnity
{ {
public Vector3 targetPosition; public Vector3 targetPosition;
public Quaternion targetRotation; public Quaternion targetRotation;
public float smoothness = .1f;
protected override byte[] SendState() protected override byte[] SendState()
{ {
@ -36,9 +36,9 @@ namespace VelNetUnity
private void Update() private void Update()
{ {
if (owner == null || owner.isLocal) return; if (IsMine) return;
transform.position = Vector3.Lerp(transform.position, targetPosition, .1f); transform.position = Vector3.Lerp(transform.position, targetPosition, 1 / smoothness / serializationRateHz);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, .1f); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 1 / smoothness / serializationRateHz);
} }
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
@ -8,8 +9,8 @@ using System.Net;
namespace VelNetUnity namespace VelNetUnity
{ {
[AddComponentMenu("VelNetUnity/VelNet Network Manager")] [AddComponentMenu("VelNetUnity/VelNet Manager")]
public class NetworkManager : MonoBehaviour public class VelNetManager : MonoBehaviour
{ {
public enum MessageType public enum MessageType
{ {
@ -22,9 +23,7 @@ namespace VelNetUnity
public string host; public string host;
public int port; public int port;
public static NetworkManager instance; public static VelNetManager instance;
#region private members
private TcpClient socketConnection; private TcpClient socketConnection;
private Socket udpSocket; private Socket udpSocket;
@ -36,8 +35,7 @@ namespace VelNetUnity
public string room; public string room;
private int messagesReceived = 0; private int messagesReceived = 0;
public GameObject playerPrefab; public readonly Dictionary<int, NetworkPlayer> players = new Dictionary<int, NetworkPlayer>();
public Dictionary<int, NetworkPlayer> players = new Dictionary<int, NetworkPlayer>();
public Action<NetworkPlayer> OnJoinedRoom; public Action<NetworkPlayer> OnJoinedRoom;
public Action<NetworkPlayer> OnPlayerJoined; public Action<NetworkPlayer> OnPlayerJoined;
@ -48,8 +46,9 @@ namespace VelNetUnity
public List<string> deletedSceneObjects = new List<string>(); public List<string> deletedSceneObjects = new List<string>();
public readonly Dictionary<string, NetworkObject> objects = new Dictionary<string, NetworkObject>(); //maintains a list of all known objects on the server (ones that have ids) public readonly Dictionary<string, NetworkObject> objects = new Dictionary<string, NetworkObject>(); //maintains a list of all known objects on the server (ones that have ids)
private NetworkPlayer masterPlayer; private NetworkPlayer masterPlayer;
public static NetworkPlayer LocalPlayer => instance.players.Where(p => p.Value.isLocal).Select(p=>p.Value).FirstOrDefault();
#endregion
// Use this for initialization // Use this for initialization
public class Message public class Message
@ -67,6 +66,7 @@ namespace VelNetUnity
{ {
Debug.LogError("Multiple NetworkManagers detected! Bad!", this); Debug.LogError("Multiple NetworkManagers detected! Bad!", this);
} }
instance = this; instance = this;
} }
@ -106,85 +106,92 @@ namespace VelNetUnity
if (m.type == 2) 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) if (userid == m.sender)
{ {
foreach (KeyValuePair<int, NetworkPlayer> kvp in players) // TODO delete all old objects when joining a new room
{
Destroy(kvp.Value.gameObject);
}
players.Clear(); //we clear the list, but will recreate as we get messages from people in our room players.Clear(); //we clear the list, but will recreate as we get messages from people in our room
if (m.text != "") if (m.text != "")
{ {
NetworkPlayer player = Instantiate(playerPrefab).GetComponent<NetworkPlayer>(); NetworkPlayer player = new NetworkPlayer
{
isLocal = true,
userid = m.sender,
room = m.text
};
player.isLocal = true;
player.userid = m.sender;
players.Add(userid, player); players.Add(userid, player);
player.room = m.text;
OnJoinedRoom?.Invoke(player); 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]; NetworkPlayer me = players[userid];
if (me.room != m.text) if (me.room != m.text)
{ {
//we got a left message, kill it // we got a left message, kill it
//change ownership of all objects to master // change ownership of all objects to master
foreach (KeyValuePair<string, NetworkObject> kvp in objects) foreach (KeyValuePair<string, NetworkObject> 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); 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; kvp.Value.owner = null;
} }
} }
} }
Destroy(players[m.sender].gameObject);
players.Remove(m.sender); players.Remove(m.sender);
} }
else else
{ {
//we got a join mesage, create it // we got a join message, create it
NetworkPlayer player = Instantiate(playerPrefab).GetComponent<NetworkPlayer>(); NetworkPlayer player = new NetworkPlayer
player.isLocal = false; {
player.room = m.text; isLocal = false,
player.userid = m.sender; room = m.text,
userid = m.sender
};
players.Add(m.sender, player); players.Add(m.sender, player);
OnPlayerJoined?.Invoke(player); OnPlayerJoined?.Invoke(player);
} }
} }
} }
if (m.type == 3) //generic message if (m.type == 3) // generic message
{ {
players[m.sender]?.HandleMessage(m); 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) if (masterPlayer == null)
{ {
masterPlayer = players[m.sender]; 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++) for (int i = 0; i < sceneObjects.Length; i++)
{ {
sceneObjects[i].networkId = -1 + "-" + i; sceneObjects[i].networkId = -1 + "-" + i;
sceneObjects[i].owner = masterPlayer; 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]); objects.Add(sceneObjects[i].networkId, sceneObjects[i]);
} }
} }
@ -195,7 +202,7 @@ namespace VelNetUnity
masterPlayer.SetAsMasterPlayer(); 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<string, NetworkObject> kvp in objects) foreach (KeyValuePair<string, NetworkObject> kvp in objects)
{ {
@ -516,6 +523,34 @@ namespace VelNetUnity
SendNetworkMessage($"5:{groupName}:{string.Join(":", userIds)}"); 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) public void DeleteNetworkObject(string networkId)
{ {
if (objects.ContainsKey(networkId)) if (objects.ContainsKey(networkId))

View File

@ -7,6 +7,10 @@ using UnityEngine.Serialization;
namespace VelNetUnity namespace VelNetUnity
{ {
/// <summary>
/// Added to the same object as DissonanceComms component. Only one in the scene.
/// </summary>
[RequireComponent(typeof(DissonanceComms))]
[AddComponentMenu("VelNetUnity/Dissonance/VelNet Comms Network")] [AddComponentMenu("VelNetUnity/Dissonance/VelNet Comms Network")]
public class VelCommsNetwork : MonoBehaviour, ICommsNetwork public class VelCommsNetwork : MonoBehaviour, ICommsNetwork
{ {
@ -26,8 +30,8 @@ namespace VelNetUnity
private ConnectionStatus _status = ConnectionStatus.Disconnected; private ConnectionStatus _status = ConnectionStatus.Disconnected;
private CodecSettings initSettings; private CodecSettings initSettings;
public string dissonanceId; public string dissonanceId;
[FormerlySerializedAs("comms")] public DissonanceComms dissonanceComms; [HideInInspector] public DissonanceComms dissonanceComms;
private NetworkManager manager; private VelNetManager manager;
/// <summary> /// <summary>
/// listen to this if you want to send voice /// listen to this if you want to send voice
@ -40,7 +44,7 @@ namespace VelNetUnity
{ {
_status = ConnectionStatus.Connected; _status = ConnectionStatus.Connected;
dissonanceComms = GetComponent<DissonanceComms>(); dissonanceComms = GetComponent<DissonanceComms>();
manager = NetworkManager.instance; manager = VelNetManager.instance;
} }
public void Initialize(string playerName, Rooms rooms, PlayerChannels playerChannels, RoomChannels roomChannels, CodecSettings codecSettings) public void Initialize(string playerName, Rooms rooms, PlayerChannels playerChannels, RoomChannels roomChannels, CodecSettings codecSettings)

View File

@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using Dissonance; using Dissonance;
using UnityEngine; using UnityEngine;
@ -12,7 +11,7 @@ namespace VelNetUnity
/// This should be added to your player object /// This should be added to your player object
/// </summary> /// </summary>
[AddComponentMenu("VelNetUnity/Dissonance/VelNet Dissonance Player")] [AddComponentMenu("VelNetUnity/Dissonance/VelNet Dissonance Player")]
public class VelNetDissonancePlayer : NetworkObject, IDissonancePlayer public class VelNetDissonancePlayer : NetworkComponent, IDissonancePlayer
{ {
private VelCommsNetwork comms; private VelCommsNetwork comms;
private bool isSpeaking; private bool isSpeaking;
@ -25,20 +24,24 @@ namespace VelNetUnity
public string PlayerId => dissonanceID; public string PlayerId => dissonanceID;
public Vector3 Position => transform.position; public Vector3 Position => transform.position;
public Quaternion Rotation => transform.rotation; 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 bool IsTracking => true;
public Vector3 targetPosition;
public Quaternion targetRotation;
private static readonly List<VelNetDissonancePlayer> allPlayers = new List<VelNetDissonancePlayer>(); private static readonly List<VelNetDissonancePlayer> allPlayers = new List<VelNetDissonancePlayer>();
public List<int> closePlayers = new List<int>(); public List<int> closePlayers = new List<int>();
[Tooltip("Maximum distance to transmit voice data. 0 to always send voice to all players.")] [Tooltip("Maximum distance to transmit voice data. 0 to always send voice to all players.")]
public float maxDistance; public float maxDistance;
// Start is called before the first frame update private enum MessageType : byte
private void Start() {
AudioData,
DissonanceId,
SpeakingState
}
// This object should not be in the scene at the start.
private void Awake()
{ {
comms = FindObjectOfType<VelCommsNetwork>(); comms = FindObjectOfType<VelCommsNetwork>();
if (comms == null) if (comms == null)
@ -53,76 +56,37 @@ namespace VelNetUnity
allPlayers.Add(this); allPlayers.Add(this);
} }
if (owner.isLocal) if (IsMine)
{ {
SetDissonanceID(comms.dissonanceId); SetDissonanceID(comms.dissonanceId);
comms.VoiceQueued += SendVoiceData; comms.VoiceQueued += SendVoiceData;
//we also need to know when other players join, so we can send the dissonance ID again //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); using MemoryStream mem = new MemoryStream();
owner.SendMessage(this, "d", b); using BinaryWriter writer = new BinaryWriter(mem);
writer.Write((byte)MessageType.DissonanceId);
writer.Write(dissonanceID);
SendBytes(mem.ToArray());
}; };
NetworkManager.instance.SetupMessageGroup("close", closePlayers.ToArray()); VelNetManager.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;
}
} }
} }
private void SendVoiceData(ArraySegment<byte> data) private void SendVoiceData(ArraySegment<byte> data)
{ {
// need to send it // need to send it
if (owner == null || !owner.isLocal) return; if (!IsMine) return;
using MemoryStream mem = new MemoryStream(); using MemoryStream mem = new MemoryStream();
using BinaryWriter writer = new BinaryWriter(mem); using BinaryWriter writer = new BinaryWriter(mem);
writer.Write((byte)MessageType.AudioData);
writer.Write(BitConverter.GetBytes(lastAudioId++)); writer.Write(BitConverter.GetBytes(lastAudioId++));
writer.Write(data.ToArray()); writer.Write(data.ToArray());
// send voice data unreliably // send voice data unreliably
owner.SendGroupMessage(this, "close", "a", mem.ToArray(), false); SendBytesToGroup("close", mem.ToArray(), false);
} }
/// <summary> /// <summary>
@ -132,8 +96,12 @@ namespace VelNetUnity
public void SetDissonanceID(string id) public void SetDissonanceID(string id)
{ {
dissonanceID = 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); comms.dissonanceComms.TrackPlayerPosition(this);
} }
@ -151,8 +119,7 @@ namespace VelNetUnity
// Update is called once per frame // Update is called once per frame
private void Update() private void Update()
{ {
if (owner == null) return; if (!IsMine) return;
if (!owner.isLocal) return;
// handle nearness cutoff // handle nearness cutoff
if (maxDistance > 0) if (maxDistance > 0)
@ -166,21 +133,21 @@ namespace VelNetUnity
} }
float dist = Vector3.Distance(p.transform.position, transform.position); 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; 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; closePlayerListChanged = true;
} }
} }
if (closePlayerListChanged) 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 if (comms.dissonanceComms.FindPlayer(dissonanceID)?.IsSpeaking != isSpeaking) //unfortunately, there does not seem to be an event for this
{ {
isSpeaking = !isSpeaking; 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) 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;
}
}
}
} }
} }

View File

@ -1,12 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI; using UnityEngine.UI;
namespace VelNetUnity namespace VelNetUnity
{ {
public class NetworkGUI : MonoBehaviour public class NetworkGUI : MonoBehaviour
{ {
public NetworkManager networkManager; [FormerlySerializedAs("networkManager")] public VelNetManager velNetManager;
public InputField userInput; public InputField userInput;
public InputField sendInput; public InputField sendInput;
public InputField roomInput; public InputField roomInput;
@ -19,7 +20,7 @@ namespace VelNetUnity
{ {
if (sendInput.text != "") 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 != "") if (userInput.text != "")
{ {
networkManager.Login(userInput.text, "nopass"); velNetManager.Login(userInput.text, "nopass");
} }
} }
@ -35,7 +36,7 @@ namespace VelNetUnity
{ {
if (roomInput.text != "") if (roomInput.text != "")
{ {
networkManager.Join(roomInput.text); velNetManager.Join(roomInput.text);
} }
} }
@ -44,7 +45,7 @@ namespace VelNetUnity
{ {
comms = FindObjectOfType<Dissonance.DissonanceComms>(); comms = FindObjectOfType<Dissonance.DissonanceComms>();
microphones.AddOptions(new List<string>(Microphone.devices)); microphones.AddOptions(new List<string>(Microphone.devices));
networkManager.MessageReceived += (m) => velNetManager.MessageReceived += (m) =>
{ {
string s = m.type + ":" + m.sender + ":" + m.text; string s = m.type + ":" + m.sender + ":" + m.text;
messageBuffer.Add(s); messageBuffer.Add(s);

View File

@ -1,16 +1,60 @@
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using UnityEngine; using UnityEngine;
namespace VelNetUnity namespace VelNetUnity
{ {
public class PlayerController : NetworkObject public class PlayerController : NetworkSerializedObject
{ {
public Vector3 targetPosition; public Vector3 targetPosition;
public Quaternion targetRotation; 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<string, NetworkObject> kvp in VelNetManager.instance.objects)
{
Owner.TakeOwnership(kvp.Key);
}
}
if (Input.GetKeyDown(KeyCode.Backspace))
{
foreach (KeyValuePair<string, NetworkObject> 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 MemoryStream mem = new MemoryStream();
using BinaryWriter writer = new BinaryWriter(mem); using BinaryWriter writer = new BinaryWriter(mem);
@ -21,80 +65,13 @@ namespace VelNetUnity
return mem.ToArray(); 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 MemoryStream mem = new MemoryStream(message);
using BinaryReader reader = new BinaryReader(mem); using BinaryReader reader = new BinaryReader(mem);
targetPosition = reader.ReadVector3(); targetPosition = reader.ReadVector3();
targetRotation = reader.ReadQuaternion(); 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<string, NetworkObject> kvp in NetworkManager.instance.objects)
{
owner.TakeOwnership(kvp.Key);
}
}
if (Input.GetKeyDown(KeyCode.Backspace))
{
foreach (KeyValuePair<string, NetworkObject> kvp in NetworkManager.instance.objects)
{
owner.NetworkDestroy(kvp.Key);
}
}
}
} }
} }
} }

View File

@ -12,7 +12,7 @@ GameObject:
- component: {fileID: 8527011532923434593} - component: {fileID: 8527011532923434593}
- component: {fileID: 6854617867369839} - component: {fileID: 6854617867369839}
- component: {fileID: 5845716565458182149} - component: {fileID: 5845716565458182149}
- component: {fileID: 5713671764962751473} - component: {fileID: 9102273340480352682}
- component: {fileID: -4404668399269848200} - component: {fileID: -4404668399269848200}
- component: {fileID: 1181612843795795320} - component: {fileID: 1181612843795795320}
m_Layer: 0 m_Layer: 0
@ -98,7 +98,7 @@ BoxCollider:
serializedVersion: 2 serializedVersion: 2
m_Size: {x: 1, y: 1, z: 1} m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0} m_Center: {x: 0, y: 0, z: 0}
--- !u!114 &5713671764962751473 --- !u!114 &9102273340480352682
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -107,14 +107,16 @@ MonoBehaviour:
m_GameObject: {fileID: 6139051692386484099} m_GameObject: {fileID: 6139051692386484099}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d8d3b6de660834e3e898725928251405, type: 3} m_Script: {fileID: 11500000, guid: 5515094c5c544b6b8ed7fd51a86548d4, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
userid: 0 ownershipLocked: 1
username: networkId:
room: prefabName:
isLocal: 0 isSceneObject: 0
lastObjectId: 0 syncedComponents:
- {fileID: -4404668399269848200}
- {fileID: 1181612843795795320}
--- !u!114 &-4404668399269848200 --- !u!114 &-4404668399269848200
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -127,10 +129,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 89e3af759df774692a566a166b4bf69b, type: 3} m_Script: {fileID: 11500000, guid: 89e3af759df774692a566a166b4bf69b, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
owner: {fileID: 5713671764962751473} networkObject: {fileID: 9102273340480352682}
networkId: serializationRateHz: 30
prefabName:
isSceneObject: 0
targetPosition: {x: 0, y: 0, z: 0} targetPosition: {x: 0, y: 0, z: 0}
targetRotation: {x: 0, y: 0, z: 0, w: 0} targetRotation: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &1181612843795795320 --- !u!114 &1181612843795795320
@ -145,13 +145,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: c773e094326d413bb1bca7f91cbf7f8c, type: 3} m_Script: {fileID: 11500000, guid: c773e094326d413bb1bca7f91cbf7f8c, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
owner: {fileID: 5713671764962751473} networkObject: {fileID: 9102273340480352682}
networkId:
prefabName:
isSceneObject: 0
dissonanceID: dissonanceID:
targetPosition: {x: 0, y: 0, z: 0} targetPosition: {x: 0, y: 0, z: 0}
targetRotation: {x: 0, y: 0, z: 0, w: 0} targetRotation: {x: 0, y: 0, z: 0, w: 0}
allPlayers: []
closePlayers: closePlayers:
maxDistance: 0 maxDistance: 0

View File

@ -9,10 +9,11 @@ GameObject:
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 8565720275311462455} - component: {fileID: 8565720275311462455}
- component: {fileID: 3951900052977689805}
- component: {fileID: 8565720275311462452} - component: {fileID: 8565720275311462452}
m_Layer: 0 m_Layer: 0
m_Name: TestNetworkedGameObject m_Name: TestNetworkedGameObject
m_TagString: Untagged m_TagString: TestSphere
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
@ -32,6 +33,24 @@ Transform:
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 0 m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 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 --- !u!114 &8565720275311462452
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -44,10 +63,11 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 3f1f9b0bbd93a484a987c51f1107ebe5, type: 3} m_Script: {fileID: 11500000, guid: 3f1f9b0bbd93a484a987c51f1107ebe5, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
owner: {fileID: 0} networkObject: {fileID: 3951900052977689805}
networkId: serializationRateHz: 30
targetPosition: {x: 0, y: 0, z: 0} targetPosition: {x: 0, y: 0, z: 0}
targetRotation: {x: 0, y: 0, z: 0, w: 0} targetRotation: {x: 0, y: 0, z: 0, w: 0}
smoothness: 0.1
--- !u!1 &8565720276181857625 --- !u!1 &8565720276181857625
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -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);
};
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2fcf036844b060b47b23ad9a1e49eec2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -38,7 +38,7 @@ RenderSettings:
m_ReflectionIntensity: 1 m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0} m_CustomReflection: {fileID: 0}
m_Sun: {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 m_UseRadianceAmbientProbe: 0
--- !u!157 &3 --- !u!157 &3
LightmapSettings: LightmapSettings:
@ -624,7 +624,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 7a7db5bc792cd471dbd8039664359eee, type: 3} m_Script: {fileID: 11500000, guid: 7a7db5bc792cd471dbd8039664359eee, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
networkManager: {fileID: 1099803616} velNetManager: {fileID: 1099803616}
userInput: {fileID: 626742069} userInput: {fileID: 626742069}
sendInput: {fileID: 945446555} sendInput: {fileID: 945446555}
roomInput: {fileID: 711524768} roomInput: {fileID: 711524768}
@ -1787,6 +1787,7 @@ GameObject:
m_Component: m_Component:
- component: {fileID: 1099803615} - component: {fileID: 1099803615}
- component: {fileID: 1099803616} - component: {fileID: 1099803616}
- component: {fileID: 1099803613}
m_Layer: 0 m_Layer: 0
m_Name: NetworkManager m_Name: NetworkManager
m_TagString: Untagged m_TagString: Untagged
@ -1794,6 +1795,19 @@ GameObject:
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 1 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 --- !u!4 &1099803615
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1825,9 +1839,9 @@ MonoBehaviour:
udpConnected: 0 udpConnected: 0
userid: -1 userid: -1
room: room:
playerPrefab: {fileID: 6139051692386484099, guid: d4158ab9c4a204cdbba28d3273fc1fb3, type: 3}
prefabs: prefabs:
- {fileID: 8565720275311462452, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} - {fileID: 3951900052977689805, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3}
- {fileID: 9102273340480352682, guid: d4158ab9c4a204cdbba28d3273fc1fb3, type: 3}
sceneObjects: [] sceneObjects: []
deletedSceneObjects: [] deletedSceneObjects: []
connected: 0 connected: 0
@ -2281,8 +2295,7 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
dissonanceId: dissonanceId:
comms: {fileID: 1434745021} dissonanceComms: {fileID: 1434745021}
manager: {fileID: 1099803616}
--- !u!4 &1434745020 --- !u!4 &1434745020
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -1,7 +1,7 @@
{ {
"name": "edu.uga.engr.vel.velnetunity", "name": "edu.uga.engr.vel.velnetunity",
"displayName": "VelNetUnity", "displayName": "VelNetUnity",
"version": "1.0.2", "version": "1.0.3",
"unity": "2019.1", "unity": "2019.1",
"description": "A custom networking library for Unity.", "description": "A custom networking library for Unity.",
"keywords": [ "keywords": [