Low Level Preparations

This commit is contained in:
mischa 2024-09-05 12:45:22 +02:00
parent bbaece8df4
commit 5cc8050d47
8 changed files with 75 additions and 3 deletions

View File

@ -42,6 +42,16 @@ public class NetworkTransformReliable : NetworkTransformBase
// Used to store last sent snapshots
protected TransformSnapshot last;
// validation //////////////////////////////////////////////////////////
// Configure is called from OnValidate and Awake
protected override void Configure()
{
base.Configure();
// force syncMethod to reliable
syncMethod = SyncMethod.Reliable;
}
// update //////////////////////////////////////////////////////////////
void Update()
{

View File

@ -30,6 +30,16 @@ public class NetworkTransformUnreliable : NetworkTransformBase
protected Changed cachedChangedComparison;
protected bool hasSentUnchangedPosition;
// validation //////////////////////////////////////////////////////////
// Configure is called from OnValidate and Awake
protected override void Configure()
{
base.Configure();
// force syncMethod to unreliable
syncMethod = SyncMethod.Unreliable;
}
// update //////////////////////////////////////////////////////////////
// Update applies interpolation
void Update()
@ -316,7 +326,7 @@ protected virtual Changed CompareChangedSnapshots(TransformSnapshot currentSnaps
}
if (syncRotation)
{
{
if (compressRotation)
{
bool rotationChanged = Quaternion.Angle(lastSnapshot.rotation, currentSnapshot.rotation) > rotationSensitivity;
@ -459,7 +469,7 @@ protected virtual void UpdateSyncData(ref SyncData syncData, SortedList<double,
// This is to extract position/rotation/scale data from payload. Override
// Construct and Deconstruct if you are implementing a different SyncData logic.
// Note however that snapshot interpolation still requires the basic 3 data
// position, rotation and scale, which are computed from here.
// position, rotation and scale, which are computed from here.
protected virtual void DeconstructSyncData(System.ArraySegment<byte> receivedPayload, out byte? changedFlagData, out Vector3? position, out Quaternion? rotation, out Vector3? scale)
{
using (NetworkReaderPooled reader = NetworkReaderPool.Get(receivedPayload))

View File

@ -94,6 +94,7 @@ public struct ObjectHideMessage : NetworkMessage
public uint netId;
}
// state update for reliable sync
public struct EntityStateMessage : NetworkMessage
{
public uint netId;
@ -102,6 +103,15 @@ public struct EntityStateMessage : NetworkMessage
public ArraySegment<byte> payload;
}
// state update for unreliable sync
public struct EntityStateMessageUnreliable : NetworkMessage
{
public uint netId;
// the serialized component data
// -> ArraySegment to avoid unnecessary allocations
public ArraySegment<byte> payload;
}
// whoever wants to measure rtt, sends this to the other end.
public struct NetworkPingMessage : NetworkMessage
{

View File

@ -6,6 +6,11 @@
namespace Mirror
{
// SyncMethod to choose between:
// * Reliable: oldschool reliable sync every syncInterval. If nothing changes, nothing is sent.
// * Unreliable: quake style unreliable state sync & delta compression, for fast paced games.
public enum SyncMethod { Reliable, Unreliable }
// SyncMode decides if a component is synced to all observers, or only owner
public enum SyncMode { Observers, Owner }
@ -24,6 +29,9 @@ public enum SyncDirection { ServerToClient, ClientToServer }
[HelpURL("https://mirror-networking.gitbook.io/docs/guides/networkbehaviour")]
public abstract class NetworkBehaviour : MonoBehaviour
{
[Tooltip("Choose between:\n- Reliable: only sends when changed. Recommended for most games!\n- Unreliable: immediately sends at the expense of bandwidth. Only for hardcore competitive games.\nClick the Help icon for full details.")]
[HideInInspector] public SyncMethod syncMethod = SyncMethod.Reliable;
/// <summary>Sync direction for OnSerialize. ServerToClient by default. ClientToServer for client authority.</summary>
[Tooltip("Server Authority calls OnSerialize on the server and syncs it to clients.\n\nClient Authority calls OnSerialize on the owning client, syncs it to server, which then broadcasts it to all other clients.\n\nUse server authority for cheat safety.")]
[HideInInspector] public SyncDirection syncDirection = SyncDirection.ServerToClient;
@ -1077,7 +1085,7 @@ protected T GetSyncVarNetworkBehaviour<T>(NetworkBehaviourSyncVar syncNetBehavio
{
return null;
}
// ensure componentIndex is in range.
// show explicit errors if something went wrong, instead of IndexOutOfRangeException.
// removing components at runtime isn't allowed, yet this happened in a project so we need to check for it.

View File

@ -33,6 +33,12 @@ public static partial class NetworkClient
public static float sendInterval => sendRate < int.MaxValue ? 1f / sendRate : 0; // for 30 Hz, that's 33ms
static double lastSendTime;
// ocassionally send a full reliable state for unreliable components to delta compress against.
// this only applies to Components with SyncMethod=Unreliable.
public static int unreliableBaselineRate => NetworkServer.unreliableBaselineRate;
public static float unreliableBaselineInterval => unreliableBaselineRate < int.MaxValue ? 1f / unreliableBaselineRate : 0; // for 1 Hz, that's 1000ms
static double lastUnreliableBaselineTime;
// For security, it is recommended to disconnect a player if a networked
// action triggers an exception\nThis could prevent components being
// accessed in an undefined state, which may be an attack vector for
@ -1547,6 +1553,7 @@ internal static void NetworkLateUpdate()
//
// Unity 2019 doesn't have Time.timeAsDouble yet
bool sendIntervalElapsed = AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime);
bool unreliableBaselineElapsed = AccurateInterval.Elapsed(NetworkTime.localTime, unreliableBaselineInterval, ref lastUnreliableBaselineTime);
if (!Application.isPlaying || sendIntervalElapsed)
{
Broadcast();

View File

@ -42,6 +42,10 @@ public class NetworkManager : MonoBehaviour
[FormerlySerializedAs("serverTickRate")]
public int sendRate = 60;
/// <summary> </summary>
[Tooltip("Ocassionally send a full reliable state for unreliable components to delta compress against. This only applies to Components with SyncMethod=Unreliable.")]
public int unreliableBaselineRate = 1;
// Deprecated 2023-11-25
// Using SerializeField and HideInInspector to self-correct for being
// replaced by headlessStartMode. This can be removed in the future.
@ -199,6 +203,11 @@ public virtual void OnValidate()
autoConnectClientBuild = false;
#pragma warning restore 618
// unreliable full send rate needs to be >= 0.
// we need to have something to delta compress against.
// it should also be <= sendRate otherwise there's no point.
unreliableBaselineRate = Mathf.Clamp(unreliableBaselineRate, 1, sendRate);
// always >= 0
maxConnections = Mathf.Max(maxConnections, 0);
@ -308,6 +317,7 @@ bool IsServerOnlineSceneChangeNeeded() =>
void ApplyConfiguration()
{
NetworkServer.tickRate = sendRate;
NetworkServer.unreliableBaselineRate = unreliableBaselineRate;
NetworkClient.snapshotSettings = snapshotSettings;
NetworkClient.connectionQualityInterval = evaluationInterval;
NetworkClient.connectionQualityMethod = evaluationMethod;

View File

@ -54,6 +54,12 @@ public static partial class NetworkServer
public static float sendInterval => sendRate < int.MaxValue ? 1f / sendRate : 0; // for 30 Hz, that's 33ms
static double lastSendTime;
// ocassionally send a full reliable state for unreliable components to delta compress against.
// this only applies to Components with SyncMethod=Unreliable.
public static int unreliableBaselineRate = 1;
public static float unreliableBaselineInterval => unreliableBaselineRate < int.MaxValue ? 1f / unreliableBaselineRate : 0; // for 1 Hz, that's 1000ms
static double lastUnreliableBaselineTime;
/// <summary>Connection to host mode client (if any)</summary>
public static LocalConnectionToClient localConnection { get; private set; }
@ -2053,6 +2059,7 @@ internal static void NetworkLateUpdate()
// snapshots _but_ not every single tick.
// Unity 2019 doesn't have Time.timeAsDouble yet
bool sendIntervalElapsed = AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime);
bool unreliableBaselineElapsed = AccurateInterval.Elapsed(NetworkTime.localTime, unreliableBaselineInterval, ref lastUnreliableBaselineTime);
if (!Application.isPlaying || sendIntervalElapsed)
Broadcast();
}

View File

@ -94,6 +94,16 @@ protected void DrawDefaultSyncSettings()
if (syncDirection.enumValueIndex == (int)SyncDirection.ServerToClient)
EditorGUILayout.PropertyField(serializedObject.FindProperty("syncMode"));
// sync method
SerializedProperty syncMethod = serializedObject.FindProperty("syncMethod");
EditorGUILayout.PropertyField(syncMethod);
// Unreliable sync method: show a warning!
if (syncMethod.enumValueIndex == (int)SyncMethod.Unreliable)
{
EditorGUILayout.HelpBox("Beware!\nUnreliable is experimental and only meant for hardcore competitive games!", MessageType.Warning);
}
// sync interval
EditorGUILayout.PropertyField(serializedObject.FindProperty("syncInterval"));