-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathMirrorNetProvider.cs
More file actions
114 lines (96 loc) · 3.85 KB
/
MirrorNetProvider.cs
File metadata and controls
114 lines (96 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#if (MIRROR || UNITY_SERVER) && !FISHNET
using System;
using System.Collections.Generic;
using MetaVoiceChat.Utils;
using Mirror;
using UnityEngine;
// A possible optimization is to handle all of the networking in one manager class and batch frames with a single timestamp.
// However, this is complex and benefits are negligible.
namespace MetaVoiceChat.NetProviders.Mirror
{
[RequireComponent(typeof(MetaVc))]
public class MirrorNetProvider : NetworkBehaviour, INetProvider
{
#region Singleton
public static MirrorNetProvider LocalPlayerInstance { get; private set; }
private readonly static List<MirrorNetProvider> instances = new();
public static IReadOnlyList<MirrorNetProvider> Instances => instances;
#endregion
bool INetProvider.IsLocalPlayerDeafened => LocalPlayerInstance.MetaVc.isDeafened;
public MetaVc MetaVc { get; private set; }
public override void OnStartClient()
{
#region Singleton
if (isLocalPlayer)
{
LocalPlayerInstance = this;
}
instances.Add(this);
#endregion
static int GetMaxDataBytesPerPacket()
{
int bytes = NetworkMessages.MaxMessageSize(Channels.Unreliable) - 13;
bytes -= sizeof(int); // Index
bytes -= sizeof(double); // Timestamp
bytes -= sizeof(byte); // Additional latency
bytes -= sizeof(ushort); // Array length
return bytes;
}
MetaVc = GetComponent<MetaVc>();
MetaVc.StartClient(this, isLocalPlayer, GetMaxDataBytesPerPacket());
}
public override void OnStopClient()
{
#region Singleton
if (isLocalPlayer)
{
LocalPlayerInstance = null;
}
instances.Remove(this);
#endregion
MetaVc.StopClient();
}
void INetProvider.RelayFrame(int index, double timestamp, ReadOnlySpan<byte> data)
{
var array = FixedLengthArrayPool<byte>.Rent(data.Length);
data.CopyTo(array);
float additionalLatency = Time.deltaTime;
MirrorFrame frame = new(index, timestamp, additionalLatency, array);
if (isServer)
{
RpcReceiveFrame(frame);
}
else
{
CmdRelayFrame(frame);
}
FixedLengthArrayPool<byte>.Return(array);
}
[Command(channel = Channels.Unreliable)]
private void CmdRelayFrame(MirrorFrame frame)
{
float additionalLatency = frame.additionalLatency + Time.deltaTime;
frame = new(frame.index, frame.timestamp, additionalLatency, frame.data);
RpcReceiveFrame(frame);
}
// A possible optimization is to use target RPCs and only send filled arrays to clients that are within audible range, and empty arrays to others.
// Audible range would be determined by the distance between the reciever's position and the sender's audio source position.
[ClientRpc(channel = Channels.Unreliable, includeOwner = false)]
private void RpcReceiveFrame(MirrorFrame frame)
{
if (MetaVc == null)
return;
if (isServer)
{
// Don't apply server Time.deltaTime to additionalLatency -- this frame did not go over the network again.
float additionalLatency = frame.additionalLatency - Time.deltaTime;
MetaVc.ReceiveFrame(frame.index, frame.timestamp, additionalLatency, frame.data);
}
else
{
MetaVc.ReceiveFrame(frame.index, frame.timestamp, frame.additionalLatency, frame.data);
}
}
}
}
#endif