mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
Merged master
This commit is contained in:
commit
801aca4889
@ -109,7 +109,6 @@ protected virtual void UpdateClient()
|
||||
// only while we have snapshots
|
||||
if (clientSnapshots.Count > 0)
|
||||
{
|
||||
|
||||
// step the interpolation without touching time.
|
||||
// NetworkClient is responsible for time globally.
|
||||
SnapshotInterpolation.StepInterpolation(
|
||||
@ -122,7 +121,6 @@ protected virtual void UpdateClient()
|
||||
// interpolate & apply
|
||||
TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t);
|
||||
Apply(computed, to);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ void Update()
|
||||
else if (isClient) UpdateClient();
|
||||
}
|
||||
|
||||
void UpdateServer()
|
||||
void UpdateServerBroadcast()
|
||||
{
|
||||
// broadcast to all clients each 'sendInterval'
|
||||
// (client with authority will drop the rpc)
|
||||
@ -118,7 +118,10 @@ void UpdateServer()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateServerInterpolation()
|
||||
{
|
||||
// apply buffered snapshots IF client authority
|
||||
// -> in server authority, server moves the object
|
||||
// so no need to apply any snapshots there.
|
||||
@ -131,112 +134,129 @@ void UpdateServer()
|
||||
connectionToClient != null &&
|
||||
!isOwned)
|
||||
{
|
||||
if (serverSnapshots.Count > 0)
|
||||
{
|
||||
// step the transform interpolation without touching time.
|
||||
// NetworkClient is responsible for time globally.
|
||||
SnapshotInterpolation.StepInterpolation(
|
||||
serverSnapshots,
|
||||
connectionToClient.remoteTimeline,
|
||||
out TransformSnapshot from,
|
||||
out TransformSnapshot to,
|
||||
out double t);
|
||||
if (serverSnapshots.Count == 0) return;
|
||||
|
||||
// interpolate & apply
|
||||
TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t);
|
||||
Apply(computed, to);
|
||||
}
|
||||
// step the transform interpolation without touching time.
|
||||
// NetworkClient is responsible for time globally.
|
||||
SnapshotInterpolation.StepInterpolation(
|
||||
serverSnapshots,
|
||||
connectionToClient.remoteTimeline,
|
||||
out TransformSnapshot from,
|
||||
out TransformSnapshot to,
|
||||
out double t);
|
||||
|
||||
// interpolate & apply
|
||||
TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t);
|
||||
Apply(computed, to);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateServer()
|
||||
{
|
||||
// broadcast to all clients each 'sendInterval'
|
||||
UpdateServerBroadcast();
|
||||
|
||||
// apply buffered snapshots IF client authority
|
||||
UpdateServerInterpolation();
|
||||
}
|
||||
|
||||
void UpdateClientBroadcast()
|
||||
{
|
||||
// https://github.com/vis2k/Mirror/pull/2992/
|
||||
if (!NetworkClient.ready) return;
|
||||
|
||||
// send to server each 'sendInterval'
|
||||
// NetworkTime.localTime for double precision until Unity has it too
|
||||
//
|
||||
// IMPORTANT:
|
||||
// snapshot interpolation requires constant sending.
|
||||
// DO NOT only send if position changed. for example:
|
||||
// ---
|
||||
// * client sends first position at t=0
|
||||
// * ... 10s later ...
|
||||
// * client moves again, sends second position at t=10
|
||||
// ---
|
||||
// * server gets first position at t=0
|
||||
// * server gets second position at t=10
|
||||
// * server moves from first to second within a time of 10s
|
||||
// => would be a super slow move, instead of a wait & move.
|
||||
//
|
||||
// IMPORTANT:
|
||||
// DO NOT send nulls if not changed 'since last send' either. we
|
||||
// send unreliable and don't know which 'last send' the other end
|
||||
// received successfully.
|
||||
if (NetworkTime.localTime >= lastClientSendTime + NetworkClient.sendInterval) // same interval as time interpolation!
|
||||
{
|
||||
// send snapshot without timestamp.
|
||||
// receiver gets it from batch timestamp to save bandwidth.
|
||||
TransformSnapshot snapshot = Construct();
|
||||
#if onlySyncOnChange_BANDWIDTH_SAVING
|
||||
cachedSnapshotComparison = CompareSnapshots(snapshot);
|
||||
if (cachedSnapshotComparison && hasSentUnchangedPosition && onlySyncOnChange) { return; }
|
||||
#endif
|
||||
|
||||
#if onlySyncOnChange_BANDWIDTH_SAVING
|
||||
CmdClientToServerSync(
|
||||
// only sync what the user wants to sync
|
||||
syncPosition && positionChanged ? snapshot.position : default(Vector3?),
|
||||
syncRotation && rotationChanged ? snapshot.rotation : default(Quaternion?),
|
||||
syncScale && scaleChanged ? snapshot.scale : default(Vector3?)
|
||||
);
|
||||
#else
|
||||
CmdClientToServerSync(
|
||||
// only sync what the user wants to sync
|
||||
syncPosition ? snapshot.position : default(Vector3?),
|
||||
syncRotation ? snapshot.rotation : default(Quaternion?),
|
||||
syncScale ? snapshot.scale : default(Vector3?)
|
||||
);
|
||||
#endif
|
||||
|
||||
lastClientSendTime = NetworkTime.localTime;
|
||||
#if onlySyncOnChange_BANDWIDTH_SAVING
|
||||
if (cachedSnapshotComparison)
|
||||
{
|
||||
hasSentUnchangedPosition = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasSentUnchangedPosition = false;
|
||||
lastSnapshot = snapshot;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateClientInterpolation()
|
||||
{
|
||||
// only while we have snapshots
|
||||
if (clientSnapshots.Count == 0) return;
|
||||
|
||||
// step the interpolation without touching time.
|
||||
// NetworkClient is responsible for time globally.
|
||||
SnapshotInterpolation.StepInterpolation(
|
||||
clientSnapshots,
|
||||
NetworkTime.time, // == NetworkClient.localTimeline from snapshot interpolation
|
||||
out TransformSnapshot from,
|
||||
out TransformSnapshot to,
|
||||
out double t);
|
||||
|
||||
// interpolate & apply
|
||||
TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t);
|
||||
Apply(computed, to);
|
||||
}
|
||||
|
||||
void UpdateClient()
|
||||
{
|
||||
// client authority, and local player (= allowed to move myself)?
|
||||
if (IsClientWithAuthority)
|
||||
{
|
||||
// https://github.com/vis2k/Mirror/pull/2992/
|
||||
if (!NetworkClient.ready) return;
|
||||
|
||||
// send to server each 'sendInterval'
|
||||
// NetworkTime.localTime for double precision until Unity has it too
|
||||
//
|
||||
// IMPORTANT:
|
||||
// snapshot interpolation requires constant sending.
|
||||
// DO NOT only send if position changed. for example:
|
||||
// ---
|
||||
// * client sends first position at t=0
|
||||
// * ... 10s later ...
|
||||
// * client moves again, sends second position at t=10
|
||||
// ---
|
||||
// * server gets first position at t=0
|
||||
// * server gets second position at t=10
|
||||
// * server moves from first to second within a time of 10s
|
||||
// => would be a super slow move, instead of a wait & move.
|
||||
//
|
||||
// IMPORTANT:
|
||||
// DO NOT send nulls if not changed 'since last send' either. we
|
||||
// send unreliable and don't know which 'last send' the other end
|
||||
// received successfully.
|
||||
if (NetworkTime.localTime >= lastClientSendTime + NetworkClient.sendInterval) // same interval as time interpolation!
|
||||
{
|
||||
// send snapshot without timestamp.
|
||||
// receiver gets it from batch timestamp to save bandwidth.
|
||||
TransformSnapshot snapshot = Construct();
|
||||
#if onlySyncOnChange_BANDWIDTH_SAVING
|
||||
cachedSnapshotComparison = CompareSnapshots(snapshot);
|
||||
if (cachedSnapshotComparison && hasSentUnchangedPosition && onlySyncOnChange) { return; }
|
||||
#endif
|
||||
|
||||
#if onlySyncOnChange_BANDWIDTH_SAVING
|
||||
CmdClientToServerSync(
|
||||
// only sync what the user wants to sync
|
||||
syncPosition && positionChanged ? snapshot.position : default(Vector3?),
|
||||
syncRotation && rotationChanged ? snapshot.rotation : default(Quaternion?),
|
||||
syncScale && scaleChanged ? snapshot.scale : default(Vector3?)
|
||||
);
|
||||
#else
|
||||
CmdClientToServerSync(
|
||||
// only sync what the user wants to sync
|
||||
syncPosition ? snapshot.position : default(Vector3?),
|
||||
syncRotation ? snapshot.rotation : default(Quaternion?),
|
||||
syncScale ? snapshot.scale : default(Vector3?)
|
||||
);
|
||||
#endif
|
||||
|
||||
lastClientSendTime = NetworkTime.localTime;
|
||||
#if onlySyncOnChange_BANDWIDTH_SAVING
|
||||
if (cachedSnapshotComparison)
|
||||
{
|
||||
hasSentUnchangedPosition = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasSentUnchangedPosition = false;
|
||||
lastSnapshot = snapshot;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
UpdateClientBroadcast();
|
||||
}
|
||||
// for all other clients (and for local player if !authority),
|
||||
// we need to apply snapshots from the buffer
|
||||
else
|
||||
{
|
||||
// only while we have snapshots
|
||||
if (clientSnapshots.Count > 0)
|
||||
{
|
||||
// step the interpolation without touching time.
|
||||
// NetworkClient is responsible for time globally.
|
||||
SnapshotInterpolation.StepInterpolation(
|
||||
clientSnapshots,
|
||||
NetworkTime.time, // == NetworkClient.localTimeline from snapshot interpolation
|
||||
out TransformSnapshot from,
|
||||
out TransformSnapshot to,
|
||||
out double t);
|
||||
|
||||
// interpolate & apply
|
||||
TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t);
|
||||
Apply(computed, to);
|
||||
}
|
||||
UpdateClientInterpolation();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,11 @@
|
||||
V1.33 [2023-03-14]
|
||||
- perf: KcpServer/Client RawReceive now call socket.Poll to avoid non-blocking
|
||||
socket's allocating a new SocketException in case they WouldBlock.
|
||||
fixes https://github.com/MirrorNetworking/Mirror/issues/3413
|
||||
- perf: KcpServer/Client RawSend now call socket.Poll to avoid non-blocking
|
||||
socket's allocating a new SocketException in case they WouldBlock.
|
||||
fixes https://github.com/MirrorNetworking/Mirror/issues/3413
|
||||
|
||||
V1.32 [2023-03-12]
|
||||
- fix: KcpPeer RawInput now doesn't disconnect in case of random internet noise
|
||||
|
||||
|
@ -131,6 +131,15 @@ protected virtual bool RawReceive(out ArraySegment<byte> segment)
|
||||
|
||||
try
|
||||
{
|
||||
// when using non-blocking sockets, ReceiveFrom may return WouldBlock.
|
||||
// in C#, WouldBlock throws a SocketException, which is expected.
|
||||
// unfortunately, creating the SocketException allocates in C#.
|
||||
// let's poll first to avoid the WouldBlock allocation.
|
||||
// note that this entirely to avoid allocations.
|
||||
// non-blocking UDP doesn't need Poll in other languages.
|
||||
// and the code still works without the Poll call.
|
||||
if (!socket.Poll(0, SelectMode.SelectRead)) return false;
|
||||
|
||||
// ReceiveFrom allocates. we used bound Receive.
|
||||
// returns amount of bytes written into buffer.
|
||||
// throws SocketException if datagram was larger than buffer.
|
||||
@ -166,6 +175,15 @@ protected virtual void RawSend(ArraySegment<byte> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
// when using non-blocking sockets, SendTo may return WouldBlock.
|
||||
// in C#, WouldBlock throws a SocketException, which is expected.
|
||||
// unfortunately, creating the SocketException allocates in C#.
|
||||
// let's poll first to avoid the WouldBlock allocation.
|
||||
// note that this entirely to avoid allocations.
|
||||
// non-blocking UDP doesn't need Poll in other languages.
|
||||
// and the code still works without the Poll call.
|
||||
if (!socket.Poll(0, SelectMode.SelectWrite)) return;
|
||||
|
||||
socket.Send(data.Array, data.Offset, data.Count, SocketFlags.None);
|
||||
}
|
||||
// for non-blocking sockets, SendTo may throw WouldBlock.
|
||||
|
@ -154,6 +154,15 @@ protected virtual bool RawReceiveFrom(out ArraySegment<byte> segment, out int co
|
||||
|
||||
try
|
||||
{
|
||||
// when using non-blocking sockets, ReceiveFrom may return WouldBlock.
|
||||
// in C#, WouldBlock throws a SocketException, which is expected.
|
||||
// unfortunately, creating the SocketException allocates in C#.
|
||||
// let's poll first to avoid the WouldBlock allocation.
|
||||
// note that this entirely to avoid allocations.
|
||||
// non-blocking UDP doesn't need Poll in other languages.
|
||||
// and the code still works without the Poll call.
|
||||
if (!socket.Poll(0, SelectMode.SelectRead)) return false;
|
||||
|
||||
// NOTE: ReceiveFrom allocates.
|
||||
// we pass our IPEndPoint to ReceiveFrom.
|
||||
// receive from calls newClientEP.Create(socketAddr).
|
||||
@ -206,11 +215,20 @@ protected virtual void RawSend(int connectionId, ArraySegment<byte> data)
|
||||
return;
|
||||
}
|
||||
|
||||
// send to the the endpoint.
|
||||
// do not send to 'newClientEP', as that's always reused.
|
||||
// fixes https://github.com/MirrorNetworking/Mirror/issues/3296
|
||||
try
|
||||
{
|
||||
// when using non-blocking sockets, SendTo may return WouldBlock.
|
||||
// in C#, WouldBlock throws a SocketException, which is expected.
|
||||
// unfortunately, creating the SocketException allocates in C#.
|
||||
// let's poll first to avoid the WouldBlock allocation.
|
||||
// note that this entirely to avoid allocations.
|
||||
// non-blocking UDP doesn't need Poll in other languages.
|
||||
// and the code still works without the Poll call.
|
||||
if (!socket.Poll(0, SelectMode.SelectWrite)) return;
|
||||
|
||||
// send to the the endpoint.
|
||||
// do not send to 'newClientEP', as that's always reused.
|
||||
// fixes https://github.com/MirrorNetworking/Mirror/issues/3296
|
||||
socket.SendTo(data.Array, data.Offset, data.Count, SocketFlags.None, connection.remoteEndPoint);
|
||||
}
|
||||
// for non-blocking sockets, SendTo may throw WouldBlock.
|
||||
|
Loading…
Reference in New Issue
Block a user