[Add] FishNet
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aea01893c4a887048868eaa5b37c656a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,79 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1907658b89c1bbe42a0063df40b7ca24
|
||||
labels:
|
||||
- RoslynAnalyzer
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
: Any
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
Exclude Editor: 1
|
||||
Exclude Linux64: 1
|
||||
Exclude OSXUniversal: 1
|
||||
Exclude WebGL: 1
|
||||
Exclude Win: 1
|
||||
Exclude Win64: 1
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
DefaultValueInitialized: true
|
||||
OS: AnyOS
|
||||
- first:
|
||||
Standalone: Linux64
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
- first:
|
||||
Standalone: OSXUniversal
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
- first:
|
||||
Standalone: Win
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
- first:
|
||||
Standalone: Win64
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/CodeAnalysis/FishNet.CodeAnalysis.Analyzers.dll
|
||||
uploadId: 866910
|
||||
Binary file not shown.
@@ -0,0 +1,40 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 620557a5e202e644cb322b8fcc9422ea
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/CodeAnalysis/FishNet.CodeAnalysis.dll
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Abdelfattah-Radwan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93ef12b9e040fa8429d9ef686212ed4e
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/CodeAnalysis/LICENSE.txt
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,2 @@
|
||||
Git URL:
|
||||
https://github.com/Abdelfattah-Radwan/FishNet.CodeAnalysis
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 835336ee0aec7ef41a1cfda40886f443
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/CodeAnalysis/README.txt
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa7c8a088aea3f04580b62c8e2a388ec
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
This software uses the license for Fish-Networking: https://github.com/FirstGearGames/FishNet/blob/main/LICENSE.md
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff1ecc2a24fd9684a862c4b99cfc2fcd
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/LICENSE.txt
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06703c0fac6f21140ab99ef3eeb8a4f7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
#if FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using System.Collections.Generic;
|
||||
using FishNet.Object;
|
||||
using GameKit.Dependencies.Utilities;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
public class ColliderRollback : NetworkBehaviour
|
||||
{
|
||||
#region Serialized.
|
||||
#pragma warning disable CS0414
|
||||
/// <summary>
|
||||
/// How to configure the bounding box check.
|
||||
/// </summary>
|
||||
[Tooltip("How to configure the bounding box check.")]
|
||||
[SerializeField]
|
||||
private RollbackManager.BoundingBoxType _boundingBox = RollbackManager.BoundingBoxType.Disabled;
|
||||
/// <summary>
|
||||
/// Physics type to generate a bounding box for.
|
||||
/// </summary>
|
||||
[Tooltip("Physics type to generate a bounding box for.")]
|
||||
[SerializeField]
|
||||
private RollbackPhysicsType _physicsType = RollbackPhysicsType.Physics;
|
||||
/// <summary>
|
||||
/// Size for the bounding box. This is only used when BoundingBox is set to Manual.
|
||||
/// </summary>
|
||||
[Tooltip("Size for the bounding box.. This is only used when BoundingBox is set to Manual.")]
|
||||
[SerializeField]
|
||||
private Vector3 _boundingBoxSize = new(3f, 3f, 3f);
|
||||
/// <summary>
|
||||
/// Center for the bounding box. This is only used when BoundingBox is set to Manual.
|
||||
/// </summary>
|
||||
[Tooltip("Center for the bounding box.. This is only used when BoundingBox is set to Manual.")]
|
||||
[SerializeField]
|
||||
private Vector3 _boundingBoxCenter = new(0f, 0f, 0f);
|
||||
/// <summary>
|
||||
/// Local Rotation for the bounding box. This is only used when BoundingBox is set to Manual.
|
||||
/// </summary>
|
||||
[Tooltip("Center for the bounding box.. This is only used when BoundingBox is set to Manual.")]
|
||||
[SerializeField]
|
||||
private Quaternion _boundingBoxLocalRotation = Quaternion.identity;
|
||||
/// <summary>
|
||||
/// Objects holding colliders which can rollback.
|
||||
/// </summary>
|
||||
[Tooltip("Objects holding colliders which can rollback.")]
|
||||
[SerializeField]
|
||||
private GameObject[] _colliderParents = new GameObject[0];
|
||||
#pragma warning restore CS0414
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8e604e0a2709484193cda1a6d03b5b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.Threaded.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,25 @@
|
||||
#if !FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GameKit.Dependencies.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
public partial class ColliderRollback
|
||||
{
|
||||
internal enum BoundingBoxType
|
||||
{
|
||||
/// <summary>
|
||||
/// Disable this feature.
|
||||
/// </summary>
|
||||
Disabled,
|
||||
/// <summary>
|
||||
/// Manually specify the dimensions of a bounding box.
|
||||
/// </summary>
|
||||
Manual
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 83b62057280ff8e4faf4a7344b9f3bda
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.Types.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,43 @@
|
||||
#if !FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using System.Collections.Generic;
|
||||
using FishNet.Managing;
|
||||
using FishNet.Object;
|
||||
using GameKit.Dependencies.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
public partial class ColliderRollback : NetworkBehaviour
|
||||
{
|
||||
#region Serialized.
|
||||
#pragma warning disable CS0414
|
||||
/// <summary>
|
||||
/// How to configure the bounding box check.
|
||||
/// </summary>
|
||||
[Tooltip("How to configure the bounding box check.")]
|
||||
[SerializeField]
|
||||
private BoundingBoxType _boundingBox = BoundingBoxType.Disabled;
|
||||
/// <summary>
|
||||
/// Physics type to generate a bounding box for.
|
||||
/// </summary>
|
||||
[Tooltip("Physics type to generate a bounding box for.")]
|
||||
[SerializeField]
|
||||
private RollbackPhysicsType _physicsType = RollbackPhysicsType.Physics;
|
||||
/// <summary>
|
||||
/// Size for the bounding box. This is only used when BoundingBox is set to Manual.
|
||||
/// </summary>
|
||||
[Tooltip("Size for the bounding box.. This is only used when BoundingBox is set to Manual.")]
|
||||
[SerializeField]
|
||||
private Vector3 _boundingBoxSize = new(3f, 3f, 3f);
|
||||
/// <summary>
|
||||
/// Objects holding colliders which can rollback.
|
||||
/// </summary>
|
||||
[Tooltip("Objects holding colliders which can rollback.")]
|
||||
[SerializeField]
|
||||
private GameObject[] _colliderParents = new GameObject[0];
|
||||
#pragma warning restore CS0414
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01a271dd97d875347b0cea860df29a9d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs
|
||||
uploadId: 866910
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
#if UNITY_EDITOR && FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static FishNet.Component.ColliderRollback.ColliderRollback;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
[CustomEditor(typeof(ColliderRollback), true)]
|
||||
[CanEditMultipleObjects]
|
||||
public class ColliderRollbackEditor : Editor
|
||||
{
|
||||
private SerializedProperty _boundingBox;
|
||||
private SerializedProperty _physicsType;
|
||||
private SerializedProperty _boundingBoxSize;
|
||||
private SerializedProperty _boundingBoxCenter;
|
||||
private SerializedProperty _boundingBoxLocalRotation;
|
||||
private SerializedProperty _colliderParents;
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
_boundingBox = serializedObject.FindProperty(nameof(_boundingBox));
|
||||
_physicsType = serializedObject.FindProperty(nameof(_physicsType));
|
||||
_boundingBoxSize = serializedObject.FindProperty(nameof(_boundingBoxSize));
|
||||
_boundingBoxCenter = serializedObject.FindProperty(nameof(_boundingBoxCenter));
|
||||
_boundingBoxLocalRotation = serializedObject.FindProperty(nameof(_boundingBoxLocalRotation));
|
||||
_colliderParents = serializedObject.FindProperty(nameof(_colliderParents));
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
ColliderRollback nob = (ColliderRollback)target;
|
||||
|
||||
GUI.enabled = false;
|
||||
EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour(nob), typeof(ColliderRollback), false);
|
||||
GUI.enabled = true;
|
||||
|
||||
EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.PropertyField(_boundingBox);
|
||||
if ((RollbackManager.BoundingBoxType)_boundingBox.intValue != RollbackManager.BoundingBoxType.Disabled)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_physicsType);
|
||||
EditorGUILayout.PropertyField(_boundingBoxSize);
|
||||
EditorGUILayout.PropertyField(_boundingBoxCenter);
|
||||
EditorGUILayout.PropertyField(_boundingBoxLocalRotation);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.PropertyField(_colliderParents);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
ColliderRollback cr = (ColliderRollback)target;
|
||||
RollbackManager.BoundingBoxData bb = cr.GetBoundingBoxData();
|
||||
if (bb.boundingBoxType == RollbackManager.BoundingBoxType.Disabled)
|
||||
return;
|
||||
|
||||
Transform tr = cr.transform;
|
||||
Vector3 centerWS = tr.TransformPoint(bb.center);
|
||||
Quaternion rotWS = tr.rotation * bb.localRotation;
|
||||
Vector3 lossy = tr.lossyScale;
|
||||
Vector3 absScale = new Vector3(Mathf.Abs(lossy.x), Mathf.Abs(lossy.y), Mathf.Abs(lossy.z));
|
||||
Vector3 sizeWS = Vector3.Scale((bb.extends * 2f), absScale);
|
||||
|
||||
Matrix4x4 prevMatrix = Handles.matrix;
|
||||
Color prevColor = Handles.color;
|
||||
|
||||
Handles.matrix = Matrix4x4.TRS(centerWS, rotWS, Vector3.one);
|
||||
Handles.color = Color.green;
|
||||
Handles.DrawWireCube(Vector3.zero, sizeWS);
|
||||
|
||||
Handles.color = new Color(1f, 0.6f, 0f, 1f);
|
||||
Handles.SphereHandleCap(0, Vector3.zero, Quaternion.identity, 0.03f * Mathf.Max(sizeWS.x, sizeWS.y, sizeWS.z), EventType.Repaint);
|
||||
|
||||
Handles.color = prevColor;
|
||||
Handles.matrix = prevMatrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 519ce5f9fc54f5342a8a4eaf09a947b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollbackEditor.Threaded.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,54 @@
|
||||
#if UNITY_EDITOR && !FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static FishNet.Component.ColliderRollback.ColliderRollback;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
[CustomEditor(typeof(ColliderRollback), true)]
|
||||
[CanEditMultipleObjects]
|
||||
public class ColliderRollbackEditor : Editor
|
||||
{
|
||||
private SerializedProperty _boundingBox;
|
||||
private SerializedProperty _physicsType;
|
||||
private SerializedProperty _boundingBoxSize;
|
||||
private SerializedProperty _colliderParents;
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
_boundingBox = serializedObject.FindProperty(nameof(_boundingBox));
|
||||
_physicsType = serializedObject.FindProperty(nameof(_physicsType));
|
||||
_boundingBoxSize = serializedObject.FindProperty(nameof(_boundingBoxSize));
|
||||
_colliderParents = serializedObject.FindProperty(nameof(_colliderParents));
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
ColliderRollback nob = (ColliderRollback)target;
|
||||
|
||||
GUI.enabled = false;
|
||||
EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour(nob), typeof(ColliderRollback), false);
|
||||
GUI.enabled = true;
|
||||
|
||||
EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.PropertyField(_boundingBox);
|
||||
if ((BoundingBoxType)_boundingBox.intValue != BoundingBoxType.Disabled)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_physicsType);
|
||||
EditorGUILayout.PropertyField(_boundingBoxSize);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.PropertyField(_colliderParents);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0fd7d7c980dbbc49b3ab071b1974d33
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollbackEditor.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,51 @@
|
||||
#if FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Jobs;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to store where colliders are during the snapshot.
|
||||
/// </summary>
|
||||
public struct ColliderSnapshot
|
||||
{
|
||||
public ColliderSnapshot(Transform t)
|
||||
{
|
||||
t.GetPositionAndRotation(out Vector3 pos, out Quaternion rot);
|
||||
WorldPosition = pos;
|
||||
WorldRotation = rot;
|
||||
}
|
||||
|
||||
public ColliderSnapshot(TransformAccess ta)
|
||||
{
|
||||
ta.GetPositionAndRotation(out Vector3 pos, out Quaternion rot);
|
||||
WorldPosition = pos;
|
||||
WorldRotation = rot;
|
||||
}
|
||||
|
||||
public void SetValues(Transform t)
|
||||
{
|
||||
t.GetPositionAndRotation(out Vector3 pos, out Quaternion rot);
|
||||
WorldPosition = pos;
|
||||
WorldRotation = rot;
|
||||
}
|
||||
|
||||
public void SetValues(TransformAccess ta)
|
||||
{
|
||||
ta.GetPositionAndRotation(out Vector3 pos, out Quaternion rot);
|
||||
WorldPosition = pos;
|
||||
WorldRotation = rot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WorldPosition of transform during snapshot.
|
||||
/// </summary>
|
||||
public float3 WorldPosition;
|
||||
/// <summary>
|
||||
/// WorldRotation of transform during snapshot.
|
||||
/// </summary>
|
||||
public quaternion WorldRotation;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7bdaf4b1542a66d4e80646758ccfd525
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderSnapshot.Threaded.cs
|
||||
uploadId: 866910
|
||||
+667
@@ -0,0 +1,667 @@
|
||||
#if FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using FishNet.Managing;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Jobs.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Jobs;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds all job-friendly data for collider rollback: flattened transform table,
|
||||
/// ring buffers of TRS snapshots, and a persistent rolled-back mask.
|
||||
/// </summary>
|
||||
public sealed partial class RollbackCollection
|
||||
{
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// NetworkManager.
|
||||
/// </summary>
|
||||
private NetworkManager _networkManager;
|
||||
/// <summary>
|
||||
/// True if the collection is configured and has valid buffers.
|
||||
/// </summary>
|
||||
private bool _ready;
|
||||
/// <summary>
|
||||
/// Ring buffer length per rolling entry.
|
||||
/// </summary>
|
||||
private int _maxSnapshots;
|
||||
/// <summary>
|
||||
/// Physics used when rolling back.
|
||||
/// </summary>
|
||||
private RollbackPhysicsType _rollbackPhysics;
|
||||
/// <summary>
|
||||
/// List of ColliderRollback.
|
||||
/// </summary>
|
||||
private readonly List<ColliderRollback> _colliderRollbacks = new();
|
||||
/// <summary>
|
||||
/// Map of ColliderRollback -> index.
|
||||
/// </summary>
|
||||
private readonly Dictionary<ColliderRollback, int> _colliderRollbacksIndices = new();
|
||||
/// <summary>
|
||||
/// Write array for Rollback requests for deferred Rollback.
|
||||
/// </summary>
|
||||
private NativeList<RollbackManager.RollbackRequest> _writeRequests;
|
||||
/// <summary>
|
||||
/// Read array for Rollback requests for deferred Rollback.
|
||||
/// </summary>
|
||||
private NativeList<RollbackManager.RollbackRequest> _readRequests;
|
||||
/// <summary>
|
||||
/// Physics that requested for deferred rollback.
|
||||
/// </summary>
|
||||
private RollbackPhysicsType _requestsRollbackPhysics;
|
||||
/// <summary>
|
||||
/// TransformAccessArray for ColliderRollbacks.
|
||||
/// </summary>
|
||||
private TransformAccessArray _colliderRollbacksTAA;
|
||||
/// <summary>
|
||||
/// TransformAccessArray for RollingColliders.
|
||||
/// </summary>
|
||||
private TransformAccessArray _rollingCollidersTAA;
|
||||
/// <summary>
|
||||
/// Snapshots of ColliderRollbacks: [colliderRollbackIndex].
|
||||
/// </summary>
|
||||
private NativeList<ColliderSnapshot> _colliderRollbacksSnapshots;
|
||||
/// <summary>
|
||||
/// Flattened snapshots ring-buffer of RollingColliders: [rollingColliderIndex * MaxSnapshots + frame].
|
||||
/// </summary>
|
||||
private NativeList<ColliderSnapshot> _rollingCollidersSnapshots;
|
||||
/// <summary>
|
||||
/// ColliderRollbacks-level rolled-back flags (0 = write, 1 = freeze).
|
||||
/// </summary>
|
||||
private NativeList<byte> _colliderRollbacksRolledBackMask;
|
||||
/// <summary>
|
||||
/// Per-colliderRollbacks scene handle to allow filtering in jobs without masks.
|
||||
/// </summary>
|
||||
private NativeList<int> _colliderRollbacksSceneHandles;
|
||||
/// <summary>
|
||||
/// Per-colliderRollbacks number of available history frames for lerp (clamped to MaxSnapshots).
|
||||
/// </summary>
|
||||
private NativeList<int> _colliderRollbacksLerpFrames;
|
||||
/// <summary>
|
||||
/// Per-colliderRollbacks BoundingBoxData.
|
||||
/// </summary>
|
||||
private NativeList<RollbackManager.BoundingBoxData> _colliderRollbacksBoundingBoxData;
|
||||
/// <summary>
|
||||
/// Maps rolling-collider index to its colliderRollbacks index.
|
||||
/// </summary>
|
||||
private NativeList<int> _rollingColliderToColliderRollbacks;
|
||||
/// <summary>x
|
||||
/// Per-rolling write pointer (next frame slot in the ring).
|
||||
/// </summary>
|
||||
private NativeList<int> _rollingCollidersWriteIndices;
|
||||
#endregion
|
||||
|
||||
~RollbackCollection() { Deinitialize(); }
|
||||
/// <summary>
|
||||
/// Initialize ring size based on network timing. Call once on startup or when timing changes.
|
||||
/// </summary>
|
||||
internal void Initialize(NetworkManager networkManager, double tickDelta, float maximumRollbackTime)
|
||||
{
|
||||
_networkManager = networkManager;
|
||||
_maxSnapshots = Mathf.Max(2, Mathf.CeilToInt((float)(maximumRollbackTime / tickDelta)));
|
||||
if (!_writeRequests.IsCreated) _writeRequests = new NativeList<RollbackManager.RollbackRequest>(64, Allocator.Persistent);
|
||||
if (!_readRequests.IsCreated) _readRequests = new NativeList<RollbackManager.RollbackRequest>(64, Allocator.Persistent);
|
||||
if (!_colliderRollbacksTAA.isCreated) _colliderRollbacksTAA = new TransformAccessArray(64);
|
||||
if (!_rollingCollidersTAA.isCreated) _rollingCollidersTAA = new TransformAccessArray(64);
|
||||
if (!_colliderRollbacksSnapshots.IsCreated) _colliderRollbacksSnapshots = new NativeList<ColliderSnapshot>(64, Allocator.Persistent);
|
||||
if (!_rollingCollidersSnapshots.IsCreated) _rollingCollidersSnapshots = new NativeList<ColliderSnapshot>(64, Allocator.Persistent);
|
||||
if (!_colliderRollbacksRolledBackMask.IsCreated) _colliderRollbacksRolledBackMask = new NativeList<byte>(64, Allocator.Persistent);
|
||||
if (!_colliderRollbacksSceneHandles.IsCreated) _colliderRollbacksSceneHandles = new NativeList<int>(64, Allocator.Persistent);
|
||||
if (!_colliderRollbacksLerpFrames.IsCreated) _colliderRollbacksLerpFrames = new NativeList<int>(64, Allocator.Persistent);
|
||||
if (!_colliderRollbacksBoundingBoxData.IsCreated) _colliderRollbacksBoundingBoxData = new NativeList<RollbackManager.BoundingBoxData>(64, Allocator.Persistent);
|
||||
if (!_rollingColliderToColliderRollbacks.IsCreated) _rollingColliderToColliderRollbacks = new NativeList<int>(64, Allocator.Persistent);
|
||||
if (!_rollingCollidersWriteIndices.IsCreated) _rollingCollidersWriteIndices = new NativeList<int>(64, Allocator.Persistent);
|
||||
|
||||
_ready = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Deinitialize all native buffers and transform access arrays.
|
||||
/// </summary>
|
||||
internal void Deinitialize()
|
||||
{
|
||||
_networkManager = null;
|
||||
if (_writeRequests.IsCreated) _writeRequests.Dispose();
|
||||
if (_readRequests.IsCreated) _readRequests.Dispose();
|
||||
if (_colliderRollbacksTAA.isCreated) _colliderRollbacksTAA.Dispose();
|
||||
if (_rollingCollidersTAA.isCreated) _rollingCollidersTAA.Dispose();
|
||||
if (_colliderRollbacksSnapshots.IsCreated) _colliderRollbacksSnapshots.Dispose();
|
||||
if (_rollingCollidersSnapshots.IsCreated) _rollingCollidersSnapshots.Dispose();
|
||||
if (_colliderRollbacksRolledBackMask.IsCreated) _colliderRollbacksRolledBackMask.Dispose();
|
||||
if (_colliderRollbacksSceneHandles.IsCreated) _colliderRollbacksSceneHandles.Dispose();
|
||||
if (_colliderRollbacksLerpFrames.IsCreated) _colliderRollbacksLerpFrames.Dispose();
|
||||
if (_colliderRollbacksBoundingBoxData.IsCreated) _colliderRollbacksBoundingBoxData.Dispose();
|
||||
if (_rollingColliderToColliderRollbacks.IsCreated) _rollingColliderToColliderRollbacks.Dispose();
|
||||
if (_rollingCollidersWriteIndices.IsCreated) _rollingCollidersWriteIndices.Dispose();
|
||||
|
||||
_colliderRollbacks.Clear();
|
||||
_colliderRollbacksIndices.Clear();
|
||||
_ready = false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Ensure capacities for upcoming additions without reallocations.
|
||||
/// </summary>
|
||||
private void EnsureCapacity(int addRollingColliders, int addColliderRollbacks)
|
||||
{
|
||||
if (!_ready)
|
||||
{
|
||||
_networkManager.LogError("RollbackCollection is not configured. Call Configure(NetworkManager, double, float) first.");
|
||||
return;
|
||||
}
|
||||
|
||||
int newColliderRollbacksCount = _colliderRollbacksTAA.length + Math.Max(0, addColliderRollbacks);
|
||||
int newRollingCollidersCount = _rollingCollidersTAA.length + Math.Max(0, addRollingColliders);
|
||||
|
||||
if (_colliderRollbacksTAA.capacity < newColliderRollbacksCount)
|
||||
_colliderRollbacksTAA.capacity = newColliderRollbacksCount;
|
||||
if (_rollingCollidersTAA.capacity < newRollingCollidersCount)
|
||||
_rollingCollidersTAA.capacity = newRollingCollidersCount;
|
||||
|
||||
if (_colliderRollbacksSnapshots.Capacity < newColliderRollbacksCount)
|
||||
_colliderRollbacksSnapshots.Capacity = newColliderRollbacksCount;
|
||||
if (_rollingCollidersSnapshots.Capacity < newRollingCollidersCount * _maxSnapshots)
|
||||
_rollingCollidersSnapshots.Capacity = newRollingCollidersCount * _maxSnapshots;
|
||||
|
||||
if (_colliderRollbacksRolledBackMask.Capacity < newColliderRollbacksCount)
|
||||
_colliderRollbacksRolledBackMask.Capacity = newColliderRollbacksCount;
|
||||
if (_colliderRollbacksSceneHandles.Capacity < newColliderRollbacksCount)
|
||||
_colliderRollbacksSceneHandles.Capacity = newColliderRollbacksCount;
|
||||
if (_colliderRollbacksLerpFrames.Capacity < newColliderRollbacksCount)
|
||||
_colliderRollbacksLerpFrames.Capacity = newColliderRollbacksCount;
|
||||
if (_colliderRollbacksBoundingBoxData.Capacity < newColliderRollbacksCount)
|
||||
_colliderRollbacksBoundingBoxData.Capacity = newColliderRollbacksCount;
|
||||
if (_rollingColliderToColliderRollbacks.Capacity < newRollingCollidersCount)
|
||||
_rollingColliderToColliderRollbacks.Capacity = newRollingCollidersCount;
|
||||
if (_rollingCollidersWriteIndices.Capacity < newRollingCollidersCount)
|
||||
_rollingCollidersWriteIndices.Capacity = newRollingCollidersCount;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Registers a ColliderRollback with all its RollingColliders.
|
||||
/// Adds new rolling entries at the end (dense indexing).
|
||||
/// </summary>
|
||||
internal void RegisterColliderRollback(ColliderRollback colliderRollback)
|
||||
{
|
||||
if (!_ready)
|
||||
{
|
||||
_networkManager.LogError("RollbackCollection is not configured. Call Configure(NetworkManager, double, float) first.");
|
||||
return;
|
||||
}
|
||||
if (_colliderRollbacksIndices.ContainsKey(colliderRollback)) return;
|
||||
|
||||
IReadOnlyList<Transform> list = colliderRollback.GetRollingColliders();
|
||||
int addColliders = list.Count;
|
||||
int newColliderRollbacksCount = _colliderRollbacks.Count + 1;
|
||||
int newRollingCollidersCount = _rollingCollidersTAA.length + addColliders;
|
||||
EnsureCapacity(addColliders, 1);
|
||||
|
||||
_colliderRollbacks.Add(colliderRollback);
|
||||
_colliderRollbacksIndices[colliderRollback] = newColliderRollbacksCount - 1;
|
||||
_colliderRollbacksTAA.Add(colliderRollback.transform);
|
||||
_colliderRollbacksSnapshots.ResizeUninitialized(newColliderRollbacksCount);
|
||||
_colliderRollbacksRolledBackMask.Add(0);
|
||||
_colliderRollbacksSceneHandles.Add(colliderRollback.gameObject.scene.handle);
|
||||
_colliderRollbacksLerpFrames.Add(0);
|
||||
_colliderRollbacksBoundingBoxData.Add(colliderRollback.GetBoundingBoxData());
|
||||
|
||||
_rollingCollidersSnapshots.ResizeUninitialized(newRollingCollidersCount * _maxSnapshots);
|
||||
for (int i = 0; i < addColliders; i++)
|
||||
{
|
||||
Transform rollingCollider = list[i];
|
||||
_rollingCollidersWriteIndices.Add(0);
|
||||
_rollingColliderToColliderRollbacks.Add(newColliderRollbacksCount - 1);
|
||||
_rollingCollidersTAA.Add(rollingCollider);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Unregisters a ColliderRollback. Removes all its rolling entries.
|
||||
/// Uses swap-back removal for both rolling entries and the colliderRollbacks, keeping indices dense.
|
||||
/// </summary>
|
||||
internal void UnregisterColliderRollback(ColliderRollback cr)
|
||||
{
|
||||
if (!_ready) return;
|
||||
if (!_colliderRollbacksIndices.Remove(cr, out int colliderRollbacksIndex)) return;
|
||||
int lastColliderRollbacks = _colliderRollbacks.Count - 1;
|
||||
|
||||
// Remove all rolling entries belonging to this colliderRollbacks (scan backwards for stability).
|
||||
for (int i = _rollingColliderToColliderRollbacks.Length - 1; i >= 0; --i)
|
||||
{
|
||||
if (_rollingColliderToColliderRollbacks[i] == colliderRollbacksIndex)
|
||||
RemoveRollingColliderAtSwapBack(i);
|
||||
}
|
||||
|
||||
// Remove the colliderRollbacks by swapping with the last colliderRollbacks.
|
||||
if (colliderRollbacksIndex != lastColliderRollbacks)
|
||||
{
|
||||
ColliderRollback tempCr = _colliderRollbacks[lastColliderRollbacks];
|
||||
_colliderRollbacksIndices[tempCr] = colliderRollbacksIndex;
|
||||
_colliderRollbacks[colliderRollbacksIndex] = tempCr;
|
||||
// Re-tag colliders that belonged to lastColliderRollbacks to now point to colliderRollbacksIndex.
|
||||
for (int i = 0; i < _rollingColliderToColliderRollbacks.Length; i++)
|
||||
{
|
||||
if (_rollingColliderToColliderRollbacks[i] == lastColliderRollbacks)
|
||||
_rollingColliderToColliderRollbacks[i] = colliderRollbacksIndex;
|
||||
}
|
||||
}
|
||||
|
||||
_colliderRollbacksTAA.RemoveAtSwapBack(colliderRollbacksIndex);
|
||||
_colliderRollbacksRolledBackMask.RemoveAtSwapBack(colliderRollbacksIndex);
|
||||
_colliderRollbacksSceneHandles.RemoveAtSwapBack(colliderRollbacksIndex);
|
||||
_colliderRollbacksLerpFrames.RemoveAtSwapBack(colliderRollbacksIndex);
|
||||
_colliderRollbacksBoundingBoxData.RemoveAtSwapBack(colliderRollbacksIndex);
|
||||
_colliderRollbacks.RemoveAt(lastColliderRollbacks);
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes one rolling entry at index by swapping with the last item.
|
||||
/// Updates all parallel structures and GlobalIndex on the moved entry.
|
||||
/// </summary>
|
||||
internal void RemoveRollingColliderAtSwapBack(int rollingColliderIndex)
|
||||
{
|
||||
int last = _rollingCollidersTAA.length - 1;
|
||||
if (last < 0) return;
|
||||
|
||||
_rollingCollidersTAA.RemoveAtSwapBack(rollingColliderIndex);
|
||||
_rollingCollidersWriteIndices.RemoveAtSwapBack(rollingColliderIndex);
|
||||
_rollingColliderToColliderRollbacks.RemoveAtSwapBack(rollingColliderIndex);
|
||||
if (rollingColliderIndex != last)
|
||||
{
|
||||
// Move last snapshots ring over the removed slot.
|
||||
int dst = rollingColliderIndex * _maxSnapshots;
|
||||
int src = last * _maxSnapshots;
|
||||
for (int k = 0; k < _maxSnapshots; k++)
|
||||
_rollingCollidersSnapshots[dst + k] =_rollingCollidersSnapshots[src + k];
|
||||
}
|
||||
_rollingCollidersSnapshots.ResizeUninitialized(_rollingCollidersSnapshots.Length - _maxSnapshots);
|
||||
}
|
||||
/// <summary>
|
||||
/// Populates one snapshot for every non-rolled-back transform using a parallel job.
|
||||
/// Call this once per tick on the server (e.g., from OnPostTick).
|
||||
/// </summary>
|
||||
internal void CreateSnapshots()
|
||||
{
|
||||
if (!_ready) return;
|
||||
|
||||
if (_colliderRollbacksTAA.length > 0 && _rollingCollidersTAA.length > 0)
|
||||
{
|
||||
JobHandle first = new RollbackManager.IncrementGroupsFramesJob
|
||||
{
|
||||
maxSnapshots = _maxSnapshots,
|
||||
colliderRollbacksLerpFrames = _colliderRollbacksLerpFrames.AsArray(),
|
||||
colliderRollbacksRolledBackMask = _colliderRollbacksRolledBackMask.AsArray(),
|
||||
}.Schedule(_colliderRollbacksTAA.length, 64);
|
||||
JobHandle second = new RollbackManager.PopulateColliderRollbackSnapshotsJob
|
||||
{
|
||||
colliderRollbackSnapshots = _colliderRollbacksSnapshots.AsArray(),
|
||||
colliderRollbacksRolledBackMask = _colliderRollbacksRolledBackMask.AsArray()
|
||||
}.Schedule(_colliderRollbacksTAA, first);
|
||||
JobHandle third = new RollbackManager.PopulateRollingColliderSnapshotsJob
|
||||
{
|
||||
maxSnapshots = _maxSnapshots,
|
||||
rollingCollidersSnapshots = _rollingCollidersSnapshots.AsArray(),
|
||||
rollingCollidersWriteIndices = _rollingCollidersWriteIndices.AsArray(),
|
||||
colliderRollbacksRolledBackMask = _colliderRollbacksRolledBackMask.AsArray(),
|
||||
colliderToColliderRollbacks = _rollingColliderToColliderRollbacks.AsArray()
|
||||
}.Schedule(_rollingCollidersTAA, second);
|
||||
third.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
#region Sinlge ColliderRollback
|
||||
/// <summary>
|
||||
/// Computes lerp mode/endFrame/percent based on 'time' and applies rollback to the whole colliderRollbacks.
|
||||
/// </summary>
|
||||
internal void Rollback(ColliderRollback colliderRollback, float time, RollbackPhysicsType rollbackPhysicsType)
|
||||
{
|
||||
if (!_ready) return;
|
||||
if (!_colliderRollbacksIndices.TryGetValue(colliderRollback, out int colliderRollbacksIndex)) return;
|
||||
|
||||
// Already rolled back.
|
||||
if (IsRolledBack(colliderRollback))
|
||||
{
|
||||
_networkManager.LogWarning("Colliders are already rolled back. Returning colliders forward first.");
|
||||
Return(colliderRollback, rollbackPhysicsType);
|
||||
}
|
||||
|
||||
int frames = _colliderRollbacksLerpFrames[colliderRollbacksIndex];
|
||||
if (frames == 0) return;
|
||||
|
||||
/* If time were 0.3f and delta was 0.2f then the
|
||||
* result would be 1.5f. This indicates to lerp between
|
||||
* the first snapshot, and one after. */
|
||||
float decimalFrame = time / (float)_networkManager.TimeManager.TickDelta;
|
||||
|
||||
RollbackManager.FrameRollbackTypes mode;
|
||||
int endFrame;
|
||||
float percent;
|
||||
|
||||
/* Rollback is beyond written quantity.
|
||||
* Set to use the last snapshot. */
|
||||
if (decimalFrame > frames)
|
||||
{
|
||||
mode = RollbackManager.FrameRollbackTypes.Exact;
|
||||
// Be sure to subtract 1 to get last entry in snapshots.
|
||||
endFrame = frames - 1;
|
||||
// Not needed for exact but must be set.
|
||||
percent = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
percent = decimalFrame % 1f;
|
||||
endFrame = Mathf.CeilToInt(decimalFrame);
|
||||
|
||||
/* If the end frame is larger than or equal to 1
|
||||
* then a lerp between two snapshots can occur. If
|
||||
* equal to 1 then the lerp would occur between 0 and 1. */
|
||||
if (endFrame >= 1)
|
||||
{
|
||||
mode = RollbackManager.FrameRollbackTypes.LerpMiddle;
|
||||
}
|
||||
// Rolling back only 1 frame.
|
||||
else
|
||||
{
|
||||
endFrame = 0;
|
||||
mode = RollbackManager.FrameRollbackTypes.LerpFirst;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply to all rolling entries belonging to this colliderRollbacks.
|
||||
for (int i = 0; i < _rollingColliderToColliderRollbacks.Length; i++)
|
||||
if (_rollingColliderToColliderRollbacks[i] == colliderRollbacksIndex)
|
||||
ApplyRollbackIndex(i, endFrame, percent, mode);
|
||||
_colliderRollbacksRolledBackMask[colliderRollbacksIndex] = 1;
|
||||
|
||||
_rollbackPhysics |= rollbackPhysicsType;
|
||||
SyncTransforms(rollbackPhysicsType);
|
||||
}
|
||||
/// <summary>
|
||||
/// Called when a specific colliderRollbacks should return.
|
||||
/// </summary>
|
||||
internal void Return(ColliderRollback colliderRollback, RollbackPhysicsType rollbackPhysicsType)
|
||||
{
|
||||
if (!_ready) return;
|
||||
if (!_colliderRollbacksIndices.TryGetValue(colliderRollback, out int colliderRollbacksIndex)) return;
|
||||
|
||||
if (!IsRolledBack(colliderRollback))
|
||||
return;
|
||||
|
||||
// Iterate dense rolling entries and return only those that belong to this colliderRollbacks.
|
||||
for (int i = 0; i < _rollingColliderToColliderRollbacks.Length; i++)
|
||||
{
|
||||
if (_rollingColliderToColliderRollbacks[i] == colliderRollbacksIndex)
|
||||
{
|
||||
int frames = _colliderRollbacksLerpFrames[colliderRollbacksIndex];
|
||||
if (frames <= 0)
|
||||
continue;
|
||||
|
||||
int writeIdx = _rollingCollidersWriteIndices[i];
|
||||
int baseOffset = i * _maxSnapshots;
|
||||
int lastIdx = (writeIdx - 1 + _maxSnapshots) % _maxSnapshots;
|
||||
|
||||
// Return to the newest (last written) snapshot
|
||||
int snapshotIndex = baseOffset + lastIdx;
|
||||
ColliderSnapshot s = _rollingCollidersSnapshots[snapshotIndex];
|
||||
Transform t = _rollingCollidersTAA[i];
|
||||
t.SetPositionAndRotation(s.WorldPosition, s.WorldRotation);
|
||||
}
|
||||
}
|
||||
_colliderRollbacksRolledBackMask[colliderRollbacksIndex] = 0;
|
||||
|
||||
_rollbackPhysics |= rollbackPhysicsType;
|
||||
SyncTransforms(rollbackPhysicsType);
|
||||
}
|
||||
/// <summary>
|
||||
/// Applies a rollback for a specific global transform index using the provided interpolation mode.
|
||||
/// </summary>
|
||||
/// <param name="rollingColliderIdx">RollingCollider index into the ColliderRollback.</param>
|
||||
/// <param name="mode">Frame interpolation mode.</param>
|
||||
/// <param name="endFrame">Target history frame index (0 = newest).</param>
|
||||
/// <param name="percent">Lerp factor for interpolation modes.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ApplyRollbackIndex(int rollingColliderIdx, int endFrame, float percent,
|
||||
RollbackManager.FrameRollbackTypes mode)
|
||||
{
|
||||
if (!_ready || rollingColliderIdx < 0 || rollingColliderIdx >= _rollingCollidersTAA.length)
|
||||
return;
|
||||
|
||||
int colliderRollbacksIndex = _rollingColliderToColliderRollbacks[rollingColliderIdx];
|
||||
int writeIdx = _rollingCollidersWriteIndices[rollingColliderIdx];
|
||||
int baseOffset = rollingColliderIdx * _maxSnapshots;
|
||||
int lastIdx = (writeIdx - 1 + _maxSnapshots) % _maxSnapshots;
|
||||
bool isRecycled = _colliderRollbacksLerpFrames[colliderRollbacksIndex] >= _maxSnapshots;
|
||||
|
||||
Transform t = _rollingCollidersTAA[rollingColliderIdx];
|
||||
|
||||
if (mode == RollbackManager.FrameRollbackTypes.Exact)
|
||||
{
|
||||
ColliderSnapshot s = _rollingCollidersSnapshots[BufIndex(baseOffset, endFrame, lastIdx, isRecycled, _maxSnapshots)];
|
||||
t.SetPositionAndRotation(s.WorldPosition, s.WorldRotation);
|
||||
}
|
||||
else if (mode == RollbackManager.FrameRollbackTypes.LerpFirst)
|
||||
{
|
||||
ColliderSnapshot s = _rollingCollidersSnapshots[BufIndex(baseOffset, endFrame, lastIdx, isRecycled, _maxSnapshots)];
|
||||
t.GetPositionAndRotation(out Vector3 curPos, out Quaternion curRot);
|
||||
t.SetPositionAndRotation(Vector3.Lerp(curPos, s.WorldPosition, percent),
|
||||
Quaternion.Lerp(curRot, s.WorldRotation, percent));
|
||||
}
|
||||
else if (mode == RollbackManager.FrameRollbackTypes.LerpMiddle)
|
||||
{
|
||||
ColliderSnapshot s0 = _rollingCollidersSnapshots[BufIndex(baseOffset, endFrame - 1, lastIdx, isRecycled, _maxSnapshots)];
|
||||
ColliderSnapshot s1 = _rollingCollidersSnapshots[BufIndex(baseOffset, endFrame, lastIdx, isRecycled, _maxSnapshots)];
|
||||
t.SetPositionAndRotation(Vector3.Lerp(s0.WorldPosition, s1.WorldPosition, percent),
|
||||
Quaternion.Lerp(s0.WorldRotation, s1.WorldRotation, percent));
|
||||
}
|
||||
return;
|
||||
|
||||
// compute buffer index with negative-safe modulo
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static int BufIndex(int baseOffset, int history, int lastIdx, bool isRecycled, int maxSnapshots)
|
||||
{
|
||||
int idx = baseOffset + lastIdx - history;
|
||||
// If negative value start taking from the back.
|
||||
if (idx < 0)
|
||||
{
|
||||
/* Cannot take from back, snapshots aren't filled yet.
|
||||
* Instead take the oldest snapshot, which in this case
|
||||
* would be index baseOffset. */
|
||||
if (!isRecycled)
|
||||
return baseOffset;
|
||||
// Snapshots filled, take from back.
|
||||
else
|
||||
return idx + maxSnapshots;
|
||||
}
|
||||
// Not a negative value, return as is.
|
||||
else return idx;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets rolled-back state for a colliderRollbacks in O(1). No per-rolling writes.
|
||||
/// </summary>
|
||||
/// <summary>True if the colliderRollbacks is currently rolled back.</summary>
|
||||
public bool IsRolledBack(ColliderRollback cr)
|
||||
=> _ready && _colliderRollbacksIndices.TryGetValue(cr, out int g) && _colliderRollbacksRolledBackMask[g] != 0;
|
||||
#endregion
|
||||
|
||||
#region Job ColliderRollback
|
||||
/// <summary>
|
||||
/// Run rollback for ALL colliderRollbacks in parallel (jobified).
|
||||
/// </summary>
|
||||
internal void Rollback(int sceneHandle, float time, RollbackPhysicsType rollbackPhysicsType)
|
||||
{
|
||||
if (!_ready || _rollingCollidersTAA.length == 0)
|
||||
return;
|
||||
|
||||
Return();
|
||||
JobHandle job = new RollbackManager.ApplyRollbackJob
|
||||
{
|
||||
sceneHandle = sceneHandle,
|
||||
maxSnapshots = _maxSnapshots,
|
||||
decimalFrame = time / (float)_networkManager.TimeManager.TickDelta,
|
||||
colliderToColliderRollbacks = _rollingColliderToColliderRollbacks.AsArray(),
|
||||
colliderRollbacksSceneHandles = _colliderRollbacksSceneHandles.AsArray(),
|
||||
colliderRollbacksLerpFrames = _colliderRollbacksLerpFrames.AsArray(),
|
||||
rollingCollidersWriteIndices = _rollingCollidersWriteIndices.AsArray(),
|
||||
colliderRollbacksRolledBackMask = _colliderRollbacksRolledBackMask.AsArray(),
|
||||
rollingCollidersSnapshots = _rollingCollidersSnapshots.AsArray()
|
||||
}.Schedule(_rollingCollidersTAA);
|
||||
job.Complete();
|
||||
|
||||
_rollbackPhysics |= rollbackPhysicsType;
|
||||
SyncTransforms(rollbackPhysicsType);
|
||||
}
|
||||
/// <summary>
|
||||
/// Run rollback for intersected colliderRollbacks by ray in parallel (jobified).
|
||||
/// </summary>
|
||||
internal void Rollback(RollbackManager.RollbackRequest rollbackRequest)
|
||||
{
|
||||
if (!_ready || _rollingCollidersTAA.length == 0)
|
||||
return;
|
||||
|
||||
Return();
|
||||
JobHandle job = new RollbackManager.ApplyRollbackRaycastJob
|
||||
{
|
||||
sceneHandle = rollbackRequest.sceneHandle,
|
||||
maxSnapshots = _maxSnapshots,
|
||||
decimalFrame = rollbackRequest.time / (float)_networkManager.TimeManager.TickDelta,
|
||||
origin = rollbackRequest.origin,
|
||||
dir = rollbackRequest.direction,
|
||||
distance = rollbackRequest.distance,
|
||||
physicsType = (int)rollbackRequest.rollbackPhysicsType,
|
||||
colliderToColliderRollbacks = _rollingColliderToColliderRollbacks.AsArray(),
|
||||
colliderRollbacksBoundingBoxData = _colliderRollbacksBoundingBoxData.AsArray(),
|
||||
colliderRollbacksSceneHandles = _colliderRollbacksSceneHandles.AsArray(),
|
||||
colliderRollbacksLerpFrames = _colliderRollbacksLerpFrames.AsArray(),
|
||||
rollingCollidersWriteIndices = _rollingCollidersWriteIndices.AsArray(),
|
||||
colliderRollbacksRolledBackMask = _colliderRollbacksRolledBackMask.AsArray(),
|
||||
colliderRollbacksSnapshots = _colliderRollbacksSnapshots.AsArray(),
|
||||
rollingCollidersSnapshots = _rollingCollidersSnapshots.AsArray()
|
||||
}.Schedule(_rollingCollidersTAA);
|
||||
job.Complete();
|
||||
|
||||
_rollbackPhysics |= rollbackRequest.rollbackPhysicsType;
|
||||
SyncTransforms(rollbackRequest.rollbackPhysicsType);
|
||||
}
|
||||
/// <summary>
|
||||
/// Request rollback for deferred rollback for intersected colliderRollbacks by ray in parallel (jobified).
|
||||
/// </summary>
|
||||
internal void RequestRollbackDeferred(RollbackManager.RollbackRequest rollbackRequest)
|
||||
{
|
||||
_writeRequests.Add(rollbackRequest);
|
||||
_requestsRollbackPhysics |= rollbackRequest.rollbackPhysicsType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run rollback for all requests intersected colliderRollbacks by ray in parallel (jobified).
|
||||
/// </summary>
|
||||
/// <returns>Count of requests.</returns>
|
||||
internal int RollbackDeferred()
|
||||
{
|
||||
if (!_ready || _rollingCollidersTAA.length == 0 || _writeRequests.Length == 0)
|
||||
return 0;
|
||||
|
||||
Return();
|
||||
|
||||
(_readRequests, _writeRequests) = (_writeRequests, _readRequests);
|
||||
_writeRequests.Clear();
|
||||
|
||||
int groupCount = _colliderRollbacksTAA.length;
|
||||
int batchSize = ComputeBatchSize(groupCount);
|
||||
|
||||
NativeArray<float> sum = new NativeArray<float>(groupCount, Allocator.TempJob);
|
||||
NativeArray<int> cnt = new NativeArray<int>(groupCount, Allocator.TempJob);
|
||||
try
|
||||
{
|
||||
JobHandle computeHandle = new RollbackManager.ComputeDeferredRollbackSumsJob
|
||||
{
|
||||
tickDelta = (float)_networkManager.TimeManager.TickDelta,
|
||||
requests = _readRequests.AsArray(),
|
||||
colliderRollbacksSceneHandles = _colliderRollbacksSceneHandles.AsArray(),
|
||||
colliderRollbacksLerpFrames = _colliderRollbacksLerpFrames.AsArray(),
|
||||
colliderRollbacksBoundingBoxData = _colliderRollbacksBoundingBoxData.AsArray(),
|
||||
colliderRollbacksSnapshots = _colliderRollbacksSnapshots.AsArray(),
|
||||
sumDecimalFrame = sum,
|
||||
hitCount = cnt
|
||||
}.Schedule(groupCount, batchSize);
|
||||
|
||||
JobHandle applyHandle = new RollbackManager.ApplyDeferredRollbackJob
|
||||
{
|
||||
maxSnapshots = _maxSnapshots,
|
||||
colliderToColliderRollbacks = _rollingColliderToColliderRollbacks.AsArray(),
|
||||
colliderRollbacksLerpFrames = _colliderRollbacksLerpFrames.AsArray(),
|
||||
rollingCollidersWriteIndices = _rollingCollidersWriteIndices.AsArray(),
|
||||
colliderRollbacksRolledBackMask = _colliderRollbacksRolledBackMask.AsArray(),
|
||||
rollingCollidersSnapshots = _rollingCollidersSnapshots.AsArray(),
|
||||
sumDecimalFrame = sum,
|
||||
hitCount = cnt
|
||||
}.Schedule(_rollingCollidersTAA, computeHandle);
|
||||
|
||||
applyHandle.Complete();
|
||||
}
|
||||
finally
|
||||
{
|
||||
sum.Dispose();
|
||||
cnt.Dispose();
|
||||
}
|
||||
|
||||
_rollbackPhysics |= _requestsRollbackPhysics;
|
||||
_requestsRollbackPhysics = 0;
|
||||
SyncTransforms(_rollbackPhysics);
|
||||
return _readRequests.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run Return for ALL colliderRollbacks in parallel (jobified).
|
||||
/// </summary>
|
||||
internal void Return()
|
||||
{
|
||||
if (!_ready || _rollingCollidersTAA.length == 0)
|
||||
return;
|
||||
|
||||
JobHandle job = new RollbackManager.ReturnRollbackAllJob
|
||||
{
|
||||
maxSnapshots = _maxSnapshots,
|
||||
colliderToColliderRollbacks = _rollingColliderToColliderRollbacks.AsArray(),
|
||||
colliderRollbacksLerpFrames = _colliderRollbacksLerpFrames.AsArray(),
|
||||
rollingCollidersWriteIndices = _rollingCollidersWriteIndices.AsArray(),
|
||||
colliderRollbacksRolledBackMask = _colliderRollbacksRolledBackMask.AsArray(),
|
||||
rollingCollidersSnapshots = _rollingCollidersSnapshots.AsArray()
|
||||
}.Schedule(_rollingCollidersTAA);
|
||||
job.Complete();
|
||||
|
||||
SyncTransforms(_rollbackPhysics);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Applies transforms for the specified physics type.
|
||||
/// </summary>
|
||||
/// <param name = "physicsType"></param>
|
||||
private static void SyncTransforms(RollbackPhysicsType physicsType)
|
||||
{
|
||||
if ((physicsType & RollbackPhysicsType.Physics) > 0)
|
||||
Physics.SyncTransforms();
|
||||
if ((physicsType & RollbackPhysicsType.Physics2D) > 0)
|
||||
Physics2D.SyncTransforms();
|
||||
}
|
||||
|
||||
private static int ComputeBatchSize(int length, int minBatch = 1, int maxBatch = 128)
|
||||
{
|
||||
if (length <= 0) return 1;
|
||||
|
||||
// +1: main thread + worker threads
|
||||
int workers = JobsUtility.JobWorkerCount + 1;
|
||||
|
||||
// Aim for ~4 waves of batches across all workers.
|
||||
int targetBatches = Mathf.Max(1, workers * 4);
|
||||
|
||||
// CeilDiv to get iterations per batch
|
||||
int batch = (length + targetBatches - 1) / targetBatches;
|
||||
|
||||
return Mathf.Clamp(batch, minBatch, maxBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a06ebb5c8a2323940b9eab5fea5ae220
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackCollection.Threaded.cs
|
||||
uploadId: 866910
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
#if FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Jobs;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
public partial class RollbackManager
|
||||
{
|
||||
internal enum DeferredRollbackOrder : byte
|
||||
{
|
||||
PreTick = 0,
|
||||
Tick = 1,
|
||||
PostTick = 2
|
||||
}
|
||||
|
||||
internal enum BoundingBoxType
|
||||
{
|
||||
/// <summary>
|
||||
/// Disable this feature.
|
||||
/// </summary>
|
||||
Disabled,
|
||||
/// <summary>
|
||||
/// Manually specify the dimensions of a bounding box.
|
||||
/// </summary>
|
||||
Manual
|
||||
}
|
||||
|
||||
internal struct BoundingBoxData
|
||||
{
|
||||
public RollbackPhysicsType rollbackPhysicsType;
|
||||
public BoundingBoxType boundingBoxType;
|
||||
public float3 extends;
|
||||
public float3 center;
|
||||
public quaternion localRotation;
|
||||
|
||||
public BoundingBoxData(RollbackPhysicsType rollbackPhysicsType, BoundingBoxType boundingBoxType,
|
||||
float3 extends, float3 center, quaternion localRotation)
|
||||
{
|
||||
this.rollbackPhysicsType = rollbackPhysicsType;
|
||||
this.boundingBoxType = boundingBoxType;
|
||||
this.extends = extends;
|
||||
this.center = center;
|
||||
this.localRotation = localRotation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A deferred rollback request.
|
||||
/// </summary>
|
||||
public struct RollbackRequest
|
||||
{
|
||||
public int sceneHandle;
|
||||
public float3 origin;
|
||||
public float3 direction;
|
||||
public float distance;
|
||||
public float time;
|
||||
public RollbackPhysicsType rollbackPhysicsType;
|
||||
|
||||
public RollbackRequest(int sceneHandle, float3 origin, float3 direction, float distance, float time, RollbackPhysicsType rollbackPhysicsType)
|
||||
{
|
||||
this.sceneHandle = sceneHandle;
|
||||
this.origin = origin;
|
||||
this.direction = direction;
|
||||
this.distance = distance;
|
||||
this.time = time;
|
||||
this.rollbackPhysicsType = rollbackPhysicsType;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b7001cad72b98c4a85dbde737dcaf43
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.Threaded.Types.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,244 @@
|
||||
#if FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using FishNet.Managing;
|
||||
using FishNet.Managing.Timing;
|
||||
using FishNet.Transporting;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
public partial class RollbackManager : MonoBehaviour
|
||||
{
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
[Tooltip("Maximum time in the past colliders can be rolled back to.")]
|
||||
[SerializeField]
|
||||
private float _maximumRollbackTime = 1.25f;
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
[Tooltip("When to invoke OnRollbackDeferred.")]
|
||||
[SerializeField]
|
||||
private DeferredRollbackOrder _deferredRollbackOrder = DeferredRollbackOrder.PreTick;
|
||||
/// <summary>
|
||||
/// Maximum time in the past colliders can be rolled back to.
|
||||
/// </summary>
|
||||
internal float MaximumRollbackTime => _maximumRollbackTime;
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
[Tooltip("Interpolation value for the NetworkTransforms or objects being rolled back.")]
|
||||
[Range(0, 250)]
|
||||
[SerializeField]
|
||||
internal ushort Interpolation = 2;
|
||||
#endregion
|
||||
|
||||
#region Private
|
||||
|
||||
#region Private Profiler Markers
|
||||
|
||||
private static readonly ProfilerMarker _pm_OnPreTick = new("RollbackManager.TimeManager_OnPreTick()");
|
||||
private static readonly ProfilerMarker _pm_OnTick = new("RollbackManager.TimeManager_OnTick()");
|
||||
private static readonly ProfilerMarker _pm_OnPostTick = new("RollbackManager.TimeManager_OnPostTick()");
|
||||
private static readonly ProfilerMarker _pm_CreateSnapshots = new("RollbackManager.CreateSnapshots()");
|
||||
private static readonly ProfilerMarker _pm_Rollback0 = new("RollbackManager.Rollback(int, PreciseTick, RollbackPhysicsType, bool)");
|
||||
private static readonly ProfilerMarker _pm_Rollback1 = new("RollbackManager.Rollback(int, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType, bool)");
|
||||
private static readonly ProfilerMarker _pm_RequestRollbackDeferred = new("RollbackManager.RequestRollbackDeferred(int, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType, bool)");
|
||||
private static readonly ProfilerMarker _pm_RollbackDeferred = new("RollbackManager.RollbackDeferred()");
|
||||
private static readonly ProfilerMarker _pm_Return = new("RollbackManager.Return()");
|
||||
|
||||
private static readonly ProfilerMarker _pm_RegisterColliderRollback = new("RollbackManager.RegisterColliderRollback(ColliderRollback)");
|
||||
private static readonly ProfilerMarker _pm_UnregisterColliderRollback = new("RollbackManager.UnregisterColliderRollback(ColliderRollback)");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Called when deferred rollback occured for all requests.
|
||||
/// </summary>
|
||||
public event Action OnRollbackDeferred;
|
||||
/// <summary>
|
||||
/// Called when deferred rollback in past occured for all requests.
|
||||
/// </summary>
|
||||
public event Action OnPostRollbackDeferred;
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this script for use.
|
||||
/// </summary>
|
||||
/// <param name = "manager"></param>
|
||||
internal void InitializeOnce_Internal(NetworkManager manager)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics, bool) instead.")] //Remove on V5
|
||||
public void Rollback(Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(Scene, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics, bool) instead.")] //Remove on V5
|
||||
public void Rollback(Scene scene, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(int, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics, bool) instead.")] //Remove on V5
|
||||
public void Rollback(int sceneHandle, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(Scene, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics2D, bool) instead.")] //Remove on V5
|
||||
public void Rollback(Scene scene, Vector2 origin, Vector2 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics2D, bool) instead.")] //Remove on V5
|
||||
public void Rollback(Vector2 origin, Vector2 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back all colliders.
|
||||
/// </summary>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back all colliders in a scene.
|
||||
/// </summary>
|
||||
/// <param name = "scene">Scene containing colliders.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(Scene scene, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back all colliders in a scene.
|
||||
/// </summary>
|
||||
/// <param name = "sceneHandle">Scene handle containing colliders.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(int sceneHandle, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
using (_pm_Rollback0.Auto())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back colliders hit by a test cast against bounding boxes.
|
||||
/// </summary>
|
||||
/// <param name = "origin">Ray origin.</param>
|
||||
/// <param name = "normalizedDirection">Direction to cast.</param>
|
||||
/// <param name = "distance">Distance of cast.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back colliders hit by a test cast against bounding boxes, in a specific scene.
|
||||
/// </summary>
|
||||
/// <param name = "scene">Scene containing colliders.</param>
|
||||
/// <param name = "origin">Ray origin.</param>
|
||||
/// <param name = "normalizedDirection">Direction to cast.</param>
|
||||
/// <param name = "distance">Distance of cast.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(Scene scene, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back colliders hit by a test cast against bounding boxes, in a specific scene.
|
||||
/// </summary>
|
||||
/// <param name = "sceneHandle">Scene handle containing colliders.</param>
|
||||
/// <param name = "origin">Ray origin.</param>
|
||||
/// <param name = "normalizedDirection">Direction to cast.</param>
|
||||
/// <param name = "distance">Distance of cast.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(int sceneHandle, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
using (_pm_Rollback1.Auto())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests deferred rollback for colliders hit by a test cast against bounding boxes.
|
||||
/// </summary>
|
||||
/// <param name = "origin">Ray origin.</param>
|
||||
/// <param name = "normalizedDirection">Direction to cast.</param>
|
||||
/// <param name = "distance">Distance of cast.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void RequestRollbackDeferred(Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests deferred rollback for colliders hit by a test cast against bounding boxes, in a specific scene.
|
||||
/// </summary>
|
||||
/// <param name = "scene">Scene containing colliders.</param>
|
||||
/// <param name = "origin">Ray origin.</param>
|
||||
/// <param name = "normalizedDirection">Direction to cast.</param>
|
||||
/// <param name = "distance">Distance of cast.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void RequestRollbackDeferred(Scene scene, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests deferred rollback for colliders hit by a test cast against bounding boxes, in a specific scene.
|
||||
/// </summary>
|
||||
/// <param name = "sceneHandle">Scene handle containing colliders.</param>
|
||||
/// <param name = "origin">Ray origin.</param>
|
||||
/// <param name = "normalizedDirection">Direction to cast.</param>
|
||||
/// <param name = "distance">Distance of cast.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void RequestRollbackDeferred(int sceneHandle, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
using (_pm_RequestRollbackDeferred.Auto())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back for all RollbackRequests.
|
||||
/// </summary>
|
||||
public void RollbackDeferred()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all ColliderRollback objects back to their original position.
|
||||
/// </summary>
|
||||
public void Return()
|
||||
{
|
||||
using (_pm_Return.Auto())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d26b760e7ad25ab409143779624d67c9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.Threaded.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,187 @@
|
||||
#if !FISHNET_THREADED_COLLIDER_ROLLBACK
|
||||
using FishNet.Connection;
|
||||
using FishNet.Managing;
|
||||
using FishNet.Managing.Scened;
|
||||
using FishNet.Managing.Timing;
|
||||
using FishNet.Transporting;
|
||||
using GameKit.Dependencies.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
public class RollbackManager : MonoBehaviour
|
||||
{
|
||||
#region Internal.
|
||||
/// <summary>
|
||||
/// Cached value for bounding box layermask.
|
||||
/// </summary>
|
||||
internal int? BoundingBoxLayerNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_boundingBoxLayerNumber == null)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if (1 << i == BoundingBoxLayer.value)
|
||||
{
|
||||
_boundingBoxLayerNumber = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _boundingBoxLayerNumber;
|
||||
}
|
||||
}
|
||||
private int? _boundingBoxLayerNumber;
|
||||
#endregion
|
||||
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
[Tooltip("Layer to use when creating and checking against bounding boxes. This should be different from any layer used.")]
|
||||
[SerializeField]
|
||||
private LayerMask _boundingBoxLayer = 0;
|
||||
/// <summary>
|
||||
/// Layer to use when creating and checking against bounding boxes. This should be different from any layer used.
|
||||
/// </summary>
|
||||
internal LayerMask BoundingBoxLayer => _boundingBoxLayer;
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
[Tooltip("Maximum time in the past colliders can be rolled back to.")]
|
||||
[SerializeField]
|
||||
private float _maximumRollbackTime = 1.25f;
|
||||
/// <summary>
|
||||
/// Maximum time in the past colliders can be rolled back to.
|
||||
/// </summary>
|
||||
internal float MaximumRollbackTime => _maximumRollbackTime;
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
[Tooltip("Interpolation value for the NetworkTransforms or objects being rolled back.")]
|
||||
[Range(0, 250)]
|
||||
[SerializeField]
|
||||
internal ushort Interpolation = 2;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this script for use.
|
||||
/// </summary>
|
||||
/// <param name = "manager"></param>
|
||||
internal void InitializeOnce_Internal(NetworkManager manager)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics, bool) instead.")] //Remove on V5
|
||||
public void Rollback(Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(Scene, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics, bool) instead.")] //Remove on V5
|
||||
public void Rollback(Scene scene, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(int, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics, bool) instead.")] //Remove on V5
|
||||
public void Rollback(int sceneHandle, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(Scene, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics2D, bool) instead.")] //Remove on V5
|
||||
public void Rollback(Scene scene, Vector2 origin, Vector2 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use Rollback(Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics2D, bool) instead.")] //Remove on V5
|
||||
public void Rollback(Vector2 origin, Vector2 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back all colliders.
|
||||
/// </summary>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back all colliders in a scene.
|
||||
/// </summary>
|
||||
/// <param name = "scene">Scene containing colliders.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(Scene scene, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back all colliders in a scene.
|
||||
/// </summary>
|
||||
/// <param name = "sceneHandle">Scene handle containing colliders.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(int sceneHandle, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back colliders hit by a test cast against bounding boxes.
|
||||
/// </summary>
|
||||
/// <param name = "origin">Ray origin.</param>
|
||||
/// <param name = "normalizedDirection">Direction to cast.</param>
|
||||
/// <param name = "distance">Distance of cast.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back colliders hit by a test cast against bounding boxes, in a specific scene.
|
||||
/// </summary>
|
||||
/// <param name = "scene">Scene containing colliders.</param>
|
||||
/// <param name = "origin">Ray origin.</param>
|
||||
/// <param name = "normalizedDirection">Direction to cast.</param>
|
||||
/// <param name = "distance">Distance of cast.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(Scene scene, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls back colliders hit by a test cast against bounding boxes, in a specific scene.
|
||||
/// </summary>
|
||||
/// <param name = "sceneHandle">Scene handle containing colliders.</param>
|
||||
/// <param name = "origin">Ray origin.</param>
|
||||
/// <param name = "normalizedDirection">Direction to cast.</param>
|
||||
/// <param name = "distance">Distance of cast.</param>
|
||||
/// <param name = "pt">Precise tick received from the client.</param>
|
||||
/// <param name = "physicsType">Type of physics to rollback; this is often what your casts will use.</param>
|
||||
/// <param name = "asOwnerAndClientHost">True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost.</param>
|
||||
public void Rollback(int sceneHandle, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all ColliderRollback objects back to their original position.
|
||||
/// </summary>
|
||||
public void Return()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b185516acd802904383e2a5f1a666750
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace FishNet.Component.ColliderRollback
|
||||
{
|
||||
/// <summary>
|
||||
/// Which physics to apply after rolling back colliders.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
[System.Flags]
|
||||
public enum RollbackPhysicsType
|
||||
{
|
||||
Physics = 1,
|
||||
Physics2D = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82b31e74d64a0c44d8fa2f3b6b08ebca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackPhysicsType.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a72c0fe8d07e9fd49911db527eddbc39
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd9a0ca39fab66c448fdc3e25da9d482
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e92e9b5fef66ccb4d991a260767c3be4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Sirenix.OdinInspector
|
||||
{
|
||||
#if !ODIN_INSPECTOR
|
||||
|
||||
public class TabGroupAttribute : PropertyAttribute
|
||||
{
|
||||
public string name;
|
||||
public bool foldEverything;
|
||||
|
||||
public TabGroupAttribute(string name, bool foldEverything = false)
|
||||
{
|
||||
this.foldEverything = foldEverything;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public class ShowIfAttribute : PropertyAttribute
|
||||
{
|
||||
#region Fields
|
||||
public string comparedPropertyName { get; private set; }
|
||||
public object comparedValue { get; private set; }
|
||||
public DisablingType disablingType { get; private set; }
|
||||
|
||||
public enum DisablingType
|
||||
{
|
||||
ReadOnly = 2,
|
||||
DontDraw = 3
|
||||
}
|
||||
#endregion
|
||||
|
||||
public ShowIfAttribute(string comparedPropertyName, object comparedValue, DisablingType disablingType = DisablingType.DontDraw)
|
||||
{
|
||||
this.comparedPropertyName = comparedPropertyName;
|
||||
this.comparedValue = comparedValue;
|
||||
this.disablingType = disablingType;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d18dbd89f49c7a4888bbc0e330675a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Editor/PlaceholderAttributes.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "GameKit.Dependencies",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.textmeshpro",
|
||||
"expression": "",
|
||||
"define": "TEXTMESHPRO"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d82bdf40e2465b44b34adf79595e74c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/GameKit.Dependencies.asmdef
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53002e457d153bf49aad4b2b28d4353c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,76 @@
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoad]
|
||||
#endif
|
||||
public static class ApplicationState
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// True if application is quitting.
|
||||
/// </summary>
|
||||
private static bool _isQuitting;
|
||||
#endif
|
||||
static ApplicationState()
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
_isQuitting = false;
|
||||
#endif
|
||||
Application.quitting -= Application_quitting;
|
||||
Application.quitting += Application_quitting;
|
||||
}
|
||||
|
||||
private static void Application_quitting()
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
_isQuitting = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the application is quitting for editor or builds.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsQuitting()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if ((!EditorApplication.isPlayingOrWillChangePlaymode && EditorApplication.isPlaying) || !EditorApplication.isPlaying)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
#else
|
||||
return _isQuitting;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the application is playing for editor or builds.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsPlaying()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return EditorApplication.isPlaying;
|
||||
#else
|
||||
return Application.isPlaying;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Quits the application for editor or builds.
|
||||
/// </summary>
|
||||
public static void Quit()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.isPlaying = false;
|
||||
#else
|
||||
Application.Quit();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54eb82a57a65e8548b57f5ca2a62bb76
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ApplicationState.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,135 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GameKit.Dependencies.Utilities.Types;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Arrays
|
||||
{
|
||||
/// <summary>
|
||||
/// Randomizer used for shuffling.
|
||||
/// </summary>
|
||||
private static readonly System.Random _random = new();
|
||||
/// <summary>
|
||||
/// StringBuilder to save performance.
|
||||
/// </summary>
|
||||
private static readonly StringBuilder _stringBuilder = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Cast each item in the collection ToString and returns all values.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string ToString<T>(this IEnumerable<T> collection, string delimeter = ", ")
|
||||
{
|
||||
if (collection == null)
|
||||
return string.Empty;
|
||||
|
||||
_stringBuilder.Clear();
|
||||
foreach (T item in collection)
|
||||
_stringBuilder.Append(item.ToString() + delimeter);
|
||||
|
||||
// Remove ending delimeter.
|
||||
if (_stringBuilder.Length > delimeter.Length)
|
||||
_stringBuilder.Length -= delimeter.Length;
|
||||
|
||||
return _stringBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an object from a list through re-ordering. This breaks the order of the list for a faster remove.
|
||||
/// </summary>
|
||||
/// <typeparam name = "T"></typeparam>
|
||||
/// <param name = "list"></param>
|
||||
/// <param name = "value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool FastReferenceRemove<T>(this List<T> list, object value)
|
||||
{
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (ReferenceEquals(list[i], value))
|
||||
{
|
||||
FastIndexRemove(list, i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an index from a list through re-ordering. This breaks the order of the list for a faster remove.
|
||||
/// </summary>
|
||||
/// <typeparam name = "T"></typeparam>
|
||||
/// <param name = "list"></param>
|
||||
/// <param name = "index"></param>
|
||||
public static void FastIndexRemove<T>(this List<T> list, int index)
|
||||
{
|
||||
list[index] = list[^1];
|
||||
list.RemoveAt(list.Count - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuffles an array.
|
||||
/// </summary>
|
||||
/// <typeparam name = "T"></typeparam>
|
||||
/// <param name = "array"></param>
|
||||
public static void Shuffle<T>(this T[] array)
|
||||
{
|
||||
int n = array.Length;
|
||||
for (int i = 0; i < n - 1; i++)
|
||||
{
|
||||
int r = i + _random.Next(n - i);
|
||||
T t = array[r];
|
||||
array[r] = array[i];
|
||||
array[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuffles a list.
|
||||
/// </summary>
|
||||
/// <typeparam name = "T"></typeparam>
|
||||
/// <param name = "lst"></param>
|
||||
public static void Shuffle<T>(this List<T> lst)
|
||||
{
|
||||
int n = lst.Count;
|
||||
for (int i = 0; i < n - 1; i++)
|
||||
{
|
||||
int r = i + _random.Next(n - i);
|
||||
T t = lst[r];
|
||||
lst[r] = lst[i];
|
||||
lst[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to a collection, ordering it's position based on itemOrder. Lower values are inserted near the beginning of the collection.
|
||||
/// </summary>
|
||||
public static void AddOrdered<T>(this List<T> collection, T item) where T : IOrderable
|
||||
{
|
||||
int count = collection.Count;
|
||||
int itemOrder = item.Order;
|
||||
|
||||
/* If no entries or is equal or larger to last
|
||||
* entry then value can be added onto the end. */
|
||||
if (count == 0 || itemOrder >= collection[^1].Order)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
/* If item being sorted is lower than the one in already added.
|
||||
* then insert it before the one already added. */
|
||||
if (itemOrder <= collection[i].Order)
|
||||
{
|
||||
collection.Insert(i, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b93eae9ff81b3e4b892128ca4b392ed
|
||||
timeCreated: 1530140103
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Arrays.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Booleans
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a boolean to an integer, 1 for true 0 for false.
|
||||
/// </summary>
|
||||
public static int ToInt(this bool b)
|
||||
{
|
||||
return b ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 602eeac4b016b174f90ae5e85254ac86
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Bools.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Various utility classes relating to floats.
|
||||
/// </summary>
|
||||
public static class Bytes
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to encode and decode strings.
|
||||
/// </summary>
|
||||
private static readonly UTF8Encoding _encoding = new(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
|
||||
|
||||
/// <summary>
|
||||
/// Pads an index a specified value. Preferred over typical padding so that pad values used with skins can be easily found in the code.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string Pad(this byte value, int padding) => Ints.PadInt(value, padding);
|
||||
|
||||
/// <summary>
|
||||
/// Provides a random inclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
|
||||
/// </summary>
|
||||
/// <param name = "minimum">Inclusive minimum value.</param>
|
||||
/// <param name = "maximum">Inclusive maximum value.</param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte RandomInclusiveRange(byte minimum, byte maximum) => (byte)Ints.RandomInclusiveRange(minimum, maximum);
|
||||
|
||||
/// <summary>
|
||||
/// Provides a random exclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
|
||||
/// </summary>
|
||||
/// <param name = "minimum">Inclusive minimum value.</param>
|
||||
/// <param name = "maximum">Exclusive maximum value.</param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte RandomExclusiveRange(byte minimum, byte maximum) => (byte)Ints.RandomExclusiveRange(minimum, maximum);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clamped int within a specified range.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to clamp.</param>
|
||||
/// <param name = "minimum">Minimum value.</param>
|
||||
/// <param name = "maximum">Maximum value.</param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte Clamp(byte value, byte minimum, byte maximum) => (byte)Ints.Clamp(value, minimum, maximum);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whichever value is lower.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte Min(byte a, byte b) => a < b ? a : b;
|
||||
|
||||
/// <summary>
|
||||
/// Determins if all values passed in are the same.
|
||||
/// </summary>
|
||||
/// <param name = "values">Values to check.</param>
|
||||
/// <returns>True if all values are the same.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool ValuesMatch(params byte[] values) => Ints.ValuesMatch((int[])(object)values);
|
||||
|
||||
/// <summary>
|
||||
/// Converts bytes to a string without error checking.
|
||||
/// </summary>
|
||||
public static string ToString(this byte[] bytes, int offset, int count) => _encoding.GetString(bytes, offset, count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26489022ceafbfe4d85bfd5cccf37303
|
||||
timeCreated: 1527268448
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Bytes.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,90 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Ways a CanvasGroup can have it's blocking properties modified.
|
||||
/// </summary>
|
||||
public enum CanvasGroupBlockingType
|
||||
{
|
||||
Unchanged = 0,
|
||||
DoNotBlock = 1,
|
||||
Block = 2
|
||||
}
|
||||
|
||||
public static class CanvaseGroups
|
||||
{
|
||||
public static void SetBlockingType(this CanvasGroup group, CanvasGroupBlockingType blockingType)
|
||||
{
|
||||
if (blockingType == CanvasGroupBlockingType.Unchanged)
|
||||
return;
|
||||
|
||||
bool block = blockingType == CanvasGroupBlockingType.Block;
|
||||
group.blocksRaycasts = block;
|
||||
group.interactable = block;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a CanvasGroup blocking type and alpha.
|
||||
/// </summary>
|
||||
/// <param name = "blockingType">How to handle interactions.</param>
|
||||
/// <param name = "alpha">Alpha for CanvasGroup.</param>
|
||||
public static void SetActive(this CanvasGroup group, CanvasGroupBlockingType blockingType, float alpha)
|
||||
{
|
||||
group.SetBlockingType(blockingType);
|
||||
group.alpha = alpha;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a canvasGroup active with specified alpha.
|
||||
/// </summary>
|
||||
public static void SetActive(this CanvasGroup group, float alpha)
|
||||
{
|
||||
group.SetActive(true, false);
|
||||
group.alpha = alpha;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a canvasGroup inactive with specified alpha.
|
||||
/// </summary>
|
||||
public static void SetInactive(this CanvasGroup group, float alpha)
|
||||
{
|
||||
group.SetActive(false, false);
|
||||
group.alpha = alpha;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a group active state by changing alpha and interaction toggles.
|
||||
/// </summary>
|
||||
public static void SetActive(this CanvasGroup group, bool active, bool setAlpha)
|
||||
{
|
||||
if (group == null)
|
||||
return;
|
||||
|
||||
if (setAlpha)
|
||||
{
|
||||
if (active)
|
||||
group.alpha = 1f;
|
||||
else
|
||||
group.alpha = 0f;
|
||||
}
|
||||
|
||||
group.interactable = active;
|
||||
group.blocksRaycasts = active;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a group active state by changing alpha and interaction toggles with a custom alpha.
|
||||
/// </summary>
|
||||
public static void SetActive(this CanvasGroup group, bool active, float alpha)
|
||||
{
|
||||
if (group == null)
|
||||
return;
|
||||
|
||||
group.alpha = alpha;
|
||||
|
||||
group.interactable = active;
|
||||
group.blocksRaycasts = active;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0e7937b287d3d24d807a115c1a3a464
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/CanvasGroups.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class ColliderExtensions
|
||||
{
|
||||
public static void GetBoxOverlapParams(this BoxCollider boxCollider, out Vector3 center, out Vector3 halfExtents)
|
||||
{
|
||||
Transform cachedTransform = boxCollider.transform;
|
||||
|
||||
// DO NOT USE UNITY'S VECTOR OPERATIONS IN HOT PATHS, UNITY DOESN'T OPTIMISE THEM
|
||||
|
||||
center = cachedTransform.TransformPoint(boxCollider.center);
|
||||
|
||||
Vector3 lossyScale = cachedTransform.lossyScale;
|
||||
|
||||
Vector3 size = boxCollider.size;
|
||||
|
||||
float x = size.x * 0.5f * lossyScale.x;
|
||||
float y = size.y * 0.5f * lossyScale.y;
|
||||
float z = size.z * 0.5f * lossyScale.z;
|
||||
|
||||
halfExtents = new(x, y, z);
|
||||
}
|
||||
|
||||
public static void GetCapsuleCastParams(this CapsuleCollider capsuleCollider, out Vector3 point1, out Vector3 point2, out float radius)
|
||||
{
|
||||
Transform cachedTransform = capsuleCollider.transform;
|
||||
|
||||
Vector3 lossyScale = cachedTransform.lossyScale;
|
||||
|
||||
// Use System.Math instead of UnityEngine.Mathf because it's much faster.
|
||||
|
||||
float absX = Math.Abs(lossyScale.x);
|
||||
float absY = Math.Abs(lossyScale.y);
|
||||
float absZ = Math.Abs(lossyScale.z);
|
||||
|
||||
float height;
|
||||
|
||||
Vector3 direction;
|
||||
|
||||
switch (capsuleCollider.direction)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
radius = capsuleCollider.radius * Math.Max(absX, absZ);
|
||||
|
||||
height = capsuleCollider.height * absY;
|
||||
|
||||
direction = Vector3.up;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
radius = capsuleCollider.radius * Math.Max(absX, absY);
|
||||
|
||||
height = capsuleCollider.height * absZ;
|
||||
|
||||
direction = Vector3.forward;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// Falling back to X is Unity's default behaviour.
|
||||
|
||||
radius = capsuleCollider.radius * Math.Max(absY, absZ);
|
||||
|
||||
height = capsuleCollider.height * absX;
|
||||
|
||||
direction = Vector3.right;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 center = cachedTransform.TransformPoint(capsuleCollider.center);
|
||||
|
||||
Vector3 offset = height < radius * 2.0f ? Vector3.zero : cachedTransform.TransformDirection(direction * (height * 0.5f - radius));
|
||||
|
||||
// DO NOT USE UNITY'S VECTOR OPERATIONS IN HOT PATHS, UNITY DOESN'T OPTIMISE THEM
|
||||
|
||||
float x1 = center.x + offset.x;
|
||||
float y1 = center.y + offset.y;
|
||||
float z1 = center.z + offset.z;
|
||||
|
||||
float x2 = center.x - offset.x;
|
||||
float y2 = center.y - offset.y;
|
||||
float z2 = center.z - offset.z;
|
||||
|
||||
point1 = new(x1, y1, z1);
|
||||
|
||||
point2 = new(x2, y2, z2);
|
||||
}
|
||||
|
||||
public static void GetSphereOverlapParams(this SphereCollider sphereCollider, out Vector3 center, out float radius)
|
||||
{
|
||||
Transform cachedTransform = sphereCollider.transform;
|
||||
|
||||
center = cachedTransform.TransformPoint(sphereCollider.center);
|
||||
|
||||
Vector3 lossyScale = cachedTransform.lossyScale;
|
||||
|
||||
// Use System.Math instead of UnityEngine.Mathf because it's much faster.
|
||||
|
||||
float x = Math.Abs(lossyScale.x);
|
||||
float y = Math.Abs(lossyScale.y);
|
||||
float z = Math.Abs(lossyScale.z);
|
||||
|
||||
// Two calls of Math.Max are faster than a single Mathf.Max call because Math.Max doesn't allocate memory and doesn't use loops.
|
||||
|
||||
radius = sphereCollider.radius * Math.Max(Math.Max(x, y), z);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Collider2DExtensions
|
||||
{
|
||||
public static void GetBox2DOverlapParams(this BoxCollider2D boxCollider, out Vector3 center, out Vector3 halfExtents)
|
||||
{
|
||||
Transform cachedTransform = boxCollider.transform;
|
||||
|
||||
// DO NOT USE UNITY'S VECTOR OPERATIONS IN HOT PATHS, UNITY DOESN'T OPTIMISE THEM
|
||||
|
||||
center = cachedTransform.TransformPoint(boxCollider.offset);
|
||||
|
||||
Vector3 lossyScale = cachedTransform.lossyScale;
|
||||
|
||||
Vector3 size = boxCollider.size;
|
||||
|
||||
float x = size.x * 0.5f * lossyScale.x;
|
||||
float y = size.y * 0.5f * lossyScale.y;
|
||||
float z = size.z * 0.5f * lossyScale.z;
|
||||
|
||||
halfExtents = new(x, y, z);
|
||||
}
|
||||
|
||||
public static void GetCircleOverlapParams(this CircleCollider2D circleCollider, out Vector3 center, out float radius)
|
||||
{
|
||||
Transform cachedTransform = circleCollider.transform;
|
||||
Vector3 offset = new(circleCollider.offset.x, circleCollider.offset.y, circleCollider.transform.position.z);
|
||||
center = cachedTransform.TransformPoint(offset);
|
||||
|
||||
Vector3 lossyScale = cachedTransform.lossyScale;
|
||||
|
||||
// Use System.Math instead of UnityEngine.Mathf because it's much faster.
|
||||
|
||||
float x = Math.Abs(lossyScale.x);
|
||||
float y = Math.Abs(lossyScale.y);
|
||||
float z = Math.Abs(lossyScale.z);
|
||||
|
||||
// Two calls of Math.Max are faster than a single Mathf.Max call because Math.Max doesn't allocate memory and doesn't use loops.
|
||||
|
||||
radius = circleCollider.radius * Math.Max(Math.Max(x, y), z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29e69fa855dd3634d9e66313e7748db4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Colliders.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,79 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class DictionaryFN
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Uses a hacky way to TryGetValue on a dictionary when using IL2CPP and on mobile.
|
||||
/// This is to support older devices that don't properly handle IL2CPP builds.
|
||||
/// </summary>
|
||||
public static bool TryGetValueIL2CPP<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dict, TKey key, out TValue value)
|
||||
{
|
||||
#if ENABLE_IL2CPP && UNITY_IOS || UNITY_ANDROID
|
||||
if (dict.ContainsKey(key))
|
||||
{
|
||||
value = dict[key];
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
#else
|
||||
return dict.TryGetValue(key, out value);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns values as a list.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<TValue> ValuesToList<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dict, bool useCache)
|
||||
{
|
||||
List<TValue> result = useCache ? CollectionCaches<TValue>.RetrieveList() : new(dict.Count);
|
||||
|
||||
//No need to clear the list since it's already clear.
|
||||
dict.ValuesToList(ref result, clearLst: false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds values to a list.
|
||||
/// </summary>
|
||||
public static void ValuesToList<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dict, ref List<TValue> result, bool clearLst)
|
||||
{
|
||||
if (clearLst)
|
||||
result.Clear();
|
||||
|
||||
foreach (TValue item in dict.Values)
|
||||
result.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns keys as a list.
|
||||
/// </summary>
|
||||
public static List<TKey> KeysToList<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dict, bool useCache)
|
||||
{
|
||||
List<TKey> result = useCache ? CollectionCaches<TKey>.RetrieveList() : new(dict.Count);
|
||||
|
||||
//No need to clear the list since it's already clear.
|
||||
dict.KeysToList(ref result, clearLst: false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds keys to a list.
|
||||
/// </summary>
|
||||
public static void KeysToList<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dict, ref List<TKey> result, bool clearLst)
|
||||
{
|
||||
result.Clear();
|
||||
|
||||
foreach (TKey item in dict.Keys)
|
||||
result.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d31d19bc39eb6041bad18d8eb68ed68
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Dictionaries.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Disks
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes specified text to a file path.
|
||||
/// </summary>
|
||||
/// <param name = "text"></param>
|
||||
/// <param name = "path"></param>
|
||||
/// <param name = "formatPath">True to format the path to the current platform.</param>
|
||||
public static void WriteToFile(string text, string path, bool formatPath = true)
|
||||
{
|
||||
// If to format the path for the platform.
|
||||
if (formatPath)
|
||||
path = FormatPlatformPath(path);
|
||||
|
||||
// Path came back or was passed in as an empty string.
|
||||
if (path == string.Empty)
|
||||
{
|
||||
Debug.LogError("Path cannot be null.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Get directory path.
|
||||
string directory = Path.GetDirectoryName(path);
|
||||
// If directory doesn't exist try to create it.
|
||||
if (!Directory.Exists(directory))
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
//Try to write the file data.
|
||||
using (FileStream fs = new(path, FileMode.Create))
|
||||
{
|
||||
using (StreamWriter writer = new(fs))
|
||||
{
|
||||
writer.Write(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"An error occured during a file write. Error: {ex.Message} {Environment.NewLine} File path: {path} {Environment.NewLine} Text: {text}");
|
||||
}
|
||||
|
||||
/* If within the editor then refresh the asset database so changes
|
||||
* reflect in the project folder. */
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.AssetDatabase.Refresh();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a file path to the current platform.
|
||||
/// </summary>
|
||||
/// <param name = "path"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatPlatformPath(string path)
|
||||
{
|
||||
//No path specified.
|
||||
if (path == string.Empty)
|
||||
{
|
||||
Debug.LogError("Path cannot be empty.");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string convertedPath = string.Empty;
|
||||
|
||||
//Get the directories as an array.
|
||||
string[] directories = path.Split(Path.DirectorySeparatorChar);
|
||||
|
||||
//Go through each directory.
|
||||
for (int i = 0; i < directories.Length; i++)
|
||||
{
|
||||
/* If only one entry in array then the path
|
||||
* is in the root of the Resources folder. */
|
||||
if (directories.Length == 1)
|
||||
{
|
||||
//Append to converted path and break from the loop.
|
||||
convertedPath = directories[i];
|
||||
break;
|
||||
}
|
||||
//More than one entry, meaning there are sub paths.
|
||||
else
|
||||
{
|
||||
/* Set converted path to the current
|
||||
* convertedPath combined with the next directory. */
|
||||
convertedPath = Path.Combine(convertedPath, directories[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return convertedPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3a909760282d284591c20c873f20837
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Disks.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,13 @@
|
||||
// #if UNITY_EDITOR
|
||||
// using System;
|
||||
// using UnityEditor;
|
||||
// using UnityEngine;
|
||||
//
|
||||
// namespace GameKit.Dependencies.Utilities
|
||||
// {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// #endif
|
||||
// Remove in V5
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd42f76391fc1254f82767dbf1a4bc8b
|
||||
timeCreated: 1525378031
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Editing.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,327 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public enum EditorLayoutEnableType
|
||||
{
|
||||
Enabled = 0,
|
||||
Disabled = 1,
|
||||
DisabledWhilePlaying = 2
|
||||
}
|
||||
|
||||
public static class EditorGuiLayoutTools
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a helpbox field.
|
||||
/// </summary>
|
||||
public static void AddHelpBox(string text, MessageType messageType = MessageType.Info)
|
||||
{
|
||||
EditorGUILayout.HelpBox(text, messageType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a property field.
|
||||
/// </summary>
|
||||
public static void AddPropertyField(SerializedProperty sp, string fieldName, string tooltip = "")
|
||||
{
|
||||
if (tooltip == "")
|
||||
tooltip = sp.tooltip;
|
||||
|
||||
EditorGUILayout.PropertyField(sp, new GUIContent(fieldName, tooltip));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a property field.
|
||||
/// </summary>
|
||||
public static void AddPropertyField(SerializedProperty sp, GUIContent guiContent)
|
||||
{
|
||||
EditorGUILayout.PropertyField(sp, guiContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a property field.
|
||||
/// </summary>
|
||||
public static void AddPropertyField(SerializedProperty sp, GUIContent guiContent = null, EditorLayoutEnableType enableType = EditorLayoutEnableType.Enabled, params GUILayoutOption[] options)
|
||||
{
|
||||
bool disable = IsDisableLayoutType(enableType);
|
||||
if (disable)
|
||||
GUI.enabled = false;
|
||||
|
||||
EditorGUILayout.PropertyField(sp, guiContent, options);
|
||||
|
||||
if (disable)
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a property field.
|
||||
/// </summary>
|
||||
/// <param name = "enabled">True to have property enabled.</param>
|
||||
[Obsolete("Use AddPropertyField(SerializedProperty, GUIContent, EditorLayoutEnableType, GUILayoutOption.")]
|
||||
public static void AddPropertyField(SerializedProperty sp, GUIContent guiContent = null, bool enabled = true, params GUILayoutOption[] options)
|
||||
{
|
||||
EditorLayoutEnableType enableType = enabled ? EditorLayoutEnableType.Enabled : EditorLayoutEnableType.Disabled;
|
||||
bool disable = IsDisableLayoutType(enableType);
|
||||
if (disable)
|
||||
GUI.enabled = false;
|
||||
|
||||
EditorGUILayout.PropertyField(sp, guiContent, options);
|
||||
|
||||
if (disable)
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an object field.
|
||||
/// </summary>
|
||||
public static void AddObjectField(string label, MonoScript ms, Type type, bool allowSceneObjects, EditorLayoutEnableType enableType = EditorLayoutEnableType.Enabled, params GUILayoutOption[] options)
|
||||
{
|
||||
bool disable = IsDisableLayoutType(enableType);
|
||||
if (disable)
|
||||
GUI.enabled = false;
|
||||
|
||||
EditorGUILayout.ObjectField("Script:", ms, type, allowSceneObjects, options);
|
||||
|
||||
if (disable)
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables GUI if playing.
|
||||
/// </summary>
|
||||
public static void DisableGUIIfPlaying()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
GUI.enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables GUI if playing.
|
||||
/// </summary>
|
||||
public static void EnableGUIIfPlaying()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a layout field should be disabled.
|
||||
/// </summary>
|
||||
/// <param name = "enableType"></param>
|
||||
/// <returns></returns>
|
||||
private static bool IsDisableLayoutType(EditorLayoutEnableType enableType)
|
||||
{
|
||||
return enableType == EditorLayoutEnableType.Disabled || (enableType == EditorLayoutEnableType.DisabledWhilePlaying && Application.isPlaying);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PropertyDrawerToolExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns GetPropertyHeight value based on drawerTool properties.
|
||||
/// </summary>
|
||||
public static float GetPropertyHeight(this PropertyDrawerTool drawerTool)
|
||||
{
|
||||
if (drawerTool == null)
|
||||
return EditorGUIUtility.singleLineHeight;
|
||||
|
||||
return EditorGUIUtility.singleLineHeight * drawerTool.LineSpacingMultiplier * drawerTool.PropertiesDrawn;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Various utility classes relating to floats.
|
||||
/// </summary>
|
||||
public class PropertyDrawerTool
|
||||
{
|
||||
public PropertyDrawerTool()
|
||||
{
|
||||
Debug.LogError($"This initializer is not supported. Use the initializer with arguments.");
|
||||
}
|
||||
|
||||
public PropertyDrawerTool(Rect position, float lineSpacingMultiplier = 1f)
|
||||
{
|
||||
Position = position;
|
||||
LineSpacingMultiplier = lineSpacingMultiplier;
|
||||
Position = position;
|
||||
_startingIndent = EditorGUI.indentLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starting position as indicated by the OnGUI method.
|
||||
/// </summary>
|
||||
/// <remarks>This value may be modified by user code.</remarks>
|
||||
public Rect Position = default;
|
||||
/// <summary>
|
||||
/// Preferred spacing between each draw.
|
||||
/// </summary>
|
||||
public float LineSpacingMultiplier;
|
||||
/// <summary>
|
||||
/// Number of entries drawn by this object.
|
||||
/// </summary>
|
||||
public int PropertiesDrawn = 0;
|
||||
/// <summary>
|
||||
/// Additional position Y of next draw.
|
||||
/// </summary>
|
||||
private float _additionalPositionY = 0;
|
||||
/// <summary>
|
||||
/// Indent level during initialization.
|
||||
/// </summary>
|
||||
private readonly int _startingIndent;
|
||||
|
||||
/// <summary>
|
||||
/// Sets EditorGUI.Indent to the level it were when initializing this class.
|
||||
/// </summary>
|
||||
public void SetIndentToStarting() => EditorGUI.indentLevel = _startingIndent;
|
||||
|
||||
/// <summary>
|
||||
/// Draws a label.
|
||||
/// </summary>
|
||||
public void DrawLabel(GUIContent lLabel) => DrawLabel(lLabel, EditorStyles.label.fontStyle, indent: 0);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a label.
|
||||
/// </summary>
|
||||
public void DrawLabel(GUIContent lLabel, FontStyle styleOverride) => DrawLabel(lLabel, styleOverride, indent: 0);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a label.
|
||||
/// </summary>
|
||||
public void DrawLabel(GUIContent lLabel, FontStyle styleOverride, int indent)
|
||||
{
|
||||
PropertiesDrawn++;
|
||||
|
||||
if (indent != 0)
|
||||
EditorGUI.indentLevel += indent;
|
||||
|
||||
// Set style.
|
||||
FontStyle startingStyle = EditorStyles.label.fontStyle;
|
||||
EditorStyles.label.fontStyle = styleOverride;
|
||||
|
||||
EditorGUI.PrefixLabel(GetRect(), GUIUtility.GetControlID(FocusType.Passive), lLabel);
|
||||
|
||||
EditorStyles.label.fontStyle = startingStyle;
|
||||
|
||||
if (indent != 0)
|
||||
EditorGUI.indentLevel -= indent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a property.
|
||||
/// </summary>
|
||||
public void DrawProperty(SerializedProperty prop) => DrawProperty(prop, lLabel: "", indent: 0);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a property.
|
||||
/// </summary>
|
||||
public void DrawProperty(SerializedProperty prop, string label) => DrawProperty(prop, new GUIContent(label), EditorStyles.label.fontStyle, indent: 0);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a property.
|
||||
/// </summary>
|
||||
public void DrawProperty(SerializedProperty prop, GUIContent content) => DrawProperty(prop, content, EditorStyles.label.fontStyle, indent: 0);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a property.
|
||||
/// </summary>
|
||||
public void DrawProperty(SerializedProperty prop, int indent) => DrawProperty(prop, lLabel: "", indent);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a property.
|
||||
/// </summary>
|
||||
public void DrawProperty(SerializedProperty prop, string lLabel, int indent) => DrawProperty(prop, lLabel, EditorStyles.label.fontStyle, indent);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a property.
|
||||
/// </summary>
|
||||
public void DrawProperty(SerializedProperty prop, GUIContent content, int indent) => DrawProperty(prop, content, EditorStyles.label.fontStyle, indent);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a property.
|
||||
/// </summary>
|
||||
public void DrawProperty(SerializedProperty prop, GUIContent content, FontStyle labelStyle) => DrawProperty(prop, content, labelStyle, indent: 0);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a property.
|
||||
/// </summary>
|
||||
public void DrawProperty(SerializedProperty prop, string lLabel, FontStyle labelStyle, int indent)
|
||||
{
|
||||
GUIContent content = lLabel == "" ? default : new GUIContent(lLabel);
|
||||
|
||||
DrawProperty(prop, content, labelStyle, indent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a property.
|
||||
/// </summary>
|
||||
public void DrawProperty(SerializedProperty prop, GUIContent content, FontStyle labelStyle, int indent)
|
||||
{
|
||||
PropertiesDrawn++;
|
||||
|
||||
EditorGUI.indentLevel += indent;
|
||||
|
||||
FontStyle startingStyle = EditorStyles.label.fontStyle;
|
||||
EditorStyles.label.fontStyle = labelStyle;
|
||||
|
||||
EditorGUI.PropertyField(GetRect(), prop, content);
|
||||
|
||||
EditorStyles.label.fontStyle = startingStyle;
|
||||
|
||||
EditorGUI.indentLevel -= indent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a help box.
|
||||
/// </summary>
|
||||
public void DrawHelpBox(string message, MessageType type = MessageType.Info, int indent = 0)
|
||||
{
|
||||
PropertiesDrawn++;
|
||||
|
||||
if (indent != 0)
|
||||
EditorGUI.indentLevel += indent;
|
||||
|
||||
// Calculate how much height the help box needs based on the current width
|
||||
// We subtract the indent spacing from the width to ensure text wrapping is calculated correctly
|
||||
float indentSpacing = indent * 15f;
|
||||
float height = EditorStyles.helpBox.CalcHeight(new(message), Position.width - indentSpacing);
|
||||
|
||||
// Get the rect and draw
|
||||
EditorGUI.HelpBox(GetRectForHelpBox(height), message, type);
|
||||
|
||||
if (indent != 0)
|
||||
EditorGUI.indentLevel -= indent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specialized Rect getter for elements with variable heights like HelpBoxes.
|
||||
/// </summary>
|
||||
private Rect GetRectForHelpBox(float height)
|
||||
{
|
||||
Rect result = new(Position.x, Position.y + _additionalPositionY, Position.width, height);
|
||||
|
||||
// Advance the Y position by the specific height of the box + standard spacing
|
||||
_additionalPositionY += height + EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next Rect to draw at.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Rect GetRect(float? lineSpacingMultiplierOverride = null)
|
||||
{
|
||||
float multiplier = lineSpacingMultiplierOverride ?? LineSpacingMultiplier;
|
||||
|
||||
Rect result = new(Position.x, Position.y + _additionalPositionY, Position.width, EditorGUIUtility.singleLineHeight * multiplier);
|
||||
|
||||
_additionalPositionY += EditorGUIUtility.singleLineHeight * multiplier;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc822ae23a249704184fa571f551f9c8
|
||||
timeCreated: 1527268448
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/EditorTools.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Enums
|
||||
{
|
||||
public const int SHIFT_EVERYTHING_INT = ~0;
|
||||
public const uint SHIFT_EVERYTHING_UINT = ~0u;
|
||||
|
||||
// 65535
|
||||
/// <summary>
|
||||
/// Determine an enum value from a given string. This can be an expensive function.
|
||||
/// </summary>
|
||||
/// <typeparam name = "T"></typeparam>
|
||||
/// <param name = "text">Text of string.</param>
|
||||
/// <param name = "defaultValue">Default value if enum couldn't be found.</param>
|
||||
/// <returns>Enum found or default value if no enum is found.</returns>
|
||||
public static T FromString<T>(string text, T defaultValue)
|
||||
{
|
||||
// If string is empty or null return default value.
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return defaultValue;
|
||||
// If enum isn't defined return default value.
|
||||
if (!Enum.IsDefined(typeof(T), (string)text))
|
||||
return defaultValue;
|
||||
//Return parsed value.
|
||||
return (T)Enum.Parse(typeof(T), text, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if whole(extended enum) has any of the part values.
|
||||
/// </summary>
|
||||
/// <param name = "whole"></param>
|
||||
/// <param name = "part">Values to check for within whole.</param>
|
||||
/// <returns>Returns true part is within whole.</returns>
|
||||
public static bool ContainsAllocated(this Enum whole, Enum part)
|
||||
{
|
||||
//If not the same type of Enum return false.
|
||||
/* Commented out for performance. Designer
|
||||
* should know better than to compare two different
|
||||
* enums. */
|
||||
//if (!SameType(value, target))
|
||||
// return false;
|
||||
|
||||
/* Convert enum values to ulong. With so few
|
||||
* values a uint would be safe, but should
|
||||
* the options expand ulong is safer. */
|
||||
ulong wholeNum = Convert.ToUInt64(whole);
|
||||
ulong partNum = Convert.ToUInt64(part);
|
||||
|
||||
return (wholeNum & partNum) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if part values contains any of whole(extended enum).
|
||||
/// </summary>
|
||||
/// <param name = "whole"></param>
|
||||
/// <param name = "part"></param>
|
||||
/// <returns>Returns true whole is within part.</returns>
|
||||
public static bool ReverseContains(this Enum whole, Enum part)
|
||||
{
|
||||
//If not the same type of Enum return false.
|
||||
/* Commented out for performance. Designer
|
||||
* should know better than to compare two different
|
||||
* enums. */
|
||||
//if (!SameType(value, target))
|
||||
// return false;
|
||||
|
||||
/* Convert enum values to ulong. With so few
|
||||
* values a uint would be safe, but should
|
||||
* the options expand ulong is safer. */
|
||||
ulong wholeNum = Convert.ToUInt64(whole);
|
||||
ulong partNum = Convert.ToUInt64(part);
|
||||
|
||||
return (partNum & wholeNum) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if an enum equals a specified value.
|
||||
/// </summary>
|
||||
/// <param name = "value"></param>
|
||||
/// <param name = "target"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Equals(this Enum value, Enum target)
|
||||
{
|
||||
//If not the same type of Enum return false.
|
||||
/* Commented out for performance. Designer
|
||||
* should know better than to compare two different
|
||||
* enums. */
|
||||
//if (!SameType(value, target))
|
||||
// return false;
|
||||
|
||||
ulong valueNum = Convert.ToUInt64(value);
|
||||
ulong wholeNum = Convert.ToUInt64(target);
|
||||
|
||||
return valueNum == wholeNum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a is the same Enum as b.
|
||||
/// </summary>
|
||||
/// <param name = "a"></param>
|
||||
/// <param name = "target"></param>
|
||||
/// <returns></returns>
|
||||
public static bool SameType(Enum a, Enum b)
|
||||
{
|
||||
return a.GetType() == b.GetType();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the highest numeric value for T.
|
||||
/// </summary>
|
||||
public static int GetHighestValue<T>()
|
||||
{
|
||||
Type enumType = typeof(T);
|
||||
/* Brute force enum values.
|
||||
* Linq Last/Max lookup throws for IL2CPP. */
|
||||
int highestValue = 0;
|
||||
Array pidValues = Enum.GetValues(enumType);
|
||||
foreach (T pid in pidValues)
|
||||
{
|
||||
object obj = Enum.Parse(enumType, pid.ToString());
|
||||
int value = Convert.ToInt32(obj);
|
||||
highestValue = Math.Max(highestValue, value);
|
||||
}
|
||||
|
||||
return highestValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6c66aec505f9254491b2b126a2d4745
|
||||
timeCreated: 1522959833
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Enums.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Floats
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to randomize float values.
|
||||
/// </summary>
|
||||
private static System.Random _random = new();
|
||||
|
||||
/// <summary>
|
||||
/// Sets a source float to value if equal to or greater than tolerance.
|
||||
/// </summary>
|
||||
/// <param name = "source">Float to check against tolerance.</param>
|
||||
/// <param name = "tolerance">Tolerance float must be equal to or greater than to change to value.</param>
|
||||
/// <param name = "value">Value source is set to when breaking tolerance.</param>
|
||||
public static float SetIfOverTolerance(this float source, float tolerance, float value)
|
||||
{
|
||||
if (source >= tolerance)
|
||||
source = value;
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a source float to value if equal to or less than tolerance.
|
||||
/// </summary>
|
||||
/// <param name = "source">Float to check against tolerance.</param>
|
||||
/// <param name = "tolerance">Tolerance float must be equal to or less than to change to value.</param>
|
||||
/// <param name = "value">Value source is set to when breaking tolerance.</param>
|
||||
public static float SetIfUnderTolerance(this float source, float tolerance, float value)
|
||||
{
|
||||
if (source <= tolerance)
|
||||
source = value;
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns how much time is left on an endTime. Returns -1 if no time is left.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static float TimeRemainingValue(this float endTime)
|
||||
{
|
||||
float remaining = endTime - Time.time;
|
||||
// None remaining.
|
||||
if (remaining < 0f)
|
||||
return -1f;
|
||||
|
||||
return endTime - Time.time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns how much time is left on an endTime. Returns -1 if no time is left.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static int TimeRemainingValue(this float endTime, bool useFloor = true)
|
||||
{
|
||||
float remaining = endTime - Time.time;
|
||||
// None remaining.
|
||||
if (remaining < 0f)
|
||||
return -1;
|
||||
|
||||
float result = endTime - Time.time;
|
||||
return useFloor ? Mathf.FloorToInt(result) : Mathf.CeilToInt(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns time remaining as a string using hh:mm:ss.
|
||||
/// </summary>
|
||||
/// <param name = "value"></param>
|
||||
/// <param name = "segments">Number of places to return. 1 is seconds, 2 is minutes, 3 is hours. If a placement does not exist it is replaced with 00.</param>
|
||||
/// <param name = "emptyOnZero">True to return an empty string when value is 0 or less.</param>
|
||||
/// <returns></returns>
|
||||
public static string TimeRemainingText(this float value, byte segments, bool emptyOnZero = false)
|
||||
{
|
||||
if (emptyOnZero && value <= 0f)
|
||||
return string.Empty;
|
||||
|
||||
int timeRounded = Math.Max(Mathf.RoundToInt(value), 0);
|
||||
TimeSpan t = TimeSpan.FromSeconds(timeRounded);
|
||||
|
||||
int hours = Mathf.FloorToInt(t.Hours);
|
||||
int minutes = Mathf.FloorToInt(t.Minutes);
|
||||
int seconds = Mathf.FloorToInt(t.Seconds);
|
||||
|
||||
string timeText;
|
||||
if (segments == 1)
|
||||
{
|
||||
seconds += minutes * 60;
|
||||
seconds += hours * 3600;
|
||||
timeText = string.Format("{0:D2}", seconds);
|
||||
}
|
||||
else if (segments == 2)
|
||||
{
|
||||
minutes += hours * 60;
|
||||
timeText = string.Format("{0:D2}:{1:D2}", minutes, seconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
timeText = string.Format("{0:D2}:{1:D2}:{2:D2}", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
return timeText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a random inclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
|
||||
/// </summary>
|
||||
/// <param name = "minimum">Inclusive minimum value.</param>
|
||||
/// <param name = "maximum">Inclusive maximum value.</param>
|
||||
/// <returns></returns>
|
||||
public static float RandomInclusiveRange(float minimum, float maximum)
|
||||
{
|
||||
double min = Convert.ToDouble(minimum);
|
||||
double max = Convert.ToDouble(maximum);
|
||||
|
||||
double result = _random.NextDouble() * (max - min) + min;
|
||||
return Convert.ToSingle(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random float between 0f and 1f.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static float Random01()
|
||||
{
|
||||
return RandomInclusiveRange(0f, 1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a target float is within variance of the source float.
|
||||
/// </summary>
|
||||
/// <param name = "a"></param>
|
||||
/// <param name = "b"></param>
|
||||
/// <param name = "tolerance"></param>
|
||||
public static bool Near(this float a, float b, float tolerance = 0.01f)
|
||||
{
|
||||
return Mathf.Abs(a - b) <= tolerance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps a float and returns if the float required clamping.
|
||||
/// </summary>
|
||||
/// <param name = "value"></param>
|
||||
/// <param name = "min"></param>
|
||||
/// <param name = "max"></param>
|
||||
/// <param name = "clamped"></param>
|
||||
/// <returns></returns>
|
||||
public static float Clamp(float value, float min, float max, ref bool clamped)
|
||||
{
|
||||
clamped = value < min;
|
||||
if (clamped)
|
||||
return min;
|
||||
|
||||
clamped = value > min;
|
||||
if (clamped)
|
||||
return max;
|
||||
|
||||
clamped = false;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a float after being adjusted by the specified variance.
|
||||
/// </summary>
|
||||
/// <param name = "source"></param>
|
||||
/// <param name = "variance"></param>
|
||||
/// <returns></returns>
|
||||
public static float Variance(this float source, float variance)
|
||||
{
|
||||
float pickedVariance = RandomInclusiveRange(1f - variance, 1f + variance);
|
||||
return source * pickedVariance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a float value to result after being adjusted by the specified variance.
|
||||
/// </summary>
|
||||
/// <param name = "source"></param>
|
||||
/// <param name = "variance"></param>
|
||||
/// <returns></returns>
|
||||
public static void Variance(this float source, float variance, ref float result)
|
||||
{
|
||||
float pickedVariance = RandomInclusiveRange(1f - variance, 1f + variance);
|
||||
result = source * pickedVariance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns negative-one, zero, or postive-one of a value instead of just negative-one or positive-one.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to sign.</param>
|
||||
/// <returns>Precise sign.</returns>
|
||||
public static float PreciseSign(float value)
|
||||
{
|
||||
if (value == 0f)
|
||||
return 0f;
|
||||
else
|
||||
return Mathf.Sign(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a float is within a range.
|
||||
/// </summary>
|
||||
/// <param name = "source">Value of float.</param>
|
||||
/// <param name = "rangeMin">Minimum of range.</param>
|
||||
/// <param name = "rangeMax">Maximum of range.</param>
|
||||
/// <returns></returns>
|
||||
public static bool InRange(this float source, float rangeMin, float rangeMax)
|
||||
{
|
||||
return source >= rangeMin && source <= rangeMax;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Randomly flips a float value.
|
||||
/// </summary>
|
||||
/// <param name = "value"></param>
|
||||
/// <returns></returns>
|
||||
public static float RandomlyFlip(this float value)
|
||||
{
|
||||
if (Ints.RandomInclusiveRange(0, 1) == 0)
|
||||
return value;
|
||||
else
|
||||
return value *= -1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ab517aa5c3b6e34ca20461339adda04
|
||||
timeCreated: 1526172456
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Floats.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Guids
|
||||
{
|
||||
/// <summary>
|
||||
/// A buffer convert data and discard.
|
||||
/// </summary>
|
||||
public static byte[] Buffer = new byte[16];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51b4d6f1925ec014d8e37fc1d8c89c71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Guids.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class HashSetsFN
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Adds a collection of items.
|
||||
/// </summary>
|
||||
public static void AddRange<T>(this HashSet<T> hashSet, IEnumerable<T> items)
|
||||
{
|
||||
foreach (T item in items)
|
||||
hashSet.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns values as a list.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<T> ToList<T>(this HashSet<T> collection, bool useCache)
|
||||
{
|
||||
List<T> result = useCache ? CollectionCaches<T>.RetrieveList() : new(collection.Count);
|
||||
|
||||
//No need to clear the list since it's already clear.
|
||||
collection.ToList(ref result, clearLst: false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds values to a list.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static void ToList<T>(this HashSet<T> collection, ref List<T> lst, bool clearLst)
|
||||
{
|
||||
if (clearLst)
|
||||
lst.Clear();
|
||||
|
||||
foreach (T item in collection)
|
||||
lst.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 552af765f3c527b4bb6d72c672044024
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/HashSets.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,74 @@
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Hashing
|
||||
{
|
||||
private const uint FNV_offset_basis32 = 2166136261;
|
||||
private const uint FNV_prime32 = 16777619;
|
||||
private const ulong FNV_offset_basis64 = 14695981039346656037;
|
||||
private const ulong FNV_prime64 = 1099511628211;
|
||||
|
||||
/// <summary>
|
||||
/// non cryptographic stable hash code,
|
||||
/// it will always return the same hash for the same
|
||||
/// string.
|
||||
/// This is simply an implementation of FNV-1 32 bit xor folded to 16 bit
|
||||
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||
/// </summary>
|
||||
/// <returns>The stable hash32.</returns>
|
||||
/// <param name = "txt">Text.</param>
|
||||
public static ushort GetStableHashU16(this string txt)
|
||||
{
|
||||
uint hash32 = txt.GetStableHashU32();
|
||||
|
||||
return (ushort)((hash32 >> 16) ^ hash32);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// non cryptographic stable hash code,
|
||||
/// it will always return the same hash for the same
|
||||
/// string.
|
||||
/// This is simply an implementation of FNV-1 32 bit
|
||||
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||
/// </summary>
|
||||
/// <returns>The stable hash32.</returns>
|
||||
/// <param name = "txt">Text.</param>
|
||||
public static uint GetStableHashU32(this string txt)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint hash = FNV_offset_basis32;
|
||||
for (int i = 0; i < txt.Length; i++)
|
||||
{
|
||||
uint ch = txt[i];
|
||||
hash = hash * FNV_prime32;
|
||||
hash = hash ^ ch;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// non cryptographic stable hash code,
|
||||
/// it will always return the same hash for the same
|
||||
/// string.
|
||||
/// This is simply an implementation of FNV-1 64 bit
|
||||
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||
/// </summary>
|
||||
/// <returns>The stable hash32.</returns>
|
||||
/// <param name = "txt">Text.</param>
|
||||
public static ulong GetStableHashU64(this string txt)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
ulong hash = FNV_offset_basis64;
|
||||
for (int i = 0; i < txt.Length; i++)
|
||||
{
|
||||
ulong ch = txt[i];
|
||||
hash = hash * FNV_prime64;
|
||||
hash = hash ^ ch;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7be723c9549bdd041ac1dc8e8c6d2d18
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Hashing.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class IOs
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds all prefab files in a path.
|
||||
/// </summary>
|
||||
/// <param name = "startingPath">Path to begin searching in; this is typically "Assets".</param>
|
||||
/// <param name = "excludedPaths">Paths to exclude when searching.</param>
|
||||
/// <param name = "recursive">True to search subpaths.</param>
|
||||
/// <returns></returns>
|
||||
public static string[] GetDirectoryFiles(string startingPath, HashSet<string> excludedPaths, bool recursive, string extension)
|
||||
{
|
||||
// Opportunity to exit early if there are no excluded paths.
|
||||
if (excludedPaths.Count == 0)
|
||||
{
|
||||
string[] strResults = Directory.GetFiles(startingPath, extension, SearchOption.AllDirectories);
|
||||
return strResults;
|
||||
}
|
||||
// starting path is excluded.
|
||||
if (excludedPaths.Contains(startingPath))
|
||||
return new string[0];
|
||||
|
||||
// Folders remaining to be iterated.
|
||||
List<string> enumeratedCollection = new() { startingPath };
|
||||
// Only check other directories if recursive.
|
||||
if (recursive)
|
||||
{
|
||||
// Find all folders which aren't excluded.
|
||||
for (int i = 0; i < enumeratedCollection.Count; i++)
|
||||
{
|
||||
string[] allFolders = Directory.GetDirectories(enumeratedCollection[i], "*", SearchOption.TopDirectoryOnly);
|
||||
for (int z = 0; z < allFolders.Length; z++)
|
||||
{
|
||||
string current = allFolders[z];
|
||||
// Not excluded.
|
||||
if (!excludedPaths.Contains(current))
|
||||
enumeratedCollection.Add(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Valid prefab files.
|
||||
List<string> results = new();
|
||||
// Build files from folders.
|
||||
int count = enumeratedCollection.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
string[] r = Directory.GetFiles(enumeratedCollection[i], extension, SearchOption.TopDirectoryOnly);
|
||||
results.AddRange(r);
|
||||
}
|
||||
|
||||
return results.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1994e262a1e963479497289602e4461
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/IOs.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,89 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Various utility classes relating to floats.
|
||||
/// </summary>
|
||||
public static class Ints
|
||||
{
|
||||
private static System.Random _random = new();
|
||||
|
||||
/// <summary>
|
||||
/// Pads an index a specified value. Preferred over typical padding so that pad values used with skins can be easily found in the code.
|
||||
/// </summary>
|
||||
/// <param name = "value"></param>
|
||||
/// <param name = "padding"></param>
|
||||
/// <returns></returns>
|
||||
public static string PadInt(int value, int padding)
|
||||
{
|
||||
return value.ToString().PadLeft(padding, '0');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a random inclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
|
||||
/// </summary>
|
||||
/// <param name = "minimum">Inclusive minimum value.</param>
|
||||
/// <param name = "maximum">Inclusive maximum value.</param>
|
||||
/// <returns></returns>
|
||||
public static int RandomInclusiveRange(int minimum, int maximum)
|
||||
{
|
||||
return _random.Next(minimum, maximum + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a random exclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
|
||||
/// </summary>
|
||||
/// <param name = "minimum">Inclusive minimum value.</param>
|
||||
/// <param name = "maximum">Exclusive maximum value.</param>
|
||||
/// <returns></returns>
|
||||
public static int RandomExclusiveRange(int minimum, int maximum)
|
||||
{
|
||||
return _random.Next(minimum, maximum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clamped int within a specified range.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to clamp.</param>
|
||||
/// <param name = "minimum">Minimum value.</param>
|
||||
/// <param name = "maximum">Maximum value.</param>
|
||||
/// <returns></returns>
|
||||
public static int Clamp(int value, int minimum, int maximum)
|
||||
{
|
||||
if (value < minimum)
|
||||
value = minimum;
|
||||
else if (value > maximum)
|
||||
value = maximum;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determins if all values passed in are the same.
|
||||
/// </summary>
|
||||
/// <param name = "values">Values to check.</param>
|
||||
/// <returns>True if all values are the same.</returns>
|
||||
public static bool ValuesMatch(params int[] values)
|
||||
{
|
||||
if (values.Length == 0)
|
||||
{
|
||||
Debug.Log("Ints -> ValuesMatch -> values array is empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assign first value as element in first array.
|
||||
int firstValue = values[0];
|
||||
// Check all values.
|
||||
for (int i = 1; i < values.Length; i++)
|
||||
{
|
||||
// If any value doesn't match first value return false.
|
||||
if (firstValue != values[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this far all values match.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c673118198f5c4b41986d52762828363
|
||||
timeCreated: 1527268448
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Ints.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,104 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Layers
|
||||
{
|
||||
/* GetInteractableLayer methods is an implementation from this
|
||||
* link: https://forum.unity.com/threads/is-there-a-way-to-get-the-layer-collision-matrix.260744/#post-3483886 */
|
||||
/// <summary>
|
||||
/// Lookup of interactable layers for each layer.
|
||||
/// </summary>
|
||||
private static Dictionary<int, int> _interactablesLayers;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to initializes InteractableLayers.
|
||||
/// </summary>
|
||||
private static void TryInitializeInteractableLayers()
|
||||
{
|
||||
if (_interactablesLayers != null)
|
||||
return;
|
||||
|
||||
_interactablesLayers = new();
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
int mask = 0;
|
||||
for (int j = 0; j < 32; j++)
|
||||
{
|
||||
if (!Physics.GetIgnoreLayerCollision(i, j))
|
||||
{
|
||||
mask |= 1 << j;
|
||||
}
|
||||
}
|
||||
// Setting without add check is quicker.
|
||||
_interactablesLayers[i] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns interactable layers value for layer.
|
||||
/// </summary>
|
||||
public static int GetInteractableLayersValue(int layer)
|
||||
{
|
||||
TryInitializeInteractableLayers();
|
||||
return _interactablesLayers[layer];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns interactable layers LayerMask for a GameObject.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static LayerMask GetInteractableLayersMask(int layer) => (LayerMask)GetInteractableLayersValue(layer);
|
||||
|
||||
/// <summary>
|
||||
/// Returns interactable layers value for a GameObject.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int GetInteractableLayersValue(GameObject go) => GetInteractableLayersValue(go.layer);
|
||||
|
||||
/// <summary>
|
||||
/// Returns interactable layers LayerMask for a GameObject.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static LayerMask GetInteractableLayersMask(GameObject go) => (LayerMask)GetInteractableLayersValue(go.layer);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a layer mask to a layer number.
|
||||
/// </summary>
|
||||
/// <param name = "mask"></param>
|
||||
/// <returns></returns>
|
||||
public static int LayerMaskToLayerNumber(LayerMask mask)
|
||||
{
|
||||
return LayerValueToLayerNumber(mask.value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a layer value int to a layer int.
|
||||
/// </summary>
|
||||
/// <param name = "bitmask"></param>
|
||||
/// <returns></returns>
|
||||
public static int LayerValueToLayerNumber(int bitmask)
|
||||
{
|
||||
int result = bitmask > 0 ? 0 : 31;
|
||||
while (bitmask > 1)
|
||||
{
|
||||
bitmask = bitmask >> 1;
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a LayerMask contains a specified layer.
|
||||
/// </summary>
|
||||
/// <param name = "layerMask">LayerMask to check for layer in.</param>
|
||||
/// <param name = "layer">Layer to check within LayerMask.</param>
|
||||
/// <returns></returns>
|
||||
public static bool ContainsLayer(LayerMask layerMask, int layer)
|
||||
{
|
||||
return layerMask == (layerMask | (1 << layer));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c18e15e44d21a94d8919f4b6b125a1f
|
||||
timeCreated: 1522349045
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Layers.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class LayoutGroups
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns how many entries can fit into a GridLayoutGroup
|
||||
/// </summary>
|
||||
public static int EntriesPerWidth(this GridLayoutGroup lg)
|
||||
{
|
||||
RectTransform rectTransform = lg.GetComponent<RectTransform>();
|
||||
return Mathf.CeilToInt(rectTransform.rect.width / lg.cellSize.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e330113395c59ca4dba5de001e010f08
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/LayoutGroups.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class ListsFN
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Adds items to collection while preventing duplicates, returning number of items added.
|
||||
/// </summary>
|
||||
public static int AddRangeUnique<T>(this List<T> collection, IEnumerable<T> items)
|
||||
{
|
||||
int added = 0;
|
||||
|
||||
foreach (T item in items)
|
||||
{
|
||||
if (!collection.Contains(item))
|
||||
{
|
||||
collection.Add(item);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds item to collection while preventing duplicates, returning if added.
|
||||
/// </summary>
|
||||
public static bool AddUnique<T>(this List<T> collection, T item)
|
||||
{
|
||||
if (!collection.Contains(item))
|
||||
{
|
||||
collection.Add(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5ae7a9f43f78a345839f65ff75ba384
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Lists.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Materials
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the color or tint color property for a material.
|
||||
/// </summary>
|
||||
/// <param name = "material"></param>
|
||||
/// <returns></returns>
|
||||
public static Color GetColor(this Material material)
|
||||
{
|
||||
if (material.HasProperty("_Color"))
|
||||
return material.color;
|
||||
else if (material.HasProperty("_TintColor"))
|
||||
return material.GetColor("_TintColor");
|
||||
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color or tint color property for a material.
|
||||
/// </summary>
|
||||
/// <param name = "material"></param>
|
||||
public static void SetColor(this Material material, Color color)
|
||||
{
|
||||
if (material.HasProperty("_Color"))
|
||||
material.color = color;
|
||||
else if (material.HasProperty("_TintColor"))
|
||||
material.SetColor("_TintColor", color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27a618c551d5fdb4ca70bf07e1905580
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Materials.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,44 @@
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Maths
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a clamped SBytte.
|
||||
/// </summary>
|
||||
public static sbyte ClampSByte(long value, sbyte min, sbyte max)
|
||||
{
|
||||
if (value < min)
|
||||
return min;
|
||||
else if (value > max)
|
||||
return max;
|
||||
else
|
||||
return (sbyte)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clamped double.
|
||||
/// </summary>
|
||||
public static double ClampDouble(double value, double min, double max)
|
||||
{
|
||||
if (value < min)
|
||||
return min;
|
||||
else if (value > max)
|
||||
return max;
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clamped byte.
|
||||
/// </summary>
|
||||
public static byte ClampByte(byte value, byte min, byte max)
|
||||
{
|
||||
if (value < min)
|
||||
return min;
|
||||
else if (value > max)
|
||||
return max;
|
||||
else
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18a583dc22a9a0f4cabec0c4a0219c6e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Maths.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,200 @@
|
||||
#if NEW_INPUTSYSTEM
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class NewInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Current Keyboard.
|
||||
/// </summary>
|
||||
public static Keyboard Keyboard => Keyboard.current;
|
||||
/// <summary>
|
||||
/// Current Mouse.
|
||||
/// </summary>
|
||||
public static Mouse Mouse => Mouse.current;
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a button is held on any map.
|
||||
/// </summary>
|
||||
public static bool GetButtonHeld(Key key)
|
||||
{
|
||||
return (Keyboard != null) ? Keyboard[key].isPressed : false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a button is pressed on any map.
|
||||
/// </summary>
|
||||
public static bool GetButtonPressed(Key key)
|
||||
{
|
||||
return (Keyboard != null) ? Keyboard[key].wasPressedThisFrame : false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a button is released on any map.
|
||||
/// </summary>
|
||||
public static bool GetButtonReleased(Key key)
|
||||
{
|
||||
return (Keyboard != null) ? Keyboard[key].wasReleasedThisFrame : false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MouseExtensions
|
||||
{
|
||||
public static Vector3 GetPosition(this Mouse m)
|
||||
{
|
||||
return m.position.ReadValue();
|
||||
}
|
||||
}
|
||||
|
||||
public static class KeyboardExtensions
|
||||
{
|
||||
public static bool GetKeyPressed(this Keyboard kb, Key kc)
|
||||
{
|
||||
return kb[kc].wasPressedThisFrame;
|
||||
}
|
||||
|
||||
public static bool GetKeyHeld(this Keyboard kb, Key kc)
|
||||
{
|
||||
return kb[kc].isPressed;
|
||||
}
|
||||
|
||||
public static bool GetKeyReleased(this Keyboard kb, Key kc)
|
||||
{
|
||||
return kb[kc].wasReleasedThisFrame;
|
||||
}
|
||||
}
|
||||
|
||||
public static class InputActionMapExtensions
|
||||
{
|
||||
#region Strings.
|
||||
public static float GetAxisRaw(this InputActionMap map, string negativeName, string positiveName)
|
||||
{
|
||||
return map.GetAxisRaw(negativeName, positiveName, out _);
|
||||
}
|
||||
|
||||
public static float GetAxisRaw(this InputActionMap map, string negativeName, string positiveName, out bool found)
|
||||
{
|
||||
found = false;
|
||||
InputAction negativeIa = map.FindAction(negativeName);
|
||||
InputAction positiveIa = map.FindAction(positiveName);
|
||||
if (negativeIa == null || positiveIa == null)
|
||||
return 0f;
|
||||
|
||||
found = true;
|
||||
bool negativePressed = negativeIa.IsPressed();
|
||||
bool positivePressed = positiveIa.IsPressed();
|
||||
/* If both are pressed then they cancel each other out.
|
||||
* And if neither are pressed then result is naturally
|
||||
* 0f. */
|
||||
if (negativePressed == positivePressed)
|
||||
return 0f;
|
||||
else if (negativePressed)
|
||||
return -1f;
|
||||
else
|
||||
return 1f;
|
||||
}
|
||||
|
||||
public static float GetAxisRaw(this InputActionMap map, string inputName)
|
||||
{
|
||||
return map.GetAxisRaw(inputName, out _);
|
||||
}
|
||||
|
||||
public static float GetAxisRaw(this InputActionMap map, string inputName, out bool found)
|
||||
{
|
||||
found = false;
|
||||
InputAction ia = map.FindAction(inputName);
|
||||
if (ia == null)
|
||||
return 0f;
|
||||
|
||||
found = true;
|
||||
float axis = ia.ReadValue<float>();
|
||||
if (axis == 0f)
|
||||
return 0f;
|
||||
else
|
||||
return Mathf.Sign(axis);
|
||||
}
|
||||
|
||||
public static bool GetButtonHeld(this InputActionMap map, string inputName)
|
||||
{
|
||||
InputAction ia = map.FindAction(inputName);
|
||||
return (ia == null) ? false : ia.IsPressed();
|
||||
}
|
||||
|
||||
public static bool GetButtonPressed(this InputActionMap map, string inputName)
|
||||
{
|
||||
InputAction ia = map.FindAction(inputName);
|
||||
return (ia == null) ? false : ia.WasPressedThisFrame();
|
||||
}
|
||||
|
||||
public static bool GetButtonReleased(this InputActionMap map, string inputName)
|
||||
{
|
||||
InputAction ia = map.FindAction(inputName);
|
||||
return (ia == null) ? false : ia.WasReleasedThisFrame();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region InputActions.
|
||||
public static float GetAxisRaw(InputAction negativeIa, InputAction positiveIa)
|
||||
{
|
||||
return GetAxisRaw(negativeIa, positiveIa, out _);
|
||||
}
|
||||
|
||||
public static float GetAxisRaw(InputAction negativeIa, InputAction positiveIa, out bool found)
|
||||
{
|
||||
found = false;
|
||||
if (negativeIa == null || positiveIa == null)
|
||||
return 0f;
|
||||
|
||||
found = true;
|
||||
bool negativePressed = negativeIa.IsPressed();
|
||||
bool positivePressed = positiveIa.IsPressed();
|
||||
/* If both are pressed then they cancel each other out.
|
||||
* And if neither are pressed then result is naturally
|
||||
* 0f. */
|
||||
if (negativePressed == positivePressed)
|
||||
return 0f;
|
||||
else if (negativePressed)
|
||||
return -1f;
|
||||
else
|
||||
return 1f;
|
||||
}
|
||||
|
||||
public static float GetAxisRaw(this InputAction ia)
|
||||
{
|
||||
return GetAxisRaw(ia, out _);
|
||||
}
|
||||
|
||||
public static float GetAxisRaw(this InputAction ia, out bool found)
|
||||
{
|
||||
found = false;
|
||||
if (ia == null)
|
||||
return 0f;
|
||||
|
||||
found = true;
|
||||
float axis = ia.ReadValue<float>();
|
||||
if (axis == 0f)
|
||||
return 0f;
|
||||
else
|
||||
return Mathf.Sign(axis);
|
||||
}
|
||||
|
||||
public static bool GetButtonHeld(this InputAction ia)
|
||||
{
|
||||
return (ia == null) ? false : ia.IsPressed();
|
||||
}
|
||||
|
||||
public static bool GetButtonPressed(this InputAction ia)
|
||||
{
|
||||
return (ia == null) ? false : ia.WasPressedThisFrame();
|
||||
}
|
||||
|
||||
public static bool GetButtonReleased(this InputAction ia)
|
||||
{
|
||||
return (ia == null) ? false : ia.WasReleasedThisFrame();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea6d91237dc169249b4a375e7e9eef00
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/NewInput.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,892 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using GameKit.Dependencies.Utilities.Types;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// ReSharper disable ThreadStaticFieldHasInitializesr
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Implement to use type with Caches.
|
||||
/// </summary>
|
||||
public interface IResettable
|
||||
{
|
||||
/// <summary>
|
||||
/// Resets values when being placed in a cache.
|
||||
/// </summary>
|
||||
void ResetState();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes values after being retrieved from a cache.
|
||||
/// </summary>
|
||||
void InitializeState();
|
||||
}
|
||||
|
||||
#region Resettable caches.
|
||||
/// <summary>
|
||||
/// Caches collections of multiple generics.
|
||||
/// </summary>
|
||||
public static class ResettableCollectionCaches<T1, T2> where T1 : IResettable, new() where T2 : IResettable, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<T1, T2> RetrieveDictionary() => CollectionCaches<T1, T2>.RetrieveDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Dictionary<T1, T2> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(Dictionary<T1, T2> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
foreach (KeyValuePair<T1, T2> kvp in value)
|
||||
{
|
||||
ResettableObjectCaches<T1>.Store(kvp.Key);
|
||||
ResettableObjectCaches<T2>.Store(kvp.Value);
|
||||
}
|
||||
|
||||
value.Clear();
|
||||
|
||||
CollectionCaches<T1, T2>.Store(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches collections of multiple generics.
|
||||
/// </summary>
|
||||
public static class ResettableT1CollectionCaches<T1, T2> where T1 : IResettable, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<T1, T2> RetrieveDictionary() => CollectionCaches<T1, T2>.RetrieveDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Dictionary<T1, T2> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(Dictionary<T1, T2> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
foreach (T1 item in value.Keys)
|
||||
ResettableObjectCaches<T1>.Store(item);
|
||||
|
||||
value.Clear();
|
||||
CollectionCaches<T1, T2>.Store(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches collections of multiple generics.
|
||||
/// </summary>
|
||||
public static class ResettableT2CollectionCaches<T1, T2> where T2 : IResettable, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<T1, T2> RetrieveDictionary() => CollectionCaches<T1, T2>.RetrieveDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Dictionary<T1, T2> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(Dictionary<T1, T2> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
foreach (T2 item in value.Values)
|
||||
ResettableObjectCaches<T2>.Store(item);
|
||||
|
||||
value.Clear();
|
||||
CollectionCaches<T1, T2>.Store(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches collections of a single generic.
|
||||
/// </summary>
|
||||
public static class ResettableCollectionCaches<T> where T : IResettable, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache for ResettableRingBuffer.
|
||||
/// </summary>
|
||||
private static readonly ConcurrentStack<ResettableRingBuffer<T>> _resettableRingBufferCache = new();
|
||||
/// <summary>
|
||||
/// Maximum number of entries allowed for the cache.
|
||||
/// </summary>
|
||||
private const int MAXIMUM_CACHE_COUNT = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
public static ResettableRingBuffer<T> RetrieveRingBuffer()
|
||||
{
|
||||
ResettableRingBuffer<T> result;
|
||||
if (!_resettableRingBufferCache.TryPop(out result))
|
||||
result = new();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static T[] RetrieveArray() => CollectionCaches<T>.RetrieveArray();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<T> RetrieveList() => CollectionCaches<T>.RetrieveList();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static SortedSet<T> RetrieveSortedSet() => CollectionCaches<T>.RetrieveSortedSet();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static HashSet<T> RetrieveHashSet() => CollectionCaches<T>.RetrieveHashSet();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Queue<T> RetrieveQueue() => CollectionCaches<T>.RetrieveQueue();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static BasicQueue<T> RetrieveBasicQueue() => CollectionCaches<T>.RetrieveBasicQueue();
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
/// <param name = "count">Number of entries in the array from the beginning.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref ResettableRingBuffer<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
/// <param name = "count">Number of entries in the array from the beginning.</param>
|
||||
public static void Store(ResettableRingBuffer<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
value.ResetState();
|
||||
|
||||
if (_resettableRingBufferCache.Count < MAXIMUM_CACHE_COUNT)
|
||||
_resettableRingBufferCache.Push(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
/// <param name = "count">Number of entries in the array from the beginning.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref T[] value, int count)
|
||||
{
|
||||
Store(value, count);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
/// <param name = "count">Number of entries in the array from the beginning.</param>
|
||||
public static void Store(T[] value, int count)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
ResettableObjectCaches<T>.Store(value[i]);
|
||||
|
||||
CollectionCaches<T>.Store(value, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref List<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(List<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < value.Count; i++)
|
||||
ResettableObjectCaches<T>.Store(value[i]);
|
||||
|
||||
value.Clear();
|
||||
CollectionCaches<T>.Store(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref SortedSet<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(SortedSet<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
foreach (T item in value)
|
||||
ResettableObjectCaches<T>.Store(item);
|
||||
|
||||
value.Clear();
|
||||
CollectionCaches<T>.Store(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref HashSet<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(HashSet<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
foreach (T item in value)
|
||||
ResettableObjectCaches<T>.Store(item);
|
||||
|
||||
value.Clear();
|
||||
CollectionCaches<T>.Store(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Queue<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(Queue<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
foreach (T item in value)
|
||||
ResettableObjectCaches<T>.Store(item);
|
||||
|
||||
value.Clear();
|
||||
CollectionCaches<T>.Store(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref BasicQueue<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(BasicQueue<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
while (value.TryDequeue(out T result))
|
||||
ResettableObjectCaches<T>.Store(result);
|
||||
|
||||
value.Clear();
|
||||
CollectionCaches<T>.Store(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches objects of a single generic.
|
||||
/// </summary>
|
||||
public static class ResettableObjectCaches<T> where T : IResettable, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves an instance of T.
|
||||
/// </summary>
|
||||
public static T Retrieve()
|
||||
{
|
||||
T result = ObjectCaches<T>.Retrieve();
|
||||
result.InitializeState();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores an instance of T and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref T value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores an instance of T.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(T value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
value.ResetState();
|
||||
ObjectCaches<T>.Store(value);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region NonResettable caches.
|
||||
/// <summary>
|
||||
/// Caches collections of multiple generics.
|
||||
/// </summary>
|
||||
public static class CollectionCaches<T1, T2>
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache for dictionaries.
|
||||
/// </summary>
|
||||
private static readonly ConcurrentStack<Dictionary<T1, T2>> _dictionaryCache = new();
|
||||
/// <summary>
|
||||
/// Maximum number of entries allowed for the cache.
|
||||
/// </summary>
|
||||
private const int MAXIMUM_CACHE_COUNT = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<T1, T2> RetrieveDictionary()
|
||||
{
|
||||
Dictionary<T1, T2> result;
|
||||
if (!_dictionaryCache.TryPop(out result))
|
||||
result = new();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Dictionary<T1, T2> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(Dictionary<T1, T2> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
value.Clear();
|
||||
if (_dictionaryCache.Count < MAXIMUM_CACHE_COUNT)
|
||||
_dictionaryCache.Push(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches collections of a single generic.
|
||||
/// </summary>
|
||||
public static partial class CollectionCaches<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache for arrays.
|
||||
/// </summary>
|
||||
private static readonly ConcurrentStack<T[]> _arrayCache;
|
||||
/// <summary>
|
||||
/// Cache for lists.
|
||||
/// </summary>
|
||||
private static readonly ConcurrentStack<List<T>> _listCache;
|
||||
/// <summary>
|
||||
/// Cache for sortedset.
|
||||
/// </summary>
|
||||
private static readonly ConcurrentStack<SortedSet<T>> _sortedSetCache;
|
||||
/// <summary>
|
||||
/// Cache for queues.
|
||||
/// </summary>
|
||||
private static readonly ConcurrentStack<Queue<T>> _queueCache;
|
||||
/// <summary>
|
||||
/// Cache for queues.
|
||||
/// </summary>
|
||||
private static readonly ConcurrentStack<BasicQueue<T>> _basicQueueCache;
|
||||
/// <summary>
|
||||
/// Cache for hashset.
|
||||
/// </summary>
|
||||
private static readonly ConcurrentStack<HashSet<T>> _hashSetCache;
|
||||
/// <summary>
|
||||
/// Maximum number of entries allowed for the cache.
|
||||
/// </summary>
|
||||
private const int MAXIMUM_CACHE_COUNT = 50;
|
||||
|
||||
static CollectionCaches()
|
||||
{
|
||||
_arrayCache = new();
|
||||
_listCache = new();
|
||||
_sortedSetCache = new();
|
||||
_queueCache = new();
|
||||
_basicQueueCache = new();
|
||||
_hashSetCache = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static T[] RetrieveArray()
|
||||
{
|
||||
T[] result;
|
||||
if (!_arrayCache.TryPop(out result))
|
||||
result = new T[0];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<T> RetrieveList()
|
||||
{
|
||||
List<T> result;
|
||||
if (!_listCache.TryPop(out result))
|
||||
result = new();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static SortedSet<T> RetrieveSortedSet()
|
||||
{
|
||||
SortedSet<T> result;
|
||||
if (!_sortedSetCache.TryPop(out result))
|
||||
result = new();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Queue<T> RetrieveQueue()
|
||||
{
|
||||
Queue<T> result;
|
||||
if (!_queueCache.TryPop(out result))
|
||||
result = new();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static BasicQueue<T> RetrieveBasicQueue()
|
||||
{
|
||||
BasicQueue<T> result;
|
||||
if (!_basicQueueCache.TryPop(out result))
|
||||
result = new();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection adding one entry.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Queue<T> RetrieveQueue(T entry)
|
||||
{
|
||||
Queue<T> result;
|
||||
if (!_queueCache.TryPop(out result))
|
||||
result = new();
|
||||
|
||||
result.Enqueue(entry);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection adding one entry.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<T> RetrieveList(T entry)
|
||||
{
|
||||
List<T> result;
|
||||
if (!_listCache.TryPop(out result))
|
||||
result = new();
|
||||
|
||||
result.Add(entry);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a HashSet<T>.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static HashSet<T> RetrieveHashSet()
|
||||
{
|
||||
HashSet<T> result;
|
||||
if (!_hashSetCache.TryPop(out result))
|
||||
result = new();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection adding one entry.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static HashSet<T> RetrieveHashSet(T entry)
|
||||
{
|
||||
HashSet<T> result;
|
||||
if (!_hashSetCache.TryPop(out result))
|
||||
return new();
|
||||
|
||||
result.Add(entry);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
/// <param name = "count">Number of entries in the array set default, from the beginning.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref T[] value, int count)
|
||||
{
|
||||
Store(value, count);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
/// <param name = "count">Number of entries in the array from the beginning.</param>
|
||||
public static void Store(T[] value, int count)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
value[i] = default;
|
||||
|
||||
if (_arrayCache.Count < MAXIMUM_CACHE_COUNT)
|
||||
_arrayCache.Push(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref List<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(List<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
value.Clear();
|
||||
|
||||
if (_listCache.Count < MAXIMUM_CACHE_COUNT)
|
||||
_listCache.Push(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref SortedSet<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(SortedSet<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
value.Clear();
|
||||
|
||||
if (_sortedSetCache.Count < MAXIMUM_CACHE_COUNT)
|
||||
_sortedSetCache.Push(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Queue<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(Queue<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
value.Clear();
|
||||
|
||||
if (_queueCache.Count < MAXIMUM_CACHE_COUNT)
|
||||
_queueCache.Push(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref BasicQueue<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(BasicQueue<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
value.Clear();
|
||||
|
||||
if (_basicQueueCache.Count < MAXIMUM_CACHE_COUNT)
|
||||
_basicQueueCache.Push(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref HashSet<T> value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
public static void Store(HashSet<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
value.Clear();
|
||||
|
||||
if (_hashSetCache.Count < MAXIMUM_CACHE_COUNT)
|
||||
_hashSetCache.Push(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches objects of a single generic.
|
||||
/// </summary>
|
||||
public static class ObjectCaches<T> where T : new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Stack to use.
|
||||
/// </summary>
|
||||
private static readonly ConcurrentStack<T> _stack = new();
|
||||
/// <summary>
|
||||
/// Maximum number of entries allowed for the cache.
|
||||
/// </summary>
|
||||
private const int MAXIMUM_CACHE_COUNT = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value from the stack or creates an instance when the stack is empty.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static T Retrieve()
|
||||
{
|
||||
T result;
|
||||
if (!_stack.TryPop(out result))
|
||||
result = new(); // Activator.CreateInstance<T>();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores an instance of T and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref T value)
|
||||
{
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a value to the stack.
|
||||
/// </summary>
|
||||
/// <param name = "value"></param>
|
||||
public static void Store(T value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
if (_stack.Count < MAXIMUM_CACHE_COUNT)
|
||||
_stack.Push(value);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3cb13274f7491a941b6e89a767905f56
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectCaching.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,341 @@
|
||||
// /* This implementation uses better naming as well provides
|
||||
// * a few new features.
|
||||
// *
|
||||
// * Object and Collection caches are now one class. */
|
||||
//
|
||||
// // TODO In V5 disappear ResettableRingBuffer and have regular check implementation on start -- this will let us use this class for caching ringbuffer with resettable types.
|
||||
// using System;
|
||||
// using System.Collections;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Runtime.CompilerServices;
|
||||
//
|
||||
// namespace GameKit.Dependencies.Utilities
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// Implement to use type with Caches.
|
||||
// /// </summary>
|
||||
// public interface IResettable
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// Resets values when being placed in a cache.
|
||||
// /// </summary>
|
||||
// void ResetState();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Initializes values after being retrieved from a cache.
|
||||
// /// </summary>
|
||||
// void InitializeState();
|
||||
// }
|
||||
//
|
||||
// public static class ResettableObjectPool<T> where T : IResettable, new() { }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Caches collections and objects of T.
|
||||
// /// </summary>
|
||||
// public static class ObjectPool<T> where T : new()
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// Cache for List<T>.
|
||||
// /// </summary>
|
||||
// private static readonly Stack<List<T>> _listCache = new();
|
||||
// /// <summary>
|
||||
// /// Resettable cache for List<T>.
|
||||
// /// </summary>
|
||||
// private static readonly Stack<List<T>> _resettableListCache = new();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Cache for HashSet<T>.
|
||||
// /// </summary>
|
||||
// private static readonly Stack<HashSet<T>> _hashSetCache = new();
|
||||
// /// <summary>
|
||||
// /// Resettable cache for HashSet<T>.
|
||||
// /// </summary>
|
||||
// private static readonly Stack<HashSet<T>> _resettableHashSetCache = new();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Cache for Queue<T>.
|
||||
// /// </summary>
|
||||
// private static readonly Stack<Queue<T>> _queueCache = new();
|
||||
// /// <summary>
|
||||
// /// Resettable cache for Queue<T>.
|
||||
// /// </summary>
|
||||
// private static readonly Stack<Queue<T>> _resettableQueueCache = new();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Cache for T[].
|
||||
// /// </summary>
|
||||
// private static readonly Stack<T[]> _arrayCache = new();
|
||||
// /// <summary>
|
||||
// /// Resettable cache for T[].
|
||||
// /// </summary>
|
||||
// private static readonly Stack<T[]> _resettableArrayCache = new();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Cache for T.
|
||||
// /// </summary>
|
||||
// private static readonly Stack<T> _tCache = new();
|
||||
// /// <summary>
|
||||
// /// Resettable cache for T.
|
||||
// /// </summary>
|
||||
// private static readonly Stack<T> _resettableTCache = new();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// True if T is a value type.
|
||||
// /// </summary>
|
||||
// private static readonly bool _isValueType;
|
||||
// /// <summary>
|
||||
// /// True if T implements IResettable.
|
||||
// /// </summary>
|
||||
// private static readonly bool _isResettable;
|
||||
//
|
||||
// static ObjectPool()
|
||||
// {
|
||||
// // Used at runtime to prevent nested collections.
|
||||
// bool isTCollection = typeof(ICollection).IsAssignableFrom(typeof(T));
|
||||
//
|
||||
// if (isTCollection)
|
||||
// throw new NotSupportedException($"ObjectPool element cannot be a collection. Type is [{typeof(T).FullName}].");
|
||||
//
|
||||
// _isValueType = typeof(T).IsValueType;
|
||||
// _isResettable = typeof(T).IsAssignableFrom(typeof(IResettable));
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Clears all pools for T.
|
||||
// /// </summary>
|
||||
// public static void ClearPools()
|
||||
// {
|
||||
// _listCache.Clear();
|
||||
// _resettableListCache.Clear();
|
||||
//
|
||||
// _hashSetCache.Clear();
|
||||
// _resettableHashSetCache.Clear();
|
||||
//
|
||||
// _queueCache.Clear();
|
||||
// _resettableQueueCache.Clear();
|
||||
//
|
||||
// _arrayCache.Clear();
|
||||
// _resettableArrayCache.Clear();
|
||||
//
|
||||
// _tCache.Clear();
|
||||
// _resettableTCache.Clear();
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Returns a List<T> automatically resetting entries when IResettable is implemented,
|
||||
// /// and pooling entries when they are a reference type.
|
||||
// /// </summary>
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static void Return(List<T> value)
|
||||
// {
|
||||
// if (value == null) return;
|
||||
//
|
||||
// Stack<List<T>> stack = _isResettable ? _resettableListCache : _listCache;
|
||||
//
|
||||
// IterateICollectionElements(value);
|
||||
//
|
||||
// value.Clear();
|
||||
// stack.Push(value);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Returns a HashSet<T> automatically resetting entries when IResettable is implemented,
|
||||
// /// and pooling entries when they are a reference type.
|
||||
// /// </summary>
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static void Return(HashSet<T> value)
|
||||
// {
|
||||
// if (value == null) return;
|
||||
//
|
||||
// Stack<HashSet<T>> stack = _isResettable ? _resettableHashSetCache : _hashSetCache;
|
||||
//
|
||||
// IterateICollectionElements(value);
|
||||
//
|
||||
// value.Clear();
|
||||
// stack.Push(value);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Returns a Queue<T> automatically resetting entries when IResettable is implemented,
|
||||
// /// and pooling entries when they are a reference type.
|
||||
// /// </summary>
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static void Return(Queue<T> value)
|
||||
// {
|
||||
// if (value == null) return;
|
||||
//
|
||||
// Stack<Queue<T>> stack = _isResettable ? _resettableQueueCache : _queueCache;
|
||||
//
|
||||
// IterateICollectionElements(value);
|
||||
//
|
||||
// value.Clear();
|
||||
// stack.Push(value);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Returns an array automatically resetting entries when IResettable is implemented,
|
||||
// /// and pools each array entry if the array element is a reference type.
|
||||
// /// </summary>
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static void Return(T[] value)
|
||||
// {
|
||||
// if (value == null) return;
|
||||
//
|
||||
// Stack<T[]> stack = _isResettable ? _resettableArrayCache : _arrayCache;
|
||||
//
|
||||
// IterateICollectionElements(value);
|
||||
//
|
||||
// Array.Clear(value, 0, value.Length);
|
||||
// stack.Push(value);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Returns value without resetting the state.
|
||||
// /// </summary>
|
||||
// public static void Return(T value)
|
||||
// {
|
||||
// _tCache.Push(value);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Creates a new List<T>.
|
||||
// /// </summary>
|
||||
// private static List<T> CreateList() => new();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Creates a new HashSet<T>.
|
||||
// /// </summary>
|
||||
// private static HashSet<T> CreateHashSet() => new();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Creates a new Queue<T>.
|
||||
// /// </summary>
|
||||
// private static Queue<T> CreateQueue() => new();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Creates a new array of length 0 (empty array).
|
||||
// /// </summary>
|
||||
// private static T[] CreateArray() => Array.Empty<T>();
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Rents a List<T>.
|
||||
// /// </summary>
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static List<T> RentList()
|
||||
// {
|
||||
// Stack<List<T>> stack = _isResettable ? _resettableListCache : _listCache;
|
||||
//
|
||||
// return RentCollection(stack, CreateList);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Rents a HashSet<T>.
|
||||
// /// </summary>
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static HashSet<T> RentHashSet()
|
||||
// {
|
||||
// Stack<HashSet<T>> stack = _isResettable ? _resettableHashSetCache : _hashSetCache;
|
||||
//
|
||||
// return RentCollection(stack, CreateHashSet);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Rents a Queue<T>.
|
||||
// /// </summary>
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static Queue<T> RentQueue()
|
||||
// {
|
||||
// Stack<Queue<T>> stack = _isResettable ? _resettableQueueCache : _queueCache;
|
||||
//
|
||||
// return RentCollection(stack, CreateQueue);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Rents an array.
|
||||
// /// </summary>
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static T[] RentArray()
|
||||
// {
|
||||
// Stack<T[]> stack = _isResettable ? _resettableArrayCache : _arrayCache;
|
||||
//
|
||||
// return RentCollection(stack, CreateArray);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Rents an object.
|
||||
// /// </summary>
|
||||
// public static T Rent()
|
||||
// {
|
||||
// Stack<T> stack = _isResettable ? _resettableTCache : _tCache;
|
||||
//
|
||||
// if (!stack.TryPop(out T result))
|
||||
// result = new();
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Rents a collection using the supplied stack. Returns using defaultFactory if stack is empty.
|
||||
// /// </summary>
|
||||
// private static TCollection RentCollection<TCollection>(Stack<TCollection> stack, Func<TCollection> defaultFactory)
|
||||
// {
|
||||
// if (!stack.TryPop(out TCollection result))
|
||||
// result = defaultFactory();
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Iterates ICollection elements, returning and resetting as needed.
|
||||
// /// </summary>
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// private static void IterateICollectionElements(IReadOnlyCollection<T> value)
|
||||
// {
|
||||
// // Reset T if possible.
|
||||
// if (_isResettable)
|
||||
// {
|
||||
// // Value type.
|
||||
// if (_isValueType)
|
||||
// {
|
||||
// foreach (T item in value)
|
||||
// ((IResettable)item).ResetState();
|
||||
// }
|
||||
// // Reference type.
|
||||
// else
|
||||
// {
|
||||
// foreach (T item in value)
|
||||
// ReturnReferenceIResettable(item);
|
||||
// }
|
||||
// }
|
||||
// // Type is not resettable.
|
||||
// else
|
||||
// {
|
||||
// // Only need to Return if is not a value type.
|
||||
// if (!_isValueType)
|
||||
// {
|
||||
// foreach (T item in value)
|
||||
// ReturnReference(item);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Returns value expecting it to be a reference type that does not implement IResettable.
|
||||
// /// </summary>
|
||||
// private static void ReturnReference(T value)
|
||||
// {
|
||||
// _resettableTCache.Push(value);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Returns value expecting it to be a reference type which implement IResettable.
|
||||
// /// </summary>
|
||||
// internal static void ReturnReferenceIResettable(T value)
|
||||
// {
|
||||
// ((IResettable)value).ResetState();
|
||||
//
|
||||
// _resettableTCache.Push(value);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6065d663177eb614bb52a41071982835
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectPool.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,63 @@
|
||||
using GameKit.Dependencies.Utilities.Types;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns if an object has been destroyed from memory.
|
||||
/// </summary>
|
||||
/// <param name = "gameObject"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsDestroyed(this GameObject gameObject)
|
||||
{
|
||||
// UnityEngine overloads the == operator for the GameObject type
|
||||
// and returns null when the object has been destroyed, but
|
||||
// actually the object is still there but has not been cleaned up yet
|
||||
// if we test both we can determine if the object has been destroyed.
|
||||
return gameObject == null && !ReferenceEquals(gameObject, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all objects in the scene of type. This method is very expensive.
|
||||
/// </summary>
|
||||
/// <typeparam name = "T"></typeparam>
|
||||
/// <param name = "requireSceneLoaded">True if the scene must be fully loaded before trying to seek objects.</param>
|
||||
/// <returns></returns>
|
||||
public static List<T> FindAllObjectsOfType<T>(bool activeSceneOnly = true, bool requireSceneLoaded = false, bool includeDDOL = true, bool includeInactive = true)
|
||||
{
|
||||
List<T> results = new();
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
Scene scene = SceneManager.GetSceneAt(i);
|
||||
// If to include only current scene.
|
||||
if (activeSceneOnly)
|
||||
{
|
||||
if (SceneManager.GetActiveScene() != scene)
|
||||
continue;
|
||||
}
|
||||
// If the scene must be fully loaded to seek objects within.
|
||||
if (!scene.isLoaded && requireSceneLoaded)
|
||||
continue;
|
||||
|
||||
GameObject[] allGameObjects = scene.GetRootGameObjects();
|
||||
for (int j = 0; j < allGameObjects.Length; j++)
|
||||
{
|
||||
results.AddRange(allGameObjects[j].GetComponentsInChildren<T>(includeInactive));
|
||||
}
|
||||
}
|
||||
|
||||
// If to also include DDOL.
|
||||
if (includeDDOL)
|
||||
{
|
||||
GameObject ddolGo = DDOL.GetDDOL().gameObject;
|
||||
results.AddRange(ddolGo.GetComponentsInChildren<T>(includeInactive));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4fa6d28a28dbf6b4295602abad3de328
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Objects.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,106 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Particles
|
||||
{
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems.
|
||||
/// </summary>
|
||||
/// <param name = "systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem[] systems, bool stopLoopingOnly)
|
||||
{
|
||||
return StopParticleSystem(systems, stopLoopingOnly, ParticleSystemStopBehavior.StopEmitting);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems while returning the time required to play out.
|
||||
/// </summary>
|
||||
/// <param name = "systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem[] systems, ParticleSystemStopBehavior stopBehavior = ParticleSystemStopBehavior.StopEmitting)
|
||||
{
|
||||
return StopParticleSystem(systems, false, stopBehavior);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems while returning the time required to play out.
|
||||
/// </summary>
|
||||
/// <param name = "systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem[] systems, bool stopLoopingOnly, ParticleSystemStopBehavior stopBehavior = ParticleSystemStopBehavior.StopEmitting)
|
||||
{
|
||||
if (systems == null)
|
||||
return 0f;
|
||||
|
||||
float playOutDuration = 0f;
|
||||
for (int i = 0; i < systems.Length; i++)
|
||||
playOutDuration = Mathf.Max(playOutDuration, StopParticleSystem(systems[i], stopLoopingOnly, stopBehavior));
|
||||
|
||||
return playOutDuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems.
|
||||
/// </summary>
|
||||
/// <param name = "systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem system, bool stopLoopingOnly, bool stopChildren = false)
|
||||
{
|
||||
return StopParticleSystem(system, stopLoopingOnly, ParticleSystemStopBehavior.StopEmitting, stopChildren);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems while returning the time required to play out.
|
||||
/// </summary>
|
||||
/// <param name = "systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem system, ParticleSystemStopBehavior stopBehavior = ParticleSystemStopBehavior.StopEmitting, bool stopChildren = false)
|
||||
{
|
||||
return StopParticleSystem(system, false, stopBehavior, stopChildren);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle system while returning the time required to play out.
|
||||
/// </summary>
|
||||
public static float StopParticleSystem(ParticleSystem system, bool stopLoopingOnly, ParticleSystemStopBehavior stopBehavior = ParticleSystemStopBehavior.StopEmitting, bool stopChildren = false)
|
||||
{
|
||||
if (system == null)
|
||||
return 0f;
|
||||
if (stopChildren)
|
||||
{
|
||||
ParticleSystem[] all = system.GetComponentsInChildren<ParticleSystem>();
|
||||
StopParticleSystem(all, stopLoopingOnly, stopBehavior);
|
||||
}
|
||||
|
||||
float playOutDuration = 0f;
|
||||
float timeLeft = system.main.duration - system.time;
|
||||
playOutDuration = Mathf.Max(playOutDuration, timeLeft);
|
||||
|
||||
if (stopLoopingOnly)
|
||||
{
|
||||
if (system.main.loop)
|
||||
system.Stop(false, stopBehavior);
|
||||
}
|
||||
else
|
||||
{
|
||||
system.Stop(false, stopBehavior);
|
||||
}
|
||||
|
||||
return playOutDuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the longest time required for all systems to stop.
|
||||
/// </summary>
|
||||
/// <param name = "systems"></param>
|
||||
/// <returns></returns>
|
||||
public static float ReturnLongestCycle(ParticleSystem[] systems)
|
||||
{
|
||||
float longestPlayTime = 0f;
|
||||
for (int i = 0; i < systems.Length; i++)
|
||||
{
|
||||
float timeLeft = systems[i].main.duration - systems[i].time;
|
||||
longestPlayTime = Mathf.Max(longestPlayTime, timeLeft);
|
||||
}
|
||||
|
||||
return longestPlayTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f3d973dcfa06554998575e8eef0938a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Particles.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,62 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Quaternions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns how fast an object must rotate over duration to reach goal.
|
||||
/// </summary>
|
||||
/// <param name = "goal">Quaternion to measure distance against.</param>
|
||||
/// <param name = "duration">How long it should take to move to goal.</param>
|
||||
/// <param name = "interval">A multiplier applied towards interval. Typically this is used for ticks passed.</param>
|
||||
/// <returns></returns>
|
||||
public static float GetRate(this Quaternion a, Quaternion goal, float duration, out float angle, uint interval = 1, float tolerance = 0f)
|
||||
{
|
||||
angle = a.Angle(goal, true);
|
||||
return angle / (duration * interval);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts b quaternion from a.
|
||||
/// </summary>
|
||||
public static Quaternion Subtract(this Quaternion a, Quaternion b) => Quaternion.Inverse(b) * a;
|
||||
|
||||
/// <summary>
|
||||
/// Adds quaternion b onto quaternion a.
|
||||
/// </summary>
|
||||
public static Quaternion Add(this Quaternion a, Quaternion b) => a * b;
|
||||
|
||||
/// <summary>
|
||||
/// Returns if two quaternions match.
|
||||
/// </summary>
|
||||
/// <param name = "precise">True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return a match even when not true due to error tolerance.</param>
|
||||
/// <returns></returns>
|
||||
public static bool Matches(this Quaternion a, Quaternion b, bool precise = false)
|
||||
{
|
||||
if (precise)
|
||||
return a.w == b.w && a.x == b.x && a.y == b.y && a.z == b.z;
|
||||
else
|
||||
return a == b;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the angle between two quaterions.
|
||||
/// </summary>
|
||||
/// <param name = "precise">True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return 0f due to error tolerance, even while there is a difference.</param>
|
||||
/// <returns></returns>
|
||||
public static float Angle(this Quaternion a, Quaternion b, bool precise = false)
|
||||
{
|
||||
if (precise)
|
||||
{
|
||||
// This is run Unitys implementation without the error tolerance.
|
||||
float dot = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
||||
return Mathf.Acos(Mathf.Min(Mathf.Abs(dot), 1f)) * 2f * 57.29578f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Quaternion.Angle(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02a9084f4f788cd4293cdff56a49b5dd
|
||||
timeCreated: 1522043602
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Quaternions.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace GameKit.Dependencies.Utilities
|
||||
{
|
||||
public static class Strings
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to encode and decode strings.
|
||||
/// </summary>
|
||||
private static readonly UTF8Encoding _encoding = new(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
|
||||
/// <summary>
|
||||
/// A buffer convert data and discard.
|
||||
/// </summary>
|
||||
public static byte[] Buffer = new byte[1024];
|
||||
|
||||
/// <summary>
|
||||
/// Converts a member string text to PascalCase
|
||||
/// </summary>
|
||||
/// <remarks>A member string is expected to be in the format '_memberName'.</remarks>
|
||||
public static string MemberToPascalCase(this string txt)
|
||||
{
|
||||
if (txt.Length < 2)
|
||||
{
|
||||
UnityEngine.Debug.LogError($"Text '{txt}' is too short.");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (txt[0] != '_')
|
||||
{
|
||||
UnityEngine.Debug.LogError($"Text '{txt}' has the incorrect member prefix.");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string firstLeter = txt[1].ToString().ToUpper();
|
||||
|
||||
string substring = txt.Length > 2 ? txt.Substring(2) : string.Empty;
|
||||
return $"{firstLeter}{substring}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a pascal case string to member case.
|
||||
/// </summary>
|
||||
/// <remarks>A PascalCase string is expected to be in the format 'PropertyName'.</remarks>
|
||||
public static string PascalCaseToMember(this string txt)
|
||||
{
|
||||
if (txt.Length < 1)
|
||||
{
|
||||
UnityEngine.Debug.LogError($"Text '{txt}' is too short.");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string firstLeter = txt[0].ToString().ToLower();
|
||||
|
||||
string subString = txt.Length > 1 ? txt.Substring(1) : string.Empty;
|
||||
return $"_{firstLeter}{subString}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attachs or detaches an suffix to a string.
|
||||
/// </summary>
|
||||
/// <param name = "text"></param>
|
||||
/// <param name = "suffix"></param>
|
||||
/// <param name = "addExtension"></param>
|
||||
public static string ReturnModifySuffix(string text, string suffix, bool addExtension)
|
||||
{
|
||||
/* Since saving to a json, add the .json extension if not present.
|
||||
* Length must be greater than 6 to contain a character and .json. */
|
||||
if (text.Length > suffix.Length + 1)
|
||||
{
|
||||
// If to add the extension.
|
||||
if (addExtension)
|
||||
{
|
||||
// If doesn't contain the extension then add it on.
|
||||
if (!text.Substring(text.Length - suffix.Length).Contains(suffix, StringComparison.CurrentCultureIgnoreCase))
|
||||
return text + suffix;
|
||||
// Already contains extension.
|
||||
else
|
||||
return text;
|
||||
}
|
||||
// Remove extension.
|
||||
else
|
||||
{
|
||||
// If contains extension.
|
||||
if (text.Substring(text.Length - suffix.Length).Contains(suffix, StringComparison.CurrentCultureIgnoreCase))
|
||||
return text.Substring(0, text.Length - suffix.Length);
|
||||
// Doesn't contain extension.
|
||||
return text;
|
||||
}
|
||||
}
|
||||
// Text isn't long enough to manipulate.
|
||||
else
|
||||
{
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string into a byte array buffer.
|
||||
/// </summary>
|
||||
/// <returns>Number of bytes written to the buffer.</returns>
|
||||
public static int ToBytes(this string value, ref byte[] buffer)
|
||||
{
|
||||
int strLength = value.Length;
|
||||
// Number of minimum bytes the buffer must be.
|
||||
int bytesNeeded = _encoding.GetMaxByteCount(strLength);
|
||||
|
||||
// Grow string buffer if needed.
|
||||
if (buffer.Length < bytesNeeded)
|
||||
Array.Resize(ref buffer, bytesNeeded * 2);
|
||||
|
||||
return _encoding.GetBytes(value, 0, strLength, buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string to bytes while allocating.
|
||||
/// </summary>
|
||||
public static byte[] ToBytesAllocated(this string value) => Encoding.Unicode.GetBytes(value);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user