Compare commits

...

40 Commits

Author SHA1 Message Date
hevinci
f6e94c9514 Update CHANGELOG.md 2023-06-09 11:27:33 +08:00
hevinci
da4ba4453c Update package.json 2023-06-09 11:27:19 +08:00
hevinci
53ea8c8002 update runtime code 2023-06-09 11:27:15 +08:00
hevinci
d4549b1228 update space shooter
修复了DEMO里IOS平台流解密失败的问题。
2023-06-05 19:02:13 +08:00
hevinci
fcf9eff2f6 update space shooter 2023-06-05 18:04:09 +08:00
hevinci
93b58149d2 update runtime code 2023-05-30 15:03:22 +08:00
hevinci
c91c49465b update cache system
修复验证远端下载文件,极小概率失败的问题。
2023-05-29 19:28:07 +08:00
hevinci
e9fa3ead04 update asset system
修复安卓平台下,小米8手机上有小概率加载原生文件失败的问题。
2023-05-29 17:30:43 +08:00
hevinci
eff2f1d968 update space shooter 2023-05-26 18:35:34 +08:00
hevinci
cd0a6579b8 Update CHANGELOG.md 2023-05-26 18:07:32 +08:00
hevinci
18c2e232cf Update package.json 2023-05-26 18:07:20 +08:00
hevinci
ad680638ac update AssetBundleBuilder
Unity2021版本及以上推荐使用可编程构建管线(SBP)
2023-05-26 18:05:39 +08:00
hevinci
0764061d8f update space shooter 2023-05-25 16:38:33 +08:00
hevinci
d448026250 update AssetBundleBuilder
修复了内置着色器Tag未正确传染给依赖资源包的问题。
2023-05-25 16:38:02 +08:00
hevinci
34f553b9e3 update AssetBundleCollector
修复了收集器对着色器未过滤的问题。
2023-05-25 16:35:18 +08:00
hevinci
25d1e32ce9 update asset system 2023-05-15 15:34:49 +08:00
hevinci
8686c32ada Update CHANGELOG.md 2023-05-12 17:45:24 +08:00
hevinci
f043c6710a Update CHANGELOG.md 2023-05-12 17:43:13 +08:00
hevinci
acd27e36fa Update package.json 2023-05-12 17:43:05 +08:00
hevinci
37f0d1e5a1 update runtime code
新增方法YooAssets.SetCacheSystemSandboxPath()
2023-05-12 17:32:41 +08:00
hevinci
e6397559ff update cache system
新增方法ResoucePackage.ClearAllCacheFilesAsync()
2023-05-12 14:30:08 +08:00
hevinci
812c46adeb update runtime code
销毁Package的时候清空缓存记录。
2023-05-06 10:42:33 +08:00
hevinci
4d7fb6301a update samples 2023-05-05 10:35:02 +08:00
hevinci
f0951f2a25 update samples 2023-05-05 09:49:08 +08:00
hevinci
7d2defedb7 update asset bundle collector 2023-05-04 11:14:01 +08:00
何冠峰
17ab618bed Merge pull request #102 from hanazonoyurine/main
可寻址地址冲突时,打印冲突地址的资源地址
2023-05-04 10:46:44 +08:00
hanazonoyurine
0f9e932616 可寻址地址冲突时,打印冲突地址的资源地址 2023-04-27 16:30:17 +08:00
hevinci
20b0bd26ae Update CHANGELOG.md 2023-04-22 17:45:25 +08:00
hevinci
3b395861d9 Update package.json 2023-04-22 17:45:13 +08:00
hevinci
d5d1f851ab update runtime code 2023-04-22 17:37:07 +08:00
hevinci
c2e2a33af1 update samples 2023-04-22 17:23:51 +08:00
hevinci
9a729f921e update editor code
BuildParameters增加共享资源的打包规则字段
2023-04-22 17:22:59 +08:00
hevinci
1b75f4b6e9 update runtime code
UpdatePackageManifestAsync方法增加自动保存版本号参数
2023-04-22 17:20:23 +08:00
hevinci
aaab6692c3 update runtime code 2023-04-22 11:25:51 +08:00
hevinci
70fc85e456 update runtime code
增加DestroyPackage()方法
2023-04-22 11:22:28 +08:00
hevinci
29358a7b4b update runtime code 2023-04-22 10:27:56 +08:00
hevinci
b1b0563d84 update editor code
增加右键创建配置文件
2023-04-22 10:27:46 +08:00
hevinci
21b1e5bee7 Update LICENSE.md 2023-04-20 21:22:27 +08:00
hevinci
c02eeef846 update edtior code
增加home page菜单栏
2023-04-20 21:22:19 +08:00
hevinci
e84e50708b update asset bundle builder
增加对WEBGL平台加密选项的检测。
2023-04-20 17:56:21 +08:00
212 changed files with 6484 additions and 264 deletions

View File

@@ -2,6 +2,110 @@
All notable changes to this package will be documented in this file.
## [1.4.15] - 2023-06-09
### Fixed
- 修复了安卓平台,解压内置文件到沙盒失败后不再重新尝试的问题。
- 修复了验证远端下载文件,极小概率失败的问题。
- 修复了太空战机DEMO在IOS平台流解密失败的问题。
## [1.4.14] - 2023-05-26
### Fixed
- 修复了收集器对着色器未过滤的问题。
- 修复了内置着色器Tag特殊情况下未正确传染给依赖资源包的问题。
### Changed
- Unity2021版本及以上推荐使用可编程构建管线SBP
## [1.4.13] - 2023-05-12
### Changed
- 可寻址地址冲突时,打印冲突地址的资源路径。
- 销毁Package的时候清空该Package的缓存记录。
### Added
- 新增方法ResoucePackage.ClearAllCacheFilesAsync()
```c#
public class ResoucePackage
{
/// <summary>
/// 清理包裹本地所有的缓存文件
/// </summary>
public ClearAllCacheFilesOperation ClearAllCacheFilesAsync();
}
```
- 新增方法YooAssets.SetCacheSystemSandboxPath()
```c#
public class YooAssets
{
/// <summary>
/// 设置缓存系统参数,沙盒目录的存储路径
/// </summary>
public static void SetCacheSystemSandboxPath(string sandboxPath);
}
```
## [1.4.12] - 2023-04-22
### Changed
- 增加了对WEBGL平台加密选项的检测。
- 增加了YooAsset/Home Page菜单栏。
- 增加了鼠标右键创建配置的菜单。
- 增加了YooAssets.DestroyPackage()方法。
```c#
class YooAssets
{
/// <summary>
/// 销毁资源包
/// </summary>
/// <param name="package">资源包对象</param>
public static void DestroyPackage(string packageName);
}
```
- UpdatePackageManifestAsync方法增加了新参数autoSaveVersion
```c#
class ResourcePackage
{
/// <summary>
/// 向网络端请求并更新清单
/// </summary>
/// <param name="packageVersion">更新的包裹版本</param>
/// <param name="autoSaveVersion">更新成功后自动保存版本号,作为下次初始化的版本。</param>
/// <param name="timeout">超时时间默认值60秒</param>
public UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion = true, int timeout = 60)
}
```
- BuildParameters类增加了新字段。
可以自定义共享资源文件的打包规则。
```c#
class BuildParameters
{
/// <summary>
/// 共享资源的打包规则
/// </summary>
public IShareAssetPackRule ShareAssetPackRule = null;
}
```
## [1.4.11] - 2023-04-14
### Fixed

View File

@@ -94,7 +94,7 @@ namespace YooAsset.Editor
{
BuildLogger.Warning($"{buildParameters.BuildMode} pipeline build failed !");
BuildLogger.Error($"Build task failed : {buildResult.FailedTask}");
BuildLogger.Error($"Build task error : {buildResult.FailedInfo}");
BuildLogger.Error(buildResult.ErrorInfo);
}
return buildResult;

View File

@@ -3,6 +3,7 @@ using UnityEngine;
namespace YooAsset.Editor
{
[CreateAssetMenu(fileName = "AssetBundleBuilderSetting", menuName = "YooAsset/Create AssetBundle Builder Settings")]
public class AssetBundleBuilderSetting : ScriptableObject
{
/// <summary>

View File

@@ -12,7 +12,7 @@ namespace YooAsset.Editor
public class AssetBundleBuilderWindow : EditorWindow
{
[MenuItem("YooAsset/AssetBundle Builder", false, 102)]
public static void ShowExample()
public static void OpenWindow()
{
AssetBundleBuilderWindow window = GetWindow<AssetBundleBuilderWindow>("资源包构建工具", true, WindowsDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600);
@@ -275,6 +275,7 @@ namespace YooAsset.Editor
buildParameters.PackageName = AssetBundleBuilderSettingData.Setting.BuildPackage;
buildParameters.PackageVersion = _buildVersionField.value;
buildParameters.VerifyBuildingResult = true;
buildParameters.ShareAssetPackRule = new DefaultShareAssetPackRule();
buildParameters.EncryptionServices = CreateEncryptionServicesInstance();
buildParameters.CompressOption = AssetBundleBuilderSettingData.Setting.CompressOption;
buildParameters.OutputNameStyle = AssetBundleBuilderSettingData.Setting.OutputNameStyle;

View File

@@ -157,7 +157,7 @@ namespace YooAsset.Editor
/// <summary>
/// 计算共享资源包的完整包名
/// </summary>
public void CalculateShareBundleName(bool uniqueBundleName, string packageName, string shadersBundleName)
public void CalculateShareBundleName(IShareAssetPackRule packRule, bool uniqueBundleName, string packageName, string shadersBundleName)
{
if (CollectorType != ECollectorType.None)
return;
@@ -173,8 +173,7 @@ namespace YooAsset.Editor
{
if (_referenceBundleNames.Count > 1)
{
IPackRule packRule = PackDirectory.StaticPackRule;
PackRuleResult packRuleResult = packRule.GetPackRuleResult(new PackRuleData(AssetPath));
PackRuleResult packRuleResult = packRule.GetPackRuleResult(AssetPath);
BundleName = packRuleResult.GetShareBundleName(packageName, uniqueBundleName);
}
else

View File

@@ -76,9 +76,14 @@ namespace YooAsset.Editor
/// 验证构建结果
/// </summary>
public bool VerifyBuildingResult = false;
/// <summary>
/// 加密类
/// 共享资源的打包规则
/// </summary>
public IShareAssetPackRule ShareAssetPackRule = null;
/// <summary>
/// 资源的加密接口
/// </summary>
public IEncryptionServices EncryptionServices = null;

View File

@@ -19,7 +19,7 @@ namespace YooAsset.Editor
/// <summary>
/// 构建失败的信息
/// </summary>
public string FailedInfo;
public string ErrorInfo;
/// <summary>
/// 输出的补丁包目录

View File

@@ -52,7 +52,7 @@ namespace YooAsset.Editor
{
EditorTools.ClearProgressBar();
buildResult.FailedTask = task.GetType().Name;
buildResult.FailedInfo = e.ToString();
buildResult.ErrorInfo = e.ToString();
buildResult.Success = false;
break;
}

View File

@@ -205,6 +205,7 @@ namespace YooAsset.Editor
throw new Exception("没有发现着色器资源包!");
// 检测依赖交集并更新依赖ID
HashSet<string> tagTemps = new HashSet<string>();
foreach (var packageAsset in manifest.AssetList)
{
List<string> dependBundles = GetPackageAssetAllDependBundles(manifest, packageAsset);
@@ -215,8 +216,23 @@ namespace YooAsset.Editor
if (newDependIDs.Contains(shaderBundleId) == false)
newDependIDs.Add(shaderBundleId);
packageAsset.DependIDs = newDependIDs.ToArray();
foreach (var tag in packageAsset.AssetTags)
{
if (tagTemps.Contains(tag) == false)
tagTemps.Add(tag);
}
}
}
// 更新资源包标签
var packageBundle = manifest.BundleList[shaderBundleId];
List<string> newTags = new List<string>(packageBundle.Tags);
foreach (var tag in tagTemps)
{
if (newTags.Contains(tag) == false)
newTags.Add(tag);
}
packageBundle.Tags = newTags.ToArray();
}
private List<string> GetPackageAssetAllDependBundles(PackageManifest manifest, PackageAsset packageAsset)
{
@@ -302,7 +318,7 @@ namespace YooAsset.Editor
{
if (packageBundle.IsRawFile)
{
_cachedBundleDepends.Add(packageBundle.BundleName, new string[] { } );
_cachedBundleDepends.Add(packageBundle.BundleName, new string[] { });
continue;
}
@@ -321,7 +337,7 @@ namespace YooAsset.Editor
}
EditorTools.ClearProgressBar();
}
private int[] GetBundleRefrenceIDs(PackageManifest manifest, PackageBundle targetBundle)
{
List<string> referenceList = new List<string>();

View File

@@ -13,7 +13,8 @@ namespace YooAsset.Editor
void IBuildTask.Run(BuildContext context)
{
var buildParametersContext = context.GetContextObject<BuildParametersContext>();
var buildMapContext = CreateBuildMap(buildParametersContext.Parameters.BuildMode, buildParametersContext.Parameters.PackageName);
var buildParameters = buildParametersContext.Parameters;
var buildMapContext = CreateBuildMap(buildParameters.BuildMode, buildParameters.ShareAssetPackRule, buildParameters.PackageName);
context.SetContextObject(buildMapContext);
BuildLogger.Log("构建内容准备完毕!");
@@ -24,7 +25,7 @@ namespace YooAsset.Editor
/// <summary>
/// 资源构建上下文
/// </summary>
public BuildMapContext CreateBuildMap(EBuildMode buildMode, string packageName)
public BuildMapContext CreateBuildMap(EBuildMode buildMode, IShareAssetPackRule packRule, string packageName)
{
Dictionary<string, BuildAssetInfo> allBuildAssetInfoDic = new Dictionary<string, BuildAssetInfo>(1000);
@@ -101,7 +102,7 @@ namespace YooAsset.Editor
var command = collectResult.Command;
foreach (var buildAssetInfo in allBuildAssetInfoDic.Values)
{
buildAssetInfo.CalculateShareBundleName(command.UniqueBundleName, command.PackageName, command.ShadersBundleName);
buildAssetInfo.CalculateShareBundleName(packRule, command.UniqueBundleName, command.PackageName, command.ShadersBundleName);
}
// 9. 移除不参与构建的资源

View File

@@ -24,6 +24,13 @@ namespace YooAsset.Editor
if (buildParameters.BuildMode != EBuildMode.SimulateBuild)
{
#if UNITY_2021_3_OR_NEWER
if (buildParameters.BuildPipeline == EBuildPipeline.BuiltinBuildPipeline)
{
BuildLogger.Warning("推荐使用可编程构建管线SBP");
}
#endif
// 检测当前是否正在构建资源包
if (BuildPipeline.isBuildingPlayer)
throw new Exception("当前正在构建资源包,请结束后再试");
@@ -40,6 +47,20 @@ namespace YooAsset.Editor
throw new Exception("首包资源标签不能为空!");
}
// 检测共享资源打包规则
if (buildParameters.ShareAssetPackRule == null)
throw new Exception("共享资源打包规则不能为空!");
#if UNITY_WEBGL
if (buildParameters.EncryptionServices != null)
{
if (buildParameters.EncryptionServices.GetType() != typeof(EncryptionNone))
{
throw new Exception("WebGL平台不支持加密");
}
}
#endif
// 检测包裹输出目录是否存在
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
if (Directory.Exists(packageOutputDirectory))

View File

@@ -197,16 +197,17 @@ namespace YooAsset.Editor
// 检测可寻址地址是否重复
if (command.EnableAddressable)
{
HashSet<string> adressTemper = new HashSet<string>();
var addressTemper = new Dictionary<string, string>();
foreach (var collectInfoPair in result)
{
if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
{
string address = collectInfoPair.Value.Address;
if (adressTemper.Contains(address) == false)
adressTemper.Add(address);
string assetPath = collectInfoPair.Value.AssetPath;
if (addressTemper.TryGetValue(address, out var existed) == false)
addressTemper.Add(address, assetPath);
else
throw new Exception($"The address is existed : {address} in collector : {CollectPath}");
throw new Exception($"The address is existed : {address} in collector : {CollectPath} \nAssetPath:\n {existed}\n {assetPath}");
}
}
}
@@ -289,10 +290,6 @@ namespace YooAsset.Editor
}
private bool IsCollectAsset(string assetPath)
{
Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader) || assetType == typeof(UnityEngine.ShaderVariantCollection))
return true;
// 根据规则设置过滤资源文件
IFilterRule filterRuleInstance = AssetBundleCollectorSettingData.GetFilterRuleInstance(FilterRuleName);
return filterRuleInstance.IsCollectAsset(new FilterRuleData(assetPath));

View File

@@ -96,16 +96,17 @@ namespace YooAsset.Editor
// 检测可寻址地址是否重复
if (command.EnableAddressable)
{
HashSet<string> adressTemper = new HashSet<string>();
var addressTemper = new Dictionary<string, string>();
foreach (var collectInfoPair in result)
{
if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
{
string address = collectInfoPair.Value.Address;
if (adressTemper.Contains(address) == false)
adressTemper.Add(address);
string assetPath = collectInfoPair.Value.AssetPath;
if (addressTemper.TryGetValue(address, out var existed) == false)
addressTemper.Add(address, assetPath);
else
throw new Exception($"The address is existed : {address} in group : {GroupName}");
throw new Exception($"The address is existed : {address} in group : {GroupName} \nAssetPath:\n {existed}\n {assetPath}");
}
}
}

View File

@@ -76,16 +76,17 @@ namespace YooAsset.Editor
// 检测可寻址地址是否重复
if (command.EnableAddressable)
{
HashSet<string> adressTemper = new HashSet<string>();
var addressTemper = new Dictionary<string, string>();
foreach (var collectInfoPair in result)
{
if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
{
string address = collectInfoPair.Value.Address;
if (adressTemper.Contains(address) == false)
adressTemper.Add(address);
string assetPath = collectInfoPair.Value.AssetPath;
if (addressTemper.TryGetValue(address, out var existed) == false)
addressTemper.Add(address, assetPath);
else
throw new Exception($"The address is existed : {address}");
throw new Exception($"The address is existed : {address} \nAssetPath:\n {existed}\n {assetPath}");
}
}
}

View File

@@ -6,6 +6,7 @@ using UnityEngine;
namespace YooAsset.Editor
{
[CreateAssetMenu(fileName = "AssetBundleCollectorSetting", menuName = "YooAsset/Create AssetBundle Collector Settings")]
public class AssetBundleCollectorSetting : ScriptableObject
{
/// <summary>

View File

@@ -12,7 +12,7 @@ namespace YooAsset.Editor
public class AssetBundleCollectorWindow : EditorWindow
{
[MenuItem("YooAsset/AssetBundle Collector", false, 101)]
public static void ShowExample()
public static void OpenWindow()
{
AssetBundleCollectorWindow window = GetWindow<AssetBundleCollectorWindow>("资源包收集工具", true, WindowsDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600);

View File

@@ -60,8 +60,6 @@ namespace YooAsset.Editor
[DisplayName("资源包名: 父类文件夹路径")]
public class PackDirectory : IPackRule
{
public static PackDirectory StaticPackRule = new PackDirectory();
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
{
string bundleName = Path.GetDirectoryName(data.AssetPath);

View File

@@ -0,0 +1,16 @@
using System;
using System.IO;
using UnityEditor;
namespace YooAsset.Editor
{
public class DefaultShareAssetPackRule : IShareAssetPackRule
{
public PackRuleResult GetPackRuleResult(string assetPath)
{
string bundleName = Path.GetDirectoryName(assetPath);
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
return result;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7bfd05221983858429246096617dff1d
guid: 3b8606481370397489cb3aa21e726d9a
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,14 @@

namespace YooAsset.Editor
{
/// <summary>
/// 共享资源的打包规则
/// </summary>
public interface IShareAssetPackRule
{
/// <summary>
/// 获取打包规则结果
/// </summary>
PackRuleResult GetPackRuleResult(string assetPath);
}
}

View File

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

View File

@@ -13,7 +13,7 @@ namespace YooAsset.Editor
public class AssetBundleDebuggerWindow : EditorWindow
{
[MenuItem("YooAsset/AssetBundle Debugger", false, 104)]
public static void ShowExample()
public static void OpenWindow()
{
AssetBundleDebuggerWindow wnd = GetWindow<AssetBundleDebuggerWindow>("资源包调试工具", true, WindowsDefine.DockedWindowTypes);
wnd.minSize = new Vector2(800, 600);

View File

@@ -10,7 +10,7 @@ namespace YooAsset.Editor
public class AssetBundleReporterWindow : EditorWindow
{
[MenuItem("YooAsset/AssetBundle Reporter", false, 103)]
public static void ShowExample()
public static void OpenWindow()
{
AssetBundleReporterWindow window = GetWindow<AssetBundleReporterWindow>("资源包报告工具", true, WindowsDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600);

View File

@@ -0,0 +1,17 @@
#if UNITY_2019_4_OR_NEWER
using System;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
internal class HomePageWindow
{
[MenuItem("YooAsset/Home Page", false, 1)]
public static void OpenWindow()
{
Application.OpenURL("https://www.yooasset.com/");
}
}
}
#endif

View File

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

View File

@@ -2,6 +2,7 @@
namespace YooAsset.Editor
{
[CreateAssetMenu(fileName = "ShaderVariantCollectorSetting", menuName = "YooAsset/Create ShaderVariant Collector Settings")]
public class ShaderVariantCollectorSetting : ScriptableObject
{
/// <summary>

View File

@@ -12,7 +12,7 @@ namespace YooAsset.Editor
public class ShaderVariantCollectorWindow : EditorWindow
{
[MenuItem("YooAsset/ShaderVariant Collector", false, 201)]
public static void ShowExample()
public static void OpenWindow()
{
ShaderVariantCollectorWindow window = GetWindow<ShaderVariantCollectorWindow>("着色器变种收集工具", true, WindowsDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600);

View File

@@ -187,7 +187,7 @@
identification within third-party archives.
Copyright 2018-2021 何冠峰
Copyright 2021-2022 TuYoo Games
Copyright 2021-2023 TuYoo Games
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -112,8 +112,6 @@ namespace YooAsset
var retObject = assetObject as TObject;
if (retObject != null)
ret.Add(retObject);
else
YooLogger.Warning($"The type conversion failed : {assetObject.name}");
}
return ret.ToArray();
}

View File

@@ -103,13 +103,14 @@ namespace YooAsset
else
{
_steps = ESteps.LoadFile;
return; //下载完毕等待一帧再去加载!
}
}
// 3. 内置文件解压
if (_steps == ESteps.Unpack)
{
int failedTryAgain = 1;
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.GetUnpackInfo(MainBundleInfo.Bundle);
_unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_steps = ESteps.CheckUnpack;

View File

@@ -92,6 +92,7 @@ namespace YooAsset
else
{
_steps = ESteps.LoadCacheFile;
return; //下载完毕等待一帧再去加载!
}
}

View File

@@ -91,7 +91,7 @@ namespace YooAsset
// 3. 解压内置文件
if (_steps == ESteps.Unpack)
{
int failedTryAgain = 1;
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.GetUnpackInfo(MainBundleInfo.Bundle);
_unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_steps = ESteps.CheckUnpack;

View File

@@ -89,7 +89,7 @@ namespace YooAsset
// 3. 从站点下载
if (_steps == ESteps.Website)
{
int failedTryAgain = 1;
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.GetUnpackInfo(MainBundleInfo.Bundle);
_website = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_steps = ESteps.CheckWebsite;

View File

@@ -23,6 +23,15 @@ namespace YooAsset
_cachedDic.Clear();
}
/// <summary>
/// 清空指定包裹的所有缓存数据
/// </summary>
public static void ClearPackage(string packageName)
{
var cache = GetOrCreateCache(packageName);
cache.ClearAll();
}
/// <summary>
/// 获取缓存文件总数
/// </summary>
@@ -115,7 +124,7 @@ namespace YooAsset
{
return VerifyingInternal(element.TempDataFilePath, element.FileSize, element.FileCRC, EVerifyLevel.High);
}
/// <summary>
/// 验证记录文件(主线程内操作)
/// </summary>
@@ -148,6 +157,14 @@ namespace YooAsset
return result;
}
/// <summary>
/// 获取所有的缓存文件
/// </summary>
public static List<string> GetAllCacheGUIDs(ResourcePackage package)
{
var cache = GetOrCreateCache(package.PackageName);
return cache.GetAllKeys();
}
private static EVerifyResult VerifyingInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
{

View File

@@ -6,6 +6,11 @@ namespace YooAsset
/// </summary>
internal enum EVerifyResult
{
/// <summary>
/// 验证异常
/// </summary>
Exception = -7,
/// <summary>
/// 未找到缓存信息
/// </summary>
@@ -37,9 +42,9 @@ namespace YooAsset
FileCrcError = -1,
/// <summary>
/// 验证异常
/// 默认状态(校验未完成)
/// </summary>
Exception = 0,
None = 0,
/// <summary>
/// 验证成功

View File

@@ -0,0 +1,71 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace YooAsset
{
/// <summary>
/// 清理本地包裹所有的缓存文件
/// </summary>
public sealed class ClearAllCacheFilesOperation : AsyncOperationBase
{
private enum ESteps
{
None,
GetAllCacheFiles,
ClearAllCacheFiles,
Done,
}
private readonly ResourcePackage _package;
private List<string> _allCacheGUIDs;
private int _fileTotalCount = 0;
private ESteps _steps = ESteps.None;
internal ClearAllCacheFilesOperation(ResourcePackage package)
{
_package = package;
}
internal override void Start()
{
_steps = ESteps.GetAllCacheFiles;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.GetAllCacheFiles)
{
_allCacheGUIDs = CacheSystem.GetAllCacheGUIDs(_package);
_fileTotalCount = _allCacheGUIDs.Count;
YooLogger.Log($"Found all cache file count : {_fileTotalCount}");
_steps = ESteps.ClearAllCacheFiles;
}
if (_steps == ESteps.ClearAllCacheFiles)
{
for (int i = _allCacheGUIDs.Count - 1; i >= 0; i--)
{
string cacheGUID = _allCacheGUIDs[i];
CacheSystem.DiscardFile(_package.PackageName, cacheGUID);
_allCacheGUIDs.RemoveAt(i);
if (OperationSystem.IsBusy)
break;
}
if (_fileTotalCount == 0)
Progress = 1.0f;
else
Progress = 1.0f - (_allCacheGUIDs.Count / _fileTotalCount);
if (_allCacheGUIDs.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
}
}

View File

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

View File

@@ -45,7 +45,7 @@ namespace YooAsset
{
// BundleFiles
{
string rootPath = PersistentHelper.GetCachedBundleFileFolderPath(_packageName);
string rootPath = PersistentTools.GetCachedBundleFileFolderPath(_packageName);
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists)
{
@@ -56,7 +56,7 @@ namespace YooAsset
// RawFiles
{
string rootPath = PersistentHelper.GetCachedRawFileFolderPath(_packageName);
string rootPath = PersistentTools.GetCachedRawFileFolderPath(_packageName);
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists)
{

View File

@@ -60,11 +60,12 @@ namespace YooAsset
if (_steps == ESteps.Waiting)
{
if (_element.IsDone == false)
int result = _element.Result;
if (result == 0)
return;
VerifyResult = _element.Result;
if (_element.Result == EVerifyResult.Succeed)
VerifyResult = (EVerifyResult)result;
if (VerifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
@@ -73,7 +74,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {_element.Result}";
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {VerifyResult}";
}
}
}
@@ -85,8 +86,8 @@ namespace YooAsset
private void VerifyInThread(object obj)
{
VerifyTempElement element = (VerifyTempElement)obj;
element.Result = CacheSystem.VerifyingTempFile(element);
element.IsDone = true;
int result = (int)CacheSystem.VerifyingTempFile(element);
element.Result = result;
}
}
@@ -120,11 +121,10 @@ namespace YooAsset
if (_steps == ESteps.VerifyFile)
{
_element.Result = CacheSystem.VerifyingTempFile(_element);
_element.IsDone = true;
_element.Result = (int)CacheSystem.VerifyingTempFile(_element);
VerifyResult = _element.Result;
if (_element.Result == EVerifyResult.Succeed)
VerifyResult = (EVerifyResult)_element.Result;
if (VerifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
@@ -133,7 +133,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {_element.Result}";
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {VerifyResult}";
}
}
}

View File

@@ -3,14 +3,59 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 资源路径帮助类
/// </summary>
internal static class PathHelper
internal static class PersistentTools
{
private const string CacheFolderName = "CacheFiles";
private const string CachedBundleFileFolder = "BundleFiles";
private const string CachedRawFileFolder = "RawFiles";
private const string ManifestFolderName = "ManifestFiles";
private const string AppFootPrintFileName = "ApplicationFootPrint.bytes";
private static string _buildinPath;
private static string _sandboxPath;
/// <summary>
/// 重写沙盒跟路径
/// </summary>
public static void OverwriteSandboxPath(string sandboxPath)
{
_sandboxPath = sandboxPath;
}
/// <summary>
/// 获取沙盒文件夹路径
/// </summary>
public static string GetPersistentRootPath()
{
#if UNITY_EDITOR
// 注意:为了方便调试查看,编辑器下把存储目录放到项目里
if (string.IsNullOrEmpty(_sandboxPath))
{
string directory = Path.GetDirectoryName(UnityEngine.Application.dataPath);
string projectPath = GetRegularPath(directory);
_sandboxPath = StringUtility.Format("{0}/Sandbox", projectPath);
}
#elif UNITY_STANDALONE
if (string.IsNullOrEmpty(_sandboxPath))
{
_sandboxPath = StringUtility.Format("{0}/Sandbox", UnityEngine.Application.dataPath);
}
#else
if (string.IsNullOrEmpty(_sandboxPath))
{
_sandboxPath = StringUtility.Format("{0}/Sandbox", UnityEngine.Application.persistentDataPath);
}
#endif
return _sandboxPath;
}
private static string GetRegularPath(string path)
{
return path.Replace('\\', '/').Replace("\\", "/"); //替换为Linux路径格式
}
/// <summary>
/// 获取基于流文件夹的加载路径
/// </summary>
@@ -32,33 +77,6 @@ namespace YooAsset
return StringUtility.Format("{0}/{1}", root, path);
}
/// <summary>
/// 获取沙盒文件夹路径
/// </summary>
public static string GetPersistentRootPath()
{
#if UNITY_EDITOR
// 注意:为了方便调试查看,编辑器下把存储目录放到项目里
if (string.IsNullOrEmpty(_sandboxPath))
{
string directory = Path.GetDirectoryName(UnityEngine.Application.dataPath);
string projectPath = GetRegularPath(directory);
_sandboxPath = StringUtility.Format("{0}/Sandbox", projectPath);
}
return _sandboxPath;
#else
if (string.IsNullOrEmpty(_sandboxPath))
{
_sandboxPath = StringUtility.Format("{0}/Sandbox", UnityEngine.Application.persistentDataPath);
}
return _sandboxPath;
#endif
}
private static string GetRegularPath(string path)
{
return path.Replace('\\', '/').Replace("\\", "/"); //替换为Linux路径格式
}
/// <summary>
/// 获取WWW加载本地资源的路径
/// </summary>
@@ -76,18 +94,6 @@ namespace YooAsset
return path;
#endif
}
}
/// <summary>
/// 持久化目录帮助类
/// </summary>
internal static class PersistentHelper
{
private const string CacheFolderName = "CacheFiles";
private const string CachedBundleFileFolder = "BundleFiles";
private const string CachedRawFileFolder = "RawFiles";
private const string ManifestFolderName = "ManifestFiles";
private const string AppFootPrintFileName = "ApplicationFootPrint.bytes";
/// <summary>
@@ -95,7 +101,7 @@ namespace YooAsset
/// </summary>
public static void DeleteSandbox()
{
string directoryPath = PathHelper.MakePersistentLoadPath(string.Empty);
string directoryPath = MakePersistentLoadPath(string.Empty);
if (Directory.Exists(directoryPath))
Directory.Delete(directoryPath, true);
}
@@ -105,7 +111,7 @@ namespace YooAsset
/// </summary>
public static void DeleteCacheFolder()
{
string root = PathHelper.MakePersistentLoadPath(CacheFolderName);
string root = MakePersistentLoadPath(CacheFolderName);
if (Directory.Exists(root))
Directory.Delete(root, true);
}
@@ -115,7 +121,7 @@ namespace YooAsset
/// </summary>
public static void DeleteManifestFolder()
{
string root = PathHelper.MakePersistentLoadPath(ManifestFolderName);
string root = MakePersistentLoadPath(ManifestFolderName);
if (Directory.Exists(root))
Directory.Delete(root, true);
}
@@ -129,7 +135,7 @@ namespace YooAsset
{
if (_cachedBundleFileFolder.TryGetValue(packageName, out string value) == false)
{
string root = PathHelper.MakePersistentLoadPath(CacheFolderName);
string root = MakePersistentLoadPath(CacheFolderName);
value = $"{root}/{packageName}/{CachedBundleFileFolder}";
_cachedBundleFileFolder.Add(packageName, value);
}
@@ -144,7 +150,7 @@ namespace YooAsset
{
if (_cachedRawFileFolder.TryGetValue(packageName, out string value) == false)
{
string root = PathHelper.MakePersistentLoadPath(CacheFolderName);
string root = MakePersistentLoadPath(CacheFolderName);
value = $"{root}/{packageName}/{CachedRawFileFolder}";
_cachedRawFileFolder.Add(packageName, value);
}
@@ -156,7 +162,7 @@ namespace YooAsset
/// </summary>
public static string GetAppFootPrintFilePath()
{
return PathHelper.MakePersistentLoadPath(AppFootPrintFileName);
return MakePersistentLoadPath(AppFootPrintFileName);
}
/// <summary>
@@ -165,7 +171,7 @@ namespace YooAsset
public static string GetCacheManifestFilePath(string packageName, string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion);
return PathHelper.MakePersistentLoadPath($"{ManifestFolderName}/{fileName}");
return MakePersistentLoadPath($"{ManifestFolderName}/{fileName}");
}
/// <summary>
@@ -174,7 +180,7 @@ namespace YooAsset
public static string GetCachePackageHashFilePath(string packageName, string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(packageName, packageVersion);
return PathHelper.MakePersistentLoadPath($"{ManifestFolderName}/{fileName}");
return MakePersistentLoadPath($"{ManifestFolderName}/{fileName}");
}
/// <summary>
@@ -183,7 +189,7 @@ namespace YooAsset
public static string GetCachePackageVersionFilePath(string packageName)
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(packageName);
return PathHelper.MakePersistentLoadPath($"{ManifestFolderName}/{fileName}");
return MakePersistentLoadPath($"{ManifestFolderName}/{fileName}");
}
/// <summary>

View File

@@ -49,8 +49,7 @@ namespace YooAsset
public string FileCRC { private set; get; }
public long FileSize { private set; get; }
public bool IsDone = false;
public EVerifyResult Result;
public int Result = 0; // 注意:原子操作对象
public VerifyTempElement(string tempDataFilePath, string fileCRC, long fileSize)
{

View File

@@ -193,7 +193,7 @@ namespace YooAsset
public static BundleInfo GetUnpackInfo(PackageBundle packageBundle)
{
// 注意:我们把流加载路径指定为远端下载地址
string streamingPath = PathHelper.ConvertToWWWPath(packageBundle.StreamingFilePath);
string streamingPath = PersistentTools.ConvertToWWWPath(packageBundle.StreamingFilePath);
BundleInfo bundleInfo = new BundleInfo(packageBundle, BundleInfo.ELoadMode.LoadFromStreaming, streamingPath, streamingPath);
return bundleInfo;
}

View File

@@ -222,7 +222,7 @@ namespace YooAsset
// 如果水印发生变化,则说明覆盖安装后首次打开游戏
if (appFootPrint.IsDirty())
{
PersistentHelper.DeleteManifestFolder();
PersistentTools.DeleteManifestFolder();
appFootPrint.Coverage();
YooLogger.Log("Delete manifest files when application foot print dirty !");
}
@@ -376,7 +376,7 @@ namespace YooAsset
/// </summary>
public void Load()
{
string footPrintFilePath = PersistentHelper.GetAppFootPrintFilePath();
string footPrintFilePath = PersistentTools.GetAppFootPrintFilePath();
if (File.Exists(footPrintFilePath))
{
_footPrint = FileUtility.ReadAllText(footPrintFilePath);
@@ -409,7 +409,7 @@ namespace YooAsset
#else
_footPrint = Application.buildGUID;
#endif
string footPrintFilePath = PersistentHelper.GetAppFootPrintFilePath();
string footPrintFilePath = PersistentTools.GetAppFootPrintFilePath();
FileUtility.CreateFile(footPrintFilePath, _footPrint);
YooLogger.Log($"Save application foot print : {_footPrint}");
}

View File

@@ -41,7 +41,7 @@ namespace YooAsset
{
if (_downloader1 == null)
{
string savePath = PersistentHelper.GetCachePackageHashFilePath(_packageName, _packageVersion);
string savePath = PersistentTools.GetCachePackageHashFilePath(_packageName, _packageVersion);
string fileName = YooAssetSettingsData.GetPackageHashFileName(_packageName, _packageVersion);
string webURL = GetDownloadRequestURL(fileName);
YooLogger.Log($"Beginning to download package hash file : {webURL}");
@@ -71,7 +71,7 @@ namespace YooAsset
{
if (_downloader2 == null)
{
string savePath = PersistentHelper.GetCacheManifestFilePath(_packageName, _packageVersion);
string savePath = PersistentTools.GetCacheManifestFilePath(_packageName, _packageVersion);
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_packageName, _packageVersion);
string webURL = GetDownloadRequestURL(fileName);
YooLogger.Log($"Beginning to download manifest file : {webURL}");

View File

@@ -42,8 +42,8 @@ namespace YooAsset
if (_downloader == null)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_buildinPackageName, _buildinPackageVersion);
string filePath = PathHelper.MakeStreamingLoadPath(fileName);
string url = PathHelper.ConvertToWWWPath(filePath);
string filePath = PersistentTools.MakeStreamingLoadPath(fileName);
string url = PersistentTools.ConvertToWWWPath(filePath);
_downloader = new UnityWebDataRequester();
_downloader.SendRequest(url);
}

View File

@@ -67,7 +67,7 @@ namespace YooAsset
if (_steps == ESteps.VerifyFileHash)
{
_manifestFilePath = PersistentHelper.GetCacheManifestFilePath(_packageName, _packageVersion);
_manifestFilePath = PersistentTools.GetCacheManifestFilePath(_packageName, _packageVersion);
if (File.Exists(_manifestFilePath) == false)
{
_steps = ESteps.Done;
@@ -131,7 +131,7 @@ namespace YooAsset
File.Delete(_manifestFilePath);
}
string hashFilePath = PersistentHelper.GetCachePackageHashFilePath(_packageName, _packageVersion);
string hashFilePath = PersistentTools.GetCachePackageHashFilePath(_packageName, _packageVersion);
if (File.Exists(hashFilePath))
{
File.Delete(hashFilePath);

View File

@@ -38,8 +38,8 @@ namespace YooAsset
if (_downloader == null)
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_packageName);
string filePath = PathHelper.MakeStreamingLoadPath(fileName);
string url = PathHelper.ConvertToWWWPath(filePath);
string filePath = PersistentTools.MakeStreamingLoadPath(fileName);
string url = PersistentTools.ConvertToWWWPath(filePath);
_downloader = new UnityWebDataRequester();
_downloader.SendRequest(url);
}

View File

@@ -37,7 +37,7 @@ namespace YooAsset
if (_steps == ESteps.LoadCachePackageHashFile)
{
string filePath = PersistentHelper.GetCachePackageHashFilePath(_packageName, _packageVersion);
string filePath = PersistentTools.GetCachePackageHashFilePath(_packageName, _packageVersion);
if (File.Exists(filePath) == false)
{
_steps = ESteps.Done;

View File

@@ -35,7 +35,7 @@ namespace YooAsset
if (_steps == ESteps.LoadCachePackageVersionFile)
{
string filePath = PersistentHelper.GetCachePackageVersionFilePath(_packageName);
string filePath = PersistentTools.GetCachePackageVersionFilePath(_packageName);
if (File.Exists(filePath) == false)
{
_steps = ESteps.Done;

View File

@@ -35,10 +35,10 @@ namespace YooAsset
{
if (_downloader1 == null)
{
string savePath = PersistentHelper.GetCachePackageHashFilePath(_buildinPackageName, _buildinPackageVersion);
string savePath = PersistentTools.GetCachePackageHashFilePath(_buildinPackageName, _buildinPackageVersion);
string fileName = YooAssetSettingsData.GetPackageHashFileName(_buildinPackageName, _buildinPackageVersion);
string filePath = PathHelper.MakeStreamingLoadPath(fileName);
string url = PathHelper.ConvertToWWWPath(filePath);
string filePath = PersistentTools.MakeStreamingLoadPath(fileName);
string url = PersistentTools.ConvertToWWWPath(filePath);
_downloader1 = new UnityWebFileRequester();
_downloader1.SendRequest(url, savePath);
}
@@ -64,10 +64,10 @@ namespace YooAsset
{
if (_downloader2 == null)
{
string savePath = PersistentHelper.GetCacheManifestFilePath(_buildinPackageName, _buildinPackageVersion);
string savePath = PersistentTools.GetCacheManifestFilePath(_buildinPackageName, _buildinPackageVersion);
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_buildinPackageName, _buildinPackageVersion);
string filePath = PathHelper.MakeStreamingLoadPath(fileName);
string url = PathHelper.ConvertToWWWPath(filePath);
string filePath = PersistentTools.MakeStreamingLoadPath(fileName);
string url = PersistentTools.ConvertToWWWPath(filePath);
_downloader2 = new UnityWebFileRequester();
_downloader2.SendRequest(url, savePath);
}

View File

@@ -69,6 +69,7 @@ namespace YooAsset
private readonly HostPlayModeImpl _impl;
private readonly string _packageName;
private readonly string _packageVersion;
private readonly bool _autoSaveVersion;
private readonly int _timeout;
private LoadCacheManifestOperation _tryLoadCacheManifestOp;
private LoadCacheManifestOperation _loadCacheManifestOp;
@@ -76,11 +77,12 @@ namespace YooAsset
private ESteps _steps = ESteps.None;
internal HostPlayModeUpdatePackageManifestOperation(HostPlayModeImpl impl, string packageName, string packageVersion, int timeout)
internal HostPlayModeUpdatePackageManifestOperation(HostPlayModeImpl impl, string packageName, string packageVersion, bool autoSaveVersion, int timeout)
{
_impl = impl;
_packageName = packageName;
_packageVersion = packageVersion;
_autoSaveVersion = autoSaveVersion;
_timeout = timeout;
}
internal override void Start()
@@ -120,6 +122,8 @@ namespace YooAsset
if (_tryLoadCacheManifestOp.Status == EOperationStatus.Succeed)
{
_impl.ActiveManifest = _tryLoadCacheManifestOp.Manifest;
if (_autoSaveVersion)
SavePackageVersion();
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
@@ -166,6 +170,8 @@ namespace YooAsset
if (_loadCacheManifestOp.Status == EOperationStatus.Succeed)
{
_impl.ActiveManifest = _loadCacheManifestOp.Manifest;
if (_autoSaveVersion)
SavePackageVersion();
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}

View File

@@ -74,12 +74,12 @@ namespace YooAsset
string folderName = FileHash.Substring(0, 2);
if (IsRawFile)
{
string cacheRoot = PersistentHelper.GetCachedRawFileFolderPath(PackageName);
string cacheRoot = PersistentTools.GetCachedRawFileFolderPath(PackageName);
_cachedDataFilePath = $"{cacheRoot}/{folderName}/{CacheGUID}/{YooAssetSettings.CacheBundleDataFileName}{_fileExtension}";
}
else
{
string cacheRoot = PersistentHelper.GetCachedBundleFileFolderPath(PackageName);
string cacheRoot = PersistentTools.GetCachedBundleFileFolderPath(PackageName);
_cachedDataFilePath = $"{cacheRoot}/{folderName}/{CacheGUID}/{YooAssetSettings.CacheBundleDataFileName}";
}
return _cachedDataFilePath;
@@ -100,12 +100,12 @@ namespace YooAsset
string folderName = FileHash.Substring(0, 2);
if (IsRawFile)
{
string cacheRoot = PersistentHelper.GetCachedRawFileFolderPath(PackageName);
string cacheRoot = PersistentTools.GetCachedRawFileFolderPath(PackageName);
_cachedInfoFilePath = $"{cacheRoot}/{folderName}/{CacheGUID}/{YooAssetSettings.CacheBundleInfoFileName}";
}
else
{
string cacheRoot = PersistentHelper.GetCachedBundleFileFolderPath(PackageName);
string cacheRoot = PersistentTools.GetCachedBundleFileFolderPath(PackageName);
_cachedInfoFilePath = $"{cacheRoot}/{folderName}/{CacheGUID}/{YooAssetSettings.CacheBundleInfoFileName}";
}
return _cachedInfoFilePath;
@@ -139,7 +139,7 @@ namespace YooAsset
if (string.IsNullOrEmpty(_streamingFilePath) == false)
return _streamingFilePath;
_streamingFilePath = PathHelper.MakeStreamingLoadPath(FileName);
_streamingFilePath = PersistentTools.MakeStreamingLoadPath(FileName);
return _streamingFilePath;
}
}

View File

@@ -43,7 +43,7 @@ namespace YooAsset
OperationSystem.StartOperation(operation);
return operation;
}
UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, int timeout)
UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion, int timeout)
{
var operation = new EditorPlayModeUpdatePackageManifestOperation();
OperationSystem.StartOperation(operation);

View File

@@ -93,7 +93,7 @@ namespace YooAsset
public void FlushManifestVersionFile()
{
if (_activeManifest != null)
PersistentHelper.SaveCachePackageVersionFile(_packageName, _activeManifest.PackageVersion);
PersistentTools.SaveCachePackageVersionFile(_packageName, _activeManifest.PackageVersion);
}
private bool IsBuildinPackageBundle(PackageBundle packageBundle)
@@ -111,9 +111,9 @@ namespace YooAsset
OperationSystem.StartOperation(operation);
return operation;
}
UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, int timeout)
UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion, int timeout)
{
var operation = new HostPlayModeUpdatePackageManifestOperation(this, _packageName, packageVersion, timeout);
var operation = new HostPlayModeUpdatePackageManifestOperation(this, _packageName, packageVersion, autoSaveVersion, timeout);
OperationSystem.StartOperation(operation);
return operation;
}

View File

@@ -43,7 +43,7 @@ namespace YooAsset
OperationSystem.StartOperation(operation);
return operation;
}
UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, int timeout)
UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion, int timeout)
{
var operation = new OfflinePlayModeUpdatePackageManifestOperation();
OperationSystem.StartOperation(operation);

View File

@@ -220,13 +220,13 @@ namespace YooAsset
/// 向网络端请求并更新清单
/// </summary>
/// <param name="packageVersion">更新的包裹版本</param>
/// <param name="autoActiveManifest">自动激活清单</param>
/// <param name="autoSaveVersion">更新成功后自动保存版本号,作为下次初始化的版本。</param>
/// <param name="timeout">超时时间默认值60秒</param>
public UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, int timeout = 60)
public UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion = true, int timeout = 60)
{
DebugCheckInitialize();
DebugCheckUpdateManifest();
return _playModeServices.UpdatePackageManifestAsync(packageVersion, timeout);
return _playModeServices.UpdatePackageManifestAsync(packageVersion, autoSaveVersion, timeout);
}
/// <summary>
@@ -251,6 +251,17 @@ namespace YooAsset
return operation;
}
/// <summary>
/// 清理包裹本地所有的缓存文件
/// </summary>
public ClearAllCacheFilesOperation ClearAllCacheFilesAsync()
{
DebugCheckInitialize();
var operation = new ClearAllCacheFilesOperation(this);
OperationSystem.StartOperation(operation);
return operation;
}
/// <summary>
/// 获取本地包裹的版本信息
/// </summary>

View File

@@ -1,6 +1,6 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("YooAsset.Editor")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor")]
[assembly: InternalsVisibleTo("YooAsset.EditorExtension")]
[assembly: InternalsVisibleTo("YooAsset.RuntimeExtension")]
[assembly: InternalsVisibleTo("YooAsset.RuntimeExtension")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor")]

View File

@@ -21,7 +21,7 @@ namespace YooAsset
/// <summary>
/// 向网络端请求并更新清单
/// </summary>
UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, int timeout);
UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion, int timeout);
/// <summary>
/// 预下载指定版本的包裹内容

View File

@@ -2,7 +2,7 @@
namespace YooAsset
{
[CreateAssetMenu(fileName = "YooAssetSettings", menuName = "YooAsset/Create Settings")]
[CreateAssetMenu(fileName = "YooAssetSettings", menuName = "YooAsset/Create YooAsset Settings")]
internal class YooAssetSettings : ScriptableObject
{
/// <summary>

View File

@@ -19,7 +19,10 @@ namespace YooAsset
public static void Initialize(ILogger logger = null)
{
if (_isInitialize)
throw new Exception($"{nameof(YooAssets)} is initialized !");
{
UnityEngine.Debug.LogWarning($"{nameof(YooAssets)} is initialized !");
return;
}
if (_isInitialize == false)
{
@@ -99,6 +102,7 @@ namespace YooAsset
if (HasPackage(packageName))
throw new Exception($"Package {packageName} already existed !");
YooLogger.Log($"Create resource package : {packageName}");
ResourcePackage package = new ResourcePackage(packageName);
_packages.Add(package);
return package;
@@ -112,7 +116,7 @@ namespace YooAsset
{
var package = TryGetPackage(packageName);
if (package == null)
YooLogger.Error($"Not found assets package : {packageName}");
YooLogger.Error($"Not found resource package : {packageName}");
return package;
}
@@ -136,6 +140,24 @@ namespace YooAsset
return null;
}
/// <summary>
/// 销毁资源包
/// </summary>
/// <param name="packageName">资源包名称</param>
public static void DestroyPackage(string packageName)
{
ResourcePackage package = GetPackage(packageName);
if (package == null)
return;
YooLogger.Log($"Destroy resource package : {packageName}");
_packages.Remove(package);
package.DestroyPackage();
// 清空缓存
CacheSystem.ClearPackage(packageName);
}
/// <summary>
/// 检测资源包是否存在
/// </summary>
@@ -215,6 +237,27 @@ namespace YooAsset
{
CacheSystem.InitVerifyLevel = verifyLevel;
}
/// <summary>
/// 设置缓存系统参数,沙盒目录的存储路径
/// </summary>
public static void SetCacheSystemSandboxPath(string sandboxPath)
{
if (string.IsNullOrEmpty(sandboxPath))
{
YooLogger.Error($"Sandbox path is null or empty !");
return;
}
// 注意:需要确保没有任何资源系统起效之前才可以设置沙盒目录!
if (_packages.Count > 0)
{
YooLogger.Error($"Please call this method {nameof(SetCacheSystemSandboxPath)} before the package is created !");
return;
}
PersistentTools.OverwriteSandboxPath(sandboxPath);
}
#endregion
#region
@@ -231,15 +274,16 @@ namespace YooAsset
/// </summary>
public static string GetSandboxRoot()
{
return PathHelper.GetPersistentRootPath();
return PersistentTools.GetPersistentRootPath();
}
/// <summary>
/// 清空沙盒目录
/// 清空沙盒目录需要重启APP
/// </summary>
public static void ClearSandbox()
{
PersistentHelper.DeleteSandbox();
YooLogger.Warning("Clear sandbox folder files, Finally, restart the application !");
PersistentTools.DeleteSandbox();
}
#endregion

View File

@@ -47,20 +47,6 @@ public class FileStreamEncryption : IEncryptionServices
return result;
}
// LoadFromFileOffset
if (fileInfo.BundleName.Contains("_gameres_uiimage"))
{
var fileData = File.ReadAllBytes(fileInfo.FilePath);
int offset = 32;
var temper = new byte[fileData.Length + offset];
Buffer.BlockCopy(fileData, 0, temper, offset, fileData.Length);
EncryptResult result = new EncryptResult();
result.LoadMethod = EBundleLoadMethod.LoadFromFileOffset;
result.EncryptedData = temper;
return result;
}
// Normal
{
EncryptResult result = new EncryptResult();

View File

@@ -8,7 +8,7 @@ public class BundleStream : FileStream
{
public const byte KEY = 64;
public BundleStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync) : base(path, mode, access, share, bufferSize, useAsync)
public BundleStream(string path, FileMode mode, FileAccess access, FileShare share) : base(path, mode, access, share)
{
}
public BundleStream(string path, FileMode mode) : base(path, mode)

View File

@@ -74,7 +74,7 @@ internal class FsmInitialize : IStateNode
}
yield return initializationOperation;
if (package.InitializeStatus == EOperationStatus.Succeed)
if (initializationOperation.Status == EOperationStatus.Succeed)
{
_machine.ChangeState<FsmUpdateVersion>();
}
@@ -144,7 +144,7 @@ internal class FsmInitialize : IStateNode
public Stream LoadFromStream(DecryptFileInfo fileInfo)
{
BundleStream bundleStream = new BundleStream(fileInfo.FilePath, FileMode.Open);
BundleStream bundleStream = new BundleStream(fileInfo.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
return bundleStream;
}

View File

@@ -32,13 +32,13 @@ public class FsmUpdateManifest : IStateNode
{
yield return new WaitForSecondsRealtime(0.5f);
bool savePackageVersion = true;
var package = YooAssets.GetPackage("DefaultPackage");
var operation = package.UpdatePackageManifestAsync(PatchManager.Instance.PackageVersion);
var operation = package.UpdatePackageManifestAsync(PatchManager.Instance.PackageVersion, savePackageVersion);
yield return operation;
if(operation.Status == EOperationStatus.Succeed)
{
operation.SavePackageVersion();
_machine.ChangeState<FsmCreateDownloader>();
}
else

View File

@@ -1,57 +0,0 @@
//-------------------------------------
// 作者Stark
//-------------------------------------
using System.Collections.Generic;
using UnityEngine;
public sealed class StreamingAssetsHelper
{
private static readonly Dictionary<string, bool> _cacheData = new Dictionary<string, bool>(1000);
#if UNITY_ANDROID && !UNITY_EDITOR
private static AndroidJavaClass _unityPlayerClass;
public static AndroidJavaClass UnityPlayerClass
{
get
{
if (_unityPlayerClass == null)
_unityPlayerClass = new UnityEngine.AndroidJavaClass("com.unity3d.player.UnityPlayer");
return _unityPlayerClass;
}
}
private static AndroidJavaObject _currentActivity;
public static AndroidJavaObject CurrentActivity
{
get
{
if (_currentActivity == null)
_currentActivity = UnityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
return _currentActivity;
}
}
/// <summary>
/// 利用安卓原生接口查询内置文件是否存在
/// </summary>
public static bool FileExists(string filePath)
{
if (_cacheData.TryGetValue(filePath, out bool result) == false)
{
result = CurrentActivity.Call<bool>("CheckAssetExist", filePath);
_cacheData.Add(filePath, result);
}
return result;
}
#else
public static bool FileExists(string filePath)
{
if (_cacheData.TryGetValue(filePath, out bool result) == false)
{
result = System.IO.File.Exists(System.IO.Path.Combine(Application.streamingAssetsPath, filePath));
_cacheData.Add(filePath, result);
}
return result;
}
#endif
}

View File

@@ -1,8 +1,66 @@
//-------------------------------------
// 作者Stark
//-------------------------------------
using System.Collections.Generic;
using UnityEngine;
#if UNITY_ANDROID
/// <summary>
/// StreamingAssets目录下资源查询帮助类
/// </summary>
public sealed class StreamingAssetsHelper
{
private static readonly Dictionary<string, bool> _cacheData = new Dictionary<string, bool>(1000);
#if UNITY_ANDROID && !UNITY_EDITOR
private static AndroidJavaClass _unityPlayerClass;
public static AndroidJavaClass UnityPlayerClass
{
get
{
if (_unityPlayerClass == null)
_unityPlayerClass = new UnityEngine.AndroidJavaClass("com.unity3d.player.UnityPlayer");
return _unityPlayerClass;
}
}
private static AndroidJavaObject _currentActivity;
public static AndroidJavaObject CurrentActivity
{
get
{
if (_currentActivity == null)
_currentActivity = UnityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
return _currentActivity;
}
}
/// <summary>
/// 利用安卓原生接口查询内置文件是否存在
/// </summary>
public static bool FileExists(string filePath)
{
if (_cacheData.TryGetValue(filePath, out bool result) == false)
{
result = CurrentActivity.Call<bool>("CheckAssetExist", filePath);
_cacheData.Add(filePath, result);
}
return result;
}
#else
public static bool FileExists(string filePath)
{
if (_cacheData.TryGetValue(filePath, out bool result) == false)
{
result = System.IO.File.Exists(System.IO.Path.Combine(Application.streamingAssetsPath, filePath));
_cacheData.Add(filePath, result);
}
return result;
}
#endif
}
#if UNITY_ANDROID && UNITY_EDITOR
/// <summary>
/// 为Github对开发者的友好采用自动补充UnityPlayerActivity.java文件的通用姿势满足各个开发者
/// </summary>
@@ -30,7 +88,6 @@ internal class AndroidPost : UnityEditor.Android.IPostGenerateGradleAndroidProje
" } \n" +
" catch(java.io.IOException e) \n" +
" { \n" +
" e.printStackTrace(); \n" +
" } \n" +
" return false; \n" +
" } \n" +
@@ -70,7 +127,7 @@ public boolean CheckAssetExist(String filePath)
}
catch(java.io.IOException e)
{
e.printStackTrace();
//e.printStackTrace();
}
return false;
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 4b1fa97e8bb8c5c46ad030b9554e1b5c
guid: 22c4a6746deb208479f4b7a040eed7f3
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,5 @@
# UniFramework.Animation
一个轻量级的高效率的动画系统。
支持新的动画文件格式不再依赖Animator文件来驱动动画使用方式非常类似于老的Animation系统。

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6a7da62cb3785ef45b2dda8fa0b3c8e5
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b19a7385dee2d0141901167dbfda9300
guid: 8664294e17a47c14c8d12545da2349a1
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,106 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
namespace UniFramework.Animation
{
internal sealed class AnimClip : AnimNode
{
public readonly string Name;
private readonly AnimationClip _clip;
public AnimationClipPlayable _clipPlayable;
/// <summary>
/// 动画层级
/// </summary>
public int Layer = 0;
/// <summary>
/// 动画长度
/// </summary>
public float ClipLength
{
get
{
if (_clip == null)
return 0f;
if (Speed == 0f)
return Mathf.Infinity;
return _clip.length / Speed;
}
}
/// <summary>
/// 归一化时间轴
/// </summary>
public float NormalizedTime
{
set
{
if (_clip == null)
return;
Time = _clip.length * value;
}
get
{
if (_clip == null)
return 1f;
return Time / _clip.length;
}
}
/// <summary>
/// 动画模式
/// </summary>
public WrapMode WrapMode
{
set
{
if (_clip != null)
_clip.wrapMode = value;
}
get
{
if (_clip == null)
return WrapMode.Default;
return _clip.wrapMode;
}
}
/// <summary>
/// 动画状态
/// </summary>
public AnimState State { private set; get; }
public AnimClip(PlayableGraph graph, AnimationClip clip, string name, int layer) : base(graph)
{
_clip = clip;
Name = name;
Layer = layer;
_clipPlayable = AnimationClipPlayable.Create(graph, clip);
_clipPlayable.SetApplyFootIK(false);
_clipPlayable.SetApplyPlayableIK(false);
SetSourcePlayable(_clipPlayable);
if (clip.wrapMode == WrapMode.Once)
{
_clipPlayable.SetDuration(clip.length);
}
State = new AnimState(this);
}
public override void PlayNode()
{
if (_clip.wrapMode == WrapMode.Once || _clip.wrapMode == WrapMode.ClampForever)
{
Time = 0;
}
base.PlayNode();
}
}
}

View File

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

View File

@@ -0,0 +1,196 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
namespace UniFramework.Animation
{
internal sealed class AnimMixer : AnimNode
{
private const float HIDE_DURATION = 0.25f;
private readonly List<AnimClip> _animClips = new List<AnimClip>(10);
private AnimationMixerPlayable _mixer;
private bool _isQuiting = false;
/// <summary>
/// 动画层级
/// </summary>
public int Layer { private set; get; }
public AnimMixer(PlayableGraph graph, int layer) : base(graph)
{
Layer = layer;
_mixer = AnimationMixerPlayable.Create(graph);
SetSourcePlayable(_mixer);
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip != null)
animClip.Update(deltaTime);
}
bool isAllDone = true;
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip != null)
{
if (animClip.IsDone == false)
isAllDone = false;
}
}
// 当子节点都已经完成的时候断开连接
if (isAllDone && _isQuiting == false)
{
_isQuiting = true;
StartWeightFade(0, HIDE_DURATION);
}
if (_isQuiting)
{
if (Mathf.Approximately(Weight, 0f))
DisconnectMixer();
}
}
/// <summary>
/// 播放指定动画
/// </summary>
public void Play(AnimClip newAnimClip, float fadeDuration)
{
// 重新激活混合器
_isQuiting = false;
StartWeightFade(1f, 0);
if (IsContains(newAnimClip) == false)
{
// 优先插入到一个空位
int index = _animClips.FindIndex(s => s == null);
if (index == -1)
{
// Increase input count
int inputCount = _mixer.GetInputCount();
_mixer.SetInputCount(inputCount + 1);
newAnimClip.Connect(_mixer, inputCount);
_animClips.Add(newAnimClip);
}
else
{
newAnimClip.Connect(_mixer, index);
_animClips[index] = newAnimClip;
}
}
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip == null)
continue;
if (animClip == newAnimClip)
{
animClip.StartWeightFade(1f, fadeDuration);
animClip.PlayNode();
}
else
{
animClip.StartWeightFade(0f, fadeDuration);
animClip.PauseNode();
}
}
}
/// <summary>
/// 停止指定动画,恢复为初始状态
/// </summary>
public void Stop(string name)
{
AnimClip animClip = FindClip(name);
if (animClip == null)
return;
animClip.PauseNode();
animClip.ResetNode();
}
/// <summary>
/// 暂停所有动画
/// </summary>
public void PauseAll()
{
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip == null)
continue;
animClip.PauseNode();
}
}
/// <summary>
/// 是否包含该动画
/// </summary>
public bool IsContains(AnimClip clip)
{
foreach (var animClip in _animClips)
{
if (animClip == clip)
return true;
}
return false;
}
/// <summary>
/// 移除一个动画
/// </summary>
public void RemoveClip(string name)
{
var animClip = FindClip(name);
if (animClip == null)
return;
_animClips[animClip.InputPort] = null;
animClip.Destroy();
}
/// <summary>
/// 获取指定的动画
/// </summary>
/// <returns>如果没有返回NULL</returns>
private AnimClip FindClip(string name)
{
foreach (var animClip in _animClips)
{
if (animClip != null && animClip.Name == name)
return animClip;
}
UniLogger.Warning($"${nameof(AnimClip)} doesn't exist : {name}");
return null;
}
private void DisconnectMixer()
{
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip == null)
continue;
animClip.Disconnect();
_animClips[i] = null;
}
Disconnect();
}
}
}

View File

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

View File

@@ -0,0 +1,221 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
namespace UniFramework.Animation
{
internal abstract class AnimNode
{
private readonly PlayableGraph _graph;
private Playable _source;
private Playable _parent;
private float _fadeSpeed = 0f;
private float _fadeWeight = 0f;
private bool _isFading = false;
/// <summary>
/// 是否已经连接
/// </summary>
public bool IsConnect { get; private set; } = false;
/// <summary>
/// 输入端口
/// </summary>
public int InputPort { private set; get; }
/// <summary>
/// 是否已经完成
/// If the duration of the playable is set, when the time of the playable reaches its duration during playback this flag will be set to true.
/// </summary>
public bool IsDone
{
get
{
return _source.IsDone();
}
}
/// <summary>
/// 是否有效
/// if the Playable is properly constructed by the PlayableGraph and has not been destroyed, false otherwise.
/// </summary>
public bool IsValid
{
get
{
return _source.IsValid();
}
}
/// <summary>
/// 是否正在播放中
/// </summary>
public bool IsPlaying
{
get
{
return _source.GetPlayState() == PlayState.Playing;
}
}
/// <summary>
/// 时间轴
/// </summary>
public float Time
{
set
{
_source.SetTime(value);
}
get
{
return (float)_source.GetTime();
}
}
/// <summary>
/// 播放速度
/// </summary>
public float Speed
{
set
{
_source.SetSpeed(value);
}
get
{
return (float)_source.GetSpeed();
}
}
/// <summary>
/// 权重值
/// </summary>
public float Weight
{
set
{
_parent.SetInputWeight(InputPort, value);
}
get
{
return _parent.GetInputWeight(InputPort);
}
}
public AnimNode(PlayableGraph graph)
{
_graph = graph;
}
public virtual void Update(float deltaTime)
{
if (_isFading)
{
Weight = Mathf.MoveTowards(Weight, _fadeWeight, _fadeSpeed * deltaTime);
if (Mathf.Approximately(Weight, _fadeWeight))
{
_isFading = false;
}
}
}
public virtual void Destroy()
{
if (IsValid)
{
_graph.DestroySubgraph(_source);
}
}
public virtual void PlayNode()
{
// NOTE : When playing, the local time of this Playable will be updated during the evaluation of the PlayableGraph.
_source.Play();
// NOTE : Changes a flag indicating that a playable has completed its operation.
// Playable that reach the end of their duration are automatically marked as done.
_source.SetDone(false);
}
public virtual void PauseNode()
{
// NOTE : When paused, the local time of this Playable will not be updated during the evaluation of the PlayableGraph.
_source.Pause();
// NOTE : Changes a flag indicating that a playable has completed its operation.
// Playable that reach the end of their duration are automatically marked as done.
_source.SetDone(true);
}
public virtual void ResetNode()
{
_fadeSpeed = 0;
_fadeWeight = 0;
_isFading = false;
Time = 0;
Speed = 1;
Weight = 0;
}
/// <summary>
/// 连接到父节点
/// </summary>
/// <param name="parent">父节点对象</param>
/// <param name="inputPort">父节点上的输入端口</param>
public void Connect(Playable parent, int parentInputPort)
{
if (IsConnect)
throw new System.Exception("AnimNode is connected.");
_parent = parent;
InputPort = parentInputPort;
// 重置节点
ResetNode();
// 连接
_graph.Connect(_source, 0, parent, parentInputPort);
IsConnect = true;
}
/// <summary>
/// 同父节点断开连接
/// </summary>
public void Disconnect()
{
if (IsConnect == false)
throw new System.Exception("AnimNode is disconnected.");
// 断开
_graph.Disconnect(_parent, InputPort);
IsConnect = false;
}
/// <summary>
/// 开始权重值过渡
/// </summary>
/// <param name="destWeight">目标权重值</param>
/// <param name="fadeDuration">过渡时间</param>
public void StartWeightFade(float destWeight, float fadeDuration)
{
if (fadeDuration <= 0)
{
Weight = destWeight;
_isFading = false;
return;
}
//注意:保持统一的渐变速度
_fadeSpeed = 1f / fadeDuration;
_fadeWeight = destWeight;
_isFading = true;
}
protected void SetSourcePlayable(Playable playable)
{
_source = playable;
}
}
}

View File

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

View File

@@ -0,0 +1,238 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
namespace UniFramework.Animation
{
internal class AnimPlayable
{
private readonly List<AnimClip> _animClips = new List<AnimClip>(10);
private readonly List<AnimMixer> _animMixers = new List<AnimMixer>(10);
private PlayableGraph _graph;
private AnimationPlayableOutput _output;
private AnimationLayerMixerPlayable _mixerRoot;
public void Create(Animator animator)
{
string name = animator.gameObject.name;
_graph = PlayableGraph.Create(name);
_graph.SetTimeUpdateMode(DirectorUpdateMode.Manual);
_mixerRoot = AnimationLayerMixerPlayable.Create(_graph);
_output = AnimationPlayableOutput.Create(_graph, name, animator);
_output.SetSourcePlayable(_mixerRoot);
}
public void Update(float deltaTime)
{
_graph.Evaluate(deltaTime);
// 更新所有层级
for (int i = 0; i < _animMixers.Count; i++)
{
var mixer = _animMixers[i];
if(mixer.IsConnect)
mixer.Update(deltaTime);
}
}
public void Destroy()
{
_graph.Destroy();
}
/// <summary>
/// Play the graph
/// </summary>
public void PlayGraph()
{
_graph.Play();
}
/// <summary>
/// Stop the graph
/// </summary>
public void StopGraph()
{
_graph.Stop();
}
/// <summary>
/// 获取动画的状态
/// </summary>
/// <param name="name">动画名称</param>
/// <returns>如果动画不存在返回空</returns>
public AnimState GetAnimState(string name)
{
for (int i = 0; i < _animClips.Count; i++)
{
if (_animClips[i].Name == name)
return _animClips[i].State;
}
return null;
}
/// <summary>
/// 检测动画是否正在播放
/// </summary>
/// <param name="name">动画名称</param>
public bool IsPlaying(string name)
{
AnimClip animClip = GetAnimClip(name);
if (animClip == null)
return false;
return animClip.IsConnect && animClip.IsPlaying;
}
/// <summary>
/// 播放一个动画
/// </summary>
/// <param name="name">动画名称</param>
/// <param name="fadeLength">融合时间</param>
public void Play(string name, float fadeLength)
{
var animClip = GetAnimClip(name);
if (animClip == null)
{
UniLogger.Warning($"Not found animation {name}");
return;
}
int layer = animClip.Layer;
var animMixer = GetAnimMixer(layer);
if (animMixer == null)
animMixer = CreateAnimMixer(layer);
if(animMixer.IsConnect == false)
animMixer.Connect(_mixerRoot, animMixer.Layer);
animMixer.Play(animClip, fadeLength);
}
/// <summary>
/// 停止一个动画
/// </summary>
/// <param name="name">动画名称</param>
public void Stop(string name)
{
var animClip = GetAnimClip(name);
if (animClip == null)
{
UniLogger.Warning($"Not found animation {name}");
return;
}
if (animClip.IsConnect == false)
return;
var animMixer = GetAnimMixer(animClip.Layer);
if (animMixer == null)
throw new System.Exception("Should never get here.");
animMixer.Stop(animClip.Name);
}
/// <summary>
/// 添加一个动画片段
/// </summary>
/// <param name="name">动画名称</param>
/// <param name="clip">动画片段</param>
/// <param name="layer">动画层级</param>
public bool AddAnimation(string name, AnimationClip clip, int layer = 0)
{
if (string.IsNullOrEmpty(name))
throw new System.ArgumentException("Name is null or empty.");
if (clip == null)
throw new System.ArgumentNullException();
if (layer < 0)
throw new System.Exception("Layer must be greater than zero.");
if (IsContains(name))
{
UniLogger.Warning($"Animation already exists : {name}");
return false;
}
AnimClip animClip = new AnimClip(_graph, clip, name, layer);
_animClips.Add(animClip);
return true;
}
/// <summary>
/// 移除一个动画片段
/// </summary>
/// <param name="name">动画名称</param>
public bool RemoveAnimation(string name)
{
if (IsContains(name) == false)
{
UniLogger.Warning($"Not found Animation : {name}");
return false;
}
AnimClip animClip = GetAnimClip(name);
AnimMixer animMixer = GetAnimMixer(animClip.Layer);
if(animMixer != null)
animMixer.RemoveClip(animClip.Name);
animClip.Destroy();
_animClips.Remove(animClip);
return true;
}
/// <summary>
/// 是否包含一个动画状态
/// </summary>
/// <param name="name">动画名称</param>
public bool IsContains(string name)
{
for (int i = 0; i < _animClips.Count; i++)
{
if (_animClips[i].Name == name)
return true;
}
return false;
}
private AnimClip GetAnimClip(string name)
{
for (int i = 0; i < _animClips.Count; i++)
{
if (_animClips[i].Name == name)
return _animClips[i];
}
return null;
}
private AnimMixer GetAnimMixer(int layer)
{
for (int i = 0; i < _animMixers.Count; i++)
{
if (_animMixers[i].Layer == layer)
return _animMixers[i];
}
return null;
}
private AnimMixer CreateAnimMixer(int layer)
{
// Increase input count
int inputCount = _mixerRoot.GetInputCount();
if(layer == 0 && inputCount == 0)
{
_mixerRoot.SetInputCount(1);
}
else
{
if (layer > inputCount - 1)
{
_mixerRoot.SetInputCount(layer + 1);
}
}
var animMixer = new AnimMixer(_graph, layer);
_animMixers.Add(animMixer);
return animMixer;
}
}
}

View File

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

View File

@@ -0,0 +1,126 @@
using System.Collections;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
namespace UniFramework.Animation
{
public class AnimState
{
private readonly AnimClip _animClip;
private AnimState()
{
}
internal AnimState(AnimClip animClip)
{
_animClip = animClip;
}
/// <summary>
/// The name of animation.
/// </summary>
public string Name
{
get
{
return _animClip.Name;
}
}
/// <summary>
/// The length of the animation clip in seconds.
/// </summary>
public float Length
{
get
{
return _animClip.ClipLength;
}
}
/// <summary>
/// The layer of animation.
/// </summary>
public int Layer
{
get
{
return _animClip.Layer;
}
}
/// <summary>
/// Wrapping mode of the animation.
/// </summary>
public WrapMode WrapMode
{
get
{
return _animClip.WrapMode;
}
}
/// <summary>
/// The weight of animation.
/// </summary>
public float Weight
{
get
{
return _animClip.Weight;
}
set
{
_animClip.Weight = value;
}
}
/// <summary>
/// The current time of the animation.
/// </summary>
public float Time
{
get
{
return _animClip.Time;
}
set
{
_animClip.Time = value;
}
}
/// <summary>
/// The normalized time of the animation.
/// </summary>
public float NormalizedTime
{
get
{
return _animClip.NormalizedTime;
}
set
{
_animClip.NormalizedTime = value;
}
}
/// <summary>
/// The playback speed of the animation. 1 is normal playback speed.
/// </summary>
public float Speed
{
get
{
return _animClip.Speed;
}
set
{
_animClip.Speed = value;
}
}
}
}

View File

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

View File

@@ -0,0 +1,182 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UniFramework.Animation
{
[RequireComponent(typeof(Animator))]
public class UniAnimation : MonoBehaviour
{
[Serializable]
public class AnimationWrapper
{
public int Layer;
public WrapMode Mode;
public AnimationClip Clip;
}
private AnimPlayable _animPlayable;
private Animator _animator;
[SerializeField]
private AnimationWrapper[] _animations;
[SerializeField]
private bool _playAutomatically = true;
[SerializeField]
private bool _animatePhysics = false;
/// <summary>
/// 自动播放动画
/// </summary>
public bool PlayAutomatically
{
get
{
return _playAutomatically;
}
set
{
_playAutomatically = value;
}
}
/// <summary>
/// 物理更新模式
/// </summary>
public bool AnimatePhysics
{
get
{
return _animatePhysics;
}
set
{
_animatePhysics = value;
_animator.updateMode = _animatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal;
}
}
public void Awake()
{
_animator = GetComponent<Animator>();
_animator.updateMode = _animatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal;
_animPlayable = new AnimPlayable();
_animPlayable.Create(_animator);
// 添加列表动作
for (int i = 0; i < _animations.Length; i++)
{
var wrapper = _animations[i];
if (wrapper == null || wrapper.Clip == null)
continue;
wrapper.Clip.wrapMode = wrapper.Mode;
_animPlayable.AddAnimation(wrapper.Clip.name, wrapper.Clip, wrapper.Layer);
}
}
public void OnEnable()
{
_animPlayable.PlayGraph();
if (PlayAutomatically)
{
var wrapper = GetDefaultWrapper();
if (wrapper != null)
{
Play(wrapper.Clip.name, 0f);
}
}
_animPlayable.Update(float.MaxValue);
}
public void OnDisable()
{
_animPlayable.StopGraph();
}
public void OnDestroy()
{
_animPlayable.Destroy();
}
public void Update()
{
_animPlayable.Update(Time.deltaTime);
}
/// <summary>
/// 添加一个动画
/// </summary>
/// <param name="clip">动画片段</param>
/// <param name="layer">动画层级</param>
public bool AddAnimation(AnimationClip clip, int layer = 0)
{
return _animPlayable.AddAnimation(clip.name, clip, layer);
}
/// <summary>
/// 移除动画
/// </summary>
/// <param name="name">动画名称</param>
public bool RemoveAnimation(string name)
{
return _animPlayable.RemoveAnimation(name);
}
/// <summary>
/// 获取动画状态
/// </summary>
public AnimState GetState(string name)
{
return _animPlayable.GetAnimState(name);
}
/// <summary>
/// 动画是否在播放中
/// </summary>
public bool IsPlaying(string name)
{
return _animPlayable.IsPlaying(name);
}
/// <summary>
/// 是否包含动画片段
/// </summary>
public bool IsContains(string name)
{
return _animPlayable.IsContains(name);
}
/// <summary>
/// 播放动画
/// </summary>
public void Play(string name, float fadeLength = 0.25f)
{
_animPlayable.Play(name, fadeLength);
}
/// <summary>
/// 停止动画
/// </summary>
public void Stop(string name)
{
_animPlayable.Stop(name);
}
private AnimationWrapper GetDefaultWrapper()
{
for (int i = 0; i < _animations.Length; i++)
{
var wrapper = _animations[i];
if (wrapper == null || wrapper.Clip == null)
continue;
return wrapper;
}
return null;
}
}
}

View File

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

View File

@@ -1,12 +1,10 @@
{
"name": "UniWindow",
"name": "UniFramework.Animation",
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3"
],
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,

View File

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

View File

@@ -0,0 +1,21 @@
using System.Diagnostics;
namespace UniFramework.Animation
{
internal static class UniLogger
{
[Conditional("DEBUG")]
public static void Log(string info)
{
UnityEngine.Debug.Log(info);
}
public static void Warning(string info)
{
UnityEngine.Debug.LogWarning(info);
}
public static void Error(string info)
{
UnityEngine.Debug.LogError(info);
}
}
}

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
{
"name": "UniEvent",
"name": "UniFramework.Event",
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3"

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 16d76e3e6337b0c4cae28696d4be4c7c
guid: 72dcc846338391f44a4134c21f94723a
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,5 +1,5 @@
{
"name": "UniPooling",
"name": "UniFramework.Machine",
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3"

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 99ad37bbd721c834d8157bb257d4b8bb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
# UniFramework.Network
一个高效的基于IOCP模型的网络系统。
```c#
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using UniFramework.Network;
// 登录请求消息
class LoginRequestMessage
{
public string Name;
public string Password;
}
// 登录反馈消息
class LoginResponseMessage
{
public string Result;
}
// TCP客户端
UniFramework.Network.TcpClient _client = null;
// 创建TCP客户端
void CreateClient()
{
// 初始化网络系统
UniNetwork.Initalize();
// 创建TCP客户端
int packageMaxSize = short.MaxValue;
var encoder = new DefaultNetPackageEncoder();
var decoder = new DefaultNetPackageDecoder();
_client = UniNetwork.CreateTcpClient(packageMaxSize, encoder, decoder);
// 连接服务器
var remote = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8000);
_client.ConnectAsync(remote, OnConnectServer);
}
// 关闭TCP客户端
void CloseClient()
{
if(_client != null)
{
_client.Dispose();
_client = null;
}
}
void OnConnectServer(SocketError error)
{
Debug.Log($"Server connect result : {error}");
if (error == SocketError.Success)
Debug.Log("服务器连接成功!");
else
Debug.Log("服务器连接失败!");
}
void Update()
{
// 每帧去获取解析的网络包
DefaultNetPackage networkPackage = client.PickPackage() as DefaultNetPackage;
if(networkPackage != null)
{
string json = Encoding.UTF8.GetString(networkPackage.BodyBytes);
LoginResponseMessage message = JsonUtility.FromJson<LoginResponseMessage>(json);
Debug.Log(message.Result);
}
}
// 发送登录请求消息
void SendLoginMessage()
{
LoginRequestMessage message = new LoginRequestMessage();
message.Name = "hevinci";
message.Password = "1234567";
DefaultNetPackage networkPackage = new DefaultNetPackage();
networkPackage.MsgID = 10001;
networkPackage.BodyBytes = Encoding.UTF8.GetBytes(JsonUtility.ToJson(message));
_client.SendPackage(networkPackage);
}
```

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9325e3d425f106a41977ea6e672fecdb
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: efa01143ee531b6478df4aca44367f8a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3cb02cc27ea1caf479c14cebf66a5dab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

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