fix: Unity 2019, 2020 support added again (#3230)

* fix: Examples/AdditiveLevels/Prefabs/Portal doesn't depend on TextMeshPro anymore (for 2019 compatibility)

* packages: removed unnecessary TextMeshPro (causes errors in Unity 2019)

* fix: NetworkReader byte[] constructor added again for 2019 support

* fix: NetworkReader byte[] SetBuffer added again for 2019 support

* fix: NetworkClient OnTimeSnapshotMessage: NetworkTime.localTime for 2019 support

* fix: NetworkServer NetworkLateUpdate: NetworkTime.localTime for 2019 support

* fix: Read/WriteGuid support for 2019

* fix: NetworkTransformBase: NetworkTime.localTime for 2019 support

* fix: Grid2D new hashSet constructor without capacity for 2019 support

* 2019

* this
This commit is contained in:
mischa 2022-10-10 23:32:13 +08:00 committed by GitHub
parent e7110d3015
commit c179d233a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 143 additions and 112 deletions

View File

@ -49,7 +49,12 @@ public void Add(Vector2Int position, T value)
// each grid entry may hold hundreds of entities.
// let's create the HashSet with a large initial capacity
// in order to avoid resizing & allocations.
#if !UNITY_2021_3_OR_NEWER
// Unity 2019 doesn't have "new HashSet(capacity)" yet
hashSet = new HashSet<T>();
#else
hashSet = new HashSet<T>(128);
#endif
grid[position] = hashSet;
}

View File

@ -113,7 +113,11 @@ protected virtual TransformSnapshot ConstructSnapshot()
// NetworkTime.localTime for double precision until Unity has it too
return new TransformSnapshot(
// our local time is what the other end uses as remote time
#if !UNITY_2020_3_OR_NEWER
NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet
#else
Time.timeAsDouble,
#endif
// the other end fills out local time itself
0,
targetComponent.localPosition,
@ -304,7 +308,11 @@ protected virtual void OnServerToClientSync(Vector3? position, Quaternion? rotat
// insert snapshot
SnapshotInterpolation.InsertIfNotExists(clientSnapshots, new TransformSnapshot(
timestamp, // arrival remote timestamp. NOT remote time.
Time.timeAsDouble, // local time of this client
#if !UNITY_2020_3_OR_NEWER
NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet
#else
Time.timeAsDouble,
#endif
position.Value,
rotation.Value,
scale.Value

View File

@ -126,7 +126,13 @@ static void OnTimeSnapshotMessage(TimeSnapshotMessage _)
// insert another snapshot for snapshot interpolation.
// before calling OnDeserialize so components can use
// NetworkTime.time and NetworkTime.timeStamp.
#if !UNITY_2020_3_OR_NEWER
// Unity 2019 doesn't have Time.timeAsDouble yet
OnTimeSnapshot(new TimeSnapshot(connection.remoteTimeStamp, NetworkTime.localTime));
#else
OnTimeSnapshot(new TimeSnapshot(connection.remoteTimeStamp, Time.timeAsDouble));
#endif
}
// see comments at the top of this file

View File

@ -53,6 +53,14 @@ public NetworkReader(ArraySegment<byte> segment)
buffer = segment;
}
#if !UNITY_2021_3_OR_NEWER
// Unity 2019 doesn't have the implicit byte[] to segment conversion yet
public NetworkReader(byte[] bytes)
{
buffer = new ArraySegment<byte>(bytes, 0, bytes.Length);
}
#endif
// sometimes it's useful to point a reader on another buffer instead of
// allocating a new reader (e.g. NetworkReaderPool)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -62,6 +70,15 @@ public void SetBuffer(ArraySegment<byte> segment)
Position = 0;
}
#if !UNITY_2021_3_OR_NEWER
// Unity 2019 doesn't have the implicit byte[] to segment conversion yet
public void SetBuffer(byte[] bytes)
{
buffer = new ArraySegment<byte>(bytes, 0, bytes.Length);
Position = 0;
}
#endif
// ReadBlittable<T> from DOTSNET
// this is extremely fast, but only works for blittable types.
// => private to make sure nobody accidentally uses it for non-blittable

View File

@ -145,6 +145,10 @@ public static ArraySegment<byte> ReadBytesAndSizeSegment(this NetworkReader read
public static Guid ReadGuid(this NetworkReader reader)
{
#if !UNITY_2021_3_OR_NEWER
// Unity 2019 doesn't have Span yet
return new Guid(reader.ReadBytes(16));
#else
// ReadBlittable(Guid) isn't safe. see ReadBlittable comments.
// Guid is Sequential, but we can't guarantee packing.
if (reader.Remaining >= 16)
@ -154,6 +158,7 @@ public static Guid ReadGuid(this NetworkReader reader)
return new Guid(span);
}
throw new EndOfStreamException($"ReadGuid out of range: {reader}");
#endif
}
public static Guid? ReadGuidNullable(this NetworkReader reader) => reader.ReadBool() ? ReadGuid(reader) : default(Guid?);

View File

@ -1746,7 +1746,12 @@ internal static void NetworkLateUpdate()
//
// during tests, we always call Broadcast() though.
if (!Application.isPlaying ||
#if !UNITY_2020_3_OR_NEWER
// Unity 2019 doesn't have Time.timeAsDouble yet
AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime))
#else
AccurateInterval.Elapsed(Time.timeAsDouble, sendInterval, ref lastSendTime))
#endif
{
Broadcast();
}

View File

@ -175,12 +175,18 @@ public static void WriteArraySegment<T>(this NetworkWriter writer, ArraySegment<
public static void WriteGuid(this NetworkWriter writer, Guid value)
{
#if !UNITY_2021_3_OR_NEWER
// Unity 2019 doesn't have Span yet
byte[] data = value.ToByteArray();
writer.WriteBytes(data, 0, data.Length);
#else
// WriteBlittable(Guid) isn't safe. see WriteBlittable comments.
// Guid is Sequential, but we can't guarantee packing.
// TryWriteBytes is safe and allocation free.
writer.EnsureCapacity(writer.Position + 16);
value.TryWriteBytes(new Span<byte>(writer.buffer, writer.Position, 16));
writer.Position += 16;
#endif
}
public static void WriteGuidNullable(this NetworkWriter writer, Guid? value)
{

View File

@ -31,6 +31,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: 0}
m_LocalScale: {x: 2, y: 2, z: 2}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1355348187805494562}
m_Father: {fileID: 0}
@ -55,6 +56,7 @@ MeshRenderer:
m_CastShadows: 0
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
@ -112,9 +114,9 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
sceneId: 0
_assetId: 1770499856
serverOnly: 0
visible: 0
m_AssetId: c624c75494b4d7d4086b9212f897e56a
hasSpawned: 0
--- !u!114 &5948271423698091598
MonoBehaviour:
@ -132,7 +134,7 @@ MonoBehaviour:
syncInterval: 0.1
destinationScene:
startPosition: {x: 0, y: 0, z: 0}
label: {fileID: 5446595135713311426}
label: {fileID: 8197110483235692531}
labelText:
--- !u!1 &5961932215084527574
GameObject:
@ -144,8 +146,8 @@ GameObject:
m_Component:
- component: {fileID: 1355348187805494562}
- component: {fileID: 5428053421152709616}
- component: {fileID: 5446595135713311426}
- component: {fileID: 3243959486819493908}
- component: {fileID: 8197110483235692531}
m_Layer: 9
m_Name: Label_TMP
m_TagString: Untagged
@ -163,6 +165,7 @@ RectTransform:
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: 1098173225717622921}
m_RootOrder: 0
@ -183,6 +186,7 @@ MeshRenderer:
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
@ -191,7 +195,7 @@ MeshRenderer:
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
- {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
@ -213,98 +217,6 @@ MeshRenderer:
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &5446595135713311426
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5961932215084527574}
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: Sub Level 2
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: 4288619804
m_fontColor: {r: 0.108668566, g: 0.14359462, b: 0.6226415, 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: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 4
m_fontSizeBase: 4
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 5
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: 1
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
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
m_hasFontAssetChanged: 0
m_renderer: {fileID: 5428053421152709616}
m_maskType: 0
_SortingLayer: 0
_SortingLayerID: 0
_SortingOrder: 0
--- !u!114 &3243959486819493908
MonoBehaviour:
m_ObjectHideFlags: 0
@ -317,3 +229,25 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: cc58300ee45438a418d9e32957fdc0c0, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!102 &8197110483235692531
TextMesh:
serializedVersion: 3
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5961932215084527574}
m_Text:
m_OffsetZ: 0
m_CharacterSize: 0.05
m_LineSpacing: 1
m_Anchor: 4
m_Alignment: 1
m_TabSize: 4
m_FontSize: 100
m_FontStyle: 0
m_RichText: 1
m_Font: {fileID: 0}
m_Color:
serializedVersion: 2
rgba: 4294967295

View File

@ -15,7 +15,7 @@ public class Portal : NetworkBehaviour
public Vector3 startPosition;
[Tooltip("Reference to child TMP label")]
public TMPro.TextMeshPro label;
public TextMesh label; // don't depend on TMPro. 2019 errors.
[SyncVar(hook = nameof(OnLabelTextChanged))]
public string labelText;

View File

@ -109,7 +109,11 @@ void Awake()
public void OnMessage(Snapshot3D snap)
{
// set local timestamp (= when it was received on our end)
#if !UNITY_2020_3_OR_NEWER
snap.localTime = NetworkTime.localTime;
#else
snap.localTime = Time.timeAsDouble;
#endif
// (optional) dynamic adjustment
if (dynamicAdjustment)

View File

@ -68,7 +68,11 @@ void Update()
void Send(Vector3 position)
{
// create snapshot
#if !UNITY_2020_3_OR_NEWER
Snapshot3D snap = new Snapshot3D(NetworkTime.localTime, 0, position);
#else
Snapshot3D snap = new Snapshot3D(Time.timeAsDouble, 0, position);
#endif
// simulate packet loss
bool drop = random.NextDouble() < loss;
@ -81,7 +85,11 @@ void Send(Vector3 position)
// simulate latency
float simulatedLatency = SimulateLatency();
#if !UNITY_2020_3_OR_NEWER
double deliveryTime = NetworkTime.localTime + simulatedLatency;
#else
double deliveryTime = Time.timeAsDouble + simulatedLatency;
#endif
queue.Insert(index, (deliveryTime, snap));
}
}
@ -92,7 +100,12 @@ void Flush()
for (int i = 0; i < queue.Count; ++i)
{
(double deliveryTime, Snapshot3D snap) = queue[i];
#if !UNITY_2020_3_OR_NEWER
if (NetworkTime.localTime >= deliveryTime)
#else
if (Time.timeAsDouble >= deliveryTime)
#endif
{
client.OnMessage(snap);
queue.RemoveAt(i);

View File

@ -236,11 +236,11 @@ public void SpawnDelegate_AddsHandlerToSpawnHandlersWithCorrectArguments(Registe
Vector3 somePosition = new Vector3(10, 20, 3);
uint assetId = AssetIdForOverload(overload);
SpawnDelegate handler = new SpawnDelegate((pos, assetId) =>
SpawnDelegate handler = new SpawnDelegate((pos, id) =>
{
handlerCalled++;
Assert.That(pos, Is.EqualTo(somePosition));
Assert.That(assetId, Is.EqualTo(assetId));
Assert.That(id, Is.EqualTo(assetId));
return null;
});

View File

@ -36,11 +36,11 @@ public void SpawnDelegate_AddsHandlerToSpawnHandlersWithCorrectArguments()
Vector3 somePosition = new Vector3(10, 20, 3);
uint assetId = 42;
SpawnDelegate spawnHandler = new SpawnDelegate((pos, assetId) =>
SpawnDelegate spawnHandler = new SpawnDelegate((pos, id) =>
{
handlerCalled++;
Assert.That(pos, Is.EqualTo(somePosition));
Assert.That(assetId, Is.EqualTo(assetId));
Assert.That(id, Is.EqualTo(assetId));
return null;
});
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});

View File

@ -83,7 +83,11 @@ float SimulateLatency(int channeldId)
// no spikes isn't realistic.
// sin is too predictable / no realistic.
// perlin is still deterministic and random enough.
#if !UNITY_2020_3_OR_NEWER
float spike = Noise((float)NetworkTime.localTime * jitterSpeed) * jitter;
#else
float spike = Noise((float)Time.unscaledTimeAsDouble * jitterSpeed) * jitter;
#endif
// base latency
switch (channeldId)
@ -116,7 +120,11 @@ void SimulateSend(
{
connectionId = connectionId,
bytes = bytes,
#if !UNITY_2020_3_OR_NEWER
time = NetworkTime.localTime + latency
#else
time = Time.unscaledTimeAsDouble + latency
#endif
};
switch (channelId)
@ -220,7 +228,11 @@ public override void ClientLateUpdate()
{
// message ready to be sent?
QueuedMessage message = reliableClientToServer[i];
#if !UNITY_2020_3_OR_NEWER
if (message.time <= NetworkTime.localTime)
#else
if (message.time <= Time.unscaledTimeAsDouble)
#endif
{
// send and eat
wrap.ClientSend(new ArraySegment<byte>(message.bytes), Channels.Reliable);
@ -235,7 +247,11 @@ public override void ClientLateUpdate()
{
// message ready to be sent?
QueuedMessage message = unreliableClientToServer[i];
#if !UNITY_2020_3_OR_NEWER
if (message.time <= NetworkTime.localTime)
#else
if (message.time <= Time.unscaledTimeAsDouble)
#endif
{
// send and eat
wrap.ClientSend(new ArraySegment<byte>(message.bytes), Channels.Reliable);
@ -256,7 +272,11 @@ public override void ServerLateUpdate()
{
// message ready to be sent?
QueuedMessage message = reliableServerToClient[i];
#if !UNITY_2020_3_OR_NEWER
if (message.time <= NetworkTime.localTime)
#else
if (message.time <= Time.unscaledTimeAsDouble)
#endif
{
// send and eat
wrap.ServerSend(message.connectionId, new ArraySegment<byte>(message.bytes), Channels.Reliable);
@ -272,7 +292,11 @@ public override void ServerLateUpdate()
{
// message ready to be sent?
QueuedMessage message = unreliableServerToClient[i];
#if !UNITY_2020_3_OR_NEWER
if (message.time <= NetworkTime.localTime)
#else
if (message.time <= Time.unscaledTimeAsDouble)
#endif
{
// send and eat
wrap.ServerSend(message.connectionId, new ArraySegment<byte>(message.bytes), Channels.Reliable);

View File

@ -4,6 +4,20 @@
namespace Mirror.SimpleWeb
{
#if !UNITY_2021_3_OR_NEWER
// Unity 2019 doesn't have ArraySegment.ToArray() yet.
public static class Extensions
{
public static byte[] ToArray(this ArraySegment<byte> segment)
{
byte[] array = new byte[segment.Count];
Array.Copy(segment.Array, segment.Offset, array, 0, segment.Count);
return array;
}
}
#endif
public class WebSocketClientWebGl : SimpleWebClient
{
static readonly Dictionary<int, WebSocketClientWebGl> instances = new Dictionary<int, WebSocketClientWebGl>();

View File

@ -7,7 +7,6 @@
"com.unity.ide.vscode": "1.2.5",
"com.unity.test-framework": "1.1.31",
"com.unity.testtools.codecoverage": "1.0.1",
"com.unity.textmeshpro": "3.0.6",
"com.unity.ugui": "1.0.0",
"com.unity.xr.legacyinputhelpers": "2.1.10",
"com.unity.modules.ai": "1.0.0",

View File

@ -72,15 +72,6 @@
},
"url": "https://packages.unity.com"
},
"com.unity.textmeshpro": {
"version": "3.0.6",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.ugui": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.ugui": {
"version": "1.0.0",
"depth": 0,