mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 11:00:32 +00:00
Merged TestNT2-WebGL
This commit is contained in:
commit
186190e2f8
4
.github/workflows/RunUnityTests.yml
vendored
4
.github/workflows/RunUnityTests.yml
vendored
@ -13,8 +13,8 @@ jobs:
|
||||
unityVersion:
|
||||
- 2019.4.40f1
|
||||
- 2020.3.46f1
|
||||
- 2021.3.20f1
|
||||
- 2022.2.10f1
|
||||
- 2021.3.21f1
|
||||
- 2022.2.12f1
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
@ -14,27 +14,6 @@ public class NetworkDiscovery : NetworkDiscoveryBase<ServerRequest, ServerRespon
|
||||
{
|
||||
#region Server
|
||||
|
||||
public long ServerId { get; private set; }
|
||||
|
||||
[Tooltip("Transport to be advertised during discovery")]
|
||||
public Transport transport;
|
||||
|
||||
[Tooltip("Invoked when a server is found")]
|
||||
public ServerFoundUnityEvent OnServerFound;
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
ServerId = RandomLong();
|
||||
|
||||
// active transport gets initialized in awake
|
||||
// so make sure we set it here in Start() (after awakes)
|
||||
// Or just let the user assign it in the inspector
|
||||
if (transport == null)
|
||||
transport = Transport.active;
|
||||
|
||||
base.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the request from a client
|
||||
/// </summary>
|
||||
@ -68,9 +47,11 @@ protected override ServerResponse ProcessRequest(ServerRequest request, IPEndPoi
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Client
|
||||
|
||||
/// <summary>
|
||||
/// Create a message that will be broadcasted on the network to discover servers
|
||||
/// </summary>
|
||||
@ -106,6 +87,7 @@ protected override void ProcessResponse(ServerResponse response, IPEndPoint endp
|
||||
|
||||
OnServerFound.Invoke(response);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -23,33 +23,46 @@ public abstract class NetworkDiscoveryBase<Request, Response> : MonoBehaviour
|
||||
{
|
||||
public static bool SupportedOnThisPlatform { get { return Application.platform != RuntimePlatform.WebGLPlayer; } }
|
||||
|
||||
// each game should have a random unique handshake, this way you can tell if this is the same game or not
|
||||
[HideInInspector]
|
||||
public long secretHandshake;
|
||||
[SerializeField]
|
||||
[Tooltip("If true, broadcasts a discovery request every ActiveDiscoveryInterval seconds")]
|
||||
public bool enableActiveDiscovery = true;
|
||||
|
||||
// broadcast address needs to be configurable on iOS:
|
||||
// https://github.com/vis2k/Mirror/pull/3255
|
||||
[Tooltip("iOS may require LAN IP address here (e.g. 192.168.x.x), otherwise leave blank.")]
|
||||
public string BroadcastAddress = "";
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The UDP port the server will listen for multi-cast messages")]
|
||||
protected int serverBroadcastListenPort = 47777;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("If true, broadcasts a discovery request every ActiveDiscoveryInterval seconds")]
|
||||
public bool enableActiveDiscovery = true;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Time in seconds between multi-cast messages")]
|
||||
[Range(1, 60)]
|
||||
float ActiveDiscoveryInterval = 3;
|
||||
|
||||
// broadcast address needs to be configurable on iOS:
|
||||
// https://github.com/vis2k/Mirror/pull/3255
|
||||
public string BroadcastAddress = "";
|
||||
[Tooltip("Transport to be advertised during discovery")]
|
||||
public Transport transport;
|
||||
|
||||
[Tooltip("Invoked when a server is found")]
|
||||
public ServerFoundUnityEvent OnServerFound;
|
||||
|
||||
// Each game should have a random unique handshake,
|
||||
// this way you can tell if this is the same game or not
|
||||
[HideInInspector]
|
||||
public long secretHandshake;
|
||||
|
||||
public long ServerId { get; private set; }
|
||||
|
||||
protected UdpClient serverUdpClient;
|
||||
protected UdpClient clientUdpClient;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnValidate()
|
||||
public virtual void OnValidate()
|
||||
{
|
||||
if (transport == null)
|
||||
transport = GetComponent<Transport>();
|
||||
|
||||
if (secretHandshake == 0)
|
||||
{
|
||||
secretHandshake = RandomLong();
|
||||
@ -58,24 +71,32 @@ void OnValidate()
|
||||
}
|
||||
#endif
|
||||
|
||||
public static long RandomLong()
|
||||
{
|
||||
int value1 = UnityEngine.Random.Range(int.MinValue, int.MaxValue);
|
||||
int value2 = UnityEngine.Random.Range(int.MinValue, int.MaxValue);
|
||||
return value1 + ((long)value2 << 32);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// virtual so that inheriting classes' Start() can call base.Start() too
|
||||
/// </summary>
|
||||
public virtual void Start()
|
||||
{
|
||||
ServerId = RandomLong();
|
||||
|
||||
// active transport gets initialized in Awake
|
||||
// so make sure we set it here in Start() after Awake
|
||||
// Or just let the user assign it in the inspector
|
||||
if (transport == null)
|
||||
transport = Transport.active;
|
||||
|
||||
// Server mode? then start advertising
|
||||
#if UNITY_SERVER
|
||||
AdvertiseServer();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static long RandomLong()
|
||||
{
|
||||
int value1 = UnityEngine.Random.Range(int.MinValue, int.MaxValue);
|
||||
int value2 = UnityEngine.Random.Range(int.MinValue, int.MaxValue);
|
||||
return value1 + ((long)value2 << 32);
|
||||
}
|
||||
|
||||
// Ensure the ports are cleared no matter when Game/Unity UI exits
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
@ -166,9 +187,7 @@ public async Task ServerListenAsync()
|
||||
// socket has been closed
|
||||
break;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
catch (Exception) {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,6 +266,7 @@ protected virtual void ProcessClientRequest(Request request, IPEndPoint endpoint
|
||||
AndroidJavaObject multicastLock;
|
||||
bool hasMulticastLock;
|
||||
#endif
|
||||
|
||||
void BeginMulticastLock()
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
|
@ -39,17 +39,22 @@ public override void OnSpawned(NetworkIdentity identity)
|
||||
|
||||
// Match ID could have been set in NetworkBehaviour::OnStartServer on this object.
|
||||
// Since that's after OnCheckObserver is called it would be missed, so force Rebuild here.
|
||||
RebuildMatchObservers(networkMatchId);
|
||||
// Add the current match to dirtyMatches for Update to rebuild it.
|
||||
dirtyMatches.Add(networkMatchId);
|
||||
}
|
||||
|
||||
[ServerCallback]
|
||||
public override void OnDestroyed(NetworkIdentity identity)
|
||||
{
|
||||
// Don't RebuildSceneObservers here - that will happen in Update.
|
||||
// Multiple objects could be destroyed in same frame and we don't
|
||||
// want to rebuild for each one...let Update do it once.
|
||||
// We must add the current match to dirtyMatches for Update to rebuild it.
|
||||
if (lastObjectMatch.TryGetValue(identity, out Guid currentMatch))
|
||||
{
|
||||
lastObjectMatch.Remove(identity);
|
||||
if (currentMatch != Guid.Empty && matchObjects.TryGetValue(currentMatch, out HashSet<NetworkIdentity> objects) && objects.Remove(identity))
|
||||
RebuildMatchObservers(currentMatch);
|
||||
dirtyMatches.Add(currentMatch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,11 +35,15 @@ public override void OnSpawned(NetworkIdentity identity)
|
||||
[ServerCallback]
|
||||
public override void OnDestroyed(NetworkIdentity identity)
|
||||
{
|
||||
// Don't RebuildSceneObservers here - that will happen in Update.
|
||||
// Multiple objects could be destroyed in same frame and we don't
|
||||
// want to rebuild for each one...let Update do it once.
|
||||
// We must add the current scene to dirtyScenes for Update to rebuild it.
|
||||
if (lastObjectScene.TryGetValue(identity, out Scene currentScene))
|
||||
{
|
||||
lastObjectScene.Remove(identity);
|
||||
if (sceneObjects.TryGetValue(currentScene, out HashSet<NetworkIdentity> objects) && objects.Remove(identity))
|
||||
RebuildSceneObservers(currentScene);
|
||||
dirtyScenes.Add(currentScene);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,17 +35,22 @@ public override void OnSpawned(NetworkIdentity identity)
|
||||
|
||||
// Team ID could have been set in NetworkBehaviour::OnStartServer on this object.
|
||||
// Since that's after OnCheckObserver is called it would be missed, so force Rebuild here.
|
||||
RebuildTeamObservers(networkTeamId);
|
||||
// Add the current team to dirtyTeams for Update to rebuild it.
|
||||
dirtyTeams.Add(networkTeamId);
|
||||
}
|
||||
|
||||
[ServerCallback]
|
||||
public override void OnDestroyed(NetworkIdentity identity)
|
||||
{
|
||||
// Don't RebuildSceneObservers here - that will happen in Update.
|
||||
// Multiple objects could be destroyed in same frame and we don't
|
||||
// want to rebuild for each one...let Update do it once.
|
||||
// We must add the current team to dirtyTeams for Update to rebuild it.
|
||||
if (lastObjectTeam.TryGetValue(identity, out string currentTeam))
|
||||
{
|
||||
lastObjectTeam.Remove(identity);
|
||||
if (!string.IsNullOrWhiteSpace(currentTeam) && teamObjects.TryGetValue(currentTeam, out HashSet<NetworkIdentity> objects) && objects.Remove(identity))
|
||||
RebuildTeamObservers(currentTeam);
|
||||
dirtyTeams.Add(currentTeam);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,18 @@ public class NetworkTransformReliable : NetworkTransformBase
|
||||
[Header("Sync Only If Changed")]
|
||||
[Tooltip("When true, changes are not sent unless greater than sensitivity values below.")]
|
||||
public bool onlySyncOnChange = true;
|
||||
float onlySyncOnChangeInterval => onlySyncOnChangeCorrectionMultiplier * sendIntervalMultiplier;
|
||||
uint sendIntervalCounter = 0;
|
||||
double lastSendIntervalTime = double.MinValue;
|
||||
|
||||
[Tooltip("If we only sync on change, then we need to correct old snapshots if more time than sendInterval * multiplier has elapsed.\n\nOtherwise the first move will always start interpolating from the last move sequence's time, which will make it stutter when starting every time.")]
|
||||
public float onlySyncOnChangeCorrectionMultiplier = 2;
|
||||
|
||||
[Header("Send Interval Multiplier")]
|
||||
[Tooltip("Check/Sync every multiple of Network Manager send interval (= 1 / NM Send Rate), instead of every send interval.")]
|
||||
[Range(1, 120)]
|
||||
public uint sendIntervalMultiplier = 3;
|
||||
|
||||
[Header("Rotation")]
|
||||
[Tooltip("Sensitivity of changes needed before an updated state is sent over the network")]
|
||||
public float rotationSensitivity = 0.01f;
|
||||
@ -33,6 +42,10 @@ public class NetworkTransformReliable : NetworkTransformBase
|
||||
[Range(0.00_01f, 1f)] // disallow 0 division. 1mm to 1m precision is enough range.
|
||||
public float scalePrecision = 0.01f; // 1 cm
|
||||
|
||||
[Header("Snapshot Interpolation")]
|
||||
[Tooltip("Add a small timeline offset to account for decoupled arrival of NetworkTime and NetworkTransform snapshots.\nfixes: https://github.com/MirrorNetworking/Mirror/issues/3427")]
|
||||
public bool timelineOffset = false;
|
||||
|
||||
// delta compression needs to remember 'last' to compress against
|
||||
protected Vector3Long lastSerializedPosition = Vector3Long.zero;
|
||||
protected Vector3Long lastDeserializedPosition = Vector3Long.zero;
|
||||
@ -43,8 +56,9 @@ public class NetworkTransformReliable : NetworkTransformBase
|
||||
// Used to store last sent snapshots
|
||||
protected TransformSnapshot last;
|
||||
|
||||
protected int lastClientCount = 1;
|
||||
|
||||
// update //////////////////////////////////////////////////////////////
|
||||
// Update applies interpolation.
|
||||
void Update()
|
||||
{
|
||||
// if server then always sync to others.
|
||||
@ -54,18 +68,19 @@ void Update()
|
||||
else if (isClient) UpdateClient();
|
||||
}
|
||||
|
||||
// LateUpdate sets dirty.
|
||||
// movement scripts may change positions in Update.
|
||||
// use LateUpdate to ensure changes are detected in the same frame.
|
||||
// otherwise this may run before user update, delaying detection until next frame.
|
||||
// this would cause visible jitter.
|
||||
void LateUpdate()
|
||||
{
|
||||
// set dirty to trigger OnSerialize. either always, or only if changed.
|
||||
if (isServer || (IsClientWithAuthority && NetworkClient.ready)) // is NetworkClient.ready even needed?
|
||||
// It has to be checked in LateUpdate() for onlySyncOnChange to avoid
|
||||
// the possibility of Update() running first before the object's movement
|
||||
// script's Update(), which then causes NT to send every alternate frame
|
||||
// instead.
|
||||
if (isServer || (IsClientWithAuthority && NetworkClient.ready))
|
||||
{
|
||||
if (!onlySyncOnChange || Changed(Construct()))
|
||||
if (sendIntervalCounter == sendIntervalMultiplier && (!onlySyncOnChange || Changed(Construct())))
|
||||
SetDirty();
|
||||
|
||||
CheckLastSendTime();
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,6 +137,19 @@ protected virtual void UpdateClient()
|
||||
TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t);
|
||||
Apply(computed, to);
|
||||
}
|
||||
|
||||
lastClientCount = clientSnapshots.Count;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CheckLastSendTime()
|
||||
{
|
||||
// timeAsDouble not available in older Unity versions.
|
||||
if (AccurateInterval.Elapsed(NetworkTime.localTime, NetworkServer.sendInterval, ref lastSendIntervalTime))
|
||||
{
|
||||
if (sendIntervalCounter == sendIntervalMultiplier)
|
||||
sendIntervalCounter = 0;
|
||||
sendIntervalCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,6 +197,16 @@ public override void OnSerialize(NetworkWriter writer, bool initialState)
|
||||
// initial
|
||||
if (initialState)
|
||||
{
|
||||
// If there is a last serialized snapshot, we use it.
|
||||
// This prevents the new client getting a snapshot that is different
|
||||
// from what the older clients last got. If this happens, and on the next
|
||||
// regular serialisation the delta compression will get wrong values.
|
||||
// Notes:
|
||||
// 1. Interestingly only the older clients have it wrong, because at the end
|
||||
// of this function, last = snapshot which is the initial state's snapshot
|
||||
// 2. Regular NTR gets by this bug because it sends every frame anyway so initialstate
|
||||
// snapshot constructed would have been the same as the last anyway.
|
||||
if (last.remoteTime > 0) snapshot = last;
|
||||
if (syncPosition) writer.WriteVector3(snapshot.position);
|
||||
if (syncRotation)
|
||||
{
|
||||
@ -205,9 +243,6 @@ public override void OnSerialize(NetworkWriter writer, bool initialState)
|
||||
Compression.ScaleToLong(snapshot.scale, scalePrecision, out Vector3Long quantized);
|
||||
DeltaCompression.Compress(writer, lastSerializedScale, quantized);
|
||||
}
|
||||
|
||||
// int written = writer.Position - before;
|
||||
// Debug.Log($"{name} compressed to {written} bytes");
|
||||
}
|
||||
|
||||
// save serialized as 'last' for next delta compression
|
||||
@ -290,15 +325,20 @@ protected virtual void OnClientToServerSync(Vector3? position, Quaternion? rotat
|
||||
RewriteHistory(
|
||||
serverSnapshots,
|
||||
connectionToClient.remoteTimeStamp,
|
||||
NetworkTime.localTime, // arrival remote timestamp. NOT remote timeline.
|
||||
NetworkServer.sendInterval, // Unity 2019 doesn't have timeAsDouble yet
|
||||
NetworkTime.localTime, // arrival remote timestamp. NOT remote timeline.
|
||||
NetworkServer.sendInterval * sendIntervalMultiplier, // Unity 2019 doesn't have timeAsDouble yet
|
||||
target.localPosition,
|
||||
target.localRotation,
|
||||
target.localScale);
|
||||
// Debug.Log($"{name}: corrected history on server to fix initial stutter after not sending for a while.");
|
||||
}
|
||||
|
||||
AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp + NetworkServer.sendInterval, position, rotation, scale);
|
||||
// add a small timeline offset to account for decoupled arrival of
|
||||
// NetworkTime and NetworkTransform snapshots.
|
||||
// needs to be sendInterval. half sendInterval doesn't solve it.
|
||||
// https://github.com/MirrorNetworking/Mirror/issues/3427
|
||||
// remove this after LocalWorldState.
|
||||
double offset = timelineOffset ? NetworkServer.sendInterval : 0;
|
||||
AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp + offset, position, rotation, scale);
|
||||
}
|
||||
|
||||
// server broadcasts sync message to all clients
|
||||
@ -309,20 +349,25 @@ protected virtual void OnServerToClientSync(Vector3? position, Quaternion? rotat
|
||||
|
||||
// 'only sync on change' needs a correction on every new move sequence.
|
||||
if (onlySyncOnChange &&
|
||||
NeedsCorrection(clientSnapshots, NetworkClient.connection.remoteTimeStamp, NetworkClient.sendInterval, onlySyncOnChangeCorrectionMultiplier))
|
||||
NeedsCorrection(clientSnapshots, NetworkClient.connection.remoteTimeStamp, NetworkClient.sendInterval * sendIntervalMultiplier, onlySyncOnChangeInterval))
|
||||
{
|
||||
RewriteHistory(
|
||||
clientSnapshots,
|
||||
NetworkClient.connection.remoteTimeStamp, // arrival remote timestamp. NOT remote timeline.
|
||||
NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet
|
||||
NetworkClient.sendInterval,
|
||||
NetworkClient.connection.remoteTimeStamp, // arrival remote timestamp. NOT remote timeline.
|
||||
NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet
|
||||
NetworkClient.sendInterval * sendIntervalMultiplier,
|
||||
target.localPosition,
|
||||
target.localRotation,
|
||||
target.localScale);
|
||||
// Debug.Log($"{name}: corrected history on client to fix initial stutter after not sending for a while.");
|
||||
}
|
||||
|
||||
AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp + NetworkClient.sendInterval, position, rotation, scale);
|
||||
// add a small timeline offset to account for decoupled arrival of
|
||||
// NetworkTime and NetworkTransform snapshots.
|
||||
// needs to be sendInterval. half sendInterval doesn't solve it.
|
||||
// https://github.com/MirrorNetworking/Mirror/issues/3427
|
||||
// remove this after LocalWorldState.
|
||||
double offset = timelineOffset ? NetworkServer.sendInterval : 0;
|
||||
AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp + offset, position, rotation, scale);
|
||||
}
|
||||
|
||||
// only sync on change /////////////////////////////////////////////////
|
||||
|
@ -9,11 +9,12 @@ namespace Mirror
|
||||
[HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")]
|
||||
public abstract class InterestManagementBase : MonoBehaviour
|
||||
{
|
||||
// Awake configures InterestManagementBase in NetworkServer/Client
|
||||
// Configures InterestManagementBase in NetworkServer/Client
|
||||
// Do NOT check for active server or client here.
|
||||
// Awake must always set the static aoi references.
|
||||
// make sure to call base.Awake when overwriting!
|
||||
protected virtual void Awake()
|
||||
// OnEnable must always set the static aoi references.
|
||||
// make sure to call base.OnEnable when overwriting!
|
||||
// Previously used Awake()
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (NetworkServer.aoi == null)
|
||||
{
|
||||
|
@ -36,9 +36,14 @@ public abstract class NetworkBehaviour : MonoBehaviour
|
||||
/// <summary>sync interval for OnSerialize (in seconds)</summary>
|
||||
// hidden because NetworkBehaviourInspector shows it only if has OnSerialize.
|
||||
// [0,2] should be enough. anything >2s is too laggy anyway.
|
||||
//
|
||||
// NetworkServer & NetworkClient broadcast() are behind a sendInterval timer now.
|
||||
// it makes sense to keep every component's syncInterval setting at '0' by default.
|
||||
// otherwise, the overlapping timers could introduce unexpected latency.
|
||||
// careful: default of '0.1' may
|
||||
[Tooltip("Time in seconds until next change is synchronized to the client. '0' means send immediately if changed. '0.5' means only send changes every 500ms.\n(This is for state synchronization like SyncVars, SyncLists, OnSerialize. Not for Cmds, Rpcs, etc.)")]
|
||||
[Range(0, 2)]
|
||||
[HideInInspector] public float syncInterval = 0.1f;
|
||||
[HideInInspector] public float syncInterval = 0;
|
||||
internal double lastSyncTime;
|
||||
|
||||
/// <summary>True if this object is on the server and has been spawned.</summary>
|
||||
|
@ -1692,7 +1692,7 @@ public static void OnGUI()
|
||||
// only if in world
|
||||
if (!ready) return;
|
||||
|
||||
GUILayout.BeginArea(new Rect(10, 5, 500, 50));
|
||||
GUILayout.BeginArea(new Rect(10, 5, 800, 50));
|
||||
|
||||
GUILayout.BeginHorizontal("Box");
|
||||
GUILayout.Label("Snapshot Interp.:");
|
||||
@ -1702,8 +1702,11 @@ public static void OnGUI()
|
||||
else GUI.color = Color.white;
|
||||
GUILayout.Box($"timeline: {localTimeline:F2}");
|
||||
GUILayout.Box($"buffer: {snapshots.Count}");
|
||||
GUILayout.Box($"DriftEMA: {NetworkClient.driftEma.Value:F2}");
|
||||
GUILayout.Box($"DelTimeEMA: {NetworkClient.deliveryTimeEma.Value:F2}");
|
||||
GUILayout.Box($"timescale: {localTimescale:F2}");
|
||||
GUILayout.Box($"BTM: {snapshotSettings.bufferTimeMultiplier:F2}");
|
||||
GUILayout.Box($"RTT: {NetworkTime.rtt * 1000:000}");
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.EndArea();
|
||||
|
@ -43,7 +43,7 @@ public static partial class NetworkClient
|
||||
|
||||
// catchup / slowdown adjustments are applied to timescale,
|
||||
// to be adjusted in every update instead of when receiving messages.
|
||||
internal static double localTimescale = 1;
|
||||
public static double localTimescale = 1;
|
||||
|
||||
// catchup /////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -540,14 +540,6 @@ void FinishStartHost()
|
||||
public void StopHost()
|
||||
{
|
||||
OnStopHost();
|
||||
|
||||
// calling OnTransportDisconnected was needed to fix
|
||||
// https://github.com/vis2k/Mirror/issues/1515
|
||||
// so that the host client receives a DisconnectMessage
|
||||
// TODO reevaluate if this is still needed after all the disconnect
|
||||
// fixes, and try to put this into LocalConnection.Disconnect!
|
||||
NetworkServer.OnTransportDisconnected(NetworkConnection.LocalConnectionId);
|
||||
|
||||
StopClient();
|
||||
StopServer();
|
||||
}
|
||||
@ -600,6 +592,12 @@ public void StopClient()
|
||||
if (mode == NetworkManagerMode.Offline)
|
||||
return;
|
||||
|
||||
// For Host client, call OnServerDisconnect before NetworkClient.Disconnect
|
||||
// because we need NetworkServer.localConnection to not be null
|
||||
// NetworkClient.Disconnect will set it null.
|
||||
if (mode == NetworkManagerMode.Host)
|
||||
OnServerDisconnect(NetworkServer.localConnection);
|
||||
|
||||
// ask client -> transport to disconnect.
|
||||
// handle voluntary and involuntary disconnects in OnClientDisconnect.
|
||||
//
|
||||
|
@ -129,14 +129,17 @@ public static ArraySegment<byte> ReadBytesAndSizeSegment(this NetworkReader read
|
||||
public static Quaternion ReadQuaternion(this NetworkReader reader) => reader.ReadBlittable<Quaternion>();
|
||||
public static Quaternion? ReadQuaternionNullable(this NetworkReader reader) => reader.ReadBlittableNullable<Quaternion>();
|
||||
|
||||
public static Rect ReadRect(this NetworkReader reader) => reader.ReadBlittable<Rect>();
|
||||
public static Rect? ReadRectNullable(this NetworkReader reader) => reader.ReadBlittableNullable<Rect>();
|
||||
// Rect is a struct with properties instead of fields
|
||||
public static Rect ReadRect(this NetworkReader reader) => new Rect(reader.ReadVector2(), reader.ReadVector2());
|
||||
public static Rect? ReadRectNullable(this NetworkReader reader) => reader.ReadBool() ? ReadRect(reader) : default(Rect?);
|
||||
|
||||
public static Plane ReadPlane(this NetworkReader reader) => reader.ReadBlittable<Plane>();
|
||||
public static Plane? ReadPlaneNullable(this NetworkReader reader) => reader.ReadBlittableNullable<Plane>();
|
||||
// Plane is a struct with properties instead of fields
|
||||
public static Plane ReadPlane(this NetworkReader reader) => new Plane(reader.ReadVector3(), reader.ReadFloat());
|
||||
public static Plane? ReadPlaneNullable(this NetworkReader reader) => reader.ReadBool() ? ReadPlane(reader) : default(Plane?);
|
||||
|
||||
public static Ray ReadRay(this NetworkReader reader) => reader.ReadBlittable<Ray>();
|
||||
public static Ray? ReadRayNullable(this NetworkReader reader) => reader.ReadBlittableNullable<Ray>();
|
||||
// Ray is a struct with properties instead of fields
|
||||
public static Ray ReadRay(this NetworkReader reader) => new Ray(reader.ReadVector3(), reader.ReadVector3());
|
||||
public static Ray? ReadRayNullable(this NetworkReader reader) => reader.ReadBool() ? ReadRay(reader) : default(Ray?);
|
||||
|
||||
public static Matrix4x4 ReadMatrix4x4(this NetworkReader reader) => reader.ReadBlittable<Matrix4x4>();
|
||||
public static Matrix4x4? ReadMatrix4x4Nullable(this NetworkReader reader) => reader.ReadBlittableNullable<Matrix4x4>();
|
||||
@ -335,11 +338,7 @@ public static Sprite ReadSprite(this NetworkReader reader)
|
||||
return Sprite.Create(texture, reader.ReadRect(), reader.ReadVector2());
|
||||
}
|
||||
|
||||
public static DateTime ReadDateTime(this NetworkReader reader)
|
||||
{
|
||||
return DateTime.FromOADate(reader.ReadDouble());
|
||||
}
|
||||
|
||||
public static DateTime ReadDateTime(this NetworkReader reader) => DateTime.FromOADate(reader.ReadDouble());
|
||||
public static DateTime? ReadDateTimeNullable(this NetworkReader reader) => reader.ReadBool() ? ReadDateTime(reader) : default(DateTime?);
|
||||
}
|
||||
}
|
||||
|
@ -166,14 +166,44 @@ public static void WriteArraySegment<T>(this NetworkWriter writer, ArraySegment<
|
||||
public static void WriteQuaternion(this NetworkWriter writer, Quaternion value) => writer.WriteBlittable(value);
|
||||
public static void WriteQuaternionNullable(this NetworkWriter writer, Quaternion? value) => writer.WriteBlittableNullable(value);
|
||||
|
||||
public static void WriteRect(this NetworkWriter writer, Rect value) => writer.WriteBlittable(value);
|
||||
public static void WriteRectNullable(this NetworkWriter writer, Rect? value) => writer.WriteBlittableNullable(value);
|
||||
// Rect is a struct with properties instead of fields
|
||||
public static void WriteRect(this NetworkWriter writer, Rect value)
|
||||
{
|
||||
writer.WriteVector2(value.position);
|
||||
writer.WriteVector2(value.size);
|
||||
}
|
||||
public static void WriteRectNullable(this NetworkWriter writer, Rect? value)
|
||||
{
|
||||
writer.WriteBool(value.HasValue);
|
||||
if (value.HasValue)
|
||||
writer.WriteRect(value.Value);
|
||||
}
|
||||
|
||||
public static void WritePlane(this NetworkWriter writer, Plane value) => writer.WriteBlittable(value);
|
||||
public static void WritePlaneNullable(this NetworkWriter writer, Plane? value) => writer.WriteBlittableNullable(value);
|
||||
// Plane is a struct with properties instead of fields
|
||||
public static void WritePlane(this NetworkWriter writer, Plane value)
|
||||
{
|
||||
writer.WriteVector3(value.normal);
|
||||
writer.WriteFloat(value.distance);
|
||||
}
|
||||
public static void WritePlaneNullable(this NetworkWriter writer, Plane? value)
|
||||
{
|
||||
writer.WriteBool(value.HasValue);
|
||||
if (value.HasValue)
|
||||
writer.WritePlane(value.Value);
|
||||
}
|
||||
|
||||
public static void WriteRay(this NetworkWriter writer, Ray value) => writer.WriteBlittable(value);
|
||||
public static void WriteRayNullable(this NetworkWriter writer, Ray? value) => writer.WriteBlittableNullable(value);
|
||||
// Ray is a struct with properties instead of fields
|
||||
public static void WriteRay(this NetworkWriter writer, Ray value)
|
||||
{
|
||||
writer.WriteVector3(value.origin);
|
||||
writer.WriteVector3(value.direction);
|
||||
}
|
||||
public static void WriteRayNullable(this NetworkWriter writer, Ray? value)
|
||||
{
|
||||
writer.WriteBool(value.HasValue);
|
||||
if (value.HasValue)
|
||||
writer.WriteRay(value.Value);
|
||||
}
|
||||
|
||||
public static void WriteMatrix4x4(this NetworkWriter writer, Matrix4x4 value) => writer.WriteBlittable(value);
|
||||
public static void WriteMatrix4x4Nullable(this NetworkWriter writer, Matrix4x4? value) => writer.WriteBlittableNullable(value);
|
||||
|
@ -127,8 +127,8 @@ public static double TimelineClamp(
|
||||
// we define a boundary of 'bufferTime' around the target time.
|
||||
// this is where catchup / slowdown will happen.
|
||||
// outside of the area, we clamp.
|
||||
double lowerBound = targetTime - bufferTime;
|
||||
double upperBound = targetTime + bufferTime;
|
||||
double lowerBound = targetTime - bufferTime; // how far behind we can get
|
||||
double upperBound = targetTime + bufferTime; // how far ahead we can get
|
||||
return Mathd.Clamp(localTimeline, lowerBound, upperBound);
|
||||
}
|
||||
|
||||
|
@ -28,11 +28,11 @@ public class SnapshotInterpolationSettings
|
||||
|
||||
[Tooltip("Local timeline acceleration in % while catching up.")]
|
||||
[Range(0, 1)]
|
||||
public double catchupSpeed = 0.01f; // 1%
|
||||
public double catchupSpeed = 0.02f; // see snap interp demo. 1% is too slow.
|
||||
|
||||
[Tooltip("Local timeline slowdown in % while slowing down.")]
|
||||
[Range(0, 1)]
|
||||
public double slowdownSpeed = 0.01f; // 1%
|
||||
public double slowdownSpeed = 0.04f; // slow down a little faster so we don't encounter empty buffer (= jitter)
|
||||
|
||||
[Tooltip("Catchup/Slowdown is adjusted over n-second exponential moving average.")]
|
||||
public int driftEmaDuration = 1; // shouldn't need to modify this, but expose it anyway
|
||||
|
@ -368,8 +368,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
@ -438,9 +438,9 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 363a8867bb9c7b845a73233566df8c1e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
speed: 1
|
||||
fadeImage: {fileID: 1040404845}
|
||||
fadeColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
stepRate: 2
|
||||
--- !u!114 &1300359892
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -7,20 +7,39 @@ namespace Mirror.Examples.AdditiveLevels
|
||||
public class FadeInOut : MonoBehaviour
|
||||
{
|
||||
// set these in the inspector
|
||||
[Range(1, 100), Tooltip("Speed of fade in / out: lower is slower")]
|
||||
public byte speed = 1;
|
||||
|
||||
[Tooltip("Reference to Image component on child panel")]
|
||||
public Image fadeImage;
|
||||
|
||||
[Tooltip("Color to use during scene transition")]
|
||||
public Color fadeColor = Color.black;
|
||||
|
||||
WaitForSeconds waitForSeconds;
|
||||
[Range(1, 100), Tooltip("Rate of fade in / out: higher is faster")]
|
||||
public byte stepRate = 2;
|
||||
|
||||
void Awake()
|
||||
float step;
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
waitForSeconds = new WaitForSeconds(speed * 0.01f);
|
||||
if (fadeImage == null)
|
||||
fadeImage = GetComponentInChildren<Image>();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
// Convert user-friendly setting value to working value
|
||||
step = stepRate * 0.001f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates FadeIn / FadeOut time.
|
||||
/// </summary>
|
||||
/// <returns>Duration in seconds</returns>
|
||||
public float GetDuration()
|
||||
{
|
||||
float frames = 1 / step;
|
||||
float frameRate = Time.deltaTime;
|
||||
float duration = frames * frameRate * 0.1f;
|
||||
return duration;
|
||||
}
|
||||
|
||||
public IEnumerator FadeIn()
|
||||
@ -29,8 +48,8 @@ public IEnumerator FadeIn()
|
||||
|
||||
while (alpha < 1)
|
||||
{
|
||||
yield return waitForSeconds;
|
||||
alpha += 0.01f;
|
||||
yield return null;
|
||||
alpha += step;
|
||||
fadeColor.a = alpha;
|
||||
fadeImage.color = fadeColor;
|
||||
}
|
||||
@ -42,8 +61,8 @@ public IEnumerator FadeOut()
|
||||
|
||||
while (alpha > 0)
|
||||
{
|
||||
yield return waitForSeconds;
|
||||
alpha -= 0.01f;
|
||||
yield return null;
|
||||
alpha -= step;
|
||||
fadeColor.a = alpha;
|
||||
fadeImage.color = fadeColor;
|
||||
}
|
||||
|
@ -25,9 +25,6 @@ public void OnLabelTextChanged(string _, string newValue)
|
||||
label.text = labelText;
|
||||
}
|
||||
|
||||
// This is approximately the fade time
|
||||
WaitForSeconds waitForFade = new WaitForSeconds(2f);
|
||||
|
||||
public override void OnStartServer()
|
||||
{
|
||||
labelText = Path.GetFileNameWithoutExtension(destinationScene);
|
||||
@ -68,7 +65,7 @@ IEnumerator SendPlayerToNewScene(GameObject player)
|
||||
// Tell client to unload previous subscene. No custom handling for this.
|
||||
conn.Send(new SceneMessage { sceneName = gameObject.scene.path, sceneOperation = SceneOperation.UnloadAdditive, customHandling = true });
|
||||
|
||||
yield return waitForFade;
|
||||
yield return new WaitForSeconds(AdditiveLevelsNetworkManager.singleton.fadeInOut.GetDuration());
|
||||
|
||||
NetworkServer.RemovePlayerForConnection(conn, false);
|
||||
|
||||
|
@ -1970,8 +1970,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -216,8 +216,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -354,8 +354,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -355,8 +355,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -3278,8 +3278,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -501,12 +501,11 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: c761308e733c51245b2e8bb4201f46dc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
secretHandshake: 1558261479176021378
|
||||
serverBroadcastListenPort: 47777
|
||||
enableActiveDiscovery: 1
|
||||
ActiveDiscoveryInterval: 3
|
||||
BroadcastAddress:
|
||||
transport: {fileID: 0}
|
||||
serverBroadcastListenPort: 47777
|
||||
ActiveDiscoveryInterval: 3
|
||||
transport: {fileID: 1556883244}
|
||||
OnServerFound:
|
||||
m_PersistentCalls:
|
||||
m_Calls:
|
||||
@ -522,6 +521,7 @@ MonoBehaviour:
|
||||
m_StringArgument:
|
||||
m_BoolArgument: 0
|
||||
m_CallState: 2
|
||||
secretHandshake: 1558261479176021378
|
||||
--- !u!1 &1611696151
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -276,8 +276,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -1198,8 +1198,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -904,8 +904,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -990,8 +990,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -278,8 +278,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -52,6 +52,10 @@ public class ClientCube : MonoBehaviour
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// show vsync reminder. too easy to forget.
|
||||
Debug.Log("Reminder: Snapshot interpolation is smoothest & easiest to debug with Vsync off.");
|
||||
|
||||
|
||||
defaultColor = render.sharedMaterial.color;
|
||||
|
||||
// initialize EMA with 'emaDuration' seconds worth of history.
|
||||
@ -173,14 +177,37 @@ void OnGUI()
|
||||
{
|
||||
lowFpsMode = !lowFpsMode;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 100ms behind"))
|
||||
|
||||
GUILayout.Label("|");
|
||||
|
||||
if (GUILayout.Button("Timeline 10s behind"))
|
||||
{
|
||||
localTimeline -= 10.0;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 1s behind"))
|
||||
{
|
||||
localTimeline -= 1.0;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 0.1s behind"))
|
||||
{
|
||||
localTimeline -= 0.1;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 100ms ahead"))
|
||||
|
||||
GUILayout.Label("|");
|
||||
|
||||
if (GUILayout.Button("Timeline 0.1s ahead"))
|
||||
{
|
||||
localTimeline += 0.1;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 1s ahead"))
|
||||
{
|
||||
localTimeline += 1.0;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 10s ahead"))
|
||||
{
|
||||
localTimeline += 10.0;
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.EndArea();
|
||||
|
@ -175,8 +175,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -481,8 +481,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
|
@ -9,7 +9,9 @@ Material:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Bot
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ValidKeywords: []
|
||||
m_ValidKeywords:
|
||||
- _GLOSSYREFLECTIONS_OFF
|
||||
- _SPECULARHIGHLIGHTS_OFF
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
@ -63,14 +65,14 @@ Material:
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Glossiness: 1
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SpecularHighlights: 0
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
|
@ -9,7 +9,9 @@ Material:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: BotNinja
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ValidKeywords: []
|
||||
m_ValidKeywords:
|
||||
- _GLOSSYREFLECTIONS_OFF
|
||||
- _SPECULARHIGHLIGHTS_OFF
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
@ -63,18 +65,18 @@ Material:
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Glossiness: 1
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SpecularHighlights: 0
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _Color: {r: 0.3301887, g: 0.029592374, b: 0.029592374, a: 1}
|
||||
- _Color: {r: 0.4716981, g: 0.006674961, b: 0.006674961, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
|
@ -9,6 +9,6 @@ PhysicMaterial:
|
||||
m_Name: Ice
|
||||
dynamicFriction: 0
|
||||
staticFriction: 0
|
||||
bounciness: 0.8
|
||||
bounciness: 0
|
||||
frictionCombine: 0
|
||||
bounceCombine: 0
|
||||
|
@ -9,7 +9,9 @@ Material:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: NPC
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ValidKeywords: []
|
||||
m_ValidKeywords:
|
||||
- _GLOSSYREFLECTIONS_OFF
|
||||
- _SPECULARHIGHLIGHTS_OFF
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
@ -63,14 +65,14 @@ Material:
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Glossiness: 1
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SpecularHighlights: 0
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
|
@ -9,7 +9,9 @@ Material:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: NPCNinja
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ValidKeywords: []
|
||||
m_ValidKeywords:
|
||||
- _GLOSSYREFLECTIONS_OFF
|
||||
- _SPECULARHIGHLIGHTS_OFF
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
@ -63,14 +65,14 @@ Material:
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Glossiness: 1
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SpecularHighlights: 0
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
|
@ -9,7 +9,9 @@ Material:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Player
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ValidKeywords: []
|
||||
m_ValidKeywords:
|
||||
- _GLOSSYREFLECTIONS_OFF
|
||||
- _SPECULARHIGHLIGHTS_OFF
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
@ -63,14 +65,14 @@ Material:
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Glossiness: 1
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SpecularHighlights: 0
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
|
@ -9,7 +9,9 @@ Material:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: PlayerNinja
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ValidKeywords: []
|
||||
m_ValidKeywords:
|
||||
- _GLOSSYREFLECTIONS_OFF
|
||||
- _SPECULARHIGHLIGHTS_OFF
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
@ -63,14 +65,14 @@ Material:
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Glossiness: 1
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SpecularHighlights: 0
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
725
Assets/Mirror/Examples/TestNT/Prefabs/PlayerUI.prefab
Normal file
725
Assets/Mirror/Examples/TestNT/Prefabs/PlayerUI.prefab
Normal file
@ -0,0 +1,725 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1617743760159216337
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5138658761349128847}
|
||||
m_Layer: 6
|
||||
m_Name: PlayerUI
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &5138658761349128847
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1617743760159216337}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 7957892404843774757}
|
||||
- {fileID: 7871618011363428555}
|
||||
- {fileID: 5401498466654688564}
|
||||
- {fileID: 6998545687844345781}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &3217452122434572523
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7957892404843774757}
|
||||
- component: {fileID: 4793196872081777735}
|
||||
- component: {fileID: 7544400784984079118}
|
||||
m_Layer: 6
|
||||
m_Name: NameText
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7957892404843774757
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3217452122434572523}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 5138658761349128847}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 1.7}
|
||||
m_SizeDelta: {x: 2, y: 0.3}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!23 &4793196872081777735
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3217452122434572523}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!114 &7544400784984079118
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3217452122434572523}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Player Name
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4280953563
|
||||
m_fontColor: {r: 0.8584906, g: 0.16602883, b: 0.16602883, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 1
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 2
|
||||
m_fontSizeBase: 2
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 1
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 0
|
||||
m_parseCtrlCharacters: 0
|
||||
m_isOrthographic: 0
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
_SortingLayer: 0
|
||||
_SortingLayerID: 0
|
||||
_SortingOrder: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_renderer: {fileID: 4793196872081777735}
|
||||
m_maskType: 0
|
||||
--- !u!1 &4941179751968018183
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6998545687844345781}
|
||||
- component: {fileID: 1220920522994516749}
|
||||
- component: {fileID: 4867227432556263592}
|
||||
m_Layer: 6
|
||||
m_Name: SnapIntText
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
--- !u!224 &6998545687844345781
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4941179751968018183}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 5138658761349128847}
|
||||
m_RootOrder: 3
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 2.25}
|
||||
m_SizeDelta: {x: 3, y: 0.75}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!23 &1220920522994516749
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4941179751968018183}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!114 &4867227432556263592
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4941179751968018183}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text:
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4278222848
|
||||
m_fontColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 1
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 2
|
||||
m_fontSizeBase: 2
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 1
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 0
|
||||
m_parseCtrlCharacters: 0
|
||||
m_isOrthographic: 0
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
_SortingLayer: 0
|
||||
_SortingLayerID: 0
|
||||
_SortingOrder: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_renderer: {fileID: 1220920522994516749}
|
||||
m_maskType: 0
|
||||
--- !u!1 &5178696367814392844
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5401498466654688564}
|
||||
- component: {fileID: 9218990128522613023}
|
||||
- component: {fileID: 8616963137272446910}
|
||||
m_Layer: 6
|
||||
m_Name: ServerBufferText
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
--- !u!224 &5401498466654688564
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5178696367814392844}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 5138658761349128847}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 1.2}
|
||||
m_SizeDelta: {x: 1.2, y: 0.25}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!23 &9218990128522613023
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5178696367814392844}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!114 &8616963137272446910
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5178696367814392844}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: 'S:'
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4278222848
|
||||
m_fontColor: {r: 0, g: 0.5019608, b: 0, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 1
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 2
|
||||
m_fontSizeBase: 2
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 1
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 0
|
||||
m_parseCtrlCharacters: 0
|
||||
m_isOrthographic: 0
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
_SortingLayer: 0
|
||||
_SortingLayerID: 0
|
||||
_SortingOrder: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_renderer: {fileID: 9218990128522613023}
|
||||
m_maskType: 0
|
||||
--- !u!1 &7371602426383271830
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7871618011363428555}
|
||||
- component: {fileID: 4977190152561775245}
|
||||
- component: {fileID: 3051119147354379199}
|
||||
m_Layer: 6
|
||||
m_Name: ClientBufferText
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7871618011363428555
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7371602426383271830}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 5138658761349128847}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 1.4}
|
||||
m_SizeDelta: {x: 1.2, y: 0.25}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!23 &4977190152561775245
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7371602426383271830}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!114 &3051119147354379199
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7371602426383271830}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: 'C:'
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4278222848
|
||||
m_fontColor: {r: 0, g: 0.5019608, b: 0, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 1
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 2
|
||||
m_fontSizeBase: 2
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 1
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 0
|
||||
m_parseCtrlCharacters: 0
|
||||
m_isOrthographic: 0
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
_SortingLayer: 0
|
||||
_SortingLayerID: 0
|
||||
_SortingOrder: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_renderer: {fileID: 4977190152561775245}
|
||||
m_maskType: 0
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 046d8acb77037cb439b4a45198e2bdb5
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -446,8 +446,8 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
@ -455,8 +455,8 @@ MonoBehaviour:
|
||||
timeInterpolationGui: 1
|
||||
playerNinjaPrefab: {fileID: 9193589764031967748, guid: 7903ea74806680c4f9f3a62da96765c2, type: 3}
|
||||
botPrefab: {fileID: 629047657802428152, guid: 45e99b6415bfdc846bbbfc2d949d53f5, type: 3}
|
||||
npcPrefab: {fileID: 9078678990242496461, guid: 41855c7cf63a3dc45ac8a93b4e2ecd54, type: 3}
|
||||
botNinjaPrefab: {fileID: 2972877558187846166, guid: 186c06a2be59cc84db82de14fccac374, type: 3}
|
||||
npcPrefab: {fileID: 9078678990242496461, guid: 41855c7cf63a3dc45ac8a93b4e2ecd54, type: 3}
|
||||
npcNinjaPrefab: {fileID: 388172571495221481, guid: 4f67582aaba8f814cae98c38f4e9782d, type: 3}
|
||||
--- !u!114 &821201136
|
||||
MonoBehaviour:
|
||||
|
@ -212,7 +212,6 @@ GameObject:
|
||||
- component: {fileID: 821201138}
|
||||
- component: {fileID: 821201136}
|
||||
- component: {fileID: 821201140}
|
||||
- component: {fileID: 821201139}
|
||||
- component: {fileID: 821201141}
|
||||
- component: {fileID: 821201142}
|
||||
m_Layer: 0
|
||||
@ -239,7 +238,7 @@ MonoBehaviour:
|
||||
handshakeMaxSize: 3000
|
||||
noDelay: 1
|
||||
sendTimeout: 5000
|
||||
receiveTimeout: 20000
|
||||
receiveTimeout: 60000
|
||||
serverMaxMessagesPerTick: 10000
|
||||
clientMaxMessagesPerTick: 2000
|
||||
batchSend: 0
|
||||
@ -280,17 +279,18 @@ MonoBehaviour:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.009999999776482582
|
||||
slowdownSpeed: 0.009999999776482582
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
deliveryTimeEmaDuration: 2
|
||||
timeInterpolationGui: 1
|
||||
playerNinjaPrefab: {fileID: 1428992836745641328, guid: 4b4e4d1a8090c7a45bab0cbc52ccfd76, type: 3}
|
||||
botPrefab: {fileID: 297236141164807331, guid: daa43d6577eba4240807391d6c63ea8d, type: 3}
|
||||
botPrefab: {fileID: 629047657802428152, guid: 45e99b6415bfdc846bbbfc2d949d53f5, type: 3}
|
||||
npcPrefab: {fileID: 9078678990242496461, guid: 41855c7cf63a3dc45ac8a93b4e2ecd54, type: 3}
|
||||
botNinjaPrefab: {fileID: 2972877558187846166, guid: 186c06a2be59cc84db82de14fccac374, type: 3}
|
||||
npcPrefab: {fileID: 9078678990242496461, guid: 41855c7cf63a3dc45ac8a93b4e2ecd54, type: 3}
|
||||
npcNinjaPrefab: {fileID: 388172571495221481, guid: 4f67582aaba8f814cae98c38f4e9782d, type: 3}
|
||||
--- !u!114 &821201136
|
||||
MonoBehaviour:
|
||||
@ -343,22 +343,6 @@ MonoBehaviour:
|
||||
useNinja: 1
|
||||
isBot: 0
|
||||
multiplier: 3
|
||||
--- !u!114 &821201139
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 821201133}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: bc654f29862fc2643b948f772ebb9e68, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
color: {r: 1, g: 1, b: 1, a: 1}
|
||||
padding: 50
|
||||
width: 100
|
||||
height: 25
|
||||
--- !u!114 &821201140
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -288,7 +288,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
m_IsActive: 1
|
||||
--- !u!65 &397708575
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -359,14 +359,14 @@ Transform:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 397708574}
|
||||
m_LocalRotation: {x: -0.21643952, y: 0, z: 0, w: 0.97629607}
|
||||
m_LocalPosition: {x: -2, y: 1.2, z: 8}
|
||||
m_LocalScale: {x: 3, y: 0.1, z: 6}
|
||||
m_LocalRotation: {x: -0.09229599, y: 0.7010574, z: 0.09229599, w: 0.7010574}
|
||||
m_LocalPosition: {x: 3, y: 0.35, z: 25.65}
|
||||
m_LocalScale: {x: 3, y: 0.1, z: 3}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 5
|
||||
m_LocalEulerAnglesHint: {x: -25, y: 0, z: 0}
|
||||
m_LocalEulerAnglesHint: {x: -15, y: 90, z: 0}
|
||||
--- !u!54 &397708579
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -586,6 +586,120 @@ MonoBehaviour:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_MaxRayIntersections: 0
|
||||
--- !u!1 &2051442530
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2051442535}
|
||||
- component: {fileID: 2051442534}
|
||||
- component: {fileID: 2051442533}
|
||||
- component: {fileID: 2051442532}
|
||||
- component: {fileID: 2051442531}
|
||||
m_Layer: 0
|
||||
m_Name: Ramp
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!54 &2051442531
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2051442530}
|
||||
serializedVersion: 2
|
||||
m_Mass: 1
|
||||
m_Drag: 0
|
||||
m_AngularDrag: 0.05
|
||||
m_UseGravity: 1
|
||||
m_IsKinematic: 1
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 0
|
||||
--- !u!65 &2051442532
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2051442530}
|
||||
m_Material: {fileID: 13400000, guid: c3ac683db06890b49a15dd5009dbd6e8, type: 2}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_Size: {x: 1, y: 1, z: 1}
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &2051442533
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2051442530}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!33 &2051442534
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2051442530}
|
||||
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!4 &2051442535
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2051442530}
|
||||
m_LocalRotation: {x: 0.09229593, y: 0.7010574, z: -0.09229593, w: 0.7010574}
|
||||
m_LocalPosition: {x: 0, y: 0.35, z: -19.21}
|
||||
m_LocalScale: {x: 3, y: 0.1, z: 3}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 6
|
||||
m_LocalEulerAnglesHint: {x: 15, y: 90, z: 0}
|
||||
--- !u!1 &2122508970
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Mirror;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TestNT
|
||||
{
|
||||
@ -38,12 +39,19 @@ void Update()
|
||||
[Command]
|
||||
void CmdSpawnNPC()
|
||||
{
|
||||
//GameObject npc = Instantiate(TestNTNetworkManager.singleton.npcPrefab);
|
||||
//npc.GetComponent<PlayerName>().playerName = "NPC";
|
||||
//npc.GetComponent<CharacterController>().enabled = true;
|
||||
//npc.GetComponent<PlayerMove>().enabled = true;
|
||||
//NetworkServer.Spawn(npc);
|
||||
//NpcList.Add(npc);
|
||||
StartCoroutine(SpawnNPC());
|
||||
}
|
||||
|
||||
IEnumerator SpawnNPC()
|
||||
{
|
||||
GameObject npc = Instantiate(TestNTNetworkManager.singleton.npcPrefab);
|
||||
npc.GetComponent<PlayerName>().playerName = "NPC";
|
||||
npc.GetComponent<CharacterController>().enabled = true;
|
||||
npc.GetComponent<PlayerMove>().enabled = true;
|
||||
NetworkServer.Spawn(npc);
|
||||
NpcList.Add(npc);
|
||||
|
||||
yield return new WaitForSeconds(.3f);
|
||||
|
||||
GameObject npcNinja = Instantiate(TestNTNetworkManager.singleton.npcNinjaPrefab);
|
||||
npcNinja.GetComponent<PlayerName>().playerName = "NPC-Ninja";
|
||||
|
@ -6,20 +6,17 @@
|
||||
|
||||
public class NTRCustomSendInterval : NetworkTransformBase
|
||||
{
|
||||
uint sendIntervalCounter = 0;
|
||||
double lastSendIntervalTime = double.MinValue;
|
||||
|
||||
float onlySyncOnChangeInterval => onlySyncOnChangeCorrectionMultiplier * sendIntervalMultiplier;
|
||||
|
||||
[Header("Sync Only If Changed")]
|
||||
[Tooltip("When true, changes are not sent unless greater than sensitivity values below.")]
|
||||
public bool onlySyncOnChange = true;
|
||||
float onlySyncOnChangeInterval => onlySyncOnChangeCorrectionMultiplier * sendIntervalMultiplier;
|
||||
|
||||
[Tooltip("If we only sync on change, then we need to correct old snapshots if more time than sendInterval * multiplier has elapsed.\n\nOtherwise the first move will always start interpolating from the last move sequence's time, which will make it stutter when starting every time.")]
|
||||
public float onlySyncOnChangeCorrectionMultiplier = 2;
|
||||
|
||||
// uint so non negative.
|
||||
[Header("Send Interval Multiplier")]
|
||||
[Tooltip("Send every multiple of Network Manager send interval (= 1 / NM Send Rate).")]
|
||||
[Tooltip("Check/Sync every multiple of Network Manager send interval (= 1 / NM Send Rate), instead of every send interval.")]
|
||||
[Range(1, 120)]
|
||||
public uint sendIntervalMultiplier = 3;
|
||||
|
||||
[Header("Rotation")]
|
||||
@ -47,6 +44,9 @@ public class NTRCustomSendInterval : NetworkTransformBase
|
||||
public Vector3 velocity;
|
||||
public Vector3 angVelocity;
|
||||
|
||||
uint sendIntervalCounter = 0;
|
||||
double lastSendIntervalTime = double.MinValue;
|
||||
|
||||
// delta compression needs to remember 'last' to compress against
|
||||
protected Vector3Long lastSerializedPosition = Vector3Long.zero;
|
||||
protected Vector3Long lastDeserializedPosition = Vector3Long.zero;
|
||||
@ -76,7 +76,7 @@ void LateUpdate()
|
||||
// the possibility of Update() running first before the object's movement
|
||||
// script's Update(), which then causes NT to send every alternate frame
|
||||
// instead.
|
||||
if (isServer || (IsClientWithAuthority && NetworkClient.ready)) // is NetworkClient.ready even needed?
|
||||
if (isServer || (IsClientWithAuthority && NetworkClient.ready))
|
||||
{
|
||||
if (sendIntervalCounter == sendIntervalMultiplier && (!onlySyncOnChange || Changed(Construct())))
|
||||
SetDirty();
|
||||
@ -167,23 +167,23 @@ protected virtual void UpdateClient()
|
||||
|
||||
protected virtual void CheckLastSendTime()
|
||||
{
|
||||
// timeAsDouble not available in older Unity versions.
|
||||
#if !UNITY_2020_3_OR_NEWER
|
||||
if (AccurateInterval.Elapsed(NetworkTime.localTime, NetworkServer.sendInterval, ref lastSendIntervalTime))
|
||||
{
|
||||
if (sendIntervalCounter == sendIntervalMultiplier)
|
||||
sendIntervalCounter = 0;
|
||||
sendIntervalCounter++;
|
||||
}
|
||||
#else
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
if (AccurateInterval.Elapsed(Time.timeAsDouble, NetworkServer.sendInterval, ref lastSendIntervalTime))
|
||||
{
|
||||
if (sendIntervalCounter == sendIntervalMultiplier)
|
||||
sendIntervalCounter = 0;
|
||||
sendIntervalCounter++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// timeAsDouble not available in older Unity versions.
|
||||
if (AccurateInterval.Elapsed(NetworkTime.localTime, NetworkServer.sendInterval, ref lastSendIntervalTime))
|
||||
{
|
||||
if (sendIntervalCounter == sendIntervalMultiplier)
|
||||
sendIntervalCounter = 0;
|
||||
sendIntervalCounter++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// check if position / rotation / scale changed since last sync
|
||||
protected virtual bool Changed(TransformSnapshot current) =>
|
||||
@ -235,7 +235,7 @@ public override void OnSerialize(NetworkWriter writer, bool initialState)
|
||||
// regular serialisation the delta compression will get wrong values.
|
||||
// Notes:
|
||||
// 1. Interestingly only the older clients have it wrong, because at the end
|
||||
// of the function, last = snapshot which is the initial state's snapshot
|
||||
// of this function, last = snapshot which is the initial state's snapshot
|
||||
// 2. Regular NTR gets by this bug because it sends every frame anyway so initialstate
|
||||
// snapshot constructed would have been the same as the last anyway.
|
||||
if (last.remoteTime > 0)
|
||||
|
@ -12,8 +12,8 @@ public class PlayerBuffers : NetworkBehaviour
|
||||
public NTRCustomSendInterval NTRCustomSendInterval;
|
||||
public NetworkTransform NetworkTransform;
|
||||
public NetworkTransformReliable NetworkTransformReliable;
|
||||
public TextMeshPro serverBufferText;
|
||||
public TextMeshPro clientBufferText;
|
||||
public TextMeshPro serverBufferText;
|
||||
public TextMeshPro snapIntText;
|
||||
|
||||
[Header("Diagnostics - Do Not Modify")]
|
||||
@ -27,8 +27,8 @@ private void OnValidate()
|
||||
NetworkTransformReliable = GetComponent<NetworkTransformReliable>();
|
||||
|
||||
// Force overrideColorTags true so we can change the color without tags
|
||||
serverBufferText.overrideColorTags = true;
|
||||
clientBufferText.overrideColorTags = true;
|
||||
serverBufferText.overrideColorTags = true;
|
||||
|
||||
this.enabled = false;
|
||||
}
|
||||
@ -46,6 +46,25 @@ public override void OnStopClient()
|
||||
|
||||
void Update()
|
||||
{
|
||||
/////// Client
|
||||
if (NTRCustomSendInterval)
|
||||
clientSnapCount = NTRCustomSendInterval.clientSnapshots.Count;
|
||||
if (NetworkTransform)
|
||||
clientSnapCount = NetworkTransform.clientSnapshots.Count;
|
||||
if (NetworkTransformReliable)
|
||||
clientSnapCount = NetworkTransformReliable.clientSnapshots.Count;
|
||||
|
||||
if (clientSnapCount < 2)
|
||||
clientBufferText.color = Color.black;
|
||||
else if (clientSnapCount < 3)
|
||||
clientBufferText.color = Color.green;
|
||||
else if (clientSnapCount < 4)
|
||||
clientBufferText.color = Color.yellow;
|
||||
else
|
||||
clientBufferText.color = Color.red;
|
||||
|
||||
clientBufferText.text = $"C: {new string('-', clientSnapCount)}";
|
||||
|
||||
/////// Server
|
||||
//serverSnapCount = networkTransformReliable.serverSnapshots.Count;
|
||||
|
||||
@ -60,25 +79,6 @@ void Update()
|
||||
|
||||
//serverBufferText.text = "S: " + new string('-', serverSnapCount);
|
||||
|
||||
/////// Client
|
||||
if (NTRCustomSendInterval)
|
||||
clientSnapCount = NTRCustomSendInterval.clientSnapshots.Count;
|
||||
if (NetworkTransform)
|
||||
clientSnapCount = NetworkTransform.clientSnapshots.Count;
|
||||
if (NetworkTransformReliable)
|
||||
clientSnapCount = NetworkTransformReliable.clientSnapshots.Count;
|
||||
|
||||
if (clientSnapCount < 2)
|
||||
clientBufferText.color = Color.gray;
|
||||
else if (clientSnapCount < 3)
|
||||
clientBufferText.color = Color.green;
|
||||
else if (clientSnapCount < 4)
|
||||
clientBufferText.color = Color.yellow;
|
||||
else
|
||||
clientBufferText.color = Color.red;
|
||||
|
||||
clientBufferText.text = "C: " + new string('-', clientSnapCount);
|
||||
|
||||
/////// Snap Interpolation
|
||||
//snapIntText.text = $"{networkTransformReliable.velocity.magnitude:N2}" +
|
||||
// $"\n{transform.position}";
|
||||
@ -86,8 +86,8 @@ void Update()
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
serverBufferText.transform.forward = mainCamTransform.forward;
|
||||
clientBufferText.transform.forward = mainCamTransform.forward;
|
||||
serverBufferText.transform.forward = mainCamTransform.forward;
|
||||
snapIntText.transform.forward = mainCamTransform.forward;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
using Mirror;
|
||||
using System;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
namespace TestNT
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Mirror;
|
||||
using System;
|
||||
|
||||
namespace TestNT
|
||||
{
|
||||
@ -249,7 +249,15 @@ void HandleTurning()
|
||||
// Headless client forced to ground
|
||||
void HandleJumping()
|
||||
{
|
||||
jumpSpeed = Physics.gravity.y * Time.deltaTime;
|
||||
if (groundState != GroundState.Grounded)
|
||||
{
|
||||
// handles running off a cliff and/or player released Spacebar.
|
||||
groundState = GroundState.Falling;
|
||||
jumpSpeed = Mathf.Min(jumpSpeed, maxJumpSpeed);
|
||||
jumpSpeed += Physics.gravity.y * Time.deltaTime;
|
||||
}
|
||||
else
|
||||
jumpSpeed = Physics.gravity.y * Time.deltaTime;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Mirror;
|
||||
using TMPro;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TestNT
|
||||
{
|
||||
|
@ -19,9 +19,9 @@ public class TestNTNetworkManager : NetworkManager
|
||||
public GameObject playerNinjaPrefab;
|
||||
|
||||
public GameObject botPrefab;
|
||||
public GameObject npcPrefab;
|
||||
|
||||
public GameObject botNinjaPrefab;
|
||||
|
||||
public GameObject npcPrefab;
|
||||
public GameObject npcNinjaPrefab;
|
||||
|
||||
/// <summary>
|
||||
|
@ -36,5 +36,19 @@ public void StopHostCallsOnServerDisconnectForHostClient()
|
||||
manager.StopHost();
|
||||
Assert.That(manager.called, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StopClientCallsOnServerDisconnectForHostClient()
|
||||
{
|
||||
// OnServerDisconnect is always called when a client disconnects.
|
||||
// it should also be called for the host client when we stop the host
|
||||
Assert.That(manager.called, Is.EqualTo(0));
|
||||
manager.StartHost();
|
||||
manager.StopClient();
|
||||
Assert.That(manager.called, Is.EqualTo(1));
|
||||
Assert.That(NetworkServer.connections.Count, Is.EqualTo(0));
|
||||
Assert.That(NetworkServer.localConnection, Is.Null);
|
||||
Assert.That(NetworkClient.connection, Is.Null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,8 @@
|
||||
V1.34 [2023-03-15]
|
||||
- Send/SendTo/Receive/ReceiveFrom NonBlocking extensions.
|
||||
to encapsulate WouldBlock allocations, exceptions, etc.
|
||||
allows for reuse when overwriting KcpServer/Client (i.e. for relays).
|
||||
|
||||
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.
|
||||
|
@ -1,6 +1,162 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace kcp2k
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
// non-blocking UDP send.
|
||||
// allows for reuse when overwriting KcpServer/Client (i.e. for relays).
|
||||
// => wrapped with Poll to avoid WouldBlock allocating new SocketException.
|
||||
// => wrapped with try-catch to ignore WouldBlock exception.
|
||||
// make sure to set socket.Blocking = false before using this!
|
||||
public static bool SendToNonBlocking(this Socket socket, ArraySegment<byte> data, EndPoint remoteEP)
|
||||
{
|
||||
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 false;
|
||||
|
||||
// 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, remoteEP);
|
||||
return true;
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// for non-blocking sockets, SendTo may throw WouldBlock.
|
||||
// in that case, simply drop the message. it's UDP, it's fine.
|
||||
if (e.SocketErrorCode == SocketError.WouldBlock) return false;
|
||||
|
||||
// otherwise it's a real socket error. throw it.
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// non-blocking UDP send.
|
||||
// allows for reuse when overwriting KcpServer/Client (i.e. for relays).
|
||||
// => wrapped with Poll to avoid WouldBlock allocating new SocketException.
|
||||
// => wrapped with try-catch to ignore WouldBlock exception.
|
||||
// make sure to set socket.Blocking = false before using this!
|
||||
public static bool SendNonBlocking(this Socket socket, 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 false;
|
||||
|
||||
// SendTo allocates. we used bound Send.
|
||||
socket.Send(data.Array, data.Offset, data.Count, SocketFlags.None);
|
||||
return true;
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// for non-blocking sockets, SendTo may throw WouldBlock.
|
||||
// in that case, simply drop the message. it's UDP, it's fine.
|
||||
if (e.SocketErrorCode == SocketError.WouldBlock) return false;
|
||||
|
||||
// otherwise it's a real socket error. throw it.
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// non-blocking UDP receive.
|
||||
// allows for reuse when overwriting KcpServer/Client (i.e. for relays).
|
||||
// => wrapped with Poll to avoid WouldBlock allocating new SocketException.
|
||||
// => wrapped with try-catch to ignore WouldBlock exception.
|
||||
// make sure to set socket.Blocking = false before using this!
|
||||
public static bool ReceiveFromNonBlocking(this Socket socket, byte[] recvBuffer, out ArraySegment<byte> data, ref EndPoint remoteEP)
|
||||
{
|
||||
data = default;
|
||||
|
||||
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).
|
||||
// IPEndPoint.Create always returns a new IPEndPoint.
|
||||
// https://github.com/mono/mono/blob/f74eed4b09790a0929889ad7fc2cf96c9b6e3757/mcs/class/System/System.Net.Sockets/Socket.cs#L1761
|
||||
//
|
||||
// throws SocketException if datagram was larger than buffer.
|
||||
// https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.receive?view=net-6.0
|
||||
int size = socket.ReceiveFrom(recvBuffer, 0, recvBuffer.Length, SocketFlags.None, ref remoteEP);
|
||||
data = new ArraySegment<byte>(recvBuffer, 0, size);
|
||||
return true;
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// for non-blocking sockets, Receive throws WouldBlock if there is
|
||||
// no message to read. that's okay. only log for other errors.
|
||||
if (e.SocketErrorCode == SocketError.WouldBlock) return false;
|
||||
|
||||
// otherwise it's a real socket error. throw it.
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// non-blocking UDP receive.
|
||||
// allows for reuse when overwriting KcpServer/Client (i.e. for relays).
|
||||
// => wrapped with Poll to avoid WouldBlock allocating new SocketException.
|
||||
// => wrapped with try-catch to ignore WouldBlock exception.
|
||||
// make sure to set socket.Blocking = false before using this!
|
||||
public static bool ReceiveNonBlocking(this Socket socket, byte[] recvBuffer, out ArraySegment<byte> data)
|
||||
{
|
||||
data = default;
|
||||
|
||||
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.
|
||||
// https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.receive?view=net-6.0
|
||||
//
|
||||
// throws SocketException if datagram was larger than buffer.
|
||||
// https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.receive?view=net-6.0
|
||||
int size = socket.Receive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None);
|
||||
data = new ArraySegment<byte>(recvBuffer, 0, size);
|
||||
return true;
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// for non-blocking sockets, Receive throws WouldBlock if there is
|
||||
// no message to read. that's okay. only log for other errors.
|
||||
if (e.SocketErrorCode == SocketError.WouldBlock) return false;
|
||||
|
||||
// otherwise it's a real socket error. throw it.
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ public class KcpClient
|
||||
public EndPoint remoteEndPoint;
|
||||
|
||||
// config
|
||||
readonly KcpConfig config;
|
||||
protected readonly KcpConfig config;
|
||||
|
||||
// raw receive buffer always needs to be of 'MTU' size, even if
|
||||
// MaxMessageSize is larger. kcp always sends in MTU segments and having
|
||||
@ -35,10 +35,10 @@ public class KcpClient
|
||||
// events are readonly, set in constructor.
|
||||
// this ensures they are always initialized when used.
|
||||
// fixes https://github.com/MirrorNetworking/Mirror/issues/3337 and more
|
||||
readonly Action OnConnected;
|
||||
readonly Action<ArraySegment<byte>, KcpChannel> OnData;
|
||||
readonly Action OnDisconnected;
|
||||
readonly Action<ErrorCode, string> OnError;
|
||||
protected readonly Action OnConnected;
|
||||
protected readonly Action<ArraySegment<byte>, KcpChannel> OnData;
|
||||
protected readonly Action OnDisconnected;
|
||||
protected readonly Action<ErrorCode, string> OnError;
|
||||
|
||||
// state
|
||||
public bool connected;
|
||||
@ -131,40 +131,19 @@ 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.
|
||||
// https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.receive?view=net-6.0
|
||||
int msgLength = socket.Receive(rawReceiveBuffer);
|
||||
|
||||
//Log.Debug($"KCP: client raw recv {msgLength} bytes = {BitConverter.ToString(buffer, 0, msgLength)}");
|
||||
segment = new ArraySegment<byte>(rawReceiveBuffer, 0, msgLength);
|
||||
return true;
|
||||
return socket.ReceiveNonBlocking(rawReceiveBuffer, out segment);
|
||||
}
|
||||
// for non-blocking sockets, Receive throws WouldBlock if there is
|
||||
// no message to read. that's okay. only log for other errors.
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (e.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
// the other end closing the connection is not an 'error'.
|
||||
// but connections should never just end silently.
|
||||
// at least log a message for easier debugging.
|
||||
// for example, his can happen when connecting without a server.
|
||||
// see test: ConnectWithoutServer().
|
||||
Log.Info($"KcpClient: looks like the other end has closed the connection. This is fine: {e}");
|
||||
peer.Disconnect();
|
||||
}
|
||||
// WouldBlock indicates there's no data yet, so return false.
|
||||
// the other end closing the connection is not an 'error'.
|
||||
// but connections should never just end silently.
|
||||
// at least log a message for easier debugging.
|
||||
// for example, his can happen when connecting without a server.
|
||||
// see test: ConnectWithoutServer().
|
||||
Log.Info($"KcpClient: looks like the other end has closed the connection. This is fine: {e}");
|
||||
peer.Disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -175,25 +154,11 @@ 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);
|
||||
socket.SendNonBlocking(data);
|
||||
}
|
||||
// for non-blocking sockets, SendTo may throw WouldBlock.
|
||||
// in that case, simply drop the message. it's UDP, it's fine.
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (e.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Log.Error($"KcpClient: Send failed: {e}");
|
||||
}
|
||||
Log.Error($"KcpClient: Send failed: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,7 +554,7 @@ void OnRawInputUnreliable(ArraySegment<byte> message)
|
||||
// invalid unreliable messages may be random internet noise.
|
||||
// show a warning, but don't disconnect.
|
||||
// otherwise attackers could disconnect someone with random noise.
|
||||
Log.Warning($"KcpPeer: received unreliable message while not authenticated. Disconnecting the connection.");
|
||||
Log.Warning($"KcpPeer: received unreliable message while not authenticated.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,13 @@ public class KcpServer
|
||||
// events are readonly, set in constructor.
|
||||
// this ensures they are always initialized when used.
|
||||
// fixes https://github.com/MirrorNetworking/Mirror/issues/3337 and more
|
||||
readonly Action<int> OnConnected;
|
||||
readonly Action<int, ArraySegment<byte>, KcpChannel> OnData;
|
||||
readonly Action<int> OnDisconnected;
|
||||
readonly Action<int, ErrorCode, string> OnError;
|
||||
protected readonly Action<int> OnConnected;
|
||||
protected readonly Action<int, ArraySegment<byte>, KcpChannel> OnData;
|
||||
protected readonly Action<int> OnDisconnected;
|
||||
protected readonly Action<int, ErrorCode, string> OnError;
|
||||
|
||||
// configuration
|
||||
readonly KcpConfig config;
|
||||
protected readonly KcpConfig config;
|
||||
|
||||
// state
|
||||
protected Socket socket;
|
||||
@ -154,53 +154,31 @@ 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).
|
||||
// IPEndPoint.Create always returns a new IPEndPoint.
|
||||
// https://github.com/mono/mono/blob/f74eed4b09790a0929889ad7fc2cf96c9b6e3757/mcs/class/System/System.Net.Sockets/Socket.cs#L1761
|
||||
//
|
||||
// throws SocketException if datagram was larger than buffer.
|
||||
// https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.receive?view=net-6.0
|
||||
int size = socket.ReceiveFrom(rawReceiveBuffer, 0, rawReceiveBuffer.Length, SocketFlags.None, ref newClientEP);
|
||||
segment = new ArraySegment<byte>(rawReceiveBuffer, 0, size);
|
||||
|
||||
// set connectionId to hash from endpoint
|
||||
// NOTE: IPEndPoint.GetHashCode() allocates.
|
||||
// it calls m_Address.GetHashCode().
|
||||
// m_Address is an IPAddress.
|
||||
// GetHashCode() allocates for IPv6:
|
||||
// https://github.com/mono/mono/blob/bdd772531d379b4e78593587d15113c37edd4a64/mcs/class/referencesource/System/net/System/Net/IPAddress.cs#L699
|
||||
//
|
||||
// => using only newClientEP.Port wouldn't work, because
|
||||
// different connections can have the same port.
|
||||
connectionId = newClientEP.GetHashCode();
|
||||
return true;
|
||||
if (socket.ReceiveFromNonBlocking(rawReceiveBuffer, out segment, ref newClientEP))
|
||||
{
|
||||
// set connectionId to hash from endpoint
|
||||
// NOTE: IPEndPoint.GetHashCode() allocates.
|
||||
// it calls m_Address.GetHashCode().
|
||||
// m_Address is an IPAddress.
|
||||
// GetHashCode() allocates for IPv6:
|
||||
// https://github.com/mono/mono/blob/bdd772531d379b4e78593587d15113c37edd4a64/mcs/class/referencesource/System/net/System/Net/IPAddress.cs#L699
|
||||
//
|
||||
// => using only newClientEP.Port wouldn't work, because
|
||||
// different connections can have the same port.
|
||||
connectionId = newClientEP.GetHashCode();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// for non-blocking sockets, Receive throws WouldBlock if there is
|
||||
// no message to read. that's okay. only log for other errors.
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (e.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
// NOTE: SocketException is not a subclass of IOException.
|
||||
// the other end closing the connection is not an 'error'.
|
||||
// but connections should never just end silently.
|
||||
// at least log a message for easier debugging.
|
||||
Log.Info($"KcpServer: ReceiveFrom failed: {e}");
|
||||
}
|
||||
// WouldBlock indicates there's no data yet, so return false.
|
||||
return false;
|
||||
// NOTE: SocketException is not a subclass of IOException.
|
||||
// the other end closing the connection is not an 'error'.
|
||||
// but connections should never just end silently.
|
||||
// at least log a message for easier debugging.
|
||||
Log.Info($"KcpServer: ReceiveFrom failed: {e}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// io - out.
|
||||
@ -217,28 +195,11 @@ protected virtual void RawSend(int connectionId, 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;
|
||||
|
||||
// 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);
|
||||
socket.SendToNonBlocking(data, connection.remoteEndPoint);
|
||||
}
|
||||
// for non-blocking sockets, SendTo may throw WouldBlock.
|
||||
// in that case, simply drop the message. it's UDP, it's fine.
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (e.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Log.Error($"KcpServer: SendTo failed: {e}");
|
||||
}
|
||||
Log.Error($"KcpServer: SendTo failed: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,13 +45,21 @@ public class #SCRIPTNAME# : NetworkAuthenticator
|
||||
public void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg)
|
||||
{
|
||||
AuthResponseMessage authResponseMessage = new AuthResponseMessage();
|
||||
|
||||
conn.Send(authResponseMessage);
|
||||
|
||||
// Accept the successful authentication
|
||||
ServerAccept(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when server stops, used to unregister message handlers if needed.
|
||||
/// </summary>
|
||||
public override void OnStopServer()
|
||||
{
|
||||
// Unregister the handler for the authentication request
|
||||
NetworkServer.UnregisterHandler<AuthRequestMessage>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Client
|
||||
@ -72,7 +80,6 @@ public class #SCRIPTNAME# : NetworkAuthenticator
|
||||
public override void OnClientAuthenticate()
|
||||
{
|
||||
AuthRequestMessage authRequestMessage = new AuthRequestMessage();
|
||||
|
||||
NetworkClient.Send(authRequestMessage);
|
||||
}
|
||||
|
||||
@ -86,5 +93,14 @@ public class #SCRIPTNAME# : NetworkAuthenticator
|
||||
ClientAccept();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when client stops, used to unregister message handlers if needed.
|
||||
/// </summary>
|
||||
public override void OnStopClient()
|
||||
{
|
||||
// Unregister the handler for the authentication response
|
||||
NetworkClient.UnregisterHandler<AuthResponseMessage>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -9,18 +9,34 @@ using Mirror.Discovery;
|
||||
|
||||
public struct DiscoveryRequest : NetworkMessage
|
||||
{
|
||||
// Add properties for whatever information you want sent by clients
|
||||
// in their broadcast messages that servers will consume.
|
||||
// Add public fields (not properties) for whatever information you want
|
||||
// sent by clients in their broadcast messages that servers will use.
|
||||
}
|
||||
|
||||
public struct DiscoveryResponse : NetworkMessage
|
||||
{
|
||||
// Add properties for whatever information you want the server to return to
|
||||
// clients for them to display or consume for establishing a connection.
|
||||
// Add public fields (not properties) for whatever information you want the server
|
||||
// to return to clients for them to display or use for establishing a connection.
|
||||
}
|
||||
|
||||
public class #SCRIPTNAME# : NetworkDiscoveryBase<DiscoveryRequest, DiscoveryResponse>
|
||||
{
|
||||
#region Unity Callbacks
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
}
|
||||
#endif
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Server
|
||||
|
||||
/// <summary>
|
||||
|
Loading…
Reference in New Issue
Block a user