Add prototype gameplay loop with character/battlefield assets and server game APIs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
udx
2026-10-20 18:50:00 +08:00
co-authored by Cursor
parent 79369e4473
commit 6c64210331
833 changed files with 998079 additions and 1042 deletions
@@ -1,39 +1,90 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace HotUpdate.UI
{
/// <summary>
/// UI Prefab 加载:编辑器 AssetDatabase;运行时优先 DefaultPackage 寻址。
/// 异步加载并持有资源句柄,随 UiManager 销毁统一释放。
/// </summary>
public sealed class UiPrefabLoader
public sealed class UiPrefabLoader : IDisposable
{
public const string PrefabFolder = "Assets/Bundles/UI/Prefab";
readonly ResourcePackage _preferredPackage;
readonly string _folder;
readonly Dictionary<string, GameObject> _cache = new Dictionary<string, GameObject>();
readonly List<AssetHandle> _handles = new List<AssetHandle>();
bool _disposed;
public GameObject Load(string prefabName)
public UiPrefabLoader(ResourcePackage preferredPackage = null, string folder = PrefabFolder)
{
if (string.IsNullOrEmpty(prefabName)) return null;
_preferredPackage = preferredPackage;
_folder = folder;
}
public IEnumerator LoadAsync(string prefabName, Action<GameObject> onLoaded)
{
if (_disposed || string.IsNullOrEmpty(prefabName))
{
onLoaded?.Invoke(null);
yield break;
}
if (_cache.TryGetValue(prefabName, out var cached) && cached != null)
{
onLoaded?.Invoke(cached);
yield break;
}
var packages = new List<ResourcePackage>();
if (_preferredPackage != null) packages.Add(_preferredPackage);
if (YooAssets.IsInitialized)
{
// DefaultPackage 或任意已初始化包
var packages = new[] { "DefaultPackage", "Art" };
foreach (var name in packages)
foreach (var name in new[] { "DefaultPackage", "Art" })
if (YooAssets.TryGetPackage(name, out var pkg) && !packages.Contains(pkg))
packages.Add(pkg);
}
foreach (var package in packages)
{
if (package.InitializeStatus != EOperationStatus.Succeeded) continue;
foreach (var address in new[] { prefabName, $"{_folder}/{prefabName}.prefab" })
{
if (!YooAssets.TryGetPackage(name, out var pkg)) continue;
if (pkg.InitializeStatus != EOperationStatus.Succeeded) continue;
var handle = pkg.LoadAssetSync<GameObject>(prefabName);
if (!package.IsLocationValid(address)) continue;
var handle = package.LoadAssetAsync<GameObject>(address);
_handles.Add(handle);
yield return handle;
if (_disposed) yield break;
if (handle.Status == EOperationStatus.Succeeded)
return handle.GetAssetObject<GameObject>();
{
var prefab = handle.GetAssetObject<GameObject>();
if (prefab != null)
{
_cache[prefabName] = prefab;
onLoaded?.Invoke(prefab);
yield break;
}
}
_handles.Remove(handle);
handle.Release();
}
}
#if UNITY_EDITOR
var path = $"{PrefabFolder}/{prefabName}.prefab";
return UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(path);
var editorPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>($"{_folder}/{prefabName}.prefab");
if (editorPrefab != null) _cache[prefabName] = editorPrefab;
onLoaded?.Invoke(editorPrefab);
#else
return null;
onLoaded?.Invoke(null);
#endif
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
foreach (var handle in _handles) handle.Release();
_handles.Clear();
_cache.Clear();
}
}
}