Moved a couple of folders and wrote some code
This commit is contained in:
64
Assets/Packages/FishNet/Runtime/Utility/ApplicationState.cs
Normal file
64
Assets/Packages/FishNet/Runtime/Utility/ApplicationState.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using FishNet.Utility.Constant;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace FishNet.Utility
|
||||
{
|
||||
#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
|
||||
}
|
||||
|
||||
public static bool IsQuitting()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!EditorApplication.isPlayingOrWillChangePlaymode && EditorApplication.isPlaying)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
#else
|
||||
return _isQuitting;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool IsPlaying()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return EditorApplication.isPlaying;
|
||||
#else
|
||||
return Application.isPlaying;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54eb82a57a65e8548b57f5ca2a62bb76
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
12
Assets/Packages/FishNet/Runtime/Utility/Constants.cs
Normal file
12
Assets/Packages/FishNet/Runtime/Utility/Constants.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace FishNet.Utility.Constant
|
||||
{
|
||||
internal static class UtilityConstants
|
||||
{
|
||||
public const string CODEGEN_ASSEMBLY_NAME = "Unity.FishNet.CodeGen";
|
||||
public const string GENERATED_ASSEMBLY_NAME = "FishNet.Generated";
|
||||
public const string DEMOS_ASSEMBLY_NAME = "FishNet.Demos";
|
||||
public const string TEST_ASSEMBLY_NAME = "FishNet.Test";
|
||||
public const string RUNTIME_ASSEMBLY_NAME = "FishNet.Runtime";
|
||||
}
|
||||
|
||||
}
|
11
Assets/Packages/FishNet/Runtime/Utility/Constants.cs.meta
Normal file
11
Assets/Packages/FishNet/Runtime/Utility/Constants.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f2a3c23b44e4ef4e9783ef53ec0d5da
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
60
Assets/Packages/FishNet/Runtime/Utility/DDOLFinder.cs
Normal file
60
Assets/Packages/FishNet/Runtime/Utility/DDOLFinder.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility
|
||||
{
|
||||
|
||||
|
||||
public class DDOLFinder : MonoBehaviour
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Singleton instance of this class.
|
||||
/// </summary>
|
||||
public static DDOLFinder Instance { get; private set; }
|
||||
#endregion
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
FirstInitialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this script for use. Should only be completed once.
|
||||
/// </summary>
|
||||
private void FirstInitialize()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Debug.LogError("Multiple DDOL scripts found. There should be only one.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Instance = this;
|
||||
gameObject.name = "DDOLFinder";
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current DDOL or creates one if not yet created.
|
||||
/// </summary>
|
||||
public static DDOLFinder GetDDOL()
|
||||
{
|
||||
//Not yet made.
|
||||
if (Instance == null)
|
||||
{
|
||||
GameObject obj = new GameObject();
|
||||
DDOLFinder ddol = obj.AddComponent<DDOLFinder>();
|
||||
return ddol;
|
||||
}
|
||||
//Already made.
|
||||
else
|
||||
{
|
||||
return Instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
11
Assets/Packages/FishNet/Runtime/Utility/DDOLFinder.cs.meta
Normal file
11
Assets/Packages/FishNet/Runtime/Utility/DDOLFinder.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47bed61fc24f71942a7437612621bbfd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Packages/FishNet/Runtime/Utility/Editor.meta
Normal file
8
Assets/Packages/FishNet/Runtime/Utility/Editor.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66122940cd5d35e49908ec08d1daf7db
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,51 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility.Editing
|
||||
{
|
||||
/* Source https://forum.unity.com/threads/how-to-link-scenes-in-the-inspector.383140/ */
|
||||
|
||||
[CustomPropertyDrawer(typeof(SceneAttribute))]
|
||||
public class SceneDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (property.propertyType == SerializedPropertyType.String)
|
||||
{
|
||||
SceneAsset sceneObject = AssetDatabase.LoadAssetAtPath<SceneAsset>(property.stringValue);
|
||||
|
||||
if (sceneObject == null && !string.IsNullOrEmpty(property.stringValue))
|
||||
{
|
||||
// try to load it from the build settings for legacy compatibility
|
||||
sceneObject = GetBuildSettingsSceneObject(property.stringValue);
|
||||
}
|
||||
if (sceneObject == null && !string.IsNullOrEmpty(property.stringValue))
|
||||
{
|
||||
Debug.Log($"Could not find scene {property.stringValue} in {property.propertyPath}, assign the proper scenes in your NetworkManager");
|
||||
}
|
||||
SceneAsset scene = (SceneAsset)EditorGUI.ObjectField(position, label, sceneObject, typeof(SceneAsset), true);
|
||||
|
||||
property.stringValue = AssetDatabase.GetAssetPath(scene);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.LabelField(position, label.text, "Use [Scene] with strings.");
|
||||
}
|
||||
}
|
||||
|
||||
protected SceneAsset GetBuildSettingsSceneObject(string sceneName)
|
||||
{
|
||||
foreach (EditorBuildSettingsScene buildScene in EditorBuildSettings.scenes)
|
||||
{
|
||||
SceneAsset sceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(buildScene.path);
|
||||
if (sceneAsset != null && sceneAsset.name == sceneName)
|
||||
{
|
||||
return sceneAsset;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b2c813205b39ed46953611f7a5659fd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Packages/FishNet/Runtime/Utility/Extension.meta
Normal file
8
Assets/Packages/FishNet/Runtime/Utility/Extension.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f30057a48bb0104d8a7813443607804
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
18
Assets/Packages/FishNet/Runtime/Utility/Extension/Bool.cs
Normal file
18
Assets/Packages/FishNet/Runtime/Utility/Extension/Bool.cs
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
public static class BooleanExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a boolean to an integer.
|
||||
/// </summary>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
public static int ToInt(this bool b)
|
||||
{
|
||||
return (b) ? 1 : 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c688c9bd497f4a749b692b9b1d628c51
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
public static class CollectionFN
|
||||
{
|
||||
/// <summary>
|
||||
/// Random for shuffling.
|
||||
/// </summary>
|
||||
private static Random _random = new Random();
|
||||
|
||||
/// <summary>
|
||||
/// Shuffle based on Fisher-Yates shuffle.
|
||||
/// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
|
||||
/// https://stackoverflow.com/questions/273313/randomize-a-listt
|
||||
/// </summary>
|
||||
public static void Shuffle<T>(this IList<T> lst)
|
||||
{
|
||||
int n = lst.Count;
|
||||
while (n > 1)
|
||||
{
|
||||
n--;
|
||||
int k = _random.Next(n + 1);
|
||||
T value = lst[k];
|
||||
lst[k] = lst[n];
|
||||
lst[n] = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a6539089deb687469d1abdc1b8964a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,35 @@
|
||||
using FishNet.Documenting;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
[APIExclude]
|
||||
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 IDictionary<TKey, TValue> dict, TKey key, out TValue value)
|
||||
{
|
||||
#if ENABLE_IL2CPP && UNITY_IOS || UNITY_ANDROID
|
||||
if (dict.ContainsKey(key))
|
||||
{
|
||||
value = dict[key];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return dict.TryGetValue(key, out value);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d286695e7464ce943bc321215aaa2ee1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
31
Assets/Packages/FishNet/Runtime/Utility/Extension/Enum.cs
Normal file
31
Assets/Packages/FishNet/Runtime/Utility/Extension/Enum.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
public static class EnumFN
|
||||
{
|
||||
|
||||
/// <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,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f58b410f20b8e694aa852d2ea5240626
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
24
Assets/Packages/FishNet/Runtime/Utility/Extension/List.cs
Normal file
24
Assets/Packages/FishNet/Runtime/Utility/Extension/List.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using FishNet.Documenting;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
[APIExclude]
|
||||
public static class ListFN
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Adds a value to the list only if the value does not already exist.
|
||||
/// </summary>
|
||||
/// <param name="lst">Collection being added to.</param>
|
||||
/// <param name="value">Value to add.</param>
|
||||
public static void AddUnique<T>(this List<T> lst, T value)
|
||||
{
|
||||
if (!lst.Contains(value))
|
||||
lst.Add(value);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 953eb4b102d504544b49087104e6b747
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
34
Assets/Packages/FishNet/Runtime/Utility/Extension/Math.cs
Normal file
34
Assets/Packages/FishNet/Runtime/Utility/Extension/Math.cs
Normal file
@ -0,0 +1,34 @@
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
|
||||
public static class MathFN
|
||||
{
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: feb978e97a6aa6b4cbb99481d925c00c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
27
Assets/Packages/FishNet/Runtime/Utility/Extension/Object.cs
Normal file
27
Assets/Packages/FishNet/Runtime/Utility/Extension/Object.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using FishNet.Connection;
|
||||
using FishNet.Object;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
|
||||
public static class ObjectFN
|
||||
{
|
||||
/// <summary>
|
||||
/// Spawns an object over the network using InstanceFinder. Only call from the server.
|
||||
/// </summary>
|
||||
public static void Spawn(this NetworkObject nob, NetworkConnection owner = null)
|
||||
{
|
||||
InstanceFinder.ServerManager.Spawn(nob, owner);
|
||||
}
|
||||
/// <summary>
|
||||
/// Spawns an object over the network using InstanceFinder. Only call from the server.
|
||||
/// </summary>
|
||||
public static void Spawn(this GameObject go, NetworkConnection owner = null)
|
||||
{
|
||||
InstanceFinder.ServerManager.Spawn(go, owner);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d1cdee4c45e73a4fa9adba1177483ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,43 @@
|
||||
using FishNet.Documenting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
[APIExclude]
|
||||
public static class QuaternionFN
|
||||
{
|
||||
|
||||
/// <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,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b8122e8a7592784896b4173707188ce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
76
Assets/Packages/FishNet/Runtime/Utility/Extension/Scene.cs
Normal file
76
Assets/Packages/FishNet/Runtime/Utility/Extension/Scene.cs
Normal file
@ -0,0 +1,76 @@
|
||||
using FishNet.Object;
|
||||
using FishNet.Utility.Performance;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
|
||||
public static class SceneFN
|
||||
{
|
||||
#region Private.
|
||||
|
||||
/// <summary>
|
||||
/// Used for performance gains when getting objects.
|
||||
/// </summary>
|
||||
private static List<GameObject> _gameObjectList = new List<GameObject>();
|
||||
/// <summary>
|
||||
/// List for NetworkObjects.
|
||||
/// </summary>
|
||||
private static List<NetworkObject> _networkObjectListA = new List<NetworkObject>();
|
||||
/// <summary>
|
||||
/// List for NetworkObjects.
|
||||
/// </summary>
|
||||
private static List<NetworkObject> _networkObjectListB = new List<NetworkObject>();
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets all NetworkObjects in a scene.
|
||||
/// </summary>
|
||||
/// <param name="s">Scene to get objects in.</param>
|
||||
/// <param name="firstOnly">True to only return the first NetworkObject within an object chain. False will return nested NetworkObjects.</param>
|
||||
/// <param name="cache">ListCache of found NetworkObjects.</param>
|
||||
/// <returns></returns>
|
||||
public static void GetSceneNetworkObjects(Scene s, bool firstOnly, out ListCache<NetworkObject> nobCache)
|
||||
{
|
||||
nobCache = ListCaches.GetNetworkObjectCache();
|
||||
//Iterate all root objects for the scene.
|
||||
s.GetRootGameObjects(_gameObjectList);
|
||||
foreach (GameObject go in _gameObjectList)
|
||||
{
|
||||
|
||||
//Get NetworkObjects within children of each root.
|
||||
go.GetComponentsInChildren<NetworkObject>(true, _networkObjectListA);
|
||||
//If network objects are found.
|
||||
if (_networkObjectListA.Count > 0)
|
||||
{
|
||||
//Add only the first networkobject
|
||||
if (firstOnly)
|
||||
{
|
||||
/* The easiest way to see if a nob is nested is to
|
||||
* get nobs in parent and if the count is greater than 1, then
|
||||
* it is nested. The technique used here isn't exactly fast but
|
||||
* it will only occur during scene loads, so I'm trading off speed
|
||||
* for effort and readability. */
|
||||
foreach (NetworkObject nob in _networkObjectListA)
|
||||
{
|
||||
nob.GetComponentsInParent<NetworkObject>(true, _networkObjectListB);
|
||||
//No extra nobs, only this one.
|
||||
if (_networkObjectListB.Count == 1)
|
||||
nobCache.AddValue(nob);
|
||||
}
|
||||
}
|
||||
//Not first only, add them all.
|
||||
else
|
||||
{
|
||||
nobCache.AddValues(_networkObjectListA);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a02f3d03f737e304e9854278f4e9211d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,42 @@
|
||||
using FishNet.Documenting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility.Extension
|
||||
{
|
||||
[APIExclude]
|
||||
public static class TransformFN
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the offset values of target from a transform.
|
||||
/// </summary>
|
||||
/// <param name="pos">Position offset result.</param>
|
||||
/// <param name="rot">Rotation offset result.</param>
|
||||
public static void SetTransformOffsets(this Transform t, Transform target, ref Vector3 pos, ref Quaternion rot)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
pos = (t.position - target.position);
|
||||
rot = (t.rotation * Quaternion.Inverse(target.rotation));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets local position and rotation for a transform.
|
||||
/// </summary>
|
||||
public static void SetLocalPositionAndRotation(this Transform t, Vector3 pos, Quaternion rot)
|
||||
{
|
||||
t.localPosition = pos;
|
||||
t.localRotation = rot;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets local position, rotation, and scale for a transform.
|
||||
/// </summary>
|
||||
public static void SetLocalPositionRotationAndScale(this Transform t, Vector3 pos, Quaternion rot, Vector3 scale)
|
||||
{
|
||||
t.localPosition = pos;
|
||||
t.localRotation = rot;
|
||||
t.localScale = scale;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d311fc1bf09b9e4fbc5a17a9c50ab0d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Packages/FishNet/Runtime/Utility/Performance.meta
Normal file
8
Assets/Packages/FishNet/Runtime/Utility/Performance.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c297487b42ef1b640a26b7c41fef6e27
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.Utility.Performance
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves and stores byte arrays using a pooling system.
|
||||
/// </summary>
|
||||
public static class ByteArrayPool
|
||||
{
|
||||
/// <summary>
|
||||
/// Stored byte arrays.
|
||||
/// </summary>
|
||||
private static Queue<byte[]> _byteArrays = new Queue<byte[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a byte array which will be of at lesat minimum length. The returned array must manually be stored.
|
||||
/// </summary>
|
||||
public static byte[] Retrieve(int minimumLength)
|
||||
{
|
||||
byte[] result = null;
|
||||
|
||||
if (_byteArrays.Count > 0)
|
||||
result = _byteArrays.Dequeue();
|
||||
|
||||
int doubleMinimumLength = (minimumLength * 2);
|
||||
if (result == null)
|
||||
result = new byte[doubleMinimumLength];
|
||||
else if (result.Length < minimumLength)
|
||||
Array.Resize(ref result, doubleMinimumLength);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a byte array for re-use.
|
||||
/// </summary>
|
||||
public static void Store(byte[] buffer)
|
||||
{
|
||||
/* Holy cow that's a lot of buffered
|
||||
* buffers. This wouldn't happen under normal
|
||||
* circumstances but if the user is stress
|
||||
* testing connections in one executable perhaps. */
|
||||
if (_byteArrays.Count > 300)
|
||||
return;
|
||||
_byteArrays.Enqueue(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7620a5e6fedc18408f8f04821b35bbd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,203 @@
|
||||
using FishNet.Managing.Object;
|
||||
using FishNet.Object;
|
||||
using FishNet.Utility.Extension;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility.Performance
|
||||
{
|
||||
|
||||
|
||||
public class DefaultObjectPool : ObjectPool
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Cache for pooled NetworkObjects.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<Dictionary<int, Stack<NetworkObject>>> Cache => _cache;
|
||||
private List<Dictionary<int, Stack<NetworkObject>>> _cache = new List<Dictionary<int, Stack<NetworkObject>>>();
|
||||
#endregion
|
||||
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// True if to use object pooling.
|
||||
/// </summary>
|
||||
[Tooltip("True if to use object pooling.")]
|
||||
[SerializeField]
|
||||
private bool _enabled = true;
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// Current count of the cache collection.
|
||||
/// </summary>
|
||||
private int _cacheCount = 0;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns an object that has been stored with a collectionId of 0. A new object will be created if no stored objects are available.
|
||||
/// </summary>
|
||||
/// <param name="prefabId">PrefabId of the object to return.</param>
|
||||
/// <param name="asServer">True if being called on the server side.</param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override NetworkObject RetrieveObject(int prefabId, bool asServer)
|
||||
{
|
||||
return RetrieveObject(prefabId, 0, asServer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an object that has been stored. A new object will be created if no stored objects are available.
|
||||
/// </summary>
|
||||
/// <param name="prefabId">PrefabId of the object to return.</param>
|
||||
/// <param name="collectionId">CollectionId of the prefab.</param>
|
||||
/// <param name="asServer">True if being called on the server side.</param>
|
||||
/// <returns></returns>
|
||||
public override NetworkObject RetrieveObject(int prefabId, ushort collectionId, bool asServer)
|
||||
{
|
||||
PrefabObjects po = base.NetworkManager.GetPrefabObjects<PrefabObjects>(collectionId, false);
|
||||
//Quick exit/normal retrieval when not using pooling.
|
||||
if (!_enabled)
|
||||
{
|
||||
NetworkObject prefab = po.GetObject(asServer, prefabId);
|
||||
return Instantiate(prefab);
|
||||
}
|
||||
|
||||
Stack<NetworkObject> cache = GetOrCreateCache(collectionId, prefabId);
|
||||
NetworkObject nob;
|
||||
//Iterate until nob is populated just in case cache entries have been destroyed.
|
||||
do
|
||||
{
|
||||
if (cache.Count == 0)
|
||||
{
|
||||
NetworkObject prefab = po.GetObject(asServer, prefabId);
|
||||
/* A null nob should never be returned from spawnables. This means something
|
||||
* else broke, likely unrelated to the object pool. */
|
||||
nob = Instantiate(prefab);
|
||||
//Can break instantly since we know nob is not null.
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
nob = cache.Pop();
|
||||
}
|
||||
|
||||
} while (nob == null);
|
||||
|
||||
nob.gameObject.SetActive(true);
|
||||
return nob;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores an object into the pool.
|
||||
/// </summary>
|
||||
/// <param name="instantiated">Object to store.</param>
|
||||
/// <param name="asServer">True if being called on the server side.</param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void StoreObject(NetworkObject instantiated, bool asServer)
|
||||
{
|
||||
//Pooling is not enabled.
|
||||
if (!_enabled)
|
||||
{
|
||||
Destroy(instantiated.gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
instantiated.gameObject.SetActive(false);
|
||||
instantiated.ResetForObjectPool();
|
||||
Stack<NetworkObject> cache = GetOrCreateCache(instantiated.SpawnableCollectionId, instantiated.PrefabId);
|
||||
cache.Push(instantiated);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a number of objects and adds them to the pool.
|
||||
/// </summary>
|
||||
/// <param name="prefab">Prefab to cache.</param>
|
||||
/// <param name="count">Quantity to spawn.</param>
|
||||
/// <param name="asServer">True if storing prefabs for the server collection. This is only applicable when using DualPrefabObjects.</param>
|
||||
public void CacheObjects(NetworkObject prefab, int count, bool asServer)
|
||||
{
|
||||
if (!_enabled)
|
||||
return;
|
||||
if (count <= 0)
|
||||
return;
|
||||
if (prefab == null)
|
||||
return;
|
||||
if (prefab.PrefabId == NetworkObject.UNSET_PREFABID_VALUE)
|
||||
{
|
||||
InstanceFinder.NetworkManager.LogError($"Pefab {prefab.name} has an invalid prefabId and cannot be cached.");
|
||||
return;
|
||||
}
|
||||
|
||||
Stack<NetworkObject> cache = GetOrCreateCache(prefab.SpawnableCollectionId, prefab.PrefabId);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
NetworkObject nob = Instantiate(prefab);
|
||||
nob.gameObject.SetActive(false);
|
||||
cache.Push(nob);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears pools for all collectionIds
|
||||
/// </summary>
|
||||
public void ClearPool()
|
||||
{
|
||||
int count = _cache.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
ClearPool(i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears a pool for collectionId.
|
||||
/// </summary>
|
||||
/// <param name="collectionId">CollectionId to clear for.</param>
|
||||
public void ClearPool(int collectionId)
|
||||
{
|
||||
if (collectionId >= _cacheCount)
|
||||
return;
|
||||
|
||||
Dictionary<int, Stack<NetworkObject>> dict = _cache[collectionId];
|
||||
//Convert to a list from the stack so we do not modify the stack directly.
|
||||
ListCache<NetworkObject> nobCache = ListCaches.GetNetworkObjectCache();
|
||||
foreach (Stack<NetworkObject> item in dict.Values)
|
||||
{
|
||||
while (item.Count > 0)
|
||||
nobCache.AddValue(item.Pop());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a cache for an id or creates one if does not exist.
|
||||
/// </summary>
|
||||
/// <param name="prefabId"></param>
|
||||
/// <returns></returns>
|
||||
private Stack<NetworkObject> GetOrCreateCache(int collectionId, int prefabId)
|
||||
{
|
||||
if (collectionId >= _cacheCount)
|
||||
{
|
||||
//Add more to the cache.
|
||||
while (_cache.Count <= collectionId)
|
||||
{
|
||||
Dictionary<int, Stack<NetworkObject>> dict = new Dictionary<int, Stack<NetworkObject>>();
|
||||
_cache.Add(dict);
|
||||
}
|
||||
_cacheCount = collectionId;
|
||||
}
|
||||
|
||||
Dictionary<int, Stack<NetworkObject>> dictionary = _cache[collectionId];
|
||||
Stack<NetworkObject> cache;
|
||||
//No cache for prefabId yet, make one.
|
||||
if (!dictionary.TryGetValueIL2CPP(prefabId, out cache))
|
||||
{
|
||||
cache = new Stack<NetworkObject>();
|
||||
dictionary[prefabId] = cache;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb13d174096685549b1d6a94d726ff7d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
341
Assets/Packages/FishNet/Runtime/Utility/Performance/ListCache.cs
Normal file
341
Assets/Packages/FishNet/Runtime/Utility/Performance/ListCache.cs
Normal file
@ -0,0 +1,341 @@
|
||||
using FishNet.Connection;
|
||||
using FishNet.Managing;
|
||||
using FishNet.Object;
|
||||
using FishNet.Serializing.Helping;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility.Performance
|
||||
{
|
||||
/// <summary>
|
||||
/// Various ListCache instances that may be used on the Unity thread.
|
||||
/// </summary>
|
||||
public static class ListCaches
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Cache collection for NetworkObjects.
|
||||
/// </summary>
|
||||
private static Stack<ListCache<NetworkObject>> _networkObjectCaches = new Stack<ListCache<NetworkObject>>();
|
||||
/// <summary>
|
||||
/// Cache collection for NetworkObjects.
|
||||
/// </summary>
|
||||
private static Stack<ListCache<NetworkBehaviour>> _networkBehaviourCaches = new Stack<ListCache<NetworkBehaviour>>();
|
||||
/// <summary>
|
||||
/// Cache collection for NetworkObjects.
|
||||
/// </summary>
|
||||
private static Stack<ListCache<Transform>> _transformCaches = new Stack<ListCache<Transform>>();
|
||||
/// <summary>
|
||||
/// Cache collection for NetworkConnections.
|
||||
/// </summary>
|
||||
private static Stack<ListCache<NetworkConnection>> _networkConnectionCaches = new Stack<ListCache<NetworkConnection>>();
|
||||
/// <summary>
|
||||
/// Cache collection for ints.
|
||||
/// </summary>
|
||||
private static Stack<ListCache<int>> _intCaches = new Stack<ListCache<int>>();
|
||||
|
||||
|
||||
#region GetCache.
|
||||
/// <summary>
|
||||
/// Returns a NetworkObject cache. Use StoreCache to return the cache.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ListCache<NetworkObject> GetNetworkObjectCache()
|
||||
{
|
||||
ListCache<NetworkObject> result;
|
||||
if (_networkObjectCaches.Count == 0)
|
||||
result = new ListCache<NetworkObject>();
|
||||
else
|
||||
result = _networkObjectCaches.Pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a NetworkConnection cache. Use StoreCache to return the cache.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ListCache<NetworkConnection> GetNetworkConnectionCache()
|
||||
{
|
||||
ListCache<NetworkConnection> result;
|
||||
if (_networkConnectionCaches.Count == 0)
|
||||
result = new ListCache<NetworkConnection>();
|
||||
else
|
||||
result = _networkConnectionCaches.Pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a Transform cache. Use StoreCache to return the cache.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ListCache<Transform> GetTransformCache()
|
||||
{
|
||||
ListCache<Transform> result;
|
||||
if (_transformCaches.Count == 0)
|
||||
result = new ListCache<Transform>();
|
||||
else
|
||||
result = _transformCaches.Pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a NetworkBehaviour cache. Use StoreCache to return the cache.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ListCache<NetworkBehaviour> GetNetworkBehaviourCache()
|
||||
{
|
||||
ListCache<NetworkBehaviour> result;
|
||||
if (_networkBehaviourCaches.Count == 0)
|
||||
result = new ListCache<NetworkBehaviour>();
|
||||
else
|
||||
result = _networkBehaviourCaches.Pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an int cache. Use StoreCache to return the cache.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ListCache<int> GetIntCache()
|
||||
{
|
||||
ListCache<int> result;
|
||||
if (_intCaches.Count == 0)
|
||||
result = new ListCache<int>();
|
||||
else
|
||||
result = _intCaches.Pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region StoreCache.
|
||||
/// <summary>
|
||||
/// Stores a NetworkObject cache.
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
public static void StoreCache(ListCache<NetworkObject> cache)
|
||||
{
|
||||
cache.Reset();
|
||||
_networkObjectCaches.Push(cache);
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a NetworkConnection cache.
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
public static void StoreCache(ListCache<NetworkConnection> cache)
|
||||
{
|
||||
cache.Reset();
|
||||
_networkConnectionCaches.Push(cache);
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a Transform cache.
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
public static void StoreCache(ListCache<Transform> cache)
|
||||
{
|
||||
cache.Reset();
|
||||
_transformCaches.Push(cache);
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a NetworkBehaviour cache.
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
public static void StoreCache(ListCache<NetworkBehaviour> cache)
|
||||
{
|
||||
cache.Reset();
|
||||
_networkBehaviourCaches.Push(cache);
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores an int cache.
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
public static void StoreCache(ListCache<int> cache)
|
||||
{
|
||||
cache.Reset();
|
||||
_intCaches.Push(cache);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a reusable cache of T which auto expands.
|
||||
/// </summary>
|
||||
public class ListCache<T>
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Collection cache is for.
|
||||
/// </summary>
|
||||
public List<T> Collection = new List<T>();
|
||||
/// <summary>
|
||||
/// Entries currently written.
|
||||
/// </summary>
|
||||
public int Written => Collection.Count;
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// Cache for type.
|
||||
/// </summary>
|
||||
private Stack<T> _cache = new Stack<T>();
|
||||
#endregion
|
||||
|
||||
public ListCache()
|
||||
{
|
||||
Collection = new List<T>();
|
||||
}
|
||||
public ListCache(int capacity)
|
||||
{
|
||||
Collection = new List<T>(capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns T from cache when possible, or creates a new object when not.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private T Retrieve()
|
||||
{
|
||||
if (_cache.Count > 0)
|
||||
return _cache.Pop();
|
||||
else
|
||||
return Activator.CreateInstance<T>();
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores value into the cache.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
private void Store(T value)
|
||||
{
|
||||
_cache.Push(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new value to Collection and returns it.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public T AddReference()
|
||||
{
|
||||
T next = Retrieve();
|
||||
Collection.Add(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an bject into Collection and returns it.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public T InsertReference(int index)
|
||||
{
|
||||
//Would just be at the end anyway.
|
||||
if (index >= Collection.Count)
|
||||
return AddReference();
|
||||
|
||||
T next = Retrieve();
|
||||
Collection.Insert(index, next);
|
||||
return next;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds value to Collection.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void AddValue(T value)
|
||||
{
|
||||
Collection.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts value into Collection.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
|
||||
public void InsertValue(int index, T value)
|
||||
{
|
||||
//Would just be at the end anyway.
|
||||
if (index >= Collection.Count)
|
||||
AddValue(value);
|
||||
else
|
||||
Collection.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds values to Collection.
|
||||
/// </summary>
|
||||
/// <param name="values"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddValues(ListCache<T> values)
|
||||
{
|
||||
int w = values.Written;
|
||||
List<T> c = values.Collection;
|
||||
for (int i = 0; i < w; i++)
|
||||
AddValue(c[i]);
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds values to Collection.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddValues(T[] values)
|
||||
{
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
AddValue(values[i]);
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds values to Collection.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddValues(List<T> values)
|
||||
{
|
||||
for (int i = 0; i < values.Count; i++)
|
||||
AddValue(values[i]);
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds values to Collection.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddValues(HashSet<T> values)
|
||||
{
|
||||
foreach (T item in values)
|
||||
AddValue(item);
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds values to Collection.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddValues(ISet<T> values)
|
||||
{
|
||||
foreach (T item in values)
|
||||
AddValue(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds values to Collection.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddValues(IReadOnlyCollection<T> values)
|
||||
{
|
||||
foreach (T item in values)
|
||||
AddValue(item);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resets cache.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
foreach (T item in Collection)
|
||||
Store(item);
|
||||
Collection.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 488b0788adfd9ee43977abd5d0280124
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,47 @@
|
||||
using FishNet.Managing;
|
||||
using FishNet.Object;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility.Performance
|
||||
{
|
||||
|
||||
public abstract class ObjectPool : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// NetworkManager this ObjectPool belongs to.
|
||||
/// </summary>
|
||||
protected NetworkManager NetworkManager {get; private set;}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this script for use.
|
||||
/// </summary>
|
||||
public virtual void InitializeOnce(NetworkManager nm)
|
||||
{
|
||||
NetworkManager = nm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an object that has been stored using collectioNid of 0. A new object will be created if no stored objects are available.
|
||||
/// </summary>
|
||||
/// <param name="prefabId">PrefabId of the object to return.</param>
|
||||
/// <param name="asServer">True if being called on the server side.</param>
|
||||
/// <returns></returns>
|
||||
public abstract NetworkObject RetrieveObject(int prefabId, bool asServer);
|
||||
/// <summary>
|
||||
/// Returns an object that has been stored. A new object will be created if no stored objects are available.
|
||||
/// </summary>
|
||||
/// <param name="prefabId">PrefabId of the object to return.</param>
|
||||
/// <param name="asServer">True if being called on the server side.</param>
|
||||
/// <returns></returns>
|
||||
public virtual NetworkObject RetrieveObject(int prefabId, ushort collectionId, bool asServer) => null;
|
||||
/// <summary>
|
||||
/// Stores an object into the pool.
|
||||
/// </summary>
|
||||
/// <param name="instantiated">Object to store.</param>
|
||||
/// <param name="asServer">True if being called on the server side.</param>
|
||||
/// <returns></returns>
|
||||
public abstract void StoreObject(NetworkObject instantiated, bool asServer);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ec7d855ffa7afc45b619b84ddbda27c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,339 @@
|
||||
using FishNet.Documenting;
|
||||
using FishNet.Managing;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Writes values to a collection of a set size, overwriting old values as needed.
|
||||
/// </summary>
|
||||
public class RingBuffer<T>
|
||||
{
|
||||
#region Types.
|
||||
/// <summary>
|
||||
/// Custom enumerator to prevent garbage collection.
|
||||
/// </summary>
|
||||
[APIExclude]
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Current entry in the enumerator.
|
||||
/// </summary>
|
||||
public T Current { get; private set; }
|
||||
/// <summary>
|
||||
/// Actual index of the last enumerated value.
|
||||
/// </summary>
|
||||
public int ActualIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
int total = (_startIndex + (_read - 1));
|
||||
int capacity = _rollingCollection.Capacity;
|
||||
if (total >= capacity)
|
||||
total -= capacity;
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Simulated index of the last enumerated value.
|
||||
/// </summary>
|
||||
public int SimulatedIndex => (_read - 1);
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// RollingCollection to use.
|
||||
/// </summary>
|
||||
private RingBuffer<T> _rollingCollection;
|
||||
/// <summary>
|
||||
/// Collection to iterate.
|
||||
/// </summary>
|
||||
private readonly T[] _collection;
|
||||
/// <summary>
|
||||
/// Number of entries read during the enumeration.
|
||||
/// </summary>
|
||||
private int _read;
|
||||
/// <summary>
|
||||
/// Start index of enumerations.
|
||||
/// </summary>
|
||||
private int _startIndex;
|
||||
#endregion
|
||||
|
||||
public Enumerator(RingBuffer<T> c)
|
||||
{
|
||||
_read = 0;
|
||||
_startIndex = 0;
|
||||
_rollingCollection = c;
|
||||
_collection = c.Collection;
|
||||
Current = default;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
int written = _rollingCollection.Count;
|
||||
if (_read >= written)
|
||||
{
|
||||
ResetRead();
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = (_startIndex + _read);
|
||||
int capacity = _rollingCollection.Capacity;
|
||||
if (index >= capacity)
|
||||
index -= capacity;
|
||||
Current = _collection[index];
|
||||
|
||||
_read++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a new start index to begin reading at.
|
||||
/// </summary>
|
||||
public void SetStartIndex(int index)
|
||||
{
|
||||
_startIndex = index;
|
||||
ResetRead();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets a new start index to begin reading at.
|
||||
/// </summary>
|
||||
public void AddStartIndex(int value)
|
||||
{
|
||||
_startIndex += value;
|
||||
|
||||
int cap = _rollingCollection.Capacity;
|
||||
if (_startIndex > cap)
|
||||
_startIndex -= cap;
|
||||
else if (_startIndex < 0)
|
||||
_startIndex += cap;
|
||||
|
||||
ResetRead();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets number of entries read during the enumeration.
|
||||
/// </summary>
|
||||
public void ResetRead()
|
||||
{
|
||||
_read = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets read count.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_startIndex = 0;
|
||||
ResetRead();
|
||||
}
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Current write index of the collection.
|
||||
/// </summary>
|
||||
public int WriteIndex { get; private set; }
|
||||
/// <summary>
|
||||
/// Number of entries currently written.
|
||||
/// </summary>
|
||||
public int Count => _written;
|
||||
/// <summary>
|
||||
/// Maximum size of the collection.
|
||||
/// </summary>
|
||||
public int Capacity => Collection.Length;
|
||||
/// <summary>
|
||||
/// Collection being used.
|
||||
/// </summary>
|
||||
public T[] Collection = new T[0];
|
||||
/// <summary>
|
||||
/// True if initialized.
|
||||
/// </summary>
|
||||
public bool Initialized { get; private set; }
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// Number of entries written. This will never go beyond the capacity but will be less until capacity is filled.
|
||||
/// </summary>
|
||||
private int _written;
|
||||
/// <summary>
|
||||
/// Enumerator for the collection.
|
||||
/// </summary>
|
||||
private Enumerator _enumerator;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the collection at length.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Size to initialize the collection as. This cannot be changed after initialized.</param>
|
||||
public void Initialize(int capacity)
|
||||
{
|
||||
if (capacity <= 0)
|
||||
{
|
||||
NetworkManager.StaticLogError($"Collection length must be larger than 0.");
|
||||
return;
|
||||
}
|
||||
|
||||
Collection = new T[capacity];
|
||||
_enumerator = new Enumerator(this);
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the collection to default values and resets indexing.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
for (int i = 0; i < Collection.Length; i++)
|
||||
Collection[i] = default;
|
||||
|
||||
Reset();
|
||||
}
|
||||
/// <summary>
|
||||
/// Resets the collection without clearing.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_written = 0;
|
||||
WriteIndex = 0;
|
||||
_enumerator.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an entry to the collection, returning a replaced entry.
|
||||
/// </summary>
|
||||
/// <param name="data">Data to add.</param>
|
||||
/// <returns>Replaced entry. Value will be default if no entry was replaced.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T Add(T data)
|
||||
{
|
||||
if (!IsInitializedWithError())
|
||||
return default;
|
||||
|
||||
int capacity = Capacity;
|
||||
T current = Collection[WriteIndex];
|
||||
Collection[WriteIndex] = data;
|
||||
|
||||
WriteIndex++;
|
||||
_written++;
|
||||
//If index would exceed next iteration reset it.
|
||||
if (WriteIndex >= capacity)
|
||||
WriteIndex = 0;
|
||||
|
||||
/* If written has exceeded capacity
|
||||
* then the start index needs to be moved
|
||||
* to adjust for overwritten values. */
|
||||
if (_written > capacity)
|
||||
{
|
||||
_written = capacity;
|
||||
_enumerator.SetStartIndex(WriteIndex);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns value in actual index as it relates to simulated index.
|
||||
/// </summary>
|
||||
/// <param name="simulatedIndex">Simulated index to return. A value of 0 would return the first simulated index in the collection.</param>
|
||||
/// <returns></returns>
|
||||
public T this[int simulatedIndex]
|
||||
{
|
||||
get
|
||||
{
|
||||
int offset = (Capacity - _written) + simulatedIndex + WriteIndex;
|
||||
if (offset >= Capacity)
|
||||
offset -= Capacity;
|
||||
return Collection[offset];
|
||||
}
|
||||
set
|
||||
{
|
||||
int offset = (Capacity - _written) + simulatedIndex + WriteIndex;
|
||||
if (offset >= Capacity)
|
||||
offset -= Capacity;
|
||||
Collection[offset] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns Enumerator for the collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
if (!IsInitializedWithError())
|
||||
return default;
|
||||
|
||||
_enumerator.ResetRead();
|
||||
return _enumerator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes values from the simulated start of the collection.
|
||||
/// </summary>
|
||||
/// <param name="fromStart">True to remove from the start, false to remove from the end.</param>
|
||||
/// <param name="length">Number of entries to remove.</param>
|
||||
public void RemoveRange(bool fromStart, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
return;
|
||||
if (length < 0)
|
||||
{
|
||||
NetworkManager.StaticLogError($"Negative values cannot be removed.");
|
||||
return;
|
||||
}
|
||||
//Full reset if value is at or more than written.
|
||||
if (length >= _written)
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
_written -= length;
|
||||
if (fromStart)
|
||||
{
|
||||
_enumerator.AddStartIndex(length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
WriteIndex -= length;
|
||||
if (WriteIndex < 0)
|
||||
WriteIndex += Capacity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if initialized and errors if not.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool IsInitializedWithError()
|
||||
{
|
||||
if (!Initialized)
|
||||
{
|
||||
NetworkManager.StaticLogError($"RingBuffer has not yet been initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a066c51d748a04546875bd7d43118837
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,39 @@
|
||||
using FishNet.Object;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility.Performance
|
||||
{
|
||||
|
||||
public static class GetNonAlloc
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private static List<Transform> _transformList = new List<Transform>();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private static List<NetworkBehaviour> _networkBehavioursList = new List<NetworkBehaviour>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets all NetworkBehaviours on a transform.
|
||||
/// </summary>
|
||||
public static List<NetworkBehaviour> GetNetworkBehaviours(this Transform t)
|
||||
{
|
||||
t.GetComponents(_networkBehavioursList);
|
||||
return _networkBehavioursList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all transforms on transform and it's children.
|
||||
/// </summary>
|
||||
public static List<Transform> GetTransformsInChildrenNonAlloc(this Transform t, bool includeInactive = false)
|
||||
{
|
||||
t.GetComponentsInChildren<Transform>(includeInactive, _transformList);
|
||||
return _transformList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d0740f919077254c8ffb131b9587407
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
12
Assets/Packages/FishNet/Runtime/Utility/SceneAttribute.cs
Normal file
12
Assets/Packages/FishNet/Runtime/Utility/SceneAttribute.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Utility
|
||||
{
|
||||
/* Source https://forum.unity.com/threads/how-to-link-scenes-in-the-inspector.383140/ */
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string property into a Scene property in the inspector
|
||||
/// </summary>
|
||||
public class SceneAttribute : PropertyAttribute { }
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3684fb9a5dec7454b8ad791f5ef19164
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user