delete all scripts from Utilities folder, except 2 of them which are moved to different folders

This commit is contained in:
in0finite 2022-09-30 14:12:37 +02:00
parent 1c96fc50f6
commit e783257e4b
117 changed files with 0 additions and 6472 deletions

View file

@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: 71d578a17e6a4cd4c893fbabe558ec16
folderAsset: yes
timeCreated: 1427127911
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,113 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.CompilerServices;
namespace SanAndreasUnity.Utilities
{
public class AsyncLoader<TKey, TObj>
{
/// <summary>
/// All successfully loaded objects.
/// </summary>
private readonly Dictionary<TKey, TObj> m_Loaded = new Dictionary<TKey, TObj>();
/// <summary>
/// Objects currently being loaded. Value represents list of subscribers which will be called when loading is finished.
/// </summary>
private readonly Dictionary<TKey, List<System.Action<TObj>>> m_Loading = new Dictionary<TKey, List<System.Action<TObj>>> ();
public AsyncLoader ()
{
}
public AsyncLoader (IEqualityComparer<TKey> comparer)
{
m_Loaded = new Dictionary<TKey, TObj> (comparer);
m_Loading = new Dictionary<TKey, List<System.Action<TObj>>> (comparer);
}
public int GetNumObjectsLoaded ()
{
return m_Loaded.Count;
}
public int GetNumObjectsLoading ()
{
return m_Loading.Count;
}
public bool IsObjectLoaded (TKey key)
{
return m_Loaded.ContainsKey (key);
}
public TObj GetLoadedObject (TKey key)
{
return m_Loaded [key];
}
public bool TryLoadObject (TKey key, System.Action<TObj> onFinish)
{
ThreadHelper.ThrowIfNotOnMainThread(); // not needed, but to make sure
if (m_Loaded.ContainsKey(key))
{
onFinish(m_Loaded[key]);
return false;
}
if (m_Loading.ContainsKey(key))
{
// this object is loading
// subscribe to finish event
m_Loading[key].Add(onFinish);
return false;
}
// insert it into loading dict
m_Loading[key] = new List<System.Action<TObj>>() {onFinish};
return true;
}
public bool TryGetLoadedObject(TKey key, out TObj loadedObject)
{
ThreadHelper.ThrowIfNotOnMainThread(); // not needed, but to make sure
return m_Loaded.TryGetValue(key, out loadedObject);
}
public void OnObjectFinishedLoading (TKey key, TObj obj, bool bSuccess)
{
ThreadHelper.ThrowIfNotOnMainThread(); // not needed, but to make sure
if (bSuccess)
{
if (m_Loaded.ContainsKey(key))
{
// this object was loaded in the meantime
// this can happen if someone else is loading objects synchronously
Debug.LogErrorFormat("Redundant load of object ({0}): {1}", typeof(TObj), key);
}
else
{
m_Loaded.Add(key, obj);
}
}
if (m_Loading.TryGetValue(key, out var subscribersList))
{
// remove from loading dict
m_Loading.Remove(key);
// invoke subscribers
foreach (var action in subscribersList)
Utilities.F.RunExceptionSafe(() => action(obj));
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3e2b0a3b29a83c74d9cd4906420d6175
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,276 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace SanAndreasUnity.Utilities
{
public class BackgroundJobRunner
{
// TODO: maybe convert to class, because it takes 36 bytes - it's too much for red-black tree operations
public struct Job<T>
{
public System.Func<T> action;
public System.Action<T> callbackSuccess;
public System.Action<System.Exception> callbackError;
public System.Action<T> callbackFinish;
public float priority;
internal object result;
internal System.Exception exception;
internal long id;
}
public class JobComparer : IComparer<Job<object>>
{
public int Compare(Job<object> a, Job<object> b)
{
if (a.id == b.id)
return 0;
if (a.priority != b.priority)
return a.priority <= b.priority ? -1 : 1;
// priorities are the same
// the advantage has the job which was created earlier
return a.id <= b.id ? -1 : 1;
}
}
private class ThreadParameters
{
public readonly BlockingCollection<Job<object>> jobs =
new BlockingCollection<Job<object>>(new System.Collections.Concurrent.ConcurrentQueue<Job<object>>());
public readonly Utilities.ConcurrentQueue<Job<object>> processedJobs = new Utilities.ConcurrentQueue<Job<object>>();
private bool _shouldThreadExit = false;
private readonly object _shouldThreadExitLockObject = new object();
public bool ShouldThreadExit()
{
lock (_shouldThreadExitLockObject)
return _shouldThreadExit;
}
public void TellThreadToExit()
{
lock (_shouldThreadExitLockObject)
_shouldThreadExit = true;
}
}
private Thread _thread;
private readonly ThreadParameters _threadParameters = new ThreadParameters();
private readonly Queue<Job<object>> _processedJobsBuffer = new Queue<Job<object>>(256);
private long _lastJobId = 0;
private readonly object _lastJobIdLockObject = new object();
private long _lastProcessedJobId = 0;
private readonly Stopwatch _stopwatch = new Stopwatch();
void StartThread()
{
if (_thread != null)
return;
_thread = new Thread(ThreadFunction);
_thread.Start(_threadParameters);
}
public void ShutDown()
{
if (_thread != null)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
// _thread.Interrupt ();
_threadParameters.TellThreadToExit();
if (_thread.Join(7000))
Debug.LogFormat("Stopped background thread in {0} ms", sw.Elapsed.TotalMilliseconds);
else
Debug.LogError("Failed to stop background thread");
}
}
public void RegisterJob<T>(Job<T> job)
{
// note: this function can be called from any thread
if (null == job.action)
throw new ArgumentException("Job must have an action");
if (0f == job.priority)
throw new ArgumentException("You forgot to assign job priority");
job.exception = null;
var j = new Job<object>()
{
priority = job.priority,
action = () => job.action(),
callbackError = job.callbackError,
};
if (job.callbackSuccess != null)
j.callbackSuccess = (arg) => job.callbackSuccess((T)arg);
if (job.callbackFinish != null)
j.callbackFinish = (arg) => job.callbackFinish((T)arg);
lock (_lastJobIdLockObject)
// make sure that changing id and adding new job is atomic operation, otherwise
// multiple threads accessing this part of code can cause the jobs to be inserted out of order
{
j.id = ++_lastJobId;
_threadParameters.jobs.Add(j);
}
}
public void UpdateJobs(ushort maxTimeToUpdateMs)
{
ThreadHelper.ThrowIfNotOnMainThread();
this.UpdateJobsInternal(maxTimeToUpdateMs);
}
void UpdateJobsInternal(ushort maxTimeToUpdateMs)
{
// get all processed jobs
_stopwatch.Restart();
Job<object> job;
while (true)
{
if (maxTimeToUpdateMs != 0 && _stopwatch.ElapsedMilliseconds >= maxTimeToUpdateMs)
break;
if (_processedJobsBuffer.Count > 0)
job = _processedJobsBuffer.Dequeue();
else
{
int numCopied = _threadParameters.processedJobs.DequeueToQueue(_processedJobsBuffer, 256);
if (numCopied == 0)
break;
job = _processedJobsBuffer.Dequeue();
}
if (job.exception != null)
{
// error happened
if (job.callbackError != null)
Utilities.F.RunExceptionSafe(() => job.callbackError(job.exception));
Debug.LogException(job.exception);
}
else
{
// success
if (job.callbackSuccess != null)
Utilities.F.RunExceptionSafe(() => job.callbackSuccess(job.result));
}
// invoke finish callback
if (job.callbackFinish != null)
F.RunExceptionSafe(() => job.callbackFinish(job.result));
_lastProcessedJobId = job.id;
}
}
public long GetNumJobsPendingApproximately()
{
ThreadHelper.ThrowIfNotOnMainThread();
// this is not done in a critical section: calling Count on 2 multithreaded collections
return (long)_threadParameters.jobs.Count + (long)_threadParameters.processedJobs.Count + (long)_processedJobsBuffer.Count;
}
public long GetNumPendingJobs()
{
// this will not work if collections used are not FIFO collections (eg. other than queues)
// - this will be the case if job priority is used
ThreadHelper.ThrowIfNotOnMainThread();
lock (_lastJobIdLockObject)
{
if (_lastProcessedJobId > _lastJobId)
throw new Exception($"Last processed job id ({_lastProcessedJobId}) is higher than last registered job id ({_lastJobId}). This should not happen.");
return _lastJobId - _lastProcessedJobId;
}
}
public long GetLastProcessedJobId()
{
ThreadHelper.ThrowIfNotOnMainThread();
return _lastProcessedJobId;
}
public int? GetBackgroundThreadId()
{
ThreadHelper.ThrowIfNotOnMainThread();
return _thread?.ManagedThreadId;
}
public int GetProcessedJobsBufferCount()
{
ThreadHelper.ThrowIfNotOnMainThread();
return _processedJobsBuffer.Count;
}
public bool IsBackgroundThreadRunning()
{
ThreadHelper.ThrowIfNotOnMainThread();
if (null == _thread)
return false;
if (_thread.ThreadState != System.Threading.ThreadState.Running)
return false;
return true;
}
public void EnsureBackgroundThreadStarted()
{
ThreadHelper.ThrowIfNotOnMainThread();
this.StartThread();
}
static void ThreadFunction(object objectParameter)
{
ThreadParameters threadParameters = (ThreadParameters)objectParameter;
while (!threadParameters.ShouldThreadExit())
{
Job<object> job;
if (!threadParameters.jobs.TryTake(out job, 200))
continue;
try
{
job.result = job.action();
}
catch (System.Exception ex)
{
job.exception = ex;
}
threadParameters.processedJobs.Enqueue(job);
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: fdd88c441d4ecba469ce3b23cab23fa3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,78 +0,0 @@

namespace SanAndreasUnity.Utilities
{
public class CmdLineUtils
{
public static string[] GetCmdLineArgs()
{
try
{
string[] commandLineArgs = System.Environment.GetCommandLineArgs();
if (commandLineArgs != null)
return commandLineArgs;
}
catch (System.Exception) {}
return new string[0];
}
public static bool GetArgument(string argName, ref string argValue)
{
string[] commandLineArgs = GetCmdLineArgs();
if (commandLineArgs.Length < 2) // first argument is program path
return false;
string search = "-" + argName + ":";
var foundArg = System.Array.Find(commandLineArgs, arg => arg.StartsWith(search));
if (null == foundArg)
return false;
// found specified argument
// extract value
argValue = foundArg.Substring(search.Length);
return true;
}
public static bool GetUshortArgument(string argName, ref ushort argValue)
{
string str = null;
if (GetArgument(argName, ref str))
{
if (ushort.TryParse(str, out ushort parsedValue))
{
argValue = parsedValue;
return true;
}
}
return false;
}
public static bool TryGetUshortArgument(string argName, out ushort argValue)
{
argValue = 0;
string str = null;
if (GetArgument(argName, ref str))
{
if (ushort.TryParse(str, out ushort parsedValue))
{
argValue = parsedValue;
return true;
}
}
return false;
}
public static bool HasArgument(string argName)
{
string str = null;
return GetArgument(argName, ref str);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: e31806ef68d937367a8bd9ec86a05f51
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 15250
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,63 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace SanAndreasUnity.Utilities
{
public static class CollectionExtensions
{
public static T RemoveLast<T>(this IList<T> list)
{
T lastElement = list[list.Count - 1];
list.RemoveAt(list.Count - 1);
return lastElement;
}
public static T RemoveFirst<T>(this IList<T> list)
{
T firstElement = list[0];
list.RemoveAt(0);
return firstElement;
}
public static Queue<T> ToQueue<T>(this IEnumerable<T> enumerable)
{
return new Queue<T>(enumerable);
}
public static Queue<T> ToQueueWithCapacity<T>(this IEnumerable<T> enumerable, int capacity)
{
var queue = new Queue<T>(capacity);
foreach (var item in enumerable)
queue.Enqueue(item);
return queue;
}
public static T[] ToArrayOfLength<T>(this IEnumerable<T> enumerable, int length)
{
T[] array = new T[length];
int i = 0;
foreach (var item in enumerable)
{
array[i] = item;
i++;
}
return array;
}
public static IEnumerable<T> AppendIf<T>(this IEnumerable<T> enumerable, bool condition, T element)
{
return condition ? enumerable.Append(element) : enumerable;
}
public static void AddMultiple<T>(this ICollection<T> collection, T value, int count)
{
for (int i = 0; i < count; i++)
collection.Add(value);
}
public static void AddMultiple<T>(this ICollection<T> collection, int count)
{
collection.AddMultiple(default, count);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d1a08f49d78741c47838f4a11e35ecc5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,87 +0,0 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace SanAndreasUnity.Utilities
{
public class ConcurrentProducerConsumerSortedSet<T> : IProducerConsumerCollection<T>
{
private SortedSet<T> _sortedSet;
private object _lockObject = new object();
public ConcurrentProducerConsumerSortedSet(IComparer<T> comparer)
{
_sortedSet = new SortedSet<T>(comparer);
}
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
public int Count
{
get
{
lock (_lockObject)
{
return _sortedSet.Count;
}
}
}
public bool IsSynchronized => throw new NotImplementedException();
public object SyncRoot => throw new NotImplementedException();
public void CopyTo(T[] array, int index)
{
throw new NotImplementedException();
}
public T[] ToArray()
{
throw new NotImplementedException();
}
public bool TryAdd(T item)
{
lock (_lockObject)
{
if (!_sortedSet.Add(item))
throw new ArgumentException($"Item with this key already exists: {item}");
return true;
}
}
public bool TryTake(out T result)
{
lock (_lockObject)
{
if (_sortedSet.Count > 0)
{
T min = _sortedSet.Min;
if (!_sortedSet.Remove(min))
throw new Exception("Failed to remove min element");
result = min;
return true;
}
result = default;
return false;
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 9c1410970028b404588b4f41a7f34497
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,79 +0,0 @@
using System.Collections.Generic;
namespace SanAndreasUnity.Utilities
{
/// <summary>
/// Alternative to System.Collections.Concurrent.ConcurrentQueue
/// (It's only available in .NET 4.0 and greater)
/// </summary>
/// <remarks>
/// It's a bit slow (as it uses locks), and only provides a small subset of the interface
/// Overall, the implementation is intended to be simple & robust
/// </remarks>
public class ConcurrentQueue<T>
{
private readonly System.Object _queueLock = new System.Object();
private readonly Queue<T> _queue = new Queue<T>();
public void Enqueue(T item)
{
lock (_queueLock)
{
_queue.Enqueue(item);
}
}
public bool TryDequeue(out T result)
{
lock (_queueLock)
{
if (_queue.Count == 0)
{
result = default(T);
return false;
}
result = _queue.Dequeue();
return true;
}
}
public T[] DequeueAll()
{
lock (_queueLock)
{
T[] copy = _queue.ToArray();
_queue.Clear();
return copy;
}
}
public int DequeueToQueue(Queue<T> collection, int maxNumItems)
{
lock (_queueLock)
{
int numAdded = 0;
while (_queue.Count > 0 && numAdded < maxNumItems)
{
collection.Enqueue(_queue.Dequeue());
numAdded++;
}
return numAdded;
}
}
public int Count
{
get
{
lock (_queueLock)
{
return _queue.Count;
}
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 0a08e17e16c677f42a9157199dc3d272
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,184 +0,0 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public static class Config
{
public const string const_game_dir = "game_dir";
public static string UserConfigFileName => "config.user.json";
public static string ConfigFilesDirectoryPath
{
get {
#if UNITY_EDITOR || UNITY_STANDALONE
return Directory.GetCurrentDirectory ();
#else
return Application.persistentDataPath;
#endif
}
}
public static string UserConfigFilePath => Path.Combine(ConfigFilesDirectoryPath, UserConfigFileName);
public static string GamePath => GetPath (const_game_dir);
public static string DataPath
{
get
{
#if UNITY_EDITOR
return Path.Combine(Directory.GetCurrentDirectory(), "Data");
#elif UNITY_STANDALONE
return Path.Combine(Application.dataPath, "Data");
#else
return Path.Combine(Application.persistentDataPath, "Data");
#endif
}
}
private static bool _loaded = false;
private static JObject _root = new JObject ();
private static JObject _user = new JObject ();
private static readonly Dictionary<string, string> _substitutions = new Dictionary<string, string> ();
static Config()
{
Load();
}
private static TVal ConvertVal<TVal>(JToken val)
{
// note that if you pass string[] as type, it will fail on IL2CPP
try
{
return (TVal)Convert.ChangeType(val, typeof(TVal));
}
catch
{
return val.ToObject<TVal>();
}
}
private static TVal Get<TVal>(string key)
{
Load();
var userVal = _user[key];
if (userVal != null)
return ConvertVal<TVal>(userVal);
return ConvertVal<TVal>(_root[key]);
}
public static string GetString(string key)
{
return Get<string>(key);
}
public static int GetInt(string key)
{
return Get<int>(key);
}
public static bool GetBool(string key)
{
return Get<bool>(key);
}
private static string GetSubstitution(string key)
{
Load();
if (_substitutions.ContainsKey(key)) return _substitutions[key];
string subs;
if (key == "data_dir")
{
subs = DataPath;
}
else
{
subs = ReplaceSubstitutions(GetString(key));
}
_substitutions.Add(key, subs);
return subs;
}
private static readonly Regex _regex = new Regex(@"\$\{(?<key>[a-z0-9_]+)\}", RegexOptions.Compiled);
private static string ReplaceSubstitutions(string value)
{
Load();
return _regex.Replace(value, x => GetSubstitution(x.Groups["key"].Value));
}
public static string GetPath(string key)
{
Load();
return ReplaceSubstitutions(GetString(key));
}
public static string[] GetPaths(string key)
{
Load();
return Get<JArray>(key)
.Select(x => ReplaceSubstitutions((string)x))
.ToArray();
}
public static void SetString (string key, string value)
{
Load();
_user [key] = value;
}
private static void Load ()
{
if (_loaded)
return;
_loaded = true;
_root = new JObject ();
_user = new JObject ();
_substitutions.Clear ();
_root = JObject.Parse (Resources.Load<TextAsset>("config").text);
if (File.Exists (UserConfigFilePath))
{
_user = JObject.Parse (File.ReadAllText (UserConfigFilePath));
}
}
public static void SaveUserConfig ()
{
Load();
File.WriteAllText (UserConfigFilePath, _user.ToString (Newtonsoft.Json.Formatting.Indented));
}
public static void SaveUserConfigSafe ()
{
Load();
F.RunExceptionSafe (() => SaveUserConfig ());
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 25ec4ed6b4fec874abfdd29f60d05484
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 9150
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,13 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
// Note about script execution order: execute this script before others to make sure config is loaded before their Awake() is called.
public class ConfigManager : MonoBehaviour
{
void Awake()
{
//Config.Load();
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 1f08780b55b9ede4cb0ffd248924ba25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -31000
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,57 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class CoroutineManager : StartupSingleton<CoroutineManager>
{
private static CoroutineRunner m_coroutineRunner = new CoroutineRunner();
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
static void InitOnLoad()
{
UnityEditor.EditorApplication.update -= EditorUpdate;
UnityEditor.EditorApplication.update += EditorUpdate;
}
static void EditorUpdate()
{
// note: this will also update coroutines in play mode, and also while the Editor is paused.
// if coroutines wish to avoid that, we need to add a flag for every coroutine
m_coroutineRunner.Update();
}
#endif
void Update()
{
if (!Application.isEditor)
m_coroutineRunner.Update();
}
public static CoroutineInfo Start(IEnumerator coroutine)
{
return m_coroutineRunner.StartCoroutine(coroutine, null, null);
}
public static CoroutineInfo Start(
IEnumerator coroutine,
System.Action onFinishSuccess,
System.Action<System.Exception> onFinishError)
{
return m_coroutineRunner.StartCoroutine(coroutine, onFinishSuccess, onFinishError);
}
public static void Stop(CoroutineInfo coroutineInfo)
{
m_coroutineRunner.StopCoroutine(coroutineInfo);
}
public static bool IsRunning(CoroutineInfo coroutineInfo)
{
return m_coroutineRunner.IsCoroutineRunning(coroutineInfo);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 81bcbcc6c7d0163408eea6ffa3732506
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 20
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,111 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class CoroutineInfo
{
private static long s_lastId = 0;
public long Id { get; } = ++s_lastId;
public IEnumerator coroutine { get; }
public System.Action onFinishSuccess { get; }
public System.Action<System.Exception> onFinishError { get; }
public CoroutineInfo(IEnumerator coroutine, Action onFinishSuccess, Action<Exception> onFinishError)
{
this.coroutine = coroutine;
this.onFinishSuccess = onFinishSuccess;
this.onFinishError = onFinishError;
}
}
public class CoroutineRunner
{
private List<CoroutineInfo> m_coroutines = new List<CoroutineInfo>();
private List<CoroutineInfo> m_newCoroutines = new List<CoroutineInfo>();
public CoroutineInfo StartCoroutine(IEnumerator coroutine, System.Action onFinishSuccess, System.Action<System.Exception> onFinishError)
{
var coroutineInfo = new CoroutineInfo(coroutine, onFinishSuccess, onFinishError);
m_newCoroutines.Add(coroutineInfo);
return coroutineInfo;
}
public void StopCoroutine(CoroutineInfo coroutineInfo)
{
if (null == coroutineInfo)
return;
int index = m_coroutines.IndexOf(coroutineInfo);
if (index >= 0)
m_coroutines[index] = null;
m_newCoroutines.Remove(coroutineInfo);
}
public bool IsCoroutineRunning(CoroutineInfo coroutineInfo)
{
if (null == coroutineInfo)
return false;
return m_coroutines.Contains(coroutineInfo) || m_newCoroutines.Contains(coroutineInfo);
}
public void Update()
{
m_coroutines.RemoveAll(c => null == c);
m_coroutines.AddRange(m_newCoroutines);
m_newCoroutines.Clear();
for (int i = 0; i < m_coroutines.Count; i++)
{
this.UpdateCoroutine(m_coroutines[i], i);
}
}
void UpdateCoroutine(CoroutineInfo coroutine, int coroutineIndex)
{
bool isFinished = false;
bool isSuccess = false;
System.Exception failureException = null;
try
{
if (!coroutine.coroutine.MoveNext())
{
isFinished = true;
isSuccess = true;
}
}
catch (System.Exception ex)
{
isFinished = true;
isSuccess = false;
failureException = ex;
Debug.LogException(ex);
}
if (isFinished)
{
m_coroutines[coroutineIndex] = null;
if (isSuccess)
{
if (coroutine.onFinishSuccess != null)
F.RunExceptionSafe(coroutine.onFinishSuccess);
}
else
{
if (coroutine.onFinishError != null)
F.RunExceptionSafe(() => coroutine.onFinishError(failureException));
}
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 577a4c9d6ba16494f8bea1797e91fb73
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,112 +0,0 @@
using UnityEngine;
using System.Collections.Generic;
namespace SanAndreasUnity.Utilities
{
public class CustomInput : MonoBehaviour
{
public static CustomInput Instance { get; private set; }
public bool IsActive { get; set; } = false;
Dictionary<string,float> axes = new Dictionary<string, float>();
Dictionary<string,bool> buttons = new Dictionary<string, bool>();
Dictionary<string,bool> buttonsDown = new Dictionary<string, bool>();
Dictionary<KeyCode,bool> keysDown = new Dictionary<KeyCode, bool>();
public float GetAxis(string name){
if (!this.IsActive)
return Input.GetAxis(name);
float value = 0;
if (axes.TryGetValue (name, out value))
return value;
return Input.GetAxis(name);
}
public float GetAxisRaw(string name){
if (!this.IsActive)
return Input.GetAxisRaw(name);
float value = 0;
if (axes.TryGetValue (name, out value))
return value;
return Input.GetAxisRaw(name);
}
public void SetAxis(string name, float value){
axes [name] = value;
}
public bool GetButton(string name){
if (!this.IsActive)
return Input.GetButton(name);
bool value = false;
if (buttons.TryGetValue (name, out value))
return value;
return Input.GetButton(name);
}
public bool GetButtonNoDefaultInput(string name){
if (!this.IsActive)
return false;
bool value = false;
buttons.TryGetValue (name, out value);
return value;
}
public bool HasButton(string name){
if (!this.IsActive)
return false;
return buttons.ContainsKey (name);
}
public bool GetButtonDown(string name){
if (!this.IsActive)
return Input.GetButtonDown(name);
bool value = false;
if (buttonsDown.TryGetValue (name, out value))
return value;
return Input.GetButtonDown(name);
}
public void SetButton(string name, bool pressed){
buttons [name] = pressed;
}
public void SetButtonDown(string name, bool pressed){
buttonsDown [name] = pressed;
}
public bool GetKeyDown(KeyCode keyCode){
if (!this.IsActive)
return Input.GetKeyDown(keyCode);
bool value = false;
if (keysDown.TryGetValue (keyCode, out value))
return value;
return Input.GetKeyDown(keyCode);
}
public void SetKeyDown(KeyCode keyCode, bool pressed)
{
keysDown [keyCode] = pressed;
}
public void ResetAllInput()
{
axes.Clear();
buttons.Clear();
buttonsDown.Clear();
keysDown.Clear();
}
void Awake()
{
Instance = this;
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 15fdcd3faa706b9fd9a440dcd477822b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 14800
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,131 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace SanAndreasUnity.Utilities
{
public class DamageInfo
{
public float amount = 0f;
public string damageType = null;
public Transform raycastHitTransform = null;
public Vector3 hitDirection = Vector3.forward;
public Vector3 hitPoint = Vector3.zero;
public Vector3 hitNormal = Vector3.up;
public object attacker = null;
public object attackingPlayer = null;
public object data = null;
}
public static class DamageType
{
public static readonly string
Bullet = "Bullet",
Explosion = "Explosion",
Gas = "Gas",
Flame = "Flame",
Melee = "Melee";
}
public class Damageable : MonoBehaviour
{
[SerializeField] private float m_health = 0f;
public float Health { get { return m_health; } set { m_health = value; } }
[SerializeField] private UnityEvent m_onDamage = new UnityEvent ();
public UnityEvent OnDamageEvent => m_onDamage;
public DamageInfo LastDamageInfo { get; private set; }
public void Damage (DamageInfo info)
{
this.LastDamageInfo = info;
F.RunExceptionSafe(() => m_onDamage.Invoke());
}
public void HandleDamageByDefault ()
{
DamageInfo info = this.LastDamageInfo;
this.Health -= info.amount;
if (this.Health <= 0f) {
Destroy (this.gameObject);
}
}
public static void InflictDamageToObjectsInArea(
Vector3 center,
float radius,
float damageAmount,
AnimationCurve damageOverDistanceCurve,
string damageType,
object attacker = null,
object attackingPlayer = null)
{
Collider[] overlappingColliders = Physics.OverlapSphere(center, radius);
var damagables = new Dictionary<Damageable, List<Collider>>();
foreach (var collider in overlappingColliders)
{
var damagable = collider.GetComponentInParent<Damageable>();
if (damagable != null)
{
if (damagables.ContainsKey(damagable))
{
damagables[damagable].Add(collider);
}
else
{
damagables.Add(damagable, new List<Collider>() { collider });
}
}
}
foreach (var pair in damagables)
{
Damageable damageable = pair.Key;
List<Collider> colliders = pair.Value;
// find closest point from all colliders
float closestPointDistance = float.MaxValue;
foreach (var collider in colliders)
{
Vector3 closestPointOnCollider = collider.ClosestPointOrBoundsCenter(center);
float distanceToPointOnCollider = Vector3.Distance(center, closestPointOnCollider);
if (distanceToPointOnCollider < closestPointDistance)
{
closestPointDistance = distanceToPointOnCollider;
}
}
// apply damage based on closest distance
float distance = closestPointDistance;
float distanceFactor = damageOverDistanceCurve.Evaluate(Mathf.Clamp01(distance / radius));
float damageAmountBasedOnDistance = damageAmount * distanceFactor;
F.RunExceptionSafe(() => damageable.Damage(new DamageInfo
{
amount = damageAmountBasedOnDistance,
damageType = damageType,
attacker = attacker,
attackingPlayer = attackingPlayer,
}));
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 62374ff6df2c74f9699075492ef7fdb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 9200
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,22 +0,0 @@
using System;
using UnityEngine;
using Object = UnityEngine.Object;
namespace SanAndreasUnity.Utilities
{
public class DestroyWhenInHeadlessMode : MonoBehaviour
{
public Component[] componentsToDestroy = Array.Empty<Component>();
private void Start() // use Start() to avoid problems with script execution order
{
if (F.IsInHeadlessMode)
{
foreach (var component in this.componentsToDestroy)
{
Object.Destroy(component);
}
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 4bb8f0fea23c3fe44828518a6ea9ad15
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5098
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,22 +0,0 @@
using System;
using UnityEngine;
using Object = UnityEngine.Object;
namespace SanAndreasUnity.Utilities
{
public class DestroyWhenNotOnServer : MonoBehaviour
{
public Component[] componentsToDestroy = Array.Empty<Component>();
private void Awake()
{
if (!NetUtils.IsServer)
{
foreach (var component in this.componentsToDestroy)
{
Object.Destroy(component);
}
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 6d68c88ae66cbc64c997da0c710b080c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5096
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,30 +0,0 @@
using System.Collections;
using System.Linq;
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class DestroyWhenParticleSystemsFinish : MonoBehaviour
{
IEnumerator Start()
{
var systems = this.GetComponentsInChildren<ParticleSystem>();
while (true)
{
yield return null;
if (systems.All(s => !s.isPlaying))
{
Object.Destroy(this.gameObject);
break;
}
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 09d6d62b56f152e449d502dce1494c75
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5062
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,19 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class DontDestroyOnLoad : MonoBehaviour
{
void Awake ()
{
if (null == this.transform.parent)
{
DontDestroyOnLoad (this.gameObject);
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 409653cfe36614ceab3cbfbf9ed04fce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 15150
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,52 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class ETAMeasurer
{
System.Diagnostics.Stopwatch m_stopwatch = System.Diagnostics.Stopwatch.StartNew();
float m_lastProgressPerc = 0f;
float m_changeInterval = 1f;
public string ETA { get; private set; } = "0";
public ETAMeasurer(float changeInterval)
{
if (float.IsNaN(changeInterval) || changeInterval < 0f)
throw new System.ArgumentOutOfRangeException(nameof(changeInterval));
m_changeInterval = changeInterval;
}
public void UpdateETA(float newProgressPerc)
{
if (float.IsNaN(newProgressPerc))
return;
newProgressPerc = Mathf.Clamp01(newProgressPerc);
double elapsedSeconds = m_stopwatch.Elapsed.TotalSeconds;
if (elapsedSeconds < m_changeInterval)
return;
m_stopwatch.Restart();
if (m_lastProgressPerc > newProgressPerc) // progress reduced
{
// don't change current ETA
m_lastProgressPerc = newProgressPerc;
return;
}
double processedPerc = newProgressPerc - m_lastProgressPerc;
double percPerSecond = processedPerc / elapsedSeconds;
double percLeft = 1.0 - newProgressPerc;
double secondsLeft = percLeft / percPerSecond;
this.ETA = F.FormatElapsedTime(secondsLeft);
m_lastProgressPerc = newProgressPerc;
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2e316e455c8b49c4c87d253c3e3e9d69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,38 +0,0 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
#endif
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public static class EditorUtilityEx
{
public static void MarkObjectAsDirty(Object obj)
{
#if UNITY_EDITOR
EditorUtility.SetDirty(obj);
#endif
}
public static bool MarkActiveSceneAsDirty()
{
#if UNITY_EDITOR
if (Application.isPlaying) // exception will be thrown if we attempt this in play mode
return false;
return EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
#else
return false;
#endif
}
public static bool IsAsset(Object obj)
{
#if UNITY_EDITOR
return AssetDatabase.Contains(obj);
#else
return false;
#endif
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 81721a1077d644a4f806a84eb4bf3de7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,68 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class ExplosionForce : MonoBehaviour
{
public float explosionForce = 4;
public float upwardsModifier = 1f;
public float radius = 10f;
public float explosionMultiplier = 1f;
public LayerMask layerMask;
private IEnumerator Start()
{
// wait one frame because some objects can be spawned right after the explosion
yield return null;
float multiplier = this.explosionMultiplier;
float r = radius * multiplier;
var cols = Physics.OverlapSphere(this.transform.position, r, layerMask);
var rigidbodies = new Dictionary<Rigidbody, List<Collider>>();
foreach (var col in cols)
{
if (col.attachedRigidbody != null)
{
if (rigidbodies.ContainsKey(col.attachedRigidbody))
{
rigidbodies[col.attachedRigidbody].Add(col);
}
else
{
rigidbodies.Add(col.attachedRigidbody, new List<Collider>() { col });
}
}
}
foreach (var pair in rigidbodies)
{
Rigidbody rb = pair.Key;
var colliders = pair.Value;
// apply higher force on objects with higher mass
float massFactor = Mathf.Pow(rb.mass, 0.95f);
foreach (var collider in colliders)
{
Vector3 closestPointOnCollider = collider.ClosestPointOrBoundsCenter(this.transform.position);
Vector3 diff = closestPointOnCollider - this.transform.position;
float distance = diff.magnitude;
float distanceFactor = Mathf.Sqrt(1.0f - Mathf.Clamp01(distance / r));
rb.AddForceAtPosition((diff.normalized * explosionForce + Vector3.up * upwardsModifier) * multiplier * distanceFactor * massFactor / colliders.Count, closestPointOnCollider, ForceMode.Impulse);
}
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 788838a8a852c8843ac90fb32e785378
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5060
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: aed867b325463d442b5f5ecdd33932ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 7250
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,22 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class FaceTowardsCamera : MonoBehaviour
{
public Transform[] transformsToFace;
void Update()
{
var cam = Camera.current;
if (cam != null)
{
Quaternion quaternion = Quaternion.LookRotation(-cam.transform.forward, cam.transform.up);
for (int i = 0; i < this.transformsToFace.Length; i++)
{
this.transformsToFace[i].rotation = quaternion;
}
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: cf07d69a4ea5dbd438aee477f5300420
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5094
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,137 +0,0 @@
using System;
using System.IO;
namespace SanAndreasUnity.Utilities
{
/// <summary>
/// Represents a subsection of another stream, starting from a certain offset and
/// with a given length.
/// </summary>
public class FrameStream : Stream
{
private readonly Stream _baseStream;
private readonly long _offset;
private readonly long _length;
private long _position;
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { return _length; }
}
public override long Position
{
get
{
return _position;
}
set
{
Seek(value, SeekOrigin.Begin);
}
}
public long AbsoluteOffset
{
get
{
var frameStream = _baseStream as FrameStream;
if (frameStream == null) return _offset;
return _offset + frameStream.AbsolutePosition;
}
}
public long AbsolutePosition
{
get
{
return _position + AbsoluteOffset;
}
}
public FrameStream(Stream baseStream, long offset, long length)
{
_baseStream = baseStream;
_offset = offset;
_length = length;
}
public override int Read(byte[] buffer, int offset, int count)
{
if (_position > _length)
{
return 0;
}
var basePos = _offset + _position;
if (_baseStream.Position != basePos)
{
_baseStream.Seek(basePos, SeekOrigin.Begin);
}
var read = _baseStream.Read(buffer, offset, (int)Math.Min(_length - _position, count));
_position += read;
return read;
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
_position = offset;
break;
case SeekOrigin.Current:
_position += offset;
break;
case SeekOrigin.End:
_position = _length - offset;
break;
}
if (_position < 0 || _position > _length)
{
throw new ArgumentOutOfRangeException("offset");
}
return _baseStream.Seek(_position + _offset, SeekOrigin.Begin) - _offset;
}
public override void Flush()
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 50e57e1fd74e6034db728443bef0cfef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 14600
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,352 +0,0 @@
// http://www.unity3d-france.com/unity/phpBB3/viewtopic.php?f=24&t=5409
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class GLDebug : MonoBehaviour
{
private struct Line
{
public Vector3 start;
public Vector3 end;
public Color color;
public double startTime;
public float duration;
public Line (Vector3 start, Vector3 end, Color color, double startTime, float duration)
{
this.start = start;
this.end = end;
this.color = color;
this.startTime = startTime;
this.duration = duration;
}
public bool DurationElapsed (bool drawLine)
{
if (drawLine)
{
GL.Color (color);
GL.Vertex (start);
GL.Vertex (end);
}
return Time.timeAsDouble - startTime >= duration;
}
}
private static GLDebug instance;
private static Material matZOn;
private static Material matZOff;
public KeyCode toggleKey;
public bool displayLines = true;
#if UNITY_EDITOR
public bool displayGizmos = true;
#endif
//public ScreenRect rect = new ScreenRect (0, 0, 150, 20);
private List<Line> linesZOn = new List<Line> ();
private List<Line> linesZOff = new List<Line> ();
// private float milliseconds;
public Shader zOnShader;
public Shader zOffShader;
void Awake ()
{
if (instance)
{
DestroyImmediate (this);
return;
}
instance = this;
SetMaterial ();
if (null == this.GetComponent<Camera> ())
{
Debug.LogError ("There should be camera attached to the same game object");
}
}
void SetMaterial ()
{
matZOn = new Material(this.zOnShader);
matZOn.hideFlags = HideFlags.HideAndDontSave;
//matZOn.shader.hideFlags = HideFlags.HideAndDontSave;
matZOff = new Material(this.zOffShader);
matZOff.hideFlags = HideFlags.HideAndDontSave;
//matZOff.shader.hideFlags = HideFlags.HideAndDontSave;
}
void Update ()
{
if (Input.GetKeyDown (toggleKey))
displayLines = !displayLines;
if (!displayLines)
{
// Stopwatch timer = Stopwatch.StartNew ();
linesZOn = linesZOn.Where (l => !l.DurationElapsed (false)).ToList ();
linesZOff = linesZOff.Where (l => !l.DurationElapsed (false)).ToList ();
// timer.Stop ();
// milliseconds = timer.Elapsed.Ticks / 10000f;
}
}
/*void OnGUI ()
{
GUI.Label (rect, "GLDebug : " + milliseconds.ToString ("f") + " ms");
}*/
#if UNITY_EDITOR
void OnDrawGizmos ()
{
if (!displayGizmos || !Application.isPlaying)
return;
for (int i = 0; i < linesZOn.Count; i++)
{
Gizmos.color = linesZOn[i].color;
Gizmos.DrawLine (linesZOn[i].start, linesZOn[i].end);
}
for (int i = 0; i < linesZOff.Count; i++)
{
Gizmos.color = linesZOff[i].color;
Gizmos.DrawLine (linesZOff[i].start, linesZOff[i].end);
}
}
#endif
void OnPostRender ()
{
if (!displayLines) return;
// Stopwatch timer = Stopwatch.StartNew ();
matZOn.SetPass (0);
GL.Begin (GL.LINES);
linesZOn = linesZOn.Where (l => !l.DurationElapsed (true)).ToList ();
GL.End ();
matZOff.SetPass (0);
GL.Begin (GL.LINES);
linesZOff = linesZOff.Where (l => !l.DurationElapsed (true)).ToList ();
GL.End ();
// timer.Stop ();
// milliseconds = timer.Elapsed.Ticks / 10000f;
}
private static void DrawLine (Vector3 start, Vector3 end, Color color, float duration = 0, bool depthTest = false)
{
if (duration == 0 && !instance.displayLines)
return;
if (start == end)
return;
if (depthTest)
instance.linesZOn.Add (new Line (start, end, color, Time.timeAsDouble, duration));
else
instance.linesZOff.Add (new Line (start, end, color, Time.timeAsDouble, duration));
}
/// <summary>
/// Draw a line from start to end with color for a duration of time and with or without depth testing.
/// If duration is 0 then the line is rendered 1 frame.
/// </summary>
/// <param name="start">Point in world space where the line should start.</param>
/// <param name="end">Point in world space where the line should end.</param>
/// <param name="color">Color of the line.</param>
/// <param name="duration">How long the line should be visible for.</param>
/// <param name="depthTest">Should the line be obscured by objects closer to the camera ?</param>
public static void DrawLine (Vector3 start, Vector3 end, Color? color = null, float duration = 0, bool depthTest = false)
{
DrawLine (start, end, color ?? Color.white, duration, depthTest);
}
/// <summary>
/// Draw a line from start to start + dir with color for a duration of time and with or without depth testing.
/// If duration is 0 then the ray is rendered 1 frame.
/// </summary>
/// <param name="start">Point in world space where the ray should start.</param>
/// <param name="dir">Direction and length of the ray.</param>
/// <param name="color">Color of the ray.</param>
/// <param name="duration">How long the ray should be visible for.</param>
/// <param name="depthTest">Should the ray be obscured by objects closer to the camera ?</param>
public static void DrawRay (Vector3 start, Vector3 dir, Color? color = null, float duration = 0, bool depthTest = false)
{
if (dir == Vector3.zero)
return;
DrawLine (start, start + dir, color, duration, depthTest);
}
/// <summary>
/// Draw an arrow from start to end with color for a duration of time and with or without depth testing.
/// If duration is 0 then the arrow is rendered 1 frame.
/// </summary>
/// <param name="start">Point in world space where the arrow should start.</param>
/// <param name="end">Point in world space where the arrow should end.</param>
/// <param name="arrowHeadLength">Length of the 2 lines of the head.</param>
/// <param name="arrowHeadAngle">Angle between the main line and each of the 2 smaller lines of the head.</param>
/// <param name="color">Color of the arrow.</param>
/// <param name="duration">How long the arrow should be visible for.</param>
/// <param name="depthTest">Should the arrow be obscured by objects closer to the camera ?</param>
public static void DrawLineArrow (Vector3 start, Vector3 end, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20, Color? color = null, float duration = 0, bool depthTest = false)
{
DrawArrow (start, end - start, arrowHeadLength, arrowHeadAngle, color, duration, depthTest);
}
/// <summary>
/// Draw an arrow from start to start + dir with color for a duration of time and with or without depth testing.
/// If duration is 0 then the arrow is rendered 1 frame.
/// </summary>
/// <param name="start">Point in world space where the arrow should start.</param>
/// <param name="dir">Direction and length of the arrow.</param>
/// <param name="arrowHeadLength">Length of the 2 lines of the head.</param>
/// <param name="arrowHeadAngle">Angle between the main line and each of the 2 smaller lines of the head.</param>
/// <param name="color">Color of the arrow.</param>
/// <param name="duration">How long the arrow should be visible for.</param>
/// <param name="depthTest">Should the arrow be obscured by objects closer to the camera ?</param>
public static void DrawArrow (Vector3 start, Vector3 dir, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20, Color? color = null, float duration = 0, bool depthTest = false)
{
if (dir == Vector3.zero)
return;
DrawRay (start, dir, color, duration, depthTest);
Vector3 right = Quaternion.LookRotation (dir) * Quaternion.Euler (0, 180 + arrowHeadAngle, 0) * Vector3.forward;
Vector3 left = Quaternion.LookRotation (dir) * Quaternion.Euler (0, 180 - arrowHeadAngle, 0) * Vector3.forward;
DrawRay (start + dir, right * arrowHeadLength, color, duration, depthTest);
DrawRay (start + dir, left * arrowHeadLength, color, duration, depthTest);
}
/// <summary>
/// Draw a square with color for a duration of time and with or without depth testing.
/// If duration is 0 then the square is renderer 1 frame.
/// </summary>
/// <param name="pos">Center of the square in world space.</param>
/// <param name="rot">Rotation of the square in euler angles in world space.</param>
/// <param name="scale">Size of the square.</param>
/// <param name="color">Color of the square.</param>
/// <param name="duration">How long the square should be visible for.</param>
/// <param name="depthTest">Should the square be obscured by objects closer to the camera ?</param>
public static void DrawSquare (Vector3 pos, Vector3? rot = null, Vector3? scale = null, Color? color = null, float duration = 0, bool depthTest = false)
{
DrawSquare (Matrix4x4.TRS (pos, Quaternion.Euler (rot ?? Vector3.zero), scale ?? Vector3.one), color, duration, depthTest);
}
/// <summary>
/// Draw a square with color for a duration of time and with or without depth testing.
/// If duration is 0 then the square is renderer 1 frame.
/// </summary>
/// <param name="pos">Center of the square in world space.</param>
/// <param name="rot">Rotation of the square in world space.</param>
/// <param name="scale">Size of the square.</param>
/// <param name="color">Color of the square.</param>
/// <param name="duration">How long the square should be visible for.</param>
/// <param name="depthTest">Should the square be obscured by objects closer to the camera ?</param>
public static void DrawSquare (Vector3 pos, Quaternion? rot = null, Vector3? scale = null, Color? color = null, float duration = 0, bool depthTest = false)
{
DrawSquare (Matrix4x4.TRS (pos, rot ?? Quaternion.identity, scale ?? Vector3.one), color, duration, depthTest);
}
/// <summary>
/// Draw a square with color for a duration of time and with or without depth testing.
/// If duration is 0 then the square is renderer 1 frame.
/// </summary>
/// <param name="matrix">Transformation matrix which represent the square transform.</param>
/// <param name="color">Color of the square.</param>
/// <param name="duration">How long the square should be visible for.</param>
/// <param name="depthTest">Should the square be obscured by objects closer to the camera ?</param>
public static void DrawSquare (Matrix4x4 matrix, Color? color = null, float duration = 0, bool depthTest = false)
{
Vector3
p_1 = matrix.MultiplyPoint3x4 (new Vector3 ( .5f, 0, .5f)),
p_2 = matrix.MultiplyPoint3x4 (new Vector3 ( .5f, 0, -.5f)),
p_3 = matrix.MultiplyPoint3x4 (new Vector3 (-.5f, 0, -.5f)),
p_4 = matrix.MultiplyPoint3x4 (new Vector3 (-.5f, 0, .5f));
DrawLine (p_1, p_2, color, duration, depthTest);
DrawLine (p_2, p_3, color, duration, depthTest);
DrawLine (p_3, p_4, color, duration, depthTest);
DrawLine (p_4, p_1, color, duration, depthTest);
}
/// <summary>
/// Draw a cube with color for a duration of time and with or without depth testing.
/// If duration is 0 then the square is renderer 1 frame.
/// </summary>
/// <param name="pos">Center of the cube in world space.</param>
/// <param name="rot">Rotation of the cube in euler angles in world space.</param>
/// <param name="scale">Size of the cube.</param>
/// <param name="color">Color of the cube.</param>
/// <param name="duration">How long the cube should be visible for.</param>
/// <param name="depthTest">Should the cube be obscured by objects closer to the camera ?</param>
public static void DrawCube (Vector3 pos, Vector3? rot = null, Vector3? scale = null, Color? color = null, float duration = 0, bool depthTest = false)
{
DrawCube (Matrix4x4.TRS (pos, Quaternion.Euler (rot ?? Vector3.zero), scale ?? Vector3.one), color, duration, depthTest);
}
/// <summary>
/// Draw a cube with color for a duration of time and with or without depth testing.
/// If duration is 0 then the square is renderer 1 frame.
/// </summary>
/// <param name="pos">Center of the cube in world space.</param>
/// <param name="rot">Rotation of the cube in world space.</param>
/// <param name="scale">Size of the cube.</param>
/// <param name="color">Color of the cube.</param>
/// <param name="duration">How long the cube should be visible for.</param>
/// <param name="depthTest">Should the cube be obscured by objects closer to the camera ?</param>
public static void DrawCube (Vector3 pos, Quaternion? rot = null, Vector3? scale = null, Color? color = null, float duration = 0, bool depthTest = false)
{
DrawCube (Matrix4x4.TRS (pos, rot ?? Quaternion.identity, scale ?? Vector3.one), color, duration, depthTest);
}
/// <summary>
/// Draw a cube with color for a duration of time and with or without depth testing.
/// If duration is 0 then the square is renderer 1 frame.
/// </summary>
/// <param name="matrix">Transformation matrix which represent the cube transform.</param>
/// <param name="color">Color of the cube.</param>
/// <param name="duration">How long the cube should be visible for.</param>
/// <param name="depthTest">Should the cube be obscured by objects closer to the camera ?</param>
public static void DrawCube (Matrix4x4 matrix, Color? color = null, float duration = 0, bool depthTest = false)
{
Vector3
down_1 = matrix.MultiplyPoint3x4 (new Vector3 ( .5f, -.5f, .5f)),
down_2 = matrix.MultiplyPoint3x4 (new Vector3 ( .5f, -.5f, -.5f)),
down_3 = matrix.MultiplyPoint3x4 (new Vector3 (-.5f, -.5f, -.5f)),
down_4 = matrix.MultiplyPoint3x4 (new Vector3 (-.5f, -.5f, .5f)),
up_1 = matrix.MultiplyPoint3x4 (new Vector3 ( .5f, .5f, .5f)),
up_2 = matrix.MultiplyPoint3x4 (new Vector3 ( .5f, .5f, -.5f)),
up_3 = matrix.MultiplyPoint3x4 (new Vector3 (-.5f, .5f, -.5f)),
up_4 = matrix.MultiplyPoint3x4 (new Vector3 (-.5f, .5f, .5f));
DrawLine (down_1, down_2, color, duration, depthTest);
DrawLine (down_2, down_3, color, duration, depthTest);
DrawLine (down_3, down_4, color, duration, depthTest);
DrawLine (down_4, down_1, color, duration, depthTest);
DrawLine (down_1, up_1, color, duration, depthTest);
DrawLine (down_2, up_2, color, duration, depthTest);
DrawLine (down_3, up_3, color, duration, depthTest);
DrawLine (down_4, up_4, color, duration, depthTest);
DrawLine (up_1, up_2, color, duration, depthTest);
DrawLine (up_2, up_3, color, duration, depthTest);
DrawLine (up_3, up_4, color, duration, depthTest);
DrawLine (up_4, up_1, color, duration, depthTest);
}
// EXTRAS
public static void DrawCircle (Vector3 center, float radius, Color? color = null, float duration = 0, bool depthTest = false)
{
// float degRad = Mathf.PI / 180;
for(float theta = 0.0f; theta < (2*Mathf.PI); theta += 0.2f)
{
Vector3 ci = (new Vector3(Mathf.Cos(theta) * radius + center.x, Mathf.Sin(theta) * radius + center.y, center.z));
DrawLine (ci, ci+new Vector3(0,0.02f,0), color, duration, depthTest);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 27b72409b037b08459c5c96c104ca2fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 10750
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: dccc1b72c027da84091293c4a668033a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,514 +0,0 @@
using UnityEngine;
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
/*
File browser for selecting files or folders at runtime.
*/
public enum FileBrowserType {
File,
Directory
}
public class FileBrowser {
// Called when the user clicks cancel or select
public delegate void FinishedCallback(string path);
// Defaults to working directory
public string CurrentDirectory {
get {
return m_currentDirectory;
}
set {
SetNewDirectory(value);
SwitchDirectoryNow();
}
}
protected string m_currentDirectory;
// Optional pattern for filtering selectable files/folders. See:
// http://msdn.microsoft.com/en-us/library/wz42302f(v=VS.90).aspx
// and
// http://msdn.microsoft.com/en-us/library/6ff71z1w(v=VS.90).aspx
public string SelectionPattern {
get {
return m_filePattern;
}
set {
m_filePattern = value;
ReadDirectoryContents();
}
}
protected string m_filePattern;
protected List<(string, string)> m_topPanelEntries = new List<(string, string)>();
// Optional image for directories
public Texture2D DirectoryImage {
get {
return m_directoryImage;
}
set {
m_directoryImage = value;
BuildContent();
}
}
protected Texture2D m_directoryImage;
// Optional image for files
public Texture2D FileImage {
get {
return m_fileImage;
}
set {
m_fileImage = value;
BuildContent();
}
}
protected Texture2D m_fileImage;
// Browser type. Defaults to File, but can be set to Folder
public FileBrowserType BrowserType {
get {
return m_browserType;
}
set {
m_browserType = value;
ReadDirectoryContents();
}
}
protected FileBrowserType m_browserType;
protected string m_newDirectory;
protected string[] m_currentDirectoryParts;
protected string[] m_files;
protected GUIContent[] m_filesWithImages;
protected int m_selectedFile;
protected string[] m_nonMatchingFiles;
protected GUIContent[] m_nonMatchingFilesWithImages;
protected int m_selectedNonMatchingDirectory;
protected string[] m_directories;
protected GUIContent[] m_directoriesWithImages;
protected int m_selectedDirectory;
protected string[] m_nonMatchingDirectories;
protected GUIContent[] m_nonMatchingDirectoriesWithImages;
protected bool m_currentDirectoryMatches;
protected GUIStyle CentredText {
get {
if (m_centredText == null) {
m_centredText = new GUIStyle(GUI.skin.label);
m_centredText.alignment = TextAnchor.MiddleLeft;
m_centredText.fixedHeight = this.ButtonStyle.fixedHeight;
}
return m_centredText;
}
}
protected GUIStyle m_centredText;
protected GUIStyle m_buttonStyle;
protected GUIStyle ButtonStyle {
get {
if (null == m_buttonStyle) {
// m_buttonStyle = new GUIStyle(GUI.skin.button);
// m_buttonStyle.fixedHeight = 25;
m_buttonStyle = GUI.skin.button;
}
return m_buttonStyle;
}
}
protected string m_name;
protected Rect m_screenRect;
protected GUIStyle m_areaStyle;
protected Vector2 m_scrollPosition;
protected FinishedCallback m_callback;
public FileBrowser(Rect screenRect, string name, GUIStyle areaStyle, FinishedCallback callback) {
m_name = name;
m_screenRect = screenRect;
m_areaStyle = areaStyle;
m_browserType = FileBrowserType.File;
m_callback = callback;
SetNewDirectory(Directory.GetCurrentDirectory());
SwitchDirectoryNow();
}
protected void SetNewDirectory(string directory) {
m_newDirectory = directory;
}
protected void SwitchDirectoryNow() {
if (m_newDirectory == null || m_currentDirectory == m_newDirectory) {
return;
}
m_currentDirectory = m_newDirectory;
m_scrollPosition = Vector2.zero;
m_selectedDirectory = m_selectedNonMatchingDirectory = m_selectedFile = -1;
ReadDirectoryContents();
}
protected void ReadDirectoryContents() {
// refresh top panel
try {
m_topPanelEntries.Clear ();
m_topPanelEntries.AddRange( GetDirectoriesForTopPanel() );
} catch {
}
if (m_currentDirectory == "/") {
m_currentDirectoryParts = new string[] {""};
m_currentDirectoryMatches = false;
} else {
m_currentDirectoryParts = m_currentDirectory.Split(Path.DirectorySeparatorChar);
if (SelectionPattern != null) {
string[] generation = GetDirectories(
Path.GetDirectoryName(m_currentDirectory),
SelectionPattern
);
m_currentDirectoryMatches = Array.IndexOf(generation, m_currentDirectory) >= 0;
} else {
m_currentDirectoryMatches = false;
}
}
if (BrowserType == FileBrowserType.File || SelectionPattern == null) {
m_directories = GetDirectories(m_currentDirectory);
m_nonMatchingDirectories = new string[0];
} else {
m_directories = GetDirectories(m_currentDirectory, SelectionPattern);
var nonMatchingDirectories = new List<string>();
foreach (string directoryPath in GetDirectories(m_currentDirectory)) {
if (Array.IndexOf(m_directories, directoryPath) < 0) {
nonMatchingDirectories.Add(directoryPath);
}
}
m_nonMatchingDirectories = nonMatchingDirectories.ToArray();
for (int i = 0; i < m_nonMatchingDirectories.Length; ++i) {
int lastSeparator = m_nonMatchingDirectories[i].LastIndexOf(Path.DirectorySeparatorChar);
m_nonMatchingDirectories[i] = m_nonMatchingDirectories[i].Substring(lastSeparator + 1);
}
Array.Sort(m_nonMatchingDirectories);
}
for (int i = 0; i < m_directories.Length; ++i) {
m_directories[i] = m_directories[i].Substring(m_directories[i].LastIndexOf(Path.DirectorySeparatorChar) + 1);
}
if (BrowserType == FileBrowserType.Directory || SelectionPattern == null) {
m_files = GetFiles(m_currentDirectory);
m_nonMatchingFiles = new string[0];
} else {
m_files = GetFiles(m_currentDirectory, SelectionPattern);
var nonMatchingFiles = new List<string>();
foreach (string filePath in GetFiles(m_currentDirectory)) {
if (Array.IndexOf(m_files, filePath) < 0) {
nonMatchingFiles.Add(filePath);
}
}
m_nonMatchingFiles = nonMatchingFiles.ToArray();
for (int i = 0; i < m_nonMatchingFiles.Length; ++i) {
m_nonMatchingFiles[i] = Path.GetFileName(m_nonMatchingFiles[i]);
}
Array.Sort(m_nonMatchingFiles);
}
for (int i = 0; i < m_files.Length; ++i) {
m_files[i] = Path.GetFileName(m_files[i]);
}
Array.Sort(m_files);
BuildContent();
m_newDirectory = null;
}
static string[] GetFiles (string path, string searchPattern)
{
try {
return Directory.GetFiles( path, searchPattern );
} catch {
return new string[0];
}
}
static string[] GetFiles (string path)
{
try {
return Directory.GetFiles( path );
} catch {
return new string[0];
}
}
static string[] GetDirectories (string path, string searchPattern)
{
try {
return Directory.GetDirectories( path, searchPattern );
} catch {
return new string[0];
}
}
static string[] GetDirectories (string path)
{
try {
return Directory.GetDirectories( path );
} catch {
return new string[0];
}
}
static List<(string, string)> GetDirectoriesForTopPanel()
{
if (Application.platform == RuntimePlatform.Android)
{
return new string[]{"/", "/sdcard/", "/storage/", "/storage/sdcard0/", "/storage/sdcard1/", "/storage/emulated/0/"}
.Select(s => (s, s))
.ToList();
}
else if (Application.platform == RuntimePlatform.LinuxPlayer || Application.platform == RuntimePlatform.LinuxEditor)
{
return new string[]{"/", "/home/", "/mnt/", "/media/"}
.Select(s => (s, s))
.ToList();
}
else if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor)
{
var result = new List<(string, string)>();
result.AddRange(Directory.GetLogicalDrives().Select(s => (s, s)));
var specialFolders = new[]
{
Environment.SpecialFolder.UserProfile,
Environment.SpecialFolder.DesktopDirectory,
Environment.SpecialFolder.MyDocuments,
Environment.SpecialFolder.ProgramFiles,
Environment.SpecialFolder.ProgramFilesX86,
};
string[] specialFolderNames = new[]
{
"User",
"Desktop",
"Documents",
"Program Files",
"Program Files (x86)",
};
for (int i = 0; i < specialFolders.Length; i++)
{
string path = string.Empty;
try
{
path = Environment.GetFolderPath(specialFolders[i]);
}
catch
{
}
if (!string.IsNullOrWhiteSpace(path))
result.Add((specialFolderNames[i], path));
}
return result;
}
else
{
return Directory.GetLogicalDrives()
.Select(s => (s, s))
.ToList();
}
}
protected void BuildContent() {
m_directoriesWithImages = new GUIContent[m_directories.Length];
for (int i = 0; i < m_directoriesWithImages.Length; ++i) {
m_directoriesWithImages[i] = new GUIContent(m_directories[i], DirectoryImage);
}
m_nonMatchingDirectoriesWithImages = new GUIContent[m_nonMatchingDirectories.Length];
for (int i = 0; i < m_nonMatchingDirectoriesWithImages.Length; ++i) {
m_nonMatchingDirectoriesWithImages[i] = new GUIContent(m_nonMatchingDirectories[i], DirectoryImage);
}
m_filesWithImages = new GUIContent[m_files.Length];
for (int i = 0; i < m_filesWithImages.Length; ++i) {
m_filesWithImages[i] = new GUIContent(m_files[i], FileImage);
}
m_nonMatchingFilesWithImages = new GUIContent[m_nonMatchingFiles.Length];
for (int i = 0; i < m_nonMatchingFilesWithImages.Length; ++i) {
m_nonMatchingFilesWithImages[i] = new GUIContent(m_nonMatchingFiles[i], FileImage);
}
}
public void OnGUI() {
if (m_areaStyle != null)
GUILayout.BeginArea(m_screenRect, m_name, m_areaStyle);
else
GUILayout.BeginArea(m_screenRect, m_name);
// display top panel
if (m_topPanelEntries.Count > 0) {
GUILayout.BeginHorizontal();
foreach (var entry in m_topPanelEntries) {
if (GUILayout.Button (entry.Item1, this.ButtonStyle)) {
SetNewDirectory (entry.Item2);
}
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal ();
}
// display directory parts
GUILayout.BeginHorizontal();
for (int parentIndex = 0; parentIndex < m_currentDirectoryParts.Length; ++parentIndex) {
if (parentIndex == m_currentDirectoryParts.Length - 1) {
GUILayout.Label(m_currentDirectoryParts[parentIndex], CentredText);
} else if (GUILayout.Button(m_currentDirectoryParts[parentIndex], this.ButtonStyle)) {
string parentDirectoryName = m_currentDirectory;
for (int i = m_currentDirectoryParts.Length - 1; i > parentIndex; --i) {
parentDirectoryName = Path.GetDirectoryName(parentDirectoryName);
}
SetNewDirectory(parentDirectoryName);
}
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
m_scrollPosition = GUILayout.BeginScrollView(
m_scrollPosition,
false,
true,
GUI.skin.horizontalScrollbar,
GUI.skin.verticalScrollbar,
GUI.skin.box
);
m_selectedDirectory = xGUILayout.SelectionList(
m_selectedDirectory,
m_directoriesWithImages,
this.ButtonStyle,
DirectoryDoubleClickCallback
);
if (m_selectedDirectory > -1) {
m_selectedFile = m_selectedNonMatchingDirectory = -1;
}
m_selectedNonMatchingDirectory = xGUILayout.SelectionList(
m_selectedNonMatchingDirectory,
m_nonMatchingDirectoriesWithImages,
this.ButtonStyle,
NonMatchingDirectoryDoubleClickCallback
);
if (m_selectedNonMatchingDirectory > -1) {
m_selectedDirectory = m_selectedFile = -1;
}
GUI.enabled = BrowserType == FileBrowserType.File;
m_selectedFile = xGUILayout.SelectionList(
m_selectedFile,
m_filesWithImages,
this.ButtonStyle,
FileDoubleClickCallback
);
GUI.enabled = true;
if (m_selectedFile > -1) {
m_selectedDirectory = m_selectedNonMatchingDirectory = -1;
}
GUI.enabled = false;
xGUILayout.SelectionList(
-1,
m_nonMatchingFilesWithImages,
this.ButtonStyle
);
GUI.enabled = true;
GUILayout.EndScrollView();
GUILayout.Space(20);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (SanAndreasUnity.Utilities.GUIUtils.ButtonWithCalculatedSize("Cancel")) {
m_callback(null);
}
GUILayout.Space(5);
if (BrowserType == FileBrowserType.File) {
GUI.enabled = m_selectedFile > -1;
} else {
if (SelectionPattern == null) {
GUI.enabled = true;//m_selectedDirectory > -1;
} else {
GUI.enabled = m_selectedDirectory > -1 ||
(
m_currentDirectoryMatches &&
m_selectedNonMatchingDirectory == -1 &&
m_selectedFile == -1
);
}
}
string selectButtonText = BrowserType == FileBrowserType.File ? "Select" : "Select current folder";
if (SanAndreasUnity.Utilities.GUIUtils.ButtonWithCalculatedSize (selectButtonText)) {
if (BrowserType == FileBrowserType.File) {
m_callback(Path.Combine(m_currentDirectory, m_files[m_selectedFile]));
} else {
// if (m_selectedDirectory > -1) {
// m_callback(Path.Combine(m_currentDirectory, m_directories[m_selectedDirectory]));
// } else {
// m_callback(m_currentDirectory);
// }
m_callback(m_currentDirectory);
}
}
GUI.enabled = true;
GUILayout.EndHorizontal();
GUILayout.EndArea();
if (Event.current.type == EventType.Repaint) {
SwitchDirectoryNow();
}
}
protected void FileDoubleClickCallback(int i) {
if (BrowserType == FileBrowserType.File) {
m_callback(Path.Combine(m_currentDirectory, m_files[i]));
}
}
protected void DirectoryDoubleClickCallback(int i) {
SetNewDirectory(Path.Combine(m_currentDirectory, m_directories[i]));
}
protected void NonMatchingDirectoryDoubleClickCallback(int i) {
SetNewDirectory(Path.Combine(m_currentDirectory, m_nonMatchingDirectories[i]));
}
public static Vector2 GetRecommendedSize()
{
float width = Mathf.Max (Screen.width * 0.75f, 600);
float height = width * 9f / 16f;
return new Vector2(width, height);
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 229e43233fee52441b6819dd07765a7d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 6950
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,360 +0,0 @@
using UnityEngine;
using System.Collections.Generic;
namespace SanAndreasUnity.Utilities
{
public enum ScreenCorner { TopRight, TopLeft, BottomRight, BottomLeft }
public static class GUIUtils
{
private static GUIStyle styleWithBackground = new GUIStyle ();
private static GUIStyle s_centeredLabelStyle = null;
public static GUIStyle CenteredLabelStyle {
get {
if (null == s_centeredLabelStyle)
s_centeredLabelStyle = new GUIStyle (GUI.skin.label) { alignment = TextAnchor.MiddleCenter };
return s_centeredLabelStyle;
}
}
public static Rect ScreenRect { get { return new Rect (0, 0, Screen.width, Screen.height); } }
public static Rect GetCornerRect(ScreenCorner corner, Vector2 size, Vector2? padding = null)
{
return GetCornerRect(corner, size.x, size.y, padding);
}
public static Rect GetCornerRect(ScreenCorner corner, float width, float height, Vector2? padding = null)
{
float padX = 0,
padY = 0;
if (padding != null)
{
padX = padding.Value.x;
padY = padding.Value.y;
}
switch (corner)
{
case ScreenCorner.TopLeft:
return new Rect(padX, padY, width, height);
case ScreenCorner.TopRight:
return new Rect(Screen.width - (width + padX), padY, width, height);
case ScreenCorner.BottomLeft:
return new Rect(padX, Screen.height - (height + padY), width, height);
case ScreenCorner.BottomRight:
return new Rect(Screen.width - (width + padX), Screen.height - (height + padY), width, height);
}
return default(Rect);
}
public static Rect GetCenteredRect( Vector2 size ) {
Vector2 pos = new Vector2 (Screen.width * 0.5f, Screen.height * 0.5f);
pos -= size * 0.5f;
return new Rect (pos, size);
}
public static Rect GetCenteredRectPerc( Vector2 sizeInScreenPercentage ) {
return GetCenteredRect (new Vector2 (Screen.width * sizeInScreenPercentage.x, Screen.height * sizeInScreenPercentage.y));
}
public static Vector2 CalcScreenSizeForContent( GUIContent content, GUIStyle style ) {
return style.CalcScreenSize (style.CalcSize (content));
}
public static Vector2 CalcScreenSizeForText( string text, GUIStyle style ) {
return CalcScreenSizeForContent (new GUIContent (text), style);
}
public static bool ButtonWithCalculatedSize( string text ) {
return ButtonWithCalculatedSize(new GUIContent(text));
}
public static bool ButtonWithCalculatedSize(string text, float minWidth, float minHeight, GUIStyle style)
{
return ButtonWithCalculatedSize(new GUIContent(text), minWidth, minHeight, style);
}
public static bool ButtonWithCalculatedSize(string text, float minWidth, float minHeight)
{
return ButtonWithCalculatedSize(text, minWidth, minHeight, GUI.skin.button);
}
public static bool ButtonWithCalculatedSize(GUIContent content)
{
return ButtonWithCalculatedSize(content, 0f, 0f);
}
public static bool ButtonWithCalculatedSize(GUIContent content, float minWidth, float minHeight)
{
return ButtonWithCalculatedSize(content, minWidth, minHeight, GUI.skin.button);
}
public static bool ButtonWithCalculatedSize(GUIContent content, float minWidth, float minHeight, GUIStyle style)
{
Vector2 size = CalcScreenSizeForContent (content, style);
if (size.x < minWidth)
size.x = minWidth;
if (size.y < minHeight)
size.y = minHeight;
return GUILayout.Button (content, style, GUILayout.Width (size.x), GUILayout.Height (size.y));
}
public static bool ButtonWithColor( Rect rect, string text, Color color) {
var oldColor = GUI.backgroundColor;
GUI.backgroundColor = color;
bool result = GUI.Button (rect, text);
GUI.backgroundColor = oldColor;
return result;
}
public static void DrawRect (Rect position, Color color, GUIContent content = null)
{
var backgroundColor = GUI.backgroundColor;
GUI.backgroundColor = color;
styleWithBackground.normal.background = Texture2D.whiteTexture;
GUI.Box (position, content ?? GUIContent.none, styleWithBackground);
GUI.backgroundColor = backgroundColor;
}
public static void DrawBar (Rect rect, float fillPerc, Color fillColor, Color backgroundColor, float borderWidth)
{
fillPerc = Mathf.Clamp01 (fillPerc);
Rect fillRect = rect;
fillRect.position += Vector2.one * borderWidth;
fillRect.size -= Vector2.one * borderWidth * 2;
// first fill with black - that will be the border
GUIUtils.DrawRect( rect, Color.black );
// fill with background
GUIUtils.DrawRect( fillRect, backgroundColor );
// draw filled part
fillRect.width *= fillPerc;
GUIUtils.DrawRect( fillRect, fillColor );
}
public static int TabsControl (int currentTabIndex, params string[] tabNames)
{
return GUILayout.Toolbar (currentTabIndex, tabNames);
}
public static Rect GetRectForBarAsBillboard (Vector3 worldPos, float worldWidth, float worldHeight, Camera cam)
{
Vector3 camRight = cam.transform.right;
// Vector3 camUp = cam.transform.up;
// Vector3 upperLeft = worldPos - camRight * worldWidth * 0.5f + camUp * worldHeight * 0.5f;
// Vector3 upperRight = upperLeft + camRight * worldWidth;
// Vector3 lowerLeft = upperLeft - camUp * worldHeight;
// Vector3 lowerRight = lowerLeft + camRight * worldWidth;
Vector3 leftWorld = worldPos - camRight * worldWidth * 0.5f;
Vector3 rightWorld = worldPos + camRight * worldWidth * 0.5f;
Vector3 leftScreen = cam.WorldToScreenPoint (leftWorld);
Vector3 rightScreen = cam.WorldToScreenPoint (rightWorld);
if (leftScreen.z < 0 || rightScreen.z < 0)
return Rect.zero;
// transform to gui coordinates
leftScreen.y = Screen.height - leftScreen.y;
rightScreen.y = Screen.height - rightScreen.y;
float screenWidth = rightScreen.x - leftScreen.x;
float screenHeight = screenWidth * worldHeight / worldWidth;
return new Rect (new Vector2(leftScreen.x, leftScreen.y - screenHeight * 0.5f), new Vector2(screenWidth, screenHeight) );
}
public static void CenteredLabel(Vector2 pos, string text) {
Vector2 size = CalcScreenSizeForText (text, GUI.skin.label);
GUI.Label (new Rect (pos - size * 0.5f, size), text);
}
public static void DrawHorizontalLine(float height, float spaceBetween, Color color)
{
GUILayout.Space(spaceBetween);
float width = GUILayoutUtility.GetLastRect().width;
Rect rect = GUILayoutUtility.GetRect(width, height);
GUIUtils.DrawRect(rect, color);
GUILayout.Space(spaceBetween);
}
/// <summary> Draws the texture flipped around Y axis. </summary>
public static void DrawTextureWithYFlipped(Rect rect, Texture2D tex) {
var savedMatrix = GUI.matrix;
GUIUtility.ScaleAroundPivot (new Vector2 (1, -1), rect.center);
GUI.DrawTexture (rect, tex);
GUI.matrix = savedMatrix;
}
public static Rect DrawItemsInARowPerc (Rect rect, System.Action<Rect, string> drawItem, string[] items, float[] widthPercs ) {
Rect itemRect = rect;
float x = rect.position.x;
for (int i = 0; i < items.Length; i++) {
float width = widthPercs [i] * rect.width;
itemRect.position = new Vector2 (x, itemRect.position.y);
itemRect.width = width;
drawItem (itemRect, items [i]);
x += width;
}
rect.position += new Vector2 (x, 0f);
rect.width -= x;
return rect;
}
public static Rect DrawItemsInARow (Rect rect, System.Action<Rect, string> drawItem, string[] items, float[] widths ) {
float[] widthPercs = new float[widths.Length];
for (int i = 0; i < widths.Length; i++) {
widthPercs [i] = widths [i] / rect.width;
}
return DrawItemsInARowPerc (rect, drawItem, items, widthPercs);
}
public static Rect GetNextRectInARowPerc (Rect rowRect, ref int currentRectIndex, float spacing, params float[] widthPercs) {
float x = rowRect.position.x;
for (int i = 0; i < currentRectIndex; i++) {
x += widthPercs [i] * rowRect.width;
x += spacing;
}
float width = widthPercs [currentRectIndex] * rowRect.width;
currentRectIndex++;
return new Rect( x, rowRect.position.y, width, rowRect.height );
}
public static Rect GetNextRectInARow (Rect rowRect, ref int currentRectIndex, float spacing, params float[] widths) {
float[] widthPercs = new float[widths.Length];
for (int i = 0; i < widths.Length; i++) {
widthPercs [i] = widths [i] / rowRect.width;
}
return GetNextRectInARowPerc (rowRect, ref currentRectIndex, spacing, widthPercs);
}
public static int DrawPagedViewNumbers (Rect rect, int currentPage, int numPages)
{
int resultingPage = currentPage;
float spacing = 1f;
var btnRect=rect;
btnRect.width = 25f;
/*
* <_x_x_...x_>
* suppose we got y pages, then there are y+1 spacing.
* totalWidth =y*btnWidth+(y+1)*spacing+2*btnWidth
* 1) if totalWidth<= rect.width use < and > , when click result page -- or ++
* 2) if totalWidth> rect.width use << and >> , when click add number of max to all,
* result page will be max+!
*/
var totalWidth = numPages * btnRect.width + (numPages + 1) * spacing + 2 * btnRect.width;
var showNextSign = totalWidth <= rect.width;
var maxShow =showNextSign?numPages:Mathf.FloorToInt( numPages/( (totalWidth-2*btnRect.width) /( rect.width-2*btnRect.width)));
if (GUI.Button (btnRect,showNextSign? "<":"<<")) {
if (showNextSign)
{
resultingPage--;
}
else
{
resultingPage -= maxShow;
}
}
btnRect.position += new Vector2(btnRect.width + spacing, 0f);
int startBtnIndex = 0;
if (maxShow != 0)
{
if (currentPage % maxShow == 0)
{
startBtnIndex =((currentPage / maxShow)-1)*maxShow;
}
else
{
startBtnIndex =currentPage / maxShow*maxShow;
}
}
for (int i = 0; i < maxShow; i++)
{
var btnIndex = startBtnIndex + i + 1;
var style = currentPage == btnIndex ? GUI.skin.box : GUI.skin.button;
if (GUI.Button (btnRect, (btnIndex).ToString (), style))
resultingPage = btnIndex ;
btnRect.position += new Vector2(btnRect.width + spacing, 0f);
}
if (GUI.Button (btnRect, showNextSign?">":">>")) {
if (showNextSign)
{
resultingPage++;
}
else
{
resultingPage += maxShow;
}
}
resultingPage = Mathf.Clamp( resultingPage, 1, numPages );
return resultingPage;
}
public static int DrawPagedViewNumbers (Rect rect, int currentPage, int totalNumItems, int numItemsPerPage)
{
int numPages = Mathf.CeilToInt (totalNumItems / (float) numItemsPerPage);
return DrawPagedViewNumbers (rect, currentPage, numPages);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 54c9105fbede21845adb37571b796cad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 14850
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,54 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class TextGizmo
{
private static TextGizmo tg = null;
private Dictionary<char, string> texturePathLookup;
private Camera editorCamera = null;
private const int CHAR_TEXTURE_HEIGHT = 8; // todo: line breaks
private const int CHAR_TEXTURE_WIDTH = 6;
private const string characters = "abcdefghijklmnopqrstuvwxyz0123456789";
public static void Init()
{
tg = new TextGizmo();
}
/* singleton constructor */
private TextGizmo()
{
editorCamera = Camera.current;
texturePathLookup = new Dictionary<char, string>();
for (int c = 0; c < characters.Length; c++)
{
texturePathLookup.Add(characters[c], "TextGizmo/text_" + characters[c] + ".tif");
}
}
/* only call this method from a OnGizmos() method */
public static void Draw(Vector3 position, string text)
{
if (tg == null) Init();
string lowerText = text.ToLower();
Vector3 screenPoint = tg.editorCamera.WorldToScreenPoint(position);
int offset = 20;
for (int c = 0; c < lowerText.Length; c++)
{
if (tg.texturePathLookup.ContainsKey(lowerText[c]))
{
Vector3 worldPoint = tg.editorCamera.ScreenToWorldPoint(new Vector3(screenPoint.x + offset, screenPoint.y, screenPoint.z));
Gizmos.DrawIcon(worldPoint, tg.texturePathLookup[lowerText[c]]);
offset += CHAR_TEXTURE_WIDTH;
}
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 56e1d137930c73144bb33c1de5196b93
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 9500
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,84 +0,0 @@
using UnityEngine;
public class xGUILayout
{
public delegate void DoubleClickCallback(int index);
public static int SelectionList(int selected, GUIContent[] list)
{
return SelectionList(selected, list, "button", null);
}
public static int SelectionList(int selected, GUIContent[] list, GUIStyle elementStyle)
{
return SelectionList(selected, list, elementStyle, null);
}
public static int SelectionList(int selected, GUIContent[] list, DoubleClickCallback callback)
{
return SelectionList(selected, list, "button", callback);
}
public static int SelectionList(int selected, GUIContent[] list, GUIStyle elementStyle, DoubleClickCallback callback)
{
for (int i = 0; i < list.Length; ++i)
{
Rect elementRect = GUILayoutUtility.GetRect(list[i], elementStyle);
bool hover = elementRect.Contains(Event.current.mousePosition);
if (hover && Event.current.type == EventType.MouseDown && Event.current.clickCount == 1) // added " && Event.current.clickCount == 1"
{
selected = i;
Event.current.Use();
}
else if (hover && callback != null && Event.current.type == EventType.MouseDown && Event.current.clickCount == 2) //Changed from MouseUp to MouseDown
{
callback(i);
Event.current.Use();
}
else if (Event.current.type == EventType.Repaint)
{
elementStyle.Draw(elementRect, list[i], hover, false, i == selected, false);
}
}
return selected;
}
public static int SelectionList(int selected, string[] list)
{
return SelectionList(selected, list, "button", null);
}
public static int SelectionList(int selected, string[] list, GUIStyle elementStyle)
{
return SelectionList(selected, list, elementStyle, null);
}
public static int SelectionList(int selected, string[] list, DoubleClickCallback callback)
{
return SelectionList(selected, list, "button", callback);
}
public static int SelectionList(int selected, string[] list, GUIStyle elementStyle, DoubleClickCallback callback)
{
for (int i = 0; i < list.Length; ++i)
{
Rect elementRect = GUILayoutUtility.GetRect(new GUIContent(list[i]), elementStyle);
bool hover = elementRect.Contains(Event.current.mousePosition);
if (hover && Event.current.type == EventType.MouseDown)
{
selected = i;
Event.current.Use();
}
else if (hover && callback != null && Event.current.type == EventType.MouseUp && Event.current.clickCount == 2)
{
callback(i);
Event.current.Use();
}
else if (Event.current.type == EventType.Repaint)
{
elementStyle.Draw(elementRect, list[i], hover, false, i == selected, false);
}
}
return selected;
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 10222b6cb1ee1324db5061c7649c32e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 12700
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,22 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public interface IState {
void OnBecameActive();
void OnBecameInactive();
bool RepresentsState(System.Type type); // TODO: should be removed
bool RepresentsState<T>() where T : IState; // TODO: should be removed
void UpdateState();
void LateUpdateState();
void FixedUpdateState();
object ParameterForEnteringState { set; }
double LastTimeWhenActivated { get; set; }
double LastTimeWhenDeactivated { get; set; }
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: f502096bd6a1442d0b73c2884a32feec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,39 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public static class MathUtils
{
public static float DistanceFromPointToLineSegment(Vector3 p, Vector3 v, Vector3 w)
{
// Return minimum distance between line segment vw and point p
float l2 = Vector3.SqrMagnitude(v - w); // i.e. |w-v|^2 - avoid a sqrt
if (l2 == 0.0f) return Vector3.Distance(p, v); // v == w case
// Consider the line extending the segment, parameterized as v + t (w - v).
// We find projection of point p onto the line.
// It falls where t = [(p-v) . (w-v)] / |w-v|^2
// We clamp t from [0,1] to handle points outside the segment vw.
float t = Mathf.Max(0, Mathf.Min(1, Vector3.Dot(p - v, w - v) / l2));
Vector3 projection = v + t * (w - v); // Projection falls on the segment
return Vector3.Distance(p, projection);
}
public static Vector3 MinComponents(Vector3 a, Vector3 b)
{
return new Vector3(Mathf.Min(a.x, b.x), Mathf.Min(a.y, b.y), Mathf.Min(a.z, b.z));
}
public static Vector3 MaxComponents(Vector3 a, Vector3 b)
{
return new Vector3(Mathf.Max(a.x, b.x), Mathf.Max(a.y, b.y), Mathf.Max(a.z, b.z));
}
public static Vector3 NormalizedOrZero(this Vector3 vec)
{
if (vec == Vector3.zero)
return Vector3.zero;
return vec.normalized;
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7988e4c48d3669647a4fdf11e186dc5c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,352 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
namespace SanAndreasUnity.Utilities
{
public class MovementAgent : MonoBehaviour
{
public NavMeshAgent NavMeshAgent { get; private set; }
private double m_lastTimeWhenSearchedForPath = 0f;
public Vector3? Destination { get; set; } = null;
private Vector3? m_lastAssignedDestination = null;
private Vector3? m_lastPositionWhenAssignedDestination = null;
private double m_lastTimeWhenWarped = 0f;
private double m_timeWhenSampledOffNavMesh = 0f;
public float warpSampleDistance = 4.5f;
public float[] destinationSampleDistances = new float[] { 3f, 8f, 100f };
public Vector3 DesiredDirection
{
get
{
if (!m_isMovingOffNavMesh)
return this.NavMeshAgent.desiredVelocity.NormalizedOrZero();
// agent is not on nav mesh
if (!this.Destination.HasValue && !m_sampledPosOffNavMesh.HasValue)
return Vector3.zero;
Vector3 myPosition = this.NavMeshAgent.transform.position;
float stoppingDistance = this.StoppingDistance;
// if we are in range of destination, don't move
if (this.Destination.HasValue && Vector3.Distance(this.Destination.Value, myPosition) <= stoppingDistance)
return Vector3.zero;
Vector3 effectiveDestination = m_sampledPosOffNavMesh ?? this.Destination.Value;
Vector3 diff = effectiveDestination - myPosition;
return diff.normalized;
}
}
public Vector3 DesiredDirectionXZ
{
get
{
Vector3 desiredDir = this.DesiredDirection;
if (desiredDir.y == 0f)
return desiredDir;
return desiredDir.WithXAndZ().NormalizedOrZero();
}
}
public Vector3? CalculatedDestination { get; private set; } = null;
private bool m_isMovingOffNavMesh = false;
private Vector3? m_sampledPosOffNavMesh = null;
public float StoppingDistance
{
get => this.NavMeshAgent.stoppingDistance;
set => this.NavMeshAgent.stoppingDistance = value;
}
void Awake()
{
this.NavMeshAgent = this.GetComponentOrThrow<NavMeshAgent>();
this.NavMeshAgent.updatePosition = false;
this.NavMeshAgent.updateRotation = false;
this.NavMeshAgent.updateUpAxis = false;
}
public void RunUpdate()
{
this.Update();
}
void Update()
{
NavMeshAgent agent = this.NavMeshAgent;
if (!agent.enabled)
{
this.ResetParams();
return;
}
double currentTime = Time.timeAsDouble;
Vector3 myPosition = agent.transform.position;
agent.nextPosition = myPosition;
Vector3 retreivedNextPosition = agent.nextPosition;
if (currentTime - m_lastTimeWhenWarped > 1f
&& (retreivedNextPosition.WithXAndZ() != myPosition.WithXAndZ() || !agent.isOnNavMesh))
{
m_lastTimeWhenWarped = currentTime;
// here we sample position to prevent Unity to spam with warning messages saying that agent is
// not close to nav mesh
if (NavMesh.SamplePosition(myPosition, out var hit, this.warpSampleDistance, agent.areaMask)
&& agent.Warp(myPosition))
{
if (this.Destination.HasValue && agent.isOnNavMesh)
{
this.SetDestination();
}
}
//Debug.Log($"warped agent {agent.name} - bWarp {bWarp}, isOnNavMesh {agent.isOnNavMesh}, pos diff {retreivedNextPosition - myPosition}, bSetDestination {bSetDestination}", this);
}
// no need to set velocity, it's automatically set by Agent
//this.NavMeshAgent.velocity = this.Velocity;
// update calculated destination
this.CalculatedDestination = agent.hasPath ? agent.destination : (Vector3?)null;
// if agent is off nav mesh, try to get it back
if (!agent.isOnNavMesh)
{
m_isMovingOffNavMesh = true; // immediately start moving when agent goes off the nav mesh
if (currentTime - m_timeWhenSampledOffNavMesh > 2.5f)
{
// try to sample position on nav mesh where agent could go
m_timeWhenSampledOffNavMesh = currentTime;
m_sampledPosOffNavMesh = null;
if (NavMesh.SamplePosition(myPosition, out var hit, 150f, agent.areaMask))
{
m_sampledPosOffNavMesh = hit.position;
}
//Debug.Log($"Tried to sample position off nav mesh - agent {agent.name}, sampled pos {m_sampledPosOffNavMesh}, distance {hit.distance}", this);
}
}
else
{
m_isMovingOffNavMesh = false;
m_sampledPosOffNavMesh = null;
}
if (!this.Destination.HasValue)
{
this.ResetParams();
return;
}
if (currentTime - m_lastTimeWhenSearchedForPath < 0.4f)
return;
if (agent.pathPending)
return;
if (!agent.isOnNavMesh)
return;
if (!m_lastAssignedDestination.HasValue)
{
this.SetDestination();
return;
}
// check if target position changed by some delta value (this value should depend on distance to target
// - if target is too far away, value should be higher)
Vector3 diffToTarget = this.Destination.Value - myPosition;
float distanceToTarget = diffToTarget.magnitude;
Vector3 deltaPos = this.Destination.Value - m_lastAssignedDestination.Value;
float deltaPosLength = deltaPos.magnitude;
// we require 10% change, with 1.5 as min
float requiredPosChange = Mathf.Max(distanceToTarget * 0.1f, 1.5f);
if (deltaPosLength > requiredPosChange)
{
this.SetDestination();
return;
}
// check if angle to target changed by some delta value (eg. 25 degrees)
// - this will make the ped turn fast in response to target changing movement direction
Vector3 lastDiffToTarget = m_lastAssignedDestination.Value - m_lastPositionWhenAssignedDestination.Value;
float angleDelta = Vector3.Angle(this.Destination.Value - m_lastPositionWhenAssignedDestination.Value, lastDiffToTarget);
if (angleDelta > 25f)
{
this.SetDestination();
return;
}
// regularly update path on some higher interval (eg. 5s)
// - this interval could also depend on distance to target
// from 5 to 12, with sqrt function, 150 as max distance
float regularUpdateInterval = 5 + 7 * Mathf.Clamp01(Mathf.Sqrt(Mathf.Min(distanceToTarget, 150f) / 150f));
if (currentTime - m_lastTimeWhenSearchedForPath > regularUpdateInterval
&& this.Destination.Value != m_lastAssignedDestination.Value)
{
this.SetDestination();
return;
}
// handle cases when destination changes by significant amount, but it's not recognized
// by "delta position" method above
// - this happens when position delta is too small, but Agent should still do re-path
// (for example, he needs to touch the destination object)
float deltaInPosition = (this.Destination.Value - m_lastAssignedDestination.Value).magnitude;
float currentDistance = (m_lastAssignedDestination.Value - myPosition).magnitude;
if (deltaInPosition > currentDistance)
{
Debug.Log($"delta pos higher than current distance - agent {agent.name}, delta {deltaInPosition}, current distance {currentDistance}", this);
this.SetDestination();
return;
}
// handle case caused by bug in NavMesh system - it can not calculate paths that are too
// long (or have too many corners). The path returned has status Partial, and it's final
// corner is not even close to destination. Not only that it doesn't return full path, but it actually
// returns path which contain closest point to destination, which can be totally wrong path.
// be careful not to mix this case with regular partial paths that happen because destination is really
// not reachable. This can actually happen quite often, if destination is, for example, on nearby roof.
float stoppingDistance = this.StoppingDistance;
float distanceToCalculatedDestination = this.CalculatedDestination.HasValue ? Vector3.Distance(this.CalculatedDestination.Value, myPosition) : float.PositiveInfinity;
float originalDistanceToCalculatedDestination = this.CalculatedDestination.HasValue ? Vector3.Distance(m_lastPositionWhenAssignedDestination.Value, this.CalculatedDestination.Value) : float.PositiveInfinity;
if (this.CalculatedDestination.HasValue
&& currentTime - m_lastTimeWhenSearchedForPath > 3f // seems like it's not needed, but just in case
&& originalDistanceToCalculatedDestination > 50f // this will make a difference between regular partial paths
&& originalDistanceToCalculatedDestination > stoppingDistance + 3f // also need to handle case when stopping distance is too large
&& (distanceToCalculatedDestination < 4f || distanceToCalculatedDestination <= stoppingDistance) // already stopped or close enough
&& agent.pathStatus == NavMeshPathStatus.PathPartial)
{
Debug.Log($"re-path due to bug in NavMesh system - agent {agent.name}, distanceToCalculatedDestination {distanceToCalculatedDestination}, originalDistanceToCalculatedDestination {originalDistanceToCalculatedDestination}", this);
this.SetDestination();
return;
}
// 2nd solution for problem above
float distanceTraveled = (myPosition - m_lastPositionWhenAssignedDestination.Value).magnitude;
if (currentTime - m_lastTimeWhenSearchedForPath > 3f
&& distanceTraveled > 200f
&& agent.pathStatus == NavMeshPathStatus.PathPartial)
{
Debug.Log($"re-path due to bug in NavMesh system #2 - agent {agent.name}, distanceTraveled {distanceTraveled}", this);
this.SetDestination();
return;
}
}
void SetDestination()
{
NavMeshAgent navMeshAgent = this.NavMeshAgent;
m_lastTimeWhenSearchedForPath = Time.timeAsDouble;
m_lastAssignedDestination = this.Destination.Value;
m_lastPositionWhenAssignedDestination = navMeshAgent.transform.position;
// here we need to sample position on navmesh first, because otherwise agent will fail
// to calculate path if target position is not on navmesh, and as a result he will be stopped
// there is a performance problem: if target position is on isolated part of navmesh,
// path calculation will take too long because the algorithm tries to go through all
// surrounding nodes, and in the meantime agent stays in place
// that's why we manually calculate path and assign it to agent - in this case, there is no waiting
// for path to be calculated asyncly, and agent starts moving immediately. The potential problem
// is that CalculatePath() can take 1-2 ms.
// TODO: performance optimization: this can be done "asyncly": register pathfinding request, and process
// requests from all agents in Update() function of some Manager script, with some time limit (eg. 1 ms)
if (this.SamplePosition(this.Destination.Value, this.destinationSampleDistances, out var hit))
{
// TODO: re-use NavMeshPath object
var navMeshPath = new NavMeshPath();
NavMesh.CalculatePath(navMeshAgent.nextPosition, hit.position, navMeshAgent.areaMask, navMeshPath);
navMeshAgent.path = navMeshPath;
this.CalculatedDestination = navMeshAgent.hasPath ? navMeshAgent.destination : (Vector3?)null;
}
else
{
// if position can not be sampled, we stop the agent
navMeshAgent.ResetPath();
this.CalculatedDestination = null;
}
}
private void ResetParams()
{
m_lastAssignedDestination = null;
m_lastPositionWhenAssignedDestination = null;
this.CalculatedDestination = null;
if (this.NavMeshAgent.hasPath)
this.NavMeshAgent.ResetPath();
}
private bool SamplePosition(Vector3 pos, float[] sampleDistances, out NavMeshHit hit)
{
int areaMask = this.NavMeshAgent.areaMask;
for (int i = 0; i < sampleDistances.Length; i++)
{
if (NavMesh.SamplePosition(pos, out hit, sampleDistances[i], areaMask))
return true;
}
hit = default;
return false;
}
private void OnDrawGizmosSelected()
{
if (null == this.NavMeshAgent)
return;
if (!this.NavMeshAgent.hasPath)
return;
Gizmos.color = Color.Lerp(Color.red, Color.black, 0.5f);
Vector3[] corners = this.NavMeshAgent.path.corners;
for (int i = 1; i < corners.Length; i++)
{
Gizmos.DrawWireSphere(corners[i], 0.75f);
Gizmos.DrawLine(corners[i - 1], corners[i]);
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: e5192eaa721a64d4c9e80632f38623ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5118
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,16 +0,0 @@
namespace SanAndreasUnity.Utilities
{
public class NetUtils
{
public static System.Func<bool> IsServerImpl = () => false;
public static bool IsServer => IsServerImpl();
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 30e28a51325bebb33982b6ac0217e1c1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5700
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,33 +0,0 @@
using System;
using System.Diagnostics;
namespace SanAndreasUnity.Utilities
{
public static class Profiler
{
private class ProfileFrame : IDisposable
{
private readonly string _name;
private readonly Stopwatch _timer;
public ProfileFrame(string name)
{
_name = name;
_timer = new Stopwatch();
_timer.Start();
}
public void Dispose()
{
_timer.Stop();
UnityEngine.Debug.LogFormat("{0}: {1:F2} ms", _name, _timer.Elapsed.TotalMilliseconds);
}
}
public static IDisposable Start(string name)
{
return new ProfileFrame(name);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 272dc48038f695d43acf0833c8a35c22
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5100
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,44 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class PushableByDamage : MonoBehaviour
{
public float forceMultiplier = 1;
private Damageable _damageable;
private void Awake()
{
_damageable = this.GetComponentOrThrow<Damageable>();
_damageable.OnDamageEvent.AddListener(this.OnDamaged);
}
void OnDamaged()
{
if (!NetUtils.IsServer)
return;
DamageInfo damageInfo = _damageable.LastDamageInfo;
if (damageInfo.damageType != DamageType.Bullet)
return;
if (null == damageInfo.raycastHitTransform)
return;
var c = damageInfo.raycastHitTransform.GetComponent<Collider>();
if (null == c)
return;
var rb = c.attachedRigidbody;
if (null == rb)
return;
rb.AddForceAtPosition(
damageInfo.hitDirection * damageInfo.amount.SqrtOrZero() * this.forceMultiplier,
damageInfo.hitPoint,
ForceMode.Impulse);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 4dafeb77b323d57489cc5b15183dc41b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5076
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,16 +0,0 @@
namespace SanAndreasUnity.Utilities
{
public class Ref<T>
{
public T value;
public Ref()
{
}
public Ref(T value)
{
this.value = value;
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 36af7629553cfad40afab00af2253f88
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,35 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class Rotator : MonoBehaviour {
public Vector3 angles = Vector3.zero;
public bool changeEulers = false;
void Update () {
Vector3 delta = this.angles * Time.deltaTime;
if (delta.sqrMagnitude < float.Epsilon)
return;
if (this.changeEulers) {
Vector3 eulers = this.transform.localEulerAngles;
eulers += delta;
this.transform.localEulerAngles = eulers;
} else {
this.transform.rotation *=
Quaternion.AngleAxis (delta.x, Vector3.right)
* Quaternion.AngleAxis (delta.y, Vector3.up)
* Quaternion.AngleAxis (delta.z, Vector3.forward);
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 42985861e4d9144258d49089df72c083
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5750
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,3 +0,0 @@
{
"name": "SanAndreasUnity.Utilities"
}

View file

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: e2bff2fa8d032b63b9d3231c79d6019c
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,116 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public static class SingletonConstants
{
public static readonly IReadOnlyList<string> nonAllowedMethodNames = new string[]
{
"Awake",
"OnEnable",
"OnDisable",
"Start",
};
}
public class SingletonComponent<T> : MonoBehaviour
where T : SingletonComponent<T>
{
#if !UNITY_EDITOR
public static T Singleton { get; private set; }
#else
private static T s_cachedSingleton;
public static T Singleton
{
get
{
if (!F.IsAppInEditMode)
{
return s_cachedSingleton;
}
if (s_cachedSingleton != null)
return s_cachedSingleton;
T[] objects = FindObjectsOfType<T>();
if (objects.Length == 0)
return null;
if (objects.Length > 1)
throw new Exception($"Found multiple singleton objects of type {typeof(T).Name}. Make sure there is only 1 singleton object created per type.");
s_cachedSingleton = objects[0];
return s_cachedSingleton;
}
private set
{
s_cachedSingleton = value;
}
}
#endif
protected SingletonComponent()
{
Type type = this.GetType();
var bindingFlags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic;
for (int i = 0; i < SingletonConstants.nonAllowedMethodNames.Count; i++)
{
string methodName = SingletonConstants.nonAllowedMethodNames[i];
var methodInfo = type.GetMethod(methodName, bindingFlags);
if (methodInfo != null)
throw new Exception($"{type.Name} is using non-allowed method {methodName}. Singletons should not have any of following methods: {string.Join(", ", SingletonConstants.nonAllowedMethodNames)}.");
}
}
private void Awake()
{
if (Singleton != null)
{
throw new Exception($"Awake() method called twice for singleton of type {this.GetType().Name}");
}
this.OnSingletonAwakeValidate();
Singleton = (T)this;
this.OnSingletonAwake();
}
protected virtual void OnSingletonAwake()
{
}
protected virtual void OnSingletonAwakeValidate()
{
}
private void OnDisable()
{
if (Singleton != this)
return;
this.OnSingletonDisable();
}
protected virtual void OnSingletonDisable()
{
}
private void Start()
{
if (this != Singleton)
return;
this.OnSingletonStart();
}
protected virtual void OnSingletonStart()
{
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 83a159913a6b77f4f939ea2f34da3a65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,16 +0,0 @@
using UnityEngine.SceneManagement;
namespace SanAndreasUnity.Utilities
{
public class StartupSingleton<T> : SingletonComponent<T>
where T : StartupSingleton<T>
{
protected override void OnSingletonAwakeValidate()
{
Scene activeScene = SceneManager.GetActiveScene();
if (!activeScene.IsValid() || activeScene.buildIndex != 0)
throw new System.Exception("Startup singleton can only be initialized in startup scene");
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 43e2ad434a43a4a4f8369aee19fed4b4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,68 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
/// <summary>
/// Container for <see cref="IState"/> objects.
/// </summary>
public class StateContainer<TState>
where TState : IState
{
private readonly List<TState> _states = new List<TState>();
public IReadOnlyList<TState> States => _states;
public TState GetState(System.Type type)
{
return this._states.FirstOrDefault (s => s.GetType ().Equals (type));
}
public T GetState<T>()
where T : TState
{
return (T) this.GetState(typeof(T));
}
public TState GetStateOrLogError(System.Type type)
{
var state = this.GetState (type);
if(null == state)
Debug.LogErrorFormat ("Failed to find state of type {0}", type);
return state;
}
public T GetStateOrLogError<T>()
where T : TState
{
return (T) this.GetStateOrLogError(typeof(T));
}
public T GetStateOrThrow<T>()
where T : TState
{
var state = this.GetState<T>();
if (null == state)
throw new ArgumentException($"Failed to find state of type {typeof(T).Name}");
return state;
}
public IEnumerable<TState> GetStatesThatInherit<TParent>()
where TParent : IState
{
return _states.OfType<TParent>().Cast<TState>();
}
public void AddState(TState stateToAdd)
{
_states.Add(stateToAdd);
}
public void AddStates(IEnumerable<TState> statesToAdd)
{
_states.AddRange(statesToAdd);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: e69f407670bd6c74cbedc3900bf033a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,61 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class StateMachine {
IState m_currentState;
public IState CurrentState { get { return m_currentState; } }
bool m_isSwitchingState = false;
public double TimeWhenSwitchedState { get; private set; }
public long FrameWhenSwitchedState { get; private set; }
public void SwitchStateWithParameter(IState newState, object parameterForEnteringState) {
if(m_isSwitchingState)
throw new System.Exception("Already switching state");
if (newState == m_currentState)
return;
m_isSwitchingState = true;
IState oldState = m_currentState;
m_currentState = newState;
if (oldState != null)
{
// need to catch exception here, because otherwise it would freeze the state machine - it would
// no longer be possible to switch states, because 'm_isSwitchingState' is true
F.RunExceptionSafe(() =>
{
oldState.LastTimeWhenDeactivated = Time.timeAsDouble;
oldState.OnBecameInactive();
});
}
m_isSwitchingState = false;
this.TimeWhenSwitchedState = Time.timeAsDouble;
this.FrameWhenSwitchedState = Time.frameCount;
if (m_currentState != null)
{
m_currentState.ParameterForEnteringState = parameterForEnteringState;
m_currentState.LastTimeWhenActivated = Time.timeAsDouble;
m_currentState.OnBecameActive();
}
}
public void SwitchState(IState newState)
{
this.SwitchStateWithParameter(newState, null);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 87049d4bb02fc4614b36c80bc088bc39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 11950
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,58 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SanAndreasUnity.Utilities
{
public class Stats
{
public class Entry
{
public string category = "";
public string text = null;
public System.Action<GetStatsContext> getStatsAction = null;
}
public class GetStatsContext
{
/// <summary>
/// This is where the stats should be stored.
/// </summary>
public readonly StringBuilder stringBuilder = new StringBuilder();
/// <summary>
/// If true, stats can be drawn using imGui, for slightly nicer output.
/// </summary>
public readonly bool isOnGui = false;
public GetStatsContext()
{
}
public GetStatsContext(bool isOnGui)
{
this.isOnGui = isOnGui;
}
public void AppendLine(string text) => this.stringBuilder.AppendLine(text);
public void AppendLine() => this.stringBuilder.AppendLine();
public void Append(string text) => this.stringBuilder.Append(text);
}
static Dictionary<string, List<Entry>> s_entries = new Dictionary<string, List<Entry>>();
public static IEnumerable<KeyValuePair<string, List<Entry>>> Entries => s_entries;
public static IEnumerable<string> Categories => s_entries.Select(pair => pair.Key);
public static UnityEngine.Rect DisplayRect { get; set; }
public static void RegisterStat(Entry entry)
{
if (s_entries.ContainsKey(entry.category))
s_entries[entry.category].Add(entry);
else
s_entries[entry.category] = new List<Entry>(){entry};
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 341c06175ec8b97e8a993ba8d30e82d2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 9250
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,14 +0,0 @@
using System;
using System.Threading;
namespace SanAndreasUnity.Utilities
{
public static class ThreadHelper
{
public static void ThrowIfNotOnMainThread()
{
if (Thread.CurrentThread.ManagedThreadId != 1)
throw new Exception("This can only be executed on the main thread");
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 8ed180a98e16c5a4cbcc059ace2bb0ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,36 +0,0 @@
using System;
using System.IO;
using System.Text;
namespace SanAndreasUnity.Utilities
{
public static class Tools
{
public static byte[] ReadBytes(this Stream self, int count)
{
var data = new byte[count];
for (var i = 0; i < count; ++i)
{
var bt = self.ReadByte();
if (bt == -1) throw new EndOfStreamException();
data[i] = (byte)bt;
}
return data;
}
public static String ReadString(this BinaryReader reader, int length)
{
var bytes = reader.ReadBytes(length);
return Encoding.UTF8.GetString(bytes).TrimNullChars();
}
public static String TrimNullChars(this String str)
{
for (var i = 0; i < str.Length; ++i) if (str[i] == '\0') return str.Substring(0, i);
return str;
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 9068ac64bca552f41a9d126b0ac27cca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 7950
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,36 +0,0 @@
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public struct TransformDataStruct
{
public Vector3 position;
public Quaternion rotation;
public Vector3 scale;
public TransformDataStruct(Vector3 position, Quaternion rotation, Vector3 scale)
{
this.position = position;
this.rotation = rotation;
this.scale = scale;
}
public TransformDataStruct(Vector3 position, Quaternion rotation) : this(position, rotation, Vector3.one)
{
}
public TransformDataStruct(Vector3 position) : this(position, Quaternion.identity)
{
}
public TransformDataStruct(Transform tr) : this(tr.position, tr.rotation, tr.lossyScale)
{
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 5a676040a6b851344acb77794d43843a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: cb808958b3d2238438ca3ce2ecaed75e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,92 +0,0 @@
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace SanAndreasUnity.Utilities
{
public class ArrowsMovementButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler, IDragHandler
{
public RawImage leftArrow, rightArrow, upArrow, downArrow;
bool m_isPointerDown = false;
public bool IsPointerDown => m_isPointerDown;
public bool IsPointerInside { get; private set; } = false;
public Vector2 LastPointerPos { get; private set; } = Vector2.zero;
void OnDisable()
{
m_isPointerDown = false;
this.IsPointerInside = false;
}
public void OnPointerDown(PointerEventData pointerEventData)
{
m_isPointerDown = true;
this.LastPointerPos = pointerEventData.position;
}
public void OnPointerUp(PointerEventData pointerEventData)
{
m_isPointerDown = false;
}
public void OnPointerEnter(PointerEventData pointerEventData)
{
this.IsPointerInside = true;
this.LastPointerPos = pointerEventData.position;
}
public void OnPointerExit(PointerEventData pointerEventData)
{
this.IsPointerInside = false;
}
public void OnDrag (PointerEventData pointerEventData)
{
this.LastPointerPos = pointerEventData.position;
}
public Vector2 GetMovementNonNormalized()
{
if (!m_isPointerDown || !this.IsPointerInside)
return Vector2.zero;
Vector2 pointerPos = this.LastPointerPos;
Vector2 localPoint = Vector2.zero;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(this.transform as RectTransform, pointerPos, null, out localPoint))
return Vector2.zero;
Vector2 diff = localPoint;
return diff;
}
public Vector2 GetMovement()
{
return this.GetMovementNonNormalized().normalized;
}
public Vector2 GetMovementPercentage()
{
Rect rect = (this.transform as RectTransform).rect;
float width = rect.width;
float height = rect.height;
if (width < float.Epsilon || height < float.Epsilon)
return Vector2.zero;
Vector2 diff = this.GetMovementNonNormalized();
float xPerc = diff.x / (width * 0.5f);
float yPerc = diff.y / (height * 0.5f);
xPerc = Mathf.Clamp(xPerc, -1f, 1f);
yPerc = Mathf.Clamp(yPerc, -1f, 1f);
return new Vector2(xPerc, yPerc);
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 8c4791292f9958a9fbed806e4ded7cfc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 10850
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,126 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
namespace SanAndreasUnity.Utilities
{
public class Bar : MonoBehaviour {
public Transform Border { get; private set; }
public Transform Background { get; private set; }
public Transform Fill { get; private set; }
public Renderer BorderRenderer { get; private set; }
public Renderer BackgroundRenderer { get; private set; }
public Renderer FillRenderer { get; private set; }
public Color BorderColor { get { return this.BorderRenderer.material.color; } set { this.BorderRenderer.material.color = value; } }
public Color BackgroundColor { get { return this.BackgroundRenderer.material.color; } set { this.BackgroundRenderer.material.color = value; } }
public Color FillColor { get { return this.FillRenderer.material.color; } set { this.FillRenderer.material.color = value; } }
[SerializeField] private Vector3 m_barSize = new Vector3 (1f, 0.2f, 1f);
public Vector3 BarSize { get { return m_barSize; } set { m_barSize = value; } }
[SerializeField] private float m_maxHeightOnScreen = 10f;
public float MaxHeightOnScreen { get { return m_maxHeightOnScreen; } set { m_maxHeightOnScreen = value; } }
public bool faceTowardsCamera = true;
void Awake ()
{
this.Border = this.transform.Find ("Border");
this.Background = this.transform.Find ("Background");
this.Fill = this.transform.Find ("Fill");
this.BorderRenderer = this.Border.GetComponent<Renderer> ();
this.BackgroundRenderer = this.Background.GetComponent<Renderer> ();
this.FillRenderer = this.Fill.GetComponent<Renderer> ();
}
void Update ()
{
Camera cam = Camera.main;
// update size
this.transform.SetGlobalScale (this.BarSize);
if (cam)
{
if (this.faceTowardsCamera)
{
// make rotation same as camera's rotation
this.transform.rotation = cam.transform.rotation;
if (this.MaxHeightOnScreen > 0)
{
// limit height on screen
// get current height on screen
Vector3 top = this.transform.position + this.transform.up * this.transform.lossyScale.y * 0.5f;
Vector3 bottom = this.transform.position - this.transform.up * this.transform.lossyScale.y * 0.5f;
Vector3 screenTop = cam.WorldToScreenPoint( top );
Vector3 screenBottom = cam.WorldToScreenPoint( bottom );
if (screenTop.z >= 0 && screenBottom.z >= 0)
{
float heightOnScreen = Mathf.Abs( screenTop.y - screenBottom.y );
if (heightOnScreen > this.MaxHeightOnScreen)
{
// reduce height of bar
float ratio = this.MaxHeightOnScreen / heightOnScreen;
Vector3 newSize = this.transform.lossyScale;
newSize.y *= ratio;
this.transform.SetGlobalScale( newSize );
}
}
}
}
}
}
public void SetFillPerc (float fillPerc)
{
fillPerc = Mathf.Clamp01 (fillPerc);
Vector3 scale = this.Fill.localScale;
scale.x = fillPerc;
this.Fill.localScale = scale;
// reposition it
Vector3 pos = this.Fill.localPosition;
pos.x = - (1.0f - fillPerc) / 2.0f;
this.Fill.localPosition = pos;
}
/*
public void SetBorderWidth (float borderWidth)
{
// borderWidthPerc = Mathf.Clamp (borderWidthPerc, 0f, 0.5f);
// stretch border to parent
this.Border.localScale = Vector3.one;
// reduce width and height of background and fill objects
Vector3 size = this.BarSize;
size.x -= borderWidth * 2;
size.y -= borderWidth * 2;
this.Background.SetGlobalScale( size );
this.Fill.SetGlobalScale( size );
}
*/
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: c7111f45c86a74947af5f6831ab01122
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 8550
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,37 +0,0 @@
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
namespace SanAndreasUnity.Utilities
{
public class CustomEventSystemForMixingIMGUIAndNewUI : EventSystem
{
bool m_wasAnyElementActiveLastFrame = false;
protected override void Start()
{
base.Start();
StartCoroutine(this.Coroutine());
}
IEnumerator Coroutine()
{
while (true)
{
yield return null;
m_wasAnyElementActiveLastFrame = GUIUtility.hotControl != 0;
}
}
protected override void Update()
{
if (!m_wasAnyElementActiveLastFrame)
base.Update();
}
}
}

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