加载性能优化, 暂时放弃异步加载

This commit is contained in:
2025-12-11 18:03:57 +08:00
parent eebf283e12
commit b99b7f2743
9 changed files with 150 additions and 138 deletions

View File

@@ -1,2 +1,15 @@
using UnityEditor;
using UnityEngine; using UnityEngine;
[CustomEditor(typeof(Demo.Game.GameController), true)]
public class GameControllerEditor : Convention.AbstractCustomEditor
{
}
[CustomEditor(typeof(Demo.Editor.EditorController), true)]
public class EditorControllerEditor : Convention.AbstractCustomEditor
{
}

View File

@@ -61,7 +61,7 @@ namespace Demo.Game
Datas.Dispose(); Datas.Dispose();
} }
#region MyRegion #region Serialize
protected override bool IsImptSerialize => true; protected override bool IsImptSerialize => true;
protected override IEnumerator CreateAndLoadingImptCacheFile(ToolFile scriptFile, ToolFile cacheFile) protected override IEnumerator CreateAndLoadingImptCacheFile(ToolFile scriptFile, ToolFile cacheFile)
@@ -69,10 +69,10 @@ namespace Demo.Game
yield return this.ParseScript2Expr(scriptFile.LoadAsText()); yield return this.ParseScript2Expr(scriptFile.LoadAsText());
using var stream = File.OpenWrite(cacheFile.GetFullPath()); using var stream = File.OpenWrite(cacheFile.GetFullPath());
using var writer = new BinaryWriter(stream); using var writer = new BinaryWriter(stream);
writer.Write(Datas.Length); writer.Write(Count);
foreach (var i in Datas) for (int i = 0; i < Count; i++)
{ {
writer.Write(i); writer.Write(Datas[i]);
} }
} }
protected override IEnumerator LoadFromImptCacheFile(ToolFile cacheFile) protected override IEnumerator LoadFromImptCacheFile(ToolFile cacheFile)
@@ -80,7 +80,7 @@ namespace Demo.Game
using var stream = File.OpenRead(cacheFile.GetFullPath()); using var stream = File.OpenRead(cacheFile.GetFullPath());
using var reader = new BinaryReader(stream); using var reader = new BinaryReader(stream);
Count = reader.ReadInt32(); Count = reader.ReadInt32();
Datas = new NativeArray<float>(Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); Datas.ResizeArray(Mathf.Max(128, Count));
for (int i = 0; i < Count; i++) for (int i = 0; i < Count; i++)
{ {
Datas[i] = reader.ReadSingle(); Datas[i] = reader.ReadSingle();
@@ -89,5 +89,16 @@ namespace Demo.Game
} }
#endregion #endregion
#if UNITY_EDITOR
[Setting, SerializeField] private List<float> d_Datas = new();
protected override IEnumerator DoSomethingDuringApplyScript()
{
yield return base.DoSomethingDuringApplyScript();
for (int i = 0; i < Count; i++)
d_Datas.Add(Datas[i]);
}
#endif
} }
} }

View File

@@ -13,6 +13,14 @@ namespace Demo.Game
{ {
public partial class GameController : MonoBehaviour public partial class GameController : MonoBehaviour
{ {
#if UNITY_EDITOR
[Resources]
public void DebugGetScriptCounter()
{
Debug.Log(ScriptableObject.s_DebugContainer.Count, this);
}
#endif
[Resources, SerializeField] public BasicAudioSystem MainAudio; [Resources, SerializeField] public BasicAudioSystem MainAudio;
[Resources, SerializeField] private CinemachineVirtualCameraBase MainCamera; [Resources, SerializeField] private CinemachineVirtualCameraBase MainCamera;
[Resources, SerializeField] public GlobalConfig MainConfig; [Resources, SerializeField] public GlobalConfig MainConfig;
@@ -201,46 +209,37 @@ namespace Demo.Game
rootGameObject.SetContent(nameof(SongOffset), SongOffset); rootGameObject.SetContent(nameof(SongOffset), SongOffset);
rootGameObject.SetContent(nameof(IsAutoPlay), IsAutoPlay ? 1 : 0); rootGameObject.SetContent(nameof(IsAutoPlay), IsAutoPlay ? 1 : 0);
rootGameObject.SetContent("SongLength", MainAudio.CurrentClip.length); rootGameObject.SetContent("SongLength", MainAudio.CurrentClip.length);
Stack<IEnumerator> loadingTask = new(); static IEnumerator Foo(IEnumerator ir)
loadingTask.Push(rootGameObject.ParseFromScriptFile2Expr(rootObject));
float waitClock = Time.realtimeSinceStartup;
Dictionary<Type, int> DebugCounter = new();
while (loadingTask.Count > 0)
{ {
// 防止大量无延迟函数如NewSubObject的使用导致的假死机 Stack<IEnumerator> loadingTask = new();
if (Time.realtimeSinceStartup - waitClock > 0.1f) loadingTask.Push(ir);
while (loadingTask.Count > 0)
{ {
yield return null; if (loadingTask.Peek().MoveNext())
waitClock = Time.realtimeSinceStartup; {
if (loadingTask.Peek().Current is IEnumerator next)
loadingTask.Push(next);
else if (loadingTask.Peek().Current is ScriptableObject)
yield return null;
}
else
{
loadingTask.Pop();
}
} }
if (loadingTask.Peek().MoveNext()) yield break;
{
if (loadingTask.Peek().Current is IEnumerator next)
loadingTask.Push(next);
}
else
{
loadingTask.Pop();
}
yield return null;
} }
int NDFSCount = 0; yield return Foo(rootGameObject.ParseFromScriptFile2Expr(rootObject));//ConventionUtility.AvoidFakeStop(rootGameObject.ParseFromScriptFile2Expr(rootObject));
IEnumerator NDFS(ScriptableObject current) static void NDFS(ScriptableObject current)
{ {
foreach (var child in current.Childs) foreach (var child in current.Childs)
{ {
ConventionUtility.StartCoroutine(NDFS(child)); NDFS(child);
NDFSCount++;
if(NDFSCount % 100 == 0)
{
yield return null;
}
} }
if (current.IsScriptApply == false) if (current.IsScriptApply == false)
ConventionUtility.StartCoroutine(current.ApplyScript()); ConventionUtility.StartCoroutine(current.ApplyScript());
} }
//yield return NDFS(rootGameObject);
ConventionUtility.StartCoroutine(NDFS(rootGameObject));
float loadRootObjectEndTime = Time.realtimeSinceStartup; float loadRootObjectEndTime = Time.realtimeSinceStartup;
float loadRootObjectElapsed = (loadRootObjectEndTime - loadRootObjectStartTime) * 1000f; float loadRootObjectElapsed = (loadRootObjectEndTime - loadRootObjectStartTime) * 1000f;
Debug.Log($"[GameInit] Load Root Object 耗时: {loadRootObjectElapsed:F2} ms", this); Debug.Log($"[GameInit] Load Root Object 耗时: {loadRootObjectElapsed:F2} ms", this);

View File

@@ -111,7 +111,7 @@ namespace Demo
/// </summary> /// </summary>
public partial class ScriptableObject public partial class ScriptableObject
{ {
public Dictionary<string, float> ScriptableObjectContents = new(); public readonly Dictionary<string, float> ScriptableObjectContents = new();
[Convention.RScript.Variable.Attr.Method] [Convention.RScript.Variable.Attr.Method]
public float GetContent(string key) public float GetContent(string key)
@@ -120,10 +120,6 @@ namespace Demo
{ {
return result; return result;
} }
if (Parent != null)
{
return Parent.GetContent(key);
}
throw new InvalidOperationException($"Key {key} is not find in contnet"); throw new InvalidOperationException($"Key {key} is not find in contnet");
} }
@@ -254,6 +250,8 @@ namespace Demo
return; return;
} }
this.Parent = parent; this.Parent = parent;
if (parent != null)
this.ScriptableObjectContents.AddRange(parent.ScriptableObjectContents);
this.name = ScriptName; this.name = ScriptName;
@@ -470,9 +468,21 @@ namespace Demo
#endif #endif
IHierarchyItemClickEventListener IHierarchyItemClickEventListener
{ {
#if UNITY_EDITOR
internal static readonly HashSet<ScriptableObject> s_DebugContainer = new();
private void Awake()
{
s_DebugContainer.Add(this);
}
private void OnDestroy()
{
s_DebugContainer.Remove(this);
}
#endif
protected virtual IEnumerator DoSomethingDuringApplyScript() protected virtual IEnumerator DoSomethingDuringApplyScript()
{ {
return null; yield break;
} }
[Content] [Content]
@@ -497,16 +507,18 @@ namespace Demo
{ {
yield break; yield break;
} }
if (IsScriptApply)
yield break;
// 等待自身脚本解析完毕 // 等待自身脚本解析完毕
while (this.IsParseScript2Expr) while (this.IsParseScript2Expr)
{ {
yield return null; yield return this;
while (LoadingTaskCoroutineCount < MaxLoadingCoroutine && WaitingTaskForLoadingCoroutine.Count > 0) }
{ while (LoadingTaskCoroutineCount < MaxLoadingCoroutine && WaitingTaskForLoadingCoroutine.Count > 0)
LoadingTaskCoroutineCount++; {
ConventionUtility.StartCoroutine(WaitingTaskForLoadingCoroutine.First.Value); LoadingTaskCoroutineCount++;
WaitingTaskForLoadingCoroutine.RemoveFirst(); ConventionUtility.StartCoroutine(WaitingTaskForLoadingCoroutine.First.Value);
} WaitingTaskForLoadingCoroutine.RemoveFirst();
} }
yield return DoSomethingDuringApplyScript(); yield return DoSomethingDuringApplyScript();
// 增数 // 增数
@@ -525,36 +537,37 @@ namespace Demo
GetRoot().UpdateChilds[type] = new() { this }; GetRoot().UpdateChilds[type] = new() { this };
} }
} }
// 释放资源
{
this.ScriptableObjectContents.Clear();
}
IsScriptApply = true; IsScriptApply = true;
} }
public virtual IEnumerator UnloadScript() public virtual IEnumerator UnloadScript()
{ {
if (EnsureEnableScript()) if (IsScriptApply)
{ {
this.name = "<Unloading>"; this.name = "<Unloading>";
foreach (var child in Childs) foreach (var child in Childs)
{ {
ConventionUtility.StartCoroutine(child.UnloadScript()); ConventionUtility.StartCoroutine(child.UnloadScript());
} }
if (IsScriptApply) yield return new WaitUntil(() => Childs.Any(x => x.isEnableScript == false) == false);
{ // 清理各种状态
// 清理各种状态 IsScriptApply = false;
IsScriptApply = false; // 清理Cache
// 清理Cache //
// // 减数
// 减数 ApplyScriptableObjectCounter--;
ApplyScriptableObjectCounter--; EnableScriptableObjectCounter--;
EnableScriptableObjectCounter++; AllScriptableObjectCounterHierarchyItem.GetHierarchyItem().text = $"SOC: {ApplyScriptableObjectCounter}/{EnableScriptableObjectCounter}";
AllScriptableObjectCounterHierarchyItem.GetHierarchyItem().text = $"SOC: {ApplyScriptableObjectCounter}/{EnableScriptableObjectCounter}";
}
if (MyHierarchyItem != null) if (MyHierarchyItem != null)
{ {
// 卸载UI // 卸载UI
MyHierarchyItem.Release(); MyHierarchyItem.Release();
MyHierarchyItem = null; MyHierarchyItem = null;
} }
yield return new WaitUntil(() => Childs.Any(x => x.isEnableScript == false) == false);
this.isEnableScript = false; this.isEnableScript = false;
this.Parent = null; this.Parent = null;
this.name = "<Unload>"; this.name = "<Unload>";

View File

@@ -247,7 +247,6 @@ namespace Demo
} }
private static readonly Dictionary<string, object> s_FileLocker = new(); private static readonly Dictionary<string, object> s_FileLocker = new();
private static readonly Dictionary<string, RScriptEngine> s_RScriptEngineCache = new();
public IEnumerator ParseFromScriptFile2Expr(ToolFile file) public IEnumerator ParseFromScriptFile2Expr(ToolFile file)
{ {
@@ -263,79 +262,59 @@ namespace Demo
{ {
lastHashFile.MustExistsPath(); lastHashFile.MustExistsPath();
lastHashFile.SaveAsText(hash); lastHashFile.SaveAsText(hash);
yield return CreateAndLoadingImptCacheFile(file, bin); yield return ConventionUtility.AvoidFakeStop(CreateAndLoadingImptCacheFile(file, bin));
} }
else else
{ {
yield return LoadFromImptCacheFile(bin); yield return ConventionUtility.AvoidFakeStop(LoadFromImptCacheFile(bin));
} }
} }
else else
{ {
bool is_engine_cached = false;
IEnumerator step = null; IEnumerator step = null;
lock (s_RScriptEngineCache) RScriptEngine engine = new();
is_engine_cached = s_RScriptEngineCache.ContainsKey(file.GetFullPath()); RScriptImportClass importClass = GenerateImport();
if (is_engine_cached == false) RScriptVariables variables = GenerateVariables(this);
object locker;
if (lastHashFile.Exists() == false || lastHashFile.LoadAsText() != hash)
{ {
lock (s_RScriptEngineCache) lastHashFile.MustExistsPath();
bin.MustExistsPath();
lastHashFile.SaveAsText(hash);
var script = file.LoadAsText();
var structBin = engine.Compile(script, importClass, variables);
lock (s_FileLocker)
{ {
RScriptEngine engine = new(); if (s_FileLocker.TryGetValue(file.GetFullPath(), out locker) == false)
RScriptImportClass importClass = GenerateImport();
RScriptVariables variables = GenerateVariables(this);
object locker;
if (lastHashFile.Exists() == false || lastHashFile.LoadAsText() != hash)
{ {
lastHashFile.MustExistsPath(); s_FileLocker.Add(file.GetFullPath(), locker = new object());
bin.MustExistsPath();
lastHashFile.SaveAsText(hash);
var script = file.LoadAsText();
var structBin = engine.Compile(script, importClass, variables);
lock (s_FileLocker)
{
if (s_FileLocker.TryGetValue(file.GetFullPath(), out locker) == false)
{
s_FileLocker.Add(file.GetFullPath(), locker = new object());
}
}
lock (locker)
{
bin.SaveAsBinary(RScriptSerializer.SerializeClass(structBin));
}
step = engine.RunAsync(script, importClass, variables);
} }
else
{
RScriptContext.SerializableClass structBin;
lock (s_FileLocker)
{
if (s_FileLocker.TryGetValue(file.GetFullPath(), out locker) == false)
{
s_FileLocker.Add(file.GetFullPath(), locker = new object());
}
}
lock (locker)
{
structBin = RScriptSerializer.DeserializeClass(bin.LoadAsBinary());
}
step = engine.RunAsync(structBin, importClass, variables);
}
s_RScriptEngineCache.Add(file.GetFullPath(), engine);
} }
lock (locker)
{
bin.SaveAsBinary(RScriptSerializer.SerializeClass(structBin));
}
step = engine.RunAsync(script, importClass, variables);
} }
else else
{ {
var engine = s_RScriptEngineCache[file.GetFullPath()]; RScriptContext.SerializableClass structBin;
lock (engine) lock (s_FileLocker)
{ {
engine.context.Variables["this"] = new() { data = this, type = this.GetType() }; if (s_FileLocker.TryGetValue(file.GetFullPath(), out locker) == false)
engine.context.Variables["self"] = new() { data = this, type = this.GetType() }; {
step = engine.ReRunAsync(); s_FileLocker.Add(file.GetFullPath(), locker = new object());
}
} }
lock (locker)
{
structBin = RScriptSerializer.DeserializeClass(bin.LoadAsBinary());
}
step = engine.RunAsync(structBin, importClass, variables);
} }
yield return step; yield return step;// ConventionUtility.AvoidFakeStop(step);
} }
} }
finally finally
@@ -354,7 +333,7 @@ namespace Demo
RScriptVariables variables = GenerateVariables(this); RScriptVariables variables = GenerateVariables(this);
var step = engine.RunAsync(script, importClass, variables); var step = engine.RunAsync(script, importClass, variables);
yield return step; yield return step;//ConventionUtility.AvoidFakeStop(step);
} }
finally finally
{ {

View File

@@ -50,31 +50,33 @@ namespace Demo.Game
public class SplineCore : ScriptableObject public class SplineCore : ScriptableObject
{ {
protected override bool IsSelfEnableUpdate => false;
public static SplineCore Make() public static SplineCore Make()
{ {
SplineCore result = new GameObject("").AddComponent<SplineCore>(); SplineCore result = new GameObject("").AddComponent<SplineCore>();
var core = result.GetOrAddComponent<SplineComputer>(); var core = result.GetOrAddComponent<SplineComputer>();
result.m_MySplineComputer = core;
core.multithreaded = true; core.multithreaded = true;
return result; return result;
} }
[Content] private SplineComputer m_MySplineComputer; [Content] private SplineComputer m_MySplineComputer;
[Content] public int NodeContent = 0; [Content] public int NodeContent = 0;
[Content] public readonly List<SplineNode> MySplineNodes = new(); [Content] public List<SplineNode> MySplineNodes = new();
[Content] public SplineComputer.SampleMode MySampleMode = default; [Content] public SplineComputer.SampleMode MySampleMode = default;
[Content] public Spline.Type MyType = default; [Content] public Spline.Type MyType = default;
public bool IsClose = false; public bool IsClose = false;
public SplineComputer MySplineComputer public SplineComputer MySplineComputer => m_MySplineComputer;
{ //{
get // get
{ // {
if(m_MySplineComputer==null) // if (m_MySplineComputer == null)
m_MySplineComputer= GetComponent<SplineComputer>(); // m_MySplineComputer = this.GetComponent<SplineComputer>();
return m_MySplineComputer; // return m_MySplineComputer;
} // }
} //}
/// <summary> /// <summary>
/// <see cref="SplineCore"/>需要在子<see cref="SplineNode"/>都添加后再应用脚本才能使得节点生效 /// <see cref="SplineCore"/>需要在子<see cref="SplineNode"/>都添加后再应用脚本才能使得节点生效

View File

@@ -1,4 +1,5 @@
using System.Collections; using System.Collections;
using Convention;
using Dreamteck.Splines; using Dreamteck.Splines;
using UnityEngine; using UnityEngine;
@@ -10,7 +11,9 @@ namespace Demo.Game
public static SplineNode Make() public static SplineNode Make()
{ {
return new GameObject("", typeof(Node)).AddComponent<SplineNode>(); var node = new GameObject("", typeof(Node)).AddComponent<SplineNode>();
node.m_MyNode = node.GetOrAddComponent<Node>();
return node;
} }
private Node m_MyNode; private Node m_MyNode;
@@ -21,15 +24,7 @@ namespace Demo.Game
public int MyNodeContent = 0; public int MyNodeContent = 0;
public Node MyNode public Node MyNode => m_MyNode;
{
get
{
if (m_MyNode == null)
m_MyNode = GetComponent<Node>();
return m_MyNode;
}
}
public void AddTo(SplineCore core) public void AddTo(SplineCore core)
{ {