1.全阶段异步加载与AB包预加载2.node加载无效的问题依然存在

This commit is contained in:
2025-10-06 16:09:52 +08:00
parent 8f8dfcbb64
commit 334f55a250
27 changed files with 1274 additions and 1220 deletions

View File

@@ -117,7 +117,7 @@ namespace Demo.Game
yield return null;
// Setup Game Rules
// Setup Game Rules (Main)
if (Editor.EditorController.instance.MainGameController == this)
{
ScriptableObject.FastScriptableObjectTypen = content.ScriptableObjectTypen;
@@ -126,11 +126,23 @@ namespace Demo.Game
SongOffset = (float)MainConfig.FindItem(nameof(SongOffset), SongOffset);
SetupSongDuration = GameContent.instance.SetupSongDuration;
SetSongCurrentTime = GameContent.instance.SetSongCurrentTime;
}
// Setup Game Rules
{
foreach (var ab in ((string)MainConfig.FindItem(nameof(AssetBundle), "")).Split(';'))
{
if (string.IsNullOrEmpty(ab))
continue;
StartCoroutine(AssetBundlesLoadHelper.LoadAssetBundleAsync(ab.Trim(), null));
}
IsHideTrackRender = (bool)MainConfig.FindItem(nameof(IsHideTrackRender), false);
IsAutoPlay = GameContent.instance.IsAutoPlay;
WhichOpenScript = (string)MainConfig.FindItem(nameof(WhichOpenScript), WhichOpenScript);
// Open Project
WhichOpenProject = (string)MainConfig.FindItem(nameof(WhichOpenProject), WhichOpenProject);
if (string.IsNullOrEmpty(WhichOpenProject) == false)
{
string path = string.Format($"{WhichOpenProject}", $"\"{Editor.EditorController.instance.PersistentDataPath}\"") ;
string path = string.Format($"{WhichOpenProject}", $"\"{Editor.EditorController.instance.PersistentDataPath}\"");
try
{
System.Diagnostics.Process.Start(path);
@@ -141,55 +153,51 @@ namespace Demo.Game
Debug.LogException(ex, this);
}
}
CurrentProjectDefaultFileStyle = content.CurrentProjectDefaultFileStyle;
}
MainConfig.SaveProperties();
yield return null;
// Load Root Object
{
while (MainConfig.Contains("root") == false)
{
IsHideTrackRender = (bool)MainConfig.FindItem(nameof(IsHideTrackRender), false);
IsAutoPlay = GameContent.instance.IsAutoPlay;
WhichOpenScript = (string)MainConfig.FindItem(nameof(WhichOpenScript), WhichOpenScript);
CurrentProjectDefaultFileStyle = content.CurrentProjectDefaultFileStyle;
}
yield return null;
MainConfig.SaveProperties();
// Load Root Object
{
while (MainConfig.Contains("root") == false)
string defaultRootPath = "root" + CurrentProjectDefaultFileStyle switch
{
string defaultRootPath = "root" + CurrentProjectDefaultFileStyle switch
ProjectDefaultFileStyle.PY => ".py",
_ => ".cpp"
};
if (content.IsCreateNewProject)
{
MainConfig["root"] = defaultRootPath;
if (MainConfig.CreateFile(defaultRootPath))
{
ProjectDefaultFileStyle.PY => ".py",
_ => ".cpp"
};
if (content.IsCreateNewProject)
{
MainConfig["root"] = defaultRootPath;
if (MainConfig.CreateFile(defaultRootPath))
{
MainConfig.SaveProperties();
break;
}
MainConfig.SaveProperties();
break;
}
Debug.LogError($"{nameof(defaultRootPath)} is cannt create or config's root property is not exist", this);
StartCoroutine(GameExit());
yield break;
}
var rootFileName = (string)MainConfig.FindItem("root");
var rootObject = new ToolFile(Path.Combine(content.RootSourceDir, rootFileName));
rootObject.MustExistsPath();
var rootGameObject = new GameObject(rootObject.GetName(true)).AddComponent<RootObject>();
rootGameObject.transform.SetParent(transform);
rootGameObject.ScriptName = rootObject.GetName(true);
rootGameObject.audioSystem = MainAudio;
rootGameObject.EnableScript(content.RootSourceDir, rootObject.GetFullPath(), this);
try
{
yield return rootGameObject.LoadScript(rootObject.LoadAsText());
}
finally
{
MainObject = rootGameObject;
}
Debug.LogError($"{nameof(defaultRootPath)} is cannt create or config's root property is not exist", this);
StartCoroutine(GameExit());
yield break;
}
var rootFileName = (string)MainConfig.FindItem("root");
var rootObject = new ToolFile(Path.Combine(content.RootSourceDir, rootFileName));
rootObject.MustExistsPath();
var rootGameObject = new GameObject(rootObject.GetName(true)).AddComponent<RootObject>();
rootGameObject.transform.SetParent(transform);
rootGameObject.ScriptName = rootObject.GetName(true);
rootGameObject.audioSystem = MainAudio;
rootGameObject.EnableScript(content.RootSourceDir, rootObject.GetFullPath(), this);
try
{
yield return rootGameObject.LoadScript(rootObject.LoadAsText());
}
finally
{
MainObject = rootGameObject;
}
}
}

View File

@@ -569,6 +569,9 @@ namespace Demo
MyHierarchyItem.GetHierarchyItem().title = this.ScriptName + $"<{scriptType}>";
MyHierarchyItem.GetHierarchyItem().target = this;
MyHierarchyItem.GetHierarchyItem().ButtonGameObject.GetComponent<Editor.UI.RightClick>().ScriptObjectMenu = OnHierarchyItemRightClick;
var parentHierarchyItem = MyHierarchyItem.GetParent();
if (parentHierarchyItem != null)
parentHierarchyItem.GetPropertyListItem().RefreshChilds();
}
public ScriptableObject FindWithPath(string path, bool isMustExist = true)
@@ -639,6 +642,48 @@ namespace Demo
return result;
}
public IEnumerator LoadSubScriptAsync([In] string type, [In] string path, [Opt] Action<ScriptableObject> callback)
{
// 判断类型是否合法
if (DefaultInstantiate.GetScriptableObjectInstantiate().TryGetValue(type, out var creater) == false)
{
Debug.LogError($"{type} is not exist or {type}'s Instantiater is not valid", this);
callback?.Invoke(null);
yield break;
}
// 生成对象
var child = creater();
// 路径预处理
if (path.Replace('\\', '/').ToLower().StartsWith("project/"))
path = $"{new ToolFile(GetRoot().SourcePath) | path[5..]}";
// 获取文件
ToolFile file;
if (File.Exists(path))
file = new(path);
else
file = new ToolFile(SourcePath) | path;
// 找不到脚本
if (file.Exists() == false)
{
Debug.LogError($"{file}<{path}> is not found", this);
callback?.Invoke(null);
yield break;
}
child.ScriptName = file.GetName(true);
child.transform.SetParent(this.transform);
child.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
child.transform.localScale = Vector3.one;
child.EnableScript(file.GetCurrentDirName(), Path.Combine(file.GetCurrentDirName(), file.GetName(false)), type, this);
// Add Child
Childs.Add(child);
// Load Child Script
yield return child.LoadScript(file.LoadAsText());
callback?.Invoke(child);
}
/// <summary>
/// 加载子脚本
/// </summary>
@@ -651,49 +696,9 @@ namespace Demo
<param name=""type"">指定类型</param>
<param name=""path"">指定脚本,可用决定路径或与当前脚本目录的相对路径</param>
")]
[return:ReturnMayNull]
public ScriptableObject LoadSubScript(string type, string path)
public IEnumerator LoadSubScript([In] string type, [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();
// 路径预处理
if (path.Replace('\\', '/').ToLower().StartsWith("project/"))
path = $"{new ToolFile(GetRoot().SourcePath) | path[5..]}";
// 获取文件
ToolFile file;
if (File.Exists(path))
file = new(path);
else
file = new ToolFile(SourcePath)| path;
// 找不到脚本
if (file.Exists() == false)
{
Debug.LogError($"{file}<{path}> is not found", this);
return null;
}
child.ScriptName = file.GetName(true);
child.transform.SetParent(this.transform);
child.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
child.transform.localScale = Vector3.one;
child.EnableScript(file.GetCurrentDirName(), Path.Combine(file.GetCurrentDirName(), file.GetName(false)), type, this);
// Add Child
Childs.Add(child);
// Load Child Script
if (gameObject.activeInHierarchy)
StartCoroutine(child.LoadScript(file.LoadAsText()));
else
GetRoot().GetComponent<MonoBehaviour>().StartCoroutine(child.LoadScript(file.LoadAsText()));
return child;
yield return LoadSubScriptAsync(type, path, null);
}
public object DynamicBindingTarget { get; protected set; } = null;
@@ -705,6 +710,8 @@ namespace Demo
Break
}
// TODO : 过多的逻辑都挤在这里, 需要拆分
// TODO : 如何统计整个游戏关卡是否加载完成, 尤其是此处的resultEnumerator与ILoadAssetBundle, 将会同时存在多条异步加载的时间线
private IEnumerator ParseScript2Expr(string script)
{
// 预处理
@@ -816,9 +823,21 @@ namespace Demo
MethodInvokerCache[this.GetType()].Add(command, commandInfo);
}
Debug.Log($"in line \"{expr}\" of \"{ScriptPath}\", {command} is try to invoke", this);
IEnumerator resultEnumerator = null;
try
{
if (ConventionUtility.TryInvokeMember(commandInfo, this, out var _, paramsList) == false)
// 调用成功
if (ConventionUtility.TryInvokeMember(commandInfo, this, out var invokeResult, paramsList) == true)
{
Debug.Log($"in line \"{expr}\" of \"{ScriptPath}\", {command} is invoke succeed", this);
// 尤其用于加载子类时
if (invokeResult != null && invokeResult is IEnumerator _resultEnumerator)
{
resultEnumerator = _resultEnumerator;
}
}
// 调用失败
else
{
MethodInvokerCache[this.GetType()].Remove(command);
var attr = commandInfo.GetCustomAttribute<ScriptableCallAttribute>();
@@ -827,10 +846,6 @@ namespace Demo
else
Debug.LogError($"in line \"{expr}\" of \"{ScriptPath}\", {command} is failed to invoke, see: {attr.Description}", this);
}
else
{
Debug.Log($"in line \"{expr}\" of \"{ScriptPath}\", {command} is invoke succeed", this);
}
}
catch (Exception ex)
{
@@ -838,7 +853,7 @@ namespace Demo
Debug.LogException(ex, this);
yield break;
}
yield return null;
yield return resultEnumerator;
}
}
@@ -988,13 +1003,12 @@ namespace Demo
private static Dictionary<string, IEnumerator> AssetBundleLoading = new();
private static PropertiesWindow.ItemEntry AssetBundlesItemEntry = null;
public static IEnumerator LoadAssetBundle(this IAssetBundleLoader self, string ab, Action<AssetBundle> callback)
public static IEnumerator LoadAssetBundleAsync(string ab, Action<AssetBundle> callback)
{
Debug.Log($"{self.SharedInterfaceScriptObject.ScriptName}.{nameof(LoadAssetBundle)}({ab})", self.SharedInterfaceScriptObject);
if (AssetBundleCounter.TryGetValue(ab, out var result))
{
result.referenceCounter++;
callback(result.assetBundle);
callback?.Invoke(result.assetBundle);
yield break;
}
if (AssetBundleLoading.TryGetValue(ab, out var tir))
@@ -1003,7 +1017,7 @@ namespace Demo
if (AssetBundleCounter.TryGetValue(ab, out result))
{
result.referenceCounter++;
callback(result.assetBundle);
callback?.Invoke(result.assetBundle);
yield break;
}
}
@@ -1047,13 +1061,19 @@ namespace Demo
loadingHierarchyItem.title = $"{ab}<Failed>";
}
AssetBundleLoading.Remove(ab);
callback(x);
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中暂时忽略卸载功能

View File

@@ -128,17 +128,19 @@ namespace Demo.Game
childFileStream.Close();
}
//不刷新世界,直接加载
var targetChildSO = so.LoadSubScript(type, childFile);
// 打开手动编辑
try
so.StartCoroutine(so.LoadSubScriptAsync(type, childFile, targetChildSO =>
{
DefaultScriptUtility.OpenScriptFile(targetChildSO);
}
catch (Exception ex)
{
Debug.LogError($"Cannt open {childFile}", so);
Debug.LogException(ex, so);
}
// 打开手动编辑
try
{
DefaultScriptUtility.OpenScriptFile(targetChildSO);
}
catch (Exception ex)
{
Debug.LogError($"Cannt open {childFile}", so);
Debug.LogException(ex, so);
}
}));
}
}
else

View File

@@ -56,6 +56,12 @@ namespace Demo.Game
}
}
public override void ResetEnterGameStatus()
{
base.ResetEnterGameStatus();
UpdateEntry(0, 0);
}
public override IEnumerator UnloadScript()
{
Content = 0;
@@ -71,18 +77,8 @@ namespace Demo.Game
return (currentTime - Entries[Content].TimePoint) / (Entries[Content + 1].TimePoint - Entries[Content].TimePoint);
}
if (Entries.Count == 0)
if (Entries.Count <= 1)
return;
if (Entries.Count == 1)
{
UpdateEntry(0, 0);
return;
}
// TODO : 删除后存在问题
if (Entries[0].TimePoint <= 0 && tickType == TickType.Reset)
{
UpdateEntry(0, 0);
}
switch (tickType)
{
case TickType.Reset: