diff --git a/Assets/DefaultNetworkPrefabs.asset b/Assets/DefaultNetworkPrefabs.asset new file mode 100644 index 0000000..219664e --- /dev/null +++ b/Assets/DefaultNetworkPrefabs.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e651dbb3fbac04af2b8f5abf007ddc23, type: 3} + m_Name: DefaultNetworkPrefabs + m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkPrefabsList + IsDefault: 1 + List: [] diff --git a/Assets/DefaultNetworkPrefabs.asset.meta b/Assets/DefaultNetworkPrefabs.asset.meta new file mode 100644 index 0000000..7b50eb8 --- /dev/null +++ b/Assets/DefaultNetworkPrefabs.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8c3b36de7a4eff74487a3afe2f72729e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers.meta new file mode 100644 index 0000000..d94f7a1 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 322fa5a6c7d5b4b4ea6b8ffcf999a9c7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Analyzers.dll b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Analyzers.dll new file mode 100644 index 0000000..defea45 Binary files /dev/null and b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Analyzers.dll differ diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Analyzers.dll.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Analyzers.dll.meta new file mode 100644 index 0000000..4c4aeba --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Analyzers.dll.meta @@ -0,0 +1,50 @@ +fileFormatVersion: 2 +guid: 53e4c6b0280fc234ab9d1ff619872df9 +labels: +- RoslynAnalyzer +PluginImporter: + externalObjects: {} + serializedVersion: 3 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + Any: + enabled: 0 + settings: + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + Linux64: + enabled: 0 + settings: + CPU: None + OSXUniversal: + enabled: 0 + settings: + CPU: None + Win: + enabled: 0 + settings: + CPU: None + Win64: + enabled: 0 + settings: + CPU: None + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Generators.dll b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Generators.dll new file mode 100644 index 0000000..397d25e Binary files /dev/null and b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Generators.dll differ diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Generators.dll.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Generators.dll.meta new file mode 100644 index 0000000..914d4c3 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Analyzers/Boxfriend.Generators.dll.meta @@ -0,0 +1,50 @@ +fileFormatVersion: 2 +guid: 8102ec9fad25fcd4991c82074c987947 +labels: +- RoslynAnalyzer +PluginImporter: + externalObjects: {} + serializedVersion: 3 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + Any: + enabled: 0 + settings: + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + Linux64: + enabled: 0 + settings: + CPU: None + OSXUniversal: + enabled: 0 + settings: + CPU: None + Win: + enabled: 0 + settings: + CPU: None + Win64: + enabled: 0 + settings: + CPU: None + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Editor.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Editor.meta new file mode 100644 index 0000000..8346981 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1ed2c7f5ecdfb474598a777964327dde +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettings.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettings.cs new file mode 100644 index 0000000..44b1588 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettings.cs @@ -0,0 +1,39 @@ +using System.IO; +using UnityEngine; + +public class TALGeneratorSettings : ScriptableObject +{ + public string FilePath; + public string FileName; + public int Seconds = 5; + + private const string SettingsPath = @"ProjectSettings\TALGeneratorSettings.asset"; + private static TALGeneratorSettings _instance; + + public static TALGeneratorSettings GetOrCreate() + { + if (_instance == null) + _instance = CreateInstance(); + + var path = GetPath(); + if (!File.Exists(path)) return _instance; + + var json = File.ReadAllText(path); + JsonUtility.FromJsonOverwrite(json, _instance); + + return _instance; + } + + private static string GetPath() + { + var projectPath = Directory.GetParent(Application.dataPath).FullName; + return Path.Combine(projectPath, SettingsPath); + } + + public void Save() + { + var json = JsonUtility.ToJson(this, true); + var path = GetPath(); + File.WriteAllText(path, json); + } +} \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettings.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettings.cs.meta new file mode 100644 index 0000000..2ec29c8 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b3a04823d2914c21a608882e87dc7d70 +timeCreated: 1742631304 \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettingsProvider.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettingsProvider.cs new file mode 100644 index 0000000..19b04ed --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettingsProvider.cs @@ -0,0 +1,157 @@ +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +public class TALGeneratorSettingsProvider : SettingsProvider +{ + private TALGeneratorSettings _settings; + + public TALGeneratorSettingsProvider(string path, SettingsScope scopes, IEnumerable keywords = null) : base(path, scopes, keywords) { } + + [SettingsProvider] + public static SettingsProvider CreateCustomSettingsProvider() + { + return new TALGeneratorSettingsProvider("Project/Tags and Layers Generator", SettingsScope.Project); + } + + public override void OnActivate(string searchContext, VisualElement rootElement) + { + _settings = TALGeneratorSettings.GetOrCreate(); + + var container = new VisualElement + { + style = + { + paddingTop = 10, + paddingLeft = 10, + paddingRight = 10 + } + }; + + var titleLabel = new Label("Tags And Layers Generator Settings") + { + style = + { + fontSize = 14, + unityFontStyleAndWeight = FontStyle.Bold + } + }; + container.Add(titleLabel); + + var folderPickerRow = new VisualElement + { + style = + { + flexDirection = FlexDirection.Row, + marginBottom = 5 + } + }; + + var folderPathField = new TextField("Selected Path") + { + value = _settings.FilePath, + tooltip = "Select a folder that the generated class will be placed into", + isReadOnly = true, + style = + { + flexGrow = 1 + } + }; + folderPickerRow.Add(folderPathField); + + var button = new Button(() => + { + var path = EditorUtility.OpenFolderPanel("Select a Folder", Application.dataPath, ""); + if (string.IsNullOrWhiteSpace(path) || !IsInAssetFolder(path)) return; + + _settings.FilePath = path; + _settings.Save(); + folderPathField.value = path; + }) + { + text = "Browse", + style = + { + marginLeft = 5 + } + }; + folderPickerRow.Add(button); + + container.Add(folderPickerRow); + + var fileNameRow = new VisualElement + { + style = + { + flexDirection = FlexDirection.Row, + marginBottom = 5 + } + }; + + var fileNameField = new TextField("File Name") + { + value = _settings.FileName, + tooltip = "Select a name for the generated file", + style = { flexGrow = 1 } + }; + fileNameField.RegisterValueChangedCallback(evt => + { + _settings.FileName = evt.newValue; + _settings.Save(); + }); + fileNameRow.Add(fileNameField); + + var csLabel = new Label(".cs") + { + style = { marginRight = 10 } + }; + fileNameRow.Add(csLabel); + container.Add(fileNameRow); + + var buttonRow = new VisualElement() + { + style = + { + flexGrow = 1, + flexDirection = FlexDirection.RowReverse, + justifyContent = new StyleEnum(Justify.SpaceBetween), + marginBottom = 5 + } + }; + var generateButton = new Button(TagAndLayerGenerator.Generate) + { + text = "Manually Generate", + style = + { + flexGrow = 0, + marginRight = 10 + } + }; + buttonRow.Add(generateButton); + var secondsField = new IntegerField("AutoGenerate Threshold") + { + value = _settings.Seconds, + tooltip = "Minimum number of seconds to wait before allowing auto generation again. Minimum of 5 seconds", + style = + { + minWidth = 30 + } + }; + secondsField.RegisterValueChangedCallback(evt => + { + _settings.Seconds = Mathf.Max(evt.newValue, 5); + _settings.Save(); + }); + buttonRow.Add(secondsField); + container.Add(buttonRow); + rootElement.Add(container); + } + + private bool IsInAssetFolder(string path) + { + var fullName = Path.GetFullPath(path); + return fullName.StartsWith(Application.dataPath); + } +} \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettingsProvider.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettingsProvider.cs.meta new file mode 100644 index 0000000..e5d9709 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TALGeneratorSettingsProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 49bd8a9472aa46a3b4b3fa44e65a8599 +timeCreated: 1742631234 \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TagAndLayerGenerator.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TagAndLayerGenerator.cs new file mode 100644 index 0000000..52cf483 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TagAndLayerGenerator.cs @@ -0,0 +1,99 @@ +using System; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEngine; + +[InitializeOnLoad] +public static class TagAndLayerGenerator +{ + private static readonly FileSystemWatcher _fileSystemWatcher; + + static TagAndLayerGenerator() + { + if (_fileSystemWatcher != null) return; + + var projectPath = Directory.GetParent(Application.dataPath).FullName; + var path = Path.Combine(projectPath, "ProjectSettings"); + _fileSystemWatcher = new FileSystemWatcher(path, "TagManager.asset"); + _fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite; + _fileSystemWatcher.Changed += OnChanged; + _fileSystemWatcher.EnableRaisingEvents = true; + + Generate(); + } + +#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + private static void OnChanged(object sender, FileSystemEventArgs e) => OnChanged(); +#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + + private static async Awaitable OnChanged() + { + await Awaitable.MainThreadAsync(); + Generate(); + } + + public static void Generate() + { + var settings = TALGeneratorSettings.GetOrCreate(); + if (string.IsNullOrWhiteSpace(settings.FileName) || string.IsNullOrWhiteSpace(settings.FilePath)) + return; + + var relativeDir = Path.GetRelativePath(Application.dataPath, settings.FilePath); + var path = Path.Combine("Assets", relativeDir, settings.FileName + ".cs"); + if (File.Exists(path)) + { + var lastEdit = File.GetLastWriteTime(path); + var difference = DateTime.Now.Subtract(lastEdit).TotalSeconds; + if (difference < Mathf.Max(settings.Seconds, 5)) + return; + } + AssetDatabase.StartAssetEditing(); + var builder = new StringBuilder(); + builder.AppendLine("namespace Boxfriend.Generated \n{"); + builder.AppendLine(GenerateTags()); + builder.AppendLine(GenerateLayers()); + builder.AppendLine("}"); + File.WriteAllText(path, builder.ToString()); + AssetDatabase.StopAssetEditing(); + AssetDatabase.ImportAsset(path); + } + + private static string GenerateTags() + { + var builder = new StringBuilder(); + builder.AppendLine("public static class Tags \n{"); + var tags = UnityEditorInternal.InternalEditorUtility.tags; + foreach (var tag in tags) + { + builder.AppendLine($"public const string {tag} = \"{tag}\";"); + builder.AppendLine($"public static readonly UnityEngine.TagHandle {tag}Handle = UnityEngine.TagHandle.GetExistingTag({tag});"); + } + builder.AppendLine("}"); + return builder.ToString(); + } + + private static string GenerateLayers() + { + var layerBuilder = new StringBuilder(); + layerBuilder.AppendLine("public static class Layers \n{"); + + var maskBuilder = new StringBuilder(); + maskBuilder.AppendLine("public static class Mask \n{"); + maskBuilder.AppendLine("public const int All = int.MaxValue;\npublic const int None = 0;"); + for (var i = 0; i < 32; i++) + { + var name = LayerMask.LayerToName(i); + if (string.IsNullOrWhiteSpace(name)) + continue; + name = name.Replace(" ", ""); + layerBuilder.AppendLine($"public const string {name} = \"{name}\";"); + maskBuilder.AppendLine($"public const int {name} = 1 << {i};"); + } + + maskBuilder.AppendLine("}"); + layerBuilder.Append(maskBuilder); + layerBuilder.AppendLine("}"); + return layerBuilder.ToString(); + } +} \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TagAndLayerGenerator.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TagAndLayerGenerator.cs.meta new file mode 100644 index 0000000..1a324dc --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Editor/TagAndLayerGenerator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c12eb4948b575804b8eaeac6a32ec517 \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime.meta new file mode 100644 index 0000000..4846baf --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d57bd0548bbaf34ab7a410438a1c879 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions.meta new file mode 100644 index 0000000..679a5f7 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 402f66c64d0efe844a7df49bf86a7b6d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/GameObjectExtensions.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/GameObjectExtensions.cs new file mode 100644 index 0000000..0d57957 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/GameObjectExtensions.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Boxfriend.Extensions +{ + public static class GameObjectExtensions + { + /// + /// Recursively changes game object and its children to specified layer + /// + /// Layer to change all objects to + public static void SetLayerRecursively(this GameObject obj, int layer) + { + obj.layer = layer; + foreach (Transform child in obj.transform) + { + child.gameObject.SetLayerRecursively(layer); + } + } + + /// + /// Returns the first child of the current GameObject that has the specified tag. Does not include itself. + /// + public static GameObject FindChildWithTag(this GameObject obj, string tag) + { + foreach(Transform child in obj.transform) + { + if(child.gameObject == obj) continue; + + if(child.CompareTag(tag)) + return child.gameObject; + } + + return null; + } + + /// + /// Returns an array containing all children of the current GameObject that have the specified tag. Does not include itself. + /// + public static GameObject[] FindChildrenWithTag(this GameObject obj, string tag) + { + var taggedArray = new GameObject[obj.transform.childCount]; + var index = 0; + foreach(Transform child in obj.transform) + { + if(child.CompareTag(tag)) + { + taggedArray[index] = child.gameObject; + index++; + } + } + + if(index == 0) return null; + + Array.Resize(ref taggedArray, index); + return taggedArray; + } + + /// + /// Returns a List containing all children of the current GameObject that have the specified tag. Does not include itself. + /// + public static List FindChildrenWithTagList(this GameObject obj, string tag) + { + var taggedList = new List(); + + foreach(Transform child in obj.transform) + { + if(child.gameObject == obj) continue; + + if(child.CompareTag(tag)) + taggedList.Add(child.gameObject); + } + return taggedList; + } + + + /// + /// Destroys all children of the GameObject not including itself\ + /// + public static void DestroyChildren(this GameObject parent) + { + var children = new Transform[parent.transform.childCount]; + for (var i = 0; i < parent.transform.childCount; i++) + children[i] = parent.transform.GetChild(i); + for (var i = 0; i < children.Length; i++) + GameObject.Destroy(children[i].gameObject); + } + + /// + /// Checks if a GameObject is tagged with any of the strings in the provided collection + /// + public static bool CompareTags(this GameObject go, IEnumerable tags) + { + foreach (var tag in tags) + { + if (go.CompareTag(tag)) + return true; + } + return false; + } + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/GameObjectExtensions.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/GameObjectExtensions.cs.meta new file mode 100644 index 0000000..55218f9 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/GameObjectExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70306add1702cb54c8da10e7385f4afd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/MathExtensions.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/MathExtensions.cs new file mode 100644 index 0000000..2e5667a --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/MathExtensions.cs @@ -0,0 +1,44 @@ +using System.Runtime.CompilerServices; +using UnityEngine; +namespace Boxfriend.Extensions +{ + public static class MathExtensions + { + /// + /// Checks if value is within specified range. + /// + /// Lowest value of the range + /// Largest value of the range + /// True if less than min and greater than max + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InRange(this int value, int min, int max) => (value >= min) && (value <= max); + /// + /// Checks if value is within specified range. + /// + /// Lowest value of the range + /// Largest value of the range + /// True if less than min and greater than max + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InRange(this float value, float min, float max) => (value >= min) && (value <= max); + /// + /// Checks if value is within specified range. + /// + /// Lowest value of the range + /// Largest value of the range + /// True if less than min and greater than max + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InRange(this double value, double min, double max) => (value >= min) && (value <= max); + + public static Vector2 Rotate(this Vector2 vector, float degrees) + { + float sin = Mathf.Sin(degrees * Mathf.Deg2Rad); + float cos = Mathf.Cos(degrees * Mathf.Deg2Rad); + + float tx = vector.x; + float ty = vector.y; + vector.x = (cos * tx) - (sin * ty); + vector.y = (sin * tx) + (cos * ty); + return vector; + } + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/MathExtensions.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/MathExtensions.cs.meta new file mode 100644 index 0000000..4db5d92 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/MathExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 750ee6f30f2644ffa9864f245b532846 +timeCreated: 1640819035 \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/StringExtensions.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/StringExtensions.cs new file mode 100644 index 0000000..fe35d41 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/StringExtensions.cs @@ -0,0 +1,22 @@ +using System.Runtime.CompilerServices; +using UnityEngine; +namespace Boxfriend.Extensions +{ + public static class StringExtensions + { + /// + /// Checks if two strings are the same without case sensitivity. + /// + /// String being compared + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool CaseInsensitveEquals (this string str, string value) => (str.ToLower() == value.ToLower()); + + /// + /// Applies a rich text color to string + /// + /// String to be colored + /// Unity Color applied to all of 'text' + public static string AddColor(this string text, Color col) => $"{text}"; + public static string ColorHexFromUnityColor(this Color unityColor) => $"#{ColorUtility.ToHtmlStringRGBA(unityColor)}"; + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/StringExtensions.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/StringExtensions.cs.meta new file mode 100644 index 0000000..81df0ab --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/StringExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ca16c6205a144610a6da0422c8bfa8c0 +timeCreated: 1640894511 \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/TransformExtensions.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/TransformExtensions.cs new file mode 100644 index 0000000..48bc83c --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/TransformExtensions.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +namespace Boxfriend.Extensions +{ + public static class TransformExtensions + { + public static T GetComponentInInactiveParent(this Transform transform) where T : Component + { + while(transform.parent != null) + { + transform = transform.parent; + if(transform.TryGetComponent(out T comp)) + return comp; + } + return null; + } + + public static void UnparentAll(this Transform transform) + { + foreach(Transform child in transform) + { + child.UnparentAll(); + } + transform.SetParent(null); + } + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/TransformExtensions.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/TransformExtensions.cs.meta new file mode 100644 index 0000000..30b93db --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/TransformExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f29e0d162e8b8054e86ab1bc8b687c8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/Vector2Extensions.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/Vector2Extensions.cs new file mode 100644 index 0000000..d611ea2 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/Vector2Extensions.cs @@ -0,0 +1,11 @@ +using UnityEngine; +namespace Boxfriend.Extensions +{ + public static class Vector2Extensions + { + /// + /// Changes a Vector2 into a Vector3 where the V2 Y axis is represented on the V3 Z axis + /// + public static Vector3 To3D(this Vector2 v2) => new Vector3(v2.x, 0, v2.y); + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/Vector2Extensions.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/Vector2Extensions.cs.meta new file mode 100644 index 0000000..98b9bde --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Extensions/Vector2Extensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a6f23bb55cb64524aca4cf21119a963b +timeCreated: 1641338003 \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils.asmdef b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils.asmdef new file mode 100644 index 0000000..a3c607e --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Utils", + "rootNamespace": "Boxfriend", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils.asmdef.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils.asmdef.meta new file mode 100644 index 0000000..da37ed1 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 753ee3d76e3343644abe0f9a98da4ded +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils.meta new file mode 100644 index 0000000..9e8ec3a --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a3eedd59ab213c4fa2931489a6fe2ac +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/AudioManager.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/AudioManager.cs new file mode 100644 index 0000000..34178b0 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/AudioManager.cs @@ -0,0 +1,92 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.Audio; + +namespace Boxfriend.Utils +{ + public class AudioManager : SingletonBehaviour + { + private ObjectPoolCircular _sources; + + [SerializeField] private AudioMixerGroup _audioMixer; + [SerializeField] private AudioSource _sourcePrefab; + + private const string _inWaitingName = "AudioManager - Ready"; + private void Awake () => _sources = new ObjectPoolCircular(Create, x => x.enabled = true, ReturnSource, DestroySource, 32); + + private AudioSource Create () + { + AudioSource source; + if (_sourcePrefab == null) + { + var go = new GameObject + { + name = _inWaitingName + }; + go.transform.parent = transform; + source = go.AddComponent(); + } else + { + source = Instantiate(_sourcePrefab, Vector3.zero, Quaternion.identity); + } + + source.outputAudioMixerGroup = _audioMixer; + source.enabled = false; + return source; + } + + private AudioSource GetSource (string clipName, Vector3 position) + { + var source = _sources.FromPool(); + source.name = $"AudioManager - Playing: {clipName}"; + source.transform.position = position; + + return source; + } + private void ReturnSource (AudioSource source) + { + source.name = _inWaitingName; + source.clip = null; +#if UNITY_2023_2_OR_NEWER + source.resource = null; +#endif + source.enabled = false; + } + private void DestroySource (AudioSource source) => Destroy(source.gameObject); + + public void PlayOneShot (AudioClip clip, float volume = 1f) => PlayOneShot(clip, Vector3.zero, volume); + public void PlayOneShot (AudioClip clip, Vector3 position, float volume = 1f) + { + var source = GetSource(clip.name, position); + source.PlayOneShot(clip, volume); + StartCoroutine(ReturnWhenDone(source)); + } + +#if !UNITY_2023_2_OR_NEWER + public void Play (AudioClip clip) => Play(clip, Vector3.zero); + public void Play (AudioClip clip, Vector3 position) + { + var source = GetSource(clip.name, position); + source.clip = clip; + source.Play(); + StartCoroutine(ReturnWhenDone(source)); + } +#else + public void Play (AudioResource resource) => Play(resource, Vector3.zero); + public void Play(AudioResource resource, Vector3 position) + { + var source = GetSource(resource.name, position); + source.resource = resource; + source.Play(); + StartCoroutine(ReturnWhenDone(source)); + } +#endif + + private IEnumerator ReturnWhenDone (AudioSource source) + { + yield return new WaitUntil(() => !source.isPlaying); + _sources.ToPool(source); + } + } + +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/AudioManager.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/AudioManager.cs.meta new file mode 100644 index 0000000..918c1be --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/AudioManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83b4266b5af7b0e43bdc7a1b68fc823d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/EventManager.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/EventManager.cs new file mode 100644 index 0000000..1f3d96a --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/EventManager.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; + +namespace Boxfriend.Utils +{ + public class EventManager : Singleton + { + public delegate void Event(object arg, object sender); + + private readonly Dictionary _events = new (); + + public void RegisterEvent(string name) + { + if (_events.ContainsKey(name)) + throw new ArgumentException($"Event {name} already registered"); + + _events.Add(name, null); + } + public void RegisterEvent (string name, Event callback) + { + if (_events.ContainsKey(name)) + throw new ArgumentException($"Event {name} already registered"); + + _events.Add(name, callback); + } + + public void UnregisterEvent(string name) + { + if (!_events.ContainsKey(name)) + throw new ArgumentException($"Event {name} not registered"); + + _events.Remove(name); + } + + public void SubscribeEvent (string name, Event callback) + { + if (!_events.ContainsKey(name)) + throw new ArgumentException($"Event {name} not registered"); + + _events[name] += callback ?? throw new ArgumentNullException($"Event {name} callback is null"); + } + + public void UnsubscribeEvent (string name, Event callback) + { + if (!_events.ContainsKey(name)) + throw new ArgumentException($"Event {name} not registered"); + + _events[name] -= callback ?? throw new ArgumentNullException($"Event {name} callback is null"); + } + + public void InvokeEvent (string name, object arg, object sender) + { + if (!_events.ContainsKey(name)) + throw new ArgumentException($"Event {name} not registered"); + + _events[name]?.Invoke(arg, sender); + } + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/EventManager.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/EventManager.cs.meta new file mode 100644 index 0000000..f9e9464 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/EventManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 11ec534d1045abc468621d74f78bfe8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/InspectorOnlyAttribute.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/InspectorOnlyAttribute.cs new file mode 100644 index 0000000..c9cbcba --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/InspectorOnlyAttribute.cs @@ -0,0 +1,7 @@ +using System; + +/// +/// Indicates a variable should only be assigned to in the inspector. Also allowed are field initializers and assignment in unity's Reset method. +/// Requires Boxfriend.Analyzers to function. +/// +public class InspectorOnlyAttribute : Attribute { } diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/InspectorOnlyAttribute.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/InspectorOnlyAttribute.cs.meta new file mode 100644 index 0000000..86363d4 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/InspectorOnlyAttribute.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0c345dad59be440eadbaa7290ff86835 diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPool.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPool.cs new file mode 100644 index 0000000..03de72d --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPool.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; + +namespace Boxfriend.Utils +{ + /// + /// Pools objects of type T, will create new objects as necessary + /// + public class ObjectPool where T : class + { + private readonly Stack _stack = new (); + private readonly Func _objectCreator; + private readonly Action _returnObjectToPool, _getObjectFromPool, _destroyObject; + private readonly int _maxSize; + + /// + /// Number of objects currently in the pool. + /// + public int Count => _stack.Count; + + /// Creates and returns an object of the specified type. + /// Action called on object when pulled from the pool or created. + /// Action called on object when returned to pool. + /// Action called on object when it is to be destroyed. Can be null + /// Number of objects to immediately add to the pool + /// Maximum number of objects in the pool + /// + /// + public ObjectPool (Func createObject, Action getObjectFromPool, Action returnObjectToPool, Action onDestroyObject = null, int defaultSize = 10, int maxSize = 100) + { + if (maxSize < defaultSize) + throw new ArgumentOutOfRangeException(nameof(maxSize), "maxSize must be greater than or equal to defaultSize"); + + if (defaultSize < 0) + throw new ArgumentOutOfRangeException(nameof(defaultSize), "defaultSize must be greater than or equal to 0"); + + _returnObjectToPool = returnObjectToPool ?? throw new ArgumentNullException(nameof(returnObjectToPool)); + _getObjectFromPool = getObjectFromPool ?? throw new ArgumentNullException(nameof(getObjectFromPool)); + _objectCreator = createObject ?? throw new ArgumentNullException(nameof(createObject)); + _destroyObject = onDestroyObject; + + _maxSize = maxSize; + + for (var i = 0; i < defaultSize; i++) + { + ToPool(_objectCreator()); + } + } + + /// + /// Gets an object from the pool or creates a new one if the pool is empty. Calls on the object + /// + public T FromPool () + { + var poolObject = _stack.Count > 0 ? _stack.Pop() : _objectCreator(); + _getObjectFromPool(poolObject); + return poolObject; + } + + /// + /// Adds an item to the pool and calls on it + /// + /// Item to be added + public void ToPool (T item) + { + if (item == null) throw new ArgumentNullException(nameof(item)); + + _returnObjectToPool(item); + + if(_stack.Count >= _maxSize) + { + _destroyObject?.Invoke(item); + return; + } + + _stack.Push(item); + } + + /// + /// Removes all items from the pool, calling on it if not null. + /// + public void EmptyPool() + { + if(_destroyObject is null) + { + _stack.Clear(); + return; + } + + while(_stack.Count > 0) + { + var obj = _stack.Pop(); + _destroyObject(obj); + } + } + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPool.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPool.cs.meta new file mode 100644 index 0000000..7866862 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d79c194a0d7106f4dae9d2b503bae707 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPoolCircular.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPoolCircular.cs new file mode 100644 index 0000000..5c106cb --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPoolCircular.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Boxfriend.Utils +{ + /// + /// Pools a specific number of objects, will reuse oldest active objects when all objects are in use. + /// + public class ObjectPoolCircular where T : class + { + + private Queue _activeQueue, _inactiveQueue; + private readonly Func _objectCreator; + private readonly Action _returnObjectToPool, _getObjectFromPool, _destroyObject; + private readonly int _size; + + /// + /// Total number of objects in the pool. + /// + public int Count => _size; + + /// + /// Total number of currently active pooled objects + /// + public int ActiveCount => _activeQueue.Count; + + /// + /// Total number of currently inactive pooled objects + /// + public int InactiveCount => _inactiveQueue.Count; + + /// Creates and returns an object of the specified type. + /// Action called on object when pulled from the pool or created. + /// Action called on object when returned to pool. + /// Action called on object when it is to be destroyed. Can be null + /// Total number of objects in the pool + /// Size must be greater than zero + /// + public ObjectPoolCircular (Func createObject, Action getObjectFromPool, Action returnObjectToPool, Action onDestroyObject = null, int size = 100) + { + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), "size must be greater than zero"); + + + _returnObjectToPool = returnObjectToPool ?? throw new ArgumentNullException(nameof(returnObjectToPool)); + _getObjectFromPool = getObjectFromPool ?? throw new ArgumentNullException(nameof(getObjectFromPool)); + _objectCreator = createObject ?? throw new ArgumentNullException(nameof(createObject)); + _destroyObject = onDestroyObject; + + _size = size; + _inactiveQueue = new(size); + _activeQueue = new(size); + for (var i = 0; i < size; i++) + { + var obj = _objectCreator(); + _returnObjectToPool(obj); + _inactiveQueue.Enqueue(obj); + } + } + + /// + /// Gets an object from the pool or reuses the oldest active object if all pooled objects are in use. Calls on the object + /// Will call if reusing an active object. + /// + public T FromPool () + { + if(_inactiveQueue.Count + _activeQueue.Count == 0) + throw new InvalidOperationException("Object pool has been cleared, there is nothing left to get"); + + + T poolObject; + if(_inactiveQueue.Count == 0) + { + poolObject = _activeQueue.Dequeue(); + _returnObjectToPool(poolObject); + } + else + { + poolObject = _inactiveQueue.Dequeue(); + } + + _getObjectFromPool(poolObject); + _activeQueue.Enqueue(poolObject); + return poolObject; + } + + /// + /// Adds an item to the pool and calls on it + /// Generates garbage if item is not the oldest object pulled from the pool + /// + /// Item to be added + public void ToPool (T item) + { + if (item == null) throw new ArgumentNullException(nameof(item)); + + if(_activeQueue.Peek() == item) + _activeQueue.Dequeue(); + else + _activeQueue = new Queue(_activeQueue.Where(x => x != item)); + + _returnObjectToPool(item); + _inactiveQueue.Enqueue(item); + } + + /// + /// Returns all active items to the inactive queue + /// + public void ReturnAllToPool() + { + while(ActiveCount > 0) + { + var obj = _activeQueue.Dequeue(); + _returnObjectToPool(obj); + _inactiveQueue.Enqueue(obj); + } + } + + /// + /// Removes all items from the pool, calling on it if not null. + /// Does not call . + /// + public void EmptyPool() + { + if(_destroyObject is null) + { + _activeQueue.Clear(); + _inactiveQueue.Clear(); + return; + } + + while(_activeQueue.Count > 0) + { + var obj = _activeQueue.Dequeue(); + _destroyObject(obj); + } + + while(_inactiveQueue.Count > 0) + { + var obj = _inactiveQueue.Dequeue(); + _destroyObject(obj); + } + } + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPoolCircular.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPoolCircular.cs.meta new file mode 100644 index 0000000..a557f41 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/ObjectPoolCircular.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9d2a88b19aa9ad4ab0b9adb718f2a0a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/PhysicsCastDebug.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/PhysicsCastDebug.cs new file mode 100644 index 0000000..2295b85 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/PhysicsCastDebug.cs @@ -0,0 +1,81 @@ +using UnityEngine; + +namespace Boxfriend.Utils +{ + + /// + /// Class to draw debug information such as physics2d casts + /// + public static class PhysicsCastDebug + { + /// + /// Casts a Physics2D BoxCast with debug lines drawn + /// + public static RaycastHit2D BoxCast(Vector2 origin, + Vector2 size, + float angle, + Vector2 direction, + float distance = 0, + int layerMask = Physics2D.AllLayers, + float minDepth = -Mathf.Infinity, + float maxDepth = Mathf.Infinity) + { + var hit = Physics2D.BoxCast(origin, size, angle, direction, distance, layerMask, minDepth, maxDepth); + + //Setting up the points to draw the origin box and end box + var points = new Vector2[8]; + var width = size.x * 0.5f; + var height = size.y * 0.5f; + + points[0] = new Vector2(-width, height); //Upper left corner + points[1] = new Vector2(width, height); //Upper right corner + points[2] = new Vector2(width, -height); //Lower right corner + points[3] = new Vector2(-width, -height); //Lower left corner + + //Calculates origin box corners using provided angle and origin point + var q = Quaternion.AngleAxis(angle, new Vector3(0, 0, 1)); + for (var i = 0; i < 4; i++) + { + points[i] = q * points[i]; + points[i] += origin; + } + + //Calculates end points using origin box points and provided distance + var realDistance = direction.normalized * distance; + for (var i = 0; i < 4; i++) + { + points[i + 4] = points[i] + realDistance; + } + + //Draw hit normal if a hit was detected + if (hit) Debug.DrawLine(hit.point, hit.point + hit.normal.normalized*0.2f, Color.yellow); + + //Draw boxes + var color = hit ? Color.green : Color.red; + for (var i = 0; i < 4; i++) + { + var j = i == 3 ? 0 : i + 1; + //Draws origin box using first 4 points + Debug.DrawLine(points[i],points[j], color); + } + + //Exit early if distance is 0, don't need to draw end position or translation if there is no distance + if (distance == 0) return hit; + + //Draws end box using last 4 points + for (var i = 0; i < 4; i++) + { + var j = i == 3 ? 0 : i + 1; + Debug.DrawLine(points[i+4],points[j+4], color); + } + //Shows translation from origin box to end box in grey + for (var i = 0; i < 4; i++) + { + var j = i + 4; + Debug.DrawLine(points[i],points[j], Color.grey); + } + + return hit; + } + } +} \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/PhysicsCastDebug.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/PhysicsCastDebug.cs.meta new file mode 100644 index 0000000..4cc3e1a --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/PhysicsCastDebug.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 749412a4d084e6d43902f628e84d38e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Singleton.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Singleton.cs new file mode 100644 index 0000000..2e419d1 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Singleton.cs @@ -0,0 +1,14 @@ +using System; +namespace Boxfriend.Utils +{ + public abstract class Singleton where T : class, new() + { + public static T Instance => _instance; + private static T _instance; + + private static T InitializeSingleton (T obj = null) => _instance = obj ?? new T(); + + public Singleton():this(null){} + public Singleton (T obj) => InitializeSingleton(obj); + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Singleton.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Singleton.cs.meta new file mode 100644 index 0000000..4b0ae24 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Singleton.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d5aa066b76ef4b48b79d2921c301f50f +timeCreated: 1640819249 \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/SingletonBehaviour.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/SingletonBehaviour.cs new file mode 100644 index 0000000..185e587 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/SingletonBehaviour.cs @@ -0,0 +1,40 @@ +using UnityEngine; + +namespace Boxfriend.Utils +{ + public abstract class SingletonBehaviour : MonoBehaviour where T : SingletonBehaviour + { + private static T _instance; + [SerializeField] protected bool _dontDestroy; + + public static T Instance + { + get + { + if( _instance == null ) + { + var go = new GameObject(typeof(T).Name); + go.AddComponent(); + } + + return _instance; + } + + private set + { + if (_instance == null) + _instance = value; + else if (value != _instance) + Destroy(value.gameObject); + } + } + + protected virtual void __internalAwake () + { + Instance = (T)this; + + if(_dontDestroy) + DontDestroyOnLoad(gameObject); + } + } +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/SingletonBehaviour.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/SingletonBehaviour.cs.meta new file mode 100644 index 0000000..edf337e --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/SingletonBehaviour.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a532c8d866cc4ff1a614091cc5e3c80b +timeCreated: 1640820898 \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/TimerUtil.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/TimerUtil.cs new file mode 100644 index 0000000..be0e3dc --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/TimerUtil.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Boxfriend.Utils +{ + /// + /// Simple timer class that will call an action on timer complete + /// + public class TimerUtil + { + public static TimerUtil Timer (Action action, float time, string name = "TimerObject") + { + GameObject timerObj = new GameObject(name, typeof(TimerMonoBehaviour)); + TimerUtil timerUtil = new TimerUtil(action, time, timerObj); + timerObj.GetComponent().onUpdate = timerUtil.UpdateTimer; + return timerUtil; + } + + private class TimerMonoBehaviour : MonoBehaviour + { + public Action onUpdate; + private void Update () + { + onUpdate(); + } + } + + private Action _act; + private float _time; + private GameObject _timerObj; + + public bool isEnded { get; private set; } + public bool isPaused { get; set; } + public float TimeRemaining => _time; + + private TimerUtil (Action action, float time, GameObject timerObj) + { + _act = action; + _time = time; + _timerObj = timerObj; + + //Ensuring the bools are correctly initialized as false + isEnded = false; + isPaused = false; + } + + private void UpdateTimer () + { + if (isEnded || isPaused) return; + + _time -= Time.deltaTime; + if (_time <= 0) + { + EndWithAction(); + } + } + + /// + /// Ends the timer and destroys associated GameObject. Cannot be undone + /// + public void EndTimer () + { + isEnded = true; + UnityEngine.Object.Destroy(_timerObj); + } + + /// + /// Ends the timer and invokes its action. Cannot be undone. + /// + public void EndWithAction () + { + _act(); + EndTimer(); + } + + /// + /// Adds specified time to the currently active timer + /// + public void AddTime (float time) + { + if (isEnded) return; + + _time += time; + } + + } +} \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/TimerUtil.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/TimerUtil.cs.meta new file mode 100644 index 0000000..966b03f --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/TimerUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f923888d5435594a9fd44c8ba579913 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Utils.cs b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Utils.cs new file mode 100644 index 0000000..28585a6 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Utils.cs @@ -0,0 +1,36 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Boxfriend.Utils +{ + /// + /// Random useful methods + /// + public class Utils + { + /// + /// Determines if the supplied ints have opposite signs + /// + public static bool OppositeSigns (int x, int y) + { + return ((x ^ y) < 0); + } + + /// + /// Formats number of bytes to string + /// + public static string FormatBytes(long bytes) + { + string[] Suffix = {"B", "KB", "MB", "GB", "TB"}; + int i; + double dblSByte = bytes; + for (i = 0; i < Suffix.Length && bytes >= 1000; i++, bytes /= 1000) + { + dblSByte = bytes / 1000.0; + } + + return $"{dblSByte:0.##} {Suffix[i]}"; + } + } +} \ No newline at end of file diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Utils.cs.meta b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Utils.cs.meta new file mode 100644 index 0000000..8751dec --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/Runtime/Utils/Utils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cca214112e1e41a48b15b4b1e145cbd4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/package.json b/Packages/com.boxfriend.utils@58cc9986a36b/package.json new file mode 100644 index 0000000..3514e62 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/package.json @@ -0,0 +1,14 @@ +{ + "name": "com.boxfriend.utils", + "displayName": "Boxfriend's Utils", + "version": "2.0.0", + "unity": "6000.0", + "author": { + "name": "Boxfriend", + "url": "https://github.com/boxfriend" + }, + "publishConfig": { + "registry": "https://package.openupm.com" + }, + "_fingerprint": "58cc9986a36bd339d892e23f0bf8d7d08d69b8e5" +} diff --git a/Packages/com.boxfriend.utils@58cc9986a36b/package.json.meta b/Packages/com.boxfriend.utils@58cc9986a36b/package.json.meta new file mode 100644 index 0000000..e0b0b89 --- /dev/null +++ b/Packages/com.boxfriend.utils@58cc9986a36b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d291b57ec95daa04c81dad42a2f06e7f +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/manifest.json b/Packages/manifest.json index 9e160d6..e6322c9 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,16 +1,24 @@ { "dependencies": { + "com.boxfriend.utils": "2.0.0", + "com.unity.addressables": "2.7.4", "com.unity.ai.navigation": "2.0.9", - "com.unity.collab-proxy": "2.10.0", + "com.unity.behavior": "1.0.13", + "com.unity.cinemachine": "3.1.5", "com.unity.ide.rider": "3.0.38", "com.unity.ide.visualstudio": "2.0.25", "com.unity.inputsystem": "1.15.0", "com.unity.multiplayer.center": "1.0.0", + "com.unity.multiplayer.tools": "2.2.6", + "com.unity.netcode.gameobjects": "2.7.0", + "com.unity.project-auditor-rules": "1.0.1", "com.unity.render-pipelines.universal": "17.4.0", "com.unity.test-framework": "1.6.0", "com.unity.timeline": "1.8.9", "com.unity.ugui": "2.0.0", + "com.unity.visualeffectgraph": "17.4.0", "com.unity.visualscripting": "1.9.9", + "com.vertx.debugging": "3.0.0", "com.unity.modules.accessibility": "1.0.0", "com.unity.modules.adaptiveperformance": "1.0.0", "com.unity.modules.ai": "1.0.0", @@ -45,5 +53,15 @@ "com.unity.modules.vr": "1.0.0", "com.unity.modules.wind": "1.0.0", "com.unity.modules.xr": "1.0.0" - } + }, + "scopedRegistries": [ + { + "name": "OpenUPM", + "url": "https://package.openupm.com", + "scopes": [ + "com.vertx", + "com.boxfriend" + ] + } + ] } diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 11f8593..d32e173 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -1,5 +1,27 @@ { "dependencies": { + "com.boxfriend.utils": { + "version": "file:com.boxfriend.utils@58cc9986a36b", + "depth": 0, + "source": "embedded", + "dependencies": {} + }, + "com.unity.addressables": { + "version": "2.7.4", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.profiling.core": "1.0.2", + "com.unity.test-framework": "1.4.5", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.scriptablebuildpipeline": "2.4.3", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.ai.navigation": { "version": "2.0.9", "depth": 0, @@ -9,9 +31,26 @@ }, "url": "https://packages.unity.com" }, + "com.unity.behavior": { + "version": "1.0.13", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.7.2", + "com.unity.dt.app-ui": "2.0.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.collections": "2.1.4", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.nuget.newtonsoft-json": "3.2.1", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.burst": { "version": "1.8.25", - "depth": 2, + "depth": 1, "source": "registry", "dependencies": { "com.unity.mathematics": "1.2.1", @@ -19,16 +58,19 @@ }, "url": "https://packages.unity.com" }, - "com.unity.collab-proxy": { - "version": "2.10.0", + "com.unity.cinemachine": { + "version": "3.1.5", "depth": 0, "source": "registry", - "dependencies": {}, + "dependencies": { + "com.unity.splines": "2.0.0", + "com.unity.modules.imgui": "1.0.0" + }, "url": "https://packages.unity.com" }, "com.unity.collections": { "version": "6.4.0", - "depth": 2, + "depth": 1, "source": "builtin", "dependencies": { "com.unity.burst": "1.8.23", @@ -38,6 +80,18 @@ "com.unity.test-framework.performance": "3.0.3" } }, + "com.unity.dt.app-ui": { + "version": "2.1.1", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.screencapture": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.ext.nunit": { "version": "2.0.5", "depth": 1, @@ -73,7 +127,7 @@ }, "com.unity.mathematics": { "version": "1.3.3", - "depth": 2, + "depth": 1, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" @@ -86,9 +140,55 @@ "com.unity.modules.uielements": "1.0.0" } }, + "com.unity.multiplayer.tools": { + "version": "2.2.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.8.18", + "com.unity.collections": "2.5.1", + "com.unity.mathematics": "1.3.2", + "com.unity.profiling.core": "1.0.2", + "com.unity.nuget.mono-cecil": "1.11.4", + "com.unity.modules.uielements": "1.0.0", + "com.unity.nuget.newtonsoft-json": "3.2.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.netcode.gameobjects": { + "version": "2.7.0", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.transport": "2.6.0", + "com.unity.nuget.mono-cecil": "1.11.4" + }, + "url": "https://packages.unity.com" + }, "com.unity.nuget.mono-cecil": { "version": "1.11.6", - "depth": 3, + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.nuget.newtonsoft-json": { + "version": "3.2.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.profiling.core": { + "version": "1.0.3", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.project-auditor-rules": { + "version": "1.0.1", + "depth": 0, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" @@ -124,6 +224,16 @@ "com.unity.render-pipelines.core": "17.4.0" } }, + "com.unity.scriptablebuildpipeline": { + "version": "2.4.3", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.4.5", + "com.unity.modules.assetbundle": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.searcher": { "version": "4.9.4", "depth": 2, @@ -131,6 +241,13 @@ "dependencies": {}, "url": "https://packages.unity.com" }, + "com.unity.settings-manager": { + "version": "2.1.1", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, "com.unity.shadergraph": { "version": "17.4.0", "depth": 1, @@ -140,6 +257,17 @@ "com.unity.searcher": "4.9.3" } }, + "com.unity.splines": { + "version": "2.8.2", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.mathematics": "1.2.1", + "com.unity.modules.imgui": "1.0.0", + "com.unity.settings-manager": "1.0.3" + }, + "url": "https://packages.unity.com" + }, "com.unity.test-framework": { "version": "1.6.0", "depth": 0, @@ -152,7 +280,7 @@ }, "com.unity.test-framework.performance": { "version": "3.2.0", - "depth": 3, + "depth": 2, "source": "registry", "dependencies": { "com.unity.test-framework": "1.1.33", @@ -165,13 +293,24 @@ "depth": 0, "source": "registry", "dependencies": { + "com.unity.modules.audio": "1.0.0", "com.unity.modules.director": "1.0.0", "com.unity.modules.animation": "1.0.0", - "com.unity.modules.audio": "1.0.0", "com.unity.modules.particlesystem": "1.0.0" }, "url": "https://packages.unity.com" }, + "com.unity.transport": { + "version": "2.6.0", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.8.24", + "com.unity.collections": "2.2.1", + "com.unity.mathematics": "1.3.2" + }, + "url": "https://packages.unity.com" + }, "com.unity.ugui": { "version": "2.0.0", "depth": 0, @@ -181,6 +320,15 @@ "com.unity.modules.imgui": "1.0.0" } }, + "com.unity.visualeffectgraph": { + "version": "17.4.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.shadergraph": "17.4.0", + "com.unity.render-pipelines.core": "17.4.0" + } + }, "com.unity.visualscripting": { "version": "1.9.9", "depth": 0, @@ -191,6 +339,17 @@ }, "url": "https://packages.unity.com" }, + "com.vertx.debugging": { + "version": "3.0.0", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.collections": "2.1.0-exp.4", + "com.unity.burst": "1.8.8", + "com.unity.mathematics": "1.3.1" + }, + "url": "https://package.openupm.com" + }, "com.unity.modules.accessibility": { "version": "1.0.0", "depth": 0, diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset index eca3dde..2271bac 100644 --- a/ProjectSettings/PackageManagerSettings.asset +++ b/ProjectSettings/PackageManagerSettings.asset @@ -30,7 +30,19 @@ MonoBehaviour: m_Compliance: m_Status: 0 m_Violations: [] - m_UserSelectedRegistryName: + - m_Id: scoped:project:OpenUPM + m_Name: OpenUPM + m_Url: https://package.openupm.com + m_Scopes: + - com.vertx + - com.boxfriend + m_IsDefault: 0 + m_Capabilities: 0 + m_ConfigSource: 4 + m_Compliance: + m_Status: 0 + m_Violations: [] + m_UserSelectedRegistryName: OpenUPM m_UserAddingNewScopedRegistry: 0 m_RegistryInfoDraft: m_Modified: 0 diff --git a/ProjectSettings/ProjectAuditorSettings.asset b/ProjectSettings/ProjectAuditorSettings.asset new file mode 100644 index 0000000..188f91d --- /dev/null +++ b/ProjectSettings/ProjectAuditorSettings.asset @@ -0,0 +1,53 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 53 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: + m_EditorClassIdentifier: UnityEditor.ProjectAuditorModule:Unity.ProjectAuditor.Editor:ProjectAuditorSettings + Rules: + rules: [] + DiagnosticParams: + paramsStack: + - PlatformGroup: + m_String: Unknown + m_SerializedParams: + - Key: StreamingClipThresholdBytes + Value: 218294 + - Key: LongDecompressedClipThresholdBytes + Value: 204800 + - Key: LongCompressedMobileClipThresholdBytes + Value: 204800 + - Key: LoadInBackGroundClipSizeThresholdBytes + Value: 204800 + - Key: TextureStreamingMipmapsSizeLimit + Value: 4000 + - Key: SpriteAtlasEmptySpaceLimit + Value: 50 + - Key: StreamingAssetsFolderSizeLimit + Value: 50 + - PlatformGroup: + m_String: Standalone + m_SerializedParams: + - Key: StreamingClipThresholdBytes + Value: 218294 + - Key: LongDecompressedClipThresholdBytes + Value: 204800 + - Key: LongCompressedMobileClipThresholdBytes + Value: 204800 + - Key: LoadInBackGroundClipSizeThresholdBytes + Value: 204800 + - Key: TextureStreamingMipmapsSizeLimit + Value: 4000 + - Key: SpriteAtlasEmptySpaceLimit + Value: 50 + - Key: StreamingAssetsFolderSizeLimit + Value: 50 + CurrentParamsIndex: 0