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
parent
e8b500f478
commit
ca96e555b2
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2fcf036844b060b47b23ad9a1e49eec2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 52c3bc18f2284ca28a9d2095e77330d2
|
||||||
|
timeCreated: 1641527089
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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:
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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))
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2fcf036844b060b47b23ad9a1e49eec2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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": [
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
--- !u!78 &1
|
--- !u!78 &1
|
||||||
TagManager:
|
TagManager:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
tags: []
|
tags:
|
||||||
|
- TestSphere
|
||||||
layers:
|
layers:
|
||||||
- Default
|
- Default
|
||||||
- TransparentFX
|
- TransparentFX
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue