refactor : 代码重构

This commit is contained in:
何冠峰
2026-04-28 10:52:01 +08:00
parent 5b81269090
commit a265b85d37
205 changed files with 3715 additions and 7726 deletions

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 0f79d08cddb5196408cff10f6750ae69
guid: 682ac5046f4686946b0003a449638651
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,61 @@
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(GameObjectReference))]
public class GameObjectReferenceDrawer : PropertyDrawer
{
private const float LineSpacing = 2f;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
SerializedProperty packageNameProp = property.FindPropertyRelative("_packageName");
SerializedProperty assetGUIDProp = property.FindPropertyRelative("_assetGUID");
EditorGUI.BeginProperty(position, label, property);
{
float lineHeight = EditorGUIUtility.singleLineHeight;
Rect line = new Rect(position.x, position.y, position.width, lineHeight);
// 绘制 PackageName
packageNameProp.stringValue = EditorGUI.TextField(line, "Package Name", packageNameProp.stringValue);
// 加载 GameObject
string assetGUID = assetGUIDProp.stringValue;
GameObject current = null;
if (string.IsNullOrEmpty(assetGUID) == false)
{
string assetPath = AssetDatabase.GUIDToAssetPath(assetGUID);
if (string.IsNullOrEmpty(assetPath) == false)
current = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
}
// 绘制 GameObject
line.y += lineHeight + LineSpacing;
GameObject newAsset = (GameObject)EditorGUI.ObjectField(line, "Game Object", current, typeof(GameObject), false);
if (newAsset != current)
{
if (newAsset == null)
{
assetGUIDProp.stringValue = "";
}
else
{
string newPath = AssetDatabase.GetAssetPath(newAsset);
if (string.IsNullOrEmpty(newPath) == false)
assetGUIDProp.stringValue = AssetDatabase.AssetPathToGUID(newPath);
}
}
// 绘制 AssetGUID
line.y += lineHeight + LineSpacing;
EditorGUI.BeginDisabledGroup(true);
EditorGUI.TextField(line, "Asset GUID", assetGUIDProp.stringValue);
EditorGUI.EndDisabledGroup();
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.singleLineHeight * 3 + LineSpacing * 2;
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ec9d17e765ccd4642aa3aa9ca0580799
guid: 53eb285fc3a7b614089a000f8c9c738c
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,17 +1,31 @@
using System;
using System;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
/// <summary>
/// 提供构建缓存清理菜单入口
/// </summary>
internal class ClearBuildCacheWindow
{
private const string SBPEditorAssemblyName = "Unity.ScriptableBuildPipeline.Editor";
private const string SBPBuildCacheTypeName = "UnityEditor.Build.Pipeline.Utilities.BuildCache";
[MenuItem("Tools/Clear Build Cache", false, 2)]
public static void OpenWindow()
{
// 清空SBP构建缓存
UnityEditor.Build.Pipeline.Utilities.BuildCache.PurgeCache(false);
var buildCacheType = Type.GetType($"{SBPBuildCacheTypeName}, {SBPEditorAssemblyName}");
if (buildCacheType != null)
{
EditorAssemblyUtility.InvokePublicStaticMethod(buildCacheType, "PurgeCache", false);
}
else
{
Debug.LogWarning($"Failed to find type: {SBPBuildCacheTypeName}");
}
// 删除AssetDependDB文件
string projectPath = YooAsset.Editor.EditorPathUtility.GetProjectPath();
@@ -20,6 +34,8 @@ namespace YooAsset.Editor
{
File.Delete(databaseFilePath);
}
Debug.Log("Clear build cache succeeded !");
}
}
}

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -6,16 +6,19 @@ using UnityEditor;
namespace YooAsset.Editor
{
public class CreateBuildinCatalogWindow : EditorWindow
/// <summary>
/// 提供内置资源清单生成工具窗口
/// </summary>
public class CreateBuiltinCatalogWindow : EditorWindow
{
static CreateBuildinCatalogWindow _thisInstance;
static CreateBuiltinCatalogWindow _thisInstance;
[MenuItem("Tools/内置清单生成工具Catalog", false, 101)]
[MenuItem("Tools/Builtin Catalog Generator", false, 101)]
static void ShowWindow()
{
if (_thisInstance == null)
{
_thisInstance = EditorWindow.GetWindow(typeof(CreateBuildinCatalogWindow), false, "内置清单生成工具", true) as CreateBuildinCatalogWindow;
_thisInstance = EditorWindow.GetWindow(typeof(CreateBuiltinCatalogWindow), false, "Builtin Catalog Generator", true) as CreateBuiltinCatalogWindow;
_thisInstance.minSize = new Vector2(800, 600);
}
_thisInstance.Show();
@@ -27,7 +30,7 @@ namespace YooAsset.Editor
{
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("选择内置资源目录", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Select Builtin Resource Directory", GUILayout.MaxWidth(250)))
{
string resultPath = EditorUtility.OpenFolderPanel("Find", "Assets/", "StreamingAssets");
if (!string.IsNullOrEmpty(resultPath))
@@ -38,7 +41,7 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(_directoryRoot) == false)
{
if (GUILayout.Button("生成Catalog文件", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Generate Catalog File", GUILayout.MaxWidth(150)))
{
CreateCatalogFile(_directoryRoot);
}
@@ -47,6 +50,13 @@ namespace YooAsset.Editor
private void CreateCatalogFile(string directoryRoot)
{
// 检查目录是否存在
if (Directory.Exists(directoryRoot) == false)
{
Debug.LogError("Selected directory does not exist.");
return;
}
// 搜索所有Package目录
List<string> packageRoots = GetPackageRoots(directoryRoot);
foreach (var packageRoot in packageRoots)
@@ -55,26 +65,20 @@ namespace YooAsset.Editor
string packageName = directoryInfo.Name;
try
{
bool result = BuiltinCatalogHelper.CreateFile(null, packageName, packageRoot); //TODO 自行处理解密
bool result = BuiltinCatalogHelper.CreateFile(null, packageName, packageRoot); // TODO: 根据业务需求处理清单解密
if (result == false)
{
Debug.LogError($"Create package {packageName} catalog file failed ! See the detail error in console !");
Debug.LogError($"Failed to create a catalog file for package '{packageName}'. See Console for details.");
}
}
catch (System.Exception ex)
{
Debug.LogError($"Create package {packageName} catalog file failed ! {ex.Message}");
Debug.LogError($"Failed to create a catalog file for package '{packageName}': {ex.Message}.");
}
}
}
private List<string> GetPackageRoots(string rootPath)
{
// 检查目录是否存在
if (Directory.Exists(rootPath) == false)
{
throw new DirectoryNotFoundException($"目录不存在: {rootPath}");
}
// 搜索所有 .version 文件(包含子目录)
string[] versionFiles = Directory.GetFiles(
rootPath,

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -6,16 +6,19 @@ using UnityEditor;
namespace YooAsset.Editor
{
/// <summary>
/// 提供空资源清单生成工具窗口
/// </summary>
public class CreateEmptyCatalogWindow : EditorWindow
{
static CreateEmptyCatalogWindow _thisInstance;
[MenuItem("Tools/空清单生成工具Catalog", false, 102)]
[MenuItem("Tools/Empty Catalog Generator", false, 102)]
static void ShowWindow()
{
if (_thisInstance == null)
{
_thisInstance = EditorWindow.GetWindow(typeof(CreateEmptyCatalogWindow), false, "空清单生成工具", true) as CreateEmptyCatalogWindow;
_thisInstance = EditorWindow.GetWindow(typeof(CreateEmptyCatalogWindow), false, "Empty Catalog Generator", true) as CreateEmptyCatalogWindow;
_thisInstance.minSize = new Vector2(800, 600);
}
_thisInstance.Show();
@@ -32,9 +35,9 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(_packageName) == false)
{
if (GUILayout.Button("生成空的Catalog文件", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Generate Empty Catalog File", GUILayout.MaxWidth(150)))
{
string outputPath = EditorDialogUtility.OpenFolderPanel("输出目录", "Assets/");
string outputPath = EditorDialogUtility.OpenFolderPanel("Output Directory", "Assets/");
if (string.IsNullOrEmpty(outputPath) == false)
{
CreateEmptyCatalogFile(outputPath);
@@ -50,12 +53,12 @@ namespace YooAsset.Editor
bool result = BuiltinCatalogHelper.CreateEmptyFile(_packageName, string.Empty, outputPath);
if (result == false)
{
Debug.LogError($"Create package {_packageName} catalog file failed ! See the detail error in console !");
Debug.LogError($"Failed to create a catalog file for package '{_packageName}'. See Console for details.");
}
}
catch (System.Exception ex)
{
Debug.LogError($"Create package {_packageName} catalog file failed ! {ex.Message}");
Debug.LogError($"Failed to create a catalog file for package '{_packageName}': {ex.Message}.");
}
}
}

View File

@@ -8,6 +8,9 @@ using UnityEditor.UIElements;
using UnityEngine.UIElements;
using YooAsset.Editor;
/// <summary>
/// 提供自定义构建管线的编辑器视图
/// </summary>
[BuildPipelineAttribute("CustomBuildPipeline")]
internal class CustomBuildPipelineViewer : LegacyBuildPipelineViewer
{

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using YooAsset.Editor;
/// <summary>
/// 按文件名生成资源定位地址
/// </summary>
[DisplayName("定位地址: 文件名.智能尾缀")]
public class AddressByFileNameAndExt : IAddressRule
{
/// <inheritdoc/>
public string GetAssetAddress(AddressRuleData data)
{
var extension = Path.GetExtension(data.AssetPath);
if (extension == ".asset")
{
var asset = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(data.AssetPath);
if (asset == null)
throw new InvalidOperationException($"Asset not found: '{data.AssetPath}'.");
var assetType = asset.GetType();
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(data.AssetPath);
return fileNameWithoutExtension + $".{assetType.Name.ToLowerInvariant()}";
}
return Path.GetFileName(data.AssetPath);
}
}

View File

@@ -1,25 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using YooAsset.Editor;
[DisplayName("定位地址: 文件名.智能尾缀")]
public class AddressByFileNameAndExt : IAddressRule
{
public string GetAssetAddress(AddressRuleData data)
{
var ext = Path.GetExtension(data.AssetPath);
if (ext == ".asset")
{
var a = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(data.AssetPath);
if (a == null) return ".errortype";
var type = a.GetType();
var dt = Path.GetFileNameWithoutExtension(data.AssetPath);
return dt + $".{type.Name.ToLowerInvariant()}";
}
return Path.GetFileName(data.AssetPath);
}
}

View File

@@ -1,20 +1,24 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using YooAsset.Editor;
/// <summary>
/// 将特效纹理按首字符分组到资源包
/// </summary>
[DisplayName("打包特效纹理(自定义)")]
public class PackEffectTexture : IBundlePackRule
{
private const string PackDirectory = "Assets/Effect/Textures/";
/// <inheritdoc/>
BundlePackRuleResult IBundlePackRule.GetPackRuleResult(BundlePackRuleData data)
{
string assetPath = data.AssetPath;
if (assetPath.StartsWith(PackDirectory) == false)
throw new Exception($"Only support folder : {PackDirectory}");
throw new ArgumentException($"Only support folder: {PackDirectory}", nameof(data));
string assetName = Path.GetFileName(assetPath).ToLower();
string firstChar = assetName.Substring(0, 1);
@@ -24,9 +28,13 @@ public class PackEffectTexture : IBundlePackRule
}
}
/// <summary>
/// 按视频资源路径生成原始文件资源包
/// </summary>
[DisplayName("打包视频(自定义)")]
public class PackVideo : IBundlePackRule
{
/// <inheritdoc/>
public BundlePackRuleResult GetPackRuleResult(BundlePackRuleData data)
{
string bundleName = RemoveExtension(data.AssetPath);

View File

@@ -1,18 +1,21 @@
using System.Collections.Generic;
using System.Collections.Generic;
#if YOO_MACRO_SUPPORT
namespace YooAsset.Editor
{
public class MacroDefine
/// <summary>
/// 提供 YooAsset 版本相关的脚本宏定义
/// </summary>
public static class MacroDefine
{
/// <summary>
/// YooAsset版本宏定义
/// YooAsset 版本宏定义集合
/// </summary>
public static readonly List<string> Macros = new List<string>()
public static IReadOnlyList<string> Macros { get; } = new List<string>()
{
"YOO_ASSET_2",
"YOO_ASSET_2_3",
"YOO_ASSET_2_3_OR_NEWER",
"YOO_ASSET_3",
"YOO_ASSET_3_0",
"YOO_ASSET_3_0_OR_NEWER",
};
}
}

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@@ -8,6 +8,9 @@ using UnityEditor;
#if YOO_MACRO_SUPPORT
namespace YooAsset.Editor
{
/// <summary>
/// 在生成 C# 工程文件时注入 YooAsset 版本宏定义
/// </summary>
[InitializeOnLoad]
public class MacroProcessor : AssetPostprocessor
{
@@ -41,7 +44,7 @@ namespace YooAsset.Editor
}
/// <summary>
/// 处理宏定义
/// 处理工程文件中的宏定义
/// </summary>
private static bool ProcessDefineConstants(XmlElement element)
{
@@ -76,7 +79,7 @@ namespace YooAsset.Editor
}
/// <summary>
/// 检工程是否引用了YooAsset
/// 检工程是否引用了 YooAsset
/// </summary>
private static bool IsCSProjectReferenced(XmlElement element)
{
@@ -93,7 +96,11 @@ namespace YooAsset.Editor
if (childNode.Name != "Reference" && childNode.Name != "ProjectReference")
continue;
string include = childNode.Attributes["Include"].Value;
XmlAttribute includeAttribute = childNode.Attributes["Include"];
if (includeAttribute == null)
continue;
string include = includeAttribute.Value;
if (include.Contains("YooAsset"))
return true;
}

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@@ -9,10 +9,13 @@ using UnityEngine;
#if YOO_MACRO_SUPPORT
namespace YooAsset.Editor.Experiment
{
/// <summary>
/// 通过 csc.rsp 文件注入 YooAsset 版本宏定义
/// </summary>
[InitializeOnLoad]
public class RspGenerator
{
// csc.rsp文件路径
// Unity 编译器响应文件路径
private static string RspFilePath => Path.Combine(Application.dataPath, "csc.rsp");
static RspGenerator()
@@ -21,9 +24,9 @@ namespace YooAsset.Editor.Experiment
}
/// <summary>
/// 更新csc.rsp文件
/// 更新 csc.rsp 文件
/// </summary>
private static void UpdateRspFile(List<string> addMacros, List<string> removeMacros)
private static void UpdateRspFile(IReadOnlyList<string> addMacros, IReadOnlyList<string> removeMacros)
{
var existingDefines = new HashSet<string>();
var otherLines = new List<string>();
@@ -34,24 +37,26 @@ namespace YooAsset.Editor.Experiment
// 2. 添加新宏
if (addMacros != null && addMacros.Count > 0)
{
addMacros.ForEach(x =>
foreach (var x in addMacros)
{
if (existingDefines.Contains(x) == false)
existingDefines.Add(x);
});
}
}
// 3. 移除指定宏
if (removeMacros != null && removeMacros.Count > 0)
{
removeMacros.ForEach(x =>
foreach (var x in removeMacros)
{
existingDefines.Remove(x);
});
}
}
// 4. 重新生成内容
WriteRspFile(existingDefines, otherLines);
bool changed = WriteRspFile(existingDefines, otherLines);
if (changed == false)
return;
// 5. 刷新AssetDatabase
AssetDatabase.Refresh();
@@ -59,7 +64,7 @@ namespace YooAsset.Editor.Experiment
}
/// <summary>
/// 读取csc.rsp文件,返回宏定义和其他行
/// 读取 csc.rsp 文件中的宏定义和其他行
/// </summary>
private static void ReadRspFile(HashSet<string> defines, List<string> others)
{
@@ -90,9 +95,10 @@ namespace YooAsset.Editor.Experiment
}
/// <summary>
/// 重新写入csc.rsp文件
/// 重新写入 csc.rsp 文件
/// </summary>
private static void WriteRspFile(HashSet<string> defines, List<string> others)
/// <returns>文件内容发生变化时返回 true</returns>
private static bool WriteRspFile(HashSet<string> defines, List<string> others)
{
StringBuilder sb = new StringBuilder();
if (others != null && others.Count > 0)
@@ -108,7 +114,16 @@ namespace YooAsset.Editor.Experiment
}
}
File.WriteAllText(RspFilePath, sb.ToString());
string newContent = sb.ToString();
if (File.Exists(RspFilePath))
{
string oldContent = File.ReadAllText(RspFilePath);
if (oldContent == newContent)
return false;
}
File.WriteAllText(RspFilePath, newContent);
return true;
}
}
}

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -6,16 +6,19 @@ using UnityEditor;
namespace YooAsset.Editor
{
/// <summary>
/// 提供补丁包差异比对工具窗口
/// </summary>
public class PackageComparatorWindow : EditorWindow
{
static PackageComparatorWindow _thisInstance;
[MenuItem("Tools/补丁包比对工具", false, 103)]
[MenuItem("Tools/Patch Package Comparator", false, 103)]
static void ShowWindow()
{
if (_thisInstance == null)
{
_thisInstance = EditorWindow.GetWindow(typeof(PackageComparatorWindow), false, "补丁包比对工具", true) as PackageComparatorWindow;
_thisInstance = EditorWindow.GetWindow(typeof(PackageComparatorWindow), false, "Patch Package Comparator", true) as PackageComparatorWindow;
_thisInstance.minSize = new Vector2(800, 600);
}
_thisInstance.Show();
@@ -32,7 +35,7 @@ namespace YooAsset.Editor
{
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("选择补丁包1", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Select Patch Package 1", GUILayout.MaxWidth(150)))
{
string resultPath = EditorUtility.OpenFilePanel("Find", "Assets/", "bytes");
if (string.IsNullOrEmpty(resultPath))
@@ -44,7 +47,7 @@ namespace YooAsset.Editor
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("选择补丁包2", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Select Patch Package 2", GUILayout.MaxWidth(150)))
{
string resultPath = EditorUtility.OpenFilePanel("Find", "Assets/", "bytes");
if (string.IsNullOrEmpty(resultPath))
@@ -56,9 +59,18 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(_manifestPath1) == false && string.IsNullOrEmpty(_manifestPath2) == false)
{
if (GUILayout.Button("比对差异", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Compare Differences", GUILayout.MaxWidth(150)))
{
ComparePackage(_changeList, _newList);
try
{
ComparePackage(_changeList, _newList);
}
catch (System.Exception ex)
{
_changeList.Clear();
_newList.Clear();
Debug.LogError($"Failed to compare patch packages: {ex.Message}.");
}
}
}
@@ -66,7 +78,7 @@ namespace YooAsset.Editor
using (new EditorGUI.DisabledScope(false))
{
int totalCount = _changeList.Count;
EditorGUILayout.Foldout(true, $"差异列表 ( {totalCount} )");
EditorGUILayout.Foldout(true, $"Changed Bundles ( {totalCount} )");
EditorGUI.indentLevel = 1;
_scrollPos1 = EditorGUILayout.BeginScrollView(_scrollPos1);
@@ -84,7 +96,7 @@ namespace YooAsset.Editor
using (new EditorGUI.DisabledScope(false))
{
int totalCount = _newList.Count;
EditorGUILayout.Foldout(true, $"新增列表 ( {totalCount} )");
EditorGUILayout.Foldout(true, $"New Bundles ( {totalCount} )");
EditorGUI.indentLevel = 1;
_scrollPos2 = EditorGUILayout.BeginScrollView(_scrollPos2);
@@ -104,13 +116,13 @@ namespace YooAsset.Editor
changeList.Clear();
newList.Clear();
// 加载补丁清单1
// 加载基准补丁清单
byte[] bytesData1 = FileUtility.ReadAllBytes(_manifestPath1);
PackageManifest manifest1 = PackageManifestHelper.DeserializeManifestFromBinary(bytesData1, null); //TODO 自行处理解密
PackageManifest manifest1 = PackageManifestHelper.DeserializeManifestFromBinary(bytesData1, null); // TODO: 根据业务需求处理清单解密
// 加载补丁清单1
// 加载待比对补丁清单
byte[] bytesData2 = FileUtility.ReadAllBytes(_manifestPath2);
PackageManifest manifest2 = PackageManifestHelper.DeserializeManifestFromBinary(bytesData2, null); //TODO 自行处理解密
PackageManifest manifest2 = PackageManifestHelper.DeserializeManifestFromBinary(bytesData2, null); // TODO: 根据业务需求处理清单解密
// 拷贝文件列表
foreach (var bundle2 in manifest2.BundleList)
@@ -132,7 +144,7 @@ namespace YooAsset.Editor
changeList.Sort((x, y) => string.Compare(x.BundleName, y.BundleName));
newList.Sort((x, y) => string.Compare(x.BundleName, y.BundleName));
Debug.Log("资源包差异比对完成!");
Debug.Log("Package comparison completed.");
}
}
}

View File

@@ -4,16 +4,19 @@ using UnityEditor;
namespace YooAsset.Editor
{
/// <summary>
/// 提供补丁包导入工具窗口
/// </summary>
public class PackageImporterWindow : EditorWindow
{
static PackageImporterWindow _thisInstance;
[MenuItem("Tools/补丁包导入工具", false, 104)]
[MenuItem("Tools/Patch Package Importer", false, 104)]
static void ShowWindow()
{
if (_thisInstance == null)
{
_thisInstance = EditorWindow.GetWindow(typeof(PackageImporterWindow), false, "补丁包导入工具", true) as PackageImporterWindow;
_thisInstance = EditorWindow.GetWindow(typeof(PackageImporterWindow), false, "Patch Package Importer", true) as PackageImporterWindow;
_thisInstance.minSize = new Vector2(800, 600);
}
_thisInstance.Show();
@@ -26,7 +29,12 @@ namespace YooAsset.Editor
{
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("选择补丁包", GUILayout.MaxWidth(150)))
_packageName = EditorGUILayout.TextField("Package Name", _packageName);
EditorGUILayout.EndHorizontal();
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Select Patch Package", GUILayout.MaxWidth(150)))
{
string resultPath = EditorUtility.OpenFilePanel("Find", "Assets/", "bytes");
if (!string.IsNullOrEmpty(resultPath))
@@ -37,54 +45,84 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(_manifestPath) == false)
{
if (GUILayout.Button("导入补丁包(全部文件)", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Import Patch Package (All Files)", GUILayout.MaxWidth(150)))
{
string streamingAssetsRoot = BundleBuilderHelper.GetStreamingAssetsRoot();
EditorFileUtility.ClearFolder(streamingAssetsRoot);
CopyPackageFiles(_manifestPath);
if (string.IsNullOrEmpty(_packageName))
{
Debug.LogError("Package name is empty.");
return;
}
try
{
CopyPackageFiles(_manifestPath);
}
catch (System.Exception ex)
{
Debug.LogError($"Failed to import patch package '{_packageName}': {ex.Message}.");
}
finally
{
AssetDatabase.Refresh();
}
}
}
}
private void CopyPackageFiles(string manifestFilePath)
{
string manifestFileName = Path.GetFileNameWithoutExtension(manifestFilePath);
string outputDirectory = Path.GetDirectoryName(manifestFilePath);
string sourceRoot = Path.GetDirectoryName(manifestFilePath);
if (string.IsNullOrEmpty(sourceRoot))
throw new DirectoryNotFoundException("Patch package directory does not exist.");
string versionFileName = YooAssetConfiguration.GetPackageVersionFileName(_packageName);
string versionSourcePath = Path.Combine(sourceRoot, versionFileName);
string packageVersion = File.ReadAllText(versionSourcePath).Trim();
string manifestFileName = YooAssetConfiguration.GetManifestBinaryFileName(_packageName, packageVersion);
string hashFileName = YooAssetConfiguration.GetPackageHashFileName(_packageName, packageVersion);
string selectedFileName = Path.GetFileName(manifestFilePath);
if (selectedFileName != manifestFileName)
throw new InvalidDataException($"Selected manifest file '{selectedFileName}' does not match expected manifest file '{manifestFileName}'.");
string destRoot = Path.Combine(BundleBuilderHelper.GetStreamingAssetsRoot(), _packageName);
// 清空旧目录
EditorFileUtility.DeleteDirectory(destRoot);
EditorFileUtility.CreateDirectory(destRoot);
// 拷贝核心文件
{
string sourcePath = $"{outputDirectory}/{manifestFileName}.bytes";
string destPath = $"{BundleBuilderHelper.GetStreamingAssetsRoot()}/{_packageName}/{manifestFileName}.bytes";
string sourcePath = Path.Combine(sourceRoot, manifestFileName);
string destPath = Path.Combine(destRoot, manifestFileName);
EditorFileUtility.CopyFile(sourcePath, destPath, true);
}
{
string sourcePath = $"{outputDirectory}/{manifestFileName}.hash";
string destPath = $"{BundleBuilderHelper.GetStreamingAssetsRoot()}/{_packageName}/{manifestFileName}.hash";
string sourcePath = Path.Combine(sourceRoot, hashFileName);
string destPath = Path.Combine(destRoot, hashFileName);
EditorFileUtility.CopyFile(sourcePath, destPath, true);
}
{
string fileName = YooAssetConfiguration.GetPackageVersionFileName(_packageName);
string sourcePath = $"{outputDirectory}/{fileName}";
string destPath = $"{BundleBuilderHelper.GetStreamingAssetsRoot()}/{_packageName}/{fileName}";
string sourcePath = versionSourcePath;
string destPath = Path.Combine(destRoot, versionFileName);
EditorFileUtility.CopyFile(sourcePath, destPath, true);
}
// 加载补丁清单
byte[] bytesData = FileUtility.ReadAllBytes(manifestFilePath);
PackageManifest manifest = PackageManifestHelper.DeserializeManifestFromBinary(bytesData, null); //TODO 自行处理解密
PackageManifest manifest = PackageManifestHelper.DeserializeManifestFromBinary(bytesData, null); // TODO: 根据业务需求处理清单解密
// 拷贝文件列表
int fileCount = 0;
foreach (var packageBundle in manifest.BundleList)
{
fileCount++;
string sourcePath = $"{outputDirectory}/{packageBundle.GetFileName()}";
string destPath = $"{BundleBuilderHelper.GetStreamingAssetsRoot()}/{_packageName}/{packageBundle.GetFileName()}";
string fileName = packageBundle.GetFileName();
string sourcePath = Path.Combine(sourceRoot, fileName);
string destPath = Path.Combine(destRoot, fileName);
EditorFileUtility.CopyFile(sourcePath, destPath, true);
}
Debug.Log($"补丁包拷贝完成,一共拷贝了{fileCount}个资源文件");
AssetDatabase.Refresh();
Debug.Log($"Patch package copy completed. Copied {fileCount} bundle files.");
}
}
}

View File

@@ -5,23 +5,26 @@ using YooAsset.Editor;
namespace YooAsset
{
/// <summary>
/// 在应用构建前生成内置资源清单
/// </summary>
public class PreprocessBuildCatalog : UnityEditor.Build.IPreprocessBuildWithReport
{
/// <summary>
/// 构建预处理回调顺序
/// </summary>
public int callbackOrder { get { return 0; } }
/// <summary>
/// 在构建应用程序前自动生成内置资源目录文件。
/// 原理搜索StreamingAssets目录下的所有资源文件将这些文件信息写入文件然后在运行时做查询用途。
/// </summary>
/// <inheritdoc/>
public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
{
YooLogger.Log("Begin to create catalog file !");
YooLogger.Log("Starting catalog file generation.");
string rootPath = BundleBuilderHelper.GetStreamingAssetsRoot();
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists == false)
{
Debug.LogWarning($"Can not found StreamingAssets root directory : {rootPath}");
Debug.LogWarning("StreamingAssets root directory does not exist.");
return;
}
@@ -30,18 +33,18 @@ namespace YooAsset
foreach (var subDirectory in subDirectories)
{
string packageName = subDirectory.Name;
string pacakgeDirectory = subDirectory.FullName;
string packageDirectory = subDirectory.FullName;
try
{
bool result = BuiltinCatalogHelper.CreateFile(null, packageName, pacakgeDirectory); //TODO 自行处理解密
bool result = BuiltinCatalogHelper.CreateFile(null, packageName, packageDirectory); // TODO: 根据业务需求处理清单解密
if (result == false)
{
Debug.LogError($"Create package {packageName} catalog file failed ! See the detail error in console !");
Debug.LogError($"Failed to create a catalog file for package '{packageName}'. See Console for details.");
}
}
catch (System.Exception ex)
{
Debug.LogError($"Create package {packageName} catalog file failed ! {ex.Message}");
Debug.LogError($"Failed to create a catalog file for package '{packageName}': {ex.Message}.");
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
@@ -7,28 +7,51 @@ using UnityEngine.Rendering;
using UnityEditor;
using YooAsset.Editor;
/// <summary>
/// 封装 Unity 编辑器中的 ShaderVariantCollection 反射调用
/// </summary>
public static class ShaderVariantCollectionHelper
{
/// <summary>
/// 清空当前编辑器记录的着色器变种集合
/// </summary>
public static void ClearCurrentShaderVariantCollection()
{
EditorAssemblyUtility.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "ClearCurrentShaderVariantCollection");
}
/// <summary>
/// 保存当前编辑器记录的着色器变种集合
/// </summary>
/// <param name="savePath">保存目标路径</param>
public static void SaveCurrentShaderVariantCollection(string savePath)
{
EditorAssemblyUtility.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "SaveCurrentShaderVariantCollection", savePath);
}
/// <summary>
/// 当前着色器变种集合中的着色器数量
/// </summary>
/// <returns>着色器数量</returns>
public static int GetCurrentShaderVariantCollectionShaderCount()
{
return (int)EditorAssemblyUtility.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "GetCurrentShaderVariantCollectionShaderCount");
}
/// <summary>
/// 当前着色器变种集合中的变种数量
/// </summary>
/// <returns>变种数量</returns>
public static int GetCurrentShaderVariantCollectionVariantCount()
{
return (int)EditorAssemblyUtility.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "GetCurrentShaderVariantCollectionVariantCount");
}
/// <summary>
/// 获取着色器的变种总数量
/// 获取指定着色器资源的变种总数量
/// </summary>
/// <param name="assetPath">着色器资源路径</param>
/// <returns>变种总数量的字符串表示</returns>
public static string GetShaderVariantCount(string assetPath)
{
Shader shader = AssetDatabase.LoadAssetAtPath<Shader>(assetPath);

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
@@ -7,50 +7,70 @@ using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;
/// <summary>
/// 着色器变种集合的可序列化清单
/// </summary>
[Serializable]
public class ShaderVariantCollectionManifest
{
/// <summary>
/// 单个着色器变种的序列化信息
/// </summary>
[Serializable]
public class ShaderVariantElement : IComparable<ShaderVariantElement>
{
/// <summary>
/// 用于稳定排序的组合键
/// </summary>
public string SortValue { private set; get; }
/// <summary>
/// Pass type to use in this variant.
/// 变种使用的渲染通道类型
/// </summary>
public PassType PassType;
/// <summary>
/// Array of shader keywords to use in this variant.
/// 变种使用的着色器关键字数组
/// </summary>
public string[] Keywords;
/// <summary>
/// 生成排序键
/// </summary>
public void MakeSortValue()
{
string combineKeyword = string.Empty;
for (int i = 0; i < Keywords.Length; i++)
{
if (i == 0)
combineKeyword = Keywords[0];
combineKeyword = Keywords[i];
else
combineKeyword = $"{combineKeyword}+{Keywords[0]}";
combineKeyword = $"{combineKeyword}+{Keywords[i]}";
}
SortValue = $"{PassType}+{combineKeyword}";
}
/// <inheritdoc/>
public int CompareTo(ShaderVariantElement other)
{
return SortValue.CompareTo(other.SortValue);
}
}
/// <summary>
/// 单个着色器及其变种列表的序列化信息
/// </summary>
[Serializable]
public class ShaderVariantInfo : IComparable<ShaderVariantInfo>
{
/// <summary>
/// 用于稳定排序的组合键
/// </summary>
public string SortValue { private set; get; }
/// <summary>
/// 着色器资源路径.
/// 着色器资源路径
/// </summary>
public string AssetPath;
@@ -69,10 +89,15 @@ public class ShaderVariantCollectionManifest
/// </summary>
public List<ShaderVariantElement> ShaderVariantElements = new List<ShaderVariantElement>(1000);
/// <summary>
/// 生成排序键
/// </summary>
public void MakeSortValue()
{
SortValue = AssetPath + "+" + ShaderName;
}
/// <inheritdoc/>
public int CompareTo(ShaderVariantInfo other)
{
return SortValue.CompareTo(other.SortValue);
@@ -81,33 +106,36 @@ public class ShaderVariantCollectionManifest
/// <summary>
/// Number of shaders in this collection
/// 清单中的着色器总数
/// </summary>
public int ShaderTotalCount;
/// <summary>
/// Number of total varians in this collection
/// 清单中的变种总数
/// </summary>
public int VariantTotalCount;
/// <summary>
/// Shader variants info list.
/// 着色器变种信息列表
/// </summary>
public List<ShaderVariantInfo> ShaderVariantInfos = new List<ShaderVariantInfo>(1000);
/// <summary>
/// 添加着色器变种信息
/// </summary>
/// <param name="assetPath">着色器资源路径</param>
/// <param name="shaderName">着色器名称</param>
/// <param name="passType">渲染通道类型</param>
/// <param name="keywords">着色器关键字数组</param>
public void AddShaderVariant(string assetPath, string shaderName, PassType passType, string[] keywords)
{
// 排序Keyword列表
List<string> temper = new List<string>(keywords);
temper.Sort();
List<string> sortedKeywords = new List<string>(keywords);
sortedKeywords.Sort();
var info = GetOrCreateShaderVariantInfo(assetPath, shaderName);
ShaderVariantElement element = new ShaderVariantElement();
element.PassType = passType;
element.Keywords = temper.ToArray();
element.Keywords = sortedKeywords.ToArray();
element.MakeSortValue();
info.ShaderVariantElements.Add(element);
info.ShaderVariantCount++;
@@ -126,20 +154,22 @@ public class ShaderVariantCollectionManifest
}
if (selectList.Count != 1)
throw new Exception("Should never get here !");
throw new InvalidOperationException($"Unexpected duplicate ShaderVariantInfo entries (count={selectList.Count}).");
return selectList[0];
}
/// <summary>
/// 解析SVC文件并将数据写入到清单
/// 从 ShaderVariantCollection 提取清单数据
/// </summary>
/// <param name="svc">待解析的着色器变种集合</param>
/// <returns>提取后的着色器变种清单</returns>
public static ShaderVariantCollectionManifest Extract(ShaderVariantCollection svc)
{
if (svc == null)
throw new ArgumentNullException(nameof(svc));
var manifest = new ShaderVariantCollectionManifest();
manifest.ShaderTotalCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionShaderCount();
manifest.VariantTotalCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionVariantCount();
using (var so = new SerializedObject(svc))
{
@@ -149,30 +179,23 @@ public class ShaderVariantCollectionManifest
for (int i = 0; i < shaderArray.arraySize; ++i)
{
var shaderRef = shaderArray.FindPropertyRelative($"data[{i}].first");
var shader = shaderRef.objectReferenceValue as Shader;
if (shader == null)
throw new InvalidOperationException("Invalid shader in ShaderVariantCollection file.");
string shaderAssetPath = AssetDatabase.GetAssetPath(shader);
string shaderName = shader.name;
// 添加变种信息
var shaderVariantsArray = shaderArray.FindPropertyRelative($"data[{i}].second.variants");
if (shaderRef != null && shaderRef.propertyType == SerializedPropertyType.ObjectReference && shaderVariantsArray != null && shaderVariantsArray.isArray)
for (int j = 0; j < shaderVariantsArray.arraySize; ++j)
{
var shader = shaderRef.objectReferenceValue as Shader;
if (shader == null)
{
throw new Exception("Invalid shader in ShaderVariantCollection file.");
}
var propKeywords = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].keywords");
var propPassType = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].passType");
string shaderAssetPath = AssetDatabase.GetAssetPath(shader);
string shaderName = shader.name;
// 添加变种信息
for (int j = 0; j < shaderVariantsArray.arraySize; ++j)
{
var propKeywords = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].keywords");
var propPassType = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].passType");
if (propKeywords != null && propPassType != null && propKeywords.propertyType == SerializedPropertyType.String)
{
string[] keywords = propKeywords.stringValue.Split(' ');
PassType pathType = (PassType)propPassType.intValue;
manifest.AddShaderVariant(shaderAssetPath, shaderName, pathType, keywords);
}
}
string[] keywords = propKeywords.stringValue.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
PassType passType = (PassType)propPassType.intValue;
manifest.AddShaderVariant(shaderAssetPath, shaderName, passType, keywords);
}
}
}
@@ -185,6 +208,13 @@ public class ShaderVariantCollectionManifest
shaderVariantInfo.ShaderVariantElements.Sort();
}
// 统计数量
foreach (var shaderVariantInfo in manifest.ShaderVariantInfos)
{
manifest.VariantTotalCount += shaderVariantInfo.ShaderVariantElements.Count;
}
manifest.ShaderTotalCount = manifest.ShaderVariantInfos.Count;
return manifest;
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -8,6 +8,9 @@ using UnityEditor;
using UnityEditor.SceneManagement;
using YooAsset.Editor;
/// <summary>
/// 收集资源包裹中材质产生的着色器变种
/// </summary>
public static class ShaderVariantCollector
{
private enum ESteps
@@ -34,21 +37,33 @@ public static class ShaderVariantCollector
/// <summary>
/// 开始收集
/// 启动着色器变种收集流程
/// </summary>
/// <param name="savePath">收集结果保存路径,扩展名必须为 .shadervariants。</param>
/// <param name="packageName">参与收集的资源包裹名称</param>
/// <param name="processMaxNum">每批处理的材质数量</param>
/// <param name="completedCallback">收集完成后的回调</param>
public static void Run(string savePath, string packageName, int processMaxNum, Action completedCallback)
{
if (_steps != ESteps.None)
return;
if (EditorSceneUtility.HasDirtyScenes())
{
UnityEngine.Debug.LogError("Unsaved scenes detected. Save all scenes before collecting shader variants.");
return;
}
if (Path.HasExtension(savePath) == false)
savePath = $"{savePath}.shadervariants";
if (Path.GetExtension(savePath) != ".shadervariants")
throw new System.Exception("Shader variant file extension is invalid.");
throw new System.ArgumentException("Shader variant file extension is invalid.", nameof(savePath));
if (string.IsNullOrEmpty(packageName))
throw new System.Exception("Package name is null or empty !");
throw new System.ArgumentNullException(nameof(packageName));
if (processMaxNum <= 0)
throw new System.ArgumentOutOfRangeException(nameof(processMaxNum), "Process capacity must be greater than zero.");
// 注意:先删除再保存,否则ShaderVariantCollection内容将无法及时刷新
// Unity 对同名 ShaderVariantCollection 的刷新存在延迟,先删除旧资源再写入新结果。
AssetDatabase.DeleteAsset(savePath);
EditorFileUtility.CreateFileDirectory(savePath);
_savePath = savePath;
@@ -67,6 +82,17 @@ public static class ShaderVariantCollector
}
private static void EditorUpdate()
{
try
{
InternalUpdate();
}
catch (Exception ex)
{
Finish(false, ex);
}
}
private static void InternalUpdate()
{
if (_steps == ESteps.None)
return;
@@ -75,14 +101,14 @@ public static class ShaderVariantCollector
{
ShaderVariantCollectionHelper.ClearCurrentShaderVariantCollection();
_steps = ESteps.CollectAllMaterial;
return; //等待一帧
return; // 等待一帧,让编辑器完成清理。
}
if (_steps == ESteps.CollectAllMaterial)
{
_allMaterials = GetAllMaterials();
_steps = ESteps.CollectVariants;
return; //等待一帧
return; // 等待一帧,让材质列表收集结果稳定。
}
if (_steps == ESteps.CollectVariants)
@@ -119,7 +145,7 @@ public static class ShaderVariantCollector
if (_steps == ESteps.WaitingDone)
{
// 注意:一定要延迟保存才会起效
// Unity 需要等待若干帧后才能把当前变种集合写入资源文件。
if (_elapsedTime.ElapsedMilliseconds > WaitMilliseconds)
{
_elapsedTime.Stop();
@@ -129,9 +155,7 @@ public static class ShaderVariantCollector
ShaderVariantCollectionHelper.SaveCurrentShaderVariantCollection(_savePath);
CreateManifest();
UnityEngine.Debug.Log($"搜集SVC完毕");
EditorApplication.update -= EditorUpdate;
_completedCallback?.Invoke();
Finish(true);
}
}
}
@@ -164,7 +188,7 @@ public static class ShaderVariantCollector
result.Add(assetPath);
}
}
EditorDialogUtility.DisplayProgressBar("搜集所有材质球", ++progressValue, collectResult.CollectAssets.Count);
EditorDialogUtility.DisplayProgressBar("Collect All Materials", ++progressValue, collectResult.CollectAssets.Count);
}
EditorDialogUtility.ClearProgressBar();
@@ -175,7 +199,7 @@ public static class ShaderVariantCollector
{
Camera camera = Camera.main;
if (camera == null)
throw new System.Exception("Not found main camera.");
throw new System.InvalidOperationException("Main camera is missing.");
// 设置主相机
float aspect = camera.aspect;
@@ -208,13 +232,19 @@ public static class ShaderVariantCollector
{
x++;
}
EditorDialogUtility.DisplayProgressBar("照射所有材质球", ++progressValue, materials.Count);
EditorDialogUtility.DisplayProgressBar("Render All Materials", ++progressValue, materials.Count);
}
EditorDialogUtility.ClearProgressBar();
}
private static GameObject CreateSphere(string assetPath, Vector3 position, int index)
{
var material = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
if (material == null)
{
UnityEngine.Debug.LogWarning($"Material not found: '{assetPath}'.");
return null;
}
var shader = material.shader;
if (shader == null)
return null;
@@ -229,11 +259,12 @@ public static class ShaderVariantCollector
{
foreach (var go in _allSpheres)
{
GameObject.DestroyImmediate(go);
if (go != null)
GameObject.DestroyImmediate(go);
}
_allSpheres.Clear();
// 尝试释放编辑器加载的资源
// 材质扫描会加载编辑器资源,收集结束后主动释放以降低内存占用。
EditorUtility.UnloadUnusedAssetsImmediate(true);
}
private static void CreateManifest()
@@ -251,4 +282,39 @@ public static class ShaderVariantCollector
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
}
private static void Finish(bool success, Exception exception = null)
{
try
{
if (success)
UnityEngine.Debug.Log("Shader variant collection completed.");
else
UnityEngine.Debug.LogError($"Shader variant collection failed: {exception}.");
_completedCallback?.Invoke();
}
finally
{
Cleanup();
}
}
private static void Cleanup()
{
EditorApplication.update -= EditorUpdate;
EditorDialogUtility.ClearProgressBar();
if (_elapsedTime != null)
{
_elapsedTime.Stop();
_elapsedTime = null;
}
DestroyAllSpheres();
_savePath = null;
_packageName = null;
_processMaxNum = 0;
_completedCallback = null;
_allMaterials = null;
_steps = ESteps.None;
}
}

View File

@@ -1,29 +1,54 @@
using UnityEngine;
using UnityEngine;
using UnityEditor;
/// <summary>
/// 保存着色器变种收集工具的编辑器偏好设置
/// </summary>
public class ShaderVariantCollectorSetting : ScriptableObject
{
private const string DefaultSavePath = "Assets/MyShaderVariants.shadervariants";
public static string GeFileSavePath(string packageName)
/// <summary>
/// 查询收集结果保存路径
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <returns>收集结果保存路径</returns>
public static string GetFileSavePath(string packageName)
{
string key = $"{Application.productName}_{packageName}_GeFileSavePath";
string key = $"{Application.productName}_{packageName}_GetFileSavePath";
return EditorPrefs.GetString(key, DefaultSavePath);
}
/// <summary>
/// 设置收集结果保存路径
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <param name="savePath">收集结果保存路径</param>
public static void SetFileSavePath(string packageName, string savePath)
{
string key = $"{Application.productName}_{packageName}_GeFileSavePath";
string key = $"{Application.productName}_{packageName}_GetFileSavePath";
EditorPrefs.SetString(key, savePath);
}
public static int GeProcessCapacity(string packageName)
/// <summary>
/// 查询单批处理容量
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <returns>单批处理容量</returns>
public static int GetProcessCapacity(string packageName)
{
string key = $"{Application.productName}_{packageName}_GeProcessCapacity";
string key = $"{Application.productName}_{packageName}_GetProcessCapacity";
return EditorPrefs.GetInt(key, 1000);
}
/// <summary>
/// 设置单批处理容量
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <param name="capacity">单批处理容量</param>
public static void SetProcessCapacity(string packageName, int capacity)
{
string key = $"{Application.productName}_{packageName}_GeProcessCapacity";
string key = $"{Application.productName}_{packageName}_GetProcessCapacity";
EditorPrefs.SetInt(key, capacity);
}
}

View File

@@ -1,140 +1,115 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using YooAsset.Editor;
/// <summary>
/// 提供着色器变种收集工具窗口
/// </summary>
public class ShaderVariantCollectorWindow : EditorWindow
{
[MenuItem("Tools/着色器变种收集器", false, 100)]
[MenuItem("Tools/Shader Variant Collector", false, 100)]
public static void OpenWindow()
{
ShaderVariantCollectorWindow window = GetWindow<ShaderVariantCollectorWindow>("着色器变种收集工具", true);
ShaderVariantCollectorWindow window = GetWindow<ShaderVariantCollectorWindow>("Shader Variant Collector", true);
window.minSize = new Vector2(800, 600);
}
private Button _collectButton;
private TextField _collectOutputField;
private Label _currentShaderCountField;
private Label _currentVariantCountField;
private SliderInt _processCapacitySlider;
private PopupField<string> _packageField;
private List<string> _packageNames;
private int _packageIndex;
private string _currentPackageName;
private string _collectOutputPath;
private int _processCapacity;
public void CreateGUI()
private void OnEnable()
{
try
_packageNames = GetBuildPackageNames();
if (_packageNames.Count > 0)
{
VisualElement root = this.rootVisualElement;
// 加载布局文件
var visualAsset = UxmlLoader.LoadWindowUxml<ShaderVariantCollectorWindow>();
if (visualAsset == null)
return;
visualAsset.CloneTree(root);
// 包裹名称列表
_packageNames = GetBuildPackageNames();
_currentPackageName = _packageNames[0];
// 文件输出目录
_collectOutputField = root.Q<TextField>("CollectOutput");
_collectOutputField.SetValueWithoutNotify(ShaderVariantCollectorSetting.GeFileSavePath(_currentPackageName));
_collectOutputField.RegisterValueChangedCallback(evt =>
{
ShaderVariantCollectorSetting.SetFileSavePath(_currentPackageName, _collectOutputField.value);
});
// 收集的包裹
var packageContainer = root.Q("PackageContainer");
if (_packageNames.Count > 0)
{
int defaultIndex = GetDefaultPackageIndex(_currentPackageName);
_packageField = new PopupField<string>(_packageNames, defaultIndex);
_packageField.label = "Package";
_packageField.style.width = 350;
_packageField.RegisterValueChangedCallback(evt =>
{
_currentPackageName = _packageField.value;
});
packageContainer.Add(_packageField);
}
else
{
_packageField = new PopupField<string>();
_packageField.label = "Package";
_packageField.style.width = 350;
packageContainer.Add(_packageField);
}
// 容器值
_processCapacitySlider = root.Q<SliderInt>("ProcessCapacity");
_processCapacitySlider.SetValueWithoutNotify(ShaderVariantCollectorSetting.GeProcessCapacity(_currentPackageName));
#if !UNITY_2020_3_OR_NEWER
_processCapacitySlider.label = $"Capacity ({_processCapacitySlider.value})";
_processCapacitySlider.RegisterValueChangedCallback(evt =>
{
ShaderVariantCollectorSetting.SetProcessCapacity(_currentPackageName, _processCapacitySlider.value);
_processCapacitySlider.label = $"Capacity ({_processCapacitySlider.value})";
});
#else
_processCapacitySlider.RegisterValueChangedCallback(evt =>
{
ShaderVariantCollectorSetting.SetProcessCapacity(_currentPackageName, _processCapacitySlider.value);
});
#endif
_currentShaderCountField = root.Q<Label>("CurrentShaderCount");
_currentVariantCountField = root.Q<Label>("CurrentVariantCount");
// 变种收集按钮
_collectButton = root.Q<Button>("CollectButton");
_collectButton.clicked += CollectButton_clicked;
}
catch (Exception e)
{
Debug.LogError(e.ToString());
_packageIndex = 0;
_currentPackageName = _packageNames[_packageIndex];
RefreshPackageSettings();
}
}
private void Update()
private void OnGUI()
{
if (_currentShaderCountField != null)
{
int currentShaderCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionShaderCount();
_currentShaderCountField.text = $"Current Shader Count : {currentShaderCount}";
}
EditorGUILayout.Space(4);
if (_currentVariantCountField != null)
{
int currentVariantCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionVariantCount();
_currentVariantCountField.text = $"Current Variant Count : {currentVariantCount}";
}
}
bool hasPackages = _packageNames.Count > 0;
private void CollectButton_clicked()
{
string savePath = ShaderVariantCollectorSetting.GeFileSavePath(_currentPackageName);
int processCapacity = _processCapacitySlider.value;
ShaderVariantCollector.Run(savePath, _currentPackageName, processCapacity, null);
}
// 构建包裹相关
private int GetDefaultPackageIndex(string packageName)
{
for (int index = 0; index < _packageNames.Count; index++)
// Package
EditorGUI.BeginDisabledGroup(!hasPackages);
{
if (_packageNames[index] == packageName)
int newIndex = EditorGUILayout.Popup("Package", _packageIndex, _packageNames.ToArray());
if (newIndex != _packageIndex && hasPackages)
{
return index;
_packageIndex = newIndex;
_currentPackageName = _packageNames[_packageIndex];
RefreshPackageSettings();
}
}
return 0;
EditorGUI.EndDisabledGroup();
// Save path
string newPath = EditorGUILayout.TextField("Save Path", _collectOutputPath);
if (newPath != _collectOutputPath)
{
_collectOutputPath = newPath;
if (!string.IsNullOrEmpty(_currentPackageName))
ShaderVariantCollectorSetting.SetFileSavePath(_currentPackageName, _collectOutputPath);
}
// Shader / variant counts
int shaderCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionShaderCount();
int variantCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionVariantCount();
EditorGUILayout.LabelField("Current Shader Count", shaderCount.ToString());
EditorGUILayout.LabelField("Current Variant Count", variantCount.ToString());
// Process capacity slider
int newCapacity = EditorGUILayout.IntSlider("Capacity", _processCapacity, 10, 1000);
if (newCapacity != _processCapacity)
{
_processCapacity = newCapacity;
if (!string.IsNullOrEmpty(_currentPackageName))
ShaderVariantCollectorSetting.SetProcessCapacity(_currentPackageName, _processCapacity);
}
GUILayout.FlexibleSpace();
// Collect button
EditorGUI.BeginDisabledGroup(!hasPackages);
{
Color defaultColor = GUI.backgroundColor;
GUI.backgroundColor = new Color(0.16f, 0.42f, 0.16f, 1f);
if (GUILayout.Button("Collect", GUILayout.Height(50)))
{
CollectButtonClicked();
}
GUI.backgroundColor = defaultColor;
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.Space(4);
}
private void CollectButtonClicked()
{
if (string.IsNullOrEmpty(_currentPackageName))
{
Debug.LogError("Package name is empty.");
return;
}
string savePath = ShaderVariantCollectorSetting.GetFileSavePath(_currentPackageName);
ShaderVariantCollector.Run(savePath, _currentPackageName, _processCapacity, null);
}
private void RefreshPackageSettings()
{
if (string.IsNullOrEmpty(_currentPackageName))
return;
_collectOutputPath = ShaderVariantCollectorSetting.GetFileSavePath(_currentPackageName);
_processCapacity = ShaderVariantCollectorSetting.GetProcessCapacity(_currentPackageName);
}
private List<string> GetBuildPackageNames()
{
@@ -145,4 +120,4 @@ public class ShaderVariantCollectorWindow : EditorWindow
}
return result;
}
}
}

View File

@@ -1,11 +0,0 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<uie:Toolbar name="Toolbar" style="display: flex; flex-direction: row-reverse;" />
<ui:VisualElement name="CollectContainer">
<ui:TextField picking-mode="Ignore" label="文件保存路径" name="CollectOutput" style="height: 22px;" />
<ui:VisualElement name="PackageContainer" style="height: 24px;" />
<ui:Label text="Current Shader Count" display-tooltip-when-elided="true" name="CurrentShaderCount" style="height: 20px; padding-left: 4px;" />
<ui:Label text="Current Variant Count" display-tooltip-when-elided="true" name="CurrentVariantCount" style="height: 20px; padding-left: 4px;" />
<ui:SliderInt picking-mode="Ignore" label="Capacity" value="9999" high-value="1000" name="ProcessCapacity" low-value="10" show-input-field="true" />
<ui:Button text="开始搜集" display-tooltip-when-elided="true" name="CollectButton" style="height: 50px; background-color: rgb(40, 106, 42); margin-top: 10px;" />
</ui:VisualElement>
</ui:UXML>

View File

@@ -1,10 +0,0 @@
fileFormatVersion: 2
guid: 9bff4878063eaf04dab8713e1e662ac5
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

View File

@@ -0,0 +1,20 @@
{
"name": "YooAsset.Extension.Editor",
"rootNamespace": "",
"references": [
"YooAsset",
"YooAsset.Editor",
"YooAsset.Extension"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 4fdc3ec5aeab28849a55f4ec8619e04c
DefaultImporter:
guid: d8e79e975991a7547b8ab3d52127065d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: cda191ef75dc59f408545d8f7d3644b0
guid: 1a5b8e8a252caf44eabfaf319fb4b2dc
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,38 @@
using System.Collections;
using UnityEngine;
using YooAsset;
/// <summary>
/// 演示如何使用 GameObjectReference 弱引用加载并实例化游戏对象
/// </summary>
public class AssetReferenceSample : MonoBehaviour
{
[SerializeField]
private GameObjectReference _reference;
private IEnumerator Start()
{
if (_reference.RuntimeKeyIsValid() == false)
{
yield break;
}
AssetHandle handle = _reference.LoadAssetAsync();
yield return handle;
if (handle.Status == EOperationStatus.Succeeded)
{
GameObject instance = handle.InstantiateSync(new InstantiateOptions(true, transform, false));
if (instance == null)
Debug.LogError($"Failed to instantiate GameObject reference '{_reference.AssetGUID}'.");
}
else
{
Debug.LogError($"Failed to load GameObject reference '{_reference.AssetGUID}': {handle.Error}.");
}
}
private void OnDestroy()
{
_reference.ReleaseAsset();
}
}

View File

@@ -0,0 +1,75 @@
using System;
using UnityEngine;
using YooAsset;
/// <summary>
/// 游戏对象弱引用,序列化时只保存资源 GUID
/// </summary>
[Serializable]
public class GameObjectReference
{
[SerializeField]
private string _packageName = "DefaultPackage";
[SerializeField]
private string _assetGUID = "";
[NonSerialized]
private AssetHandle _handle;
/// <summary>
/// 资源所属的包裹名称
/// </summary>
public string PackageName => _packageName;
/// <summary>
/// 资源 GUID
/// </summary>
public string AssetGUID => _assetGUID;
/// <summary>
/// 检查运行时引用键是否有效
/// </summary>
public bool RuntimeKeyIsValid()
{
if (string.IsNullOrEmpty(_packageName) || string.IsNullOrEmpty(_assetGUID))
return false;
var package = YooAssets.GetPackage(_packageName);
var assetInfo = package.GetAssetInfoByGuid(_assetGUID, typeof(GameObject));
return assetInfo.IsValid;
}
/// <summary>
/// 异步加载引用的游戏对象
/// </summary>
/// <returns>加载操作句柄</returns>
public AssetHandle LoadAssetAsync()
{
if (_handle != null)
throw new InvalidOperationException("GameObject reference has already been loaded. Release it first.");
if (string.IsNullOrEmpty(_packageName))
throw new ArgumentException("Package name is not set.", nameof(_packageName));
if (string.IsNullOrEmpty(_assetGUID))
throw new ArgumentException("Asset GUID is not set.", nameof(_assetGUID));
var package = YooAssets.GetPackage(_packageName);
var assetInfo = package.GetAssetInfoByGuid(_assetGUID, typeof(GameObject));
_handle = package.LoadAssetAsync(assetInfo);
return _handle;
}
/// <summary>
/// 释放已加载的资源句柄
/// </summary>
public void ReleaseAsset()
{
if (_handle == null)
return;
_handle.Release();
_handle = null;
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b974d3d744622f3499d026f99074cd72
guid: 15552077c0d6ff441a4cd62af62b7d5a
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,502 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
#region InitializeParameters
/// <summary>
/// 初始化参数
/// </summary>
public abstract class InitializeParameters
{
/// <summary>
/// 同时加载Bundle文件的最大并发数
/// </summary>
public int BundleLoadingMaxConcurrency = int.MaxValue;
/// <summary>
/// 当资源引用计数为零的时候自动释放资源包
/// </summary>
public bool AutoUnloadBundleWhenUnused = false;
/// <summary>
/// WebGL平台强制同步加载资源对象
/// </summary>
public bool WebGLForceSyncLoadAsset = false;
}
/// <summary>
/// 编辑器下模拟运行模式的初始化参数
/// </summary>
public class EditorSimulateModeParameters : InitializeParameters
{
public FileSystemParameters EditorFileSystemParameters;
}
/// <summary>
/// 离线运行模式的初始化参数
/// </summary>
public class OfflinePlayModeParameters : InitializeParameters
{
public FileSystemParameters BuiltinFileSystemParameters;
}
/// <summary>
/// 联机运行模式的初始化参数
/// </summary>
public class HostPlayModeParameters : InitializeParameters
{
public FileSystemParameters BuiltinFileSystemParameters;
public FileSystemParameters CacheFileSystemParameters;
}
/// <summary>
/// WebGL运行模式的初始化参数
/// </summary>
public class WebPlayModeParameters : InitializeParameters
{
public FileSystemParameters WebServerFileSystemParameters;
public FileSystemParameters WebRemoteFileSystemParameters;
}
#endregion
#region InitializationOperation
public class InitializationOperation : AsyncOperationBase
{
private bool _isDone = false;
private readonly InitializePackageOperation _operation;
internal InitializationOperation(InitializePackageOperation op)
{
_operation = op;
}
protected override void InternalStart()
{
}
protected override void InternalUpdate()
{
if (_isDone)
return;
_operation.UpdateOperation();
if (_operation.IsDone == false)
return;
_isDone = true;
if (_operation.Status == EOperationStatus.Succeeded)
SetResult();
else
SetError(_operation.Error);
}
}
#endregion
#region DestroyOperation
public class DestroyOperation : AsyncOperationBase
{
private bool _isDone = false;
private readonly DestroyPackageOperation _operation;
internal DestroyOperation(DestroyPackageOperation op)
{
_operation = op;
}
protected override void InternalStart()
{
}
protected override void InternalUpdate()
{
if (_isDone)
return;
_operation.UpdateOperation();
if (_operation.IsDone == false)
return;
_isDone = true;
if (_operation.Status == EOperationStatus.Succeeded)
SetResult();
else
SetError(_operation.Error);
}
}
#endregion
#region UpdatePackageManifestOperation
public class UpdatePackageManifestOperation : AsyncOperationBase
{
private bool _isDone = false;
private readonly LoadPackageManifestOperation _operation;
internal UpdatePackageManifestOperation(LoadPackageManifestOperation op)
{
_operation = op;
}
protected override void InternalStart()
{
}
protected override void InternalUpdate()
{
if (_isDone)
return;
_operation.UpdateOperation();
if (_operation.IsDone == false)
return;
_isDone = true;
if (_operation.Status == EOperationStatus.Succeeded)
SetResult();
else
SetError(_operation.Error);
}
}
#endregion
#region ImportFileInfo
public struct ImportFileInfo
{
/// <summary>
/// 本地文件路径
/// </summary>
public string FilePath;
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// 资源包GUID
/// </summary>
public string BundleGuid;
}
#endregion
public static class CompatibleResourcePackage
{
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static InitializationOperation InitializeAsync(this ResourcePackage package, InitializeParameters parameters)
{
if (parameters is EditorSimulateModeParameters)
{
var initializeParameters = parameters as EditorSimulateModeParameters;
var options = new EditorSimulateModeOptions();
options.BundleLoadingMaxConcurrency = initializeParameters.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = initializeParameters.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = initializeParameters.WebGLForceSyncLoadAsset;
options.EditorFileSystemParameters = initializeParameters.EditorFileSystemParameters;
var operation = package.InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
else if (parameters is OfflinePlayModeParameters)
{
var initializeParameters = parameters as OfflinePlayModeParameters;
var options = new OfflinePlayModeOptions();
options.BundleLoadingMaxConcurrency = initializeParameters.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = initializeParameters.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = initializeParameters.WebGLForceSyncLoadAsset;
options.BuiltinFileSystemParameters = initializeParameters.BuiltinFileSystemParameters;
var operation = package.InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
else if (parameters is HostPlayModeParameters)
{
var initializeParameters = parameters as HostPlayModeParameters;
var options = new HostPlayModeOptions();
options.BundleLoadingMaxConcurrency = initializeParameters.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = initializeParameters.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = initializeParameters.WebGLForceSyncLoadAsset;
options.BuiltinFileSystemParameters = initializeParameters.BuiltinFileSystemParameters;
options.CacheFileSystemParameters = initializeParameters.CacheFileSystemParameters;
var operation = package.InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
else if (parameters is WebPlayModeParameters)
{
var initializeParameters = parameters as WebPlayModeParameters;
var options = new WebPlayModeOptions();
options.BundleLoadingMaxConcurrency = initializeParameters.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = initializeParameters.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = initializeParameters.WebGLForceSyncLoadAsset;
options.WebServerFileSystemParameters = initializeParameters.WebServerFileSystemParameters;
options.WebRemoteFileSystemParameters = initializeParameters.WebRemoteFileSystemParameters;
var operation = package.InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
else
{
throw new System.NotImplementedException();
}
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static DestroyOperation DestroyAsync(this ResourcePackage package)
{
var operation = package.DestroyPackageAsync();
var wrapper = new DestroyOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static RequestPackageVersionOperation RequestPackageVersionAsync(this ResourcePackage package, bool appendTimeTicks = true, int timeout = 60)
{
var options = new RequestPackageVersionOptions(appendTimeTicks, timeout);
return package.RequestPackageVersionAsync(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static UpdatePackageManifestOperation UpdatePackageManifestAsync(this ResourcePackage package, string packageVersion, int timeout = 60)
{
var options = new LoadPackageManifestOptions(packageVersion, timeout);
var operation = package.LoadPackageManifestAsync(options);
var wrapper = new UpdatePackageManifestOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static PrefetchManifestOperation PreDownloadContentAsync(this ResourcePackage package, string packageVersion, int timeout = 60)
{
var options = new PrefetchManifestOptions(packageVersion, timeout);
return package.PrefetchManifestAsync(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ClearCacheOperation ClearCacheFilesAsync(this ResourcePackage package, string fileClearMode, object clearParam = null)
{
var options = new ClearCacheOptions(fileClearMode, clearParam);
return package.ClearCacheAsync(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static UnloadUnusedAssetsOperation UnloadUnusedAssetsAsync(this ResourcePackage package, int loopCount)
{
var options = new UnloadUnusedAssetsOptions(loopCount);
return package.UnloadUnusedAssetsAsync(options);
}
#region
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateResourceDownloader(this ResourcePackage package, int downloadingMaxNumber, int failedTryAgain)
{
var options = new ResourceDownloaderOptions(downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateResourceDownloader(this ResourcePackage package, string tag, int downloadingMaxNumber, int failedTryAgain)
{
string[] tags = new string[] { tag };
var options = new ResourceDownloaderOptions(tags, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateResourceDownloader(this ResourcePackage package, string[] tags, int downloadingMaxNumber, int failedTryAgain)
{
var options = new ResourceDownloaderOptions(tags, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, string location, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
var assetInfo = package.ConvertLocationToAssetInfo(location, null);
var options = new BundleDownloaderOptions(assetInfo, recursiveDownload, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, string location, int downloadingMaxNumber, int failedTryAgain)
{
return package.CreateBundleDownloader(location, false, downloadingMaxNumber, failedTryAgain);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, string[] locations, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
List<AssetInfo> assetInfos = new List<AssetInfo>(locations.Length);
foreach (var location in locations)
{
var assetInfo = package.ConvertLocationToAssetInfo(location, null);
assetInfos.Add(assetInfo);
}
var options = new BundleDownloaderOptions(assetInfos.ToArray(), recursiveDownload, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, string[] locations, int downloadingMaxNumber, int failedTryAgain)
{
return package.CreateBundleDownloader(locations, false, downloadingMaxNumber, failedTryAgain);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, AssetInfo assetInfo, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
AssetInfo[] assetInfos = new AssetInfo[] { assetInfo };
var options = new BundleDownloaderOptions(assetInfos, recursiveDownload, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, AssetInfo assetInfo, int downloadingMaxNumber, int failedTryAgain)
{
return package.CreateBundleDownloader(assetInfo, false, downloadingMaxNumber, failedTryAgain);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, AssetInfo[] assetInfos, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
var options = new BundleDownloaderOptions(assetInfos, recursiveDownload, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, AssetInfo[] assetInfos, int downloadingMaxNumber, int failedTryAgain)
{
return package.CreateBundleDownloader(assetInfos, false, downloadingMaxNumber, failedTryAgain);
}
#endregion
#region
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceUnpackerOperation CreateResourceUnpacker(this ResourcePackage package, int unpackingMaxNumber, int failedTryAgain)
{
var options = new ResourceUnpackerOptions(unpackingMaxNumber, failedTryAgain);
return package.CreateResourceUnpacker(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceUnpackerOperation CreateResourceUnpacker(this ResourcePackage package, string tag, int unpackingMaxNumber, int failedTryAgain)
{
string[] tags = new string[] { tag };
var options = new ResourceUnpackerOptions(tags, unpackingMaxNumber, failedTryAgain);
return package.CreateResourceUnpacker(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceUnpackerOperation CreateResourceUnpacker(this ResourcePackage package, string[] tags, int unpackingMaxNumber, int failedTryAgain)
{
var options = new ResourceUnpackerOptions(tags, unpackingMaxNumber, failedTryAgain);
return package.CreateResourceUnpacker(options);
}
#endregion
#region
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceImporterOperation CreateResourceImporter(this ResourcePackage package, string[] filePaths, int importerMaxNumber, int failedTryAgain)
{
ImportFileInfo[] fileInfos = new ImportFileInfo[filePaths.Length];
for (int i = 0; i < filePaths.Length; i++)
{
ImportFileInfo fileInfo = new ImportFileInfo();
fileInfo.FilePath = filePaths[i];
fileInfos[i] = fileInfo;
}
return package.CreateResourceImporter(fileInfos, importerMaxNumber, failedTryAgain);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceImporterOperation CreateResourceImporter(this ResourcePackage package, ImportFileInfo[] fileInfos, int importerMaxNumber, int failedTryAgain)
{
ImportBundleInfo[] bundleInfos = new ImportBundleInfo[fileInfos.Length];
for (int i = 0; i < fileInfos.Length; i++)
{
bundleInfos[i] = new ImportBundleInfo(
filePath: fileInfos[i].FilePath,
bundleName: fileInfos[i].BundleName,
bundleGuid: fileInfos[i].BundleGuid);
}
var options = new BundleImporterOptions(bundleInfos, importerMaxNumber, failedTryAgain);
return package.CreateResourceImporter(options);
}
#endregion
}
public static class CompatibleAssetHandle
{
public static GameObject InstantiateSync(this AssetHandle handle, Transform parent)
{
var options = new InstantiateOptions(true, parent, false);
return handle.InstantiateSync(options);
}
public static GameObject InstantiateSync(this AssetHandle handle, Transform parent, bool worldPositionStays)
{
var options = new InstantiateOptions(true, parent, worldPositionStays);
return handle.InstantiateSync(options);
}
public static GameObject InstantiateSync(this AssetHandle handle, Vector3 position, Quaternion rotation)
{
var options = new InstantiateOptions(true, position, rotation);
return handle.InstantiateSync(options);
}
public static GameObject InstantiateSync(this AssetHandle handle, Vector3 position, Quaternion rotation, Transform parent)
{
var options = new InstantiateOptions(true, parent, position, rotation);
return handle.InstantiateSync(options);
}
public static InstantiateOperation InstantiateAsync(this AssetHandle handle, Transform parent, bool actived = true)
{
var options = new InstantiateOptions(actived, parent, false);
return handle.InstantiateAsync(options);
}
public static InstantiateOperation InstantiateAsync(this AssetHandle handle, Transform parent, bool worldPositionStays, bool actived = true)
{
var options = new InstantiateOptions(actived, parent, worldPositionStays);
return handle.InstantiateAsync(options);
}
public static InstantiateOperation InstantiateAsync(this AssetHandle handle, Vector3 position, Quaternion rotation, bool actived = true)
{
var options = new InstantiateOptions(actived, position, rotation);
return handle.InstantiateAsync(options);
}
public static InstantiateOperation InstantiateAsync(this AssetHandle handle, Vector3 position, Quaternion rotation, Transform parent, bool actived = true)
{
var options = new InstantiateOptions(actived, parent, position, rotation);
return handle.InstantiateAsync(options);
}
}

View File

@@ -3,11 +3,16 @@ using System.Collections.Generic;
using UnityEngine;
using YooAsset;
/// <summary>
/// 提供资源句柄的扩展方法
/// </summary>
public static class AssetHandleExtension
{
/// <summary>
/// 等待异步执行完毕
/// 等待资源加载操作完成
/// </summary>
/// <param name="thisHandle">等待完成的资源句柄</param>
/// <returns>已完成等待的资源句柄</returns>
public static AssetHandle WaitForAsyncOperationComplete(this AssetHandle thisHandle)
{
thisHandle.WaitForAsyncComplete();

View File

@@ -3,8 +3,16 @@ using System.Collections.Generic;
using UnityEngine;
using YooAsset;
/// <summary>
/// 提供资源句柄基类的扩展方法
/// </summary>
public static class HandleBaseExtension
{
/// <summary>
/// 检查句柄是否已成功完成
/// </summary>
/// <param name="thisHandle">待检查的句柄</param>
/// <returns>句柄已完成且状态为成功时返回 true。</returns>
public static bool IsSucceed(this HandleBase thisHandle)
{
return thisHandle.IsDone && thisHandle.Status == EOperationStatus.Succeeded;

View File

@@ -1,156 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using YooAsset;
/// <summary>
/// 拷贝内置清单文件到沙盒目录
/// </summary>
public class CopyBuildinManifestOperation : AsyncOperationBase
{
private enum ESteps
{
None,
CheckHashFile,
UnpackHashFile,
CheckManifestFile,
UnpackManifestFile,
Done,
}
private readonly string _packageName;
private readonly string _packageVersion;
private readonly IDownloadBackend _backend;
private IDownloadFileRequest _hashFileRequest;
private IDownloadFileRequest _manifestFileRequest;
private ESteps _steps = ESteps.None;
public CopyBuildinManifestOperation(string packageName, string packageVersion)
{
_packageName = packageName;
_packageVersion = packageVersion;
_backend = new UnityWebRequestBackend();
}
protected override void InternalStart()
{
_steps = ESteps.CheckHashFile;
}
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckHashFile)
{
string hashFilePath = GetCacheHashFilePath();
if (File.Exists(hashFilePath))
{
_steps = ESteps.CheckManifestFile;
return;
}
_steps = ESteps.UnpackHashFile;
}
if (_steps == ESteps.UnpackHashFile)
{
if(_hashFileRequest == null)
{
string sourcePath = GetBuildinHashFilePath();
string destPath = GetCacheHashFilePath();
string url = DownloadUrlHelper.ToLocalFileUrl(sourcePath);
var args = new DownloadFileRequestArgs(url, 60, 0, destPath);
_hashFileRequest = _backend.CreateFileRequest(args);
_hashFileRequest.SendRequest();
}
if (_hashFileRequest.IsDone == false)
return;
if (_hashFileRequest.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.CheckManifestFile;
}
else
{
_steps = ESteps.Done;
SetError(_hashFileRequest.Error);
}
}
if (_steps == ESteps.CheckManifestFile)
{
string manifestFilePath = GetCacheManifestFilePath();
if (File.Exists(manifestFilePath))
{
_steps = ESteps.Done;
SetResult();
return;
}
_steps = ESteps.UnpackManifestFile;
}
if (_steps == ESteps.UnpackManifestFile)
{
if (_manifestFileRequest == null)
{
string sourcePath = GetBuildinManifestFilePath();
string destPath = GetCacheManifestFilePath();
string url = DownloadUrlHelper.ToLocalFileUrl(sourcePath);
var args = new DownloadFileRequestArgs(url, 60, 0, destPath);
_manifestFileRequest = _backend.CreateFileRequest(args);
_manifestFileRequest.SendRequest();
}
if (_manifestFileRequest.IsDone == false)
return;
if (_manifestFileRequest.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.Done;
SetResult();
}
else
{
_steps = ESteps.Done;
SetError(_manifestFileRequest.Error);
}
}
}
private string GetBuildinYooRoot()
{
return YooAssetConfiguration.GetDefaultBuiltinRoot();
}
private string GetBuildinHashFilePath()
{
string fileRoot = GetBuildinYooRoot();
string fileName = YooAssetConfiguration.GetPackageHashFileName(_packageName, _packageVersion);
return PathUtility.Combine(fileRoot, _packageName, fileName);
}
private string GetBuildinManifestFilePath()
{
string fileRoot = GetBuildinYooRoot();
string fileName = YooAssetConfiguration.GetManifestBinaryFileName(_packageName, _packageVersion);
return PathUtility.Combine(fileRoot, _packageName, fileName);
}
private string GetCacheYooRoot()
{
return YooAssetConfiguration.GetDefaultCacheRoot();
}
private string GetCacheHashFilePath()
{
string fileRoot = GetCacheYooRoot();
string fileName = YooAssetConfiguration.GetPackageHashFileName(_packageName, _packageVersion);
return PathUtility.Combine(fileRoot, _packageName, fileName);
}
private string GetCacheManifestFilePath()
{
string fileRoot = GetCacheYooRoot();
string fileName = YooAssetConfiguration.GetManifestBinaryFileName(_packageName, _packageVersion);
return PathUtility.Combine(fileRoot, _packageName, fileName);
}
}

View File

@@ -17,7 +17,6 @@ public class GetBuildinPackageVersionOperation : AsyncOperationBase
}
private readonly string _packageName;
private readonly IDownloadBackend _backend;
private IDownloadTextRequest _downloadTextRequest;
private ESteps _steps = ESteps.None;
@@ -26,10 +25,16 @@ public class GetBuildinPackageVersionOperation : AsyncOperationBase
/// </summary>
public string PackageVersion { private set; get; }
/// <summary>
/// 创建内置资源清单版本查询操作实例
/// </summary>
/// <param name="packageName">资源包裹名称</param>
public GetBuildinPackageVersionOperation(string packageName)
{
if (string.IsNullOrEmpty(packageName))
throw new System.ArgumentNullException(nameof(packageName));
_packageName = packageName;
_backend = new UnityWebRequestBackend();
}
protected override void InternalStart()
{
@@ -47,7 +52,7 @@ public class GetBuildinPackageVersionOperation : AsyncOperationBase
string filePath = GetBuildinPackageVersionFilePath();
string url = DownloadUrlHelper.ToLocalFileUrl(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_downloadTextRequest = _backend.CreateTextRequest(args);
_downloadTextRequest = new UnityWebRequestText(args, null);
_downloadTextRequest.SendRequest();
}
@@ -67,6 +72,14 @@ public class GetBuildinPackageVersionOperation : AsyncOperationBase
}
}
}
protected override void InternalDispose()
{
if (_downloadTextRequest != null)
{
_downloadTextRequest.Dispose();
_downloadTextRequest = null;
}
}
private string GetBuildinYooRoot()
{

View File

@@ -20,13 +20,20 @@ public class GetCacheBundleSizeOperation : AsyncOperationBase
private ESteps _steps = ESteps.None;
/// <summary>
/// 总大小单位字节
/// 缓存文件总大小单位字节
/// </summary>
public long TotalSize = 0;
public long TotalSize { private set; get; }
/// <summary>
/// 创建缓存文件大小统计操作实例
/// </summary>
/// <param name="packageName">资源包裹名称</param>
public GetCacheBundleSizeOperation(string packageName)
{
if (string.IsNullOrEmpty(packageName))
throw new System.ArgumentNullException(nameof(packageName));
_packageName = packageName;
}
protected override void InternalStart()

View File

@@ -4,6 +4,10 @@ using System.Collections.Generic;
using UnityEngine;
using YooAsset;
/// <summary>
/// 按资源标签加载一组资源对象
/// </summary>
/// <typeparam name="TObject">资源对象的 Unity 类型</typeparam>
public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObject : UnityEngine.Object
{
private enum ESteps
@@ -18,15 +22,26 @@ public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObjec
private readonly string _tag;
private ESteps _steps = ESteps.None;
private List<AssetHandle> _handles;
private List<TObject> _assetObjects;
/// <summary>
/// 资源对象集合
/// 加载成功的资源对象集合
/// </summary>
public List<TObject> AssetObjects { private set; get; }
public IReadOnlyList<TObject> AssetObjects { get { return _assetObjects; } }
/// <summary>
/// 创建按标签加载资源对象的操作实例
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <param name="tag">资源标签</param>
public LoadAssetsByTagOperation(string packageName, string tag)
{
if (string.IsNullOrEmpty(packageName))
throw new System.ArgumentNullException(nameof(packageName));
if (string.IsNullOrEmpty(tag))
throw new System.ArgumentNullException(nameof(tag));
_packageName = packageName;
_tag = tag;
}
@@ -65,7 +80,7 @@ public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObjec
index++;
}
AssetObjects = new List<TObject>(_handles.Count);
_assetObjects = new List<TObject>(_handles.Count);
foreach (var handle in _handles)
{
if (handle.Status == EOperationStatus.Succeeded)
@@ -73,21 +88,21 @@ public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObjec
var assetObject = handle.AssetObject as TObject;
if (assetObject != null)
{
AssetObjects.Add(assetObject);
_assetObjects.Add(assetObject);
}
else
{
string error = $"资源类型转换失败:{handle.AssetObject.name}";
Debug.LogError($"{error}");
AssetObjects.Clear();
string error = $"Asset type cast failed: {handle.AssetObject.name}";
Debug.LogError(error);
_assetObjects.Clear();
SetFailed(error);
return;
}
}
else
{
Debug.LogError($"{handle.Error}");
AssetObjects.Clear();
Debug.LogError(handle.Error);
_assetObjects.Clear();
SetFailed(handle.Error);
return;
}
@@ -108,10 +123,13 @@ public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObjec
}
/// <summary>
/// 释放资源句柄
/// 释放加载过程中创建的资源句柄
/// </summary>
public void ReleaseHandle()
{
if (_handles == null)
return;
foreach (var handle in _handles)
{
handle.Release();

View File

@@ -4,8 +4,21 @@ using System.Collections.Generic;
using UnityEngine;
using YooAsset;
/// <summary>
/// 提供资源包裹的游戏对象加载扩展方法
/// </summary>
public static class YooAssetsExtension
{
/// <summary>
/// 加载并实例化游戏对象
/// </summary>
/// <param name="package">发起加载的资源包裹</param>
/// <param name="location">资源定位地址</param>
/// <param name="position">实例化位置</param>
/// <param name="rotation">实例化旋转</param>
/// <param name="parent">实例化父节点</param>
/// <param name="destroyGoOnRelease">释放句柄时是否销毁实例对象</param>
/// <returns>游戏对象加载操作句柄</returns>
public static LoadGameObjectOperation LoadGameObjectAsync(this ResourcePackage package, string location, Vector3 position, Quaternion rotation, Transform parent, bool destroyGoOnRelease = false)
{
var operation = new LoadGameObjectOperation(package.PackageName, location, position, rotation, parent, destroyGoOnRelease);
@@ -14,6 +27,9 @@ public static class YooAssetsExtension
}
}
/// <summary>
/// 加载并实例化游戏对象的操作
/// </summary>
public class LoadGameObjectOperation : AsyncOperationBase
{
private enum ESteps
@@ -25,7 +41,7 @@ public class LoadGameObjectOperation : AsyncOperationBase
private readonly string _packageName;
private readonly string _location;
private readonly Vector3 _positon;
private readonly Vector3 _position;
private readonly Quaternion _rotation;
private readonly Transform _parent;
private readonly bool _destroyGoOnRelease;
@@ -33,16 +49,29 @@ public class LoadGameObjectOperation : AsyncOperationBase
private ESteps _steps = ESteps.None;
/// <summary>
/// 加载的游戏对象
/// 加载并实例化后的游戏对象
/// </summary>
public GameObject Go { private set; get; }
public GameObject GameObjectInstance { private set; get; }
/// <summary>
/// 创建游戏对象加载操作实例
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <param name="location">资源定位地址</param>
/// <param name="position">实例化位置</param>
/// <param name="rotation">实例化旋转</param>
/// <param name="parent">实例化父节点</param>
/// <param name="destroyGoOnRelease">释放句柄时是否销毁实例对象</param>
public LoadGameObjectOperation(string packageName, string location, Vector3 position, Quaternion rotation, Transform parent, bool destroyGoOnRelease = false)
{
if (string.IsNullOrEmpty(packageName))
throw new System.ArgumentNullException(nameof(packageName));
if (string.IsNullOrEmpty(location))
throw new System.ArgumentNullException(nameof(location));
_packageName = packageName;
_location = location;
_positon = position;
_position = position;
_rotation = rotation;
_parent = parent;
_destroyGoOnRelease = destroyGoOnRelease;
@@ -70,12 +99,12 @@ public class LoadGameObjectOperation : AsyncOperationBase
if (_handle.Status != EOperationStatus.Succeeded)
{
SetError(_handle.Error);
SetError($"Failed to load GameObject '{_location}': {_handle.Error}.");
_steps = ESteps.Done;
}
else
{
Go = _handle.InstantiateSync(_positon, _rotation, _parent);
GameObjectInstance = _handle.InstantiateSync(new InstantiateOptions(true, _parent, _position, _rotation));
SetResult();
_steps = ESteps.Done;
}
@@ -83,7 +112,7 @@ public class LoadGameObjectOperation : AsyncOperationBase
}
/// <summary>
/// 释放资源句柄
/// 释放加载过程中创建的资源句柄
/// </summary>
public void ReleaseHandle()
{
@@ -93,8 +122,8 @@ public class LoadGameObjectOperation : AsyncOperationBase
if (_destroyGoOnRelease)
{
if (Go != null)
GameObject.Destroy(Go);
if (GameObjectInstance != null)
GameObject.Destroy(GameObjectInstance);
}
}
}

View File

@@ -1,16 +1,21 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using YooAsset;
public class OperationHelper
/// <summary>
/// 提供业务自定义操作的启动入口
/// </summary>
public static class OperationHelper
{
/// <summary>
/// 开始一个业务实现的自定义异步任务
/// 启动业务自定义操作
/// </summary>
public static void StartOperation(AsyncOperationBase operation)
/// <param name="packageName">调度器或资源包裹名称</param>
/// <param name="operation">待启动的操作实例</param>
public static void StartOperation(string packageName, AsyncOperationBase operation)
{
AsyncOperationSystem.StartOperation(AsyncOperationSystem.GlobalSchedulerName, operation);
AsyncOperationSystem.StartOperation(packageName, operation);
}
}
}

View File

@@ -1,73 +0,0 @@
using UnityEngine;
using YooAsset;
#if UNITY_EDITOR
[UnityEditor.CustomEditor(typeof(GameObjectAssetReference), true)]
public class GameObjectAssetReferenceInspector : UnityEditor.Editor
{
private bool _init = false;
private GameObject _cacheObject;
public override void OnInspectorGUI()
{
GameObjectAssetReference mono = (GameObjectAssetReference)target;
if (_init == false)
{
_init = true;
if (string.IsNullOrEmpty(mono.AssetGUID) == false)
{
string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(mono.AssetGUID);
if (string.IsNullOrEmpty(assetPath) == false)
{
_cacheObject = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
}
}
}
GameObject go = (GameObject)UnityEditor.EditorGUILayout.ObjectField(_cacheObject, typeof(GameObject), false);
if (go != _cacheObject)
{
_cacheObject = go;
string assetPath = UnityEditor.AssetDatabase.GetAssetPath(go);
mono.AssetGUID = UnityEditor.AssetDatabase.AssetPathToGUID(assetPath);
UnityEditor.EditorUtility.SetDirty(target);
}
UnityEditor.EditorGUILayout.LabelField("Asset GUID", mono.AssetGUID);
}
}
#endif
public class GameObjectAssetReference : MonoBehaviour
{
[HideInInspector]
public string AssetGUID = "";
private AssetHandle _handle;
public void Start()
{
var package = YooAssets.GetPackage("DefaultPackage");
var assetInfo = package.GetAssetInfoByGuid(AssetGUID);
_handle = package.LoadAssetAsync(assetInfo);
_handle.Completed += Handle_Completed;
}
public void OnDestroy()
{
if (_handle != null)
{
_handle.Release();
_handle = null;
}
}
private void Handle_Completed(AssetHandle handle)
{
if (handle.Status == EOperationStatus.Succeeded)
{
handle.InstantiateSync(this.transform);
}
}
}

View File

@@ -1,19 +1,13 @@
using System;
using UnityEngine;
using YooAsset;
/// <summary>
/// 演示操作生命周期监控的接入位置
/// </summary>
public static class OperationMonitor
{
/// <summary>
/// 注册操作生命周期回调
/// </summary>
public static void RegisterOperationCallback()
{
}
private static void OperationStartCallback(string packageName, AsyncOperationBase operation)
{
Debug.Log($"Operation start : {operation.GetType().Name}");
}
private static void OperationFinishCallback(string packageName, AsyncOperationBase operation)
{
Debug.Log($"Operation finish : {operation.GetType().Name}");
// TODO: 当前版本不支持全局操作回调注册,请根据业务需求自行实现监控逻辑。
}
}

View File

@@ -1,24 +1,36 @@
using System;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
using YooAsset;
/// <summary>
/// 响应 Unity 图集请求并通过资源包裹加载 SpriteAtlas
/// </summary>
public class SpriteAtlasLoader : MonoBehaviour
{
private Dictionary<string, SpriteAtlas> _loadedAtlas = new Dictionary<string, SpriteAtlas>(1000);
private List<AssetHandle> _loadHandles = new List<AssetHandle>(1000);
/// <summary>
/// 注册图集请求回调
/// </summary>
public void Awake()
{
SpriteAtlasManager.atlasRequested += RequestAtlas;
}
/// <summary>
/// 注销图集请求回调并释放已加载图集句柄
/// </summary>
public void OnDestroy()
{
SpriteAtlasManager.atlasRequested -= RequestAtlas;
foreach (var handle in _loadHandles)
{
handle.Release();
}
_loadHandles.Clear();
}
private void RequestAtlas(string atlasName, Action<SpriteAtlas> callback)
@@ -33,7 +45,9 @@ public class SpriteAtlasLoader : MonoBehaviour
var loadHandle = package.LoadAssetSync<SpriteAtlas>(atlasName);
if (loadHandle.Status != EOperationStatus.Succeeded)
{
Debug.LogWarning($"Failed to load sprite atlas : {atlasName} ! {loadHandle.Error}");
Debug.LogWarning($"Failed to load sprite atlas '{atlasName}': {loadHandle.Error}.");
loadHandle.Release();
callback.Invoke(null);
return;
}
@@ -43,4 +57,4 @@ public class SpriteAtlasLoader : MonoBehaviour
callback.Invoke(atlas);
}
}
}
}

View File

@@ -1,12 +1,15 @@
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
/// <summary>
/// 记录 UI 面板依赖的图集资源
/// </summary>
public class PanelManifest : MonoBehaviour
{
/// <summary>
/// 面板自动引用的图集
/// 面板依赖的图集列表
/// </summary>
public List<SpriteAtlas> ReferencesAtlas = new List<SpriteAtlas>();
}

View File

@@ -1,13 +1,16 @@
#if UNITY_EDITOR && UNITY_2021_3_OR_NEWER
#if UNITY_EDITOR && UNITY_2021_3_OR_NEWER
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.U2D;
/// <summary>
/// 提供 UI 面板监测示例的目录配置
/// </summary>
public static class UIPanelSettings
{
/// <summary>
/// 是否开启面板监测
/// 是否启用面板依赖监测
/// </summary>
public static bool EnablePanelMonitor = false;
@@ -26,35 +29,52 @@ public static class UIPanelSettings
/// </summary>
private const string UIAtlasDirectoryGUID = "c355c783476322b4cacac98c5e1b46d8";
public static string GetPanelDirecotry()
/// <summary>
/// 面板资源目录
/// </summary>
/// <returns>面板资源目录路径</returns>
public static string GetPanelDirectory()
{
string result = UnityEditor.AssetDatabase.GUIDToAssetPath(UIPanelDirectoryGUID);
if (string.IsNullOrEmpty(result))
{
throw new System.Exception($"Can not found panel direcotry : {UIPanelDirectoryGUID}");
throw new System.IO.DirectoryNotFoundException($"Panel directory not found for GUID '{UIPanelDirectoryGUID}'.");
}
return result;
}
public static string GetSpriteDirecotry()
/// <summary>
/// 精灵资源目录
/// </summary>
/// <returns>精灵资源目录路径</returns>
public static string GetSpriteDirectory()
{
string result = UnityEditor.AssetDatabase.GUIDToAssetPath(UISpriteDirectoryGUID);
if (string.IsNullOrEmpty(result))
{
throw new System.Exception($"Can not found sprite direcotry : {UISpriteDirectoryGUID}");
throw new System.IO.DirectoryNotFoundException($"Sprite directory not found for GUID '{UISpriteDirectoryGUID}'.");
}
return result;
}
public static string GetAtlasDirecotry()
/// <summary>
/// 图集资源目录
/// </summary>
/// <returns>图集资源目录路径</returns>
public static string GetAtlasDirectory()
{
string result = UnityEditor.AssetDatabase.GUIDToAssetPath(UIAtlasDirectoryGUID);
if (string.IsNullOrEmpty(result))
{
throw new System.Exception($"Can not found atlas direcotry : {UIAtlasDirectoryGUID}");
throw new System.IO.DirectoryNotFoundException($"Atlas directory not found for GUID '{UIAtlasDirectoryGUID}'.");
}
return result;
}
}
/// <summary>
/// 在预制体保存时刷新 UI 面板依赖的图集清单
/// </summary>
public class UIPanelMonitor : UnityEditor.Editor
{
[UnityEditor.InitializeOnLoadMethod]
@@ -71,7 +91,7 @@ public class UIPanelMonitor : UnityEditor.Editor
UnityEditor.SceneManagement.PrefabStage stage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
if (stage != null)
{
string panelDirectory = UIPanelSettings.GetPanelDirecotry();
string panelDirectory = UIPanelSettings.GetPanelDirectory();
if (stage.assetPath.StartsWith(panelDirectory))
{
PanelManifest manifest = go.GetComponent<PanelManifest>();
@@ -90,8 +110,8 @@ public class UIPanelMonitor : UnityEditor.Editor
{
manifest.ReferencesAtlas.Clear();
string spriteDirectory = UIPanelSettings.GetSpriteDirecotry();
string altasDirectory = UIPanelSettings.GetAtlasDirecotry();
string spriteDirectory = UIPanelSettings.GetSpriteDirectory();
string atlasDirectory = UIPanelSettings.GetAtlasDirectory();
// 获取依赖的图集名称
Transform root = manifest.transform;
@@ -113,11 +133,11 @@ public class UIPanelMonitor : UnityEditor.Editor
if (spriteAssetPath.StartsWith(spriteDirectory) == false)
continue;
string atlasAssetPath = GetAtlasPath(altasDirectory, spriteAssetPath);
string atlasAssetPath = GetAtlasPath(atlasDirectory, spriteAssetPath);
SpriteAtlas spriteAtlas = UnityEditor.AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasAssetPath);
if (spriteAtlas == null)
{
throw new System.Exception($"Not found SpriteAtlas : {atlasAssetPath}");
throw new System.IO.FileNotFoundException($"SpriteAtlas not found: '{atlasAssetPath}'.");
}
else
{

View File

@@ -1,8 +1,8 @@
{
"name": "YooAsset.RuntimeExtension",
"name": "YooAsset.Extension",
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3"
"YooAsset"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -1,81 +0,0 @@
using System.Collections;
using UnityEngine;
namespace YooAsset
{
internal class FileSystemTester
{
public IEnumerator RunTester(IFileSystem fileSystem, string testLocation)
{
string packageName = fileSystem.PackageName;
// 初始化小游戏文件系统
Debug.Log("初始化小游戏文件系统!");
var initializeFileSystemOp = fileSystem.InitializeAsync();
AsyncOperationSystem.StartOperation(packageName, initializeFileSystemOp);
yield return initializeFileSystemOp;
if (initializeFileSystemOp.Status != EOperationStatus.Succeeded)
{
Debug.LogError($"初始化小游戏文件系统失败!{initializeFileSystemOp.Error}");
yield break;
}
// 请求资源版本
Debug.Log("请求资源版本信息!");
var requestPackageVersionOptions = new FSRequestPackageVersionOptions(true, 60);
var requestPackageVersionOp = fileSystem.RequestPackageVersionAsync(requestPackageVersionOptions);
AsyncOperationSystem.StartOperation(packageName, requestPackageVersionOp);
yield return requestPackageVersionOp;
if (requestPackageVersionOp.Status != EOperationStatus.Succeeded)
{
Debug.LogError($"请求资源版本信息失败!{requestPackageVersionOp.Error}");
yield break;
}
// 请求资源清单
string packageVersion = requestPackageVersionOp.PackageVersion;
Debug.Log($"加载资源清单文件!{packageVersion}");
var loadPackageManifestOptions = new FSLoadPackageManifestOptions(packageVersion, 60);
var loadPackageManifestOp = fileSystem.LoadPackageManifestAsync(loadPackageManifestOptions);
AsyncOperationSystem.StartOperation(packageName, loadPackageManifestOp);
yield return loadPackageManifestOp;
if (loadPackageManifestOp.Status != EOperationStatus.Succeeded)
{
Debug.LogError($"加载资源清单文件失败!{loadPackageManifestOp.Error}");
yield break;
}
// 加载资源包
Debug.Log("加载资源包!");
{
var manifest = loadPackageManifestOp.Manifest;
var packageBundle = GetPackageBundle(manifest, testLocation);
var loadBundleFileOptions = new FSLoadPackageBundleOptions(packageBundle);
var loadBundleFileOp = fileSystem.LoadPackageBundleAsync(loadBundleFileOptions);
AsyncOperationSystem.StartOperation(packageName, loadBundleFileOp);
yield return loadBundleFileOp;
if (loadBundleFileOp.Status != EOperationStatus.Succeeded)
{
Debug.LogError($"加载资源包失败!{loadBundleFileOp.Error}");
yield break;
}
else
{
Debug.Log("加载资源包成功!");
}
// 卸载资源包
loadBundleFileOp.BundleHandle.UnloadBundle();
}
Debug.Log("完整测试成功!");
}
private PackageBundle GetPackageBundle(PackageManifest manifest, string location)
{
var assetInfo = manifest.ConvertLocationToAssetInfo(location, typeof(GameObject));
var packageBundle = manifest.GetMainPackageBundle(assetInfo.Asset);
return packageBundle;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 19ed2b81fece5b84fa771a5eeb108572
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,46 +0,0 @@
#if UNITY_WEBGL && DOUYINMINIGAME
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal class TiktokFileSystemTest : MonoBehaviour
{
private void Awake()
{
YooAssets.Initialize();
}
private IEnumerator Start()
{
string packageName = "DefaultPackage";
string testLocation = "asteroid01";
string hostServer = "http://127.0.0.1/CDN/WebGL/yoo";
string packageRoot = $"{StarkSDKSpace.StarkFileSystemManager.USER_DATA_PATH}/__GAME_FILE_CACHE";
IRemoteService remoteService = new RemoteService(hostServer);
TiktokFileSystem fileSystem = new TiktokFileSystem();
fileSystem.SetParameter(EFileSystemParameter.RemoteService, remoteService);
fileSystem.OnCreate(packageName, packageRoot);
FileSystemTester tester = new FileSystemTester();
yield return tester.RunTester(fileSystem, testLocation);
}
private class RemoteService : IRemoteService
{
private readonly string _hostServer;
public RemoteService(string hostServer)
{
_hostServer = hostServer;
}
IReadOnlyList<string> IRemoteService.GetRemoteUrls(string fileName)
{
return new List<string> { $"{_hostServer}/{fileName}" };
}
}
}
}
#endif

View File

@@ -1,46 +0,0 @@
#if UNITY_WEBGL && WEIXINMINIGAME
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal class WechatFileSystemTest : MonoBehaviour
{
private void Awake()
{
YooAssets.Initialize();
}
private IEnumerator Start()
{
string packageName = "DefaultPackage";
string testLocation = "asteroid01";
string hostServer = "http://127.0.0.1/CDN/WebGL/yoo";
string packageRoot = $"{WeChatWASM.WX.env.USER_DATA_PATH}/__GAME_FILE_CACHE";
IRemoteService remoteService = new RemoteService(hostServer);
WechatFileSystem fileSystem = new WechatFileSystem();
fileSystem.SetParameter(EFileSystemParameter.RemoteService, remoteService);
fileSystem.OnCreate(packageName, packageRoot);
FileSystemTester tester = new FileSystemTester();
yield return tester.RunTester(fileSystem, testLocation);
}
private class RemoteService : IRemoteService
{
private readonly string _hostServer;
public RemoteService(string hostServer)
{
_hostServer = hostServer;
}
IReadOnlyList<string> IRemoteService.GetRemoteUrls(string fileName)
{
return new List<string> { $"{_hostServer}/{fileName}" };
}
}
}
}
#endif

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3036392c24e1a3b49b7628fbf6cc24d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -2,7 +2,7 @@
"name": "YooAsset.MiniGame",
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3",
"YooAsset",
"GUID:5efd170ecd8084500bed5692932fe14e",
"GUID:bb21d6197862c4c3e863390dec9859a7",
"GUID:870f26a2ffa82429195df0861505c5d5",

View File

@@ -1,449 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.3730807, g: 0.380755, b: 0.35876408, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 3
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &749215248
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 749215251}
- component: {fileID: 749215250}
- component: {fileID: 749215249}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &749215249
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 749215248}
m_Enabled: 1
--- !u!20 &749215250
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 749215248}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 2
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_Iso: 200
m_ShutterSpeed: 0.005
m_Aperture: 16
m_FocusDistance: 10
m_FocalLength: 50
m_BladeCount: 5
m_Curvature: {x: 2, y: 11}
m_BarrelClipping: 0.25
m_Anamorphism: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &749215251
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 749215248}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &821591607
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 821591609}
- component: {fileID: 821591610}
m_Layer: 0
m_Name: Test
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &821591609
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 821591607}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &821591610
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 821591607}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ec9d17e765ccd4642aa3aa9ca0580799, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &941113990
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 941113991}
- component: {fileID: 941113993}
- component: {fileID: 941113992}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &941113991
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 941113990}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1861717922}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &941113992
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 941113990}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 60
m_FontStyle: 1
m_BestFit: 0
m_MinSize: 6
m_MaxSize: 60
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\u5C0F\u6E38\u620F\u6D4B\u8BD5\u7528\u4F8B\uFF0C\u65E5\u5FD7\u8BF7\u67E5\u770B\u5C0F\u6E38\u620F\u5F00\u53D1\u8005\u5DE5\u5177\uFF01"
--- !u!222 &941113993
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 941113990}
m_CullTransparentMesh: 1
--- !u!1 &1861717918
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1861717922}
- component: {fileID: 1861717921}
- component: {fileID: 1861717920}
- component: {fileID: 1861717919}
m_Layer: 5
m_Name: Canvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1861717919
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1861717918}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
serializedVersion: 2
m_Bits: 4294967295
--- !u!114 &1861717920
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1861717918}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 800, y: 600}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 0
--- !u!223 &1861717921
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1861717918}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!224 &1861717922
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1861717918}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 941113991}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 749215251}
- {fileID: 821591609}
- {fileID: 1861717922}

View File

@@ -1,449 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.3730807, g: 0.380755, b: 0.35876408, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 3
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &749215248
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 749215251}
- component: {fileID: 749215250}
- component: {fileID: 749215249}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &749215249
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 749215248}
m_Enabled: 1
--- !u!20 &749215250
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 749215248}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 2
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_Iso: 200
m_ShutterSpeed: 0.005
m_Aperture: 16
m_FocusDistance: 10
m_FocalLength: 50
m_BladeCount: 5
m_Curvature: {x: 2, y: 11}
m_BarrelClipping: 0.25
m_Anamorphism: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &749215251
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 749215248}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &821591607
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 821591609}
- component: {fileID: 821591610}
m_Layer: 0
m_Name: Test
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &821591609
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 821591607}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &821591610
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 821591607}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3036392c24e1a3b49b7628fbf6cc24d8, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &941113990
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 941113991}
- component: {fileID: 941113993}
- component: {fileID: 941113992}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &941113991
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 941113990}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1861717922}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &941113992
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 941113990}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 60
m_FontStyle: 1
m_BestFit: 0
m_MinSize: 6
m_MaxSize: 60
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\u5C0F\u6E38\u620F\u6D4B\u8BD5\u7528\u4F8B\uFF0C\u65E5\u5FD7\u8BF7\u67E5\u770B\u5C0F\u6E38\u620F\u5F00\u53D1\u8005\u5DE5\u5177\uFF01"
--- !u!222 &941113993
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 941113990}
m_CullTransparentMesh: 1
--- !u!1 &1861717918
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1861717922}
- component: {fileID: 1861717921}
- component: {fileID: 1861717920}
- component: {fileID: 1861717919}
m_Layer: 5
m_Name: Canvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1861717919
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1861717918}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
serializedVersion: 2
m_Bits: 4294967295
--- !u!114 &1861717920
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1861717918}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 800, y: 600}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 0
--- !u!223 &1861717921
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1861717918}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!224 &1861717922
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1861717918}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 941113991}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 749215251}
- {fileID: 821591609}
- {fileID: 1861717922}

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 2aba4dc1069712d4da0976a70c62e040
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniFramework.Event;
@@ -14,7 +13,7 @@ public class RoomBoundary
}
/// <summary>
/// 战斗房间
/// Battle room.
/// </summary>
public class BattleRoom
{
@@ -31,7 +30,7 @@ public class BattleRoom
private readonly EventGroup _eventGroup = new EventGroup();
private GameObject _roomRoot;
// 关卡参数
// Level parameters.
private const int EnemyCount = 10;
private const int EnemyScore = 10;
private const int AsteroidScore = 1;
@@ -52,25 +51,25 @@ public class BattleRoom
/// <summary>
/// 初始化房间
/// Initializes the room.
/// </summary>
public void IntRoom()
public void InitRoom()
{
// 创建房间根对象
// Create room root object.
_roomRoot = new GameObject("BattleRoom");
// 监听游戏事件
_eventGroup.AddListener<BattleEventDefine.PlayerDead>(OnHandleEventMessage);
_eventGroup.AddListener<BattleEventDefine.EnemyDead>(OnHandleEventMessage);
_eventGroup.AddListener<BattleEventDefine.AsteroidExplosion>(OnHandleEventMessage);
_eventGroup.AddListener<BattleEventDefine.PlayerFireBullet>(OnHandleEventMessage);
_eventGroup.AddListener<BattleEventDefine.EnemyFireBullet>(OnHandleEventMessage);
// Listen for game events.
_eventGroup.AddListener<BattlePlayerDeadEvent>(OnHandleEventMessage);
_eventGroup.AddListener<BattleEnemyDeadEvent>(OnHandleEventMessage);
_eventGroup.AddListener<BattleAsteroidExplosionEvent>(OnHandleEventMessage);
_eventGroup.AddListener<BattlePlayerFireBulletEvent>(OnHandleEventMessage);
_eventGroup.AddListener<BattleEnemyFireBulletEvent>(OnHandleEventMessage);
_steps = ESteps.Ready;
}
/// <summary>
/// 销毁房间
/// Destroys the room.
/// </summary>
public void DestroyRoom()
{
@@ -88,7 +87,7 @@ public class BattleRoom
}
/// <summary>
/// 更新房间
/// Updates the room.
/// </summary>
public void UpdateRoom()
{
@@ -99,11 +98,11 @@ public class BattleRoom
{
if (_startWaitTimer.Update(Time.deltaTime))
{
// 生成实体
var assetHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<GameObject>("player_ship");
// Spawn entity.
var assetHandle = GameManager.Instance.GamePackage.LoadAssetAsync<GameObject>("player_ship");
assetHandle.Completed += (AssetHandle handle) =>
{
handle.InstantiateSync(_roomRoot.transform);
handle.InstantiateSync(new InstantiateOptions(true, _roomRoot.transform, false));
};
_handles.Add(assetHandle);
_steps = ESteps.SpawnEnemy;
@@ -116,11 +115,11 @@ public class BattleRoom
Vector3 spawnPosition = new Vector3(Random.Range(-_spawnValues.x, _spawnValues.x), _spawnValues.y, _spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
// 生成实体
var assetHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<GameObject>(enemyLocation);
// Spawn entity.
var assetHandle = GameManager.Instance.GamePackage.LoadAssetAsync<GameObject>(enemyLocation);
assetHandle.Completed += (AssetHandle handle) =>
{
handle.InstantiateSync(spawnPosition, spawnRotation, _roomRoot.transform);
handle.InstantiateSync(new InstantiateOptions(true, _roomRoot.transform, spawnPosition, spawnRotation));
};
_handles.Add(assetHandle);
@@ -156,77 +155,77 @@ public class BattleRoom
}
/// <summary>
/// 接收事件
/// Handles event messages.
/// </summary>
/// <param name="message"></param>
private void OnHandleEventMessage(IEventMessage message)
{
if (message is BattleEventDefine.PlayerDead)
if (message is BattlePlayerDeadEvent)
{
var msg = message as BattleEventDefine.PlayerDead;
var msg = message as BattlePlayerDeadEvent;
// 创建爆炸效果
var assetHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<GameObject>("explosion_player");
// Create explosion effect.
var assetHandle = GameManager.Instance.GamePackage.LoadAssetAsync<GameObject>("explosion_player");
assetHandle.Completed += (AssetHandle handle) =>
{
handle.InstantiateSync(msg.Position, msg.Rotation, _roomRoot.transform);
handle.InstantiateSync(new InstantiateOptions(true, _roomRoot.transform, msg.Position, msg.Rotation));
};
_handles.Add(assetHandle);
_steps = ESteps.GameOver;
BattleEventDefine.GameOver.SendEventMessage();
BattleGameOverEvent.SendEventMessage();
}
else if (message is BattleEventDefine.EnemyDead)
else if (message is BattleEnemyDeadEvent)
{
var msg = message as BattleEventDefine.EnemyDead;
var msg = message as BattleEnemyDeadEvent;
// 创建爆炸效果
var assetHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<GameObject>("explosion_enemy");
// Create explosion effect.
var assetHandle = GameManager.Instance.GamePackage.LoadAssetAsync<GameObject>("explosion_enemy");
assetHandle.Completed += (AssetHandle handle) =>
{
handle.InstantiateSync(msg.Position, msg.Rotation, _roomRoot.transform);
handle.InstantiateSync(new InstantiateOptions(true, _roomRoot.transform, msg.Position, msg.Rotation));
};
_handles.Add(assetHandle);
_totalScore += EnemyScore;
BattleEventDefine.ScoreChange.SendEventMessage(_totalScore);
BattleScoreChangedEvent.SendEventMessage(_totalScore);
}
else if (message is BattleEventDefine.AsteroidExplosion)
else if (message is BattleAsteroidExplosionEvent)
{
var msg = message as BattleEventDefine.AsteroidExplosion;
var msg = message as BattleAsteroidExplosionEvent;
// 创建爆炸效果
var assetHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<GameObject>("explosion_asteroid");
// Create explosion effect.
var assetHandle = GameManager.Instance.GamePackage.LoadAssetAsync<GameObject>("explosion_asteroid");
assetHandle.Completed += (AssetHandle handle) =>
{
handle.InstantiateSync(msg.Position, msg.Rotation, _roomRoot.transform);
handle.InstantiateSync(new InstantiateOptions(true, _roomRoot.transform, msg.Position, msg.Rotation));
};
_handles.Add(assetHandle);
_totalScore += AsteroidScore;
BattleEventDefine.ScoreChange.SendEventMessage(_totalScore);
BattleScoreChangedEvent.SendEventMessage(_totalScore);
}
else if (message is BattleEventDefine.PlayerFireBullet)
else if (message is BattlePlayerFireBulletEvent)
{
var msg = message as BattleEventDefine.PlayerFireBullet;
var msg = message as BattlePlayerFireBulletEvent;
// 创建子弹实体
var assetHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<GameObject>("player_bullet");
// Create bullet entity.
var assetHandle = GameManager.Instance.GamePackage.LoadAssetAsync<GameObject>("player_bullet");
assetHandle.Completed += (AssetHandle handle) =>
{
handle.InstantiateSync(msg.Position, msg.Rotation, _roomRoot.transform);
handle.InstantiateSync(new InstantiateOptions(true, _roomRoot.transform, msg.Position, msg.Rotation));
};
_handles.Add(assetHandle);
}
else if (message is BattleEventDefine.EnemyFireBullet)
else if (message is BattleEnemyFireBulletEvent)
{
var msg = message as BattleEventDefine.EnemyFireBullet;
var msg = message as BattleEnemyFireBulletEvent;
// 创建子弹实体
var assetHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<GameObject>("enemy_bullet");
// Create bullet entity.
var assetHandle = GameManager.Instance.GamePackage.LoadAssetAsync<GameObject>("enemy_bullet");
assetHandle.Completed += (AssetHandle handle) =>
{
handle.InstantiateSync(msg.Position, msg.Rotation, _roomRoot.transform);
handle.InstantiateSync(new InstantiateOptions(true, _roomRoot.transform, msg.Position, msg.Rotation));
};
_handles.Add(assetHandle);
}

View File

@@ -1,5 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EntityAsteroid : MonoBehaviour
@@ -20,7 +18,7 @@ public class EntityAsteroid : MonoBehaviour
var name = other.gameObject.name;
if (name.StartsWith("player"))
{
BattleEventDefine.AsteroidExplosion.SendEventMessage(this.transform.position, this.transform.rotation);
BattleAsteroidExplosionEvent.SendEventMessage(this.transform.position, this.transform.rotation);
GameObject.Destroy(this.gameObject);
}
}

View File

@@ -1,5 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EntityBullet : MonoBehaviour

View File

@@ -1,6 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EntityEffect : MonoBehaviour
{
public float DelayDestroyTime = 1f;

View File

@@ -1,5 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
@@ -43,7 +42,7 @@ public class EntityEnemy : MonoBehaviour
{
_lastFireTime = Time.time;
_audioSource.Play();
BattleEventDefine.EnemyFireBullet.SendEventMessage(_shotSpawn.position, _shotSpawn.rotation);
BattleEnemyFireBulletEvent.SendEventMessage(_shotSpawn.position, _shotSpawn.rotation);
}
}
void FixedUpdate()
@@ -65,7 +64,7 @@ public class EntityEnemy : MonoBehaviour
var name = other.gameObject.name;
if (name.StartsWith("player"))
{
BattleEventDefine.EnemyDead.SendEventMessage(this.transform.position, this.transform.rotation);
BattleEnemyDeadEvent.SendEventMessage(this.transform.position, this.transform.rotation);
GameObject.Destroy(this.gameObject);
}
}

View File

@@ -1,9 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EntityPlayer : MonoBehaviour
{
{
public RoomBoundary Boundary;
public float MoveSpeed = 10f;
public float FireRate = 0.25f;
@@ -25,7 +23,7 @@ public class EntityPlayer : MonoBehaviour
{
_nextFireTime = Time.time + FireRate;
_audioSource.Play();
BattleEventDefine.PlayerFireBullet.SendEventMessage(_shotSpawn.position, _shotSpawn.rotation);
BattlePlayerFireBulletEvent.SendEventMessage(_shotSpawn.position, _shotSpawn.rotation);
}
}
void FixedUpdate()
@@ -50,7 +48,7 @@ public class EntityPlayer : MonoBehaviour
var name = other.gameObject.name;
if (name.StartsWith("enemy") || name.StartsWith("asteroid"))
{
BattleEventDefine.PlayerDead.SendEventMessage(this.transform.position, this.transform.rotation);
BattlePlayerDeadEvent.SendEventMessage(this.transform.position, this.transform.rotation);
GameObject.Destroy(this.gameObject);
}
}

View File

@@ -1,4 +1,3 @@
using System;
using UnityEngine;
public class BackgroundScroller : MonoBehaviour

View File

@@ -1,6 +1,3 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniFramework.Event;
using YooAsset;
@@ -8,33 +5,33 @@ using YooAsset;
public class Boot : MonoBehaviour
{
/// <summary>
/// 资源系统运行模式
/// Resource system play mode.
/// </summary>
public EPlayMode PlayMode = EPlayMode.EditorSimulateMode;
void Awake()
{
Debug.Log($"资源系统运行模式:{PlayMode}");
Debug.Log($"Resource system play mode: {PlayMode}.");
Application.targetFrameRate = 60;
Application.runInBackground = true;
DontDestroyOnLoad(this.gameObject);
}
void Start()
{
// 游戏管理器
GameManager.Instance.Behaviour = this;
// Game manager.
GameManager.Instance.SetBehaviour(this);
// 初始化事件系统
// Initialize event system.
UniEvent.Initalize();
// 初始化资源系统
// Initialize asset system.
YooAssets.Initialize();
// 加载更新页面
// Load patch window.
var go = Resources.Load<GameObject>("PatchWindow");
GameObject.Instantiate(go);
// 补丁更新流程
// Start patch workflow.
PatchManager.Create("DefaultPackage", PlayMode);
PatchManager.Start();
}
@@ -42,4 +39,4 @@ public class Boot : MonoBehaviour
{
PatchManager.Update();
}
}
}

View File

@@ -1,119 +1,131 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniFramework.Event;
public class BattleEventDefine
/// <summary>
/// Battle score changed event.
/// </summary>
public sealed class BattleScoreChangedEvent : IEventMessage
{
/// <summary>
/// 分数改变
/// </summary>
public class ScoreChange : IEventMessage
{
public int CurrentScores;
public int CurrentScores { get; }
public static void SendEventMessage(int currentScores)
{
var msg = new ScoreChange();
msg.CurrentScores = currentScores;
UniEvent.SendMessage(msg);
}
private BattleScoreChangedEvent(int currentScores)
{
CurrentScores = currentScores;
}
/// <summary>
/// 游戏结束
/// </summary>
public class GameOver : IEventMessage
public static void SendEventMessage(int currentScores)
{
public static void SendEventMessage()
{
var msg = new GameOver();
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new BattleScoreChangedEvent(currentScores));
}
}
/// <summary>
/// Battle game over event.
/// </summary>
public sealed class BattleGameOverEvent : IEventMessage
{
public static void SendEventMessage()
{
UniEvent.SendMessage(new BattleGameOverEvent());
}
}
/// <summary>
/// Battle enemy dead event.
/// </summary>
public sealed class BattleEnemyDeadEvent : IEventMessage
{
public Vector3 Position { get; }
public Quaternion Rotation { get; }
private BattleEnemyDeadEvent(Vector3 position, Quaternion rotation)
{
Position = position;
Rotation = rotation;
}
/// <summary>
/// 敌人死亡
/// </summary>
public class EnemyDead : IEventMessage
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
public Vector3 Position;
public Quaternion Rotation;
UniEvent.SendMessage(new BattleEnemyDeadEvent(position, rotation));
}
}
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
var msg = new EnemyDead();
msg.Position = position;
msg.Rotation = rotation;
UniEvent.SendMessage(msg);
}
/// <summary>
/// Battle player dead event.
/// </summary>
public sealed class BattlePlayerDeadEvent : IEventMessage
{
public Vector3 Position { get; }
public Quaternion Rotation { get; }
private BattlePlayerDeadEvent(Vector3 position, Quaternion rotation)
{
Position = position;
Rotation = rotation;
}
/// <summary>
/// 玩家死亡
/// </summary>
public class PlayerDead : IEventMessage
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
public Vector3 Position;
public Quaternion Rotation;
UniEvent.SendMessage(new BattlePlayerDeadEvent(position, rotation));
}
}
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
var msg = new PlayerDead();
msg.Position = position;
msg.Rotation = rotation;
UniEvent.SendMessage(msg);
}
/// <summary>
/// Battle asteroid explosion event.
/// </summary>
public sealed class BattleAsteroidExplosionEvent : IEventMessage
{
public Vector3 Position { get; }
public Quaternion Rotation { get; }
private BattleAsteroidExplosionEvent(Vector3 position, Quaternion rotation)
{
Position = position;
Rotation = rotation;
}
/// <summary>
/// 小行星爆炸
/// </summary>
public class AsteroidExplosion : IEventMessage
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
public Vector3 Position;
public Quaternion Rotation;
UniEvent.SendMessage(new BattleAsteroidExplosionEvent(position, rotation));
}
}
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
var msg = new AsteroidExplosion();
msg.Position = position;
msg.Rotation = rotation;
UniEvent.SendMessage(msg);
}
/// <summary>
/// Battle enemy fire bullet event.
/// </summary>
public sealed class BattleEnemyFireBulletEvent : IEventMessage
{
public Vector3 Position { get; }
public Quaternion Rotation { get; }
private BattleEnemyFireBulletEvent(Vector3 position, Quaternion rotation)
{
Position = position;
Rotation = rotation;
}
/// <summary>
/// 敌人发射子弹
/// </summary>
public class EnemyFireBullet : IEventMessage
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
public Vector3 Position;
public Quaternion Rotation;
UniEvent.SendMessage(new BattleEnemyFireBulletEvent(position, rotation));
}
}
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
var msg = new EnemyFireBullet();
msg.Position = position;
msg.Rotation = rotation;
UniEvent.SendMessage(msg);
}
/// <summary>
/// Battle player fire bullet event.
/// </summary>
public sealed class BattlePlayerFireBulletEvent : IEventMessage
{
public Vector3 Position { get; }
public Quaternion Rotation { get; }
private BattlePlayerFireBulletEvent(Vector3 position, Quaternion rotation)
{
Position = position;
Rotation = rotation;
}
/// <summary>
/// 玩家发射子弹
/// </summary>
public class PlayerFireBullet : IEventMessage
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
public Vector3 Position;
public Quaternion Rotation;
public static void SendEventMessage(Vector3 position, Quaternion rotation)
{
var msg = new PlayerFireBullet();
msg.Position = position;
msg.Rotation = rotation;
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new BattlePlayerFireBulletEvent(position, rotation));
}
}

View File

@@ -1,111 +1,117 @@
using UniFramework.Event;
using UniFramework.Event;
using YooAsset;
public class PatchEventDefine
/// <summary>
/// Patch package initialization failed event.
/// </summary>
public sealed class PatchInitializeFailedEvent : IEventMessage
{
/// <summary>
/// 补丁包初始化失败
/// </summary>
public class InitializeFailed : IEventMessage
public static void SendEventMessage()
{
public static void SendEventMessage()
{
var msg = new InitializeFailed();
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new PatchInitializeFailedEvent());
}
}
/// <summary>
/// Patch workflow step changed event.
/// </summary>
public sealed class PatchStepChangedEvent : IEventMessage
{
public string Tips { get; }
private PatchStepChangedEvent(string tips)
{
Tips = tips;
}
/// <summary>
/// 补丁流程步骤改变
/// </summary>
public class PatchStepsChange : IEventMessage
public static void SendEventMessage(string tips)
{
public string Tips;
UniEvent.SendMessage(new PatchStepChangedEvent(tips));
}
}
public static void SendEventMessage(string tips)
{
var msg = new PatchStepsChange();
msg.Tips = tips;
UniEvent.SendMessage(msg);
}
/// <summary>
/// Update files found event.
/// </summary>
public sealed class PatchFoundUpdateFilesEvent : IEventMessage
{
public int TotalCount { get; }
public long TotalSizeBytes { get; }
private PatchFoundUpdateFilesEvent(int totalCount, long totalSizeBytes)
{
TotalCount = totalCount;
TotalSizeBytes = totalSizeBytes;
}
/// <summary>
/// 发现更新文件
/// </summary>
public class FoundUpdateFiles : IEventMessage
public static void SendEventMessage(int totalCount, long totalSizeBytes)
{
public int TotalCount;
public long TotalSizeBytes;
UniEvent.SendMessage(new PatchFoundUpdateFilesEvent(totalCount, totalSizeBytes));
}
}
public static void SendEventMessage(int totalCount, long totalSizeBytes)
{
var msg = new FoundUpdateFiles();
msg.TotalCount = totalCount;
msg.TotalSizeBytes = totalSizeBytes;
UniEvent.SendMessage(msg);
}
/// <summary>
/// Download progress updated event.
/// </summary>
public sealed class PatchDownloadUpdatedEvent : IEventMessage
{
public int TotalDownloadCount { get; }
public int CurrentDownloadCount { get; }
public long TotalDownloadSizeBytes { get; }
public long CurrentDownloadSizeBytes { get; }
private PatchDownloadUpdatedEvent(DownloadProgressChangedEventArgs updateData)
{
TotalDownloadCount = updateData.TotalDownloadCount;
CurrentDownloadCount = updateData.CurrentDownloadCount;
TotalDownloadSizeBytes = updateData.TotalDownloadBytes;
CurrentDownloadSizeBytes = updateData.CurrentDownloadBytes;
}
/// <summary>
/// 下载进度更新
/// </summary>
public class DownloadUpdate : IEventMessage
public static void SendEventMessage(DownloadProgressChangedEventArgs updateData)
{
public int TotalDownloadCount;
public int CurrentDownloadCount;
public long TotalDownloadSizeBytes;
public long CurrentDownloadSizeBytes;
UniEvent.SendMessage(new PatchDownloadUpdatedEvent(updateData));
}
}
public static void SendEventMessage(DownloadProgressChangedEventArgs updateData)
{
var msg = new DownloadUpdate();
msg.TotalDownloadCount = updateData.TotalDownloadCount;
msg.CurrentDownloadCount = updateData.CurrentDownloadCount;
msg.TotalDownloadSizeBytes = updateData.TotalDownloadBytes;
msg.CurrentDownloadSizeBytes = updateData.CurrentDownloadBytes;
UniEvent.SendMessage(msg);
}
/// <summary>
/// Package version request failed event.
/// </summary>
public sealed class PatchPackageVersionRequestFailedEvent : IEventMessage
{
public static void SendEventMessage()
{
UniEvent.SendMessage(new PatchPackageVersionRequestFailedEvent());
}
}
/// <summary>
/// Package manifest update failed event.
/// </summary>
public sealed class PatchPackageManifestUpdateFailedEvent : IEventMessage
{
public static void SendEventMessage()
{
UniEvent.SendMessage(new PatchPackageManifestUpdateFailedEvent());
}
}
/// <summary>
/// Web file download failed event.
/// </summary>
public sealed class PatchWebFileDownloadFailedEvent : IEventMessage
{
public string FileName { get; }
public string Error { get; }
private PatchWebFileDownloadFailedEvent(DownloadErrorEventArgs errorData)
{
FileName = errorData.FileName;
Error = errorData.ErrorInfo;
}
/// <summary>
/// 资源版本请求失败
/// </summary>
public class PackageVersionRequestFailed : IEventMessage
public static void SendEventMessage(DownloadErrorEventArgs errorData)
{
public static void SendEventMessage()
{
var msg = new PackageVersionRequestFailed();
UniEvent.SendMessage(msg);
}
}
/// <summary>
/// 资源清单更新失败
/// </summary>
public class PackageManifestUpdateFailed : IEventMessage
{
public static void SendEventMessage()
{
var msg = new PackageManifestUpdateFailed();
UniEvent.SendMessage(msg);
}
}
/// <summary>
/// 网络文件下载失败
/// </summary>
public class WebFileDownloadFailed : IEventMessage
{
public string FileName;
public string Error;
public static void SendEventMessage(DownloadErrorEventArgs errorData)
{
var msg = new WebFileDownloadFailed();
msg.FileName = errorData.FileName;
msg.Error = errorData.ErrorInfo;
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new PatchWebFileDownloadFailedEvent(errorData));
}
}

View File

@@ -1,22 +1,23 @@
using UniFramework.Event;
using UniFramework.Event;
public class SceneEventDefine
/// <summary>
/// Change to home scene event.
/// </summary>
public sealed class SceneChangeToHomeEvent : IEventMessage
{
public class ChangeToHomeScene : IEventMessage
public static void SendEventMessage()
{
public static void SendEventMessage()
{
var msg = new ChangeToHomeScene();
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new SceneChangeToHomeEvent());
}
}
public class ChangeToBattleScene : IEventMessage
/// <summary>
/// Change to battle scene event.
/// </summary>
public sealed class SceneChangeToBattleEvent : IEventMessage
{
public static void SendEventMessage()
{
public static void SendEventMessage()
{
var msg = new ChangeToBattleScene();
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new SceneChangeToBattleEvent());
}
}

View File

@@ -1,64 +1,56 @@
using UniFramework.Event;
using UniFramework.Event;
public class UserEventDefine
/// <summary>
/// User retry package initialization event.
/// </summary>
public sealed class UserTryInitializePackageEvent : IEventMessage
{
/// <summary>
/// 用户尝试再次初始化资源包
/// </summary>
public class UserTryInitialize : IEventMessage
public static void SendEventMessage()
{
public static void SendEventMessage()
{
var msg = new UserTryInitialize();
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new UserTryInitializePackageEvent());
}
}
/// <summary>
/// 用户开始下载网络文件
/// </summary>
public class UserBeginDownloadWebFiles : IEventMessage
/// <summary>
/// User begin downloading web files event.
/// </summary>
public sealed class UserBeginDownloadWebFilesEvent : IEventMessage
{
public static void SendEventMessage()
{
public static void SendEventMessage()
{
var msg = new UserBeginDownloadWebFiles();
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new UserBeginDownloadWebFilesEvent());
}
}
/// <summary>
/// 用户尝试再次请求资源版本
/// </summary>
public class UserTryRequestPackageVersion : IEventMessage
/// <summary>
/// User retry package version request event.
/// </summary>
public sealed class UserTryRequestPackageVersionEvent : IEventMessage
{
public static void SendEventMessage()
{
public static void SendEventMessage()
{
var msg = new UserTryRequestPackageVersion();
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new UserTryRequestPackageVersionEvent());
}
}
/// <summary>
/// 用户尝试再次更新补丁清单
/// </summary>
public class UserTryUpdatePackageManifest : IEventMessage
/// <summary>
/// User retry package manifest update event.
/// </summary>
public sealed class UserTryUpdatePackageManifestEvent : IEventMessage
{
public static void SendEventMessage()
{
public static void SendEventMessage()
{
var msg = new UserTryUpdatePackageManifest();
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new UserTryUpdatePackageManifestEvent());
}
}
/// <summary>
/// 用户尝试再次下载网络文件
/// </summary>
public class UserTryDownloadWebFiles : IEventMessage
/// <summary>
/// User retry web file download event.
/// </summary>
public sealed class UserTryDownloadWebFilesEvent : IEventMessage
{
public static void SendEventMessage()
{
public static void SendEventMessage()
{
var msg = new UserTryDownloadWebFiles();
UniEvent.SendMessage(msg);
}
UniEvent.SendMessage(new UserTryDownloadWebFilesEvent());
}
}

View File

@@ -1,62 +1,87 @@
using System.Collections;
using System.Collections.Generic;
using System;
using System.Collections;
using UnityEngine;
using UniFramework.Event;
using YooAsset;
public class GameManager
{
private static GameManager _instance;
private static GameManager s_instance;
public static GameManager Instance
{
get
{
if (_instance == null)
_instance = new GameManager();
return _instance;
if (s_instance == null)
s_instance = new GameManager();
return s_instance;
}
}
private readonly EventGroup _eventGroup = new EventGroup();
private ResourcePackage _gamePackage;
private MonoBehaviour _behaviour;
/// <summary>
/// 游戏包裹
/// Game package.
/// </summary>
public ResourcePackage GamePakcage;
public ResourcePackage GamePackage
{
get
{
if (_gamePackage == null)
throw new InvalidOperationException("Game package has not been set. Call SetGamePackage before loading game assets.");
return _gamePackage;
}
}
/// <summary>
/// 协程启动器
/// Sets the game package.
/// </summary>
public MonoBehaviour Behaviour;
public void SetGamePackage(ResourcePackage gamePackage)
{
_gamePackage = gamePackage ?? throw new ArgumentNullException(nameof(gamePackage));
}
/// <summary>
/// Sets the coroutine runner.
/// </summary>
public void SetBehaviour(MonoBehaviour behaviour)
{
_behaviour = behaviour ?? throw new ArgumentNullException(nameof(behaviour));
}
private GameManager()
{
// 注册监听事件
_eventGroup.AddListener<SceneEventDefine.ChangeToHomeScene>(OnHandleEventMessage);
_eventGroup.AddListener<SceneEventDefine.ChangeToBattleScene>(OnHandleEventMessage);
// Register event listeners.
_eventGroup.AddListener<SceneChangeToHomeEvent>(OnHandleEventMessage);
_eventGroup.AddListener<SceneChangeToBattleEvent>(OnHandleEventMessage);
}
/// <summary>
/// 开启一个协程
/// Starts a coroutine.
/// </summary>
public void StartCoroutine(IEnumerator enumerator)
{
Behaviour.StartCoroutine(enumerator);
if (enumerator == null)
throw new ArgumentNullException(nameof(enumerator));
if (_behaviour == null)
throw new InvalidOperationException("Coroutine runner has not been set. Call SetBehaviour before starting coroutines.");
_behaviour.StartCoroutine(enumerator);
}
/// <summary>
/// 接收事件
/// Handles event messages.
/// </summary>
private void OnHandleEventMessage(IEventMessage message)
{
if (message is SceneEventDefine.ChangeToHomeScene)
if (message is SceneChangeToHomeEvent)
{
GamePakcage.LoadSceneAsync("scene_home");
GamePackage.LoadSceneAsync("scene_home");
}
else if (message is SceneEventDefine.ChangeToBattleScene)
else if (message is SceneChangeToBattleEvent)
{
GamePakcage.LoadSceneAsync("scene_battle");
GamePackage.LoadSceneAsync("scene_battle");
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
@@ -13,53 +12,53 @@ internal class SceneBattle : MonoBehaviour
private IEnumerator Start()
{
// 加载战斗页面
_windowHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<GameObject>("UIBattle");
// Load battle window.
_windowHandle = GameManager.Instance.GamePackage.LoadAssetAsync<GameObject>("UIBattle");
yield return _windowHandle;
_windowHandle.InstantiateSync(CanvasDesktop.transform);
_windowHandle.InstantiateSync(new InstantiateOptions(true, CanvasDesktop.transform, false));
// 加载背景音乐
_musicHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<AudioClip>("music_background");
// Load background music.
_musicHandle = GameManager.Instance.GamePackage.LoadAssetAsync<AudioClip>("music_background");
yield return _musicHandle;
// 播放背景音乐
// Play background music.
var audioSource = this.gameObject.AddComponent<AudioSource>();
audioSource.loop = true;
audioSource.clip = _musicHandle.AssetObject as AudioClip;
audioSource.Play();
// 切换场景的时候释放资源
// Release unused assets after changing scenes.
var package = YooAssets.GetPackage("DefaultPackage");
var operation = package.UnloadUnusedAssetsAsync();
yield return operation;
_battleRoom = new BattleRoom();
_battleRoom.IntRoom();
_battleRoom.InitRoom();
}
private void OnDestroy()
{
// 释放资源句柄
// Release asset handle.
if (_windowHandle != null)
{
_windowHandle.Release();
_windowHandle = null;
}
// 释放资源句柄
// Release asset handle.
if (_musicHandle != null)
{
_musicHandle.Release();
_musicHandle = null;
}
// 释放资源句柄
// Release battle room.
if (_battleRoom != null)
{
_battleRoom.DestroyRoom();
_battleRoom = null;
}
// 切换场景的时候释放资源
// Release unused assets after changing scenes.
if (YooAssets.IsInitialized)
{
var package = YooAssets.GetPackage("DefaultPackage");

View File

@@ -1,12 +1,10 @@
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine;
using YooAsset;
public class SceneHome : MonoBehaviour
{
public GameObject CanvasDesktop;
private AssetHandle _windowHandle;
void Start()
@@ -16,12 +14,12 @@ public class SceneHome : MonoBehaviour
private async void AsyncLoad()
{
// 加载主页面
_windowHandle = GameManager.Instance.GamePakcage.LoadAssetAsync<GameObject>("UIHome");
// Load home window.
_windowHandle = GameManager.Instance.GamePackage.LoadAssetAsync<GameObject>("UIHome");
await _windowHandle;
_windowHandle.InstantiateSync(CanvasDesktop.transform);
_windowHandle.InstantiateSync(new InstantiateOptions(true, CanvasDesktop.transform, false));
// 切换场景的时候释放资源
// Release unused assets after changing scenes.
var package = YooAssets.GetPackage("DefaultPackage");
var operation = package.UnloadUnusedAssetsAsync();
await operation;
@@ -29,7 +27,7 @@ public class SceneHome : MonoBehaviour
private void OnDestroy()
{
// 释放资源句柄
// Release asset handle.
if (_windowHandle != null)
{
_windowHandle.Release();

View File

@@ -1,6 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniFramework.Machine;
using YooAsset;
@@ -14,10 +11,11 @@ internal class FsmClearCacheBundle : IStateNode
}
void IStateNode.OnEnter()
{
PatchEventDefine.PatchStepsChange.SendEventMessage("清理未使用的缓存文件!");
PatchStepChangedEvent.SendEventMessage("Clearing unused cache files.");
var packageName = (string)_machine.GetBlackboardValue("PackageName");
var package = YooAssets.GetPackage(packageName);
var operation = package.ClearCacheFilesAsync(ClearCacheMethods.ClearUnusedBundleFiles);
var options = new ClearCacheOptions(ClearCacheMethods.ClearUnusedBundleFiles);
var operation = package.ClearCacheAsync(options);
operation.Completed += Operation_Completed;
}
void IStateNode.OnUpdate()

View File

@@ -1,10 +1,8 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
using UniFramework.Machine;
using YooAsset;
public class FsmCreateDownloader : IStateNode
internal class FsmCreateDownloader : IStateNode
{
private StateMachine _machine;
@@ -14,7 +12,7 @@ public class FsmCreateDownloader : IStateNode
}
void IStateNode.OnEnter()
{
PatchEventDefine.PatchStepsChange.SendEventMessage("创建资源下载器!");
PatchStepChangedEvent.SendEventMessage("Creating resource downloader.");
CreateDownloader();
}
void IStateNode.OnUpdate()
@@ -30,21 +28,22 @@ public class FsmCreateDownloader : IStateNode
var package = YooAssets.GetPackage(packageName);
int downloadingMaxNum = 10;
int failedTryAgain = 3;
var downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);
var options = new ResourceDownloaderOptions(downloadingMaxNum, failedTryAgain);
var downloader = package.CreateResourceDownloader(options);
_machine.SetBlackboardValue("Downloader", downloader);
if (downloader.TotalDownloadCount == 0)
{
Debug.Log("Not found any download files !");
Debug.Log("No download files were found.");
_machine.ChangeState<FsmStartGame>();
}
else
{
// 发现新更新文件后,挂起流程系统
// 注意:开发者需要在下载前检测磁盘空间不足
// Suspend the patch workflow after update files are found.
// Developers should check available disk space before downloading.
int totalDownloadCount = downloader.TotalDownloadCount;
long totalDownloadBytes = downloader.TotalDownloadBytes;
PatchEventDefine.FoundUpdateFiles.SendEventMessage(totalDownloadCount, totalDownloadBytes);
PatchFoundUpdateFilesEvent.SendEventMessage(totalDownloadCount, totalDownloadBytes);
}
}
}

View File

@@ -1,9 +1,8 @@
using System.Collections;
using UnityEngine;
using UniFramework.Machine;
using YooAsset;
public class FsmDownloadPackageFiles : IStateNode
internal class FsmDownloadPackageFiles : IStateNode
{
private StateMachine _machine;
@@ -13,7 +12,7 @@ public class FsmDownloadPackageFiles : IStateNode
}
void IStateNode.OnEnter()
{
PatchEventDefine.PatchStepsChange.SendEventMessage("开始下载资源文件!");
PatchStepChangedEvent.SendEventMessage("Downloading resource files.");
GameManager.Instance.StartCoroutine(StartDownload());
}
void IStateNode.OnUpdate()
@@ -26,12 +25,12 @@ public class FsmDownloadPackageFiles : IStateNode
private IEnumerator StartDownload()
{
var downloader = (ResourceDownloaderOperation)_machine.GetBlackboardValue("Downloader");
downloader.DownloadError += PatchEventDefine.WebFileDownloadFailed.SendEventMessage;
downloader.DownloadProgressChanged += PatchEventDefine.DownloadUpdate.SendEventMessage;
downloader.DownloadError += PatchWebFileDownloadFailedEvent.SendEventMessage;
downloader.DownloadProgressChanged += PatchDownloadUpdatedEvent.SendEventMessage;
downloader.StartDownload();
yield return downloader;
// 检测下载结果
// Check download result.
if (downloader.Status != EOperationStatus.Succeeded)
yield break;

View File

@@ -1,7 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniFramework.Machine;
using UniFramework.Machine;
internal class FsmDownloadPackageOver : IStateNode
{
@@ -13,7 +10,7 @@ internal class FsmDownloadPackageOver : IStateNode
}
void IStateNode.OnEnter()
{
PatchEventDefine.PatchStepsChange.SendEventMessage("资源文件下载完毕!");
PatchStepChangedEvent.SendEventMessage("Resource files download completed.");
_machine.ChangeState<FsmClearCacheBundle>();
}
void IStateNode.OnUpdate()

View File

@@ -1,4 +1,3 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
@@ -16,7 +15,7 @@ internal class FsmInitializePackage : IStateNode
}
void IStateNode.OnEnter()
{
PatchEventDefine.PatchStepsChange.SendEventMessage("初始化资源包!");
PatchStepChangedEvent.SendEventMessage("Initializing package.");
GameManager.Instance.StartCoroutine(InitPackage());
}
void IStateNode.OnUpdate()
@@ -31,75 +30,75 @@ internal class FsmInitializePackage : IStateNode
var playMode = (EPlayMode)_machine.GetBlackboardValue("PlayMode");
var packageName = (string)_machine.GetBlackboardValue("PackageName");
// 创建资源包裹类
// Create package.
if (!YooAssets.TryGetPackage(packageName, out var package))
package = YooAssets.CreatePackage(packageName);
// 编辑器下的模拟模式
InitializationOperation initializationOperation = null;
// Editor simulation mode.
InitializePackageOperation initializationOperation = null;
if (playMode == EPlayMode.EditorSimulateMode)
{
var buildResult = EditorSimulateBuildInvoker.Build(packageName, (int)EBundleType.VirtualBundle);
var packageRoot = buildResult.PackageRootDirectory;
var createParameters = new EditorSimulateModeParameters();
var createParameters = new EditorSimulateModeOptions();
createParameters.EditorFileSystemParameters = FileSystemParameters.CreateDefaultEditorFileSystemParameters(packageRoot);
createParameters.EditorFileSystemParameters.AddParameter(EFileSystemParameter.VirtualWebglMode, true);
createParameters.EditorFileSystemParameters.AddParameter(EFileSystemParameter.VirtualDownloadMode, true);
createParameters.EditorFileSystemParameters.AddParameter(EFileSystemParameter.VirtualDownloadSpeed, 1024 * 1000);
createParameters.EditorFileSystemParameters.AddParameter(EFileSystemParameter.AsyncSimulateMinFrame, 5);
createParameters.EditorFileSystemParameters.AddParameter(EFileSystemParameter.AsyncSimulateMaxFrame, 10);
initializationOperation = package.InitializeAsync(createParameters);
initializationOperation = package.InitializePackageAsync(createParameters);
}
// 单机运行模式
// Offline play mode.
if (playMode == EPlayMode.OfflinePlayMode)
{
var createParameters = new OfflinePlayModeParameters();
var createParameters = new OfflinePlayModeOptions();
createParameters.BuiltinFileSystemParameters = FileSystemParameters.CreateDefaultBuiltinFileSystemParameters();
initializationOperation = package.InitializeAsync(createParameters);
initializationOperation = package.InitializePackageAsync(createParameters);
}
// 联机运行模式
// Host play mode.
if (playMode == EPlayMode.HostPlayMode)
{
string defaultHostServer = GetHostServerURL();
string fallbackHostServer = GetHostServerURL();
IRemoteService remoteService = new RemoteService(defaultHostServer, fallbackHostServer);
var createParameters = new HostPlayModeParameters();
var createParameters = new HostPlayModeOptions();
createParameters.BuiltinFileSystemParameters = FileSystemParameters.CreateDefaultBuiltinFileSystemParameters();
createParameters.BuiltinFileSystemParameters.AddParameter(EFileSystemParameter.CopyBuiltinPackageManifest, true);
createParameters.CacheFileSystemParameters = FileSystemParameters.CreateDefaultSandboxFileSystemParameters(remoteService);
createParameters.CacheFileSystemParameters.AddParameter(EFileSystemParameter.DownloadMaxConcurrency, 5);
createParameters.CacheFileSystemParameters.AddParameter(EFileSystemParameter.DownloadMaxRequestPerFrame, 1);
createParameters.CacheFileSystemParameters.AddParameter(EFileSystemParameter.DownloadWatchdogTimeout, 10);
initializationOperation = package.InitializeAsync(createParameters);
initializationOperation = package.InitializePackageAsync(createParameters);
}
// WebGL运行模式
// Web play mode.
if (playMode == EPlayMode.WebPlayMode)
{
#if UNITY_WEBGL && WEIXINMINIGAME && !UNITY_EDITOR
var createParameters = new WebPlayModeParameters();
string defaultHostServer = GetHostServerURL();
var createParameters = new WebPlayModeOptions();
string defaultHostServer = GetHostServerURL();
string fallbackHostServer = GetHostServerURL();
string packageRoot = $"{WeChatWASM.WX.env.USER_DATA_PATH}/__GAME_FILE_CACHE"; //注意:如果有子目录,请修改此处!
string packageRoot = $"{WeChatWASM.WX.env.USER_DATA_PATH}/__GAME_FILE_CACHE"; // Change this path if subdirectories are required.
IRemoteService remoteService = new RemoteService(defaultHostServer, fallbackHostServer);
createParameters.WebServerFileSystemParameters = WechatFileSystemCreater.CreateFileSystemParameters(packageRoot, remoteService);
initializationOperation = package.InitializeAsync(createParameters);
initializationOperation = package.InitializePackageAsync(createParameters);
#else
var createParameters = new WebPlayModeParameters();
var createParameters = new WebPlayModeOptions();
createParameters.WebServerFileSystemParameters = FileSystemParameters.CreateDefaultWebServerFileSystemParameters();
initializationOperation = package.InitializeAsync(createParameters);
initializationOperation = package.InitializePackageAsync(createParameters);
#endif
}
yield return initializationOperation;
// 如果初始化失败弹出提示界面
// Show prompt when initialization fails.
if (initializationOperation.Status != EOperationStatus.Succeeded)
{
Debug.LogWarning($"{initializationOperation.Error}");
PatchEventDefine.InitializeFailed.SendEventMessage();
PatchInitializeFailedEvent.SendEventMessage();
}
else
{
@@ -108,11 +107,11 @@ internal class FsmInitializePackage : IStateNode
}
/// <summary>
/// 获取资源服务器地址
/// Gets the resource server URL.
/// </summary>
private string GetHostServerURL()
{
//string hostServerIP = "http://10.0.2.2"; //安卓模拟器地址
//string hostServerIP = "http://10.0.2.2"; // Android emulator address.
string hostServerIP = "http://127.0.0.1";
string appVersion = "v1.0";
@@ -138,7 +137,7 @@ internal class FsmInitializePackage : IStateNode
}
/// <summary>
/// 远端资源地址查询服务类
/// Remote resource URL query service.
/// </summary>
private class RemoteService : IRemoteService
{

View File

@@ -1,5 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniFramework.Machine;
using YooAsset;
@@ -14,7 +13,7 @@ internal class FsmRequestPackageVersion : IStateNode
}
void IStateNode.OnEnter()
{
PatchEventDefine.PatchStepsChange.SendEventMessage("请求资源版本 !");
PatchStepChangedEvent.SendEventMessage("Requesting package version.");
GameManager.Instance.StartCoroutine(UpdatePackageVersion());
}
void IStateNode.OnUpdate()
@@ -34,11 +33,11 @@ internal class FsmRequestPackageVersion : IStateNode
if (operation.Status != EOperationStatus.Succeeded)
{
Debug.LogWarning(operation.Error);
PatchEventDefine.PackageVersionRequestFailed.SendEventMessage();
PatchPackageVersionRequestFailedEvent.SendEventMessage();
}
else
{
Debug.Log($"Request package version : {operation.PackageVersion}");
Debug.Log($"Package version requested: '{operation.PackageVersion}'.");
_machine.SetBlackboardValue("PackageVersion", operation.PackageVersion);
_machine.ChangeState<FsmUpdatePackageManifest>();
}

View File

@@ -1,6 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniFramework.Machine;
using YooAsset;
@@ -11,13 +8,13 @@ internal class FsmStartGame : IStateNode
}
void IStateNode.OnEnter()
{
PatchEventDefine.PatchStepsChange.SendEventMessage("开始游戏!");
PatchStepChangedEvent.SendEventMessage("Starting game.");
// 设置默认的资源包
GameManager.Instance.GamePakcage = YooAssets.GetPackage("DefaultPackage");
// Set default package.
GameManager.Instance.SetGamePackage(YooAssets.GetPackage("DefaultPackage"));
// 切换到主页面场景
SceneEventDefine.ChangeToHomeScene.SendEventMessage();
// Change to home scene.
SceneChangeToHomeEvent.SendEventMessage();
}
void IStateNode.OnUpdate()
{

View File

@@ -1,10 +1,9 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniFramework.Machine;
using YooAsset;
public class FsmUpdatePackageManifest : IStateNode
internal class FsmUpdatePackageManifest : IStateNode
{
private StateMachine _machine;
@@ -14,7 +13,7 @@ public class FsmUpdatePackageManifest : IStateNode
}
void IStateNode.OnEnter()
{
PatchEventDefine.PatchStepsChange.SendEventMessage("更新资源清单!");
PatchStepChangedEvent.SendEventMessage("Updating package manifest.");
GameManager.Instance.StartCoroutine(UpdateManifest());
}
void IStateNode.OnUpdate()
@@ -29,13 +28,14 @@ public class FsmUpdatePackageManifest : IStateNode
var packageName = (string)_machine.GetBlackboardValue("PackageName");
var packageVersion = (string)_machine.GetBlackboardValue("PackageVersion");
var package = YooAssets.GetPackage(packageName);
var operation = package.UpdatePackageManifestAsync(packageVersion);
var options = new LoadPackageManifestOptions(packageVersion, 60);
var operation = package.LoadPackageManifestAsync(options);
yield return operation;
if (operation.Status != EOperationStatus.Succeeded)
{
Debug.LogWarning(operation.Error);
PatchEventDefine.PackageManifestUpdateFailed.SendEventMessage();
PatchPackageManifestUpdateFailedEvent.SendEventMessage();
yield break;
}
else

View File

@@ -1,4 +1,4 @@
using UnityEngine;
using System;
using UniFramework.Machine;
using UniFramework.Event;
using YooAsset;
@@ -10,14 +10,19 @@ public static class PatchManager
public static void Create(string packageName, EPlayMode playMode)
{
// 注册监听事件
_eventGroup.AddListener<UserEventDefine.UserTryInitialize>(OnHandleEventMessage);
_eventGroup.AddListener<UserEventDefine.UserBeginDownloadWebFiles>(OnHandleEventMessage);
_eventGroup.AddListener<UserEventDefine.UserTryRequestPackageVersion>(OnHandleEventMessage);
_eventGroup.AddListener<UserEventDefine.UserTryUpdatePackageManifest>(OnHandleEventMessage);
_eventGroup.AddListener<UserEventDefine.UserTryDownloadWebFiles>(OnHandleEventMessage);
if (string.IsNullOrWhiteSpace(packageName))
throw new ArgumentException("Package name cannot be null or empty.", nameof(packageName));
if (!IsValidPlayMode(playMode))
throw new ArgumentException($"Invalid play mode: {playMode}.", nameof(playMode));
// 创建状态机
// Register event listeners.
_eventGroup.AddListener<UserTryInitializePackageEvent>(OnHandleEventMessage);
_eventGroup.AddListener<UserBeginDownloadWebFilesEvent>(OnHandleEventMessage);
_eventGroup.AddListener<UserTryRequestPackageVersionEvent>(OnHandleEventMessage);
_eventGroup.AddListener<UserTryUpdatePackageManifestEvent>(OnHandleEventMessage);
_eventGroup.AddListener<UserTryDownloadWebFilesEvent>(OnHandleEventMessage);
// Create state machine.
_machine = new StateMachine(null);
_machine.AddNode<FsmInitializePackage>();
_machine.AddNode<FsmRequestPackageVersion>();
@@ -33,41 +38,61 @@ public static class PatchManager
}
public static void Start()
{
if (_machine == null)
throw new InvalidOperationException("Patch manager has not been created. Call Create before Start.");
_machine.Run<FsmInitializePackage>();
}
public static void Update()
{
if (_machine == null)
throw new InvalidOperationException("Patch manager has not been created. Call Create before Update.");
_machine.Update();
}
/// <summary>
/// 接收事件
/// Handles event messages.
/// </summary>
private static void OnHandleEventMessage(IEventMessage message)
{
if (message is UserEventDefine.UserTryInitialize)
if (message is UserTryInitializePackageEvent)
{
_machine.ChangeState<FsmInitializePackage>();
}
else if (message is UserEventDefine.UserBeginDownloadWebFiles)
else if (message is UserBeginDownloadWebFilesEvent)
{
_machine.ChangeState<FsmDownloadPackageFiles>();
}
else if (message is UserEventDefine.UserTryRequestPackageVersion)
else if (message is UserTryRequestPackageVersionEvent)
{
_machine.ChangeState<FsmRequestPackageVersion>();
}
else if (message is UserEventDefine.UserTryUpdatePackageManifest)
else if (message is UserTryUpdatePackageManifestEvent)
{
_machine.ChangeState<FsmUpdatePackageManifest>();
}
else if (message is UserEventDefine.UserTryDownloadWebFiles)
else if (message is UserTryDownloadWebFilesEvent)
{
_machine.ChangeState<FsmCreateDownloader>();
}
else
{
throw new System.NotImplementedException($"{message.GetType()}");
throw new InvalidOperationException($"Unsupported patch event message type: {message.GetType().FullName}.");
}
}
private static bool IsValidPlayMode(EPlayMode playMode)
{
switch (playMode)
{
case EPlayMode.EditorSimulateMode:
case EPlayMode.OfflinePlayMode:
case EPlayMode.HostPlayMode:
case EPlayMode.WebPlayMode:
return true;
default:
return false;
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
@@ -8,7 +7,7 @@ using UniFramework.Event;
public class PatchWindow : MonoBehaviour
{
/// <summary>
/// 对话框封装类
/// Message box wrapper.
/// </summary>
private class MessageBox
{
@@ -55,7 +54,7 @@ public class PatchWindow : MonoBehaviour
private readonly EventGroup _eventGroup = new EventGroup();
private readonly List<MessageBox> _msgBoxList = new List<MessageBox>();
// UGUI相关
// UGUI references.
private GameObject _messageBoxObj;
private Slider _slider;
private Text _tips;
@@ -64,17 +63,17 @@ public class PatchWindow : MonoBehaviour
{
_slider = transform.Find("UIWindow/Slider").GetComponent<Slider>();
_tips = transform.Find("UIWindow/Slider/txt_tips").GetComponent<Text>();
_tips.text = "Initializing the game world !";
_tips.text = "Initializing the game world.";
_messageBoxObj = transform.Find("UIWindow/MessgeBox").gameObject;
_messageBoxObj.SetActive(false);
_eventGroup.AddListener<PatchEventDefine.InitializeFailed>(OnHandleEventMessage);
_eventGroup.AddListener<PatchEventDefine.PatchStepsChange>(OnHandleEventMessage);
_eventGroup.AddListener<PatchEventDefine.FoundUpdateFiles>(OnHandleEventMessage);
_eventGroup.AddListener<PatchEventDefine.DownloadUpdate>(OnHandleEventMessage);
_eventGroup.AddListener<PatchEventDefine.PackageVersionRequestFailed>(OnHandleEventMessage);
_eventGroup.AddListener<PatchEventDefine.PackageManifestUpdateFailed>(OnHandleEventMessage);
_eventGroup.AddListener<PatchEventDefine.WebFileDownloadFailed>(OnHandleEventMessage);
_eventGroup.AddListener<PatchInitializeFailedEvent>(OnHandleEventMessage);
_eventGroup.AddListener<PatchStepChangedEvent>(OnHandleEventMessage);
_eventGroup.AddListener<PatchFoundUpdateFilesEvent>(OnHandleEventMessage);
_eventGroup.AddListener<PatchDownloadUpdatedEvent>(OnHandleEventMessage);
_eventGroup.AddListener<PatchPackageVersionRequestFailedEvent>(OnHandleEventMessage);
_eventGroup.AddListener<PatchPackageManifestUpdateFailedEvent>(OnHandleEventMessage);
_eventGroup.AddListener<PatchWebFileDownloadFailedEvent>(OnHandleEventMessage);
}
void OnDestroy()
{
@@ -82,81 +81,81 @@ public class PatchWindow : MonoBehaviour
}
/// <summary>
/// 接收事件
/// Handles event messages.
/// </summary>
private void OnHandleEventMessage(IEventMessage message)
{
if (message is PatchEventDefine.InitializeFailed)
if (message is PatchInitializeFailedEvent)
{
System.Action callback = () =>
{
UserEventDefine.UserTryInitialize.SendEventMessage();
UserTryInitializePackageEvent.SendEventMessage();
};
ShowMessageBox($"Failed to initialize package !", callback);
ShowMessageBox("Failed to initialize package.", callback);
}
else if (message is PatchEventDefine.PatchStepsChange)
else if (message is PatchStepChangedEvent)
{
var msg = message as PatchEventDefine.PatchStepsChange;
var msg = message as PatchStepChangedEvent;
_tips.text = msg.Tips;
UnityEngine.Debug.Log(msg.Tips);
}
else if (message is PatchEventDefine.FoundUpdateFiles)
else if (message is PatchFoundUpdateFilesEvent)
{
var msg = message as PatchEventDefine.FoundUpdateFiles;
var msg = message as PatchFoundUpdateFilesEvent;
System.Action callback = () =>
{
UserEventDefine.UserBeginDownloadWebFiles.SendEventMessage();
UserBeginDownloadWebFilesEvent.SendEventMessage();
};
float sizeMB = msg.TotalSizeBytes / 1048576f;
sizeMB = Mathf.Clamp(sizeMB, 0.1f, float.MaxValue);
string totalSizeMB = sizeMB.ToString("f1");
ShowMessageBox($"Found update patch files, Total count {msg.TotalCount} Total szie {totalSizeMB}MB", callback);
ShowMessageBox($"Update files were found. Total count: {msg.TotalCount}. Total size: {totalSizeMB} MB.", callback);
}
else if (message is PatchEventDefine.DownloadUpdate)
else if (message is PatchDownloadUpdatedEvent)
{
var msg = message as PatchEventDefine.DownloadUpdate;
var msg = message as PatchDownloadUpdatedEvent;
_slider.value = (float)msg.CurrentDownloadCount / msg.TotalDownloadCount;
string currentSizeMB = (msg.CurrentDownloadSizeBytes / 1048576f).ToString("f1");
string totalSizeMB = (msg.TotalDownloadSizeBytes / 1048576f).ToString("f1");
_tips.text = $"{msg.CurrentDownloadCount}/{msg.TotalDownloadCount} {currentSizeMB}MB/{totalSizeMB}MB";
}
else if (message is PatchEventDefine.PackageVersionRequestFailed)
else if (message is PatchPackageVersionRequestFailedEvent)
{
System.Action callback = () =>
{
UserEventDefine.UserTryRequestPackageVersion.SendEventMessage();
UserTryRequestPackageVersionEvent.SendEventMessage();
};
ShowMessageBox($"Failed to request package version, please check the network status.", callback);
ShowMessageBox("Failed to request package version. Check the network status.", callback);
}
else if (message is PatchEventDefine.PackageManifestUpdateFailed)
else if (message is PatchPackageManifestUpdateFailedEvent)
{
System.Action callback = () =>
{
UserEventDefine.UserTryUpdatePackageManifest.SendEventMessage();
UserTryUpdatePackageManifestEvent.SendEventMessage();
};
ShowMessageBox($"Failed to update patch manifest, please check the network status.", callback);
ShowMessageBox("Failed to update package manifest. Check the network status.", callback);
}
else if (message is PatchEventDefine.WebFileDownloadFailed)
else if (message is PatchWebFileDownloadFailedEvent)
{
var msg = message as PatchEventDefine.WebFileDownloadFailed;
var msg = message as PatchWebFileDownloadFailedEvent;
System.Action callback = () =>
{
UserEventDefine.UserTryDownloadWebFiles.SendEventMessage();
UserTryDownloadWebFilesEvent.SendEventMessage();
};
ShowMessageBox($"Failed to download file : {msg.FileName}", callback);
ShowMessageBox($"Failed to download file: '{msg.FileName}'.", callback);
}
else
{
throw new System.NotImplementedException($"{message.GetType()}");
throw new InvalidOperationException($"Unsupported patch window event message type: {message.GetType().FullName}.");
}
}
/// <summary>
/// 显示对话框
/// Shows a message box.
/// </summary>
private void ShowMessageBox(string content, System.Action ok)
{
// 尝试获取一个可用的对话框
// Try to reuse an inactive message box.
MessageBox msgBox = null;
for (int i = 0; i < _msgBoxList.Count; i++)
{
@@ -168,7 +167,7 @@ public class PatchWindow : MonoBehaviour
}
}
// 如果没有可用的对话框,则创建一个新的对话框
// Create a new message box if none are available.
if (msgBox == null)
{
msgBox = new MessageBox();
@@ -177,7 +176,7 @@ public class PatchWindow : MonoBehaviour
_msgBoxList.Add(msgBox);
}
// 显示对话框
// Show the message box.
msgBox.Show(content, ok);
}
}

View File

@@ -1,5 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
@@ -8,10 +6,10 @@ public class UIAboutWindow : MonoBehaviour
private void Awake()
{
var maskBtn = this.transform.Find("mask").GetComponent<Button>();
maskBtn.onClick.AddListener(OnClicMaskBtn);
maskBtn.onClick.AddListener(OnClickMaskBtn);
}
private void OnClicMaskBtn()
private void OnClickMaskBtn()
{
GameObject.Destroy(this.gameObject);
}

View File

@@ -1,5 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UniFramework.Event;
@@ -14,7 +12,7 @@ public class UIBattleWindow : MonoBehaviour
{
_overView = this.transform.Find("OverView").gameObject;
_scoreLabel = this.transform.Find("ScoreView/Score").GetComponent<Text>();
_scoreLabel.text = "Score : 0";
_scoreLabel.text = "Score: 0";
var restartBtn = this.transform.Find("OverView/ReplayButton").GetComponent<Button>();
restartBtn.onClick.AddListener(OnClickReplayBtn);
@@ -22,8 +20,8 @@ public class UIBattleWindow : MonoBehaviour
var homeBtn = this.transform.Find("OverView/HomeButton").GetComponent<Button>();
homeBtn.onClick.AddListener(OnClickHomeBtn);
_eventGroup.AddListener<BattleEventDefine.ScoreChange>(OnHandleEventMessage);
_eventGroup.AddListener<BattleEventDefine.GameOver>(OnHandleEventMessage);
_eventGroup.AddListener<BattleScoreChangedEvent>(OnHandleEventMessage);
_eventGroup.AddListener<BattleGameOverEvent>(OnHandleEventMessage);
}
private void OnDestroy()
{
@@ -32,20 +30,20 @@ public class UIBattleWindow : MonoBehaviour
private void OnClickReplayBtn()
{
SceneEventDefine.ChangeToBattleScene.SendEventMessage();
SceneChangeToBattleEvent.SendEventMessage();
}
private void OnClickHomeBtn()
{
SceneEventDefine.ChangeToHomeScene.SendEventMessage();
SceneChangeToHomeEvent.SendEventMessage();
}
private void OnHandleEventMessage(IEventMessage message)
{
if(message is BattleEventDefine.ScoreChange)
if(message is BattleScoreChangedEvent)
{
var msg = message as BattleEventDefine.ScoreChange;
_scoreLabel.text = $"Score : {msg.CurrentScores}";
var msg = message as BattleScoreChangedEvent;
_scoreLabel.text = $"Score: {msg.CurrentScores}";
}
else if(message is BattleEventDefine.GameOver)
else if(message is BattleGameOverEvent)
{
_overView.SetActive(true);
}

View File

@@ -1,5 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
@@ -17,7 +15,7 @@ public class UIHomeWindow : MonoBehaviour
loginBtn.onClick.AddListener(OnClickPlayGameBtn);
var aboutBtn = this.transform.Find("AboutButton").GetComponent<Button>();
aboutBtn.onClick.AddListener(OnClicAboutBtn);
aboutBtn.onClick.AddListener(OnClickAboutBtn);
var maskBtn = this.transform.Find("AboutView/mask").GetComponent<Button>();
maskBtn.onClick.AddListener(OnClickMaskBtn);
@@ -25,14 +23,14 @@ public class UIHomeWindow : MonoBehaviour
private void Start()
{
var package = YooAsset.YooAssets.GetPackage("DefaultPackage");
_version.text = "Version : " + package.GetPackageVersion();
_version.text = "Version: " + package.GetPackageVersion();
}
private void OnClickPlayGameBtn()
{
SceneEventDefine.ChangeToBattleScene.SendEventMessage();
SceneChangeToBattleEvent.SendEventMessage();
}
private void OnClicAboutBtn()
private void OnClickAboutBtn()
{
_aboutView.SetActive(true);
}

View File

@@ -1,5 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UniFramework.Utility;

View File

@@ -1,4 +1,4 @@
using UnityEditor;
using UnityEditor;
using UnityEngine;
using YooAsset;
using YooAsset.Editor;

View File

@@ -1,10 +1,10 @@
{
"name": "YooAsset.Test.Editor",
"name": "YooAsset.Tests.Editor",
"rootNamespace": "",
"references": [
"YooAsset",
"YooAsset.Editor",
"YooAsset.Test"
"YooAsset.Tests"
],
"includePlatforms": [
"Editor"

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Text;
using System.Collections;
using UnityEngine;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Text;
using System.IO;
using System.Collections;

View File

@@ -1,58 +0,0 @@
using System;
using System.IO;
using System.Collections;
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using YooAsset;
using UnityEngine.Video;
/// <summary>
/// 测试视频文件加载与播放
/// </summary>
/// <remarks>
/// 覆盖 API: LoadRawFileAsync / RawFileHandle.GetRawFilePath
/// 测试内容:
/// 1. 异步加载视频原生文件,验证加载状态和文件存在
/// 2. 拷贝缓存文件到临时路径(补充 .mp4 扩展名以适配 VideoPlayer
/// 3. 创建 VideoPlayer 组件播放视频,等待 1 秒后验证正在播放
/// 4. 销毁 VideoPlayer 并清理临时文件
/// </remarks>
public class TestLoadRawVideo
{
public IEnumerator RuntimeTester()
{
ResourcePackage package = YooAssets.GetPackage(TestConsts.RawBundlePackageName);
Assert.IsNotNull(package);
var rawFileHandle = package.LoadRawFileAsync("video_logo");
yield return rawFileHandle;
Assert.AreEqual(EOperationStatus.Succeeded, rawFileHandle.Status);
// 获取视频文件地址
string videoFilePath = rawFileHandle.GetRawFilePath();
Assert.IsTrue(File.Exists(videoFilePath));
// VideoPlayer 需要文件带正确扩展名才能识别格式,缓存文件名为 __data 无扩展名
string tempPath = Path.Combine(Application.temporaryCachePath, "test_video.mp4");
File.Copy(videoFilePath, tempPath, true);
// 创建预制体播放视频
GameObject go = new GameObject("video player");
var videoPlayer = go.AddComponent<VideoPlayer>();
videoPlayer.source = VideoSource.Url;
videoPlayer.renderMode = VideoRenderMode.APIOnly;
videoPlayer.url = tempPath;
videoPlayer.Play();
yield return new WaitForSeconds(1f);
Assert.IsTrue(videoPlayer.isPlaying);
// 清理 VideoPlayer 和临时文件
videoPlayer.Stop();
GameObject.Destroy(go);
if (File.Exists(tempPath))
File.Delete(tempPath);
rawFileHandle.Release();
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 0ec434834a510eb4d823b786b2b83927
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Text;
using System.Collections;
using UnityEngine;
@@ -47,7 +47,7 @@ public class TestLoadScene
// 同步加载附加场景并等待
yield return new WaitForSeconds(0.2f);
SceneHandle cachedHandle;
YooAsset.SceneHandle cachedHandle;
{
cachedHandle = package.LoadSceneSync("scene_c", LoadSceneMode.Additive);
yield return cachedHandle;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Text;
using System.Collections;
using UnityEngine.TestTools;

Some files were not shown because too many files have changed in this diff Show More