Files
FittsLaw/Assets/Oculus/Avatar/Samples/SocialStarter/Assets/Scripts/P2PManager.cs
2018-10-09 20:59:57 -04:00

232 lines
7.9 KiB
C#

using UnityEngine;
using System;
using Oculus.Platform;
using Oculus.Platform.Models;
// Helper class to manage a Peer-to-Peer connection to the other user.
// The connection is used to send and received the Transforms for the
// Avatars. The Transforms are sent via unreliable UDP at a fixed
// frequency.
public class P2PManager
{
// packet header is a message type byte
private enum MessageType : byte
{
Update = 1,
};
public P2PManager()
{
Net.SetPeerConnectRequestCallback(PeerConnectRequestCallback);
Net.SetConnectionStateChangedCallback(ConnectionStateChangedCallback);
}
#region Connection Management
public void ConnectTo(ulong userID)
{
// ID comparison is used to decide who calls Connect and who calls Accept
if (SocialPlatformManager.MyID < userID)
{
Net.Connect(userID);
SocialPlatformManager.LogOutput("P2P connect to " + userID);
}
}
public void Disconnect(ulong userID)
{
if (userID != 0)
{
Net.Close(userID);
RemotePlayer remote = SocialPlatformManager.GetRemoteUser(userID);
if (remote != null)
{
remote.p2pConnectionState = PeerConnectionState.Unknown;
}
}
}
void PeerConnectRequestCallback(Message<NetworkingPeer> msg)
{
SocialPlatformManager.LogOutput("P2P request from " + msg.Data.ID);
RemotePlayer remote = SocialPlatformManager.GetRemoteUser(msg.Data.ID);
if (remote != null)
{
SocialPlatformManager.LogOutput("P2P request accepted from " + msg.Data.ID);
Net.Accept(msg.Data.ID);
}
}
void ConnectionStateChangedCallback(Message<NetworkingPeer> msg)
{
SocialPlatformManager.LogOutput("P2P state to " + msg.Data.ID + " changed to " + msg.Data.State);
RemotePlayer remote = SocialPlatformManager.GetRemoteUser(msg.Data.ID);
if (remote != null)
{
remote.p2pConnectionState = msg.Data.State;
if (msg.Data.State == PeerConnectionState.Timeout &&
// ID comparison is used to decide who calls Connect and who calls Accept
SocialPlatformManager.MyID < msg.Data.ID)
{
// keep trying until hangup!
Net.Connect(msg.Data.ID);
SocialPlatformManager.LogOutput("P2P re-connect to " + msg.Data.ID);
}
}
}
#endregion
#region Message Sending
public void SendAvatarUpdate(ulong userID, Transform bodyTransform, UInt32 sequence, byte[] avatarPacket)
{
const int UPDATE_DATA_LENGTH = 41;
byte[] sendBuffer = new byte[avatarPacket.Length + UPDATE_DATA_LENGTH];
int offset = 0;
PackByte((byte)MessageType.Update, sendBuffer, ref offset);
PackULong(SocialPlatformManager.MyID, sendBuffer, ref offset);
PackFloat(bodyTransform.localPosition.x, sendBuffer, ref offset);
PackFloat(bodyTransform.localPosition.y, sendBuffer, ref offset);
PackFloat(bodyTransform.localPosition.z, sendBuffer, ref offset);
PackFloat(bodyTransform.localRotation.x, sendBuffer, ref offset);
PackFloat(bodyTransform.localRotation.y, sendBuffer, ref offset);
PackFloat(bodyTransform.localRotation.z, sendBuffer, ref offset);
PackFloat(bodyTransform.localRotation.w, sendBuffer, ref offset);
PackUInt32(sequence, sendBuffer, ref offset);
Debug.Assert(offset == UPDATE_DATA_LENGTH);
Buffer.BlockCopy(avatarPacket, 0, sendBuffer, offset, avatarPacket.Length);
Net.SendPacket(userID, sendBuffer, SendPolicy.Unreliable);
}
#endregion
#region Message Receiving
public void GetRemotePackets()
{
Packet packet;
while ((packet = Net.ReadPacket()) != null)
{
byte[] receiveBuffer = new byte[packet.Size];
packet.ReadBytes(receiveBuffer);
int offset = 0;
MessageType messageType = (MessageType)ReadByte(receiveBuffer, ref offset);
ulong remoteUserID = ReadULong(receiveBuffer, ref offset);
RemotePlayer remote = SocialPlatformManager.GetRemoteUser(remoteUserID);
if (remote == null)
{
SocialPlatformManager.LogOutput("Unknown remote player: " + remoteUserID);
continue;
}
if (messageType == MessageType.Update)
{
processAvatarPacket(remote, ref receiveBuffer, ref offset);
}
else
{
SocialPlatformManager.LogOutput("Invalid packet type: " + packet.Size);
continue;
}
}
}
public void processAvatarPacket(RemotePlayer remote, ref byte[] packet, ref int offset)
{
if (remote == null)
return;
remote.receivedBodyPositionPrior = remote.receivedBodyPosition;
remote.receivedBodyPosition.x = ReadFloat(packet, ref offset);
remote.receivedBodyPosition.y = ReadFloat(packet, ref offset);
remote.receivedBodyPosition.z = ReadFloat(packet, ref offset);
remote.receivedBodyRotationPrior = remote.receivedBodyRotation;
remote.receivedBodyRotation.x = ReadFloat(packet, ref offset);
remote.receivedBodyRotation.y = ReadFloat(packet, ref offset);
remote.receivedBodyRotation.z = ReadFloat(packet, ref offset);
remote.receivedBodyRotation.w = ReadFloat(packet, ref offset);
remote.RemoteAvatar.transform.localPosition = remote.receivedBodyPosition;
remote.RemoteAvatar.transform.localRotation = remote.receivedBodyRotation;
// forward the remaining data to the avatar system
int sequence = (int)ReadUInt32(packet, ref offset);
byte[] remainingAvatarBuffer = new byte[packet.Length - offset];
Buffer.BlockCopy(packet, offset, remainingAvatarBuffer, 0, remainingAvatarBuffer.Length);
IntPtr avatarPacket = Oculus.Avatar.CAPI.ovrAvatarPacket_Read((UInt32)remainingAvatarBuffer.Length, remainingAvatarBuffer);
var ovravatarPacket = new OvrAvatarPacket { ovrNativePacket = avatarPacket };
remote.RemoteAvatar.GetComponent<OvrAvatarRemoteDriver>().QueuePacket(sequence, ovravatarPacket);
}
#endregion
#region Serialization
void PackByte(byte b, byte[] buf, ref int offset)
{
buf[offset] = b;
offset += sizeof(byte);
}
byte ReadByte(byte[] buf, ref int offset)
{
byte val = buf[offset];
offset += sizeof(byte);
return val;
}
void PackFloat(float f, byte[] buf, ref int offset)
{
Buffer.BlockCopy(BitConverter.GetBytes(f), 0, buf, offset, sizeof(float));
offset += sizeof(float);
}
float ReadFloat(byte[] buf, ref int offset)
{
float val = BitConverter.ToSingle(buf, offset);
offset += sizeof(float);
return val;
}
void PackULong(ulong u, byte[] buf, ref int offset)
{
Buffer.BlockCopy(BitConverter.GetBytes(u), 0, buf, offset, sizeof(ulong));
offset += sizeof(ulong);
}
ulong ReadULong(byte[] buf, ref int offset)
{
ulong val = BitConverter.ToUInt64(buf, offset);
offset += sizeof(ulong);
return val;
}
void PackUInt32(UInt32 u, byte[] buf, ref int offset)
{
Buffer.BlockCopy(BitConverter.GetBytes(u), 0, buf, offset, sizeof(UInt32));
offset += sizeof(UInt32);
}
UInt32 ReadUInt32(byte[] buf, ref int offset)
{
UInt32 val = BitConverter.ToUInt32(buf, offset);
offset += sizeof(UInt32);
return val;
}
#endregion
}