Files
Convention-Unity-Demo/Assets/Scripts/Framework/ScriptableObject.cs

849 lines
31 KiB
C#

using Convention;
using Convention.RScript;
using Convention.WindowsUI.Variant;
using Demo.Game;
using Dreamteck.Splines;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Unity.VisualScripting;
using UnityEngine;
namespace Demo
{
public interface IScriptableObject
{
ScriptableObject SharedInterfaceScriptObject { get; }
}
#region ScriptableObject Inside
namespace PrivateType
{
public class EaseCurveTypeInstance
{
public static EaseCurveTypeInstance instance = new();
public MathExtension.EaseCurveType Linear => MathExtension.EaseCurveType.Linear;
public MathExtension.EaseCurveType InQuad => MathExtension.EaseCurveType.InQuad;
public MathExtension.EaseCurveType OutQuad => MathExtension.EaseCurveType.OutQuad;
public MathExtension.EaseCurveType InOutQuad => MathExtension.EaseCurveType.InOutQuad;
public MathExtension.EaseCurveType InCubic => MathExtension.EaseCurveType.InCubic;
public MathExtension.EaseCurveType OutCubic => MathExtension.EaseCurveType.OutCubic;
public MathExtension.EaseCurveType InOutCubic => MathExtension.EaseCurveType.InOutCubic;
public MathExtension.EaseCurveType InQuart => MathExtension.EaseCurveType.InQuart;
public MathExtension.EaseCurveType OutQuart => MathExtension.EaseCurveType.OutQuart;
public MathExtension.EaseCurveType InOutQuart => MathExtension.EaseCurveType.InOutQuart;
public MathExtension.EaseCurveType InQuint => MathExtension.EaseCurveType.InQuint;
public MathExtension.EaseCurveType OutQuint => MathExtension.EaseCurveType.OutQuint;
public MathExtension.EaseCurveType InOutQuint => MathExtension.EaseCurveType.InOutQuint;
public MathExtension.EaseCurveType InSine => MathExtension.EaseCurveType.InSine;
public MathExtension.EaseCurveType OutSine => MathExtension.EaseCurveType.OutSine;
public MathExtension.EaseCurveType InOutSine => MathExtension.EaseCurveType.InOutSine;
public MathExtension.EaseCurveType InExpo => MathExtension.EaseCurveType.InExpo;
public MathExtension.EaseCurveType OutExpo => MathExtension.EaseCurveType.OutExpo;
public MathExtension.EaseCurveType InOutExpo => MathExtension.EaseCurveType.InOutExpo;
public MathExtension.EaseCurveType InCirc => MathExtension.EaseCurveType.InCirc;
public MathExtension.EaseCurveType OutCirc => MathExtension.EaseCurveType.OutCirc;
public MathExtension.EaseCurveType InOutCirc => MathExtension.EaseCurveType.InOutCirc;
public MathExtension.EaseCurveType InBounce => MathExtension.EaseCurveType.InBounce;
public MathExtension.EaseCurveType OutBounce => MathExtension.EaseCurveType.OutBounce;
public MathExtension.EaseCurveType InOutBounce => MathExtension.EaseCurveType.InOutBounce;
public MathExtension.EaseCurveType InElastic => MathExtension.EaseCurveType.InElastic;
public MathExtension.EaseCurveType OutElastic => MathExtension.EaseCurveType.OutElastic;
public MathExtension.EaseCurveType InOutElastic => MathExtension.EaseCurveType.InOutElastic;
public MathExtension.EaseCurveType InBack => MathExtension.EaseCurveType.InBack;
public MathExtension.EaseCurveType OutBack => MathExtension.EaseCurveType.OutBack;
public MathExtension.EaseCurveType InOutBack => MathExtension.EaseCurveType.InOutBack;
public MathExtension.EaseCurveType Custom => MathExtension.EaseCurveType.Custom;
}
public class SplineComputerSampleModeInstance
{
public static SplineComputerSampleModeInstance instance = new();
public SplineComputer.SampleMode Default => SplineComputer.SampleMode.Default;
public SplineComputer.SampleMode Uniform => SplineComputer.SampleMode.Uniform;
public SplineComputer.SampleMode Optimized => SplineComputer.SampleMode.Optimized;
}
public class SplineTypeInstance
{
public static SplineTypeInstance instance = new();
public Spline.Type Linear => Spline.Type.Linear;
public Spline.Type BSpline => Spline.Type.BSpline;
public Spline.Type CatmullRom => Spline.Type.CatmullRom;
public Spline.Type Bezier => Spline.Type.Bezier;
}
}
public partial class ScriptableObject : IScriptableObject
{
/// <summary>
/// 用于开放给倒置接口
/// </summary>
public ScriptableObject SharedInterfaceScriptObject => this;
}
/// <summary>
/// 初始化与对象设置
/// </summary>
public partial class ScriptableObject
{
[Content, SerializeField] private Vector3
EnterGameLocalPosition = Vector3.zero,
EnterGameEulerAngles = Vector3.zero,
EnterGameLocalScaling = Vector3.one;
[Content, SerializeField] private bool IsSetObjectDisable = false;
[Content] public int UpdatePerFrame = 1;
/// <summary>
/// 设置坐标
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="z"></param>
[Convention.RScript.Variable.Attr.Method]
public void SetLocalPosition(float x, float y, float z)
{
EnterGameLocalPosition = new(x, y, z);
}
/// <summary>
/// 设置欧拉角
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="z"></param>
[Convention.RScript.Variable.Attr.Method]
public void SetLocalEulerAngles(float x, float y, float z)
{
EnterGameEulerAngles = new(x, y, z);
}
/// <summary>
/// 设置缩放
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="z"></param>
[Convention.RScript.Variable.Attr.Method]
public void SetLocalScaling(float x, float y, float z)
{
EnterGameLocalScaling = new(x, y, z);
}
/// <summary>
/// 关闭该物体,
/// 在面对如多Game场景时关闭某些GameWorld中默认存在的全局灯光等场景时非常有用
/// </summary>
[Convention.RScript.Variable.Attr.Method]
public void SetObjectDisable()
{
IsSetObjectDisable = true;
}
/// <summary>
/// 指定多少个<see cref="TickType.Update"/>状态的<see cref="UpdateTicks(float, float, TickType)"/>执行一次更新,不会影响到子物体
/// 属于性能优化的高级选项
/// </summary>
/// <param name="frame">每frame帧更新一次, 等于0代表不会在<see cref="TickType.Update"/>状态运行</param>
[Convention.RScript.Variable.Attr.Method]
public void SetUpdatePerFrame(int frame)
{
UpdatePerFrame = Mathf.Max(1, frame);
}
private void ScriptableObjectDoReset()
{
transform.localPosition = EnterGameLocalPosition;
transform.localEulerAngles = EnterGameEulerAngles;
transform.localScale = EnterGameLocalScaling;
gameObject.SetActive(IsSetObjectDisable == false);
}
}
/// <summary>
/// 跨脚本上下文变量
/// </summary>
public partial class ScriptableObject
{
public Dictionary<string, float> ScriptableObjectContents = new();
[Convention.RScript.Variable.Attr.Method]
public float GetContent(string key)
{
if (ScriptableObjectContents.TryGetValue(key, out var result))
{
return result;
}
if (Parent != null)
{
return Parent.GetContent(key);
}
throw new InvalidOperationException($"Key {key} is not find in contnet");
}
[Convention.RScript.Variable.Attr.Method]
public float SetContent(string key, float value)
{
ScriptableObjectContents[key] = value;
return value;
}
}
/// <summary>
/// 基础信息, 父子关系与EnableScript
/// </summary>
public partial class ScriptableObject
{
public static bool IsAutoPlay = false;
public static float OneBarTime = 60;
private bool isEnableScript = false;
public string ScriptName = "";
public ScriptableObject Parent;
public readonly List<ScriptableObject> Childs = new();
public readonly List<ScriptableObject> UpdateChilds = new();
/// <summary>
/// 获取根脚本对象
/// </summary>
/// <returns></returns>
[Convention.RScript.Variable.Attr.Method]
public RootObject GetRoot()
{
if (Parent == null)
return this as RootObject;
if (Parent is RootObject result)
return result;
else
return Parent.GetRoot();
}
public const string RootObjectQuickPath = "project/";
public ScriptableObject FindWithPath(string path, bool isMustExist = true)
{
if (string.IsNullOrEmpty(path))
{
if (isMustExist)
throw new Exception("path is null or empty");
else
return null;
}
// GetParent
ScriptableObject result = Parent;
if (path.Replace('\\', '/').ToLower().StartsWith(RootObjectQuickPath))
{
result = GetRoot();
path = path[RootObjectQuickPath.Length..];
}
if (Parent == null)
{
throw new InvalidOperationException($"Root is nosupport to {nameof(FindWithPath)}");
}
// Find
var components = path.Split('/', '\\');
components[^1] = new ToolFile(components[^1]).GetFilename(true);
foreach (var component in components)
{
if (component == "..")
result = result.Parent;
else if (component == "." || string.IsNullOrEmpty(component))
continue;
else
{
int index = 0;
string targetScriptObjectPath = component;
Regex regex = new(@"^(.*)\[(\d*)\]$");
var match = regex.Match(component);
if (match.Success)
{
targetScriptObjectPath = match.Groups[1].Value;
index = int.Parse(match.Groups[2].Value);
}
var target = result.Childs.FirstOrDefault(x =>
{
bool stats = x.ScriptName == targetScriptObjectPath;
if (index == 0)
return stats;
else if (stats)
index--;
return false;
});
if (target != null)
result = target;
else
{
if (isMustExist)
throw new Exception($"{component} in {path} is not found");
else
{
Debug.Log($"{component} in {path} is not found", this);
return null;
}
}
}
}
return result;
}
public void EnableScript(ScriptableObject parent)
{
if (isEnableScript)
{
Debug.LogError($"ScriptableObject is currently enableScript, start coroutine {nameof(UnloadScript)} to disable", this);
return;
}
this.Parent = parent;
this.name = ScriptName;
isEnableScript = true;
// 只有RootObject的parent会是空的
if (parent != null)
{
MyHierarchyItem = parent.MyHierarchyItem.GetHierarchyItem().CreateSubPropertyItem(1)[0];
}
else
{
MyHierarchyItem = HierarchyWindow.instance.CreateRootItemEntryWithBinders(1)[0];
}
MyHierarchyItem.GetHierarchyItem().title = this.ScriptName + $"<{this.GetType()}>";
MyHierarchyItem.GetHierarchyItem().target = this;
MyHierarchyItem.GetHierarchyItem().ButtonGameObject.GetComponent<Editor.UI.RightClick>().ScriptObjectMenu = OnHierarchyItemRightClick;
}
#region Hierarchy
public PropertiesWindow.ItemEntry MyHierarchyItem;
public static PropertiesWindow.ItemEntry AllScriptableObjectCounterHierarchyItem;
public bool EnsureEnableScript()
{
if (isEnableScript == false)
{
Debug.LogError("ScriptableObject is currently disableScript", this);
}
return isEnableScript;
}
#endregion
}
/// <summary>
/// 脚本解析与Update执行
/// </summary>
public partial class ScriptableObject
{
public static Dictionary<string, Type> FastScriptableObjectTypen = new();
public static int AllScriptableObjectCounter = 0;
public bool IsParseScript2Expr { get; private set; } = false;
protected virtual bool IsSelfEnableUpdate { get => true; }
public bool IsEnableUpdate { get; private set; } = true;
#region LoadSubScript
/// <summary>
/// 创建基于子脚本的实例对象
/// </summary>
/// <param name="type"></param>
/// <param name="name"></param>
/// <returns></returns>
[Convention.RScript.Variable.Attr.Method]
public ScriptableObject LoadSubScript([In] string type, [In] string name, [In] string path)
{
// 判断类型是否合法
if (DefaultInstantiate.GetScriptableObjectInstantiate().TryGetValue(type, out var creater) == false)
{
Debug.LogError($"{type} is not exist or {type}'s Instantiater is not valid", this);
return null;
}
// 生成对象
var child = creater();
// 获取文件
var file = new ToolFile(GetRoot().SourcePath);
file = file | path;
// 找不到脚本
if (file.Exists() == false)
{
Debug.LogError($"{file}<{path}> is not found", this);
return null;
}
child.ScriptName = name;
child.transform.SetParent(this.transform);
child.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
child.transform.localScale = Vector3.one;
child.EnableScript(this);
// Add Child
Childs.Add(child);
UpdateChilds.Add(child);
// Load Child Script
ConventionUtility.StartCoroutine(child.ParseScript2Expr(file.LoadAsText()));
return child;
}
/// <summary>
/// 创建不基于子脚本的实例对象
/// </summary>
/// <param name="type"></param>
/// <param name="name"></param>
/// <returns></returns>
[Convention.RScript.Variable.Attr.Method]
public ScriptableObject NewSubScript([In] string type, string name)
{
// 判断类型是否合法
if (DefaultInstantiate.GetScriptableObjectInstantiate().TryGetValue(type, out var creater) == false)
{
Debug.LogError($"{type} is not exist or {type}'s Instantiater is not valid", this);
return null;
}
// 生成对象
var child = creater();
child.ScriptName = name;
child.transform.SetParent(this.transform);
child.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
child.transform.localScale = Vector3.one;
child.EnableScript(this);
// Add Child
Childs.Add(child);
UpdateChilds.Add(child);
return child;
}
/// <summary>
/// 获取已加载的脚本对象
/// </summary>
/// <returns>无法找到时将返回空</returns>
[Convention.RScript.Variable.Attr.Method]
public ScriptableObject GetLoadedObject(string path)
{
return FindWithPath(path, false);
}
/// <summary>
/// 获取父脚本对象
/// </summary>
/// <returns></returns>
[Convention.RScript.Variable.Attr.Method]
public ScriptableObject GetParentObject()
{
return Parent;
}
#endregion
public static class RandomTool
{
public static float Random(float min,float max)
{
return UnityEngine.Random.Range(min,max);
}
public static float Random(double min,double max)
{
return UnityEngine.Random.Range((float)min, (float)max);
}
}
public class ConsoleTool
{
GameObject gameObject;
public ConsoleTool(GameObject gameObject)
{
this.gameObject = gameObject;
}
public void Log(object obj)
{
Debug.Log(obj);
}
}
public IEnumerator ParseScript2Expr(string script)
{
IsParseScript2Expr = true;
RScriptEngine engine = new();
RScriptImportClass importClass = new()
{
typeof(Mathf),
typeof(RandomTool),
};
RScriptVariables variables = new()
{
{ "this", new() { data = this, type = this.GetType() } },
{ "self", new() { data = this, type = this.GetType() } },
{ "console", new() { data = new ConsoleTool(gameObject), type = typeof(ConsoleTool) } },
{ nameof(MathExtension.EaseCurveType), new() { data = PrivateType.EaseCurveTypeInstance.instance, type = typeof(PrivateType.EaseCurveTypeInstance) } },
{ $"Spline{nameof(SplineComputer.SampleMode)}",
new() { data = PrivateType.SplineComputerSampleModeInstance.instance, type = typeof(PrivateType.SplineComputerSampleModeInstance)} },
{ $"Spline{nameof(Spline.Type)}",
new() { data = PrivateType.SplineTypeInstance.instance, type = typeof(PrivateType.SplineTypeInstance)} },
};
foreach (var ir in engine.RunAsync(script, importClass, variables).Yield())
{
// using var _curr_sen = Profiler.BeginZone(engine.context.CurrentSentence.content);
yield return ir;
}
IsParseScript2Expr = false;
}
public enum TickType
{
Reset,
Pause,
Start,
Update
}
[Content, SerializeField] private int ScriptUpdateCounter = 0;
public void ScriptUpdate(float currentTime, float deltaTime, TickType tickType)
{
if (IsScriptApply == false)
return;
if (gameObject.activeInHierarchy == false)
return;
using (Profiler.BeginZone($"{GetType().Name}.ScriptUpdate"))
{
if (tickType == TickType.Reset)
{
ResetEnterGameStatus();
// Childs UpdateTicks
foreach (var child in Childs)
{
child.ScriptUpdate(currentTime, deltaTime, tickType);
}
}
else
{
// UpdateTicks
if (UpdatePerFrame > 0)
{
if (ScriptUpdateCounter % UpdatePerFrame == 0)
UpdateTicks(currentTime, deltaTime, tickType);
ScriptUpdateCounter += tickType == TickType.Update ? 1 : 0;
}
// Childs UpdateTicks
foreach (var child in UpdateChilds)
{
child.ScriptUpdate(currentTime, deltaTime, tickType);
}
}
}
}
protected virtual void UpdateTicks(float currentTime, float deltaTime, TickType tickType)
{
}
}
/// <summary>
/// <para>使用<see cref="Convention.RScript.Variable.Attr.MethodAttribute"/>标记可编辑脚本所能够调用的函数</para>
/// <para>使用<see cref="Convention.RScript.Variable.Attr.DefaultAttribute"/>标记派生类,并附加默认模板</para>
/// </summary>
public partial class ScriptableObject :
#if ENABLE_SerializedMonoBehaviour_CLASS
SerializedMonoBehaviour,
#else
MonoBehaviour,
#endif
IHierarchyItemClickEventListener
{
protected virtual IEnumerator DoSomethingDuringApplyScript()
{
yield break;
}
[Content]
public bool IsScriptApply { get; private set; } = false;
[Convention.RScript.Variable.Attr.Method]
public IEnumerator ApplyScript()
{
if (EnsureEnableScript() == false)
{
yield break;
}
// 等待自身脚本解析完毕
while (this.IsParseScript2Expr)
{
yield return null;
}
yield return DoSomethingDuringApplyScript();
// 增数
{
AllScriptableObjectCounter++;
AllScriptableObjectCounterHierarchyItem.GetHierarchyItem().text = $"ScriptableObjectCount: {AllScriptableObjectCounter}";
}
// 统计更新能力
{
IsEnableUpdate = this.IsSelfEnableUpdate;
foreach (var child in this.Childs)
{
if (IsEnableUpdate)
break;
IsEnableUpdate |= child.IsEnableUpdate;
}
if (IsEnableUpdate == false && Parent != null)
Parent.UpdateChilds.Remove(this);
}
IsScriptApply = true;
}
public virtual IEnumerator UnloadScript()
{
if (EnsureEnableScript())
{
this.name = "<Unloading>";
try
{
foreach (var child in Childs)
{
yield return child.UnloadScript();
}
}
finally
{
this.isEnableScript = false;
this.Parent = null;
this.name = "<Unload>";
if (IsScriptApply)
{
// 清理各种状态
IsScriptApply = false;
// 清理Cache
//
// 减数
AllScriptableObjectCounter--;
AllScriptableObjectCounterHierarchyItem.GetHierarchyItem().text = $"ScriptableObjectCount: {AllScriptableObjectCounter}";
}
if (MyHierarchyItem != null)
{
// 卸载UI
MyHierarchyItem.Release();
MyHierarchyItem = null;
}
}
}
}
public virtual void ResetEnterGameStatus()
{
ScriptableObjectDoReset();
}
public virtual void OnHierarchyItemRightClick(RectTransform item)
{
DefaultInstantiate.OpenInstantiateMenu(this, item);
}
public virtual void OnHierarchyItemClick(HierarchyItem item)
{
}
}
#endregion
public interface IAssetBundleLoader : IScriptableObject
{
public RootObject GetRoot();
}
public static class AssetBundlesLoadHelper
{
public struct Entry
{
public AssetBundle assetBundle;
public int referenceCounter;
public PropertiesWindow.ItemEntry entry;
public Entry(AssetBundle assetBundle, int referenceCounter = 0, PropertiesWindow.ItemEntry entry = null)
{
this.assetBundle = assetBundle;
this.referenceCounter = referenceCounter;
this.entry = entry;
}
}
public static Dictionary<string, Entry> AssetBundleCounter = new();
private static Dictionary<string, IEnumerator> AssetBundleLoading = new();
private static PropertiesWindow.ItemEntry AssetBundlesItemEntry = null;
public static IEnumerator LoadAssetBundleAsync(string ab, Action<AssetBundle> callback)
{
if (AssetBundleCounter.TryGetValue(ab, out var result))
{
result.referenceCounter++;
callback?.Invoke(result.assetBundle);
yield break;
}
if (AssetBundleLoading.TryGetValue(ab, out var tir))
{
yield return tir;
if (AssetBundleCounter.TryGetValue(ab, out result))
{
result.referenceCounter++;
callback?.Invoke(result.assetBundle);
yield break;
}
}
var file = new ToolFile(PlatformIndicator.StreamingAssetsPath) | "AssetBundle/";
#if PLATFORM_WINDOWS
file = file | "Windows";
#endif
file = file | ab;
#if ENABLE_CLASS_Interaction
var downloader = new Interaction(file.GetFullPath());
#else
var downloader = new ToolFile(file.GetFullPath());
#endif
if (AssetBundlesItemEntry == null)
{
var hierarchy = HierarchyWindow.instance;
AssetBundlesItemEntry = hierarchy.CreateRootItemEntryWithBinders(nameof(AssetBundlesLoadHelper))[0];
AssetBundlesItemEntry.ref_value.GetComponent<HierarchyItem>().title = nameof(AssetBundlesLoadHelper);
}
var abLoadingItem = AssetBundlesItemEntry.ref_value.GetComponent<HierarchyItem>().CreateSubPropertyItem(1)[0];
var loadingHierarchyItem = abLoadingItem.ref_value.GetComponent<HierarchyItem>();
loadingHierarchyItem.title = $"{ab}<Loading>";
var ir = downloader.LoadAsAssetBundle(p =>
{
loadingHierarchyItem.title = $"{ab}<Loading{(int)(p * 100)}%>";
}, x =>
{
if (x != null)
{
loadingHierarchyItem.title = $"{ab}";
var assets = x.GetAllAssetNames();
var subAssetsItems = loadingHierarchyItem.CreateSubPropertyItem(assets.Length);
for (int i = 0, e = assets.Length; i < e; i++)
{
subAssetsItems[i].ref_value.GetComponent<HierarchyItem>().title = Path.GetFileName(assets[i]);
}
AssetBundleCounter[ab] = new(x, 1, abLoadingItem);
}
else
{
loadingHierarchyItem.title = $"{ab}<Failed>";
}
AssetBundleLoading.Remove(ab);
callback?.Invoke(x);
});
AssetBundleLoading.Add(ab, ir);
yield return ir;
AssetBundleLoading.Remove(ab);
}
public static IEnumerator LoadAssetBundle(this IAssetBundleLoader self, string ab, Action<AssetBundle> callback)
{
Debug.Log($"{self.SharedInterfaceScriptObject.ScriptName}.{nameof(LoadAssetBundle)}({ab})", self.SharedInterfaceScriptObject);
yield return LoadAssetBundleAsync(ab, callback);
}
public static IEnumerator UnloadAssetBundle(this IAssetBundleLoader self, string ab)
{
// Editor中暂时忽略卸载功能
yield break;
}
}
public abstract class TimelineScriptObject : ScriptableObject
{
public static PropertiesWindow TimelineWindow;
private PropertiesWindow.ItemEntry MyTimelineEntry;
private Editor.UI.TimelineItem MyTimelineItem;
//[SerializeField] private bool IsTimelineItemShow = false;
private static List<TimelineScriptObject> TimelineScriptObjectWhichOnShow = new();
private static UnityEngine.UI.Image CacheLastFocusImage;
private static Color CacheLastFocusImageOriginColor = new(1, 1, 1, 0.01f);
private static Color FocusImageColor = new(1f, 47f / 51f, 0.0156862754f, 0.1f);
protected override IEnumerator DoSomethingDuringApplyScript()
{
yield return base.DoSomethingDuringApplyScript();
if(MyTimelineEntry==null)
{
MyTimelineEntry = TimelineWindow.CreateRootItemEntries(1)[0];
MyTimelineItem = MyTimelineEntry.ref_value.GetComponent<Editor.UI.TimelineItem>();
}
MyTimelineItem.title = ScriptName;
MyTimelineItem.RawButton.onClick.RemoveAllListeners();
MyTimelineItem.AddListener(() =>
{
HierarchyWindow.instance.MakeFocusOn(MyHierarchyItem.GetHierarchyItem());
if (CacheLastFocusImage != null)
CacheLastFocusImage.color = CacheLastFocusImageOriginColor;
CacheLastFocusImage = MyHierarchyItem.GetHierarchyItem().ButtonGameObject.GetComponent<UnityEngine.UI.Image>();
CacheLastFocusImage.color = FocusImageColor;
});
SetupTimelineItem(MyTimelineItem);
// 暂时的逻辑是总是展示的
{
TimelineScriptObjectWhichOnShow.Add(this);
}
}
public override IEnumerator UnloadScript()
{
yield return base.UnloadScript();
// 这里的两处判空是因为如果抛出错误就会打断了逻辑, 所以这里需要判断
if (MyTimelineItem)
{
MyTimelineItem.RawButton.onClick.RemoveAllListeners();
MyTimelineItem = null;
}
if (MyTimelineEntry != null)
{
MyTimelineEntry.Release();
MyTimelineEntry = null;
}
}
public override void OnHierarchyItemClick(HierarchyItem item)
{
}
protected override void UpdateTicks(float currentTime, float deltaTime, TickType tickType)
{
base.UpdateTicks(currentTime, deltaTime, tickType);
{
MyTimelineItem.ResizeOnTimeline();
}
}
protected abstract void SetupTimelineItem(Editor.UI.TimelineItem item);
protected virtual Color GetTimelineItemColor()
{
static float Foo(uint hash)
{
float a= (hash % 10) * 0.1f;
return a;
}
var a1 = (uint)this.GetType().GetHashCode();
var a2 = (uint)a1.ToString().GetHashCode();
var a3 = (uint)(a2.ToString().GetHashCode() >> 5);
var color = new Vector3(Foo(a1), Foo(a2), Foo(a3)).normalized;
return new(color.x, color.y, color.z);
}
}
}