[Add] FishNet

This commit is contained in:
2026-03-30 20:11:57 +07:00
parent ee793a3361
commit c22c08753a
1797 changed files with 197950 additions and 1 deletions
@@ -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
}
@@ -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
}
}
}
@@ -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);
}
}
@@ -0,0 +1,20 @@
fileFormatVersion: 2
guid: b396f2be4de550a4e92b552650311600
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/Strings.cs
uploadId: 866910
@@ -0,0 +1,195 @@
using System.Collections.Generic;
using UnityEngine;
namespace GameKit.Dependencies.Utilities
{
public static class Transforms
{
/// <summary>
/// Returns the sizeDelta halfed.
/// </summary>
/// <param name = "considerScale">True to multiple values by RectTransform scale.</param>
public static Vector2 HalfSizeDelta(this RectTransform rectTransform, bool useScale = false)
{
Vector2 sizeDelta = useScale ? rectTransform.SizeDeltaScaled() : rectTransform.sizeDelta;
return sizeDelta / 2f;
}
/// <summary>
/// Returns the sizeDelta multiplied by scale.
/// </summary>
public static Vector2 SizeDeltaScaled(this RectTransform rectTransform)
{
return rectTransform.sizeDelta * rectTransform.localScale;
}
/// <summary>
/// Returns a position for the rectTransform ensuring it's fully on the screen.
/// </summary>
/// <param name = "desiredPosition">Preferred position for the rectTransform.</param>
/// <param name = "padding">How much padding the transform must be from the screen edges.</param>
public static Vector3 GetOnScreenPosition(this RectTransform rectTransform, Vector3 desiredPosition, Vector2 padding)
{
RectTransform canvasRectTransform = rectTransform.GetComponentInParent<Canvas>().transform as RectTransform;
Vector2 clampedPos = desiredPosition;
Vector2 localScale = canvasRectTransform.localScale;
Vector2 oneMinusPivot = Vector2.one - rectTransform.pivot;
// The size has to be scaled to account for the size and scale of the Canvas it is childed to
Vector2 scaledSize = rectTransform.sizeDelta * localScale;
// Calculate the minimum and maximum bounds of the canvas our object can occupy
Vector2 minClamp = scaledSize * rectTransform.pivot + padding;
Vector2 maxClamp = (canvasRectTransform.rect.size - (rectTransform.sizeDelta * oneMinusPivot + padding)) * localScale;
float clampX = Mathf.Clamp(clampedPos.x, minClamp.x, maxClamp.x);
float clampY = Mathf.Clamp(clampedPos.y, minClamp.y, maxClamp.y);
return new Vector2(clampX, clampY);
}
/// <summary>
/// Sets a parent for src while maintaining position, rotation, and scale of src.
/// </summary>
/// <param name = "parent">Transform to become a child of.</param>
public static void SetParentAndKeepTransform(this Transform src, Transform parent)
{
Vector3 pos = src.position;
Quaternion rot = src.rotation;
Vector3 scale = src.localScale;
src.SetParent(parent);
src.position = pos;
src.rotation = rot;
src.localScale = scale;
}
/// <summary>
/// Destroys all children under the specified transform.
/// </summary>
public static void DestroyChildren(this Transform t, bool destroyImmediately = false)
{
// If destroying immediately then the iteration needs to occur only on the top-most children.
if (destroyImmediately)
{
List<Transform> children = CollectionCaches<Transform>.RetrieveList();
int childCount = t.childCount;
for (int i = 0; i < childCount; i++)
children.Add(t.GetChild(i));
foreach (Transform child in children)
Object.DestroyImmediate(child);
CollectionCaches<Transform>.Store(children);
}
// Iterate using Unitys enumerator.
else
{
foreach (Transform child in t)
Object.Destroy(child.gameObject);
}
}
/// <summary>
/// Destroys all children of a type under the specified transform.
/// </summary>
public static void DestroyChildren<T>(this Transform t, bool destroyImmediately = false) where T : MonoBehaviour
{
T[] children = t.GetComponentsInChildren<T>();
foreach (T child in children)
{
if (destroyImmediately)
MonoBehaviour.DestroyImmediate(child.gameObject);
else
Object.Destroy(child.gameObject);
}
}
/// <summary>
/// Gets components in children and optionally parent.
/// </summary>
/// <typeparam name = "T"></typeparam>
/// <param name = "results"></param>
/// <param name = "parent"></param>
/// <param name = "includeParent"></param>
/// <param name = "includeInactive"></param>
public static void GetComponentsInChildren<T>(this Transform parent, List<T> results, bool includeParent = true, bool includeInactive = false) where T : Component
{
if (!includeParent)
{
List<T> current = CollectionCaches<T>.RetrieveList();
for (int i = 0; i < parent.childCount; i++)
{
parent.GetChild(i).GetComponentsInChildren(includeInactive, current);
results.AddRange(current);
}
CollectionCaches<T>.Store(current);
}
else
{
parent.GetComponentsInChildren(includeInactive, results);
}
}
/// <summary>
/// Returns the position of this transform.
/// </summary>
public static Vector3 GetPosition(this Transform t, bool localSpace)
{
return localSpace ? t.localPosition : t.position;
}
/// <summary>
/// Returns the rotation of this transform.
/// </summary>
public static Quaternion GetRotation(this Transform t, bool localSpace)
{
return localSpace ? t.localRotation : t.rotation;
}
/// <summary>
/// Returns the scale of this transform.
/// </summary>
public static Vector3 GetScale(this Transform t)
{
return t.localScale;
}
/// <summary>
/// Sets the position of this transform.
/// </summary>
/// <param name = "t"></param>
/// <param name = "localSpace"></param>
public static void SetPosition(this Transform t, bool localSpace, Vector3 pos)
{
if (localSpace)
t.localPosition = pos;
else
t.position = pos;
}
/// <summary>
/// Sets the position of this transform.
/// </summary>
/// <param name = "t"></param>
/// <param name = "localSpace"></param>
public static void SetRotation(this Transform t, bool localSpace, Quaternion rot)
{
if (localSpace)
t.localRotation = rot;
else
t.rotation = rot;
}
/// <summary>
/// Sets the position of this transform.
/// </summary>
/// <param name = "t"></param>
/// <param name = "localSpace"></param>
public static void SetScale(this Transform t, Vector3 scale)
{
t.localScale = scale;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ba23540de73f58b458e7d7a200f3bb30
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/Transforms.cs
uploadId: 866910
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a29cd7621a70a044bb205cc8cfd96b3c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,242 @@
using System;
using UnityEngine;
namespace GameKit.Dependencies.Utilities
{
/// <summary>
/// Unity 2022 has a bug where codegen will not compile when referencing a Queue type,
/// while also targeting .Net as the framework API.
/// As a work around this class is used for queues instead.
/// </summary>
public class BasicQueue<T>
{
/// <summary>
/// Maximum size of the collection.
/// </summary>
public int Capacity => Collection.Length;
/// <summary>
/// Number of elements in the queue.
/// </summary>
public int Count => _written;
/// <summary>
/// Collection containing data.
/// </summary>
private T[] Collection = new T[4];
/// <summary>
/// Current write index of the collection.
/// </summary>
public int WriteIndex { get; private set; }
/// <summary>
/// Buffer for resizing.
/// </summary>
private T[] _resizeBuffer = new T[0];
/// <summary>
/// Read position of the next Dequeue.
/// </summary>
private int _read;
/// <summary>
/// Length of the queue.
/// </summary>
private int _written;
/// <summary>
/// Enqueues an entry.
/// </summary>
/// <param name = "data"></param>
public void Enqueue(T data)
{
if (_written == Collection.Length)
Resize();
if (WriteIndex >= Collection.Length)
WriteIndex = 0;
Collection[WriteIndex] = data;
WriteIndex++;
_written++;
}
/// <summary>
/// Tries to dequeue the next entry.
/// </summary>
/// <param name = "result">Dequeued entry.</param>
/// <param name = "defaultArrayEntry">True to set the array entry as default.</param>
/// <returns>True if an entry existed to dequeue.</returns>
public bool TryDequeue(out T result, bool defaultArrayEntry = true)
{
if (_written == 0)
{
result = default;
return false;
}
result = Dequeue(defaultArrayEntry);
return true;
}
/// <summary>
/// Dequeues the next entry.
/// </summary>
/// <param name = "defaultArrayEntry">True to set the array entry as default.</param>
public T Dequeue(bool defaultArrayEntry = true)
{
if (_written == 0)
return default;
T result = Collection[_read];
if (defaultArrayEntry)
Collection[_read] = default;
_written--;
_read++;
if (_read >= Collection.Length)
_read = 0;
return result;
}
/// <summary>
/// Tries to peek the next entry.
/// </summary>
/// <param name = "result">Peeked entry.</param>
/// <returns>True if an entry existed to peek.</returns>
public bool TryPeek(out T result)
{
if (_written == 0)
{
result = default;
return false;
}
result = Peek();
return true;
}
/// <summary>
/// Peeks the next queue entry.
/// </summary>
/// <returns></returns>
public T Peek()
{
if (_written == 0)
throw new($"Queue of type {typeof(T).Name} is empty.");
return Collection[_read];
}
/// <summary>
/// Returns an entry at index or default if index is invalid.
/// </summary>
public T GetIndexOrDefault(int simulatedIndex)
{
int offset = GetRealIndex(simulatedIndex, allowUnusedBuffer: false, log: false);
if (offset != -1 && offset < Collection.Length)
return Collection[offset];
return default;
}
/// <summary>
/// Clears the queue.
/// </summary>
public void Clear()
{
_read = 0;
WriteIndex = 0;
_written = 0;
DefaultCollection(Collection);
DefaultCollection(_resizeBuffer);
void DefaultCollection(T[] array)
{
int count = array.Length;
for (int i = 0; i < count; i++)
array[i] = default;
}
}
/// <summary>
/// Doubles the queue size.
/// </summary>
private void Resize()
{
int length = _written;
int doubleLength = length * 2;
int read = _read;
/* Make sure copy array is the same size as current
* and copy contents into it. */
// Ensure large enough to fit contents.
T[] resizeBuffer = _resizeBuffer;
if (resizeBuffer.Length < doubleLength)
Array.Resize(ref resizeBuffer, doubleLength);
// Copy from the read of queue first.
int copyLength = length - read;
Array.Copy(Collection, read, resizeBuffer, 0, copyLength);
/* If read index was higher than 0
* then copy remaining data as well from 0. */
if (read > 0)
Array.Copy(Collection, 0, resizeBuffer, copyLength, read);
// Set _array to resize.
Collection = resizeBuffer;
// Reset positions.
_read = 0;
WriteIndex = length;
}
/// <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 = GetRealIndex(simulatedIndex);
return Collection[offset];
}
set
{
int offset = GetRealIndex(simulatedIndex);
Collection[offset] = value;
}
}
/// <summary>
/// Returns the real index of the collection using a simulated index.
/// </summary>
/// <param name = "allowUnusedBuffer">True to allow an index be returned from an unused portion of the buffer so long as it is within bounds.</param>
private int GetRealIndex(int simulatedIndex, bool allowUnusedBuffer = false, bool log = true)
{
if (simulatedIndex >= Capacity)
{
return ReturnError();
}
else
{
int written = _written;
// May be out of bounds if allowUnusedBuffer is false.
if (simulatedIndex >= written)
{
if (!allowUnusedBuffer)
return ReturnError();
}
int offset = Capacity - written + simulatedIndex + WriteIndex;
if (offset >= Capacity)
offset -= Capacity;
return offset;
}
int ReturnError()
{
if (log)
Debug.LogError($"Index {simulatedIndex} is out of range. Collection count is {_written}, Capacity is {Capacity}");
return -1;
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f966ec63b499e77438c185b2870595cd
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/Types/BasicQueue.cs
uploadId: 866910
@@ -0,0 +1,45 @@
using UnityEngine;
namespace GameKit.Dependencies.Utilities.Types
{
[System.Serializable]
public struct ByteRange
{
public ByteRange(byte minimum, byte maximum)
{
Minimum = minimum;
Maximum = maximum;
}
/// <summary>
/// Minimum range.
/// </summary>
public byte Minimum;
/// <summary>
/// Maximum range.
/// </summary>
public byte Maximum;
/// <summary>
/// Returns an exclusive random value between Minimum and Maximum.
/// </summary>
/// <returns></returns>
public byte RandomExclusive() => Bytes.RandomExclusiveRange(Minimum, Maximum);
/// <summary>
/// Returns an inclusive random value between Minimum and Maximum.
/// </summary>
/// <returns></returns>
public byte RandomInclusive() => Bytes.RandomInclusiveRange(Minimum, Maximum);
/// <summary>
/// Clamps value between Minimum and Maximum.
/// </summary>
public byte Clamp(byte value) => Bytes.Clamp(value, Minimum, Maximum);
/// <summary>
/// True if value is within range of Minimum and Maximum.
/// </summary>
public bool InRange(byte value) => value >= Minimum && value <= Maximum;
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2756054f52fbd5d4cb1871b0dd6ff5b7
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/Types/ByteRange.cs
uploadId: 866910
@@ -0,0 +1,236 @@
using Sirenix.OdinInspector;
using UnityEngine;
namespace GameKit.Dependencies.Utilities.Types
{
public class CanvasGroupFader : MonoBehaviour
{
#region Types.
/// <summary>
/// Current fade state or goal for this class.
/// </summary>
public enum FadeGoalType
{
Unset = 0,
Hidden = 1,
Visible = 2
}
#endregion
#region Public.
/// <summary>
/// Current goal for the fader.
/// </summary>
public FadeGoalType FadeGoal { get; private set; } = FadeGoalType.Unset;
/// <summary>
/// True if hidden or in the process of hiding.
/// </summary>
public bool IsHiding => FadeGoal == FadeGoalType.Hidden;
/// <summary>
/// True if visible. Will be true long as the CanvasGroup has alpha. Also see IsHiding.
/// </summary>
public bool IsVisible => CanvasGroup.alpha > 0f;
#endregion
#region Serialized.
/// <summary>
/// CanvasGroup to fade in and out.
/// </summary>
[Tooltip("CanvasGroup to fade in and out.")]
[SerializeField]
[TabGroup("Components")]
protected CanvasGroup CanvasGroup;
/// <summary>
/// True to update the CanvasGroup blocking settings when showing and hiding.
/// </summary>
[Tooltip("True to update the CanvasGroup blocking settings when showing and hiding.")]
[SerializeField]
[TabGroup("Effects")]
protected bool UpdateCanvasBlocking = true;
/// <summary>
/// How long it should take to fade in the CanvasGroup.
/// </summary>
[SerializeField]
[TabGroup("Effects")]
protected float FadeInDuration = 0.1f;
/// <summary>
/// How long it should take to fade out the CanvasGroup.
/// </summary>
[SerializeField]
[TabGroup("Effects")]
protected float FadeOutDuration = 0.3f;
#endregion
#region Private.
/// <summary>
/// True if a fade cycle has completed at least once.
/// </summary>
private bool _completedOnce;
#endregion
protected virtual void OnEnable()
{
FadeGoal = CanvasGroup.alpha > 0f ? FadeGoalType.Visible : FadeGoalType.Hidden;
}
protected virtual void OnDisable()
{
if (FadeGoal == FadeGoalType.Visible)
ShowImmediately();
else
HideImmediately();
}
protected virtual void Update()
{
Fade();
}
/// <summary>
/// Shows CanvasGroup immediately.
/// </summary>
public virtual void ShowImmediately()
{
SetFadeGoal(true);
CompleteFade(true);
OnShow();
}
/// <summary>
/// Hides CanvasGroup immediately.
/// </summary>
public virtual void HideImmediately()
{
SetFadeGoal(false);
CompleteFade(false);
OnHide();
}
/// <summary>
/// Shows CanvasGroup with a fade.
/// </summary>
public virtual void Show()
{
if (FadeInDuration <= 0f)
{
ShowImmediately();
}
else
{
SetFadeGoal(true);
OnShow();
}
}
/// <summary>
/// Called after Show or ShowImmediate.
/// </summary>
protected virtual void OnShow() { }
/// <summary>
/// Hides CanvasGroup with a fade.
/// </summary>
public virtual void Hide()
{
if (FadeOutDuration <= 0f)
{
HideImmediately();
}
else
{
// Immediately make unclickable so players cannot hit UI objects as it's fading out.
SetCanvasGroupBlockingType(CanvasGroupBlockingType.Block);
SetFadeGoal(false);
OnHide();
}
}
/// <summary>
/// Called after Hide or HideImmediate.
/// </summary>
protected virtual void OnHide() { }
/// <summary>
/// Sets showing and begins fading if required.
/// </summary>
/// <param name = "fadeIn"></param>
private void SetFadeGoal(bool fadeIn)
{
FadeGoal = fadeIn ? FadeGoalType.Visible : FadeGoalType.Hidden;
}
/// <summary>
/// Fades in or out over time.
/// </summary>
/// <returns></returns>
private void Fade()
{
// Should not be possible.
if (FadeGoal == FadeGoalType.Unset)
{
Debug.LogError($"{gameObject.name} has an unset FadeGoal. This should not be possible.");
return;
}
bool fadingIn = FadeGoal == FadeGoalType.Visible;
float duration;
float targetAlpha;
if (fadingIn)
{
targetAlpha = 1f;
duration = FadeInDuration;
}
else
{
targetAlpha = 0f;
duration = FadeOutDuration;
}
/* Already at goal and had completed an iteration at least once.
* This is checked because even if at alpha we want to
* complete the cycle if not done once so that all
* local states and canvasgroup settings are proper. */
if (_completedOnce && CanvasGroup.alpha == targetAlpha)
return;
float rate = 1f / duration;
CanvasGroup.alpha = Mathf.MoveTowards(CanvasGroup.alpha, targetAlpha, rate * Time.deltaTime);
// If complete.
if (CanvasGroup.alpha == targetAlpha)
CompleteFade(fadingIn);
}
/// <summary>
/// Called when the fade completes.
/// </summary>
protected virtual void CompleteFade(bool fadingIn)
{
CanvasGroupBlockingType blockingType;
float alpha;
if (fadingIn)
{
blockingType = CanvasGroupBlockingType.Block;
alpha = 1f;
}
else
{
blockingType = CanvasGroupBlockingType.DoNotBlock;
alpha = 0f;
}
SetCanvasGroupBlockingType(blockingType);
CanvasGroup.alpha = alpha;
_completedOnce = true;
}
/// <summary>
/// Changes the CanvasGroups interactable and bloacking state.
/// </summary>
protected virtual void SetCanvasGroupBlockingType(CanvasGroupBlockingType blockingType)
{
if (UpdateCanvasBlocking)
CanvasGroup.SetBlockingType(blockingType);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6aa7bd78c33474948b74e3c7a1d97454
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/Types/CanvasGroupFader.cs
uploadId: 866910
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f04cb37e5f34ee749b8be696cb9c6ba3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,58 @@
namespace GameKit.Dependencies.Utilities.Types.CanvasContainers
{
public class ButtonData : IResettable
{
#region Public.
/// <summary>
/// Text to place on the button.
/// </summary>
public string Text { get; protected set; } = string.Empty;
/// <summary>
/// When not null this will be called when action is taken.
/// </summary>
/// <param name = "key">Optional key to associate with callback.</param>
public delegate void PressedDelegate(string key);
/// <summary>
/// Optional key to include within the callback.
/// </summary>
public string Key { get; protected set; } = string.Empty;
#endregion
/// <summary>
/// Delegate to invoke when pressed.
/// </summary>
private PressedDelegate _delegate = null;
/// <summary>
/// Initializes this for use.
/// </summary>
/// <param name = "text">Text to display on the button.</param>
/// <param name = "callback">Callback when OnPressed is called.</param>
/// <param name = "key">Optional key to include within the callback.</param>
public void Initialize(string text, PressedDelegate callback, string key = "")
{
Text = text;
Key = key;
_delegate = callback;
}
/// <summary>
/// Called whewn the button for this data is pressed.
/// </summary>
public virtual void OnPressed()
{
_delegate?.Invoke(Key);
}
public virtual void ResetState()
{
Text = string.Empty;
_delegate = null;
Key = string.Empty;
}
public void InitializeState() { }
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 1baacd2a6a8a0e94b897c6b7176c7000
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/Types/Canvases/ButtonData.cs
uploadId: 866910
@@ -0,0 +1,120 @@
using System.Collections.Generic;
namespace GameKit.Dependencies.Utilities.Types
{
/// <summary>
/// Used to track generic canvases and their states.
/// </summary>
public static class CanvasTracker
{
/// <summary>
/// Canvases which should block input.
/// </summary>
public static IReadOnlyList<object> InputBlockingCanvases => _inputBlockingCanvases;
private static List<object> _inputBlockingCanvases = new();
/// <summary>
/// Canvases which are currently open, in the order they were opened.
/// </summary>
public static IReadOnlyList<object> OpenCanvases => _openCanvases;
private static List<object> _openCanvases = new();
/// <summary>
/// True if any blocking canvas is open.
/// </summary>
public static bool IsInputBlockingCanvasOpen => _inputBlockingCanvases.Count > 0;
/// <summary>
/// Returns true if is the last canvas opened or if no canvases are set as opened.
/// </summary>
public static bool IsLastOpenCanvas(object canvas) => IsEmptyCollectionOrLastEntry(canvas, _openCanvases);
/// <summary>
/// Returns true if is the last canvas blocking input or if no input blocking canvases are set as opened.
/// </summary>
public static bool IsLastInputBlockingCanvas(object canvas) => IsEmptyCollectionOrLastEntry(canvas, _inputBlockingCanvases);
/// <summary>
/// Returns true if canvas is the last object in collection or collection is empty.
/// </summary>
/// <returns></returns>
private static bool IsEmptyCollectionOrLastEntry(object canvas, List<object> collection)
{
int count = collection.Count;
if (count == 0)
return true;
return collection[count - 1] == canvas;
}
/// <summary>
/// Clears all collections.
/// </summary>
public static void ClearCollections()
{
_openCanvases.Clear();
_inputBlockingCanvases.Clear();
}
/// <summary>
/// Removes null references of canvases.
/// This can be used as clean-up if you were unable to remove a canvas properly.
/// Using this method regularly could be expensive if there are hundreds of open canvases.
/// </summary>
public static void RemoveNullReferences()
{
RemoveNullEntries(_openCanvases);
RemoveNullEntries(_inputBlockingCanvases);
void RemoveNullEntries(List<object> collection)
{
for (int i = 0; i < collection.Count; i++)
{
if (collection[i] == null)
{
collection.RemoveAt(i);
i--;
}
}
}
}
/// <summary>
/// Returns true if canvas is an open canvas.
/// </summary>
public static bool IsOpenCanvas(object canvas)
{
return _openCanvases.Contains(canvas);
}
/// <summary>
/// Returns if the canvas is an input blocking canvas.
/// </summary>
public static bool IsInputBlockingCanvas(object canvas)
{
return _inputBlockingCanvases.Contains(canvas);
}
/// <summary>
/// Adds a canvas to OpenCanvases if not already added.
/// </summary>
/// <param name = "addToBlocking">True to also add as an input blocking canvas.</param>
/// <returns>True if the canvas was added, false if already added.</returns>
public static bool AddOpenCanvas(object canvas, bool addToBlocking)
{
bool added = _openCanvases.AddUnique(canvas);
if (added && addToBlocking)
_inputBlockingCanvases.Add(canvas);
return added;
}
/// <summary>
/// Removes a canvas from OpenCanvases.
/// </summary>
/// <returns>True if the canvas was removed, false if it was not added.</returns>
public static bool RemoveOpenCanvas(object canvas)
{
_inputBlockingCanvases.Remove(canvas);
return _openCanvases.Remove(canvas);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: bd8ee85ef5b290246b270cefc7f018ca
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/Types/Canvases/CanvasTracker.cs
uploadId: 866910
@@ -0,0 +1,233 @@
using GameKit.Dependencies;
using System.Runtime.CompilerServices;
using Sirenix.OdinInspector;
using UnityEngine;
namespace GameKit.Dependencies.Utilities.Types.CanvasContainers
{
public class FloatingContainer : CanvasGroupFader
{
#region Serialized.
/// <summary>
/// RectTransform to move.
/// </summary>
[Tooltip("RectTransform to move.")]
[SerializeField]
[TabGroup("Components")]
protected RectTransform RectTransform;
/// <summary>
/// True to use edge avoidance.
/// </summary>
[Tooltip("True to use edge avoidance.")]
[SerializeField]
[TabGroup("Sizing")]
protected bool UseEdgeAvoidance = true;
/// <summary>
/// How much to avoid screen edges when being moved.
/// </summary>
[Tooltip("How much to avoid screen edges when being moved.")]
[SerializeField]
[TabGroup("Sizing")]
[ShowIf(nameof(UseEdgeAvoidance), true)]
protected Vector2 EdgeAvoidance;
#endregion
#region Private.
/// <summary>
/// Desired position.
/// </summary>
private Vector3 _positionGoal;
/// <summary>
/// Desired rotation.
/// </summary>
private Quaternion _rotationGoal;
/// <summary>
/// Desired scale.
/// </summary>
private Vector3 _scaleGoal = Vector3.one;
/// <summary>
/// How much edge avoidance to use.
/// </summary>
private Vector2? _edgeAvoidance;
#endregion
/// <summary>
/// Attachs a gameObject as a child of this object and sets transform valus to default.
/// </summary>
/// <param name = "go">GameObject to attach.</param>
public void AttachGameObject(GameObject go)
{
if (go == null)
return;
Transform goT = go.transform;
goT.SetParent(transform);
goT.localPosition = Vector3.zero;
goT.localRotation = Quaternion.identity;
goT.localScale = Vector3.one;
}
/// <summary>
/// Shows the container.
/// </summary>
/// <param name = "position">Position to use.</param>
/// <param name = "rotation">Rotation to use.</param>
/// <param name = "scale">Scale to use.</param>
/// <param name = "pivot">Pivot for rectTransform.</param>
/// <param name = "edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
public virtual void Show(Vector3 position, Quaternion rotation, Vector3 scale, Vector2 pivot, Vector2? edgeAvoidanceOverride = null)
{
UpdateEdgeAvoidance(edgeAvoidanceOverride, false);
UpdatePivot(pivot, false);
UpdatePositionRotationAndScale(position, rotation, scale);
base.Show();
}
/// <summary>
/// Shows the container.
/// </summary>
/// <param name = "position">Position to use.</param>
/// <param name = "edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void Show(Vector3 position, Vector2? edgeAvoidanceOverride = null)
{
Show(position, Quaternion.identity, Vector3.one, RectTransform.pivot);
}
/// <summary>
/// Shows the container.
/// </summary>
/// <param name = "position">Position to use.</param>
/// <param name = "rotation">Rotation to use.</param>
/// <param name = "edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void Show(Vector3 position, Quaternion rotation, Vector2? edgeAvoidanceOverride = null)
{
Show(position, rotation, Vector3.one, RectTransform.pivot);
}
/// <summary>
/// Shows the container.
/// </summary>
/// <param name = "startingPoint">Transform to use for position, rotation, and scale.</param>
/// <param name = "edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void Show(Transform startingPoint, Vector2? edgeAvoidanceOverride = null)
{
if (startingPoint == null)
{
Debug.LogError($"A null Transform cannot be used as the starting point.");
return;
}
Show(startingPoint.position, startingPoint.rotation, startingPoint.localScale, RectTransform.pivot);
}
/// <summary>
/// Updates the rectTransform pivot.
/// </summary>
/// <param name = "pivot">New pivot.</param>
/// <param name = "move">True to move the RectTransform after updating.</param>
public virtual void UpdatePivot(Vector2 pivot, bool move = true)
{
RectTransform.pivot = pivot;
if (move)
Move();
}
/// <summary>
/// Updates to a new position.
/// </summary>
/// <param name = "position">Next position.</param>
/// <param name = "move">True to move towards new position.</param>
public virtual void UpdatePosition(Vector3 position, bool move = true)
{
_positionGoal = position;
if (move)
Move();
}
/// <summary>
/// Updates to a new rotation.
/// </summary>
/// <param name = "rotation">Next rotation.</param>
public virtual void UpdateRotation(Quaternion rotation, bool move = true)
{
_rotationGoal = rotation;
if (move)
Move();
}
/// <summary>
/// Updates to a new scale.
/// </summary>
/// <param name = "scale">Next scale.</param>
/// <param name = "move">True to move the RectTransform after updating.</param>
public virtual void UpdateScale(Vector3 scale, bool move = true)
{
_scaleGoal = scale;
if (move)
Move();
}
/// <summary>
/// Updates to a new position and rotation.
/// </summary>
/// <param name = "position">Next position.</param>
/// <param name = "rotation">Next rotation.</param>
/// <param name = "move">True to move the RectTransform after updating.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void UpdatePositionAndRotation(Vector3 position, Quaternion rotation, bool move = true)
{
UpdatePosition(position, false);
UpdateRotation(rotation, false);
if (move)
Move();
}
/// <summary>
/// Updates to a new position, rotation, and scale.
/// </summary>
/// <param name = "position">Next position.</param>
/// <param name = "rotation">Next rotation.</param>
/// <param name = "scale">Next scale.</param>
/// <param name = "move">True to move the RectTransform after updating.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void UpdatePositionRotationAndScale(Vector3 position, Quaternion rotation, Vector3 scale, bool move = true)
{
UpdatePositionAndRotation(position, rotation, false);
UpdateScale(scale, false);
Move();
}
/// <summary>
/// Updates how much edge avoidance to use. When null serialized values are used.
/// </summary>
/// <param name = "edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
/// <param name = "move">True to move the RectTransform after updating.</param>
public virtual void UpdateEdgeAvoidance(Vector2? edgeAvoidanceOverride = null, bool move = true)
{
_edgeAvoidance = edgeAvoidanceOverride.HasValue ? edgeAvoidanceOverride.Value : EdgeAvoidance;
if (move)
Move();
}
/// <summary>
/// Moves to configured goals.
/// </summary>
protected virtual void Move()
{
// Update scale first so edge avoidance takes it into consideration.
RectTransform.localScale = _scaleGoal;
Vector2 position = _positionGoal;
if (UseEdgeAvoidance)
{
Vector2 avoidance = _edgeAvoidance.HasValue ? _edgeAvoidance.Value : EdgeAvoidance;
position = RectTransform.GetOnScreenPosition(_positionGoal, avoidance);
}
RectTransform.SetPositionAndRotation(position, _rotationGoal);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f1fcd998728ace94ea809c34ad0d09e8
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/Types/Canvases/FloatingContainer.cs
uploadId: 866910
@@ -0,0 +1,30 @@
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.UI;
namespace GameKit.Dependencies.Utilities.Types.CanvasContainers
{
public class FloatingImage : FloatingContainer
{
/// <summary>
/// Renderer to apply sprite on.
/// </summary>
[Tooltip("Renderer to apply sprite on.")]
[SerializeField]
[TabGroup("Components")]
protected Image Renderer;
/// <summary>
/// Sets which sprite to use.
/// </summary>
/// <param name = "sprite">Sprite to use.</param>
/// <param name = "sizeOverride">When has value the renderer will be set to this size. Otherwise, the size of the sprite will be used. This value assumes the sprite anchors are set to center.</param>
public virtual void SetSprite(Sprite sprite, Vector3? sizeOverride)
{
Renderer.sprite = sprite;
Vector3 size = sizeOverride == null ? sprite.bounds.size * sprite.pixelsPerUnit : sizeOverride.Value;
Renderer.rectTransform.sizeDelta = size;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2169e34ec7dd63a4e99b5cc89fd0e966
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/Types/Canvases/FloatingImage.cs
uploadId: 866910
@@ -0,0 +1,38 @@
using GameKit.Dependencies.Utilities.Types.CanvasContainers;
using System.Collections.Generic;
namespace GameKit.Dependencies.Utilities.Types.OptionMenuButtons
{
public class FloatingOptions : CanvasGroupFader
{
#region Protected.
/// <summary>
/// Current buttons.
/// </summary>
protected List<ButtonData> Buttons = new();
#endregion
/// <summary>
/// Adds buttons.
/// </summary>
/// <param name = "clearExisting">True to clear existing buttons first.</param>
/// <param name = "buttonDatas">Buttons to add.</param>
protected virtual void AddButtons(bool clearExisting, IEnumerable<ButtonData> buttonDatas)
{
if (clearExisting)
RemoveButtons();
foreach (ButtonData item in buttonDatas)
Buttons.Add(item);
}
/// <summary>
/// Removes all buttons.
/// </summary>
protected virtual void RemoveButtons()
{
foreach (ButtonData item in Buttons)
ResettableObjectCaches<ButtonData>.Store(item);
Buttons.Clear();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: cbc5b08db621303449f60b59f56eac92
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/Types/Canvases/FloatingOptions.cs
uploadId: 866910
@@ -0,0 +1,34 @@
using System;
using UnityEngine;
namespace GameKit.Dependencies.Utilities.Types.CanvasContainers
{
public class ImageButtonData : ButtonData
{
#region Public.
/// <summary>
/// Image to display.
/// </summary>
public Sprite DisplayImage { get; protected set; } = null;
#endregion
/// <summary>
/// Initializes this for use.
/// </summary>
/// <param name = "sprite">Image to use on the button.</param>
/// <param name = "text">Text to display on the button.</param>
/// <param name = "callback">Callback when OnPressed is called.</param>
/// <param name = "key">Optional key to include within the callback.</param>
public void Initialize(Sprite sprite, string text, PressedDelegate callback, string key = "")
{
base.Initialize(text, callback, key);
DisplayImage = sprite;
}
public override void ResetState()
{
base.ResetState();
DisplayImage = null;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d60e355b6d09be14487df1ed91e901b2
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/Types/Canvases/ImageButtonData.cs
uploadId: 866910
@@ -0,0 +1,26 @@
#if TEXTMESHPRO
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace GameKit.Dependencies.Utilities.Types.CanvasContainers
{
public class OptionMenuImageButton : OptionMenuButton
{
#region Serialized.
/// <summary>
/// Image component to show image on.
/// </summary>
[Tooltip("Image component to show image on.")]
[SerializeField]
private Image _image;
#endregion
public virtual void Initialize(ImageButtonData buttonData)
{
base.Initialize(buttonData);
_image.sprite = buttonData.DisplayImage;
}
}
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2fee1d5cad375e84eaab6a4cd1d6e915
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/Types/Canvases/ImageOptionButton.cs
uploadId: 866910
@@ -0,0 +1,32 @@
#if TEXTMESHPRO
using TMPro;
using UnityEngine;
namespace GameKit.Dependencies.Utilities.Types.CanvasContainers
{
public class OptionMenuButton : MonoBehaviour
{
#region Public.
/// <summary>
/// ButtonData for this button.
/// </summary>
public ButtonData ButtonData { get; protected set; }
#endregion
#region Serialized.
/// <summary>
/// Text component to show button text.
/// </summary>
[Tooltip("Text component to show button text.")]
[SerializeField]
private TextMeshProUGUI _text;
#endregion
public virtual void Initialize(ButtonData buttonData)
{
ButtonData = buttonData;
_text.text = buttonData.Text;
}
}
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 22d4118a529704b49858d02b956dc48d
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/Types/Canvases/OptionButton.cs
uploadId: 866910
@@ -0,0 +1,107 @@
using System.Collections.Generic;
using UnityEngine;
namespace GameKit.Dependencies.Utilities.Types
{
/// <summary>
/// Gameplay canvases register to this manager.
/// </summary>
public class RectTransformResizer : MonoBehaviour
{
#region Types.
public class ResizeData : IResettable
{
public byte Remaining;
public ResizeDelegate Delegate;
public ResizeData()
{
Remaining = 2;
}
public void InitializeState() { }
public void ResetState()
{
Remaining = 2;
Delegate = null;
}
}
#endregion
#region Public.
/// <summary>
/// Delegate for resizing RectTransforms.
/// </summary>
/// <param name = "complete">True if the resize iterations are complete. Typically show your visuals when true.</param>
public delegate void ResizeDelegate(bool complete);
#endregion
#region Private.
/// <summary>
/// Elements to resize.
/// </summary>
private List<ResizeData> _resizeDatas = new();
/// <summary>
/// Singleton instance of this class.
/// </summary>
private static RectTransformResizer _instance;
#endregion
private void OnDestroy()
{
foreach (ResizeData item in _resizeDatas)
ResettableObjectCaches<ResizeData>.Store(item);
}
private void Update()
{
Resize();
}
/// <summary>
/// Calls pending resizeDatas.
/// </summary>
private void Resize()
{
for (int i = 0; i < _resizeDatas.Count; i++)
{
_resizeDatas[i].Remaining--;
bool complete = _resizeDatas[i].Remaining == 0;
_resizeDatas[i].Delegate?.Invoke(complete);
if (complete)
{
ResettableObjectCaches<ResizeData>.Store(_resizeDatas[i]);
_resizeDatas.RemoveAt(i);
i--;
}
}
}
/// <summary>
/// Used to call a delegate twice, over two frames.
/// This is an easy way to resize RectTransforms multiple times as they will often fail after the first resize due to Unity limitations.
/// Note: this work-around may not be required for newer Unity versions.
/// </summary>
/// <param name = "del">Delegate to invoke when resizing completes.</param>
public static void Resize(ResizeDelegate del)
{
// Check to make a singleton instance.
if (_instance == null)
{
GameObject go = new(typeof(RectTransformResizer).Name);
_instance = go.AddComponent<RectTransformResizer>();
DontDestroyOnLoad(go);
}
_instance.Resize_Internal(del);
}
private void Resize_Internal(ResizeDelegate del)
{
ResizeData rd = ResettableObjectCaches<ResizeData>.Retrieve();
rd.Delegate = del;
_instance._resizeDatas.Add(rd);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c4b4655d59b39584faed638f43d4d287
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/Types/Canvases/RectTransformResizer.cs
uploadId: 866910
@@ -0,0 +1,48 @@
using System.Runtime.CompilerServices;
using UnityEngine;
namespace GameKit.Dependencies.Utilities.Types.CanvasContainers
{
public class ResizableContainer : FloatingContainer
{
#region Serialized.
/// <summary>
/// Minimum and maximum range for widwth and height of the RectTransform.
/// </summary>
[Tooltip("Minimum and maximum range for width and height of the RectTransform.")]
// [Foldout("Sizing")]
public FloatRange2D SizeLimits = new()
{
X = new(0f, 999999f),
Y = new(0f, 999999f)
};
#endregion
/// <summary>
/// Sets a size, and resizes if needed.
/// Other transform values must be set separately using inherited methods.
/// </summary>
/// <param name = "size">New size to use.</param>
/// <param name = "ignoreSizeLimits">True to ignore serialized Size limits.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetSizeAndShow(Vector2 size, bool ignoreSizeLimits = false)
{
ResizeAndShow(size, ignoreSizeLimits);
}
/// <summary>
/// Resizes this canvas.
/// </summary>
protected virtual void ResizeAndShow(Vector2 desiredSize, bool ignoreSizeLimits)
{
float widthRequired = desiredSize.x;
float heightRequired = desiredSize.y;
// Clamp width and height.
widthRequired = Mathf.Clamp(widthRequired, SizeLimits.X.Minimum, SizeLimits.X.Maximum);
heightRequired = Mathf.Clamp(heightRequired, SizeLimits.Y.Minimum, SizeLimits.Y.Maximum);
RectTransform.sizeDelta = new(widthRequired, heightRequired);
base.Move();
base.Show();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 5764e627642cf5643a3f4518d450840e
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/Types/Canvases/ResizableContainer.cs
uploadId: 866910
@@ -0,0 +1,37 @@
using System;
using UnityEngine;
namespace GameKit.Dependencies.Utilities.Types
{
public class DDOL : MonoBehaviour
{
#region Public.
/// <summary>
/// Created instance of DDOL.
/// </summary>
private static DDOL _instance;
#endregion
/// <summary>
/// Returns the current DDOL or creates one if not yet created.
/// </summary>
public static DDOL GetDDOL()
{
// Not yet made.
if (_instance == null)
{
GameObject obj = new();
obj.name = "FirstGearGames DDOL";
DDOL ddol = obj.AddComponent<DDOL>();
DontDestroyOnLoad(ddol);
_instance = ddol;
return ddol;
}
// Already made.
else
{
return _instance;
}
}
}
}
@@ -0,0 +1,20 @@
fileFormatVersion: 2
guid: 4e0b25628cfd4f241a22a7c0ee2b932f
timeCreated: 1528404670
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/Types/DDOL.cs
uploadId: 866910
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a4e1653f734aa924a947707391413c6c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,51 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
namespace GameKit.Dependencies.Utilities.Types.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,18 @@
fileFormatVersion: 2
guid: c144891e57ef5054d9b7e03b82c00cf2
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/Types/Editor/SceneDrawer.cs
uploadId: 866910

Some files were not shown because too many files have changed in this diff Show More