├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── LICENSE.meta
├── README.md
├── README.md.meta
├── Runtime.meta
├── Runtime
├── Extensions.meta
├── Extensions
│ ├── ListExtensions.cs
│ ├── ListExtensions.cs.meta
│ ├── MathExtensions.cs
│ ├── MathExtensions.cs.meta
│ ├── ObjectExtensions.cs
│ └── ObjectExtensions.cs.meta
├── Misc.meta
├── Misc
│ ├── ObjectPool.cs
│ ├── ObjectPool.cs.meta
│ ├── Rand.cs
│ ├── Rand.cs.meta
│ ├── Ref.cs
│ ├── Ref.cs.meta
│ ├── SemVer.cs
│ └── SemVer.cs.meta
├── Singleton.meta
├── Singleton
│ ├── AutoMonoSingleton.cs
│ ├── AutoMonoSingleton.cs.meta
│ ├── MonoSingleton.cs
│ ├── MonoSingleton.cs.meta
│ ├── Singleton.Create.cs
│ ├── Singleton.Create.cs.meta
│ ├── Singleton.New.cs
│ └── Singleton.New.cs.meta
├── UnityCommons.Runtime.asmdef
├── UnityCommons.Runtime.asmdef.meta
├── UpdateManager.meta
├── UpdateManager
│ ├── AsyncUpdateEvent.cs
│ ├── AsyncUpdateEvent.cs.meta
│ ├── ParallelAsyncUpdateManager.cs
│ ├── ParallelAsyncUpdateManager.cs.meta
│ ├── SequentialAsyncUpdateManager.cs
│ ├── SequentialAsyncUpdateManager.cs.meta
│ ├── UpdateManager.cs
│ └── UpdateManager.cs.meta
├── Utilities.meta
└── Utilities
│ ├── GridXY.cs
│ ├── GridXY.cs.meta
│ ├── GridXZ.cs
│ ├── GridXZ.cs.meta
│ ├── ListUtilities.cs
│ ├── ListUtilities.cs.meta
│ ├── RangeUtils.cs
│ ├── RangeUtils.cs.meta
│ ├── Run.cs
│ ├── Run.cs.meta
│ ├── UnityUtils.cs
│ └── UnityUtils.cs.meta
├── package.json
└── package.json.meta
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: teodorvecerdi
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.toptal.com/developers/gitignore/api/unity,rider
3 | # Edit at https://www.toptal.com/developers/gitignore?templates=unity,rider
4 |
5 | ### Rider ###
6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
8 |
9 | # User-specific stuff
10 | .idea/**/workspace.xml
11 | .idea/**/tasks.xml
12 | .idea/**/usage.statistics.xml
13 | .idea/**/dictionaries
14 | .idea/**/shelf
15 |
16 | # Generated files
17 | .idea/**/contentModel.xml
18 |
19 | # Sensitive or high-churn files
20 | .idea/**/dataSources/
21 | .idea/**/dataSources.ids
22 | .idea/**/dataSources.local.xml
23 | .idea/**/sqlDataSources.xml
24 | .idea/**/dynamic.xml
25 | .idea/**/uiDesigner.xml
26 | .idea/**/dbnavigator.xml
27 |
28 | # Gradle
29 | .idea/**/gradle.xml
30 | .idea/**/libraries
31 |
32 | # Gradle and Maven with auto-import
33 | # When using Gradle or Maven with auto-import, you should exclude module files,
34 | # since they will be recreated, and may cause churn. Uncomment if using
35 | # auto-import.
36 | # .idea/artifacts
37 | # .idea/compiler.xml
38 | # .idea/jarRepositories.xml
39 | # .idea/modules.xml
40 | # .idea/*.iml
41 | # .idea/modules
42 | # *.iml
43 | # *.ipr
44 |
45 | # CMake
46 | cmake-build-*/
47 |
48 | # Mongo Explorer plugin
49 | .idea/**/mongoSettings.xml
50 |
51 | # File-based project format
52 | *.iws
53 |
54 | # IntelliJ
55 | out/
56 |
57 | # mpeltonen/sbt-idea plugin
58 | .idea_modules/
59 |
60 | # JIRA plugin
61 | atlassian-ide-plugin.xml
62 |
63 | # Cursive Clojure plugin
64 | .idea/replstate.xml
65 |
66 | # Crashlytics plugin (for Android Studio and IntelliJ)
67 | com_crashlytics_export_strings.xml
68 | crashlytics.properties
69 | crashlytics-build.properties
70 | fabric.properties
71 |
72 | # Editor-based Rest Client
73 | .idea/httpRequests
74 |
75 | # Android studio 3.1+ serialized cache file
76 | .idea/caches/build_file_checksums.ser
77 |
78 | ### Unity ###
79 | # This .gitignore file should be placed at the root of your Unity project directory
80 | #
81 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
82 | /[Ll]ibrary/
83 | /[Tt]emp/
84 | /[Oo]bj/
85 | /[Bb]uild/
86 | /[Bb]uilds/
87 | /[Ll]ogs/
88 | /[Uu]ser[Ss]ettings/
89 |
90 | # MemoryCaptures can get excessive in size.
91 | # They also could contain extremely sensitive data
92 | /[Mm]emoryCaptures/
93 |
94 | # Asset meta data should only be ignored when the corresponding asset is also ignored
95 | !/[Aa]ssets/**/*.meta
96 |
97 | # Uncomment this line if you wish to ignore the asset store tools plugin
98 | # /[Aa]ssets/AssetStoreTools*
99 |
100 | # Autogenerated Jetbrains Rider plugin
101 | /[Aa]ssets/Plugins/Editor/JetBrains*
102 |
103 | # Visual Studio cache directory
104 | .vs/
105 |
106 | # Gradle cache directory
107 | .gradle/
108 |
109 | # Autogenerated VS/MD/Consulo solution and project files
110 | ExportedObj/
111 | .consulo/
112 | *.csproj
113 | *.unityproj
114 | *.sln
115 | *.suo
116 | *.tmp
117 | *.user
118 | *.userprefs
119 | *.pidb
120 | *.booproj
121 | *.svd
122 | *.pdb
123 | *.mdb
124 | *.opendb
125 | *.VC.db
126 |
127 | # Unity3D generated meta files
128 | *.pidb.meta
129 | *.pdb.meta
130 | *.mdb.meta
131 |
132 | # Unity3D generated file on crash reports
133 | sysinfo.txt
134 |
135 | # Builds
136 | *.apk
137 | *.unitypackage
138 |
139 | # Crashlytics generated file
140 |
141 | # Autogenerated files
142 | InitTestScene*.unity.meta
143 | InitTestScene*.unity
144 |
145 |
146 | # End of https://www.toptal.com/developers/gitignore/api/unity,rider
147 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Copyright 2022 Teodor Vecerdi
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/LICENSE.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3a99fe99824854142870c2067838487d
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unity Commons
2 |
3 | [](https://github.com/TeodorVecerdi/UnityCommons/stargazers) [](https://github.com/TeodorVecerdi/UnityCommons/releases)
4 |
5 | Library of reusable Unity-related scripts.
6 |
7 | # Installing Unity Commons
8 |
9 | ## 1. as a git submodule (recommended)
10 |
11 | Run the following on the command line in your unity project's folder:
12 |
13 | ```sh
14 | git submodule add https://github.com/TeodorVecerdi/UnityCommons.git Assets/Plugins/UnityCommons
15 | ```
16 |
17 | ## 2. using OpenUPM
18 |
19 | **Requires [OpenUPM-CLI][openupm-cli]**
20 | Run the following on the command line in your unity project's folder:
21 |
22 | ```sh
23 | openupm add dev.vecerdi.unitycommons
24 | ```
25 |
26 | [openupm-cli]: https://openupm.com/docs/getting-started.html#installing-openupm-cli
27 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f4b7c6cbd793b6a4dbcf696b107b79a7
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 597f7c05e3a182c4c9a33d8cca9293fb
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Extensions.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0285a2fbf46d4c07834d67a98d602965
3 | timeCreated: 1608653944
--------------------------------------------------------------------------------
/Runtime/Extensions/ListExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using UnityEngine;
5 |
6 | namespace UnityCommons {
7 | public static partial class Extensions {
8 | #region Misc
9 |
10 | ///
11 | /// Returns the number of items in , or 0 if it is null
12 | ///
13 | public static int CountAllowNull(this IList list) {
14 | if (list != null)
15 | return list.Count;
16 | return 0;
17 | }
18 |
19 | ///
20 | /// Returns true if is empty or null, and false otherwise
21 | ///
22 | public static bool NullOrEmpty(this IList list) {
23 | if (list != null)
24 | return list.Count == 0;
25 | return true;
26 | }
27 |
28 | ///
29 | /// Shuffles
30 | ///
31 | public static void Shuffle(this IList list) {
32 | int count = list.Count;
33 | while (count > 1) {
34 | --count;
35 | int index = Rand.RangeInclusive(0, count);
36 | T obj = list[index];
37 | list[index] = list[count];
38 | list[count] = obj;
39 | }
40 | }
41 |
42 | ///
43 | /// Runs on each element of
44 | ///
45 | public static void ForEach(this IEnumerable enumerable, Action action) {
46 | if (action == null) throw new ArgumentNullException(nameof(action));
47 | if (enumerable == null) throw new ArgumentNullException(nameof(enumerable));
48 |
49 | using (IEnumerator enumerator = enumerable.GetEnumerator()) {
50 | while (enumerator.MoveNext()) {
51 | T current = enumerator.Current;
52 | if (current == null) return;
53 |
54 | action(current);
55 | }
56 | }
57 | }
58 |
59 | ///
60 | /// Joins to and pipes it to an IEnumerable
61 | ///
62 | public static IEnumerable AppendMany(this IEnumerable source, IEnumerable enumerable) {
63 | if (source == null) throw new ArgumentNullException(nameof(source));
64 | if (enumerable == null) throw new ArgumentNullException(nameof(enumerable));
65 |
66 | foreach (T element in source) yield return element;
67 | foreach (T element in enumerable) yield return element;
68 | }
69 |
70 | #endregion
71 |
72 | #region Copy
73 |
74 | ///
75 | /// Returns a deep copy of
76 | ///
77 | public static IList DeepCopyStruct(this IEnumerable source) where T : struct {
78 | List list = new List();
79 | foreach (T item in source) {
80 | T copy = item;
81 | list.Add(copy);
82 | }
83 |
84 | return list;
85 | }
86 |
87 | ///
88 | /// Returns a deep copy of
89 | ///
90 | public static IList DeepCopyStructOrNull(this IEnumerable source) where T : struct {
91 | return source?.DeepCopyStruct();
92 | }
93 |
94 | ///
95 | /// Returns a deep copy of
96 | ///
97 | public static IList DeepCopyCloneable(this IEnumerable source) where T : ICloneable {
98 | return source.Select(item => (T) item.Clone()).ToList();
99 | }
100 |
101 | ///
102 | /// Returns a deep copy of
103 | ///
104 | public static IList DeepCopyCloneableOrNull(this IEnumerable source) where T : ICloneable {
105 | return source?.DeepCopyCloneable();
106 | }
107 |
108 | ///
109 | /// Returns a deep copy of
110 | ///
111 | public static IList ShallowCopy(this IEnumerable source) {
112 | return new List(source);
113 | }
114 |
115 | ///
116 | /// Returns a deep copy of
117 | ///
118 | public static IList ShallowCopyOrNull(this IEnumerable source) {
119 | return source?.ShallowCopy();
120 | }
121 |
122 | #endregion
123 |
124 | #region Duplicates
125 |
126 | ///
127 | /// Removes duplicates from
128 | ///
129 | public static void RemoveDuplicates(this List list) where T : IComparable {
130 | RemoveDuplicates(list, (comparable, comparable1) => comparable.CompareTo(comparable1));
131 | }
132 |
133 | ///
134 | /// Removes duplicates from
135 | ///
136 | public static void RemoveDuplicates(this List list, Comparison comparison) {
137 | if (list.Count <= 1)
138 | return;
139 | for (int index1 = list.Count - 1; index1 >= 0; --index1)
140 | for (int index2 = 0; index2 < index1; ++index2)
141 | if (comparison(list[index1], list[index2]) == 0) {
142 | list.RemoveAt(index1);
143 | break;
144 | }
145 | }
146 |
147 | ///
148 | /// Removes duplicates from
149 | ///
150 | public static void RemoveDuplicates(this IList list) where T : IEquatable {
151 | if (list.Count <= 1) return;
152 | list = list.Distinct().ToList();
153 | }
154 |
155 | #endregion
156 |
157 | #region Printing
158 |
159 | ///
160 | /// Prints each element of with the format of "[a, b, c, d, ...]"
161 | ///
162 | public static void Print(this IEnumerable list, string separator = ", ", string start = "[", string end = "]") {
163 | Debug.Log(list.ToListString());
164 | }
165 |
166 | ///
167 | /// Joins each element of to a string with the format of "[a, b, c, d, ...]"
168 | ///
169 | public static string ToListString(this IEnumerable list, string separator = ", ", string start = "[", string end = "]") {
170 | return start + string.Join(separator, list.Select(item => item.ToString())) + end;
171 | }
172 |
173 | #endregion
174 |
175 | #region Sorting
176 |
177 | ///
178 | /// Returns true if is sorted, false otherwise
179 | ///
180 | public static bool IsSorted(this IList list, Comparison comparison) {
181 | for (int i = 0; i < list.Count - 1; i++) {
182 | if (comparison(list[i], list[i + 1]) > 0) return false;
183 | }
184 |
185 | return true;
186 | }
187 |
188 | ///
189 | /// Returns true if is sorted, false otherwise
190 | ///
191 | public static bool IsSorted(this IList list) where T : IComparable {
192 | return IsSorted(list, (comparable, comparable1) => comparable.CompareTo(comparable1));
193 | }
194 |
195 | ///
196 | /// Returns sorted using a quicksort algorithm
197 | ///
198 | public static List QuickSorted(this List list, Comparison comparison) {
199 | if (list == null) throw new ArgumentNullException(nameof(list));
200 | if (comparison == null) throw new ArgumentNullException(nameof(comparison));
201 |
202 | QuickSort_Impl(list, 0, list.Count - 1, comparison);
203 | return list;
204 | }
205 |
206 | ///
207 | /// Returns sorted using a quicksort algorithm
208 | ///
209 | public static List QuickSorted(this List list) where T : IComparable {
210 | return QuickSorted(list, (comparable, comparable1) => comparable.CompareTo(comparable1));
211 | }
212 |
213 | ///
214 | /// Returns sorted using an insertion sorting algorithm
215 | ///
216 | public static List InsertionSorted(this List list, Comparison comparison) {
217 | if (list == null) throw new ArgumentNullException(nameof(list));
218 | if (comparison == null) throw new ArgumentNullException(nameof(comparison));
219 |
220 | InsertionSort(list, comparison);
221 | return list;
222 | }
223 |
224 | ///
225 | /// Returns sorted using an insertion sorting algorithm
226 | ///
227 | public static List InsertionSorted(this List list) where T : IComparable {
228 | return InsertionSorted(list, (comparable, comparable1) => comparable.CompareTo(comparable1));
229 | }
230 |
231 | ///
232 | /// Sorts using a quicksort algorithm
233 | ///
234 | public static void QuickSort(this IList list, Comparison comparison) {
235 | QuickSort_Impl(list, 0, list.Count - 1, comparison);
236 | }
237 |
238 | ///
239 | /// Sorts using a quicksort algorithm
240 | ///
241 | public static void QuickSort(this IList list) where T : IComparable {
242 | QuickSort_Impl(list, 0, list.Count - 1, (comparable, comparable1) => comparable.CompareTo(comparable1));
243 | }
244 |
245 | ///
246 | /// Sorts using an insertion sorting algorithm
247 | ///
248 | public static void InsertionSort(this IList list, Comparison comparison) {
249 | int count = list.Count;
250 | for (int index1 = 1; index1 < count; ++index1) {
251 | T y = list[index1];
252 | int index2;
253 | for (index2 = index1 - 1; index2 >= 0 && comparison(list[index2], y) > 0; --index2)
254 | list[index2 + 1] = list[index2];
255 | list[index2 + 1] = y;
256 | }
257 | }
258 |
259 | ///
260 | /// Sorts using an insertion sorting algorithm
261 | ///
262 | public static void InsertionSort(this IList list) where T : IComparable {
263 | InsertionSort(list, (comparable, comparable1) => comparable.CompareTo(comparable1));
264 | }
265 |
266 | #endregion
267 |
268 | #region private Utilities
269 |
270 | private static void QuickSort_Impl(this IList list, int startIndex, int endIndex, Comparison comparison) {
271 | while (true) {
272 | if (startIndex >= endIndex) return;
273 |
274 | int partitionIndex = QuickSort_Partition(list, startIndex, endIndex, comparison);
275 |
276 | QuickSort_Impl(list, startIndex, partitionIndex - 1, comparison);
277 | startIndex = partitionIndex + 1;
278 | }
279 | }
280 |
281 | private static int QuickSort_Partition(IList list, int low, int high, Comparison comparison) {
282 | T pivot = list[high];
283 | int lowIndex = low - 1;
284 |
285 | for (int j = low; j < high; j++)
286 | if (comparison(list[j], pivot) <= 0) {
287 | lowIndex++;
288 | T temp = list[lowIndex];
289 | list[lowIndex] = list[j];
290 | list[j] = temp;
291 | }
292 |
293 | T temp1 = list[lowIndex + 1];
294 | list[lowIndex + 1] = list[high];
295 | list[high] = temp1;
296 |
297 | return lowIndex + 1;
298 | }
299 |
300 | #endregion
301 | }
302 | }
--------------------------------------------------------------------------------
/Runtime/Extensions/ListExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 65b6208db80048d4996d71f69d283345
3 | timeCreated: 1608653952
--------------------------------------------------------------------------------
/Runtime/Extensions/MathExtensions.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UnityCommons {
4 | public static partial class Extensions {
5 | #region General Mapping
6 |
7 | ///
8 | /// Maps from the range [, ] to the range [, ].
9 | ///
10 | /// Value to map
11 | /// Minimum source value
12 | /// Maximum source value
13 | /// Minimum target value
14 | /// Maximum target value
15 | /// mapped from range [, ] to range [, ]
16 | public static float Map(this float value, float fromSource, float toSource, float fromTarget, float toTarget) {
17 | return (value - fromSource) / (toSource - fromSource) * (toTarget - fromTarget) + fromTarget;
18 | }
19 |
20 | ///
21 | /// Maps from the range [, ] to the range [, ].
22 | ///
23 | /// Value to map
24 | /// Minimum source value
25 | /// Maximum source value
26 | /// Minimum target value
27 | /// Maximum target value
28 | /// mapped from range [, ] to range [, ]
29 | public static int Map(this int value, int fromSource, int toSource, int fromTarget, int toTarget) {
30 | return (int) (((float)value - fromSource) / (toSource - fromSource) * (toTarget - fromTarget) + fromTarget);
31 | }
32 |
33 | ///
34 | /// Maps from the range [, ] to the range [, ].
35 | ///
36 | /// Value to map
37 | /// Minimum source value
38 | /// Maximum source value
39 | /// Minimum target value
40 | /// Maximum target value
41 | /// mapped from range [, ] to range [, ]
42 | public static UnityEngine.Vector2 Map(this UnityEngine.Vector2 value, float fromSource, float toSource, float fromTarget, float toTarget) {
43 | return new UnityEngine.Vector2(value.x.Map(fromSource, toSource, fromTarget, toTarget),
44 | value.y.Map(fromSource, toSource, fromTarget, toTarget));
45 | }
46 |
47 | ///
48 | /// Maps from the range [, ] to the range [, ].
49 | ///
50 | /// Value to map
51 | /// Minimum source value
52 | /// Maximum source value
53 | /// Minimum target value
54 | /// Maximum target value
55 | /// mapped from range [, ] to range [, ]
56 | public static UnityEngine.Vector3 Map(this UnityEngine.Vector3 value, float fromSource, float toSource, float fromTarget, float toTarget) {
57 | return new UnityEngine.Vector3(value.x.Map(fromSource, toSource, fromTarget, toTarget),
58 | value.y.Map(fromSource, toSource, fromTarget, toTarget),
59 | value.z.Map(fromSource, toSource, fromTarget, toTarget));
60 | }
61 |
62 | #endregion
63 |
64 | #region Extensions
65 |
66 | ///
67 | /// Returns clamped to be in range [0, 1]
68 | ///
69 | /// The value to clamp
70 | /// clamped to the range [0, 1]
71 | public static float Clamped01(this float value) => Clamped(value, 0.0f, 1.0f);
72 |
73 | ///
74 | /// Returns clamped to be in range [0, 1]
75 | ///
76 | /// The value to clamp
77 | /// clamped to the range [0, 1]
78 | public static double Clamped01(this double value) => Clamped(value, 0.0d, 1.0d);
79 |
80 | ///
81 | /// Returns clamped to be in range [0, 1]
82 | ///
83 | /// The value to clamp
84 | /// clamped to the range [0, 1]
85 | public static decimal Clamped01(this decimal value) => Clamped(value, 0.0m, 1.0m);
86 |
87 | ///
88 | /// Returns clamped to be in range [0, 1]
89 | ///
90 | /// The value to clamp
91 | /// clamped to the range [0, 1]
92 | public static int Clamped01(this int value) => value <= 0 ? 0 : 1;
93 |
94 | ///
95 | /// Returns clamped to be in range [(0,0,0), (1,1,1)]
96 | ///
97 | /// The value to clamp
98 | /// clamped to the range [(0,0,0), (1,1,1)]
99 | public static Vector3 Clamped01(this Vector3 value) => value.Clamped(Vector3.zero, Vector3.one);
100 |
101 | ///
102 | /// Returns clamped to be in range [, ]
103 | ///
104 | /// The value to clamp
105 | /// The minimum value
106 | /// The maximum value
107 | /// clamped to the range [, ]
108 | public static Vector3 Clamped(this Vector3 value, Vector3 min, Vector3 max) {
109 | return new Vector3(value.x.Clamped(min.x, max.x),
110 | value.y.Clamped(min.y, max.y),
111 | value.z.Clamped(min.z, max.z));
112 | }
113 |
114 | ///
115 | /// Returns wrapped between the range and .
116 | ///
117 | public static float Wrapped(this float value, float min, float max) {
118 | if (value < min)
119 | return max - (min - value) % (max - min);
120 | return min + (value - min) % (max - min);
121 | }
122 |
123 | ///
124 | /// Returns wrapped between the range and .
125 | ///
126 | public static double Wrapped(this double value, double min, double max) {
127 | if (value < min)
128 | return max - (min - value) % (max - min);
129 | return min + (value - min) % (max - min);
130 | }
131 |
132 | ///
133 | /// Returns wrapped between the range and .
134 | ///
135 | public static decimal Wrapped(this decimal value, decimal min, decimal max) {
136 | if (value < min)
137 | return max - (min - value) % (max - min);
138 | return min + (value - min) % (max - min);
139 | }
140 |
141 | ///
142 | /// Returns wrapped between the range and .
143 | ///
144 | public static int Wrapped(this int value, int min, int max) {
145 | if (value < min)
146 | return max - (min - value) % (max - min);
147 | return min + (value - min) % (max - min);
148 | }
149 |
150 | ///
151 | /// Returns rounded to the nearest multiple of
152 | ///
153 | /// The value to round
154 | /// The number to round to nearest multiple of
155 | /// rounded to the nearest multiple of
156 | public static int RoundedTo(this int value, int n) {
157 | int remainder = value % n;
158 | if (System.Math.Abs(remainder) < n / 2.0) return value - remainder;
159 | if (value > 0) return value + (n - System.Math.Abs(remainder));
160 | return value - (n - System.Math.Abs(remainder));
161 | }
162 |
163 | ///
164 | /// Returns rounded to the nearest multiple of
165 | ///
166 | /// The value to round
167 | /// The number to round to nearest multiple of
168 | /// rounded to the nearest multiple of
169 | public static float RoundedTo(this float value, float n) => UnityEngine.Mathf.Round(value / n) * n;
170 |
171 | ///
172 | /// Returns rounded to the nearest multiple of
173 | ///
174 | /// The value to round
175 | /// The number to round to nearest multiple of
176 | /// rounded to the nearest multiple of
177 | public static double RoundedTo(this double value, double n) => System.Math.Round(value / n, System.MidpointRounding.AwayFromZero) * n;
178 |
179 | ///
180 | /// Returns rounded to the nearest multiple of
181 | ///
182 | /// The value to round
183 | /// The number to round to nearest multiple of
184 | /// rounded to the nearest multiple of
185 | public static decimal RoundedTo(this decimal value, decimal n) => System.Math.Round(value / n, System.MidpointRounding.AwayFromZero) * n;
186 |
187 | #endregion
188 |
189 | #region Generic Extensions
190 |
191 | ///
192 | /// Returns clamped to be in range [, ]
193 | ///
194 | /// The value to clamp
195 | /// The minimum value
196 | /// The maximum value
197 | /// Type that implements IComparable
198 | /// clamped to the range [, ]
199 | public static T Clamped(this T value, T min, T max) where T : System.IComparable {
200 | // swap is min is greater than max
201 | if (min.CompareTo(max) > 0) {
202 | (min, max) = (max, min);
203 | }
204 | return value.CompareTo(min) < 0 ? min : value.CompareTo(max) > 0 ? max : value;
205 | }
206 |
207 | ///
208 | /// Constrains to be at least
209 | ///
210 | /// The value to constrain
211 | /// The minimum value
212 | /// Type that implements IComparable
213 | /// if is less than , and otherwise
214 | public static T MinClamped(this T value, T min) where T : System.IComparable {
215 | return value.CompareTo(min) < 0 ? min : value;
216 | }
217 |
218 | ///
219 | /// Constrains to be at most
220 | ///
221 | /// The value to constrain
222 | /// The maximum value
223 | /// Type that implements IComparable
224 | /// if is greater than , and otherwise
225 | public static T MaxClamped(this T value, T max) where T : System.IComparable {
226 | return value.CompareTo(max) > 0 ? max : value;
227 | }
228 |
229 | ///
230 | /// Returns true
if is between (inclusive) and (inclusive), otherwise false
.
231 | ///
232 | /// The value to compare
233 | /// The minimum value to compare against (inclusive)
234 | /// The maximum value to compare against (inclusive)
235 | /// Type that implements IComparable
236 | /// true if is between (inclusive) and (inclusive), otherwise false
237 | public static bool Between(this T value, T a, T b) where T : System.IComparable => value.CompareTo(a) >= 0 && value.CompareTo(b) <= 0;
238 |
239 | #endregion
240 | }
241 | }
--------------------------------------------------------------------------------
/Runtime/Extensions/MathExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 84376514daf94f97a5dec986ff44b908
3 | timeCreated: 1609418329
--------------------------------------------------------------------------------
/Runtime/Extensions/ObjectExtensions.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UnityCommons {
4 | public static partial class Extensions {
5 | public static void Log(this object value) {
6 | Debug.Log(value);
7 | }
8 |
9 | public static void LogWarning(this object value) {
10 | Debug.LogWarning(value);
11 | }
12 |
13 | public static void LogError(this object value) {
14 | Debug.LogError(value);
15 | }
16 |
17 | public static void Log(this object value, Object context) {
18 | Debug.Log(value, context);
19 | }
20 |
21 | public static void LogWarning(this object value, Object context) {
22 | Debug.LogWarning(value, context);
23 | }
24 |
25 | public static void LogError(this object value, Object context) {
26 | Debug.LogError(value, context);
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/Runtime/Extensions/ObjectExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ff02e37d71ac42cabd311b68ac26e2f1
3 | timeCreated: 1613925449
--------------------------------------------------------------------------------
/Runtime/Misc.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 159d01ccfd4be4f4388fde7c8b28fc85
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Misc/ObjectPool.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 |
4 | namespace UnityCommons {
5 | public abstract class ObjectPool : MonoBehaviour {
6 | [Header("Pool Settings")]
7 | [SerializeField, Tooltip("The number of items initially allocated to the pool.")] private int initialPoolSize = 16;
8 | [SerializeField, Tooltip("Represents the factor by which the pool grows in size. For example, a growth factor of 2.0 means that the pool doubles in size once it runs out of elements")] private float growthFactor = 1.5f;
9 |
10 | private Queue pool;
11 | private int size;
12 | private bool initialized;
13 |
14 | public int PooledCount => pool.Count;
15 | public int ReleasedCount => size - pool.Count;
16 |
17 | private void Awake() {
18 | pool = new Queue();
19 | size = 0;
20 | initialized = false;
21 | }
22 |
23 | ///
24 | /// Returns a new instance of type .
25 | ///
26 | protected abstract T CreatePooled();
27 |
28 | ///
29 | /// Called when an item is requested from the pool.
30 | ///
31 | protected virtual void OnGet(T pooledItem) {
32 | }
33 |
34 | ///
35 | /// Called when an item is returned back to the pool.
36 | ///
37 | protected virtual void OnReturn(T pooledItem) {
38 | }
39 |
40 | ///
41 | /// Gets an item from the pool.
42 | ///
43 | public T Get() {
44 | if (!initialized) {
45 | Allocate(initialPoolSize);
46 | initialized = true;
47 | }
48 |
49 | if (pool.Count == 0) {
50 | Grow();
51 | }
52 |
53 | T pooledItem = pool.Dequeue();
54 | OnGet(pooledItem);
55 | return pooledItem;
56 | }
57 |
58 | ///
59 | /// Returns to the pool.
60 | ///
61 | public void Return(T pooledItem) {
62 | OnReturn(pooledItem);
63 | pool.Enqueue(pooledItem);
64 | }
65 |
66 | private void Allocate(int amount) {
67 | size += amount;
68 | for (int i = 0; i < amount; i++) {
69 | pool.Enqueue(CreatePooled());
70 | }
71 | }
72 |
73 | private void Grow() {
74 | if (growthFactor <= 1.0f) growthFactor = 1.5f;
75 | int newItems = Mathf.CeilToInt(size * growthFactor) - size;
76 | Allocate(newItems);
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/Runtime/Misc/ObjectPool.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d31c6050692f4e27a60d438c901c0b46
3 | timeCreated: 1641815488
--------------------------------------------------------------------------------
/Runtime/Misc/Rand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using UnityEngine;
5 |
6 | namespace UnityCommons {
7 | public static class Rand {
8 | private static readonly RNGProvider provider = new RNGProvider();
9 | private static readonly Stack stateStack = new Stack();
10 | private static uint iterations;
11 | private const float pi = 3.1415926535897932f;
12 | private const float twoPi = 6.2831853071795864f;
13 |
14 | public static int Seed {
15 | set {
16 | if (stateStack.Count == 0)
17 | Debug.LogError("Modifying the initial rand seed. Call PushState() first. The initial rand seed should always be based on the startup time and set only once.");
18 | provider.Seed = (uint) value;
19 | iterations = 0U;
20 | }
21 | }
22 |
23 | ///
24 | /// Returns a random float from 0 to 1 (both inclusive)
25 | ///
26 | public static float Float => provider.GetFloat(iterations++);
27 |
28 | ///
29 | /// Returns a random integer
30 | ///
31 | public static int Int => provider.GetInt(iterations++);
32 |
33 | ///
34 | /// Returns a random long
35 | ///
36 | public static long Long => BitConverter.ToInt64(Bytes(8), 0);
37 |
38 | ///
39 | /// Returns a random bool
40 | ///
41 | public static bool Bool => Float < 0.5;
42 |
43 | ///
44 | /// Returns a random sign. (Either 1 or -1)
45 | ///
46 | public static int Sign => Bool ? 1 : -1;
47 |
48 | private static ulong StateCompressed {
49 | get => provider.Seed | ((ulong) iterations << 32);
50 | set {
51 | provider.Seed = (uint) (value & uint.MaxValue);
52 | iterations = (uint) ((value >> 32) & uint.MaxValue);
53 | }
54 | }
55 |
56 | static Rand() {
57 | provider.Seed = (uint) DateTime.Now.GetHashCode();
58 | }
59 |
60 | #region Lists
61 |
62 | ///
63 | /// Returns a random element from
64 | ///
65 | public static T ListItem(IList list) {
66 | return list[Range(0, list.Count)];
67 | }
68 |
69 | ///
70 | /// Returns a random element from
71 | ///
72 | public static T ReadOnlyListItem(IReadOnlyList readOnlyList) {
73 | return readOnlyList[Range(0, readOnlyList.Count)];
74 | }
75 |
76 | #endregion
77 |
78 | #region General
79 |
80 | ///
81 | /// Returns a random integer from (inclusive) to (exclusive)
82 | ///
83 | /// Minimum range (inclusive)
84 | /// Maximum range (exclusive)
85 | /// A random integer from (inclusive) to (exclusive)
86 | public static int Range(int min, int max) {
87 | if (max <= min)
88 | return min;
89 | return min + Mathf.Abs(Int % (max - min));
90 | }
91 | ///
92 | /// Returns a random integer from 0 (inclusive) to (exclusive)
93 | ///
94 | /// Maximum range (exclusive)
95 | /// A random integer from 0 (inclusive) to (exclusive)
96 | public static int Range(int max) {
97 | return Range(0, max);
98 | }
99 |
100 | ///
101 | /// Returns a random integer from (inclusive) to (inclusive)
102 | ///
103 | /// Minimum range (inclusive)
104 | /// Maximum range (inclusive)
105 | /// A random integer from (inclusive) to (inclusive)
106 | public static int RangeInclusive(int min, int max) {
107 | if (max <= min)
108 | return min;
109 | return Range(min, max + 1);
110 | }
111 |
112 | ///
113 | /// Returns a random float from (inclusive) to (inclusive)
114 | ///
115 | /// Minimum range (inclusive)
116 | /// Maximum range (inclusive)
117 | /// A random float from (inclusive) to (inclusive)
118 | public static float Range(float min, float max) {
119 | if (max <= (double) min)
120 | return min;
121 | return Float * (max - min) + min;
122 | }
123 |
124 | ///
125 | /// Returns a random float from 0 (inclusive) to (inclusive)
126 | ///
127 | /// Maximum range (inclusive)
128 | /// A random float from 0 (inclusive) to (inclusive)
129 | public static float Range(float max) {
130 | return Range(0f, max);
131 | }
132 |
133 | ///
134 | /// Returns true if a random chance occurs, false otherwise
135 | ///
136 | /// The chance (between 0 and 1)
137 | /// true if a random chance occurs, false otherwise
138 | public static bool Chance(float chance) {
139 | if (chance <= 0.0)
140 | return false;
141 | if (chance >= 1.0)
142 | return true;
143 | return Float < (double) chance;
144 | }
145 |
146 | ///
147 | /// Returns an array of random bytes
148 | ///
149 | /// The number of bytes to generate
150 | /// An array of random bytes
151 | public static byte[] Bytes(int count) {
152 | byte[] buffer = new byte[count];
153 | for (int i = 0; i < buffer.Length; i++) {
154 | buffer[i] = (byte) (Int % 256);
155 | }
156 | return buffer;
157 | }
158 |
159 | #endregion
160 |
161 | #region Geometric
162 |
163 | ///
164 | /// Returns a random unit vector
165 | ///
166 | public static Vector3 UnitVector3 => new Vector3(Gaussian(), Gaussian(), Gaussian()).normalized;
167 |
168 | ///
169 | /// Returns a random unit vector
170 | ///
171 | public static Vector2 UnitVector2 => new Vector2(Gaussian(), Gaussian()).normalized;
172 |
173 | ///
174 | /// Returns a random point inside the unit circle
175 | ///
176 | public static Vector2 InsideUnitCircle {
177 | get {
178 | Vector2 vector;
179 | do {
180 | vector = new Vector2(Float - 0.5f, Float - 0.5f) * 2f;
181 | } while (vector.sqrMagnitude > 1.0f);
182 |
183 | return vector;
184 | }
185 | }
186 |
187 | ///
188 | /// Returns a random point inside the unit circle
189 | ///
190 | public static Vector3 InsideUnitCircleVec3 {
191 | get {
192 | Vector2 insideUnitCircle = InsideUnitCircle;
193 | return new Vector3(insideUnitCircle.x, 0.0f, insideUnitCircle.y);
194 | }
195 | }
196 |
197 | ///
198 | /// Returns a random point inside the unit sphere
199 | ///
200 | public static Vector3 InsideUnitSphere {
201 | get {
202 | Vector3 vector;
203 | do {
204 | vector = new Vector3(Float - 0.5f, Float - 0.5f, Float - 0.5f) * 2f;
205 | } while (vector.sqrMagnitude > 1.0f);
206 |
207 | return vector;
208 | }
209 | }
210 |
211 | #endregion
212 |
213 | #region Seeded
214 |
215 | ///
216 | /// Returns a random integer in from (inclusive) to (exclusive) using as a seed
217 | ///
218 | /// Minimum range (inclusive)
219 | /// Maximum range (exclusive)
220 | /// Custom seed
221 | /// A random integer in from (inclusive) to (exclusive) using as a seed
222 | public static int RangeSeeded(int min, int max, int seed) {
223 | PushState(seed);
224 | int num = Range(min, max);
225 | PopState();
226 | return num;
227 | }
228 |
229 | ///
230 | /// Returns a random integer in from (inclusive) to (inclusive) using as a seed
231 | ///
232 | /// Minimum range (inclusive)
233 | /// Maximum range (inclusive)
234 | /// Custom seed
235 | /// A random integer in from (inclusive) to (inclusive) using as a seed
236 | public static int RangeInclusiveSeeded(int min, int max, int seed) {
237 | PushState(seed);
238 | int num = RangeInclusive(min, max);
239 | PopState();
240 | return num;
241 | }
242 |
243 | ///
244 | /// Returns a random float in from (inclusive) to (inclusive) using as a seed
245 | ///
246 | /// Minimum range (inclusive)
247 | /// Maximum range (inclusive)
248 | /// Custom seed
249 | /// A random float in from (inclusive) to (inclusive) using as a seed
250 | public static float RangeSeeded(float min, float max, int seed) {
251 | PushState(seed);
252 | float num = Range(min, max);
253 | PopState();
254 | return num;
255 | }
256 |
257 | ///
258 | /// Returns a random float from 0 to 1 (both inclusive) using as a seed
259 | ///
260 | /// Custom seed
261 | /// A random float from 0 to 1 (both inclusive) using as a seed
262 | public static float FloatSeeded(int seed) {
263 | PushState(seed);
264 | float num = Float;
265 | PopState();
266 | return num;
267 | }
268 |
269 | ///
270 | /// Returns true if a random chance occurs using as a seed, false otherwise
271 | ///
272 | /// The chance (between 0 and 1)
273 | /// Custom seed
274 | /// true if a random chance occurs using as a seed, false otherwise
275 | public static bool ChanceSeeded(float chance, int seed) {
276 | PushState(seed);
277 | bool flag = Chance(chance);
278 | PopState();
279 | return flag;
280 | }
281 |
282 | ///
283 | /// Returns an array of random bytes using as a seed
284 | ///
285 | /// The number of bytes to generate
286 | /// Custom seed
287 | /// An array of random bytes
288 | public static byte[] BytesSeeded(int count, int seed) {
289 | PushState(seed);
290 | byte[] bytes = Bytes(count);
291 | PopState();
292 | return bytes;
293 | }
294 |
295 | #endregion
296 |
297 | #region Element
298 |
299 | ///
300 | /// Returns either or randomly.
301 | ///
302 | public static T Element(T a, T b) {
303 | if (Bool)
304 | return a;
305 | return b;
306 | }
307 |
308 | ///
309 | /// Returns either , , or randomly.
310 | ///
311 | public static T Element(T a, T b, T c) {
312 | float num = Float;
313 | if (num < 0.333330005407333)
314 | return a;
315 | if (num < 0.666660010814667)
316 | return b;
317 | return c;
318 | }
319 |
320 | ///
321 | /// Returns either , , , or randomly.
322 | ///
323 | public static T Element(T a, T b, T c, T d) {
324 | float num = Float;
325 | if (num < 0.25)
326 | return a;
327 | if (num < 0.5)
328 | return b;
329 | if (num < 0.75)
330 | return c;
331 | return d;
332 | }
333 |
334 | ///
335 | /// Returns either , , , , or randomly.
336 | ///
337 | public static T Element(T a, T b, T c, T d, T e) {
338 | float num = Float;
339 | if (num < 0.2f)
340 | return a;
341 | if (num < 0.4f)
342 | return b;
343 | if (num < 0.6f)
344 | return c;
345 | if (num < 0.8f)
346 | return d;
347 | return e;
348 | }
349 |
350 | ///
351 | /// Returns either , , , , , or randomly.
352 | ///
353 | public static T Element(T a, T b, T c, T d, T e, T f) {
354 | float num = Float;
355 | if (num < 0.166659995913506)
356 | return a;
357 | if (num < 0.333330005407333)
358 | return b;
359 | if (num < 0.5)
360 | return c;
361 | if (num < 0.666660010814667)
362 | return d;
363 | if (num < 0.833329975605011)
364 | return e;
365 | return f;
366 | }
367 |
368 | ///
369 | /// Returns a random element from
370 | ///
371 | public static T Element(params T[] items) {
372 | return ListItem(items);
373 | }
374 |
375 | #endregion
376 |
377 | #region Vector Ranges
378 |
379 | ///
380 | /// Returns a random float from .x to .y
381 | ///
382 | public static float Range(Vector2 range) {
383 | return Range(range.x, range.y);
384 | }
385 |
386 | ///
387 | /// Returns a random integer from .x (inclusive) to .y (exclusive)
388 | ///
389 | public static int Range(Vector2Int range) {
390 | return Range(range.x, range.y);
391 | }
392 |
393 | ///
394 | /// Returns a random integer from .x (inclusive) to .y (inclusive)
395 | ///
396 | public static int RangeInclusive(Vector2Int range) {
397 | return RangeInclusive(range.x, range.y);
398 | }
399 |
400 | #endregion
401 |
402 | #region Utilities
403 |
404 | public static float Gaussian(float centerX = 0.0f, float widthFactor = 1f) {
405 | return Mathf.Sqrt(-2f * Mathf.Log(Float)) * Mathf.Sin(twoPi * Float) * widthFactor + centerX;
406 | }
407 |
408 | public static float GaussianAsymmetric(float centerX = 0.0f, float lowerWidthFactor = 1f, float upperWidthFactor = 1f) {
409 | float num = Mathf.Sqrt(-2f * Mathf.Log(Float)) * Mathf.Sin(twoPi * Float);
410 | if (num <= 0.0)
411 | return num * lowerWidthFactor + centerX;
412 | return num * upperWidthFactor + centerX;
413 | }
414 |
415 | public static void PushState() {
416 | stateStack.Push(StateCompressed);
417 | }
418 |
419 | ///
420 | /// Replaces the current seed with . Use to undo this operation and retrieve the original state
421 | ///
422 | public static void PushState(int replacementSeed) {
423 | PushState();
424 | Seed = replacementSeed;
425 | }
426 |
427 | public static void PopState() {
428 | StateCompressed = stateStack.Pop();
429 | }
430 |
431 | public static void EnsureStateStackEmpty() {
432 | if (stateStack.Count <= 0)
433 | return;
434 | Debug.LogWarning("Random state stack is not empty. There were more calls to PushState than PopState. Fixing.");
435 | while (stateStack.Any())
436 | PopState();
437 | }
438 |
439 | #endregion
440 |
441 | #region Miscellaneous
442 |
443 | ///
444 | /// Generates a random color using an HSV range and alpha range.
445 | ///
446 | /// Minimum hue [range 0..1]
447 | /// Maximum hue [range 0..1]
448 | /// Minimum saturation [range 0..1]
449 | /// Maximum saturation [range 0..1]
450 | /// Minimum value [range 0..1]
451 | /// Maximum value [range 0..1]
452 | /// Minimum alpha [range 0..1]
453 | /// Maximum alpha [range 0..1]
454 | /// A random color with HSV and alpha values in input range
455 | ///
456 | public static Color ColorHSV(
457 | float hueMin = 0.0f, float hueMax = 1.0f, float saturationMin = 0.0f, float saturationMax = 1.0f,
458 | float valueMin = 0.0f, float valueMax = 1.0f, float alphaMin = 1.0f, float alphaMax = 1.0f
459 | ) {
460 | Color color = Color.HSVToRGB(
461 | Range(hueMin.Clamped01(), hueMax.Clamped01()),
462 | Range(saturationMin.Clamped01(), saturationMax.Clamped01()),
463 | Range(valueMin.Clamped01(), valueMax.Clamped01())
464 | );
465 | color.a = Range(alphaMin.Clamped01(), alphaMax.Clamped01());
466 | return color;
467 | }
468 |
469 | #endregion
470 |
471 | private class RNGProvider {
472 | public uint Seed = (uint) DateTime.Now.GetHashCode();
473 |
474 | public int GetInt(uint iterations) {
475 | return (int) GetHash((int) iterations);
476 | }
477 |
478 | public float GetFloat(uint iterations) {
479 | return (float) ((GetInt(iterations) - (double) int.MinValue) / uint.MaxValue);
480 | }
481 |
482 | private uint GetHash(int buffer) {
483 | uint num1 = Rotate(Seed + 374761393U + 4U + (uint) (buffer * -1028477379), 17) * 668265263U;
484 | uint num2 = (num1 ^ (num1 >> 15)) * 2246822519U;
485 | uint num3 = (num2 ^ (num2 >> 13)) * 3266489917U;
486 | return num3 ^ (num3 >> 16);
487 | }
488 |
489 | private static uint Rotate(uint value, int count) {
490 | return (value << count) | (value >> (32 - count));
491 | }
492 | }
493 |
494 | }
495 | }
--------------------------------------------------------------------------------
/Runtime/Misc/Rand.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 431bfa14b3472ec4a8cf9d8e4007e154
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Misc/Ref.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UnityCommons {
4 | ///
5 | /// Creates a reference object to a struct type
6 | ///
7 | /// Type of object
8 | public class Ref : IEquatable, IEquatable[> where T : struct {
9 | private T value;
10 | private Func getValue = null;
11 | private Action setValue = null;
12 |
13 | private Ref(T value) {
14 | this.value = value;
15 | }
16 |
17 | private Ref() {
18 | value = new T();
19 | }
20 |
21 | public ref T GetReference() {
22 | if (getValue != null) {
23 | T val = getValue();
24 | if (!val.Equals(value)) value = val;
25 | }
26 | return ref value;
27 | }
28 |
29 | public T GetValue() {
30 | if (getValue != null) {
31 | T val = getValue();
32 | if (!val.Equals(value)) value = val;
33 | }
34 | return value;
35 | }
36 |
37 | public void Set(T newValue) {
38 | value = newValue;
39 | setValue?.Invoke();
40 | }
41 |
42 | public void SetValueUnbound(T newValue) {
43 | value = newValue;
44 | }
45 |
46 | public T GetValueUnbound() {
47 | return value;
48 | }
49 |
50 | public void Bind(Func getValue, Action setValue) {
51 | this.getValue = getValue;
52 | this.setValue = setValue;
53 | }
54 |
55 | public void Unbind() {
56 | getValue = null;
57 | setValue = null;
58 | }
59 |
60 | #region Equality Members
61 | public bool Equals(T other) {
62 | return value.Equals(other);
63 | }
64 |
65 | public bool Equals(Ref other) {
66 | if (ReferenceEquals(null, other))
67 | return false;
68 | if (ReferenceEquals(this, other))
69 | return true;
70 | return Equals(other.value);
71 | }
72 |
73 | public override bool Equals(object obj) {
74 | if (ReferenceEquals(null, obj))
75 | return false;
76 | if (ReferenceEquals(this, obj))
77 | return true;
78 | if (obj.GetType() != this.GetType())
79 | return false;
80 | return Equals((Ref) obj);
81 | }
82 |
83 | public override int GetHashCode() {
84 | // ReSharper disable once NonReadonlyMemberInGetHashCode
85 | return value.GetHashCode();
86 | }
87 |
88 | public static bool operator ==(Ref left, Ref right) {
89 | return Equals(left, right);
90 | }
91 |
92 | public static bool operator !=(Ref left, Ref right) {
93 | return !Equals(left, right);
94 | }
95 |
96 | public static bool operator ==(Ref left, T right) {
97 | if (ReferenceEquals(null, left))
98 | return false;
99 | return Equals(left.value, right);
100 | }
101 |
102 | public static bool operator !=(Ref left, T right) {
103 | if (ReferenceEquals(null, left))
104 | return true;
105 | return !Equals(left.value, right);
106 | }
107 | #endregion
108 |
109 | public override string ToString() {
110 | return $"Ref<{typeof(T).Name}>[{value}]";
111 | }
112 |
113 | public static Ref MakeRef(T initialValue, Func getValue, Action setValue) {
114 | Ref reference = new Ref(initialValue);
115 | reference.Bind(getValue, setValue);
116 | return reference;
117 | }
118 |
119 | public static Ref MakeRef(T initialValue) {
120 | return new Ref(initialValue);
121 | }
122 |
123 | public static Ref MakeRef() {
124 | return new Ref();
125 | }
126 |
127 | #region Operators
128 | public static explicit operator Ref(T value) {
129 | return new Ref(value);
130 | }
131 | #endregion
132 | }
133 | }
--------------------------------------------------------------------------------
/Runtime/Misc/Ref.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 32118dfc803ec2d449701d71eebcc739
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Misc/SemVer.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UnityCommons {
4 | ///
5 | /// Represents a Semantic Versioning (or SemVer) data type. Contains , , and members.
6 | ///
7 | [System.Serializable]
8 | public struct SemVer : System.IEquatable, System.IComparable {
9 | public static readonly SemVer Invalid = new SemVer {MAJOR = -1, MINOR = -1, PATCH = -1};
10 |
11 | // ReSharper disable once InconsistentNaming
12 | public int MAJOR;
13 |
14 | // ReSharper disable once InconsistentNaming
15 | public int MINOR;
16 |
17 | // ReSharper disable once InconsistentNaming
18 | public int PATCH;
19 |
20 |
21 | public SemVer(string versionString) {
22 | if (!IsValid(versionString, out int major, out int minor, out int patch)) {
23 | Debug.LogError($"Could not parse SemVer string {versionString} into format MAJOR.MINOR.PATCH.");
24 | this = Invalid;
25 | return;
26 | }
27 |
28 | MAJOR = major;
29 | MINOR = minor;
30 | PATCH = patch;
31 | }
32 |
33 | public void BumpMajor() {
34 | MAJOR++;
35 | MINOR = 0;
36 | PATCH = 0;
37 | }
38 |
39 | public void BumpMinor() {
40 | MINOR++;
41 | PATCH = 0;
42 | }
43 |
44 | public void BumpPatch() => PATCH++;
45 |
46 | public override string ToString() {
47 | return $"{MAJOR}.{MINOR}.{PATCH}";
48 | }
49 |
50 | public static implicit operator string(SemVer semVer) {
51 | return semVer.ToString();
52 | }
53 |
54 | public static explicit operator SemVer(string versionString) {
55 | return FromVersionString(versionString);
56 | }
57 |
58 | public static SemVer FromVersionString(string versionString) {
59 | return new SemVer(versionString);
60 | }
61 |
62 | public static bool IsValid(string versionString, out int major, out int minor, out int patch) {
63 | string[] split = versionString.Split('.');
64 | if (split.Length != 3) {
65 | major = -1;
66 | minor = -1;
67 | patch = -1;
68 | return false;
69 | }
70 |
71 | bool majorWorks = int.TryParse(split[0], out int majorParsed) && majorParsed >= 0;
72 | bool minorWorks = int.TryParse(split[1], out int minorParsed) && minorParsed >= 0;
73 | bool patchWorks = int.TryParse(split[2], out int patchParsed) && patchParsed >= 0;
74 | major = majorParsed;
75 | minor = minorParsed;
76 | patch = patchParsed;
77 | return majorWorks && minorWorks && patchWorks;
78 | }
79 |
80 | public static bool IsValid(string versionString) => IsValid(versionString, out _, out _, out _);
81 |
82 | public bool Equals(SemVer other) {
83 | return MAJOR == other.MAJOR && MINOR == other.MINOR && PATCH == other.PATCH;
84 | }
85 |
86 | public override bool Equals(object obj) {
87 | return obj is SemVer other && Equals(other);
88 | }
89 |
90 | public override int GetHashCode() {
91 | unchecked {
92 | int hashCode = MAJOR;
93 | hashCode = (hashCode * 397) ^ MINOR;
94 | hashCode = (hashCode * 397) ^ PATCH;
95 | return hashCode;
96 | }
97 | }
98 |
99 | public static bool operator ==(SemVer left, SemVer right) {
100 | return left.Equals(right);
101 | }
102 |
103 | public static bool operator !=(SemVer left, SemVer right) {
104 | return !left.Equals(right);
105 | }
106 |
107 | public int CompareTo(SemVer other) {
108 | int majorComparison = MAJOR.CompareTo(other.MAJOR);
109 | if (majorComparison != 0)
110 | return majorComparison;
111 | int minorComparison = MINOR.CompareTo(other.MINOR);
112 | if (minorComparison != 0)
113 | return minorComparison;
114 | return PATCH.CompareTo(other.PATCH);
115 | }
116 | }
117 | }
--------------------------------------------------------------------------------
/Runtime/Misc/SemVer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a2e11db8a2d66fb4aa5707c3368a2d9c
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Singleton.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5d0dda5df1bb412e9c1a6b194d326400
3 | timeCreated: 1640799715
--------------------------------------------------------------------------------
/Runtime/Singleton/AutoMonoSingleton.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UnityCommons {
4 | ///
5 | /// Creates a MonoBehaviour singleton of type . Ensures that only a single instance exists.
6 | ///
7 | /// Component type
8 | public abstract class AutoMonoSingleton : MonoBehaviour where T : AutoMonoSingleton {
9 | private static readonly System.Type type = typeof(T);
10 | private static T instance;
11 | public static bool IsInitialized => instance != null;
12 |
13 | public static T Instance {
14 | get {
15 | // Find first object of type T. Other instances are destroyed when Awake is called on them.
16 | #if UNITY_2020_1_OR_NEWER
17 | if (instance == null) instance = FindObjectOfType(true);
18 | #else
19 | if (instance == null) {
20 | T[] objects = Resources.FindObjectsOfTypeAll();
21 | if (objects.Length > 0) instance = objects[0];
22 | }
23 | #endif
24 | if (instance != null) return instance;
25 |
26 | instance = new GameObject($"MonoSingleton<{type.Name}>").AddComponent();
27 | return instance;
28 | }
29 | }
30 |
31 | public static void EnsureInitialized() {
32 | _ = Instance;
33 | }
34 |
35 | private void Awake() {
36 | if (Instance != null && Instance != this) {
37 | Debug.LogError($"Cannot have multiple instances of {type.Name}. Destroying excess instances.");
38 | Destroy(this);
39 | return;
40 | }
41 |
42 | OnAwake();
43 | }
44 |
45 | protected virtual void OnAwake() {
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/Runtime/Singleton/AutoMonoSingleton.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: cf4de925caaa47a88ebc07924a1e91f8
3 | timeCreated: 1644336523
--------------------------------------------------------------------------------
/Runtime/Singleton/MonoSingleton.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UnityCommons {
4 | ///
5 | /// Creates a MonoBehaviour singleton of type . Ensures that only a single instance exists.
6 | ///
7 | /// Component type
8 | public abstract class MonoSingleton : MonoBehaviour where T : MonoSingleton {
9 | private static readonly System.Type type = typeof(T);
10 | private static T instance;
11 | public static bool IsInitialized => instance != null;
12 |
13 | public static T Instance {
14 | get {
15 | // Find first object of type T. Other instances are destroyed when Awake is called on them.
16 | #if UNITY_2020_1_OR_NEWER
17 | if (instance == null) instance = FindObjectOfType(true);
18 | #else
19 | if (instance == null) {
20 | T[] objects = Resources.FindObjectsOfTypeAll();
21 | if (objects.Length > 0) instance = objects[0];
22 | }
23 | #endif
24 | if (instance != null) return instance;
25 |
26 | Debug.LogWarning($"MonoSingleton<{type.Name}> could not be found!");
27 | return instance = null;
28 | }
29 | }
30 |
31 | private void Awake() {
32 | if (!IsInitialized) {
33 | instance = (T)this;
34 | OnAwake();
35 | return;
36 | }
37 |
38 | if (instance != (T)this) {
39 | Debug.LogError($"Cannot have multiple instances of {type.Name}. Destroying excess instances.");
40 | Destroy(this);
41 | return;
42 | }
43 |
44 | OnAwake();
45 | }
46 |
47 | protected virtual void OnAwake() {
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/Runtime/Singleton/MonoSingleton.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bdab651a02674fe78ed1439c2704898f
3 | timeCreated: 1612529978
--------------------------------------------------------------------------------
/Runtime/Singleton/Singleton.Create.cs:
--------------------------------------------------------------------------------
1 | namespace UnityCommons {
2 | public static partial class Singleton {
3 | public abstract class Create where T : Create {
4 | private static T instance;
5 | public static T Instance => instance ?? (instance = MakeInstance());
6 | public static bool IsInitialized => instance != null;
7 |
8 | protected abstract T CreateInstance();
9 |
10 | private static T MakeInstance() {
11 | return ((T)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(T))).CreateInstance();
12 | }
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Runtime/Singleton/Singleton.Create.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e84c369c5efd444e82b6d48455173dff
3 | timeCreated: 1640799724
--------------------------------------------------------------------------------
/Runtime/Singleton/Singleton.New.cs:
--------------------------------------------------------------------------------
1 | namespace UnityCommons {
2 | public static partial class Singleton {
3 | public abstract class New where T : New, new() {
4 | private static T instance;
5 | public static T Instance => instance ?? (instance = new T());
6 | public static bool IsInitialized => instance != null;
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/Runtime/Singleton/Singleton.New.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7d4c326ca744455a99bca54e0572604f
3 | timeCreated: 1640799724
--------------------------------------------------------------------------------
/Runtime/UnityCommons.Runtime.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "UnityCommons.Runtime",
3 | "references": [
4 | "GUID:6055be8ebefd69e48b49212b09b47b2f"
5 | ],
6 | "includePlatforms": [],
7 | "excludePlatforms": [],
8 | "allowUnsafeCode": false,
9 | "overrideReferences": false,
10 | "precompiledReferences": [],
11 | "autoReferenced": true,
12 | "defineConstraints": [],
13 | "versionDefines": [],
14 | "noEngineReferences": false
15 | }
--------------------------------------------------------------------------------
/Runtime/UnityCommons.Runtime.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d0ebc447e86057349b22b7994d613127
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime/UpdateManager.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3e5a6ec3c10a450a89cd5929c3dd25f5
3 | timeCreated: 1640799791
--------------------------------------------------------------------------------
/Runtime/UpdateManager/AsyncUpdateEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace UnityCommons {
7 | public delegate Task AsyncUpdateDelegate();
8 |
9 | public sealed class AsyncUpdateEvent {
10 | private readonly List delegates = new List();
11 |
12 | private AsyncUpdateEvent Add(AsyncUpdateDelegate @delegate) {
13 | if (@delegate == null) {
14 | throw new ArgumentNullException(nameof(@delegate));
15 | }
16 |
17 | delegates.Add(@delegate);
18 | return this;
19 | }
20 |
21 | private AsyncUpdateEvent Remove(AsyncUpdateDelegate @delegate) {
22 | if (@delegate == null) {
23 | throw new ArgumentNullException(nameof(@delegate));
24 | }
25 |
26 | delegates.Remove(@delegate);
27 | return this;
28 | }
29 |
30 | internal async Task InvokeSequential() {
31 | foreach (AsyncUpdateDelegate @delegate in delegates)
32 | await @delegate().ConfigureAwait(false);
33 | }
34 |
35 | internal async Task InvokeParallel() {
36 | await Task.WhenAll(delegates.Select(@delegate => @delegate())).ConfigureAwait(false);
37 | }
38 |
39 | public static AsyncUpdateEvent operator +(AsyncUpdateEvent @event, AsyncUpdateDelegate @delegate) {
40 | return @event.Add(@delegate);
41 | }
42 |
43 | public static AsyncUpdateEvent operator -(AsyncUpdateEvent @event, AsyncUpdateDelegate @delegate) {
44 | return @event.Remove(@delegate);
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/Runtime/UpdateManager/AsyncUpdateEvent.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 78b2d001c93a483a96dcc36e1f57f4cc
3 | timeCreated: 1640799806
--------------------------------------------------------------------------------
/Runtime/UpdateManager/ParallelAsyncUpdateManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UnityCommons {
4 | public sealed class ParallelAsyncUpdateManager : MonoSingleton {
5 | private readonly AsyncUpdateEvent onUpdate = new AsyncUpdateEvent();
6 | private readonly AsyncUpdateEvent onLateUpdate = new AsyncUpdateEvent();
7 | private readonly AsyncUpdateEvent onFixedUpdate = new AsyncUpdateEvent();
8 |
9 | public AsyncUpdateEvent OnUpdate {
10 | get => onUpdate;
11 | set {
12 | if (value != onUpdate) throw new InvalidOperationException("Cannot change OnUpdate event");
13 | }
14 | }
15 |
16 | public AsyncUpdateEvent OnLateUpdate {
17 | get => onLateUpdate;
18 | set {
19 | if (value != onLateUpdate) throw new InvalidOperationException("Cannot change OnLateUpdate event");
20 | }
21 | }
22 |
23 | public AsyncUpdateEvent OnFixedUpdate {
24 | get => onFixedUpdate;
25 | set {
26 | if (value != onFixedUpdate) throw new InvalidOperationException("Cannot change OnFixedUpdate event");
27 | }
28 | }
29 |
30 | private async void Update() {
31 | await OnUpdate.InvokeParallel();
32 | }
33 |
34 | private async void LateUpdate() {
35 | await OnLateUpdate.InvokeParallel();
36 | }
37 |
38 | private async void FixedUpdate() {
39 | await OnFixedUpdate.InvokeParallel();
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/Runtime/UpdateManager/ParallelAsyncUpdateManager.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c0e183f43f9d4de59afa0cf0656d4d18
3 | timeCreated: 1640799806
--------------------------------------------------------------------------------
/Runtime/UpdateManager/SequentialAsyncUpdateManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UnityCommons {
4 | public sealed class SequentialAsyncUpdateManager : MonoSingleton {
5 | private readonly AsyncUpdateEvent onUpdate = new AsyncUpdateEvent();
6 | private readonly AsyncUpdateEvent onLateUpdate = new AsyncUpdateEvent();
7 | private readonly AsyncUpdateEvent onFixedUpdate = new AsyncUpdateEvent();
8 |
9 | public AsyncUpdateEvent OnUpdate {
10 | get => onUpdate;
11 | set {
12 | if (value != onUpdate) throw new InvalidOperationException("Cannot change OnUpdate event");
13 | }
14 | }
15 |
16 | public AsyncUpdateEvent OnLateUpdate {
17 | get => onLateUpdate;
18 | set {
19 | if (value != onLateUpdate) throw new InvalidOperationException("Cannot change OnLateUpdate event");
20 | }
21 | }
22 |
23 | public AsyncUpdateEvent OnFixedUpdate {
24 | get => onFixedUpdate;
25 | set {
26 | if (value != onFixedUpdate) throw new InvalidOperationException("Cannot change OnFixedUpdate event");
27 | }
28 | }
29 |
30 | private async void Update() {
31 | await OnUpdate.InvokeSequential();
32 | }
33 |
34 | private async void LateUpdate() {
35 | await OnLateUpdate.InvokeSequential();
36 | }
37 |
38 | private async void FixedUpdate() {
39 | await OnFixedUpdate.InvokeSequential();
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/Runtime/UpdateManager/SequentialAsyncUpdateManager.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 494e0b73f1be4c35bf46214a9bd6e318
3 | timeCreated: 1640799806
--------------------------------------------------------------------------------
/Runtime/UpdateManager/UpdateManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UnityCommons {
4 | public class UpdateManager : MonoSingleton {
5 | private static readonly Action nop = () => { };
6 |
7 | public event Action OnUpdate = nop;
8 | public event Action OnLateUpdate = nop;
9 | public event Action OnFixedUpdate = nop;
10 |
11 | private void Update() {
12 | OnUpdate();
13 | }
14 |
15 | private void LateUpdate() {
16 | OnLateUpdate();
17 | }
18 |
19 | private void FixedUpdate() {
20 | OnFixedUpdate();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Runtime/UpdateManager/UpdateManager.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 40fc7141468a4504ba2ca9b574d516a9
3 | timeCreated: 1640799806
--------------------------------------------------------------------------------
/Runtime/Utilities.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 19d929ea43804675bdc7077fddcbe125
3 | timeCreated: 1609418542
--------------------------------------------------------------------------------
/Runtime/Utilities/GridXY.cs:
--------------------------------------------------------------------------------
1 | using TMPro;
2 | using UnityEngine;
3 |
4 | namespace UnityCommons {
5 | public class GridXY {
6 | public event GridValueChangedEvent OnGridValueChanged;
7 |
8 | private readonly int width;
9 | private readonly int height;
10 | private readonly float cellSize;
11 | private readonly Vector3 gridOrigin;
12 | private readonly T[,] grid;
13 | private readonly TextMeshPro[,] debugText;
14 |
15 | public GridXY(int width, int height, float cellSize, Vector3 gridOrigin = default, T startingValue = default, bool debug = false, DebugOptions? debugOptions = null) {
16 | this.width = width;
17 | this.height = height;
18 | this.cellSize = cellSize;
19 | this.gridOrigin = gridOrigin;
20 |
21 | grid = new T[width, height];
22 | for (int x = 0; x < width; x++) {
23 | for (int y = 0; y < height; y++) {
24 | grid[x, y] = startingValue;
25 | }
26 | }
27 |
28 | if (!debug) return;
29 |
30 | if (debugOptions == null) debugOptions = new DebugOptions();
31 | Quaternion rotation = Quaternion.Euler(90, 0, 0);
32 | if(debugOptions.Value.ShowText)
33 | debugText = new TextMeshPro[width, height];
34 | for (int x = 0; x < width; x++) {
35 | for (int y = 0; y < height; y++) {
36 | Debug.DrawLine(GetWorldCoordinates(x, y), GetWorldCoordinates(x, y + 1), Color.white, debugOptions.Value.LineDuration, false);
37 | Debug.DrawLine(GetWorldCoordinates(x, y), GetWorldCoordinates(x + 1, y), Color.white, debugOptions.Value.LineDuration, false);
38 |
39 | if(debugOptions.Value.ShowText)
40 | debugText[x, y] = Utils.CreateWorldText(grid[x, y].ToString(), position: GetWorldCoordinates(x, y) + new Vector3(cellSize, cellSize) * 0.5f,
41 | fontSize: debugOptions.Value.FontSize, rotation: rotation, horizontalAlignment: HorizontalAlignmentOptions.Center,
42 | verticalAlignment: VerticalAlignmentOptions.Middle);
43 | }
44 | }
45 |
46 | Debug.DrawLine(GetWorldCoordinates(0, height), GetWorldCoordinates(width, height), Color.white, debugOptions.Value.LineDuration, false);
47 | Debug.DrawLine(GetWorldCoordinates(width, 0), GetWorldCoordinates(width, height), Color.white, debugOptions.Value.LineDuration, false);
48 | OnGridValueChanged += args => { debugText[args.X, args.Y].text = args.NewValue.ToString(); };
49 | }
50 |
51 | public Vector3 GetWorldCoordinates(int x, int y) {
52 | return new Vector3(x, y) * cellSize + gridOrigin;
53 | }
54 |
55 | public (int x, int y) GetGridCoordinates(Vector3 worldCoordinates) {
56 | worldCoordinates -= gridOrigin;
57 | return (Mathf.FloorToInt(worldCoordinates.x / cellSize), Mathf.FloorToInt(worldCoordinates.y / cellSize));
58 | }
59 |
60 | public T this[int x, int y] {
61 | get {
62 | if (Utils.RangeCheck(x, width) && Utils.RangeCheck(y, height)) {
63 | return grid[x, y];
64 | }
65 |
66 | return default;
67 | }
68 | set {
69 | if (Utils.RangeCheck(x, width) && Utils.RangeCheck(y, height)) {
70 | grid[x, y] = value;
71 | OnGridValueChanged?.Invoke((x, y, value));
72 | }
73 | }
74 | }
75 |
76 | public T this[Vector2Int gridPosition] {
77 | get => this[gridPosition.x, gridPosition.y];
78 | set => this[gridPosition.x, gridPosition.y] = value;
79 | }
80 |
81 | public T this[Vector3 worldPosition] {
82 | get {
83 | (int x, int y) = GetGridCoordinates(worldPosition);
84 | return this[x, y];
85 | }
86 | set {
87 | (int x, int y) = GetGridCoordinates(worldPosition);
88 | this[x, y] = value;
89 | }
90 | }
91 |
92 | public delegate void GridValueChangedEvent(GridValueChangedEventArgs eventArgs);
93 |
94 | public readonly struct GridValueChangedEventArgs {
95 | public readonly int X;
96 | public readonly int Y;
97 | public readonly T NewValue;
98 |
99 | public GridValueChangedEventArgs(int x, int y, T newValue) {
100 | X = x;
101 | Y = y;
102 | NewValue = newValue;
103 | }
104 |
105 | public static implicit operator GridValueChangedEventArgs((int x, int y, T value) tuple) {
106 | (int x, int y, T value) = tuple;
107 | return new GridValueChangedEventArgs(x, y, value);
108 | }
109 | }
110 | }
111 |
112 | // Used in GridXZ as well
113 | public readonly struct DebugOptions {
114 | public readonly int FontSize;
115 | public readonly float LineDuration;
116 | public readonly bool ShowText;
117 |
118 | public DebugOptions(int fontSize = 2, float lineDuration = float.MaxValue, bool showText = false) {
119 | FontSize = fontSize;
120 | LineDuration = lineDuration;
121 | ShowText = showText;
122 | }
123 | }
124 |
125 | }
--------------------------------------------------------------------------------
/Runtime/Utilities/GridXY.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 159f0df197f0424486da96b5a1582d62
3 | timeCreated: 1613209096
--------------------------------------------------------------------------------
/Runtime/Utilities/GridXZ.cs:
--------------------------------------------------------------------------------
1 | using TMPro;
2 | using UnityEngine;
3 |
4 | namespace UnityCommons {
5 | public class GridXZ {
6 | public event GridValueChangedEvent OnGridValueChanged;
7 |
8 | private readonly int width;
9 | private readonly int height;
10 | private readonly float cellSize;
11 | private readonly Vector3 gridOrigin;
12 | private readonly T[,] grid;
13 | private readonly TextMeshPro[,] debugText;
14 |
15 | public GridXZ(int width, int height, float cellSize, Vector3 gridOrigin = default, T startingValue = default, bool debug = false, DebugOptions? debugOptions = null) {
16 | this.width = width;
17 | this.height = height;
18 | this.cellSize = cellSize;
19 | this.gridOrigin = gridOrigin;
20 |
21 | grid = new T[width, height];
22 | for (int x = 0; x < width; x++) {
23 | for (int y = 0; y < height; y++) {
24 | grid[x, y] = startingValue;
25 | }
26 | }
27 |
28 | if (!debug) return;
29 |
30 | if (debugOptions == null) debugOptions = new DebugOptions();
31 | Quaternion rotation = Quaternion.Euler(90, 0, 0);
32 | if(debugOptions.Value.ShowText)
33 | debugText = new TextMeshPro[width, height];
34 | for (int x = 0; x < width; x++) {
35 | for (int y = 0; y < height; y++) {
36 | Debug.DrawLine(GetWorldCoordinates(x, y), GetWorldCoordinates(x, y + 1), Color.white, debugOptions.Value.LineDuration, false);
37 | Debug.DrawLine(GetWorldCoordinates(x, y), GetWorldCoordinates(x + 1, y), Color.white, debugOptions.Value.LineDuration, false);
38 |
39 | if(debugOptions.Value.ShowText)
40 | debugText[x, y] = Utils.CreateWorldText(grid[x, y].ToString(), position: GetWorldCoordinates(x, y) + new Vector3(cellSize, cellSize) * 0.5f,
41 | fontSize: debugOptions.Value.FontSize, rotation: rotation, horizontalAlignment: HorizontalAlignmentOptions.Center,
42 | verticalAlignment: VerticalAlignmentOptions.Middle);
43 | }
44 | }
45 |
46 | Debug.DrawLine(GetWorldCoordinates(0, height), GetWorldCoordinates(width, height), Color.white, debugOptions.Value.LineDuration, false);
47 | Debug.DrawLine(GetWorldCoordinates(width, 0), GetWorldCoordinates(width, height), Color.white, debugOptions.Value.LineDuration, false);
48 | OnGridValueChanged += args => { debugText[args.X, args.Y].text = args.NewValue.ToString(); };
49 | }
50 |
51 | public Vector3 GetWorldCoordinates(int x, int y) {
52 | return new Vector3(x, 0, y) * cellSize + gridOrigin;
53 | }
54 |
55 | public (int x, int y) GetGridCoordinates(Vector3 worldCoordinates) {
56 | worldCoordinates -= gridOrigin;
57 | return (Mathf.FloorToInt(worldCoordinates.x / cellSize), Mathf.FloorToInt(worldCoordinates.z / cellSize));
58 | }
59 |
60 | public T this[int x, int y] {
61 | get {
62 | if (Utils.RangeCheck(x, width) && Utils.RangeCheck(y, height)) {
63 | return grid[x, y];
64 | }
65 |
66 | return default;
67 | }
68 | set {
69 | if (Utils.RangeCheck(x, width) && Utils.RangeCheck(y, height)) {
70 | grid[x, y] = value;
71 | OnGridValueChanged?.Invoke((x, y, value));
72 | }
73 | }
74 | }
75 |
76 | public T this[Vector2Int gridPosition] {
77 | get => this[gridPosition.x, gridPosition.y];
78 | set => this[gridPosition.x, gridPosition.y] = value;
79 | }
80 |
81 | public T this[Vector3 worldPosition] {
82 | get {
83 | (int x, int y) = GetGridCoordinates(worldPosition);
84 | return this[x, y];
85 | }
86 | set {
87 | (int x, int y) = GetGridCoordinates(worldPosition);
88 | this[x, y] = value;
89 | }
90 | }
91 |
92 | public delegate void GridValueChangedEvent(GridValueChangedEventArgs eventArgs);
93 |
94 | public readonly struct GridValueChangedEventArgs {
95 | public readonly int X;
96 | public readonly int Y;
97 | public readonly T NewValue;
98 |
99 | public GridValueChangedEventArgs(int x, int y, T newValue) {
100 | X = x;
101 | Y = y;
102 | NewValue = newValue;
103 | }
104 |
105 | public static implicit operator GridValueChangedEventArgs((int x, int y, T value) tuple) {
106 | (int x, int y, T value) = tuple;
107 | return new GridValueChangedEventArgs(x, y, value);
108 | }
109 | }
110 | }
111 | }
--------------------------------------------------------------------------------
/Runtime/Utilities/GridXZ.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: aae67a5c99824c979c58deea1267211c
3 | timeCreated: 1613210482
--------------------------------------------------------------------------------
/Runtime/Utilities/ListUtilities.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace UnityCommons {
5 | public static class ListUtilities {
6 | ///
7 | /// Combines into a single list
8 | ///
9 | public static List Combine(params List[] lists) {
10 | List combined = new List();
11 | foreach (List list in lists) {
12 | combined.AddRange(list);
13 | }
14 |
15 | return combined;
16 | }
17 |
18 | ///
19 | /// Combines into a single list
20 | ///
21 | public static List Combine(IEnumerable> lists) {
22 | return lists.SelectMany(list => list).ToList();
23 | }
24 |
25 | ///
26 | /// Combines into a single list
27 | ///
28 | public static IEnumerable Combine(IEnumerable lists) where TList : IEnumerable {
29 | return lists.SelectMany(list => list);
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/Runtime/Utilities/ListUtilities.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f56ef9c8b2854962b914ecc8c59687f4
3 | timeCreated: 1609418549
--------------------------------------------------------------------------------
/Runtime/Utilities/RangeUtils.cs:
--------------------------------------------------------------------------------
1 | namespace UnityCommons {
2 | public static partial class Utils {
3 | ///
4 | /// Returns true
5 | /// if is between (inclusive) and (exclusive),
6 | /// and false otherwise.
7 | ///
8 | public static bool RangeCheck(int value, int minValue, int maxValue) {
9 | return value >= minValue && value < maxValue;
10 | }
11 |
12 | ///
13 | /// Returns true
14 | /// if is between (inclusive) and (inclusive),
15 | /// and false otherwise.
16 | ///
17 | public static bool RangeCheckInclusive(int value, int minValue, int maxValue) {
18 | return value >= minValue && value <= maxValue;
19 | }
20 |
21 | ///
22 | /// Returns true
23 | /// if is between 0 (inclusive) and (exclusive),
24 | /// and false otherwise.
25 | ///
26 | public static bool RangeCheck(int value, int maxValue) {
27 | return RangeCheck(value, 0, maxValue);
28 | }
29 |
30 | ///
31 | /// Returns true
32 | /// if is between 0 (inclusive) and (inclusive),
33 | /// and false otherwise.
34 | ///
35 | public static bool RangeCheckInclusive(int value, int maxValue) {
36 | return RangeCheckInclusive(value, 0, maxValue);
37 | }
38 |
39 | ///
40 | /// Returns true
41 | /// if {x,y} is between {x,y} (inclusive) and {x,y} (exclusive),
42 | /// and false otherwise.
43 | ///
44 | public static bool RangeCheck((int a, int b) value, (int a, int b) minValue, (int a, int b) maxValue) {
45 | return RangeCheck(value.a, minValue.a, maxValue.a) && RangeCheck(value.b, minValue.b, maxValue.b);
46 | }
47 |
48 | ///
49 | /// Returns true
50 | /// if {x,y} is between {x,y} (inclusive) and {x,y} (inclusive),
51 | /// and false otherwise.
52 | ///
53 | public static bool RangeCheckInclusive((int a, int b) value, (int a, int b) minValue, (int a, int b) maxValue) {
54 | return RangeCheckInclusive(value.a, minValue.a, maxValue.a) && RangeCheckInclusive(value.b, minValue.b, maxValue.b);
55 | }
56 |
57 | ///
58 | /// Returns true
59 | /// if {x,y} is between 0{x,y} (inclusive) and {x,y} (exclusive),
60 | /// and false otherwise.
61 | ///
62 | public static bool RangeCheck((int a, int b) value, (int a, int b) maxValue) {
63 | return RangeCheck(value.a, 0, maxValue.a) && RangeCheck(value.b, 0, maxValue.b);
64 | }
65 |
66 | ///
67 | /// Returns true
68 | /// if {x,y} is between 0{x,y} (inclusive) and {x,y} (inclusive),
69 | /// and false otherwise.
70 | ///
71 | public static bool RangeCheckInclusive((int a, int b) value, (int a, int b) maxValue) {
72 | return RangeCheckInclusive(value.a, 0, maxValue.a) && RangeCheckInclusive(value.b, 0, maxValue.b);
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/Runtime/Utilities/RangeUtils.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 99a9f2e3a2cb4a87aa565554c6f3e049
3 | timeCreated: 1613209200
--------------------------------------------------------------------------------
/Runtime/Utilities/Run.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Concurrent;
4 | using System.Collections.Generic;
5 | using JetBrains.Annotations;
6 | using UnityEngine;
7 |
8 | namespace UnityCommons {
9 | public static class Run {
10 | ///
11 | /// Runs every updates/ticks. determines whether
12 | /// is ran in the Update, LateUpdate, or FixedUpdate loop
13 | ///
14 | /// An IDisposable which can be used to remove from updating by calling ].Dispose()
on it
15 | [MustUseReturnValue] public static IDisposable EveryTicks(int ticks, UpdateType updateType, Action action) {
16 | return RunUtilityUpdater.Instance.EveryTicks(ticks, action, updateType);
17 | }
18 |
19 | ///
20 | /// Runs every updates/ticks.
21 | ///
22 | /// An IDisposable which can be used to remove from updating by calling .Dispose()
on it
23 | [MustUseReturnValue] public static IDisposable EveryTicks(int ticks, Action action) {
24 | return RunUtilityUpdater.Instance.EveryTicks(ticks, action, UpdateType.Normal);
25 | }
26 |
27 | ///
28 | /// Runs every frame. determines whether
29 | /// is ran in the Update, LateUpdate, or FixedUpdate loop
30 | ///
31 | /// An IDisposable which can be used to remove from updating by calling .Dispose()
on it
32 | [MustUseReturnValue] public static IDisposable EveryFrame(UpdateType updateType, Action action) {
33 | return RunUtilityUpdater.Instance.EveryFrame(action, updateType);
34 | }
35 |
36 | ///
37 | /// Runs every Update loop (every frame).
38 | ///
39 | /// An IDisposable which can be used to remove from updating by calling .Dispose()
on it
40 | [MustUseReturnValue] public static IDisposable EveryFrame(Action action) {
41 | return RunUtilityUpdater.Instance.EveryFrame(action, UpdateType.Normal);
42 | }
43 |
44 | ///
45 | /// Runs every seconds, with an initial delay of 0 seconds.
46 | ///
47 | /// An IDisposable which can be used to remove from being run by calling .Dispose()
on it
48 | [MustUseReturnValue] public static IDisposable Every(float rate, Action action) {
49 | return RunUtilityUpdater.Instance.Every(action, rate, 0);
50 | }
51 |
52 | ///
53 | /// Runs every seconds, with an initial delay of seconds.
54 | ///
55 | /// An IDisposable which can be used to remove from being run by calling .Dispose()
on it
56 | [MustUseReturnValue] public static IDisposable Every(float rate, float initialDelay, Action action) {
57 | return RunUtilityUpdater.Instance.Every(action, rate, initialDelay);
58 | }
59 |
60 | ///
61 | /// Runs in the next frame. determines whether
62 | /// is ran in the Update, LateUpdate, or FixedUpdate loop
63 | ///
64 | public static void NextFrame(Action action, UpdateType updateType = UpdateType.Normal) {
65 | RunUtilityUpdater.Instance.NextFrame(action, updateType);
66 | }
67 |
68 | ///
69 | /// Runs after seconds.
70 | ///
71 | /// An IDisposable which can be used to cancel the call of by calling .Dispose()
on it
72 | public static IDisposable After(float delay, Action action) {
73 | return RunUtilityUpdater.Instance.After(action, delay);
74 | }
75 |
76 | public static void EnsureInitialized() {
77 | RunUtilityUpdater.EnsureInitialized();
78 | }
79 |
80 | private class RunUtilityUpdater : AutoMonoSingleton {
81 | private readonly List functions = new List();
82 | private readonly ConcurrentDictionary nextUpdateFunctions = new ConcurrentDictionary();
83 | private readonly Queue removeUpdate = new Queue();
84 | private readonly Queue removeLate = new Queue();
85 | private readonly Queue removeFixed = new Queue();
86 | private readonly ConcurrentQueue<(int, Function)> removeNextUpdate = new ConcurrentQueue<(int, Function)>();
87 |
88 | protected override void OnAwake() {
89 | gameObject.hideFlags = HideFlags.HideAndDontSave;
90 | }
91 |
92 | private void Update() {
93 | ClearQueue(removeUpdate);
94 | foreach (Function function in functions) {
95 | if (function.updateType != UpdateType.Normal) continue;
96 | if (function is TickFunction tickFunction) {
97 | if (Time.frameCount % tickFunction.ticks != 0) continue;
98 | }
99 |
100 | function.action?.Invoke();
101 | }
102 | ClearQueue(removeUpdate);
103 |
104 | foreach (KeyValuePair kvp in nextUpdateFunctions) {
105 | (int key, Function value) = (kvp.Key, kvp.Value);
106 | if (value.updateType != UpdateType.Normal) continue;
107 | value.action?.Invoke();
108 | removeNextUpdate.Enqueue((key, value));
109 | }
110 | ClearQueue(removeNextUpdate);
111 | }
112 |
113 | private void LateUpdate() {
114 | ClearQueue(removeLate);
115 | foreach (Function function in functions) {
116 | if (function.updateType != UpdateType.Late) continue;
117 | if (function is TickFunction tickFunction) {
118 | if (Time.frameCount % tickFunction.ticks != 0) continue;
119 | }
120 |
121 | function.action?.Invoke();
122 | }
123 | ClearQueue(removeLate);
124 |
125 | foreach (KeyValuePair kvp in nextUpdateFunctions) {
126 | (int key, Function value) = (kvp.Key, kvp.Value);
127 | if (value.updateType != UpdateType.Late) continue;
128 | value.action?.Invoke();
129 | removeNextUpdate.Enqueue((key, value));
130 | }
131 | ClearQueue(removeNextUpdate);
132 | }
133 |
134 | private void FixedUpdate() {
135 | ClearQueue(removeFixed);
136 | foreach (Function function in functions) {
137 | if (function.updateType != UpdateType.Fixed) continue;
138 | if (function is TickFunction tickFunction) {
139 | int fixedFrameCount = Mathf.RoundToInt(Time.fixedTime / Time.fixedDeltaTime);
140 | if (fixedFrameCount % tickFunction.ticks != 0) continue;
141 | }
142 |
143 | function.action?.Invoke();
144 | }
145 | ClearQueue(removeFixed);
146 |
147 | foreach (KeyValuePair kvp in nextUpdateFunctions) {
148 | (int key, Function value) = (kvp.Key, kvp.Value);
149 | if (value.updateType != UpdateType.Fixed) continue;
150 | value.action?.Invoke();
151 | removeNextUpdate.Enqueue((key, value));
152 | }
153 | ClearQueue(removeNextUpdate);
154 | }
155 |
156 | internal IDisposable EveryTicks(int ticks, Action action, UpdateType updateType) {
157 | TickFunction function = new TickFunction(ticks, action, updateType);
158 | functions.Add(function);
159 | return new FunctionDisposable(this, function);
160 | }
161 |
162 | internal IDisposable EveryFrame(Action action, UpdateType updateType) {
163 | Function function = new Function(action, updateType);
164 | functions.Add(function);
165 | return new FunctionDisposable(this, function);
166 | }
167 |
168 | internal IDisposable Every(Action action, float rate, float initialDelay) {
169 | return new CoroutineDisposable(this, StartCoroutine(Runner(action, rate, initialDelay)));
170 | }
171 |
172 | internal IDisposable After(Action action, float delay) {
173 | return new CoroutineDisposable(this, StartCoroutine(Delayer(action, delay)));
174 | }
175 |
176 | internal void NextFrame(Action action, UpdateType updateType) {
177 | if (!nextUpdateFunctions.TryAdd(nextUpdateFunctions.Count, new Function(action, updateType))) {
178 | Debug.LogWarning("Failed to add function to next update queue");
179 | }
180 | }
181 |
182 | private IEnumerator Runner(Action action, float rate, float initialDelay) {
183 | yield return new WaitForSeconds(initialDelay);
184 |
185 | while (true) {
186 | yield return null;
187 | action?.Invoke();
188 | yield return new WaitForSeconds(rate);
189 | }
190 | }
191 |
192 | private IEnumerator Delayer(Action action, float delay) {
193 | yield return new WaitForSeconds(delay);
194 | yield return null;
195 | action?.Invoke();
196 | }
197 |
198 | private void ClearQueue(Queue queue) {
199 | while (queue.Count > 0) {
200 | Function func = queue.Dequeue();
201 | functions.Remove(func);
202 | }
203 | }
204 |
205 | internal void ClearQueue(ConcurrentQueue<(int, Function)> queue) {
206 | while (queue.Count > 0) {
207 | if (queue.TryDequeue(out (int, Function) pair)) {
208 | if (!nextUpdateFunctions.TryRemove(pair.Item1, out _)) {
209 | Debug.LogWarning("Failed to remove function from next update queue");
210 | }
211 | }
212 | }
213 | }
214 |
215 | internal void QueueFree(Function function) {
216 | switch (function.updateType) {
217 | case UpdateType.Normal:
218 | removeUpdate.Enqueue(function);
219 | break;
220 | case UpdateType.Late:
221 | removeLate.Enqueue(function);
222 | break;
223 | case UpdateType.Fixed:
224 | removeFixed.Enqueue(function);
225 | break;
226 | default:
227 | throw new ArgumentOutOfRangeException();
228 | }
229 | }
230 | }
231 |
232 | private class CoroutineDisposable : IDisposable {
233 | private readonly RunUtilityUpdater owner;
234 | private readonly Coroutine coroutine;
235 | private bool disposed;
236 |
237 | public CoroutineDisposable(RunUtilityUpdater owner, Coroutine coroutine) {
238 | this.owner = owner;
239 | this.coroutine = coroutine;
240 | }
241 |
242 | public void Dispose() {
243 | if (disposed) return;
244 |
245 | owner.StopCoroutine(coroutine);
246 | disposed = true;
247 | }
248 | }
249 |
250 | private class FunctionDisposable : IDisposable {
251 | private readonly RunUtilityUpdater owner;
252 | private readonly Function function;
253 | private bool disposed;
254 |
255 | public FunctionDisposable(RunUtilityUpdater owner, Function function) {
256 | this.owner = owner;
257 | this.function = function;
258 | }
259 |
260 | public void Dispose() {
261 | if (disposed) return;
262 |
263 | owner.QueueFree(function);
264 | disposed = true;
265 | }
266 | }
267 |
268 | private class Function {
269 | // ReSharper disable once InconsistentNaming
270 | internal readonly Action action;
271 | // ReSharper disable once InconsistentNaming
272 | internal readonly UpdateType updateType;
273 |
274 | public Function(Action action, UpdateType updateType) {
275 | this.action = action;
276 | this.updateType = updateType;
277 | }
278 | }
279 |
280 | private class TickFunction : Function {
281 | // ReSharper disable once InconsistentNaming
282 | internal readonly int ticks;
283 |
284 | public TickFunction(int ticks, Action action, UpdateType updateType) : base(action, updateType) {
285 | this.ticks = ticks;
286 | }
287 | }
288 |
289 | public enum UpdateType {
290 | Normal,
291 | Late,
292 | Fixed
293 | }
294 | }
295 | }
--------------------------------------------------------------------------------
/Runtime/Utilities/Run.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5d07fd64d43c4870b2cc5e2475b9dc00
3 | timeCreated: 1613925928
--------------------------------------------------------------------------------
/Runtime/Utilities/UnityUtils.cs:
--------------------------------------------------------------------------------
1 | using TMPro;
2 | using UnityEngine;
3 |
4 | namespace UnityCommons {
5 | public static partial class Utils {
6 | ///
7 | /// Returns the world position of the mouse in screen position
8 | /// using Camera.main as the active camera, with z = 0.
9 | ///
10 | public static Vector3 MouseWorld_NoZ() {
11 | Vector3 world = MouseWorld();
12 | world.z = 0;
13 | return world;
14 | }
15 |
16 | ///
17 | /// Returns the world position of the mouse in screen position
18 | /// using Camera.main as the active camera, with y = 0.
19 | ///
20 | public static Vector3 MouseWorld_NoY() {
21 | Vector3 world = MouseWorld();
22 | world.y = 0;
23 | return world;
24 | }
25 |
26 | ///
27 | /// Returns the world position of the mouse in screen position
28 | /// using Camera.main as the active camera.
29 | ///
30 | public static Vector3 MouseWorld() {
31 | return ScreenToWorld(Input.mousePosition, Camera.main);
32 | }
33 |
34 | ///
35 | /// Returns the world position of the mouse in screen position
36 | /// using as the active camera.
37 | ///
38 | public static Vector3 MouseWorld(Camera camera) {
39 | return ScreenToWorld(Input.mousePosition, camera);
40 | }
41 |
42 | ///
43 | /// Returns the world position of the mouse in screen position using as the
44 | /// active camera, and as the layer mask.
45 | ///
46 | public static Vector3 MouseWorld(Camera camera, int layerMask) {
47 | return ScreenToWorld(Input.mousePosition, camera, layerMask);
48 | }
49 |
50 | ///
51 | /// Returns the world position of
52 | /// using Camera.main as the active camera.
53 | ///
54 | public static Vector3 ScreenToWorld(Vector3 screenPoint) {
55 | return ScreenToWorld(screenPoint, Camera.main);
56 | }
57 |
58 | ///
59 | /// Returns the world position of
60 | /// using as the active camera.
61 | ///
62 | public static Vector3 ScreenToWorld(Vector3 screenPoint, Camera camera) {
63 | Ray ray = camera.ScreenPointToRay(screenPoint);
64 | return Physics.Raycast(ray, out RaycastHit info, 10000f) ? info.point : Vector3.zero;
65 | }
66 |
67 | ///
68 | /// Returns the world position of using
69 | /// as the active camera, and as a layer mask.
70 | ///
71 | public static Vector3 ScreenToWorld(Vector3 screenPoint, Camera camera, int layerMask) {
72 | Ray ray = camera.ScreenPointToRay(screenPoint);
73 | return Physics.Raycast(ray, out RaycastHit info, 10000f, layerMask) ? info.point : Vector3.zero;
74 | }
75 |
76 | ///
77 | /// Returns the world position in 2D of Input.mousePosition with y = 0,
78 | /// using Camera.main as the active camera.
79 | ///
80 | public static Vector3 MouseWorld2D_NoY() {
81 | Vector3 position = MouseWorld2D();
82 | position.y = 0;
83 | return position;
84 | }
85 |
86 | ///
87 | /// Returns the world position in 2D of Input.mousePosition with z = 0,
88 | /// using Camera.main as the active camera.
89 | ///
90 | public static Vector3 MouseWorld2D_NoZ() {
91 | Vector3 position = MouseWorld2D();
92 | position.z = 0;
93 | return position;
94 | }
95 |
96 | ///
97 | /// Returns the world position in 2D of Input.mousePosition
98 | /// using Camera.main as the active camera.
99 | ///
100 | public static Vector3 MouseWorld2D() {
101 | return ScreenToWorld2D(Input.mousePosition, Camera.main);
102 | }
103 |
104 | ///
105 | /// Returns the world position in 2D of Input.mousePosition
106 | /// using as the active camera.
107 | ///
108 | public static Vector3 MouseWorld2D(Camera camera) {
109 | return ScreenToWorld2D(Input.mousePosition, camera);
110 | }
111 |
112 | ///
113 | /// Returns the world position in 2D of
114 | /// using Camera.main as the active camera.
115 | ///
116 | public static Vector3 ScreenToWorld2D(Vector3 screenPoint) {
117 | return ScreenToWorld2D(screenPoint, Camera.main);
118 | }
119 |
120 | ///
121 | /// Returns the world position in 2D of
122 | /// using as the active camera.
123 | ///
124 | public static Vector3 ScreenToWorld2D(Vector3 screenPoint, Camera camera) {
125 | return camera.ScreenToWorldPoint(screenPoint);
126 | }
127 |
128 | ///
129 | /// Creates a 3D text (TextMeshPro) object using the specified parameters.
130 | ///
131 | /// The 3D text instance
132 | public static TextMeshPro CreateWorldText(string text, Transform parent = null, Vector3 position = default, Quaternion? rotation = null, int fontSize = 32,
133 | Color? color = null,
134 | HorizontalAlignmentOptions horizontalAlignment = HorizontalAlignmentOptions.Left,
135 | VerticalAlignmentOptions verticalAlignment = VerticalAlignmentOptions.Top, int sortingOrder = 1000) {
136 | return CreateWorldText(text, parent, position, rotation ?? Quaternion.identity, fontSize, color ?? Color.white, horizontalAlignment, verticalAlignment, sortingOrder);
137 | }
138 |
139 | ///
140 | /// Creates a 3D text (TextMeshPro) object using the specified parameters.
141 | ///
142 | /// The 3D text instance
143 | public static TextMeshPro CreateWorldText(string text, Transform parent, Vector3 position, Quaternion rotation, int fontSize, Color color,
144 | HorizontalAlignmentOptions horizontalAlignment, VerticalAlignmentOptions verticalAlignment, int sortingOrder) {
145 | TextMeshPro textMesh = new GameObject("WorldText", typeof(TextMeshPro)).GetComponent();
146 | textMesh.text = text;
147 | textMesh.fontSize = fontSize;
148 | textMesh.color = color;
149 | textMesh.horizontalAlignment = horizontalAlignment;
150 | textMesh.verticalAlignment = verticalAlignment;
151 | textMesh.sortingOrder = sortingOrder;
152 |
153 | textMesh.transform.SetParent(parent, false);
154 | textMesh.transform.localPosition = position;
155 | textMesh.transform.localRotation = rotation;
156 |
157 | return textMesh;
158 | }
159 | }
160 | }
--------------------------------------------------------------------------------
/Runtime/Utilities/UnityUtils.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: af2cab2c3865456da228398b04f7771c
3 | timeCreated: 1613210591
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dev.vecerdi.unitycommons",
3 | "version": "2.1.5",
4 | "displayName": "Unity Commons",
5 | "description": "Library of project-agnostic & reusable scripts.",
6 | "license": "MIT",
7 | "unity": "2019.4",
8 | "type": "tool",
9 | "keywords": [
10 | "scripts",
11 | "library",
12 | "common",
13 | "utility"
14 | ],
15 | "author": {
16 | "name": "Teodor Vecerdi",
17 | "email": "teodor.vecerdi@gmail.com",
18 | "url": "https://github.com/TeodorVecerdi"
19 | },
20 | "dependencies": {
21 | },
22 | "repository": {
23 | "url": "https://github.com/TeodorVecerdi/UnityCommons.git",
24 | "type": "git"
25 | }
26 | }
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f2b4fbe4c0eb0e74697e83c73da9871b
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------