Compare commits

...

13 Commits

Author SHA1 Message Date
fd68071416 修复一些遗漏 2025-12-16 17:54:29 +08:00
a530eba460 优化参数传递 2025-12-15 17:45:36 +08:00
32f0038e34 新增类型友好的名称打印 2025-12-15 11:36:06 +08:00
c12d4a3754 开始增加二进制序列化器 2025-12-12 17:45:25 +08:00
a3483f23d8 更新迭代器函数 2025-12-11 18:02:49 +08:00
3db8bde1c2 新增Avoid拆分协程 2025-12-09 18:00:47 +08:00
223df3fb91 新增性能容器 2025-12-05 16:25:40 +08:00
8e419a3257 退化File中读取二进制的功能用于修复bug 2025-12-03 14:35:12 +08:00
48965decbb 修复ActionStepCoroutineWrapper中的错误调用顺序 2025-12-02 16:54:58 +08:00
172b2af3ea 尝试一些优化 2025-12-02 14:24:00 +08:00
5cc1d2aabc 修复UnityEditor.Build的引用错误 2025-11-30 02:26:15 +08:00
0b562b7f65 新增宏的6000支持 2025-11-29 00:42:41 +08:00
ccb51f26c3 去除确认无效的内容 2025-11-28 17:40:42 +08:00
7 changed files with 1643 additions and 100 deletions

View File

@@ -109,6 +109,7 @@ namespace Convention.Experimental.Modules
} }
else else
{ {
Debug.LogError("This object does not belong to any pool.", instance);
throw new PublicType.GameException("This object does not belong to any pool."); throw new PublicType.GameException("This object does not belong to any pool.");
} }
} }

View File

@@ -32,7 +32,6 @@ MonoBehaviour:
assemblyNames: assemblyNames:
- Assembly-CSharp - Assembly-CSharp
- Assembly-CSharp-firstpass - Assembly-CSharp-firstpass
- Cinemachine
- Dreamteck.Splines - Dreamteck.Splines
- Dreamteck.Utilities - Dreamteck.Utilities
- EasySave3 - EasySave3

View File

@@ -1,5 +1,4 @@
using Convention.WindowsUI; using System;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@@ -8,9 +7,16 @@ using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using Convention.WindowsUI;
using Demo.Game;
using Unity.Collections;
using UnityEditor; using UnityEditor;
#if UNITY_EDITOR
using UnityEditor.Build;
#endif
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityEngine.UI; using UnityEngine.UI;
@@ -1268,7 +1274,11 @@ namespace Convention
#endif #endif
public static void InitExtensionEnv() public static void InitExtensionEnv()
{ {
UnityEngine.Application.quitting += () => CoroutineStarter = null; UnityEngine.Application.quitting += () =>
{
GameObject.Destroy(s_CoroutineStarter.gameObject);
s_CoroutineStarter = null;
};
InitExtensionEnvCalls(); InitExtensionEnvCalls();
GlobalConfig.InitExtensionEnv(); GlobalConfig.InitExtensionEnv();
@@ -1282,27 +1292,82 @@ namespace Convention
return MainThreadID == Thread.CurrentThread.ManagedThreadId; return MainThreadID == Thread.CurrentThread.ManagedThreadId;
} }
private static CoroutineMonoStarterUtil CoroutineStarter; private static CoroutineMonoStarterUtil s_CoroutineStarter;
private static CoroutineMonoStarterUtil CoroutineStarter
{
get
{
if (s_CoroutineStarter == null)
{
s_CoroutineStarter = new GameObject($"{nameof(ConventionUtility)}-{nameof(CoroutineStarter)}").AddComponent<CoroutineMonoStarterUtil>();
}
return s_CoroutineStarter;
}
}
public static GameObject Singleton => CoroutineStarter.gameObject; public static GameObject Singleton => CoroutineStarter.gameObject;
private class CoroutineMonoStarterUtil : MonoBehaviour private class CoroutineMonoStarterUtil : MonoBehaviour
{ {
internal float waitClock;
private void Update() private void Update()
{ {
waitClock = Time.realtimeSinceStartup;
MainThreadID = Thread.CurrentThread.ManagedThreadId; MainThreadID = Thread.CurrentThread.ManagedThreadId;
} }
private void OnDestroy() private void OnDestroy()
{ {
CoroutineStarter = null; s_CoroutineStarter = null;
}
}
/// <summary>
/// 包装即将用于协程的迭代器成为一个防止假死机的迭代器
/// </summary>
/// <param name="ir"></param>
/// <returns></returns>
public static IEnumerator AvoidFakeStop(IEnumerator ir, float fps = 5)
{
Stack<IEnumerator> loadingTask = new();
loadingTask.Push(ir);
float maxWaitClock = 1 / fps;
while (loadingTask.Count > 0)
{
// 防止大量无延迟函数的使用导致假死机
//if (Time.realtimeSinceStartup - CoroutineStarter.waitClock > maxWaitClock)
{
yield return null;
}
if (loadingTask.Peek().MoveNext())
{
if (loadingTask.Peek().Current is IEnumerator next)
loadingTask.Push(next);
}
else
{
loadingTask.Pop();
}
}
}
/// <summary>
/// 包装即将用于协程的迭代器成为一个防止假死机的迭代器
/// </summary>
/// <param name="ir"></param>
/// <returns></returns>
public static IEnumerator AvoidFakeStopWithoutDeepStack(IEnumerator ir, float fps = 5)
{
float maxWaitClock = 1 / fps;
while (ir.MoveNext())
{
// 防止大量无延迟函数的使用导致假死机
if (Time.realtimeSinceStartup - CoroutineStarter.waitClock > maxWaitClock)
{
yield return null;
}
} }
} }
public static Coroutine StartCoroutine(IEnumerator coroutine) public static Coroutine StartCoroutine(IEnumerator coroutine)
{ {
if (CoroutineStarter == null)
{
CoroutineStarter = new GameObject($"{nameof(ConventionUtility)}-{nameof(CoroutineStarter)}").AddComponent<CoroutineMonoStarterUtil>();
}
return CoroutineStarter.StartCoroutine(coroutine); return CoroutineStarter.StartCoroutine(coroutine);
} }
public static void CloseCoroutine(Coroutine coroutine) public static void CloseCoroutine(Coroutine coroutine)
@@ -1316,28 +1381,30 @@ namespace Convention
public class ActionStepCoroutineWrapper public class ActionStepCoroutineWrapper
{ {
private class YieldInstructionWrapper private struct YieldInstructionWrapper
{ {
public YieldInstruction UnityYieldInstruction; public YieldInstruction UnityYieldInstruction;
public CustomYieldInstruction CustomYieldInstruction; public CustomYieldInstruction CustomYieldInstruction;
public YieldInstructionWrapper() public YieldInstructionWrapper(YieldInstruction unityYieldInstruction, CustomYieldInstruction customYieldInstruction)
{
}
public YieldInstructionWrapper(YieldInstruction unityYieldInstruction)
{ {
this.UnityYieldInstruction = unityYieldInstruction; this.UnityYieldInstruction = unityYieldInstruction;
this.CustomYieldInstruction = customYieldInstruction;
} }
public YieldInstructionWrapper(CustomYieldInstruction customYieldInstruction) public static YieldInstructionWrapper Make(YieldInstruction unityYieldInstruction)
{ {
this.CustomYieldInstruction = customYieldInstruction; return new(unityYieldInstruction, null);
}
public static YieldInstructionWrapper Make(CustomYieldInstruction customYieldInstruction)
{
return new(null, customYieldInstruction);
} }
} }
private List<KeyValuePair<YieldInstructionWrapper, Action>> steps = new(); private List<KeyValuePair<YieldInstructionWrapper, Action>> steps = new();
public ActionStepCoroutineWrapper Update(Action action) public ActionStepCoroutineWrapper Update(Action action)
{ {
steps.Add(new(new(), action)); steps.Add(new(new(), action));
@@ -1345,33 +1412,33 @@ namespace Convention
} }
public ActionStepCoroutineWrapper Wait(float time, Action action) public ActionStepCoroutineWrapper Wait(float time, Action action)
{ {
steps.Add(new(new(new WaitForSeconds(time)), action)); steps.Add(new(YieldInstructionWrapper.Make(new WaitForSeconds(time)), action));
return this; return this;
} }
public ActionStepCoroutineWrapper FixedUpdate(Action action) public ActionStepCoroutineWrapper FixedUpdate(Action action)
{ {
steps.Add(new(new (new WaitForFixedUpdate()), action)); steps.Add(new(YieldInstructionWrapper.Make(new WaitForFixedUpdate()), action));
return this; return this;
} }
public ActionStepCoroutineWrapper Next(Action action) public ActionStepCoroutineWrapper Next(Action action)
{ {
steps.Add(new(new(new WaitForEndOfFrame()), action)); steps.Add(new(YieldInstructionWrapper.Make(new WaitForEndOfFrame()), action));
return this; return this;
} }
public ActionStepCoroutineWrapper Until(Func<bool> pr, Action action) public ActionStepCoroutineWrapper Until(Func<bool> pr, Action action)
{ {
steps.Add(new(new(new WaitUntil(pr)), action)); steps.Add(new(YieldInstructionWrapper.Make(new WaitUntil(pr)), action));
return this; return this;
} }
private static IEnumerator Execute(List<KeyValuePair<YieldInstructionWrapper, Action>> steps) private static IEnumerator Execute(List<KeyValuePair<YieldInstructionWrapper, Action>> steps)
{ {
foreach (var (waiting, action) in steps) foreach (var (waiting, action) in steps)
{ {
action();
if (waiting.UnityYieldInstruction != null) if (waiting.UnityYieldInstruction != null)
yield return waiting.UnityYieldInstruction; yield return waiting.UnityYieldInstruction;
else else
yield return waiting.CustomYieldInstruction; yield return waiting.CustomYieldInstruction;
action();
} }
} }
~ActionStepCoroutineWrapper() ~ActionStepCoroutineWrapper()
@@ -2199,6 +2266,39 @@ namespace Convention
public static class ScriptingDefineUtility public static class ScriptingDefineUtility
{ {
#if UNITY_EDITOR #if UNITY_EDITOR
#if UNITY_6000_0_OR_NEWER
public static void Add(string define, NamedBuildTarget target, bool log = false)
{
string definesString = PlayerSettings.GetScriptingDefineSymbols(target);
if (definesString.Contains(define)) return;
string[] allDefines = definesString.Split(';');
ArrayUtility.Add(ref allDefines, define);
definesString = string.Join(";", allDefines);
PlayerSettings.SetScriptingDefineSymbols(target, definesString);
Debug.Log("Added \"" + define + "\" from " + EditorUserBuildSettings.selectedBuildTargetGroup + " Scripting define in Player Settings");
}
public static void Remove(string define, NamedBuildTarget target, bool log = false)
{
string definesString = PlayerSettings.GetScriptingDefineSymbols(target);
if (!definesString.Contains(define)) return;
string[] allDefines = definesString.Split(';');
ArrayUtility.Remove(ref allDefines, define);
definesString = string.Join(";", allDefines);
PlayerSettings.SetScriptingDefineSymbols(target, definesString);
Debug.Log("Removed \"" + define + "\" from " + EditorUserBuildSettings.selectedBuildTargetGroup + " Scripting define in Player Settings");
}
public static void Add(string define, BuildTargetGroup target, bool log = false)
{
Add(define, NamedBuildTarget.FromBuildTargetGroup(target), log);
}
public static void Remove(string define, BuildTargetGroup target, bool log = false)
{
Remove(define, NamedBuildTarget.FromBuildTargetGroup(target), log);
}
#else
public static void Add(string define, BuildTargetGroup target, bool log = false) public static void Add(string define, BuildTargetGroup target, bool log = false)
{ {
string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(target); string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(target);
@@ -2220,6 +2320,8 @@ namespace Convention
PlayerSettings.SetScriptingDefineSymbolsForGroup(target, definesString); PlayerSettings.SetScriptingDefineSymbolsForGroup(target, definesString);
Debug.Log("Removed \"" + define + "\" from " + EditorUserBuildSettings.selectedBuildTargetGroup + " Scripting define in Player Settings"); Debug.Log("Removed \"" + define + "\" from " + EditorUserBuildSettings.selectedBuildTargetGroup + " Scripting define in Player Settings");
} }
#endif
#endif #endif
} }
} }
@@ -2444,33 +2546,6 @@ namespace Convention
} }
} }
namespace Convention
{
public static partial class ConventionUtility
{
/// <summary>
/// Unity engine function to disable the GC
/// </summary>
public static void GC_disable()
{
#if !UNITY_EDITOR
GarbageCollector.GCMode = GarbageCollector.Mode.Disabled;
#endif
}
/// <summary>
/// Unity engine function to enable the GC
/// </summary>
public static void GC_enable()
{
#if !UNITY_EDITOR
GarbageCollector.GCMode = GarbageCollector.Mode.Enabled;
#endif
}
}
}
namespace Convention namespace Convention
{ {
public static partial class Utility public static partial class Utility
@@ -2526,3 +2601,441 @@ namespace Convention
} }
} }
namespace Convention
{
public static class BinarySerializeUtility
{
#region Base
public static void WriteBool(BinaryWriter writer, bool data)
{
writer.Write(data);
}
public static bool ReadBool(BinaryReader reader)
{
return reader.ReadBoolean();
}
public static void WriteInt(BinaryWriter writer, in int data)
{
writer.Write(data);
}
public static int ReadInt(BinaryReader reader)
{
return reader.ReadInt32();
}
public static void WriteFloat(BinaryWriter writer, in float data)
{
writer.Write(data);
}
public static float ReadFloat(BinaryReader reader)
{
return reader.ReadSingle();
}
public static void WriteChar(BinaryWriter writer, in char data)
{
writer.Write(data);
}
public static char ReadChar(BinaryReader reader)
{
return reader.ReadChar();
}
public static void WriteString(BinaryWriter writer, in string data)
{
writer.Write(data ?? "");
}
public static string ReadString(BinaryReader reader)
{
return reader.ReadString();
}
public static void WriteVec3(BinaryWriter writer, in Vector3 data)
{
writer.Write(data.x);
writer.Write(data.y);
writer.Write(data.z);
}
public static Vector3 ReadVec3(BinaryReader reader)
{
float x, y, z;
x = reader.ReadSingle();
y = reader.ReadSingle();
z = reader.ReadSingle();
return new Vector3(x, y, z);
}
public static void WriteVec2(BinaryWriter writer, in Vector2 data)
{
writer.Write(data.x);
writer.Write(data.y);
}
public static Vector2 ReadVec2(BinaryReader reader)
{
float x, y;
x = reader.ReadSingle();
y = reader.ReadSingle();
return new Vector2(x, y);
}
public static void WriteColor(BinaryWriter writer, in Color data)
{
writer.Write(data.r);
writer.Write(data.g);
writer.Write(data.b);
writer.Write(data.a);
}
public static Color ReadColor(BinaryReader reader)
{
float r, g, b, a;
r = reader.ReadSingle();
g = reader.ReadSingle();
b = reader.ReadSingle();
a = reader.ReadSingle();
return new(r, g, b, a);
}
#endregion
#region Serialize
#region Int
public static void SerializeNativeArray(BinaryWriter writer, in NativeArray<int> array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
writer.Write(array[start++]);
}
}
public static int DeserializeNativeArray(BinaryReader reader, ref NativeArray<int> array)
{
int count = reader.ReadInt32();
if (array.Length < count)
array.ResizeArray(count);
for (int i = 0; i < count; i++)
{
array[i] = reader.ReadInt32();
}
return count;
}
public static void SerializeArray(BinaryWriter writer, in int[] array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
writer.Write(array[start++]);
}
}
public static int[] DeserializeIntArray(BinaryReader reader)
{
int count = reader.ReadInt32();
int[] array = new int[count];
for (int i = 0; i < count; i++)
{
array[i] = reader.ReadInt32();
}
return array;
}
#endregion
#region Float
public static void SerializeNativeArray(BinaryWriter writer, in NativeArray<float> array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
writer.Write(array[start++]);
}
}
public static int DeserializeNativeArray(BinaryReader reader, ref NativeArray<float> array)
{
int count = reader.ReadInt32();
if (array.Length < count)
array.ResizeArray(count);
for (int i = 0; i < count; i++)
{
array[i] = reader.ReadSingle();
}
return count;
}
public static void SerializeArray(BinaryWriter writer, in float[] array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
writer.Write(array[start++]);
}
}
public static float[] DeserializeFloatArray(BinaryReader reader)
{
int count = reader.ReadInt32();
float[] array = new float[count];
for (int i = 0; i < count; i++)
{
array[i] = reader.ReadSingle();
}
return array;
}
#endregion
#region String
public static void SerializeArray(BinaryWriter writer, in string[] array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
writer.Write(array[start++] ?? "");
}
}
public static string[] DeserializeStringArray(BinaryReader reader)
{
int count = reader.ReadInt32();
string[] array = new string[count];
for (int i = 0; i < count; i++)
{
array[i] = reader.ReadString();
}
return array;
}
#endregion
#region Vector3
public static void SerializeNativeArray(BinaryWriter writer, in NativeArray<Vector3> array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
writer.Write(array[start].x);
writer.Write(array[start].y);
writer.Write(array[start].z);
start++;
}
}
public static int DeserializeNativeArray(BinaryReader reader, ref NativeArray<Vector3> array)
{
int count = reader.ReadInt32();
if (array.Length < count)
array.ResizeArray(count);
float x, y, z;
for (int i = 0; i < count; i++)
{
x = reader.ReadSingle();
y = reader.ReadSingle();
z = reader.ReadSingle();
array[i] = new(x, y, z);
}
return count;
}
public static void SerializeArray(BinaryWriter writer, in Vector3[] array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
writer.Write(array[start].x);
writer.Write(array[start].y);
writer.Write(array[start].z);
start++;
}
}
public static Vector3[] DeserializeVec3Array(BinaryReader reader, int start = 0)
{
int count = reader.ReadInt32();
Vector3[] array = new Vector3[count];
float x, y, z;
for (int i = 0; i < count; i++)
{
x = reader.ReadSingle();
y = reader.ReadSingle();
z = reader.ReadSingle();
array[start + i] = new(x, y, z);
}
return array;
}
#endregion
#region Vector2
public static void SerializeNativeArray(BinaryWriter writer, in NativeArray<Vector2> array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
writer.Write(array[start].x);
writer.Write(array[start].y);
start++;
}
}
public static int DeserializeNativeArray(BinaryReader reader, ref NativeArray<Vector2> array)
{
int count = reader.ReadInt32();
if (array.Length < count)
array.ResizeArray(count);
float x, y;
for (int i = 0; i < count; i++)
{
x = reader.ReadSingle();
y = reader.ReadSingle();
array[i] = new(x, y);
}
return count;
}
public static void SerializeArray(BinaryWriter writer, in Vector2[] array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
writer.Write(array[start].x);
writer.Write(array[start].y);
start++;
}
}
public static Vector2[] DeserializeVec2Array(BinaryReader reader)
{
int count = reader.ReadInt32();
Vector2[] array = new Vector2[count];
float x, y;
for (int i = 0; i < count; i++)
{
x = reader.ReadSingle();
y = reader.ReadSingle();
array[i] = new(x, y);
}
return array;
}
#endregion
#region Color
public static void SerializeNativeArray(BinaryWriter writer, in NativeArray<Color> array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
WriteColor(writer, array[start]);
start++;
}
}
public static int DeserializeNativeArray(BinaryReader reader, ref NativeArray<Color> array)
{
int count = reader.ReadInt32();
if (array.Length < count)
array.ResizeArray(count);
float x, y, z;
for (int i = 0; i < count; i++)
{
array[i] = ReadColor(reader);
}
return count;
}
public static void SerializeArray(BinaryWriter writer, in Color[] array, int start = 0, int end = int.MaxValue)
{
int e = Mathf.Min(array.Length, end);
writer.Write(e - start);
while (start < e)
{
WriteColor(writer, array[start]);
start++;
}
}
public static Color[] DeserializeVec3Array(BinaryReader reader)
{
int count = reader.ReadInt32();
Color[] array = new Color[count];
float x, y, z;
for (int i = 0; i < count; i++)
{
array[i] = ReadColor(reader);
}
return array;
}
#endregion
#endregion
}
public static partial class Utility
{
/// <summary>
/// 获取类型的友好显示名称,支持泛型、数组等复杂类型
/// </summary>
public static string GetFriendlyName(this Type type)
{
if (type == null) return null;
// 处理泛型类型
if (type.IsGenericType)
{
// 特殊处理可空类型Nullable<T>
if (type.IsNullable())
{
return $"{GetFriendlyName(type.GetGenericArguments()[0])}?";
}
var sb = new StringBuilder();
// 获取类型基础名称(移除 `1, `2 等后缀)
string baseName = type.Name.Contains('`') ? type.Name[..type.Name.IndexOf('`')] : type.Name;
sb.Append(baseName);
sb.Append('<');
// 递归处理泛型参数
Type[] args = type.GetGenericArguments();
for (int i = 0; i < args.Length; i++)
{
if (i > 0) sb.Append(", ");
sb.Append(GetFriendlyName(args[i]));
}
sb.Append('>');
return sb.ToString();
}
// 处理数组类型
if (type.IsArray)
{
string elementName = GetFriendlyName(type.GetElementType());
int rank = type.GetArrayRank();
return rank == 1 ? $"{elementName}[]" : $"{elementName}[{new string(',', rank - 1)}]";
}
// 处理指针类型
if (type.IsPointer)
{
return $"{GetFriendlyName(type.GetElementType())}*";
}
// 处理引用类型ref/out 参数)
if (type.IsByRef)
{
return $"{GetFriendlyName(type.GetElementType())}&";
}
// 普通类型直接返回名称
return type.Name;
}
/// <summary>
/// 判断是否为可空类型
/// </summary>
public static bool IsNullable(this Type type)
{
return type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Unity.Collections;
namespace Convention.Collections namespace Convention.Collections
{ {
@@ -453,4 +454,985 @@ namespace Convention.Collections
} }
} }
} }
namespace Cache
{
/// <summary>
/// Native LRUCache - <20><><EFBFBD><EFBFBD>Unity.Collections<6E>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>û<EFBFBD><C3BB><EFBFBD>
/// Burst<73><74><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD>Ҫ<EFBFBD>ֶ<EFBFBD>Dispose
/// </summary>
/// <typeparam name="TKey"><3E><><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>unmanaged<65><64><EFBFBD>ͣ<EFBFBD></typeparam>
/// <typeparam name="TValue">ֵ<><D6B5><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>unmanaged<65><64><EFBFBD>ͣ<EFBFBD></typeparam>
public struct NativeLRUCache<TKey, TValue> : IDisposable
where TKey : unmanaged, IEquatable<TKey>
where TValue : unmanaged
{
// <20><><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>
private struct Node
{
public TKey key;
public TValue value;
public int prevIndex; // ǰһ<C7B0><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
public int nextIndex; // <20><>һ<EFBFBD><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
}
private NativeList<Node> nodes; // <20>ڵ<EFBFBD><DAB5><EFBFBD>
private readonly NativeHashMap<TKey, int> hashMap; // key -> <20>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
private readonly NativeList<int> freeList; // <20><><EFBFBD>нڵ<D0BD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
private readonly int capacity;
private int headIndex; // <20><><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δʹ<CEB4>ã<EFBFBD>
private int tailIndex; // <20><><EFBFBD><EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD>
private int count;
// <20>Ƿ<EFBFBD>Ϊ<EFBFBD><CEAA>Ч<EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
private readonly bool IsValidIndex(int index) => index >= 0;
public NativeLRUCache(int capacity, Allocator allocator)
{
this.capacity = capacity;
this.count = 0;
this.headIndex = -1;
this.tailIndex = -1;
hashMap = new NativeHashMap<TKey, int>(capacity, allocator);
nodes = new NativeList<Node>(capacity, allocator);
freeList = new NativeList<int>(capacity, allocator);
// Ԥ<><D4A4><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>
nodes.Length = capacity;
for (int i = capacity - 1; i >= 0; i--)
{
freeList.Add(i);
}
}
/// <summary>
/// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ֵ
/// </summary>
public bool TryGetValue(TKey key, out TValue value)
{
if (hashMap.TryGetValue(key, out int nodeIndex))
{
MoveToTail(nodeIndex); // <20>ƶ<EFBFBD><C6B6><EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD>
value = nodes[nodeIndex].value;
return true;
}
value = default;
return false;
}
/// <summary>
/// <20><><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD>»<EFBFBD><C2BB><EFBFBD>
/// </summary>
public void Put(TKey key, TValue value)
{
// <20>Ѵ<EFBFBD><D1B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>²<EFBFBD><C2B2>ƶ<EFBFBD><C6B6><EFBFBD>β<EFBFBD><CEB2>
if (hashMap.TryGetValue(key, out int nodeIndex))
{
Node node = nodes[nodeIndex];
node.value = value;
nodes[nodeIndex] = node;
MoveToTail(nodeIndex);
return;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̭ͷ<CCAD><CDB7><EFBFBD>ڵ<EFBFBD>
if (count >= capacity)
{
EvictHead();
}
// <20><><EFBFBD><EFBFBD><EFBFBD>½ڵ<C2BD>
nodeIndex = AllocateNode();
nodes[nodeIndex] = new Node
{
key = key,
value = value,
prevIndex = tailIndex,
nextIndex = -1
};
hashMap.Add(key, nodeIndex);
AddToTail(nodeIndex);
count++;
}
/// <summary>
/// ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public bool Remove(TKey key)
{
if (!hashMap.TryGetValue(key, out int nodeIndex))
return false;
hashMap.Remove(key);
RemoveFromList(nodeIndex);
FreeNode(nodeIndex);
count--;
return true;
}
/// <summary>
/// <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD>
/// </summary>
public void Clear()
{
hashMap.Clear();
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>нڵ㵽<DAB5><E3B5BD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
freeList.Clear();
for (int i = 0; i < capacity; i++)
{
freeList.Add(i);
}
headIndex = -1;
tailIndex = -1;
count = 0;
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
private readonly int AllocateNode()
{
int index = freeList[^1];
freeList.RemoveAtSwapBack(freeList.Length - 1);
return index;
}
// <20>ͷŽڵ<C5BD><DAB5><EFBFBD><EFBFBD><EFBFBD>
private readonly void FreeNode(int index)
{
freeList.Add(index);
}
// <20><><EFBFBD>ڵ<EFBFBD><DAB5>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD>
private void MoveToTail(int nodeIndex)
{
if (nodeIndex == tailIndex)
return;
RemoveFromList(nodeIndex);
AddToTail(nodeIndex);
}
// <20><><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD>ӵ<EFBFBD>β<EFBFBD><CEB2>
private void AddToTail(int nodeIndex)
{
Node node = nodes[nodeIndex];
node.prevIndex = tailIndex;
node.nextIndex = -1;
nodes[nodeIndex] = node;
if (IsValidIndex(tailIndex))
{
Node tail = nodes[tailIndex];
tail.nextIndex = nodeIndex;
nodes[tailIndex] = tail;
}
tailIndex = nodeIndex;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>գ<EFBFBD>ͷβָ<CEB2><D6B8>ͬһ<CDAC>ڵ<EFBFBD>
if (!IsValidIndex(headIndex))
{
headIndex = nodeIndex;
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><C6B3>ڵ<EFBFBD>
private void RemoveFromList(int nodeIndex)
{
Node node = nodes[nodeIndex];
// <20><><EFBFBD><EFBFBD>ǰһ<C7B0><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>nextָ<74><D6B8>
if (IsValidIndex(node.prevIndex))
{
Node prev = nodes[node.prevIndex];
prev.nextIndex = node.nextIndex;
nodes[node.prevIndex] = prev;
}
else
{
// û<><C3BB>ǰһ<C7B0><D2BB><EFBFBD>ڵ㣬˵<E3A3AC><CBB5><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ<EFBFBD>
headIndex = node.nextIndex;
}
// <20><><EFBFBD>º<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>prevָ<76><D6B8>
if (IsValidIndex(node.nextIndex))
{
Node next = nodes[node.nextIndex];
next.prevIndex = node.prevIndex;
nodes[node.nextIndex] = next;
}
else
{
// û<>к<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ڵ㣬˵<E3A3AC><CBB5><EFBFBD><EFBFBD>β<EFBFBD>ڵ<EFBFBD>
tailIndex = node.prevIndex;
}
}
// <20><>̭ͷ<CCAD><CDB7><EFBFBD>ڵ㣨<DAB5><E3A3A8><EFBFBD><EFBFBD>δʹ<CEB4>ã<EFBFBD>
private void EvictHead()
{
if (!IsValidIndex(headIndex)) return;
int oldHead = headIndex;
Node headNode = nodes[oldHead];
hashMap.Remove(headNode.key);
headIndex = headNode.nextIndex;
if (IsValidIndex(headIndex))
{
Node newHead = nodes[headIndex];
newHead.prevIndex = -1;
nodes[headIndex] = newHead;
}
else
{
tailIndex = -1; // <20><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>
}
FreeNode(oldHead);
count--;
}
public void Dispose()
{
if (hashMap.IsCreated) hashMap.Dispose();
if (nodes.IsCreated) nodes.Dispose();
if (freeList.IsCreated) freeList.Dispose();
headIndex = -1;
tailIndex = -1;
count = 0;
}
// <20><><EFBFBD>Է<EFBFBD><D4B7><EFBFBD><EFBFBD><EFBFBD>
public readonly int Count => count;
public readonly int Capacity => capacity;
public readonly bool IsCreated => hashMap.IsCreated;
}
/// <summary>
/// Native LFUCache - <20><><EFBFBD><EFBFBD>Unity.Collections<6E>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EEB2BB><C6B5>ʹ<EFBFBD>û<EFBFBD><C3BB><EFBFBD>
/// Burst<73><74><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD>Ҫ<EFBFBD>ֶ<EFBFBD>Dispose
/// </summary>
/// <typeparam name="TKey"><3E><><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>unmanaged<65><64><EFBFBD>ͣ<EFBFBD></typeparam>
/// <typeparam name="TValue">ֵ<><D6B5><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>unmanaged<65><64><EFBFBD>ͣ<EFBFBD></typeparam>
public struct NativeLFUCache<TKey, TValue> : IDisposable
where TKey : unmanaged, IEquatable<TKey>
where TValue : unmanaged
{
// <20><><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>
private struct Node
{
public TKey key;
public TValue value;
public int frequency; // <20><><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5>
public int prevIndex; // ͬƵ<CDAC><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD>ǰһ<C7B0><D2BB><EFBFBD>ڵ<EFBFBD>
public int nextIndex; // ͬƵ<CDAC><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еĺ<D0B5>һ<EFBFBD><D2BB><EFBFBD>ڵ<EFBFBD>
}
// Ƶ<><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷβ
private struct FrequencyList
{
public int headIndex; // <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ㣨<DAB5><E3A3A8><EFBFBD><EFBFBD>δʹ<CEB4>ã<EFBFBD>
public int tailIndex; // <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD>ڵ㣨<DAB5><E3A3A8><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD>
public readonly bool IsEmpty => headIndex == -1;
}
private readonly NativeHashMap<TKey, int> keyToNodeIndex; // key -> nodeIndex
private NativeList<Node> nodes; // <20>ڵ<EFBFBD><DAB5><EFBFBD>
private readonly NativeList<int> freeList; // <20><><EFBFBD>нڵ<D0BD><DAB5><EFBFBD><EFBFBD><EFBFBD>
private NativeHashMap<int, FrequencyList> freqToList; // frequency -> FrequencyList
private readonly int capacity;
private int count;
private int minFrequency; // <20><>ǰ<EFBFBD><C7B0>СƵ<D0A1><C6B5>
public NativeLFUCache(int capacity, Allocator allocator)
{
this.capacity = capacity;
this.count = 0;
this.minFrequency = 0;
keyToNodeIndex = new NativeHashMap<TKey, int>(capacity, allocator);
nodes = new NativeList<Node>(capacity, allocator);
freeList = new NativeList<int>(capacity, allocator);
freqToList = new NativeHashMap<int, FrequencyList>(capacity, allocator);
// Ԥ<><D4A4><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>
nodes.Length = capacity;
for (int i = capacity - 1; i >= 0; i--)
{
freeList.Add(i);
}
}
/// <summary>
/// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5>
/// </summary>
public bool TryGetValue(TKey key, out TValue value)
{
if (keyToNodeIndex.TryGetValue(key, out int nodeIndex))
{
// <20><><EFBFBD>ӷ<EFBFBD><D3B7><EFBFBD>Ƶ<EFBFBD><C6B5>
IncreaseFrequency(nodeIndex);
value = nodes[nodeIndex].value;
return true;
}
value = default;
return false;
}
/// <summary>
/// <20><><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD>»<EFBFBD><C2BB><EFBFBD>
/// </summary>
public void Put(TKey key, TValue value)
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
if (keyToNodeIndex.TryGetValue(key, out int nodeIndex))
{
Node node = nodes[nodeIndex];
node.value = value;
nodes[nodeIndex] = node;
IncreaseFrequency(nodeIndex);
return;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̭<EFBFBD><CCAD>СƵ<D0A1>ʵĽڵ<C4BD>
if (count >= capacity)
{
EvictMinFrequencyNode();
}
// <20><><EFBFBD><EFBFBD><EFBFBD>½ڵ㣬<DAB5><E3A3AC>ʼƵ<CABC><C6B5>Ϊ1
nodeIndex = AllocateNode();
nodes[nodeIndex] = new Node
{
key = key,
value = value,
frequency = 1,
prevIndex = -1,
nextIndex = -1
};
keyToNodeIndex.Add(key, nodeIndex);
AddToFrequencyList(nodeIndex, 1);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>СƵ<D0A1><C6B5>
if (minFrequency == 0)
{
minFrequency = 1;
}
count++;
}
/// <summary>
/// ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public bool Remove(TKey key)
{
if (!keyToNodeIndex.TryGetValue(key, out int nodeIndex))
return false;
RemoveNode(nodeIndex);
return true;
}
/// <summary>
/// <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD>
/// </summary>
public void Clear()
{
keyToNodeIndex.Clear();
freqToList.Clear();
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>нڵ㵽<DAB5><E3B5BD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
freeList.Clear();
for (int i = 0; i < capacity; i++)
{
freeList.Add(i);
}
minFrequency = 0;
count = 0;
}
/// <summary>
/// <20>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>
/// </summary>
public void Dispose()
{
if (keyToNodeIndex.IsCreated) keyToNodeIndex.Dispose();
if (nodes.IsCreated) nodes.Dispose();
if (freeList.IsCreated) freeList.Dispose();
if (freqToList.IsCreated) freqToList.Dispose();
minFrequency = 0;
count = 0;
}
#region <EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
private int AllocateNode()
{
int index = freeList[^1];
freeList.RemoveAtSwapBack(freeList.Length - 1);
return index;
}
private void FreeNode(int index)
{
freeList.Add(index);
}
/// <summary>
/// <20><><EFBFBD>ӽڵ<D3BD><DAB5>ķ<EFBFBD><C4B7><EFBFBD>Ƶ<EFBFBD><C6B5>
/// </summary>
private void IncreaseFrequency(int nodeIndex)
{
Node node = nodes[nodeIndex];
int oldFreq = node.frequency;
int newFreq = oldFreq + 1;
// <20>Ӿ<EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD>
RemoveFromFrequencyList(nodeIndex, oldFreq);
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>СƵ<D0A1><C6B5>
if (oldFreq == minFrequency && GetFrequencyListHead(oldFreq) == -1)
{
minFrequency = newFreq;
}
// <20><><EFBFBD>½ڵ<C2BD>Ƶ<EFBFBD><C6B5>
node.frequency = newFreq;
nodes[nodeIndex] = node;
// <20><><EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
AddToFrequencyList(nodeIndex, newFreq);
}
/// <summary>
/// <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><C6B3>ڵ<EFBFBD>
/// </summary>
private void RemoveFromFrequencyList(int nodeIndex, int frequency)
{
if (!freqToList.TryGetValue(frequency, out var list))
return;
Node node = nodes[nodeIndex];
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ<EFBFBD>
if (node.prevIndex == -1)
{
list.headIndex = node.nextIndex;
}
else
{
// <20><><EFBFBD><EFBFBD>ǰһ<C7B0><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>nextָ<74><D6B8>
Node prevNode = nodes[node.prevIndex];
prevNode.nextIndex = node.nextIndex;
nodes[node.prevIndex] = prevNode;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD>ڵ<EFBFBD>
if (node.nextIndex == -1)
{
list.tailIndex = node.prevIndex;
}
else
{
// <20><><EFBFBD>º<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>prevָ<76><D6B8>
Node nextNode = nodes[node.nextIndex];
nextNode.prevIndex = node.prevIndex;
nodes[node.nextIndex] = nextNode;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>գ<EFBFBD><D5A3>Ƴ<EFBFBD><C6B3><EFBFBD>Ƶ<EFBFBD><C6B5>
if (list.headIndex == -1)
{
freqToList.Remove(frequency);
}
else
{
freqToList[frequency] = list;
}
}
/// <summary>
/// <20><><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD>ӵ<EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><CEB2>
/// </summary>
private void AddToFrequencyList(int nodeIndex, int frequency)
{
if (!freqToList.TryGetValue(frequency, out var list))
{
// <20><><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
list = new FrequencyList { headIndex = nodeIndex, tailIndex = nodeIndex };
freqToList.Add(frequency, list);
// <20><><EFBFBD>ýڵ<C3BD>ָ<EFBFBD><D6B8>
Node node = nodes[nodeIndex];
node.prevIndex = -1;
node.nextIndex = -1;
nodes[nodeIndex] = node;
}
else
{
// <20><><EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><CEB2>
int oldTail = list.tailIndex;
// <20><><EFBFBD><EFBFBD>ԭβ<D4AD>ڵ<EFBFBD>
Node oldTailNode = nodes[oldTail];
oldTailNode.nextIndex = nodeIndex;
nodes[oldTail] = oldTailNode;
// <20><><EFBFBD><EFBFBD><EFBFBD>½ڵ<C2BD>
Node newNode = nodes[nodeIndex];
newNode.prevIndex = oldTail;
newNode.nextIndex = -1;
nodes[nodeIndex] = newNode;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β
list.tailIndex = nodeIndex;
freqToList[frequency] = list;
}
}
/// <summary>
/// <20><>ȡƵ<C8A1><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ<EFBFBD>
/// </summary>
private int GetFrequencyListHead(int frequency)
{
if (freqToList.TryGetValue(frequency, out var list))
{
return list.headIndex;
}
return -1;
}
/// <summary>
/// <20><>̭<EFBFBD><CCAD>СƵ<D0A1>ʵĽڵ㣨<DAB5><E3A3A8>̭<EFBFBD><CCAD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ㣩
/// </summary>
private void EvictMinFrequencyNode()
{
// <20>ҵ<EFBFBD><D2B5>нڵ<D0BD><DAB5><EFBFBD><EFBFBD><EFBFBD>СƵ<D0A1><C6B5>
while (minFrequency <= capacity && GetFrequencyListHead(minFrequency) == -1)
{
minFrequency++;
}
if (minFrequency > capacity) return;
int headIndex = GetFrequencyListHead(minFrequency);
if (headIndex == -1) return;
RemoveNode(headIndex);
}
/// <summary>
/// <20>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ㣨<DAB5><E3A3A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݽṹ<DDBD><E1B9B9>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>
/// </summary>
private void RemoveNode(int nodeIndex)
{
Node node = nodes[nodeIndex];
// <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD>
RemoveFromFrequencyList(nodeIndex, node.frequency);
// <20><><EFBFBD><EFBFBD>HashMap<61>Ƴ<EFBFBD>
keyToNodeIndex.Remove(node.key);
// <20><><EFBFBD>սڵ<D5BD>
FreeNode(nodeIndex);
count--;
}
#endregion
// <20><><EFBFBD>Է<EFBFBD><D4B7><EFBFBD><EFBFBD><EFBFBD>
public readonly int Count => count;
public readonly int Capacity => capacity;
public readonly bool IsCreated => keyToNodeIndex.IsCreated;
}
public struct NativeARCCache<TKey, TValue> : IDisposable
where TKey : unmanaged, IEquatable<TKey>
where TValue : unmanaged
{
private const int LIST_T1 = 0, LIST_T2 = 1, LIST_B1 = 2, LIST_B2 = 3;
private struct Node
{
public TKey key;
public TValue value;
public byte listType;
public int prevIndex;
public int nextIndex;
}
private NativeHashMap<TKey, int> keyToNode;
private NativeList<Node> nodes;
private NativeList<int> freeList;
// <20>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD><EFBFBD>ͷβָ<CEB2><D6B8>
private int t1Head, t1Tail, t2Head, t2Tail, b1Head, b1Tail, b2Head, b2Tail;
private int capacity, t1Count, t2Count, b1Count, b2Count, p;
public NativeARCCache(int capacity, Allocator allocator)
{
this.capacity = capacity;
this.t1Count = this.t2Count = this.b1Count = this.b2Count = 0;
this.p = 0;
t1Head = t1Tail = t2Head = t2Tail = -1;
b1Head = b1Tail = b2Head = b2Tail = -1;
int totalNodes = capacity * 2;
keyToNode = new NativeHashMap<TKey, int>(totalNodes, allocator);
nodes = new NativeList<Node>(totalNodes, allocator);
freeList = new NativeList<int>(totalNodes, allocator);
nodes.Length = totalNodes;
for (int i = totalNodes - 1; i >= 0; i--)
{
freeList.Add(i);
}
}
public bool TryGetValue(TKey key, out TValue value)
{
if (keyToNode.TryGetValue(key, out int nodeIndex))
{
Node node = nodes[nodeIndex]; // <20>ȶ<EFBFBD>ȡ
if (node.listType == LIST_T1 || node.listType == LIST_T2)
{
MoveToMRU(nodeIndex, LIST_T2);
value = node.value;
return true;
}
if (node.listType == LIST_B1)
{
node = ComputeNewPAndReplace(node, b2Count, b1Count, true);
b1Count--; t2Count++;
value = node.value;
return true;
}
if (node.listType == LIST_B2)
{
node = ComputeNewPAndReplace(node, b1Count, b2Count, false);
b2Count--; t2Count++;
value = node.value;
return true;
}
}
value = default;
return false;
}
public void Put(TKey key, TValue value)
{
if (keyToNode.TryGetValue(key, out int nodeIndex))
{
Node node = nodes[nodeIndex];
node.value = value;
if (node.listType == LIST_T1 || node.listType == LIST_T2)
{
MoveToMRU(nodeIndex, LIST_T2);
}
else if (node.listType == LIST_B1)
{
node = ComputeNewPAndReplace(node, b2Count, b1Count, true);
b1Count--; t2Count++;
}
else if (node.listType == LIST_B2)
{
node = ComputeNewPAndReplace(node, b1Count, b2Count, false);
b2Count--; t2Count++;
}
nodes[nodeIndex] = node; // д<><D0B4>
return;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>Replace
int totalSize = t1Count + t2Count;
if (totalSize >= capacity)
{
Replace();
}
// <20><><EFBFBD><EFBFBD><EFBFBD>½ڵ㵽T1
nodeIndex = AllocateNode();
nodes[nodeIndex] = new Node
{
key = key,
value = value,
listType = LIST_T1,
prevIndex = -1,
nextIndex = -1
};
keyToNode.Add(key, nodeIndex);
AddToHead(nodeIndex, LIST_T1);
t1Count++;
}
private Node ComputeNewPAndReplace(Node node, int oppositeCount, int sameCount, bool isB1)
{
int delta = (oppositeCount >= sameCount) ? 1 : oppositeCount / sameCount + 1;
// <20><><EFBFBD>޸<EFBFBD>
if (isB1) p = Math.Min(p + delta, capacity);
else p = Math.Max(p - delta, 0);
// ִ<><D6B4><EFBFBD>
Replace();
// <20>ƶ<EFBFBD><C6B6>ڵ<EFBFBD>
MoveBetweenLists(node.prevIndex, node.listType, LIST_T2);
node.listType = LIST_T2;
return node;
}
private void Replace()
{
if (t1Count > 0 && (t1Count > p || (b2Count > 0 && t1Count == p)))
{
MoveBetweenLists(t1Head, LIST_T1, LIST_B1);
t1Count--; b1Count++;
if (b1Count > capacity)
{
int old = b1Head; Node n = nodes[old];
RemoveFromList(old);
keyToNode.Remove(n.key);
FreeNode(old);
b1Count--;
}
}
else
{
MoveBetweenLists(t2Head, LIST_T2, LIST_B2);
t2Count--; b2Count++;
if (b2Count > capacity)
{
int old = b2Head; Node n = nodes[old];
RemoveFromList(old);
keyToNode.Remove(n.key);
FreeNode(old);
b2Count--;
}
}
}
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
private void MoveToMRU(int nodeIndex, byte targetList)
{
RemoveFromList(nodeIndex);
AddToHead(nodeIndex, targetList);
}
private void MoveBetweenLists(int nodeIndex, byte fromList, byte toList)
{
RemoveFromList(nodeIndex);
AddToHead(nodeIndex, toList);
}
private void AddToHead(int nodeIndex, byte listType)
{
Node node = nodes[nodeIndex]; // <20><>ȡ
node.listType = listType;
node.prevIndex = -1;
switch (listType)
{
case LIST_T1:
node.nextIndex = t1Head;
nodes[nodeIndex] = node; // д<><D0B4>
if (t1Head != -1)
{
Node headNode = nodes[t1Head];
headNode.prevIndex = nodeIndex;
nodes[t1Head] = headNode; // д<><D0B4>
}
t1Head = nodeIndex;
if (t1Tail == -1) t1Tail = nodeIndex;
break;
case LIST_T2:
node.nextIndex = t2Head;
nodes[nodeIndex] = node; // д<><D0B4>
if (t2Head != -1)
{
Node headNode = nodes[t2Head];
headNode.prevIndex = nodeIndex;
nodes[t2Head] = headNode; // д<><D0B4>
}
t2Head = nodeIndex;
if (t2Tail == -1) t2Tail = nodeIndex;
break;
case LIST_B1:
node.nextIndex = b1Head;
nodes[nodeIndex] = node; // д<><D0B4>
if (b1Head != -1)
{
Node headNode = nodes[b1Head];
headNode.prevIndex = nodeIndex;
nodes[b1Head] = headNode; // д<><D0B4>
}
b1Head = nodeIndex;
if (b1Tail == -1) b1Tail = nodeIndex;
break;
case LIST_B2:
node.nextIndex = b2Head;
nodes[nodeIndex] = node; // д<><D0B4>
if (b2Head != -1)
{
Node headNode = nodes[b2Head];
headNode.prevIndex = nodeIndex;
nodes[b2Head] = headNode; // д<><D0B4>
}
b2Head = nodeIndex;
if (b2Tail == -1) b2Tail = nodeIndex;
break;
}
}
private void RemoveFromList(int nodeIndex)
{
Node node = nodes[nodeIndex]; // <20><>ȡ
int prev = node.prevIndex;
int next = node.nextIndex;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͸<EFBFBD><CDB8><EFBFBD>ͷβָ<CEB2><D6B8>
switch (node.listType)
{
case LIST_T1:
if (nodeIndex == t1Head) t1Head = next;
if (nodeIndex == t1Tail) t1Tail = prev;
break;
case LIST_T2:
if (nodeIndex == t2Head) t2Head = next;
if (nodeIndex == t2Tail) t2Tail = prev;
break;
case LIST_B1:
if (nodeIndex == b1Head) b1Head = next;
if (nodeIndex == b1Tail) b1Tail = prev;
break;
case LIST_B2:
if (nodeIndex == b2Head) b2Head = next;
if (nodeIndex == b2Tail) b2Tail = prev;
break;
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ھ<EFBFBD>
if (prev != -1)
{
Node prevNode = nodes[prev];
prevNode.nextIndex = next;
nodes[prev] = prevNode; // д<><D0B4>
}
if (next != -1)
{
Node nextNode = nodes[next];
nextNode.prevIndex = prev;
nodes[next] = nextNode; // д<><D0B4>
}
node.prevIndex = node.nextIndex = -1;
nodes[nodeIndex] = node; // д<><D0B4>
}
#endregion
private int AllocateNode()
{
int index = freeList[^1];
freeList.RemoveAtSwapBack(freeList.Length - 1);
return index;
}
private void FreeNode(int index)
{
freeList.Add(index);
}
public bool Remove(TKey key)
{
if (!keyToNode.TryGetValue(key, out int nodeIndex))
return false;
Node node = nodes[nodeIndex]; // <20><>ȡ
// <20><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>
if (node.listType == LIST_T1) t1Count--;
else if (node.listType == LIST_T2) t2Count--;
else if (node.listType == LIST_B1) b1Count--;
else if (node.listType == LIST_B2) b2Count--;
RemoveFromList(nodeIndex);
keyToNode.Remove(key);
FreeNode(nodeIndex);
return true;
}
public void Clear()
{
keyToNode.Clear();
freeList.Clear();
for (int i = 0; i < nodes.Length; i++)
{
freeList.Add(i);
}
t1Head = t1Tail = t2Head = t2Tail = -1;
b1Head = b1Tail = b2Head = b2Tail = -1;
t1Count = t2Count = b1Count = b2Count = 0;
p = 0;
}
public void Dispose()
{
if (keyToNode.IsCreated) keyToNode.Dispose();
if (nodes.IsCreated) nodes.Dispose();
if (freeList.IsCreated) freeList.Dispose();
t1Head = t1Tail = t2Head = t2Tail = -1;
b1Head = b1Tail = b2Head = b2Tail = -1;
t1Count = t2Count = b1Count = b2Count = 0;
p = 0;
}
public int Count => t1Count + t2Count;
public int Capacity => capacity;
public bool IsCreated => keyToNode.IsCreated;
public int T1Count => t1Count;
public int T2Count => t2Count;
public int PValue => p;
}
}
} }

View File

@@ -201,18 +201,7 @@ namespace Convention
{ {
if (IsFile() == false) if (IsFile() == false)
throw new InvalidOperationException("Target is not a file"); throw new InvalidOperationException("Target is not a file");
var file = this.OriginInfo as FileInfo; return File.ReadAllBytes(OriginPath);
const int BlockSize = 1024;
long FileSize = file.Length;
byte[] result = new byte[FileSize];
long offset = 0;
using (var fs = file.OpenRead())
{
fs.ReadAsync(result[(int)(offset)..(int)(offset + BlockSize)], 0, (int)(offset + BlockSize) - (int)(offset));
offset += BlockSize;
offset = System.Math.Min(offset, FileSize);
}
return result;
} }
public List<string[]> LoadAsCsv() public List<string[]> LoadAsCsv()
@@ -340,7 +329,8 @@ namespace Convention
public void SaveAsBinary(byte[] data) public void SaveAsBinary(byte[] data)
{ {
SaveDataAsBinary(OriginPath, data, (OriginInfo as FileInfo).OpenWrite()); using var fs = (OriginInfo as FileInfo).OpenWrite();
SaveDataAsBinary(OriginPath, data, fs);
} }
public void SaveAsCsv(List<string[]> csvData) public void SaveAsCsv(List<string[]> csvData)

View File

@@ -1,14 +1,15 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Unity.Burst;
using UnityEngine; using UnityEngine;
#if UNITY_URP #if UNITY_URP
using static Unity.Mathematics.math; using static Unity.Mathematics.math;
#endif #endif
using static Convention.MathExtension;
namespace Convention namespace Convention
{ {
[BurstCompile]
public static partial class MathExtension public static partial class MathExtension
{ {
#region EaseCurve #region EaseCurve
@@ -105,6 +106,7 @@ namespace Convention
}; };
} }
[BurstCompile]
public static float Linear(float from, float to, float t) public static float Linear(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -112,6 +114,7 @@ namespace Convention
return c * t / 1f + from; return c * t / 1f + from;
} }
[BurstCompile]
public static float InQuad(float from, float to, float t) public static float InQuad(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -119,6 +122,7 @@ namespace Convention
return c * t * t + from; return c * t * t + from;
} }
[BurstCompile]
public static float OutQuad(float from, float to, float t) public static float OutQuad(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -126,6 +130,7 @@ namespace Convention
return -c * t * (t - 2f) + from; return -c * t * (t - 2f) + from;
} }
[BurstCompile]
public static float InOutQuad(float from, float to, float t) public static float InOutQuad(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -135,6 +140,7 @@ namespace Convention
return -c / 2f * (t * (t - 2) - 1) + from; return -c / 2f * (t * (t - 2) - 1) + from;
} }
[BurstCompile]
public static float InCubic(float from, float to, float t) public static float InCubic(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -142,6 +148,7 @@ namespace Convention
return c * t * t * t + from; return c * t * t * t + from;
} }
[BurstCompile]
public static float OutCubic(float from, float to, float t) public static float OutCubic(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -150,6 +157,7 @@ namespace Convention
return c * (t * t * t + 1) + from; return c * (t * t * t + 1) + from;
} }
[BurstCompile]
public static float InOutCubic(float from, float to, float t) public static float InOutCubic(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -159,6 +167,7 @@ namespace Convention
return c / 2f * (t * t * t + 2) + from; return c / 2f * (t * t * t + 2) + from;
} }
[BurstCompile]
public static float InQuart(float from, float to, float t) public static float InQuart(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -166,6 +175,7 @@ namespace Convention
return c * t * t * t * t + from; return c * t * t * t * t + from;
} }
[BurstCompile]
public static float OutQuart(float from, float to, float t) public static float OutQuart(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -174,6 +184,7 @@ namespace Convention
return -c * (t * t * t * t - 1) + from; return -c * (t * t * t * t - 1) + from;
} }
[BurstCompile]
public static float InOutQuart(float from, float to, float t) public static float InOutQuart(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -183,6 +194,7 @@ namespace Convention
return -c / 2f * (t * t * t * t - 2) + from; return -c / 2f * (t * t * t * t - 2) + from;
} }
[BurstCompile]
public static float InQuint(float from, float to, float t) public static float InQuint(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -190,6 +202,7 @@ namespace Convention
return c * t * t * t * t * t + from; return c * t * t * t * t * t + from;
} }
[BurstCompile]
public static float OutQuint(float from, float to, float t) public static float OutQuint(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -198,6 +211,7 @@ namespace Convention
return c * (t * t * t * t * t + 1) + from; return c * (t * t * t * t * t + 1) + from;
} }
[BurstCompile]
public static float InOutQuint(float from, float to, float t) public static float InOutQuint(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -207,36 +221,42 @@ namespace Convention
return c / 2f * (t * t * t * t * t + 2) + from; return c / 2f * (t * t * t * t * t + 2) + from;
} }
[BurstCompile]
public static float InSine(float from, float to, float t) public static float InSine(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
return -c * Mathf.Cos(t / 1f * (Mathf.PI / 2f)) + c + from; return -c * Mathf.Cos(t / 1f * (Mathf.PI / 2f)) + c + from;
} }
[BurstCompile]
public static float OutSine(float from, float to, float t) public static float OutSine(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
return c * Mathf.Sin(t / 1f * (Mathf.PI / 2f)) + from; return c * Mathf.Sin(t / 1f * (Mathf.PI / 2f)) + from;
} }
[BurstCompile]
public static float InOutSine(float from, float to, float t) public static float InOutSine(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
return -c / 2f * (Mathf.Cos(Mathf.PI * t / 1f) - 1) + from; return -c / 2f * (Mathf.Cos(Mathf.PI * t / 1f) - 1) + from;
} }
[BurstCompile]
public static float InExpo(float from, float to, float t) public static float InExpo(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
return c * Mathf.Pow(2, 10 * (t / 1f - 1)) + from; return c * Mathf.Pow(2, 10 * (t / 1f - 1)) + from;
} }
[BurstCompile]
public static float OutExpo(float from, float to, float t) public static float OutExpo(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
return c * (-Mathf.Pow(2, -10 * t / 1f) + 1) + from; return c * (-Mathf.Pow(2, -10 * t / 1f) + 1) + from;
} }
[BurstCompile]
public static float InOutExpo(float from, float to, float t) public static float InOutExpo(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -246,6 +266,7 @@ namespace Convention
return c / 2f * (-Mathf.Pow(2, -10 * t) + 2) + from; return c / 2f * (-Mathf.Pow(2, -10 * t) + 2) + from;
} }
[BurstCompile]
public static float InCirc(float from, float to, float t) public static float InCirc(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -253,6 +274,7 @@ namespace Convention
return -c * (Mathf.Sqrt(1 - t * t) - 1) + from; return -c * (Mathf.Sqrt(1 - t * t) - 1) + from;
} }
[BurstCompile]
public static float OutCirc(float from, float to, float t) public static float OutCirc(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -261,6 +283,7 @@ namespace Convention
return c * Mathf.Sqrt(1 - t * t) + from; return c * Mathf.Sqrt(1 - t * t) + from;
} }
[BurstCompile]
public static float InOutCirc(float from, float to, float t) public static float InOutCirc(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -270,12 +293,14 @@ namespace Convention
return c / 2f * (Mathf.Sqrt(1 - t * t) + 1) + from; return c / 2f * (Mathf.Sqrt(1 - t * t) + 1) + from;
} }
[BurstCompile]
public static float InBounce(float from, float to, float t) public static float InBounce(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
return c - OutBounce(0f, c, 1f - t) + from; //does this work? return c - OutBounce(0f, c, 1f - t) + from; //does this work?
} }
[BurstCompile]
public static float OutBounce(float from, float to, float t) public static float OutBounce(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -298,6 +323,7 @@ namespace Convention
} }
} }
[BurstCompile]
public static float InOutBounce(float from, float to, float t) public static float InOutBounce(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -306,6 +332,7 @@ namespace Convention
} }
[BurstCompile]
public static float InElastic(float from, float to, float t) public static float InElastic(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -316,6 +343,7 @@ namespace Convention
return -(c * Mathf.Pow(2, 10 * (t -= 1)) * Mathf.Sin((t - s) * (2 * Mathf.PI) / p)) + from; return -(c * Mathf.Pow(2, 10 * (t -= 1)) * Mathf.Sin((t - s) * (2 * Mathf.PI) / p)) + from;
} }
[BurstCompile]
public static float OutElastic(float from, float to, float t) public static float OutElastic(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -326,6 +354,7 @@ namespace Convention
return (c * Mathf.Pow(2, -10 * t) * Mathf.Sin((t - s) * (2 * Mathf.PI) / p) + c + from); return (c * Mathf.Pow(2, -10 * t) * Mathf.Sin((t - s) * (2 * Mathf.PI) / p) + c + from);
} }
[BurstCompile]
public static float InOutElastic(float from, float to, float t) public static float InOutElastic(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -338,6 +367,7 @@ namespace Convention
return c * Mathf.Pow(2, -10 * (t -= 1)) * Mathf.Sin((t - s) * (2f * Mathf.PI) / p) * 0.5f + c + from; return c * Mathf.Pow(2, -10 * (t -= 1)) * Mathf.Sin((t - s) * (2f * Mathf.PI) / p) * 0.5f + c + from;
} }
[BurstCompile]
public static float InBack(float from, float to, float t) public static float InBack(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -346,6 +376,7 @@ namespace Convention
return c * t * t * ((s + 1) * t - s) + from; return c * t * t * ((s + 1) * t - s) + from;
} }
[BurstCompile]
public static float OutBack(float from, float to, float t) public static float OutBack(float from, float to, float t)
{ {
float c = to - from; float c = to - from;
@@ -354,6 +385,7 @@ namespace Convention
return c * (t * t * ((s + 1) * t + s) + 1) + from; return c * (t * t * ((s + 1) * t + s) + 1) + from;
} }
[BurstCompile]
public static float InOutBack(float from, float to, float t) public static float InOutBack(float from, float to, float t)
{ {
float c = to - from; float c = to - from;

View File

@@ -844,28 +844,26 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 72ece51f2901e7445ab60da3685d6b5f, type: 3} m_Script: {fileID: 11500000, guid: 72ece51f2901e7445ab60da3685d6b5f, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_ShowDebugText: 0 ShowDebugText: 0
m_ShowCameraFrustum: 1 ShowCameraFrustum: 1
m_IgnoreTimeScale: 0 IgnoreTimeScale: 0
m_WorldUpOverride: {fileID: 0} WorldUpOverride: {fileID: 0}
m_UpdateMethod: 2 ChannelMask: -1
m_BlendUpdateMethod: 1 UpdateMethod: 2
m_DefaultBlend: BlendUpdateMethod: 1
m_Style: 1 LensModeOverride:
m_Time: 0.5 Enabled: 0
m_CustomCurve: DefaultMode: 2
DefaultBlend:
Style: 1
Time: 0.5
CustomCurve:
serializedVersion: 2 serializedVersion: 2
m_Curve: [] m_Curve: []
m_PreInfinity: 2 m_PreInfinity: 2
m_PostInfinity: 2 m_PostInfinity: 2
m_RotationOrder: 4 m_RotationOrder: 4
m_CustomBlends: {fileID: 0} CustomBlends: {fileID: 0}
m_CameraCutEvent:
m_PersistentCalls:
m_Calls: []
m_CameraActivatedEvent:
m_PersistentCalls:
m_Calls: []
--- !u!114 &1937889226080204937 --- !u!114 &1937889226080204937
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -1060,12 +1058,13 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 45e653bab7fb20e499bda25e1b646fea, type: 3} m_Script: {fileID: 11500000, guid: 45e653bab7fb20e499bda25e1b646fea, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_ExcludedPropertiesInInspector: Priority:
- m_Script Enabled: 0
m_LockStageInInspector: m_Value: 0
OutputChannel: 1
StandbyUpdate: 2
m_StreamingVersion: 20170927 m_StreamingVersion: 20170927
m_Priority: 10 m_LegacyPriority: 10
m_StandbyUpdate: 2
m_LookAt: {fileID: 0} m_LookAt: {fileID: 0}
m_Follow: {fileID: 0} m_Follow: {fileID: 0}
m_Lens: m_Lens:
@@ -1075,17 +1074,30 @@ MonoBehaviour:
FarClipPlane: 5000 FarClipPlane: 5000
Dutch: 0 Dutch: 0
ModeOverride: 0 ModeOverride: 0
LensShift: {x: 0, y: 0}
GateFit: 2 GateFit: 2
FocusDistance: 10
m_SensorSize: {x: 1, y: 1} m_SensorSize: {x: 1, y: 1}
m_Transitions: LensShift: {x: 0, y: 0}
FocusDistance: 10
Iso: 200
ShutterSpeed: 0.005
Aperture: 16
BladeCount: 5
Curvature: {x: 2, y: 11}
BarrelClipping: 0.25
Anamorphism: 0
BlendHint: 0
m_OnCameraLiveEvent:
m_PersistentCalls:
m_Calls: []
m_ExcludedPropertiesInInspector:
- m_Script
m_LockStageInInspector:
m_LegacyTransitions:
m_BlendHint: 0 m_BlendHint: 0
m_InheritPosition: 0 m_InheritPosition: 0
m_OnCameraLive: m_OnCameraLive:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_LegacyBlendHint: 0
m_ComponentOwner: {fileID: 11535700043902880} m_ComponentOwner: {fileID: 11535700043902880}
--- !u!20 &2319537278398014183 --- !u!20 &2319537278398014183
Camera: Camera:
@@ -1439,12 +1451,13 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 45e653bab7fb20e499bda25e1b646fea, type: 3} m_Script: {fileID: 11500000, guid: 45e653bab7fb20e499bda25e1b646fea, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_ExcludedPropertiesInInspector: Priority:
- m_Script Enabled: 0
m_LockStageInInspector: m_Value: 0
OutputChannel: 1
StandbyUpdate: 2
m_StreamingVersion: 20170927 m_StreamingVersion: 20170927
m_Priority: 10 m_LegacyPriority: 10
m_StandbyUpdate: 2
m_LookAt: {fileID: 0} m_LookAt: {fileID: 0}
m_Follow: {fileID: 0} m_Follow: {fileID: 0}
m_Lens: m_Lens:
@@ -1454,17 +1467,30 @@ MonoBehaviour:
FarClipPlane: 5000 FarClipPlane: 5000
Dutch: 0 Dutch: 0
ModeOverride: 0 ModeOverride: 0
LensShift: {x: 0, y: 0}
GateFit: 2 GateFit: 2
FocusDistance: 10
m_SensorSize: {x: 1, y: 1} m_SensorSize: {x: 1, y: 1}
m_Transitions: LensShift: {x: 0, y: 0}
FocusDistance: 10
Iso: 200
ShutterSpeed: 0.005
Aperture: 16
BladeCount: 5
Curvature: {x: 2, y: 11}
BarrelClipping: 0.25
Anamorphism: 0
BlendHint: 0
m_OnCameraLiveEvent:
m_PersistentCalls:
m_Calls: []
m_ExcludedPropertiesInInspector:
- m_Script
m_LockStageInInspector:
m_LegacyTransitions:
m_BlendHint: 0 m_BlendHint: 0
m_InheritPosition: 0 m_InheritPosition: 0
m_OnCameraLive: m_OnCameraLive:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_LegacyBlendHint: 0
m_ComponentOwner: {fileID: 3000479872335485243} m_ComponentOwner: {fileID: 3000479872335485243}
--- !u!20 &7206794941111705965 --- !u!20 &7206794941111705965
Camera: Camera: