【SDK】PHXHSDK重新添加
parent
504ae4ca72
commit
fcfae0ba6b
|
@ -0,0 +1 @@
|
|||
Subproject commit c689899a54a45fe71f6a69d76961d47088f196e7
|
|
@ -1,75 +0,0 @@
|
|||
# This .gitignore file should be placed at the root of your Unity project directory
|
||||
#
|
||||
# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore
|
||||
#
|
||||
/[Ll]ibrary/
|
||||
/[Tt]emp/
|
||||
/[Oo]bj/
|
||||
/[Bb]uild/
|
||||
/[Bb]uilds/
|
||||
/[Ll]ogs/
|
||||
/[Uu]ser[Ss]ettings/
|
||||
|
||||
# MemoryCaptures can get excessive in size.
|
||||
# They also could contain extremely sensitive data
|
||||
/[Mm]emoryCaptures/
|
||||
|
||||
# Recordings can get excessive in size
|
||||
/[Rr]ecordings/
|
||||
|
||||
# Uncomment this line if you wish to ignore the asset store tools plugin
|
||||
# /[Aa]ssets/AssetStoreTools*
|
||||
|
||||
# Autogenerated Jetbrains Rider plugin
|
||||
/[Aa]ssets/Plugins/Editor/JetBrains*
|
||||
|
||||
# Visual Studio cache directory
|
||||
.vs/
|
||||
|
||||
# Gradle cache directory
|
||||
.gradle/
|
||||
|
||||
# Autogenerated VS/MD/Consulo solution and project files
|
||||
ExportedObj/
|
||||
.consulo/
|
||||
*.csproj
|
||||
*.unityproj
|
||||
*.sln
|
||||
*.suo
|
||||
*.tmp
|
||||
*.user
|
||||
*.userprefs
|
||||
*.pidb
|
||||
*.booproj
|
||||
*.svd
|
||||
*.pdb
|
||||
*.mdb
|
||||
*.opendb
|
||||
*.VC.db
|
||||
|
||||
# Unity3D generated meta files
|
||||
*.pidb.meta
|
||||
*.pdb.meta
|
||||
*.mdb.meta
|
||||
|
||||
# Unity3D generated file on crash reports
|
||||
sysinfo.txt
|
||||
|
||||
# Builds
|
||||
*.apk
|
||||
*.aab
|
||||
*.unitypackage
|
||||
*.app
|
||||
|
||||
# Crashlytics generated file
|
||||
crashlytics-build.properties
|
||||
|
||||
# Packed Addressables
|
||||
/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
|
||||
|
||||
# Temporary auto-generated Android Assets
|
||||
/[Aa]ssets/[Ss]treamingAssets/aa.meta
|
||||
/[Aa]ssets/[Ss]treamingAssets/aa/*
|
||||
|
||||
# Mac
|
||||
*.DS_Store
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d56946792ef24427975f9f6ebdd85aa1
|
||||
timeCreated: 1708490322
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"name": "ForceAOT",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:e34a5702dd353724aa315fb8011f08c3",
|
||||
"GUID:f51ebe6a0ceec4240a699833d6309b23",
|
||||
"GUID:9e24947de15b9834991c9d8411ea37cf",
|
||||
"GUID:593a5b492d29ac6448b1ebf7f035ef33",
|
||||
"GUID:84651a3751eca9349aac36a66bba901b",
|
||||
"GUID:13ba8ce62aa80c74598530029cb2d649"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a57549a73a7740d48803470f3282422f
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6f5bc95ef7bf4aa2ae49466a309d9637
|
||||
timeCreated: 1708574088
|
|
@ -1,247 +0,0 @@
|
|||
#if USE_HCLR
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using HybridCLR;
|
||||
using PhxhSDK.AOT.SimpleLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public class HybridCLRHelper
|
||||
{
|
||||
const string META_DATA_DLL_PATH = "Assets/HotUpdateDlls/MetaDataDll/";
|
||||
const string HOT_UPDATE_DLL_PATH = "Assets/HotUpdateDlls/HotUpdateDll/";
|
||||
const string PHXH_DLL_NAME = "Phxh.dll";
|
||||
const string FRAMEWORK_DLL_NAME = "FrameWork.dll";
|
||||
const string GAMEPLAY_DLL_NAME = "GamePlay.dll";
|
||||
|
||||
private byte[] _dllBytes;
|
||||
|
||||
private Dictionary<string, Assembly> _allHotUpdateAssemblies = new();
|
||||
|
||||
private readonly List<string> _phxhDependencyDlls = new List<string>()
|
||||
{
|
||||
};
|
||||
|
||||
private readonly List<string> _frameWorkDependencyDlls = new List<string>()
|
||||
{
|
||||
//不要随意改顺序!
|
||||
};
|
||||
|
||||
private readonly List<string> _gamePlayDependencyDlls = new List<string>()
|
||||
{
|
||||
//不要随意改顺序!
|
||||
"BehaviorDesigner.Runtime.dll",
|
||||
//"BestHTTP.dll",
|
||||
"DOTweenCSharp.dll",
|
||||
};
|
||||
|
||||
//所有使用了RuntimeInitializeOnLoadMethod attribute的程序集
|
||||
private readonly List<string> _hasRuntimeInitializeOnLoadMethodAssemblies = new List<string>()
|
||||
{
|
||||
"BehaviorDesigner.Runtime",
|
||||
//"BestHTTP",
|
||||
"GamePlay",
|
||||
};
|
||||
|
||||
private List<string> _aotAssemblyList = new List<string>();
|
||||
|
||||
private ISimpleLoader _loader;
|
||||
|
||||
public async UniTask LoadAssemblies()
|
||||
{
|
||||
await LoadPhxhDependencyAssemblies();
|
||||
await LoadPhxhAssembies();
|
||||
await LoadFrameworkDependencyAssemblies();
|
||||
await LoadFrameWorkAssemblies();
|
||||
await LoadMetadataForAOTAssemblies();
|
||||
await LoadGamePlayDependencyAssemblies();
|
||||
await LoadGamePlayAssemblies();
|
||||
await ReloadAddressableCatalog();
|
||||
_ExecuteRuntimeInitializeOnLoadMethodAttribute();
|
||||
await UniTask.NextFrame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Addressable初始化时热更新代码所对应的ScriptableObject的类型会被识别为System.Object,需要在热更新dll加载完后重新加载一下Addressable的Catalog
|
||||
/// https://hybridclr.doc.code-philosophy.com/docs/help/commonerrors
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async UniTask ReloadAddressableCatalog()
|
||||
{
|
||||
#if !USE_YOO
|
||||
await SimpleLoader_Addressables.ReloadAddressableCatalog();
|
||||
#endif
|
||||
await UniTask.NextFrame();
|
||||
}
|
||||
|
||||
private void _TryHandleMethod(MethodInfo method, List<MethodExecutionInfo> runtimeMethods)
|
||||
{
|
||||
if (!method.IsStatic)
|
||||
return;
|
||||
var runtimeInitializedAttribute = typeof(RuntimeInitializeOnLoadMethodAttribute);
|
||||
var attri = method.GetCustomAttribute(runtimeInitializedAttribute);
|
||||
if (attri == null)
|
||||
return;
|
||||
var sequence = (int)((RuntimeInitializeOnLoadMethodAttribute)attri).loadType;
|
||||
var methodInfo = new MethodExecutionInfo(method, sequence);
|
||||
runtimeMethods.Add(methodInfo);
|
||||
}
|
||||
|
||||
private void _ExecuteRuntimeInitializeOnLoadMethodAttribute()
|
||||
{
|
||||
List<MethodExecutionInfo> runtimeMethods = new();
|
||||
foreach (var assemblyName in _hasRuntimeInitializeOnLoadMethodAssemblies)
|
||||
{
|
||||
var assembly = GetAssembly(assemblyName);
|
||||
if (assembly == null)
|
||||
{
|
||||
Debug.LogError($"找不到使用过RuntimeInitializeOnLoadMethod的assembly,name:{assemblyName}");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
var methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
foreach (var method in methods)
|
||||
{
|
||||
_TryHandleMethod(method, runtimeMethods);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runtimeMethods.Sort((a, b) => b.sequnence.CompareTo(a.sequnence));
|
||||
foreach (var methodInfo in runtimeMethods)
|
||||
{
|
||||
Debug.Log($"call method methodName:{methodInfo.method.Name} sequnence:{methodInfo.sequnence}");
|
||||
methodInfo.method.Invoke(null, null);
|
||||
}
|
||||
|
||||
Debug.Log("调用RuntimeInitializeOnLoadMethod结束!");
|
||||
}
|
||||
|
||||
private Assembly GetAssembly(string assemblyName)
|
||||
{
|
||||
assemblyName = assemblyName.Replace(".dll", "");
|
||||
IEnumerable<Assembly> allAssemblies = _allHotUpdateAssemblies.Values;
|
||||
return allAssemblies.First(assembly => assembly.FullName.Contains(assemblyName));
|
||||
}
|
||||
|
||||
private async UniTask LoadSingleHotUpdateAssembly(string dllName)
|
||||
{
|
||||
var path = $"{HOT_UPDATE_DLL_PATH}{dllName}.bytes";
|
||||
await ReadDllBytes(path);
|
||||
if (_dllBytes != null)
|
||||
{
|
||||
var assembly = Assembly.Load(_dllBytes);
|
||||
_allHotUpdateAssemblies.Add(assembly.FullName, assembly);
|
||||
Debug.Log($"Load Assembly success,assembly Name:{assembly.FullName}");
|
||||
// foreach (var type in GetAssembly(dllName).GetTypes())
|
||||
// {
|
||||
// Debug.Log($"type:{type} in assembly:{GAMEPLAY_DLL_NAME}");
|
||||
// }
|
||||
}
|
||||
await UniTask.NextFrame();
|
||||
}
|
||||
|
||||
//加载GamePlay程序集
|
||||
private async UniTask LoadGamePlayAssemblies()
|
||||
{
|
||||
await LoadSingleHotUpdateAssembly(GAMEPLAY_DLL_NAME);
|
||||
Debug.Log("加载GamePlay程序集结束!");
|
||||
}
|
||||
|
||||
//加载GamePlay依赖的第三方程序集
|
||||
private async UniTask LoadGamePlayDependencyAssemblies()
|
||||
{
|
||||
foreach (var dllName in _gamePlayDependencyDlls)
|
||||
{
|
||||
await LoadSingleHotUpdateAssembly(dllName);
|
||||
}
|
||||
|
||||
Debug.Log("加载GamePlay依赖程序集结束!");
|
||||
}
|
||||
|
||||
//加载Framework程序集
|
||||
private async UniTask LoadFrameWorkAssemblies()
|
||||
{
|
||||
await LoadSingleHotUpdateAssembly(FRAMEWORK_DLL_NAME);
|
||||
Debug.Log("加载Framework程序集结束!");
|
||||
}
|
||||
|
||||
//加载FrameWork依赖的第三方热更序集
|
||||
private async UniTask LoadFrameworkDependencyAssemblies()
|
||||
{
|
||||
foreach (var dllName in _frameWorkDependencyDlls)
|
||||
{
|
||||
await LoadSingleHotUpdateAssembly(dllName);
|
||||
}
|
||||
|
||||
Debug.Log("加载Framework依赖程序集结束!");
|
||||
}
|
||||
|
||||
private async UniTask LoadPhxhAssembies()
|
||||
{
|
||||
await LoadSingleHotUpdateAssembly(PHXH_DLL_NAME);
|
||||
Debug.Log("加载Phxh程序集结束!");
|
||||
}
|
||||
|
||||
private async UniTask LoadPhxhDependencyAssemblies()
|
||||
{
|
||||
foreach (var dllName in _phxhDependencyDlls)
|
||||
{
|
||||
await LoadSingleHotUpdateAssembly(dllName);
|
||||
}
|
||||
|
||||
Debug.Log("加载Phxh依赖程序集结束!");
|
||||
}
|
||||
|
||||
//补充元数据
|
||||
private async UniTask LoadMetadataForAOTAssemblies()
|
||||
{
|
||||
var aotAssemblies = _aotAssemblyList;
|
||||
if (aotAssemblies == null)
|
||||
{
|
||||
Debug.LogError($"LoadMetadataForAOTAssemblies failed, PatchedAOTAssemblyList is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var aotDllName in aotAssemblies)
|
||||
{
|
||||
var path = $"{META_DATA_DLL_PATH}{aotDllName}.bytes";
|
||||
await ReadDllBytes(path);
|
||||
if (_dllBytes != null)
|
||||
{
|
||||
var err = RuntimeApi.LoadMetadataForAOTAssembly(_dllBytes, HomologousImageMode.SuperSet);
|
||||
Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. ret:{err}");
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("补充元数据结束!");
|
||||
}
|
||||
|
||||
private async UniTask ReadDllBytes(string path)
|
||||
{
|
||||
_dllBytes = await _loader.LoadDllBytes(path);
|
||||
if (_dllBytes == null)
|
||||
{
|
||||
Debug.LogError($"cant load dll,path:{path}");
|
||||
return;
|
||||
}
|
||||
await _loader.UnloadDll(path);
|
||||
}
|
||||
|
||||
public void RegistLoader(ISimpleLoader loader)
|
||||
{
|
||||
_loader = loader;
|
||||
}
|
||||
|
||||
public void SetDllList(IReadOnlyList<string> dllList)
|
||||
{
|
||||
_aotAssemblyList.AddRange(dllList);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 88d9df6663654361adc0bec9396b21c9
|
||||
timeCreated: 1708574103
|
|
@ -1,15 +0,0 @@
|
|||
using System.Reflection;
|
||||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public class MethodExecutionInfo
|
||||
{
|
||||
public MethodInfo method;
|
||||
public int sequnence;
|
||||
|
||||
public MethodExecutionInfo(MethodInfo method, int sequnence)
|
||||
{
|
||||
this.method = method;
|
||||
this.sequnence = sequnence;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d048804b8b42464d95190aa5ba3546a2
|
||||
timeCreated: 1708576339
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4d06325ab1cf455f88fb987aa35ddb2b
|
||||
timeCreated: 1708574646
|
|
@ -1,11 +0,0 @@
|
|||
using Cysharp.Threading.Tasks;
|
||||
namespace PhxhSDK.AOT.SimpleLoader
|
||||
{
|
||||
public interface ISimpleLoader
|
||||
{
|
||||
UniTask<byte[]> LoadDllBytes(string path);
|
||||
UniTask UnloadDll(string path);
|
||||
|
||||
UniTask LoadSceneAsync(string path);
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 202a545f2ec148c19eb199a62d92e0b8
|
||||
timeCreated: 1708574653
|
|
@ -1,52 +0,0 @@
|
|||
#if USE_ADDRESSABLES
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PhxhSDK.AOT.SimpleLoader
|
||||
{
|
||||
public class SimpleLoader_Addressables : ISimpleLoader
|
||||
{
|
||||
|
||||
private Dictionary<string, Object> _loadedAssets = new Dictionary<string, Object>();
|
||||
|
||||
public async UniTask<byte[]> LoadDllBytes(string path)
|
||||
{
|
||||
var op = Addressables.LoadAssetAsync<TextAsset>(path);
|
||||
await op;
|
||||
if (op.Status == AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
_loadedAssets.Add(path, op.Result);
|
||||
return op.Result.bytes;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public UniTask UnloadDll(string path)
|
||||
{
|
||||
if (_loadedAssets.TryGetValue(path, out var asset))
|
||||
{
|
||||
Addressables.Release(asset);
|
||||
_loadedAssets.Remove(path);
|
||||
}
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
public async UniTask LoadSceneAsync(string path)
|
||||
{
|
||||
await Addressables.LoadSceneAsync(path);
|
||||
}
|
||||
|
||||
public static async UniTask ReloadAddressableCatalog()
|
||||
{
|
||||
var op = Addressables.LoadContentCatalogAsync($"{Addressables.RuntimePath}/catalog.json");
|
||||
await op;
|
||||
if (op.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"load content catalog failed, exception:{op.OperationException.Message} \r\n {op.OperationException.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 33021c41fc0a4368a91312930aa72d0b
|
||||
timeCreated: 1708574988
|
|
@ -1,40 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
|
||||
namespace PhxhSDK.AOT.SimpleLoader
|
||||
{
|
||||
public class SimpleLoader_YooAsset : ISimpleLoader
|
||||
{
|
||||
|
||||
private Dictionary<string, AssetHandle> _loadedAssets = new Dictionary<string, AssetHandle>();
|
||||
|
||||
public async UniTask<byte[]> LoadDllBytes(string path)
|
||||
{
|
||||
var op = YooAssets.LoadAssetAsync<TextAsset>(path);
|
||||
await op;
|
||||
_loadedAssets.Add(path, op);
|
||||
if (op.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
return (op.AssetObject as TextAsset)?.bytes;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public UniTask UnloadDll(string path)
|
||||
{
|
||||
if (_loadedAssets.TryGetValue(path, out var asset))
|
||||
{
|
||||
asset.Release();
|
||||
_loadedAssets.Remove(path);
|
||||
}
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public async UniTask LoadSceneAsync(string path)
|
||||
{
|
||||
await YooAssets.LoadSceneAsync(path);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 91a500ba67764ceaa13e4305e58ed1d5
|
||||
timeCreated: 1708576470
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 04d521a802e944d88b4e057cdb0fdf8f
|
||||
timeCreated: 1708580107
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 273bf894badf42508bcf6b111faa5e5d
|
||||
timeCreated: 1708921974
|
|
@ -1,159 +0,0 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PhxhSDK.AOT.VersionUpdate
|
||||
{
|
||||
public class PackDataInst
|
||||
{
|
||||
public static PackDataInst inst { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新本地信息
|
||||
/// 初始存放于resources文件夹下
|
||||
/// 读取后存放与playerprefs中
|
||||
/// </summary>
|
||||
public UpdateLocalInfo localInfo { get; private set; }
|
||||
|
||||
private static string _localInfoKey = "LocalInfo_";
|
||||
private const string PathInResources = "LocalInfo";
|
||||
|
||||
public static void CreateInst()
|
||||
{
|
||||
if (inst != null) return;
|
||||
var textAsset = Resources.Load<TextAsset>(PathInResources);
|
||||
if (textAsset == null)
|
||||
{
|
||||
throw new Exception("本地信息文件不存在:" + PathInResources);
|
||||
}
|
||||
var textJson = textAsset.text;
|
||||
var infoInResources = JsonUtility.FromJson<UpdateLocalInfo>(textJson);
|
||||
Resources.UnloadAsset(textAsset);
|
||||
|
||||
var versionInResources = infoInResources.version;
|
||||
Debug.Log("Resources中的版本信息:" + versionInResources);
|
||||
|
||||
inst = new PackDataInst();
|
||||
_localInfoKey += Application.productName;
|
||||
Debug.Log("LocalInfoKey:" + _localInfoKey);
|
||||
var json = PlayerPrefs.GetString(_localInfoKey);
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
Debug.Log("PlayerPrefs中无本地信息,使用Resources中的信息:" + textJson);
|
||||
inst.localInfo = infoInResources;
|
||||
inst.SaveData();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("读取PlayerPrefs本地信息:" + json);
|
||||
inst.localInfo = JsonUtility.FromJson<UpdateLocalInfo>(json);
|
||||
}
|
||||
// version使用resources中的
|
||||
inst.localInfo.version = versionInResources;
|
||||
}
|
||||
|
||||
public void SaveData()
|
||||
{
|
||||
var json = JsonUtility.ToJson(localInfo);
|
||||
PlayerPrefs.SetString(_localInfoKey, json);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
public static string GetRuntimePlatform()
|
||||
{
|
||||
switch (Application.platform)
|
||||
{
|
||||
case RuntimePlatform.WindowsPlayer:
|
||||
case RuntimePlatform.WindowsEditor:
|
||||
#if AB_DEBUG
|
||||
return "Android";
|
||||
#else
|
||||
return "Windows";
|
||||
#endif
|
||||
case RuntimePlatform.Android:
|
||||
return "Android";
|
||||
case RuntimePlatform.IPhonePlayer:
|
||||
return "iOS";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[UnityEditor.MenuItem("Test/YooAsset/创建本地信息文件")]
|
||||
public static void TestFunc()
|
||||
{
|
||||
var key = "LocalInfo_" + Application.productName;
|
||||
PlayerPrefs.DeleteKey(key);
|
||||
PlayerPrefs.Save();
|
||||
|
||||
var info = new UpdateLocalInfo();
|
||||
info.version = "0.1.0";
|
||||
info.workSpace = "Dev";
|
||||
info.buildCount = 1;
|
||||
CreateResourceJson(info);
|
||||
|
||||
// 弹出提示框
|
||||
UnityEditor.EditorUtility.DisplayDialog("创建本地信息", "创建成功", "确定");
|
||||
}
|
||||
|
||||
[UnityEditor.MenuItem("Test/YooAsset/清除本地信息文件")]
|
||||
public static void ClearPlayerData()
|
||||
{
|
||||
var key = "LocalInfo_" + Application.productName;
|
||||
PlayerPrefs.DeleteKey(key);
|
||||
PlayerPrefs.Save();
|
||||
// 弹出提示框
|
||||
UnityEditor.EditorUtility.DisplayDialog("清除本地信息", "清除成功", "确定");
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void CreateResourceJson(UpdateLocalInfo info)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var savePath = Application.dataPath + "/Resources/" + PathInResources + ".json";
|
||||
var json = JsonUtility.ToJson(info);
|
||||
var dirPath = Application.dataPath + "/Resources";
|
||||
if (!System.IO.Directory.Exists(dirPath))
|
||||
{
|
||||
System.IO.Directory.CreateDirectory(dirPath);
|
||||
}
|
||||
System.IO.File.WriteAllText(savePath, json);
|
||||
UnityEditor.AssetDatabase.Refresh();
|
||||
#else
|
||||
Debug.LogError("该方法仅能在Editor模式下使用");
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void CreateBuildCount(string workSpacke,
|
||||
string version,
|
||||
int count)
|
||||
{
|
||||
var combinePath = Application.dataPath + $"/../Yoo_Build_Cache/{workSpacke}/{version}";
|
||||
if (!System.IO.Directory.Exists(combinePath))
|
||||
{
|
||||
System.IO.Directory.CreateDirectory(combinePath);
|
||||
}
|
||||
var savePath = combinePath + "/build_count.txt";
|
||||
System.IO.File.WriteAllText(savePath, count.ToString());
|
||||
Debug.Log("创建build_count.txt成功 version:" + version + " count:" + count);
|
||||
}
|
||||
|
||||
public static int ReadBuildCount(string workSpace, string version)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var combinePath = Application.dataPath + $"/../Yoo_Build_Cache/{workSpace}/{version}/build_count.txt";
|
||||
if (!System.IO.File.Exists(combinePath))
|
||||
{
|
||||
Debug.LogError("build_count.txt不存在,打更新包时请确保build_count.txt存在");
|
||||
throw new System.Exception("build_count.txt不存在");
|
||||
}
|
||||
var count = System.IO.File.ReadAllText(combinePath);
|
||||
Debug.Log("读取build_count.txt成功 version:" + version + " count:" + count);
|
||||
return int.Parse(count);
|
||||
#else
|
||||
Debug.LogError("该方法仅能在Editor模式下使用");
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 44eb7b74a8c94e1cb705377229681d81
|
||||
timeCreated: 1708922010
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
namespace PhxhSDK.AOT.VersionUpdate
|
||||
{
|
||||
[Serializable]
|
||||
public class UpdateLocalInfo
|
||||
{
|
||||
public string workSpace = "DevYoo";
|
||||
public string version = "0.2.0";
|
||||
public string serverUrl = "http://132.232.113.98";
|
||||
public int buildCount = 1;
|
||||
public string pathRoot = "Build";
|
||||
public string localFullVersion = "empty";
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4eeb9040a2844743bec5c9b35105f806
|
||||
timeCreated: 1708921897
|
|
@ -1,27 +0,0 @@
|
|||
namespace PhxhSDK.AOT.VersionUpdate
|
||||
{
|
||||
public enum EVersionUpdateType
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 不需要更新
|
||||
/// </summary>
|
||||
NoUpdate,
|
||||
|
||||
/// <summary>
|
||||
/// 资源更新
|
||||
/// </summary>
|
||||
ResUpdate,
|
||||
|
||||
/// <summary>
|
||||
/// 整包更新
|
||||
/// </summary>
|
||||
PackUpdate,
|
||||
|
||||
/// <summary>
|
||||
/// 出错
|
||||
/// </summary>
|
||||
Error,
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1b70d270da4c44dbaefd50e9835c573b
|
||||
timeCreated: 1708580602
|
|
@ -1,14 +0,0 @@
|
|||
using Cysharp.Threading.Tasks;
|
||||
namespace PhxhSDK.AOT.VersionUpdate
|
||||
{
|
||||
public interface IVersionUpdate
|
||||
{
|
||||
|
||||
UniTask<EVersionUpdateType> CheckVersion();
|
||||
|
||||
UniTask<bool> UpdateRes();
|
||||
|
||||
VersionUpdateInfo GetVersionInfo();
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dc873595eb49408794db5ba8c13a4878
|
||||
timeCreated: 1708580756
|
|
@ -1,14 +0,0 @@
|
|||
using Cysharp.Threading.Tasks;
|
||||
namespace PhxhSDK.AOT.VersionUpdate
|
||||
{
|
||||
public interface IVersionUpdateUI
|
||||
{
|
||||
UniTask<bool> ShowDialog(string title,
|
||||
string content);
|
||||
|
||||
void UpdateProgress(float progress);
|
||||
void UpdateProgressText(string text);
|
||||
|
||||
void CloseAll();
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0d8b5e01044d4ecdb7f5ef7cf7435045
|
||||
timeCreated: 1708580151
|
|
@ -1,66 +0,0 @@
|
|||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
namespace PhxhSDK.AOT.VersionUpdate
|
||||
{
|
||||
public class VersionUpdateHandle
|
||||
{
|
||||
|
||||
private readonly IVersionUpdate _updateImpl;
|
||||
private readonly IVersionUpdateUI _updateUI;
|
||||
|
||||
public VersionUpdateHandle(IVersionUpdateUI ui)
|
||||
{
|
||||
#if USE_YOO
|
||||
_updateImpl = new VersionUpdate_YooAsset(ui);
|
||||
#else
|
||||
_updateImpl = new VersionUpdate_Addressables(ui);
|
||||
#endif
|
||||
|
||||
_updateUI = ui;
|
||||
}
|
||||
|
||||
public async UniTask<bool> CheckUpdate()
|
||||
{
|
||||
Debug.Log("开始检查版本更新");
|
||||
var checkResult = await _CheckVersion();
|
||||
switch (checkResult)
|
||||
{
|
||||
case EVersionUpdateType.NoUpdate:
|
||||
Debug.Log("无需更新");
|
||||
return true;
|
||||
case EVersionUpdateType.ResUpdate:
|
||||
Debug.Log("资源更新");
|
||||
await _UpdateRes();
|
||||
return true;
|
||||
default:
|
||||
_updateUI.UpdateProgressText("Start Failed!");
|
||||
Debug.LogError("暂未实现的更新类型: " + checkResult);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask<EVersionUpdateType> _CheckVersion()
|
||||
{
|
||||
return await _updateImpl.CheckVersion();
|
||||
}
|
||||
|
||||
private async UniTask<bool> _UpdateRes()
|
||||
{
|
||||
var versionInfo = _updateImpl.GetVersionInfo();
|
||||
var totalBytes = versionInfo.totalBytes;
|
||||
var totalMb = totalBytes / 1024f / 1024f;
|
||||
var totalMbStr = totalMb.ToString("F2");
|
||||
var showStr = $"Find New Version: {versionInfo.newVersion}\n" +
|
||||
$"Current Version: {versionInfo.oldVersion}\n" +
|
||||
$"Need Download Size: {totalMbStr}MB\n" +
|
||||
$"Continue?";
|
||||
var result = await _updateUI.ShowDialog("Need Update", showStr);
|
||||
if (!result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return await _updateImpl.UpdateRes();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3aaed81d361946f8ae7a260f2b3445b1
|
||||
timeCreated: 1708580492
|
|
@ -1,9 +0,0 @@
|
|||
namespace PhxhSDK.AOT.VersionUpdate
|
||||
{
|
||||
public class VersionUpdateInfo
|
||||
{
|
||||
public string oldVersion = "unknown";
|
||||
public string newVersion = "unknown";
|
||||
public long totalBytes = 0;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 32d04333b6a24d26a5707f5e4e619892
|
||||
timeCreated: 1708581325
|
|
@ -1,191 +0,0 @@
|
|||
#if USE_ADDRESSABLES
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using PhxhSDK.AOT.SimpleLoader;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
namespace PhxhSDK.AOT.VersionUpdate
|
||||
{
|
||||
public class VersionUpdate_Addressables : IVersionUpdate
|
||||
{
|
||||
|
||||
private IVersionUpdateUI _versionUpdateUI;
|
||||
|
||||
private VersionUpdateInfo _versionUpdateInfo = new VersionUpdateInfo();
|
||||
|
||||
[Serializable]
|
||||
private class DownloadContent
|
||||
{
|
||||
public List<string> catalogs = new();
|
||||
}
|
||||
|
||||
//记录在playerPres里的需要下载的catalogs的ID
|
||||
const string DOWNLOAD_CATALOGS_ID = "DownloadCatalogs";
|
||||
|
||||
//version update
|
||||
private AsyncOperationHandle _downloadOP;
|
||||
|
||||
//此对象里保存了需要下载的catalog,每次获取新的catalog会将此对象保存到手机上,如果在下载的过程中关闭了游戏,下次打开还能拿到catalog继续下载
|
||||
private DownloadContent _downloadContent = new();
|
||||
|
||||
private List<object> _KeysNeedToDownload = new();
|
||||
|
||||
private bool HasContentToDownload => _downloadContent != null && _downloadContent.catalogs != null &&
|
||||
_downloadContent.catalogs.Count > 0;
|
||||
|
||||
public VersionUpdate_Addressables(IVersionUpdateUI ui)
|
||||
{
|
||||
_versionUpdateUI = ui;
|
||||
}
|
||||
|
||||
public async UniTask<EVersionUpdateType> CheckVersion()
|
||||
{
|
||||
EVersionUpdateType result = EVersionUpdateType.Error;
|
||||
//todo 如果包体版本不一致则提示用户去app store重新下载
|
||||
var checkUpdateOP = Addressables.CheckForCatalogUpdates(false);
|
||||
await checkUpdateOP;
|
||||
if (checkUpdateOP.Status == AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
result = EVersionUpdateType.NoUpdate;
|
||||
_downloadContent.catalogs = checkUpdateOP.Result;
|
||||
if (HasContentToDownload)
|
||||
{
|
||||
Debug.Log("new version on server");
|
||||
//如果服务器上的catalog和本地不一致,则覆盖上一次需要下载的被内容
|
||||
var jsonStr = JsonUtility.ToJson(_downloadContent);
|
||||
PlayerPrefs.SetString(DOWNLOAD_CATALOGS_ID, jsonStr);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PlayerPrefs.HasKey(DOWNLOAD_CATALOGS_ID))
|
||||
{
|
||||
Debug.Log("there are some contents remains from last downloading");
|
||||
var jsonStr = PlayerPrefs.GetString(DOWNLOAD_CATALOGS_ID);
|
||||
JsonUtility.FromJsonOverwrite(jsonStr, _downloadContent);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasContentToDownload)
|
||||
{
|
||||
var updateCatalogOP = Addressables.UpdateCatalogs(_downloadContent.catalogs, false);
|
||||
await updateCatalogOP;
|
||||
if (updateCatalogOP.Status == AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
_KeysNeedToDownload.Clear();
|
||||
foreach (var resourceLocator in updateCatalogOP.Result)
|
||||
{
|
||||
_KeysNeedToDownload.AddRange(resourceLocator.Keys);
|
||||
}
|
||||
|
||||
if (HasContentToDownload)
|
||||
{
|
||||
var downloadSizeOp = Addressables.GetDownloadSizeAsync((IEnumerable)_KeysNeedToDownload);
|
||||
await downloadSizeOp;
|
||||
Debug.Log($"download size: {downloadSizeOp.Result / (1024f * 1024f)}MB");
|
||||
result = EVersionUpdateType.ResUpdate;
|
||||
_versionUpdateInfo.totalBytes = downloadSizeOp.Result;
|
||||
|
||||
Addressables.Release(downloadSizeOp);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = EVersionUpdateType.NoUpdate;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Update catalog failed!exception:{updateCatalogOP.OperationException.Message}");
|
||||
}
|
||||
|
||||
Addressables.Release(updateCatalogOP);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"CheckUpdate failed!exception:{checkUpdateOP.OperationException.Message}");
|
||||
}
|
||||
|
||||
Addressables.Release(checkUpdateOP);
|
||||
await SimpleLoader_Addressables.ReloadAddressableCatalog();
|
||||
Debug.Log($"版本检查结束,是否有需要下载的内容:{HasContentToDownload}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//下载资源
|
||||
private async UniTask<bool> Download()
|
||||
{
|
||||
//_downloadStuckTime = 0;
|
||||
// //下载经常在100%的时候卡住,参考:https://forum.unity.com/threads/addressables-1-14-2-downloaddependenciesasync-does-not-complete-randomly.966671/
|
||||
// //倒数第二个回答
|
||||
// var asyncLoadResources = Addressables.LoadResourceLocationsAsync((IEnumerable)_KeysNeedToDownload,
|
||||
// Addressables.MergeMode.Union, null);
|
||||
// IList<IResourceLocation> dependencyLoadList = new List<IResourceLocation>();
|
||||
// yield return asyncLoadResources;
|
||||
// foreach (var item in asyncLoadResources.Result)
|
||||
// {
|
||||
// dependencyLoadList.Add(item);
|
||||
// }
|
||||
//
|
||||
// Addressables.Release(asyncLoadResources);
|
||||
//
|
||||
// _downloadOP =
|
||||
// Addressables.DownloadDependenciesAsync(dependencyLoadList);
|
||||
|
||||
_downloadOP =
|
||||
Addressables.DownloadDependenciesAsync((IEnumerable)_KeysNeedToDownload, Addressables.MergeMode.Union, false);
|
||||
|
||||
// while (!_downloadOP.IsDone)
|
||||
// {
|
||||
// RefreshDownLoadStatus();
|
||||
// if (!CheckIfNeedReDownload())
|
||||
// yield return 0;
|
||||
// else
|
||||
// {
|
||||
// //下载会经常卡在99%,此时还剩下很少的资源要下载,可以直接放弃下载,进入游戏
|
||||
// //经过尝试,上述方法行不通,_downloadOp不能被终止,如果直接release的话会导致后续逻辑报错
|
||||
// Debug.LogError($"下载卡住超过时间上限,放弃下载!");
|
||||
// yield return _downloadOP;
|
||||
// }
|
||||
// }
|
||||
|
||||
_versionUpdateUI.UpdateProgressText("Start Downloading...");
|
||||
|
||||
while (_downloadOP.IsValid() && !_downloadOP.IsDone)
|
||||
{
|
||||
await UniTask.DelayFrame(1);
|
||||
var downloadStatus = _downloadOP.GetDownloadStatus();
|
||||
_versionUpdateUI.UpdateProgress(downloadStatus.Percent);
|
||||
}
|
||||
|
||||
if (_downloadOP.Status == AsyncOperationStatus.Succeeded)
|
||||
Debug.Log($"下载完毕!");
|
||||
else
|
||||
Debug.LogError($"Download Update Content Failed! exception:{_downloadOP.OperationException.Message} \r\n {_downloadOP.OperationException.StackTrace}");
|
||||
|
||||
Addressables.Release(_downloadOP);
|
||||
|
||||
//清除需要下载的内容
|
||||
Debug.Log($"delete key:{DOWNLOAD_CATALOGS_ID}");
|
||||
PlayerPrefs.DeleteKey(DOWNLOAD_CATALOGS_ID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async UniTask<bool> UpdateRes()
|
||||
{
|
||||
return await Download();
|
||||
}
|
||||
public VersionUpdateInfo GetVersionInfo()
|
||||
{
|
||||
return _versionUpdateInfo;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 74a3780a1779428a88fbde5745bdc8b8
|
||||
timeCreated: 1708580803
|
|
@ -1,196 +0,0 @@
|
|||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
namespace PhxhSDK.AOT.VersionUpdate
|
||||
{
|
||||
public class VersionUpdate_YooAsset : IVersionUpdate
|
||||
{
|
||||
|
||||
private VersionUpdateInfo _versionInfo = new VersionUpdateInfo();
|
||||
private ResourceDownloaderOperation _downloaderOperation_Default;
|
||||
private ResourceDownloaderOperation _downloaderOperation_Raw;
|
||||
private IVersionUpdateUI _updateUI;
|
||||
private long _totalNeedDownloadBytes;
|
||||
private long _currentDownLoadBytesDefault;
|
||||
private long _currentDownloadBytesRaw;
|
||||
private string _serverVersion;
|
||||
|
||||
public VersionUpdate_YooAsset(IVersionUpdateUI ui)
|
||||
{
|
||||
_updateUI = ui;
|
||||
}
|
||||
|
||||
public async UniTask<ResourceDownloaderOperation> _CreateDownloader(ResourcePackage package)
|
||||
{
|
||||
Debug.Log("[LTRes]开始获取package:" + package.PackageName);
|
||||
|
||||
var operation = package.UpdatePackageVersionAsync();
|
||||
await operation.Task;
|
||||
|
||||
if (operation.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
var packageCRC = operation.PackageVersion;
|
||||
Debug.Log($"[LTRes]获取到服务器CRC:{packageCRC}");
|
||||
var op = package.UpdatePackageManifestAsync(packageCRC, true);
|
||||
await op.Task;
|
||||
|
||||
Debug.Log("[LTRes]开始更新补丁清单");
|
||||
if (op.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
Debug.Log("[LTRes]更新补丁清单成功");
|
||||
var downloadingMaxNum = 10;
|
||||
var failedTryAgain = 3;
|
||||
var downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);
|
||||
return downloader;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async UniTask<EVersionUpdateType> CheckVersion()
|
||||
{
|
||||
// TODO: 这里可以做自定义版本检查
|
||||
var package = YooAssetHelper.defaultPackage;
|
||||
|
||||
UpdatePackageVersionOperation operation = package.UpdatePackageVersionAsync();
|
||||
await operation.Task;
|
||||
|
||||
// var localCRC = "unknown";
|
||||
// try
|
||||
// {
|
||||
// localCRC = package.GetPackageVersion();
|
||||
// }
|
||||
// catch (System.Exception e)
|
||||
// {
|
||||
// Debug.LogError($"[LTRes]获取本地CRC失败:{e}");
|
||||
// return EVersionUpdateType.Error;
|
||||
// }
|
||||
// Debug.Log($"[LTRes]获取到本地crc:{localCRC}");
|
||||
|
||||
if (operation.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
var packageCRC = operation.PackageVersion;
|
||||
Debug.Log($"[LTRes]获取到服务器CRC:{packageCRC}");
|
||||
_serverVersion = packageCRC;
|
||||
// 更新补丁清单
|
||||
UpdatePackageManifestOperation op = package.UpdatePackageManifestAsync(packageCRC, true);
|
||||
await op.Task;
|
||||
|
||||
Debug.Log("[LTRes]开始更新补丁清单");
|
||||
if (op.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
Debug.Log("[LTRes]更新补丁清单成功");
|
||||
var downloadingMaxNum = 10;
|
||||
var failedTryAgain = 3;
|
||||
var downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);
|
||||
_downloaderOperation_Default = downloader;
|
||||
|
||||
// 添加原生文件下载
|
||||
var rawDownloader = await _CreateDownloader(YooAssetHelper.rawPackage);
|
||||
_downloaderOperation_Raw = rawDownloader;
|
||||
|
||||
var localCRC = PackDataInst.inst.localInfo.localFullVersion;
|
||||
var totalDownloadCount = _downloaderOperation_Default.TotalDownloadCount + _downloaderOperation_Raw.TotalDownloadCount;
|
||||
if (totalDownloadCount == 0)
|
||||
{
|
||||
Debug.Log($"[LTRes]没有需要下载的文件,无需更新,本地CRC:{localCRC} 服务器CRC:{packageCRC}");
|
||||
_SaveVersionToLocal();
|
||||
return EVersionUpdateType.NoUpdate;
|
||||
}
|
||||
|
||||
var totalDownloadBytes = _downloaderOperation_Default.TotalDownloadBytes + _downloaderOperation_Raw.TotalDownloadBytes;
|
||||
|
||||
_versionInfo.newVersion = packageCRC;
|
||||
_versionInfo.oldVersion = localCRC;
|
||||
_versionInfo.totalBytes = totalDownloadBytes;
|
||||
_totalNeedDownloadBytes = totalDownloadBytes;
|
||||
_currentDownloadBytesRaw = 0;
|
||||
_currentDownLoadBytesDefault = 0;
|
||||
return EVersionUpdateType.ResUpdate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[LTRes]更新补丁清单失败");
|
||||
await _updateUI.ShowDialog("提示", "网络错误");
|
||||
return EVersionUpdateType.Error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[LTRes]获取服务器CRC失败");
|
||||
await _updateUI.ShowDialog("提示", "网络错误");
|
||||
return EVersionUpdateType.Error;
|
||||
}
|
||||
}
|
||||
|
||||
private void _SaveVersionToLocal()
|
||||
{
|
||||
PackDataInst.inst.localInfo.localFullVersion = _serverVersion;
|
||||
PackDataInst.inst.SaveData();
|
||||
}
|
||||
|
||||
public async UniTask<bool> UpdateRes()
|
||||
{
|
||||
var downloader1 = _downloaderOperation_Default;
|
||||
downloader1.OnDownloadProgressCallback += _OnProgressChangeDefault;
|
||||
downloader1.BeginDownload();
|
||||
|
||||
var downloader2 = _downloaderOperation_Raw;
|
||||
downloader2.OnDownloadProgressCallback += _OnProgressChangeRaw;
|
||||
downloader2.BeginDownload();
|
||||
|
||||
while (!downloader1.IsDone || !downloader1.IsDone)
|
||||
{
|
||||
await UniTask.DelayFrame(1);
|
||||
}
|
||||
|
||||
if (downloader1.Status == EOperationStatus.Succeed
|
||||
&& downloader2.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
Debug.Log("[LTRes]下载成功");
|
||||
|
||||
_SaveVersionToLocal();
|
||||
return true;
|
||||
}
|
||||
|
||||
Debug.LogError($"[LTRes]下载失败:{downloader1.Error}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void _OnProgressChangeRaw(int totalDownloadCount,
|
||||
int currentDownloadCount,
|
||||
long totalDownloadBytes,
|
||||
long currentDownloadBytes)
|
||||
{
|
||||
_currentDownloadBytesRaw = currentDownloadBytes;
|
||||
|
||||
_UpdateUI();
|
||||
}
|
||||
|
||||
private void _UpdateUI()
|
||||
{
|
||||
var currentDownloadBytes = _currentDownloadBytesRaw + _currentDownLoadBytesDefault;
|
||||
var progress = (float)currentDownloadBytes / _totalNeedDownloadBytes;
|
||||
var progressStr = (progress * 100f).ToString("0.00") + "%";
|
||||
// Debug.Log(progressStr);
|
||||
_updateUI.UpdateProgressText(progressStr);
|
||||
_updateUI.UpdateProgress(progress);
|
||||
}
|
||||
|
||||
private void _OnProgressChangeDefault(int totalDownloadCount,
|
||||
int currentDownloadCount,
|
||||
long totalDownloadBytes,
|
||||
long currentDownloadBytes)
|
||||
{
|
||||
_currentDownLoadBytesDefault = currentDownloadBytes;
|
||||
|
||||
_UpdateUI();
|
||||
}
|
||||
|
||||
public VersionUpdateInfo GetVersionInfo()
|
||||
{
|
||||
return _versionInfo;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 00eeef6b6c104d20801654dbe19d0fc5
|
||||
timeCreated: 1708580923
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 334ceaaa51174ec199be985764c31ac8
|
||||
timeCreated: 1708514105
|
|
@ -1,9 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public class BuildinFileManifest : ScriptableObject
|
||||
{
|
||||
public List<string> BuildinFiles = new List<string>();
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 56888749a2144af0929c016f5d24356c
|
||||
timeCreated: 1708514040
|
|
@ -1,103 +0,0 @@
|
|||
using System.IO;
|
||||
using UnityEngine;
|
||||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public class CustomFileStream : Stream
|
||||
{
|
||||
|
||||
private FileStream _fileStream;
|
||||
|
||||
public CustomFileStream(string path)
|
||||
{
|
||||
_fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
Debug.LogError("不支持Flush操作");
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer,
|
||||
int offset,
|
||||
int count)
|
||||
{
|
||||
var read = _fileStream.Read(buffer, offset, count);
|
||||
for (int i = 0; i < read; i++)
|
||||
{
|
||||
// 取反
|
||||
var index = offset + i;
|
||||
buffer[index] = (byte)~buffer[index];
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
public override long Seek(long offset,
|
||||
SeekOrigin origin)
|
||||
{
|
||||
return _fileStream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
_fileStream.SetLength(value);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer,
|
||||
int offset,
|
||||
int count)
|
||||
{
|
||||
Debug.LogError("不支持Write操作");
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fileStream.CanRead;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fileStream.CanSeek;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fileStream.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fileStream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
_fileStream.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
_fileStream.Close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b780b30d69794883b021b86a210e69b0
|
||||
timeCreated: 1708668162
|
|
@ -1,24 +0,0 @@
|
|||
using YooAsset;
|
||||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public class LTRemoteServices : IRemoteServices
|
||||
{
|
||||
|
||||
private string _remotePath;
|
||||
|
||||
public LTRemoteServices(string remotePath)
|
||||
{
|
||||
_remotePath = remotePath;
|
||||
}
|
||||
|
||||
public string GetRemoteMainURL(string fileName)
|
||||
{
|
||||
return _remotePath + "/" + fileName;
|
||||
}
|
||||
|
||||
public string GetRemoteFallbackURL(string fileName)
|
||||
{
|
||||
return _remotePath + "/" + fileName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2ad9a3bb07b74d8dae76fdcc627d42c1
|
||||
timeCreated: 1708514573
|
|
@ -1,136 +0,0 @@
|
|||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
|
||||
namespace PhxhSDK.AOT
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 资源文件查询服务类
|
||||
/// </summary>
|
||||
public class GameQueryServices : IBuildinQueryServices
|
||||
{
|
||||
public bool Query(string packageName,
|
||||
string fileName,
|
||||
string fileCRC)
|
||||
{
|
||||
// 注意:fileName包含文件格式
|
||||
return StreamingAssetsHelper.FileExists(packageName, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
public class GameDeliveryServices : IDeliveryQueryServices
|
||||
{
|
||||
public bool Query(string packageName,
|
||||
string fileName,
|
||||
string fileCRC)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public string GetFilePath(string packageName,
|
||||
string fileName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// StreamingAssets目录下资源查询帮助类
|
||||
/// </summary>
|
||||
public sealed class StreamingAssetsHelper
|
||||
{
|
||||
public static void Init() {}
|
||||
public static bool FileExists(string packageName,
|
||||
string fileName)
|
||||
{
|
||||
string filePath = Path.Combine(Application.streamingAssetsPath, StreamingAssetsDefine.RootFolderName, packageName, fileName);
|
||||
return File.Exists(filePath);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// StreamingAssets目录下资源查询帮助类
|
||||
/// </summary>
|
||||
public sealed class StreamingAssetsHelper
|
||||
{
|
||||
private static bool _isInit = false;
|
||||
private static readonly HashSet<string> _cacheData = new HashSet<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
public static void Init()
|
||||
{
|
||||
if (_isInit == false)
|
||||
{
|
||||
_isInit = true;
|
||||
var manifest = Resources.Load<BuildinFileManifest>("BuildinFileManifest");
|
||||
if (manifest != null)
|
||||
{
|
||||
foreach (string fileName in manifest.BuildinFiles)
|
||||
{
|
||||
_cacheData.Add(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内置文件查询方法
|
||||
/// </summary>
|
||||
public static bool FileExists(string packageName, string fileName)
|
||||
{
|
||||
if (_isInit == false)
|
||||
Init();
|
||||
return _cacheData.Contains(fileName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal class PreprocessBuild : UnityEditor.Build.IPreprocessBuildWithReport
|
||||
{
|
||||
public int callbackOrder { get { return 0; } }
|
||||
|
||||
/// <summary>
|
||||
/// 在构建应用程序前处理
|
||||
/// </summary>
|
||||
public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
|
||||
{
|
||||
string saveFilePath = "Assets/Resources/BuildinFileManifest.asset";
|
||||
if (File.Exists(saveFilePath))
|
||||
File.Delete(saveFilePath);
|
||||
|
||||
string folderPath = $"{Application.dataPath}/StreamingAssets/{StreamingAssetsDefine.RootFolderName}";
|
||||
DirectoryInfo root = new DirectoryInfo(folderPath);
|
||||
if (root.Exists == false)
|
||||
{
|
||||
Debug.Log($"没有发现YooAsset内置目录 : {folderPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
var manifest = ScriptableObject.CreateInstance<BuildinFileManifest>();
|
||||
FileInfo[] files = root.GetFiles("*", SearchOption.AllDirectories);
|
||||
foreach (var fileInfo in files)
|
||||
{
|
||||
if (fileInfo.Extension == ".meta")
|
||||
continue;
|
||||
if (fileInfo.Name.StartsWith("PackageManifest_"))
|
||||
continue;
|
||||
manifest.BuildinFiles.Add(fileInfo.Name);
|
||||
}
|
||||
|
||||
if (Directory.Exists("Assets/Resources") == false)
|
||||
Directory.CreateDirectory("Assets/Resources");
|
||||
UnityEditor.AssetDatabase.CreateAsset(manifest, saveFilePath);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
UnityEditor.AssetDatabase.Refresh();
|
||||
Debug.Log($"一共{manifest.BuildinFiles.Count}个内置文件,内置资源清单保存成功 : {saveFilePath}");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e22d54ed66a149198e471736a4e537d7
|
||||
timeCreated: 1708513920
|
|
@ -1,7 +0,0 @@
|
|||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public class StreamingAssetsDefine
|
||||
{
|
||||
public const string RootFolderName = "yoo";
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3cd0086ebeeb48d0bbad9622c5c577b8
|
||||
timeCreated: 1708514012
|
|
@ -1,7 +0,0 @@
|
|||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public static class YooAssetBuildStatus
|
||||
{
|
||||
public static bool isInBuild = false;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0982954dec7e4817aacc6acdf44b9cf3
|
||||
timeCreated: 1708490336
|
|
@ -1,116 +0,0 @@
|
|||
using Cysharp.Threading.Tasks;
|
||||
using PhxhSDK.AOT.VersionUpdate;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public class YooAssetHelper
|
||||
{
|
||||
public static ResourcePackage defaultPackage;
|
||||
public static ResourcePackage rawPackage;
|
||||
|
||||
public static async UniTask Init()
|
||||
{
|
||||
if (defaultPackage != null) return;
|
||||
// 初始化资源系统
|
||||
YooAssets.Initialize();
|
||||
|
||||
// 创建默认的资源包
|
||||
defaultPackage = YooAssets.CreatePackage("DefaultPackage");
|
||||
rawPackage = YooAssets.CreatePackage("RawPackage");
|
||||
|
||||
// 设置该资源包为默认的资源包,可以使用YooAssets相关加载接口加载该资源包内容。
|
||||
YooAssets.SetDefaultPackage(defaultPackage);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
#if AB_DEBUG
|
||||
await _InitRemote();
|
||||
#else
|
||||
await _InitEditor();
|
||||
#endif
|
||||
#else
|
||||
await _InitRemote();
|
||||
#endif
|
||||
}
|
||||
|
||||
private static async UniTask<bool> _InitEditor()
|
||||
{
|
||||
Debug.Log("[LTRes]开始初始化编辑器模拟模式");
|
||||
var initParametersDefault = new EditorSimulateModeParameters();
|
||||
initParametersDefault.AutoDestroyAssetProvider = true;
|
||||
initParametersDefault.SimulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild(EDefaultBuildPipeline.BuiltinBuildPipeline, "DefaultPackage");
|
||||
var op = defaultPackage.InitializeAsync(initParametersDefault);
|
||||
await op.Task;
|
||||
if (op.Status != EOperationStatus.Succeed)
|
||||
{
|
||||
Debug.LogError("[LTRes]初始化编辑器模拟模式失败");
|
||||
return false;
|
||||
}
|
||||
var initParametersRaw = new EditorSimulateModeParameters();
|
||||
initParametersRaw.AutoDestroyAssetProvider = true;
|
||||
initParametersRaw.SimulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild(EDefaultBuildPipeline.RawFileBuildPipeline, "RawPackage");
|
||||
var op2 = rawPackage.InitializeAsync(initParametersRaw);
|
||||
await op2.Task;
|
||||
if (op2.Status != EOperationStatus.Succeed)
|
||||
{
|
||||
Debug.LogError("[LTRes]初始化编辑器模拟模式失败");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async UniTask InitEditor()
|
||||
{
|
||||
await _InitEditor();
|
||||
}
|
||||
|
||||
private static async UniTask<bool> _InitRemote()
|
||||
{
|
||||
if (!_isInit)
|
||||
{
|
||||
_isInit = true;
|
||||
await _InitPackage(defaultPackage, false);
|
||||
await _InitPackage(rawPackage, true);
|
||||
Debug.Log("[LTRes]InitializeAsync 完成");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[LTRes]开始重新尝试初始化remote load");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool _isInit = false;
|
||||
private static async UniTask _InitPackage(ResourcePackage package, bool noEncrypt)
|
||||
{
|
||||
Debug.Log("开始初始化package:" + package);
|
||||
var initParameters = new HostPlayModeParameters();
|
||||
initParameters.AutoDestroyAssetProvider = true;
|
||||
initParameters.BuildinQueryServices = new GameQueryServices();
|
||||
// initParameters.DeliveryQueryServices = new GameDeliveryServices();
|
||||
if (noEncrypt)
|
||||
{
|
||||
initParameters.DecryptionServices = new YooDecryptionNone();
|
||||
}
|
||||
else
|
||||
{
|
||||
initParameters.DecryptionServices = new YooDecryptionFS();
|
||||
}
|
||||
|
||||
PackDataInst.CreateInst();
|
||||
var workSpace = PackDataInst.inst.localInfo.workSpace;
|
||||
var version = PackDataInst.inst.localInfo.version;
|
||||
var buildTarget = PackDataInst.GetRuntimePlatform();
|
||||
var serverUrl = PackDataInst.inst.localInfo.serverUrl;
|
||||
var pathRoot = PackDataInst.inst.localInfo.pathRoot;
|
||||
var hostPath = $"{serverUrl}/{pathRoot}/{workSpace}/{buildTarget}/{version}";
|
||||
initParameters.RemoteServices = new LTRemoteServices(hostPath);
|
||||
|
||||
await package.InitializeAsync(initParameters).Task;
|
||||
Debug.Log("初始化package结束:" + package);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a783ee08288c46c799a5f409eb5c65ea
|
||||
timeCreated: 1708495618
|
|
@ -1,24 +0,0 @@
|
|||
using System.IO;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public class YooDecryptionFS : IDecryptionServices
|
||||
{
|
||||
|
||||
public AssetBundle LoadAssetBundle(DecryptFileInfo fileInfo,
|
||||
out Stream managedStream)
|
||||
{
|
||||
managedStream = new CustomFileStream(fileInfo.FileLoadPath);
|
||||
return AssetBundle.LoadFromStream(managedStream);
|
||||
}
|
||||
|
||||
public AssetBundleCreateRequest LoadAssetBundleAsync(DecryptFileInfo fileInfo,
|
||||
out Stream managedStream)
|
||||
{
|
||||
managedStream = new CustomFileStream(fileInfo.FileLoadPath);
|
||||
return AssetBundle.LoadFromStreamAsync(managedStream);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 06fb2e9ce57845f0bdabda7c756334ba
|
||||
timeCreated: 1708668451
|
|
@ -1,22 +0,0 @@
|
|||
using System.IO;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
namespace PhxhSDK.AOT
|
||||
{
|
||||
public class YooDecryptionNone : IDecryptionServices
|
||||
{
|
||||
|
||||
public AssetBundle LoadAssetBundle(DecryptFileInfo fileInfo,
|
||||
out Stream managedStream)
|
||||
{
|
||||
managedStream = new FileStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read);
|
||||
return AssetBundle.LoadFromStream(managedStream);
|
||||
}
|
||||
public AssetBundleCreateRequest LoadAssetBundleAsync(DecryptFileInfo fileInfo,
|
||||
out Stream managedStream)
|
||||
{
|
||||
managedStream = new FileStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read);
|
||||
return AssetBundle.LoadFromStreamAsync(managedStream);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 540fa3c1015f486aa3be05a496c9d170
|
||||
timeCreated: 1708514119
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3f290986483554bde92a8a36ddc1704a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c12723bd0454c41b4806ab3381cff9a7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cee1b9a78f7514d5ba92ac5e927f489e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,104 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
[Serializable]
|
||||
[CreateAssetMenu(fileName = "MaterialImportSettings", menuName = "AssetImportSettings/MaterialImportSettings",
|
||||
order = 0)]
|
||||
public class MaterialImportSettings : ScriptableObject
|
||||
{
|
||||
private static bool _isDirtyLock = true;
|
||||
|
||||
[LabelText("Material设置")] public List<MaterialImportSetting> settings;
|
||||
|
||||
public static bool IsDirtyLock
|
||||
{
|
||||
set => _isDirtyLock = value;
|
||||
get
|
||||
{
|
||||
var r = _isDirtyLock;
|
||||
_isDirtyLock = false;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
[Button]
|
||||
public void Save()
|
||||
{
|
||||
IsDirtyLock = true;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class MaterialImportSetting
|
||||
{
|
||||
public const string MaterialImportSettingsPath = "Assets/Editor/Settings/MaterialImportSettings.asset";
|
||||
|
||||
public static string ExcludePostFix = "_CC";
|
||||
public static string NameFormatNone = "-";
|
||||
|
||||
public static readonly string[] NameFormatPre =
|
||||
{
|
||||
NameFormatNone, // none, dont move
|
||||
|
||||
"M_A",
|
||||
"M_B",
|
||||
"M_C",
|
||||
"M_E",
|
||||
"M_G",
|
||||
"M_N",
|
||||
"M_S"
|
||||
};
|
||||
|
||||
public static readonly string[] NameFormatPost =
|
||||
{
|
||||
NameFormatNone, // none, dont move
|
||||
|
||||
"_bar",
|
||||
"_cw",
|
||||
"_bow",
|
||||
"_dmr",
|
||||
"_ar",
|
||||
"_sg",
|
||||
"_lmg",
|
||||
"_hf",
|
||||
"_mg"
|
||||
};
|
||||
|
||||
public string name;
|
||||
|
||||
|
||||
[LabelText("名前缀")] [ValueDropdown("NameFormatPre")]
|
||||
public string PreFix;
|
||||
|
||||
[LabelText("名后缀")] [ValueDropdown("NameFormatPost")]
|
||||
public string PostFix;
|
||||
|
||||
|
||||
[ValueDropdown("AllShaderNames")] public string shaderName;
|
||||
|
||||
[ShowIf("shaderName", "NLD_URP/NLD_Charactor")]
|
||||
public string outlineColorName;
|
||||
|
||||
[ShowIf("shaderName", "NLD_URP/NLD_Charactor")]
|
||||
public Color outlineColor;
|
||||
|
||||
[ShowIf("shaderName", "NLD_URP/NLD_Charactor")]
|
||||
public string thickOfOutlineName;
|
||||
|
||||
[ShowIf("shaderName", "NLD_URP/NLD_Charactor")] [Range(0, 0.1f)]
|
||||
public float thickOfOutline;
|
||||
|
||||
[ShowIf("shaderName", "NLD_URP/NLD_Charactor")]
|
||||
public string factorName;
|
||||
|
||||
[ShowIf("shaderName", "NLD_URP/NLD_Charactor")] [Range(0, 1f)]
|
||||
public float factor;
|
||||
|
||||
|
||||
public string[] AllShaderNames =
|
||||
{
|
||||
"NLD_URP/NLD_Charactor"
|
||||
};
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1d33b14a14b99496e8c62e98e0cbf523
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,50 +0,0 @@
|
|||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class MaterialsPostprocessor : AssetPostprocessor
|
||||
{
|
||||
private static MaterialImportSettings config;
|
||||
|
||||
private void OnPostprocessMaterial(Material material)
|
||||
{
|
||||
UpdateMaterialSettings();
|
||||
|
||||
if (config == null) return;
|
||||
|
||||
var fileName = GetFileName(assetPath);
|
||||
|
||||
if (fileName.EndsWith(MaterialImportSetting.ExcludePostFix)) return;
|
||||
|
||||
|
||||
var settings = config.settings.Find(set => set.PreFix != MaterialImportSetting.NameFormatNone
|
||||
&& fileName.StartsWith(set.PreFix)
|
||||
&&
|
||||
(set.PostFix == MaterialImportSetting.NameFormatNone
|
||||
|| fileName.EndsWith(set.PostFix)));
|
||||
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
material.SetColor(settings.outlineColorName, settings.outlineColor);
|
||||
material.SetFloat(settings.thickOfOutlineName, settings.thickOfOutline);
|
||||
material.SetFloat(settings.factorName, settings.factor);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMaterialSettings()
|
||||
{
|
||||
if (config == null || MaterialImportSettings.IsDirtyLock)
|
||||
{
|
||||
config =
|
||||
AssetDatabase.LoadAssetAtPath<MaterialImportSettings>(MaterialImportSetting.MaterialImportSettingsPath);
|
||||
if (config == null) Debug.LogError("material format config is null");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string GetFileName(string assetPath)
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(assetPath);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 85e015d9b1baf4521999c8366748fedd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 595ddfe0ba6d143879db141104269478
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,47 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[Serializable]
|
||||
[CreateAssetMenu(fileName = "ModelImportSetting", menuName = "AssetImportSettings/ModelSettings", order = 0)]
|
||||
public class ModelImportSettings : ScriptableObject
|
||||
{
|
||||
public ModelImportSetting defaultImportSetting;
|
||||
public List<ModelImportSetting> settings;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ModelImportSetting
|
||||
{
|
||||
public enum BasedUpon
|
||||
{
|
||||
Original
|
||||
}
|
||||
|
||||
public enum NameFormatPost
|
||||
{
|
||||
none
|
||||
}
|
||||
|
||||
|
||||
public enum NameFormatPre
|
||||
{
|
||||
none
|
||||
}
|
||||
|
||||
public string Name;
|
||||
public NameFormatPre PreFix;
|
||||
public NameFormatPost PostFix;
|
||||
|
||||
|
||||
public bool rootRotationBakeIntoPose;
|
||||
public BasedUpon rootRotationBasedUpon;
|
||||
public bool rootPositionYBakeIntoPose;
|
||||
public BasedUpon rootPositionYBasedUpon;
|
||||
public bool rootPositionXZBakeIntoPose;
|
||||
public BasedUpon rootPositionXZBasedUpon;
|
||||
|
||||
|
||||
public ModelImporterAnimationCompression animationCompression;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ec2265d5373f3404c8ecdc99113af95e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,69 +0,0 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class ModelPostProcessor : AssetPostprocessor
|
||||
{
|
||||
private void OnPreprocessModel()
|
||||
{
|
||||
var config =
|
||||
AssetDatabase.LoadAssetAtPath<ModelImportSettings>("Assets/Editor/Settings/ModelImportSetting.asset");
|
||||
if (config == null)
|
||||
{
|
||||
Debug.LogError("Model format config is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var importer = assetImporter as ModelImporter;
|
||||
|
||||
var fileName = GetFileName(importer.assetPath);
|
||||
|
||||
// if (fileName.EndsWith("_cc"))
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
var settings = config.settings.Find(set =>
|
||||
(set.PreFix != ModelImportSetting.NameFormatPre.none &&
|
||||
fileName.ToLower().StartsWith(set.PreFix.ToString().ToLower())) ||
|
||||
(set.PostFix != ModelImportSetting.NameFormatPost.none &&
|
||||
fileName.ToLower().EndsWith(set.PostFix.ToString().ToLower())));
|
||||
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
var animations = importer.clipAnimations;
|
||||
if (animations != null)
|
||||
for (var i = 0; i < animations.Length; i++)
|
||||
SetAnimation(animations[i], config.defaultImportSetting);
|
||||
|
||||
importer.clipAnimations = animations;
|
||||
importer.animationCompression = config.defaultImportSetting.animationCompression;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAnimation(ModelImporterClipAnimation animation, ModelImportSetting importSetting)
|
||||
{
|
||||
animation.keepOriginalOrientation =
|
||||
importSetting.rootRotationBasedUpon == ModelImportSetting.BasedUpon.Original;
|
||||
animation.lockRootRotation = importSetting.rootRotationBakeIntoPose;
|
||||
|
||||
animation.keepOriginalPositionY = importSetting.rootPositionYBasedUpon == ModelImportSetting.BasedUpon.Original;
|
||||
animation.lockRootHeightY = importSetting.rootPositionYBakeIntoPose;
|
||||
|
||||
|
||||
animation.keepOriginalPositionXZ =
|
||||
importSetting.rootPositionXZBasedUpon == ModelImportSetting.BasedUpon.Original;
|
||||
animation.lockRootPositionXZ = importSetting.rootPositionXZBakeIntoPose;
|
||||
}
|
||||
|
||||
|
||||
private string GetFileName(string assetPath)
|
||||
{
|
||||
var fileName = assetPath.Remove(0, assetPath.LastIndexOf('/') + 1);
|
||||
var pointIndex = fileName.LastIndexOf('.');
|
||||
fileName = fileName.Remove(pointIndex, fileName.Length - pointIndex);
|
||||
|
||||
return fileName;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c0058c62bd07b4105aaabff7a6144da5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 572b9c54ed20b40439605f545b6e05a2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,36 +0,0 @@
|
|||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.Utilities;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEditor;
|
||||
|
||||
public class AssetProcessEditor : OdinMenuEditorWindow
|
||||
{
|
||||
[MenuItem("Tools/AssetProcessEditor")]
|
||||
private static void OpenWindow()
|
||||
{
|
||||
var window = GetWindow<AssetProcessEditor>();
|
||||
window.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600);
|
||||
}
|
||||
|
||||
protected override OdinMenuTree BuildMenuTree()
|
||||
{
|
||||
var tree = new OdinMenuTree(true)
|
||||
{
|
||||
{
|
||||
"Home", PrefabTools.Instance, SdfIconType.Box
|
||||
},
|
||||
{
|
||||
"Setting", null, SdfIconType.Gear
|
||||
}
|
||||
};
|
||||
|
||||
tree.AddAssetAtPath("Setting/Prefab", PrefabImportSetting.PrefabImportSettingsPath);
|
||||
|
||||
// As you can see, Odin provides a few ways to quickly add editors / objects to your menu tree.
|
||||
// The API also gives you full control over the selection, etc..
|
||||
// Make sure to check out the API Documentation for OdinMenuEditorWindow, OdinMenuTree and OdinMenuItem for more information on what you can do!
|
||||
|
||||
return tree;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1180e461b5b3e462ca3fa75143369233
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,103 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
[Serializable]
|
||||
[CreateAssetMenu(fileName = "PrefabImportSettings", menuName = "AssetImportSettings/PrefabImportSettings", order = 0)]
|
||||
public class PrefabImportSettings : ScriptableObject
|
||||
{
|
||||
[LabelText("Prefab规则")] public List<PrefabImportSetting> settings;
|
||||
|
||||
[Button]
|
||||
public void AddSetting()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class PrefabImportSetting
|
||||
{
|
||||
public const string PrefabImportSettingsPath = "Assets/Editor/Settings/PrefabImportSettings.asset";
|
||||
|
||||
public static string ExcludePostFix = "_CC";
|
||||
public static string NameFormatNone = "-";
|
||||
|
||||
public static readonly string[] NameFormatPre =
|
||||
{
|
||||
NameFormatNone, // none, dont move
|
||||
|
||||
"P_A",
|
||||
"P_B",
|
||||
"P_C",
|
||||
"P_E",
|
||||
"P_G",
|
||||
"P_N",
|
||||
"P_S",
|
||||
|
||||
"Skill_",
|
||||
"Bullet_"
|
||||
};
|
||||
|
||||
public static readonly string[] NameFormatPost =
|
||||
{
|
||||
NameFormatNone, // none, dont move
|
||||
|
||||
"_bar",
|
||||
"_cw",
|
||||
"_bow",
|
||||
"_dmr",
|
||||
"_ar",
|
||||
"_sg",
|
||||
"_lmg",
|
||||
"_hf",
|
||||
"_mg"
|
||||
};
|
||||
|
||||
public string name;
|
||||
|
||||
|
||||
[LabelText("名前缀")] [ValueDropdown("NameFormatPre")]
|
||||
public string PreFix;
|
||||
|
||||
[LabelText("名后缀")] [ValueDropdown("NameFormatPost")]
|
||||
public string PostFix;
|
||||
|
||||
|
||||
[ValueDropdown("AllLayerNames")] public int layer;
|
||||
|
||||
|
||||
[LabelText("绑胶囊体")] public bool bindCapsuleCollider;
|
||||
|
||||
[ShowIf("bindCapsuleCollider")] public float radius;
|
||||
|
||||
[ShowIf("bindCapsuleCollider")] public float height;
|
||||
|
||||
[ShowIf("bindCapsuleCollider")] public Vector3 center;
|
||||
|
||||
|
||||
[LabelText("处理SkinnedMeshRenderer")] public bool processSkinnedMeshRenderer;
|
||||
|
||||
[ShowIf("processSkinnedMeshRenderer")] public bool skinnedMotionVectors;
|
||||
|
||||
[LabelText("处理particle system")] public bool processParticlesSystem;
|
||||
|
||||
[ShowIf("processParticlesSystem")] public int maxParticles = 50;
|
||||
|
||||
public IEnumerable AllLayerNames()
|
||||
{
|
||||
var list = new ValueDropdownList<int>();
|
||||
|
||||
var totalLayers = 32; // Unity supports 32 layers by default
|
||||
// Loop through each layer and get its name
|
||||
for (var i = 0; i < totalLayers; i++)
|
||||
{
|
||||
var layerName = LayerMask.LayerToName(i);
|
||||
// Check if the layer name is not empty (i.e., it is defined)
|
||||
if (!string.IsNullOrEmpty(layerName)) list.Add(layerName, i);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8bc2d05bc013943f3836a4462e767326
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,154 +0,0 @@
|
|||
using System;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[Serializable]
|
||||
public class PrefabTools
|
||||
{
|
||||
private static PrefabTools _instance;
|
||||
|
||||
public static PrefabTools Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null) _instance = new PrefabTools();
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
[Button]
|
||||
public void ProcessAll()
|
||||
{
|
||||
_ProcessPrefabs();
|
||||
}
|
||||
|
||||
private void _ProcessTexture2Ds()
|
||||
{
|
||||
var allT2DGUIDs = AssetDatabase.FindAssets("t:Texture2D", new[] { "Assets/Art" });
|
||||
for (var i = 0; i < allT2DGUIDs.Length; i++)
|
||||
{
|
||||
var guid = allT2DGUIDs[i];
|
||||
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
_ProcessTexture2D(assetPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void _ProcessPrefabs()
|
||||
{
|
||||
try
|
||||
{
|
||||
var allPrefabs = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Art" });
|
||||
|
||||
for (var i = 0; i < allPrefabs.Length; i++)
|
||||
{
|
||||
var guid = allPrefabs[i];
|
||||
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var gameObject = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
|
||||
if (gameObject != null) ProcessPrefab(gameObject, assetPath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _ProcessTexture2D(string assetPath)
|
||||
{
|
||||
var texture2D = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);
|
||||
if (texture2D == null) return;
|
||||
var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
|
||||
}
|
||||
|
||||
|
||||
public static void ProcessPrefab(GameObject go, string assetPath)
|
||||
{
|
||||
if (go == null)
|
||||
{
|
||||
Debug.LogError($"Prefab is null, assetPath = {assetPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
var config = AssetDatabase.LoadAssetAtPath<PrefabImportSettings>(PrefabImportSetting.PrefabImportSettingsPath);
|
||||
if (config == null)
|
||||
{
|
||||
Debug.LogError("Prefab Import config is null");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var fileName = GetFileName(assetPath);
|
||||
|
||||
if (fileName.EndsWith(PrefabImportSetting.ExcludePostFix)) return;
|
||||
// 同时满足前缀后缀
|
||||
var settings = config.settings.Find(set => set.PreFix != PrefabImportSetting.NameFormatNone
|
||||
&& fileName.StartsWith(set.PreFix)
|
||||
&&
|
||||
set.PostFix != PrefabImportSetting.NameFormatNone
|
||||
&& fileName.EndsWith(set.PostFix));
|
||||
|
||||
// 前缀后缀满足其一
|
||||
if (settings == null)
|
||||
settings = config.settings.Find(set => (
|
||||
set.PreFix != PrefabImportSetting.NameFormatNone
|
||||
&& fileName.StartsWith(set.PreFix))
|
||||
||
|
||||
(set.PostFix != PrefabImportSetting.NameFormatNone
|
||||
&& fileName.EndsWith(set.PostFix)));
|
||||
|
||||
// 默认设置
|
||||
if (settings == null)
|
||||
settings = config.settings.Find(set => fileName.StartsWith(PrefabImportSetting.NameFormatNone)
|
||||
&&
|
||||
fileName.EndsWith(PrefabImportSetting.NameFormatNone));
|
||||
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
if (settings.bindCapsuleCollider)
|
||||
if (go.GetComponent<CapsuleCollider>() == null)
|
||||
{
|
||||
var capsuleCollider = go.AddComponent<CapsuleCollider>();
|
||||
capsuleCollider.radius = settings.radius;
|
||||
capsuleCollider.center = settings.center;
|
||||
capsuleCollider.height = settings.height;
|
||||
}
|
||||
|
||||
go.layer = settings.layer;
|
||||
|
||||
if (settings.processSkinnedMeshRenderer)
|
||||
{
|
||||
var smrs = go.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
if (smrs != null)
|
||||
for (var i = 0; i < smrs.Length; i++)
|
||||
smrs[i].skinnedMotionVectors = settings.skinnedMotionVectors;
|
||||
}
|
||||
|
||||
if (settings.processParticlesSystem)
|
||||
{
|
||||
var pss = go.GetComponentsInChildren<ParticleSystem>();
|
||||
if (pss != null)
|
||||
for (var i = 0; i < pss.Length; i++)
|
||||
{
|
||||
var ps = pss[i];
|
||||
ps.maxParticles = settings.maxParticles;
|
||||
}
|
||||
}
|
||||
|
||||
// VersionControlSystem.Checkout(assetPath);
|
||||
PrefabUtility.SavePrefabAsset(go);
|
||||
// VersionControlSystem.Revert(assetPath, RevertMode.Unchanged);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetFileName(string assetPath)
|
||||
{
|
||||
var fileName = assetPath.Remove(0, assetPath.LastIndexOf('/') + 1);
|
||||
var pointIndex = fileName.LastIndexOf('.');
|
||||
fileName = fileName.Remove(pointIndex, fileName.Length - pointIndex);
|
||||
|
||||
return fileName;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9a0edacf4f6b46e5b2b59d9b2a9f1e51
|
||||
timeCreated: 1690528911
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 86d4e4f851d494ba68f47daa0153d149
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,63 +0,0 @@
|
|||
public static class TextureFormatSettingConst
|
||||
{
|
||||
public const string TextureFormatSettingsPath = "Assets/Editor/Settings/TextureFormatSettings.asset";
|
||||
|
||||
public static string ExcludePostFix = "_CC";
|
||||
public static string NameFormatNone = "-";
|
||||
|
||||
public static readonly string[] NameFormatPre =
|
||||
{
|
||||
NameFormatNone, // none, dont move
|
||||
|
||||
"UI_",
|
||||
"BG_",
|
||||
|
||||
"Poster_",
|
||||
"Icon_",
|
||||
"Gfx_",
|
||||
"T_A",
|
||||
"T_E",
|
||||
"T_G",
|
||||
"T_C",
|
||||
"T_B",
|
||||
"T_emoji",
|
||||
"T_S",
|
||||
"T_emoji_lian_",
|
||||
"T_F",
|
||||
"Map",
|
||||
"split",
|
||||
"Skybox_",
|
||||
"Combie"
|
||||
};
|
||||
|
||||
public static readonly string[] NameFormatPost =
|
||||
{
|
||||
NameFormatNone, // none, dont move
|
||||
|
||||
"_slh",
|
||||
"_mask",
|
||||
"_d",
|
||||
"_surface"
|
||||
};
|
||||
|
||||
public static readonly string[] EndDress =
|
||||
{
|
||||
NameFormatNone,
|
||||
|
||||
".jpg",
|
||||
".png"
|
||||
};
|
||||
|
||||
public static readonly string[] TextureMaxSize =
|
||||
{
|
||||
"32",
|
||||
"64",
|
||||
"128",
|
||||
"256",
|
||||
"512",
|
||||
"1024",
|
||||
"2048",
|
||||
"4096",
|
||||
"8192"
|
||||
};
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b8956928438d341afaa07921ffcd9f8a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,135 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof(TextureFormatSettings))]
|
||||
public class TextureFormatSettingInspector : Editor
|
||||
{
|
||||
private TextureFormatSettings targetSettings;
|
||||
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
targetSettings = target as TextureFormatSettings;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.LabelField("排除后缀为", TextureFormatSettingConst.ExcludePostFix);
|
||||
|
||||
|
||||
for (var i = 0; i < targetSettings.settings.Count; i++)
|
||||
{
|
||||
var setting = targetSettings.settings[i];
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
setting.Name = EditorGUILayout.TextField("种类", setting.Name);
|
||||
if (GUILayout.Button("↑") && i > 0)
|
||||
{
|
||||
targetSettings.settings[i] = targetSettings.settings[i - 1];
|
||||
targetSettings.settings[i - 1] = setting;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("↓") && i < targetSettings.settings.Count - 1)
|
||||
{
|
||||
targetSettings.settings[i] = targetSettings.settings[i + 1];
|
||||
targetSettings.settings[i + 1] = setting;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("删"))
|
||||
{
|
||||
for (var j = i + 1; j < targetSettings.settings.Count; j++)
|
||||
targetSettings.settings[j - 1] = targetSettings.settings[j];
|
||||
targetSettings.settings.RemoveAt(targetSettings.settings.Count - 1);
|
||||
setting = targetSettings.settings[i];
|
||||
}
|
||||
}
|
||||
|
||||
setting.InspectorFoldOut = EditorGUILayout.Foldout(setting.InspectorFoldOut, "");
|
||||
if (setting.InspectorFoldOut)
|
||||
{
|
||||
setting.PreFix = EditorGUILayoutPopup("前缀", setting.PreFix, TextureFormatSettingConst.NameFormatPre);
|
||||
setting.PostFix = EditorGUILayoutPopup("后缀", setting.PostFix, TextureFormatSettingConst.NameFormatPost);
|
||||
setting.EndDress = EditorGUILayoutPopup("文件类型", setting.EndDress, TextureFormatSettingConst.EndDress);
|
||||
|
||||
setting.ImporterType =
|
||||
(TextureImporterType)EditorGUILayout.EnumPopup("Texture Type", setting.ImporterType);
|
||||
setting.ImporterShape =
|
||||
(TextureImporterShape)EditorGUILayout.EnumPopup("Texture Shape", setting.ImporterShape);
|
||||
setting.GeneratePhysicShape =
|
||||
EditorGUILayout.Toggle("Generate Physic Shape", setting.GeneratePhysicShape);
|
||||
setting.MaxSize = int.Parse(EditorGUILayoutPopup("Max Size", setting.MaxSize.ToString(),
|
||||
TextureFormatSettingConst.TextureMaxSize));
|
||||
setting.StandaloneMaxSize = int.Parse(EditorGUILayoutPopup("standalone max size",
|
||||
setting.StandaloneMaxSize.ToString(), TextureFormatSettingConst.TextureMaxSize));
|
||||
setting.MipMap = EditorGUILayout.Toggle("Mip Maps", setting.MipMap);
|
||||
setting.ForceAlphaSetting = EditorGUILayout.Toggle("force alpha", setting.ForceAlphaSetting);
|
||||
setting.Alpha = (TextureImporterAlphaSource)EditorGUILayout.EnumPopup("alpha source", setting.Alpha);
|
||||
setting.WrapMode = (TextureWrapMode)EditorGUILayout.EnumPopup("wrap mode", setting.WrapMode);
|
||||
setting.IsReadable = EditorGUILayout.Toggle("is readable", setting.IsReadable);
|
||||
setting.FilterMode = (FilterMode)EditorGUILayout.EnumPopup("filter mode", setting.FilterMode);
|
||||
setting.NPOT = (TextureImporterNPOTScale)EditorGUILayout.EnumPopup("Non-Power of 2", setting.NPOT);
|
||||
|
||||
setting.FormatIos = (TextureImporterFormat)EditorGUILayout.EnumPopup("IOS Format", setting.FormatIos);
|
||||
setting.FormatAndroid =
|
||||
(TextureImporterFormat)EditorGUILayout.EnumPopup("Android Format", setting.FormatAndroid);
|
||||
setting.FormatIosAlpha =
|
||||
(TextureImporterFormat)EditorGUILayout.EnumPopup("IOS Alpha Format", setting.FormatIosAlpha);
|
||||
setting.FormatAndroidAlpha =
|
||||
(TextureImporterFormat)EditorGUILayout.EnumPopup("Android Alpha Format",
|
||||
setting.FormatAndroidAlpha);
|
||||
setting.FormatStandalone =
|
||||
(TextureImporterFormat)EditorGUILayout.EnumPopup("Standalone Format", setting.FormatStandalone);
|
||||
setting.FormatStandaloneAlpha =
|
||||
(TextureImporterFormat)EditorGUILayout.EnumPopup("Standalone Alpha Format",
|
||||
setting.FormatStandaloneAlpha);
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("+")) targetSettings.settings.Add(new TextureFormatSetting { Name = "未知" });
|
||||
|
||||
TextureFormatSettings.IsDirtyLock = true;
|
||||
EditorUtility.SetDirty(targetSettings);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Save"))
|
||||
{
|
||||
}
|
||||
|
||||
if (GUILayout.Button("ReImport All Textures"))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int FindIndex<T>(IReadOnlyList<T> collection, T value)
|
||||
{
|
||||
if (collection != null)
|
||||
for (var i = 0; i < collection.Count; i++)
|
||||
if (collection[i].Equals(value))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
private string EditorGUILayoutPopup(string label, string selected, string[] displayOption)
|
||||
{
|
||||
try
|
||||
{
|
||||
var index = EditorGUILayout.Popup(label, FindIndex(displayOption, selected), displayOption);
|
||||
return displayOption[index >= 0 ? index : 0];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e5fd574fa651d45b69d4187aa0a520da
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,75 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
[Serializable]
|
||||
[CreateAssetMenu(fileName = "TextureFormatSettings", menuName = "ResourceImportSettings/TextureFormatSettings",
|
||||
order = 0)]
|
||||
public class TextureFormatSettings : ScriptableObject
|
||||
{
|
||||
private static bool _isDirtyLock = true;
|
||||
public List<TextureFormatSetting> settings;
|
||||
|
||||
public static bool IsDirtyLock
|
||||
{
|
||||
set => _isDirtyLock = value;
|
||||
get
|
||||
{
|
||||
var r = _isDirtyLock;
|
||||
_isDirtyLock = false;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class TextureFormatSetting
|
||||
{
|
||||
public string Name;
|
||||
public string PreFix;
|
||||
public string PostFix;
|
||||
public string EndDress;
|
||||
|
||||
public TextureImporterType ImporterType;
|
||||
public TextureImporterShape ImporterShape = TextureImporterShape.Texture2D;
|
||||
public bool GeneratePhysicShape;
|
||||
public int MaxSize;
|
||||
public int StandaloneMaxSize;
|
||||
public bool MipMap;
|
||||
public bool ForceAlphaSetting = true;
|
||||
public TextureImporterAlphaSource Alpha;
|
||||
public TextureWrapMode WrapMode;
|
||||
|
||||
public bool IsReadable;
|
||||
|
||||
public FilterMode FilterMode = FilterMode.Bilinear;
|
||||
public TextureImporterNPOTScale NPOT = TextureImporterNPOTScale.ToNearest;
|
||||
|
||||
public TextureImporterFormat FormatIos = TextureImporterFormat.ASTC_5x5;
|
||||
public TextureImporterFormat FormatAndroid = TextureImporterFormat.ASTC_5x5;
|
||||
public TextureImporterFormat FormatIosAlpha = TextureImporterFormat.ASTC_5x5;
|
||||
public TextureImporterFormat FormatAndroidAlpha = TextureImporterFormat.ASTC_5x5;
|
||||
public TextureImporterFormat FormatStandalone = TextureImporterFormat.RGB24;
|
||||
public TextureImporterFormat FormatStandaloneAlpha = TextureImporterFormat.RGBA32;
|
||||
|
||||
|
||||
public bool InspectorFoldOut;
|
||||
|
||||
|
||||
public TextureImporterFormat GetFormatIos(bool hasAlpha)
|
||||
{
|
||||
return hasAlpha ? FormatIosAlpha : FormatIos;
|
||||
}
|
||||
|
||||
public TextureImporterFormat GetFormatAndroid(bool hasAlpha)
|
||||
{
|
||||
return hasAlpha ? FormatAndroidAlpha : FormatAndroid;
|
||||
}
|
||||
|
||||
public TextureImporterFormat GetFormatStandalone(bool hasAlpha)
|
||||
{
|
||||
return hasAlpha ? FormatStandaloneAlpha : FormatStandalone;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 241fd960f87d34d42b47d6058bfdb0e6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,21 +0,0 @@
|
|||
using System.IO;
|
||||
|
||||
public partial class TextureProcessor
|
||||
{
|
||||
private string CheckName(string fileName)
|
||||
{
|
||||
if (fileName.Contains("ReflectionProbe-"))
|
||||
{
|
||||
var index = fileName.LastIndexOf("-");
|
||||
fileName = fileName.Remove(index, fileName.Length - index);
|
||||
fileName += "_";
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private string GetFileName(string assetPath)
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(assetPath);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 090220ad1333849d1ad579d5b2701559
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,192 +0,0 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public partial class TextureProcessor : AssetPostprocessor
|
||||
{
|
||||
private static TextureFormatSettings config;
|
||||
|
||||
private void OnPreprocessTexture()
|
||||
{
|
||||
UpdateTextureFormatSettings();
|
||||
|
||||
if (config == null) return;
|
||||
|
||||
var textureImporter = assetImporter as TextureImporter;
|
||||
var fileName = GetFileName(textureImporter.assetPath);
|
||||
|
||||
if (fileName.EndsWith(TextureFormatSettingConst.ExcludePostFix)) return;
|
||||
|
||||
fileName = CheckName(fileName);
|
||||
|
||||
var settings = config.settings.Find(set => (
|
||||
set.PreFix != TextureFormatSettingConst.NameFormatNone
|
||||
&& fileName.StartsWith(set.PreFix))
|
||||
||
|
||||
(set.PostFix != TextureFormatSettingConst.NameFormatNone
|
||||
&& fileName.EndsWith(set.PostFix)));
|
||||
|
||||
|
||||
var handleSize = true;
|
||||
var handleType = true;
|
||||
var handleShape = true;
|
||||
var handlePhysicsShape = true;
|
||||
var handleAlpha = true;
|
||||
var handleFormat = true;
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
handleSize = false;
|
||||
handleType = false;
|
||||
handleShape = false;
|
||||
handlePhysicsShape = false;
|
||||
handleAlpha = false;
|
||||
handleFormat = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//size
|
||||
var maxSize = settings.MaxSize;
|
||||
|
||||
//Type
|
||||
if (handleType) textureImporter.textureType = settings.ImporterType;
|
||||
|
||||
//Shape
|
||||
if (handleShape) textureImporter.textureShape = settings.ImporterShape;
|
||||
|
||||
//Physics Shape
|
||||
if (handlePhysicsShape)
|
||||
{
|
||||
var importerSettings = new TextureImporterSettings();
|
||||
textureImporter.ReadTextureSettings(importerSettings);
|
||||
importerSettings.spriteGenerateFallbackPhysicsShape = settings.GeneratePhysicShape;
|
||||
textureImporter.SetTextureSettings(importerSettings);
|
||||
}
|
||||
|
||||
|
||||
//Alpha
|
||||
if (handleAlpha)
|
||||
{
|
||||
if (settings.ForceAlphaSetting)
|
||||
{
|
||||
textureImporter.alphaSource = settings.Alpha;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (textureImporter.DoesSourceTextureHaveAlpha())
|
||||
{
|
||||
textureImporter.alphaSource = TextureImporterAlphaSource.FromInput;
|
||||
textureImporter.alphaIsTransparency = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
textureImporter.alphaSource = TextureImporterAlphaSource.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Format & MaxSize
|
||||
var psAndroid = textureImporter.GetPlatformTextureSettings("Android");
|
||||
var psIPhone = textureImporter.GetPlatformTextureSettings("iPhone");
|
||||
var psStandalone = textureImporter.GetPlatformTextureSettings("Standalone");
|
||||
psAndroid.overridden = true;
|
||||
psIPhone.overridden = true;
|
||||
psStandalone.overridden = true;
|
||||
|
||||
if (handleSize)
|
||||
{
|
||||
psIPhone.maxTextureSize = maxSize;
|
||||
psAndroid.maxTextureSize = maxSize;
|
||||
psStandalone.maxTextureSize = settings.StandaloneMaxSize;
|
||||
}
|
||||
|
||||
if (handleFormat)
|
||||
{
|
||||
var hasAlpha = textureImporter.DoesSourceTextureHaveAlpha();
|
||||
psAndroid.format = settings.GetFormatAndroid(hasAlpha);
|
||||
psIPhone.format = settings.GetFormatIos(hasAlpha);
|
||||
psStandalone.format = settings.GetFormatStandalone(hasAlpha);
|
||||
}
|
||||
|
||||
textureImporter.SetPlatformTextureSettings(psAndroid);
|
||||
textureImporter.SetPlatformTextureSettings(psIPhone);
|
||||
textureImporter.SetPlatformTextureSettings(psStandalone);
|
||||
|
||||
|
||||
// //设置Read/Write Enabled开关,不勾选
|
||||
// textureImporter.isReadable = false;
|
||||
|
||||
//mipmap
|
||||
textureImporter.mipmapEnabled = settings.MipMap;
|
||||
|
||||
textureImporter.wrapMode = settings.WrapMode;
|
||||
|
||||
textureImporter.isReadable = settings.IsReadable;
|
||||
|
||||
textureImporter.filterMode = settings.FilterMode;
|
||||
|
||||
textureImporter.npotScale = settings.NPOT;
|
||||
|
||||
void UpdateTextureFormatSettings()
|
||||
{
|
||||
if (config == null || TextureFormatSettings.IsDirtyLock)
|
||||
{
|
||||
config =
|
||||
AssetDatabase.LoadAssetAtPath<TextureFormatSettings>(TextureFormatSettingConst
|
||||
.TextureFormatSettingsPath);
|
||||
if (config == null) Debug.LogError("Texture format config is null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private TextureImporterFormat GetFormat(string platForm, bool hasAlpha)
|
||||
// {
|
||||
// if (platForm == "iPhone")
|
||||
// {
|
||||
// var format = TextureImporterFormat.ASTC_RGB_4x4;
|
||||
// if (hasAlpha) format = TextureImporterFormat.ASTC_RGBA_4x4;
|
||||
|
||||
// return format;
|
||||
// }
|
||||
|
||||
// if (platForm == "Android")
|
||||
// {
|
||||
// var format = TextureImporterFormat.ETC2_RGB4;
|
||||
// if (hasAlpha) format = TextureImporterFormat.ETC2_RGBA8;
|
||||
|
||||
// return format;
|
||||
// }
|
||||
|
||||
// return TextureImporterFormat.RGBA32;
|
||||
// }
|
||||
|
||||
|
||||
// [MenuItem("校验工具/Session01")]
|
||||
// static public void AutoValidate() {
|
||||
// //写入csv日志
|
||||
// StreamWriter sw = new StreamWriter("ValidateS01.csv", false, System.Text.Encoding.UTF8);
|
||||
// sw.WriteLine("Validate -- Session01");
|
||||
|
||||
// string[] allAssets = AssetDatabase.GetAllAssetPaths();
|
||||
// foreach (string s in allAssets) {
|
||||
// if (s.StartsWith("Assets/")) {
|
||||
// Texture tex = AssetDatabase.LoadAssetAtPath(s, typeof(Texture)) as Texture;
|
||||
|
||||
// if (tex) {
|
||||
// //检测纹理资源命名是否合法
|
||||
// if (!Regex.IsMatch(s, @"^[a-zA-Z][a-zA-Z0-9_/.]*$")) {
|
||||
// sw.WriteLine(string.Format("illegal texture filename,{0}", s));
|
||||
// }
|
||||
|
||||
// //判断纹理尺寸是否符合四的倍数
|
||||
// if (((tex.width % 4) != 0) || ((tex.height % 4) != 0)) {
|
||||
// sw.WriteLine(string.Format("illegal texture W/H size,{0},{1},{2}", s, tex.width, tex.height));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// sw.Flush();
|
||||
// sw.Close();
|
||||
// }
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 79db869ee1fd842c399871dfa471726a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b08651cbbe20cef42a533ea68ddc5c7c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,44 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public static class VideoFormatSettingConst
|
||||
{
|
||||
/// <summary>
|
||||
/// 视频格式设置路径
|
||||
/// </summary>
|
||||
public const string VideoFormatSettingsPath = "Assets/Editor/Settings/VideoFormatSettings.asset";
|
||||
/// <summary>
|
||||
/// 忽略后缀
|
||||
/// </summary>
|
||||
public static string ExcludePostFix = "_CC";
|
||||
public static string NameFormatNone = "-";
|
||||
|
||||
/// <summary>
|
||||
/// 前缀
|
||||
/// </summary>
|
||||
public static readonly string[] NameFormatPre =
|
||||
{
|
||||
NameFormatNone, // none, dont move
|
||||
|
||||
"Raffle_", // 抽卡
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 后缀
|
||||
/// </summary>
|
||||
public static readonly string[] NameFormatPost =
|
||||
{
|
||||
NameFormatNone, // none, dont move
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 文件类型
|
||||
/// </summary>
|
||||
public static readonly string[] EndDress =
|
||||
{
|
||||
NameFormatNone,
|
||||
|
||||
".mp4",
|
||||
};
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b90a2566d59018e4abed2a25f2ea56a2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,138 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof(VideoFormatSettings))]
|
||||
public class VideoFormatSettingInspector : Editor
|
||||
{
|
||||
private VideoFormatSettings targetSettings;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
targetSettings = target as VideoFormatSettings;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.LabelField("排除后缀为", VideoFormatSettingConst.ExcludePostFix);
|
||||
|
||||
for (var i = 0; i < targetSettings.ListSetting.Count; i++)
|
||||
{
|
||||
VideoFormatSetting setting = targetSettings.ListSetting[i];
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
setting.Name = EditorGUILayout.TextField("种类", setting.Name);
|
||||
if (GUILayout.Button("↑") && i > 0)
|
||||
{
|
||||
targetSettings.ListSetting[i] = targetSettings.ListSetting[i - 1];
|
||||
targetSettings.ListSetting[i - 1] = setting;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("↓") && i < targetSettings.ListSetting.Count - 1)
|
||||
{
|
||||
targetSettings.ListSetting[i] = targetSettings.ListSetting[i + 1];
|
||||
targetSettings.ListSetting[i + 1] = setting;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("删"))
|
||||
{
|
||||
for (int j = i + 1; j < targetSettings.ListSetting.Count; ++j)
|
||||
{
|
||||
targetSettings.ListSetting[j - 1] = targetSettings.ListSetting[j];
|
||||
}
|
||||
|
||||
targetSettings.ListSetting.RemoveAt(targetSettings.ListSetting.Count - 1);
|
||||
|
||||
if (i < targetSettings.ListSetting.Count)
|
||||
setting = targetSettings.ListSetting[i];
|
||||
}
|
||||
}
|
||||
|
||||
setting.IsInspectorFoldOut = EditorGUILayout.Foldout(setting.IsInspectorFoldOut, "");
|
||||
if (setting.IsInspectorFoldOut)
|
||||
{
|
||||
setting.PreFix = EditorGUILayoutPopup("前缀", setting.PreFix, VideoFormatSettingConst.NameFormatPre);
|
||||
setting.PostFix = EditorGUILayoutPopup("后缀", setting.PostFix, VideoFormatSettingConst.NameFormatPost);
|
||||
setting.EndDress = EditorGUILayoutPopup("文件类型", setting.EndDress, VideoFormatSettingConst.EndDress);
|
||||
|
||||
setting.EnableTranscoding = EditorGUILayout.Toggle("EnableTranscoding", setting.EnableTranscoding);
|
||||
setting.ResizeMode = (VideoResizeMode)EditorGUILayout.EnumPopup("ResizeMode", setting.ResizeMode);
|
||||
setting.AspectRatio = (VideoEncodeAspectRatio)EditorGUILayout.EnumPopup("AspectRatio", setting.AspectRatio);
|
||||
setting.Codec = (VideoCodec)EditorGUILayout.EnumPopup("Codec", setting.Codec);
|
||||
setting.BitrateMode = (VideoBitrateMode)EditorGUILayout.EnumPopup("BitrateMode", setting.BitrateMode);
|
||||
setting.SpatialQuality = (VideoSpatialQuality)EditorGUILayout.EnumPopup("SpatialQuality", setting.SpatialQuality);
|
||||
setting.DeinterlaceMode = (VideoDeinterlaceMode)EditorGUILayout.EnumPopup("DeinterlaceMode", setting.DeinterlaceMode);
|
||||
setting.FlipHorizontal = EditorGUILayout.Toggle("FlipHorizontal", setting.FlipHorizontal);
|
||||
setting.FlipVertical = EditorGUILayout.Toggle("FlipVertical", setting.FlipVertical);
|
||||
setting.ImportAudio = EditorGUILayout.Toggle("ImportAudio", setting.ImportAudio);
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("+"))
|
||||
targetSettings.ListSetting.Add(new VideoFormatSetting { Name = "未知" });
|
||||
|
||||
TextureFormatSettings.IsDirtyLock = true;
|
||||
EditorUtility.SetDirty(targetSettings);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Save"))
|
||||
{
|
||||
}
|
||||
|
||||
if (GUILayout.Button("ReImport All Video"))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找索引
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="collection"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
private int FindIndex<T>(IReadOnlyList<T> collection, T value)
|
||||
{
|
||||
if (null == collection)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < collection.Count; ++i)
|
||||
{
|
||||
if (collection[i].Equals(value))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 弹出框
|
||||
/// </summary>
|
||||
/// <param name="label"></param>
|
||||
/// <param name="selected"></param>
|
||||
/// <param name="displayOption"></param>
|
||||
/// <returns></returns>
|
||||
private string EditorGUILayoutPopup(string label, string selected, string[] displayOption)
|
||||
{
|
||||
try
|
||||
{
|
||||
int index = EditorGUILayout.Popup(label, FindIndex(displayOption, selected), displayOption);
|
||||
return displayOption[index >= 0 ? index : 0];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 16497f7524ba1424e87ce23bba4d4398
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,62 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Video;
|
||||
|
||||
/// <summary>
|
||||
/// 视频格式设置
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[CreateAssetMenu(fileName = "VideoFormatSettings", menuName = "ResourceImportSettings/VideoFormatSettings", order = 0)]
|
||||
public class VideoFormatSettings : ScriptableObject
|
||||
{
|
||||
private static bool isDirtyLock = true;
|
||||
public List<VideoFormatSetting> ListSetting;
|
||||
|
||||
public static bool IsDirtyLock
|
||||
{
|
||||
get
|
||||
{
|
||||
bool r = isDirtyLock;
|
||||
isDirtyLock = false;
|
||||
|
||||
return r;
|
||||
}
|
||||
set { isDirtyLock = value; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class VideoFormatSetting
|
||||
{
|
||||
public string Name;
|
||||
/// <summary>
|
||||
/// 前缀
|
||||
/// </summary>
|
||||
public string PreFix;
|
||||
/// <summary>
|
||||
/// 后缀
|
||||
/// </summary>
|
||||
public string PostFix;
|
||||
/// <summary>
|
||||
/// 文件类型
|
||||
/// </summary>
|
||||
public string EndDress;
|
||||
|
||||
public bool EnableTranscoding = true;
|
||||
public VideoResizeMode ResizeMode = VideoResizeMode.HalfRes;
|
||||
public VideoEncodeAspectRatio AspectRatio = VideoEncodeAspectRatio.Stretch;
|
||||
public VideoCodec Codec = VideoCodec.VP8;
|
||||
public VideoBitrateMode BitrateMode = VideoBitrateMode.High;
|
||||
public VideoSpatialQuality SpatialQuality = VideoSpatialQuality.HighSpatialQuality;
|
||||
|
||||
public VideoDeinterlaceMode DeinterlaceMode = VideoDeinterlaceMode.Off;
|
||||
public bool FlipHorizontal = false;
|
||||
public bool FlipVertical = false;
|
||||
public bool ImportAudio = true;
|
||||
|
||||
public bool IsInspectorFoldOut;
|
||||
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6f2876953098c9f468aa6cad3c6df275
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,21 +0,0 @@
|
|||
using System.IO;
|
||||
|
||||
public partial class VideoProcessor
|
||||
{
|
||||
private string CheckName(string fileName)
|
||||
{
|
||||
if (fileName.Contains("ReflectionProbe-"))
|
||||
{
|
||||
int index = fileName.LastIndexOf("-");
|
||||
fileName = fileName.Remove(index, fileName.Length - index);
|
||||
fileName += "_";
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private string GetFileName(string assetPath)
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(assetPath);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0f81d25e10192b8478e006c0f5729ffd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,88 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public partial class VideoProcessor : AssetPostprocessor
|
||||
{
|
||||
private static VideoFormatSettings config;
|
||||
|
||||
private void OnPreprocessAsset()
|
||||
{
|
||||
string endDress = Path.GetExtension(assetPath).ToLower();
|
||||
if (!endDress.Equals(".mp4") &&
|
||||
!endDress.Equals(".mov") &&
|
||||
!endDress.Equals(".avi"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateVideoFormatSettings();
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
// 设置导入设置
|
||||
VideoClipImporter videoImporter = assetImporter as VideoClipImporter;
|
||||
if (null == videoImporter)
|
||||
return;
|
||||
|
||||
string fileName = GetFileName(videoImporter.assetPath);
|
||||
|
||||
if (fileName.EndsWith(VideoFormatSettingConst.ExcludePostFix))
|
||||
return;
|
||||
|
||||
fileName = CheckName(fileName);
|
||||
|
||||
VideoFormatSetting settings = config.ListSetting.Find(set =>
|
||||
(
|
||||
set.PreFix != TextureFormatSettingConst.NameFormatNone && fileName.StartsWith(set.PreFix)) ||
|
||||
(set.PostFix != TextureFormatSettingConst.NameFormatNone && fileName.EndsWith(set.PostFix))
|
||||
);
|
||||
|
||||
#region 设置视频的导入格式和输出分辨率
|
||||
VideoImporterTargetSettings androidSetting = videoImporter.GetTargetSettings("Android");
|
||||
VideoImporterTargetSettings iosSetting = videoImporter.GetTargetSettings("iPhone");
|
||||
if (androidSetting != null && iosSetting != null) // 已经设置过的不重复设置
|
||||
{
|
||||
if (androidSetting.enableTranscoding == settings.EnableTranscoding && iosSetting.enableTranscoding == settings.EnableTranscoding &&
|
||||
androidSetting.resizeMode == settings.ResizeMode && iosSetting.resizeMode == settings.ResizeMode &&
|
||||
androidSetting.aspectRatio == settings.AspectRatio && iosSetting.aspectRatio == settings.AspectRatio &&
|
||||
androidSetting.codec == settings.Codec && iosSetting.codec == settings.Codec &&
|
||||
androidSetting.bitrateMode == settings.BitrateMode && iosSetting.bitrateMode == settings.BitrateMode &&
|
||||
androidSetting.spatialQuality == settings.SpatialQuality && iosSetting.spatialQuality == settings.SpatialQuality)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VideoImporterTargetSettings targetSettings = new()
|
||||
{
|
||||
enableTranscoding = settings.EnableTranscoding,
|
||||
resizeMode = settings.ResizeMode,
|
||||
aspectRatio = settings.AspectRatio,
|
||||
codec = settings.Codec,
|
||||
bitrateMode = settings.BitrateMode,
|
||||
spatialQuality = settings.SpatialQuality,
|
||||
|
||||
};
|
||||
|
||||
videoImporter.SetTargetSettings("Android", targetSettings);
|
||||
videoImporter.SetTargetSettings("iPhone", targetSettings);
|
||||
videoImporter.deinterlaceMode = settings.DeinterlaceMode;
|
||||
videoImporter.flipHorizontal = settings.FlipHorizontal;
|
||||
videoImporter.flipVertical = settings.FlipVertical;
|
||||
videoImporter.importAudio = settings.ImportAudio;
|
||||
#endregion
|
||||
}
|
||||
|
||||
private void UpdateVideoFormatSettings()
|
||||
{
|
||||
if (config == null || VideoFormatSettings.IsDirtyLock)
|
||||
{
|
||||
config = AssetDatabase.LoadAssetAtPath<VideoFormatSettings>(VideoFormatSettingConst.VideoFormatSettingsPath);
|
||||
if (config == null)
|
||||
Debug.LogError("Video format config is null");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bb0a4d7e78dc7a043ae55b1932265e99
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2cc6cd0fb49146789026812735f60505
|
||||
timeCreated: 1704259084
|
|
@ -1,237 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace PhxhSDK.Phxh.AutoCombine
|
||||
{
|
||||
public class AutoCombine
|
||||
{
|
||||
|
||||
public static void ConvertMeshToSkinMesh(GameObject obj)
|
||||
{
|
||||
var allMeshRenders = obj.GetComponentsInChildren<MeshRenderer>(true);
|
||||
foreach (var meshRender in allMeshRenders)
|
||||
{
|
||||
var meshFilter = meshRender.GetComponent<MeshFilter>();
|
||||
if (meshFilter == null) continue;
|
||||
var mesh = meshFilter.sharedMesh;
|
||||
if (mesh == null) continue;
|
||||
var skinMesh = new GameObject(mesh.name);
|
||||
skinMesh.transform.SetParent(obj.transform);
|
||||
|
||||
var skinMeshRender = skinMesh.AddComponent<SkinnedMeshRenderer>();
|
||||
skinMeshRender.sharedMesh = mesh;
|
||||
skinMeshRender.sharedMaterial = meshRender.sharedMaterial;
|
||||
|
||||
// 设置骨骼
|
||||
var rootBone = meshRender.transform.parent;
|
||||
skinMeshRender.rootBone = rootBone;
|
||||
skinMeshRender.bones = new[] {rootBone};
|
||||
|
||||
// 设置bindposes
|
||||
var bindPose = rootBone.worldToLocalMatrix * meshRender.transform.localToWorldMatrix;
|
||||
skinMeshRender.sharedMesh.bindposes = new[] {bindPose};
|
||||
|
||||
// 设置权重
|
||||
var vertexCount = mesh.vertexCount;
|
||||
var boneWeights = new BoneWeight[vertexCount];
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
boneWeights[i].boneIndex0 = 0;
|
||||
boneWeights[i].weight0 = 1;
|
||||
}
|
||||
skinMeshRender.sharedMesh.boneWeights = boneWeights;
|
||||
|
||||
Object.DestroyImmediate(meshRender.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CombineSkinMesh(GameObject obj,string[] textureNames,int combineTexSize = 2048)
|
||||
{
|
||||
Dictionary<string, List<SkinnedMeshRenderer>> needCombinelist = new Dictionary<string, List<SkinnedMeshRenderer>>();
|
||||
SkinnedMeshRenderer[] parts = obj.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
foreach (var item in parts)
|
||||
{
|
||||
var shaderName = item.sharedMaterial.shader.name;
|
||||
if (needCombinelist.ContainsKey(shaderName))
|
||||
{
|
||||
needCombinelist[shaderName].Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
var addList = new List<SkinnedMeshRenderer>();
|
||||
addList.Add(item);
|
||||
needCombinelist.Add(shaderName, addList);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in needCombinelist)
|
||||
{
|
||||
// 只有一个不合并
|
||||
if (item.Value.Count <= 1) continue;
|
||||
List<Transform> bones = new List<Transform>();
|
||||
List<Vector2[]> uvList = new List<Vector2[]>();
|
||||
List<CombineInstance> combineInstances = new List<CombineInstance>();
|
||||
Material mat = Object.Instantiate(item.Value[0].sharedMaterial) as Material;
|
||||
Dictionary<string, List<Texture2D>> textureDict = new Dictionary<string, List<Texture2D>>();
|
||||
int uvCount = 0;
|
||||
foreach (var cur in item.Value)
|
||||
{
|
||||
CombineInstance ci = new CombineInstance();
|
||||
ci.mesh = DeepCopyMesh(cur.sharedMesh);
|
||||
// ci.transform = cur.transform.localToWorldMatrix;
|
||||
combineInstances.Add(ci);
|
||||
uvList.Add(cur.sharedMesh.uv);
|
||||
uvCount += cur.sharedMesh.uv.Length;
|
||||
foreach (var needCombineTex in textureNames)
|
||||
{
|
||||
var getTexture = cur.sharedMaterial.GetTexture(needCombineTex) as Texture2D;
|
||||
if (textureDict.ContainsKey(needCombineTex))
|
||||
{
|
||||
textureDict[needCombineTex].Add(getTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Texture2D> addList = new List<Texture2D>();
|
||||
addList.Add(getTexture);
|
||||
textureDict.Add(needCombineTex, addList);
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < cur.bones.Length; k++)
|
||||
{
|
||||
bones.Add(cur.bones[k]);
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, Texture2D> combinedTexs = new Dictionary<string, Texture2D>();
|
||||
Rect[] packingResult = null;
|
||||
foreach (var needPackTexList in textureDict)
|
||||
{
|
||||
Texture2D newCombineTex = new Texture2D(4, 4, TextureFormat.ARGB4444, true);
|
||||
if (packingResult == null)
|
||||
{
|
||||
packingResult = newCombineTex.PackTextures(needPackTexList.Value.ToArray(), 0, combineTexSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
newCombineTex.PackTextures(needPackTexList.Value.ToArray(), 0, combineTexSize);
|
||||
}
|
||||
combinedTexs.Add(needPackTexList.Key, newCombineTex);
|
||||
}
|
||||
|
||||
//string textureName = "autocombine" + obj.name;
|
||||
Vector2[] atlasUVs = new Vector2[uvCount];
|
||||
int count = 0;
|
||||
for (int i = 0; i < uvList.Count; i++)
|
||||
{
|
||||
var tmpArray = uvList[i];
|
||||
for (int j = 0; j < tmpArray.Length; j++)
|
||||
{
|
||||
Vector2 uv = tmpArray[j];
|
||||
atlasUVs[count].x = Mathf.Lerp(packingResult[i].xMin, packingResult[i].xMax, uv.x);
|
||||
atlasUVs[count].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
GameObject newSkinnedGo = new GameObject("CombineObj_" + _ConvertShaderName(item.Key));
|
||||
newSkinnedGo.transform.SetParent(obj.transform);
|
||||
|
||||
var s = newSkinnedGo.AddComponent<SkinnedMeshRenderer>();
|
||||
Mesh nMesh = new Mesh();
|
||||
nMesh.CombineMeshes(combineInstances.ToArray(), true, false);
|
||||
s.sharedMesh = nMesh;
|
||||
// s.sharedMesh = CombineMeshesWithTransformsAndBones(combineInstances.ToArray());
|
||||
s.bones = bones.ToArray();
|
||||
s.sharedMesh.uv = atlasUVs;
|
||||
s.sharedMaterial = mat;
|
||||
|
||||
foreach (var combineTex in combinedTexs)
|
||||
{
|
||||
s.sharedMaterial.SetTexture(combineTex.Key, combineTex.Value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < item.Value.Count; i++)
|
||||
{
|
||||
var skin = item.Value[i];
|
||||
Object.DestroyImmediate(skin.gameObject, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Mesh DeepCopyMesh(Mesh originalMesh)
|
||||
{
|
||||
Mesh copiedMesh = new Mesh();
|
||||
|
||||
copiedMesh.vertices = (Vector3[])originalMesh.vertices.Clone();
|
||||
copiedMesh.triangles = (int[])originalMesh.triangles.Clone();
|
||||
copiedMesh.uv = (Vector2[])originalMesh.uv.Clone();
|
||||
copiedMesh.normals = (Vector3[])originalMesh.normals.Clone();
|
||||
copiedMesh.tangents = (Vector4[])originalMesh.tangents.Clone();
|
||||
copiedMesh.colors = (Color[])originalMesh.colors.Clone();
|
||||
copiedMesh.boneWeights = (BoneWeight[])originalMesh.boneWeights.Clone();
|
||||
copiedMesh.bindposes = (Matrix4x4[])originalMesh.bindposes.Clone();
|
||||
|
||||
return copiedMesh;
|
||||
}
|
||||
|
||||
public static Mesh CombineMeshesWithTransformsAndBones(CombineInstance[] combineInstances)
|
||||
{
|
||||
List<Vector3> vertices = new List<Vector3>();
|
||||
List<int> triangles = new List<int>();
|
||||
List<Vector2> uvs = new List<Vector2>();
|
||||
List<BoneWeight> boneWeights = new List<BoneWeight>();
|
||||
List<Matrix4x4> bindposes = new List<Matrix4x4>();
|
||||
|
||||
for (int i = 0; i < combineInstances.Length; i++)
|
||||
{
|
||||
Mesh mesh = combineInstances[i].mesh;
|
||||
Matrix4x4 transform = combineInstances[i].transform;
|
||||
|
||||
if (mesh == null)
|
||||
{
|
||||
Debug.LogError("没有mesh");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var j = 0; j < mesh.vertices.Length; ++j)
|
||||
{
|
||||
var vertex = mesh.vertices[j];
|
||||
var bipPos = mesh.bindposes[j];
|
||||
|
||||
vertices.Add(bipPos.MultiplyPoint3x4(vertex));
|
||||
}
|
||||
|
||||
foreach (Vector2 uv in mesh.uv)
|
||||
{
|
||||
uvs.Add(uv);
|
||||
}
|
||||
|
||||
int vertexOffset = vertices.Count - mesh.vertexCount;
|
||||
foreach (int triangle in mesh.triangles)
|
||||
{
|
||||
triangles.Add(vertexOffset + triangle);
|
||||
}
|
||||
|
||||
// 添加骨骼权重和绑定姿势
|
||||
boneWeights.AddRange(mesh.boneWeights);
|
||||
bindposes.AddRange(mesh.bindposes);
|
||||
}
|
||||
|
||||
Mesh combinedMesh = new Mesh();
|
||||
combinedMesh.vertices = vertices.ToArray();
|
||||
combinedMesh.triangles = triangles.ToArray();
|
||||
combinedMesh.uv = uvs.ToArray();
|
||||
combinedMesh.boneWeights = boneWeights.ToArray();
|
||||
combinedMesh.bindposes = bindposes.ToArray();
|
||||
|
||||
return combinedMesh;
|
||||
}
|
||||
|
||||
private static string _ConvertShaderName(string shaderName)
|
||||
{
|
||||
// 将/替换为_
|
||||
shaderName = shaderName.Replace("/", "_");
|
||||
// 将空格替换为_
|
||||
shaderName = shaderName.Replace(" ", "_");
|
||||
return shaderName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 51b50b155c5c4401ba71a7b347e322e4
|
||||
timeCreated: 1704259092
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue