【SDK】PHXHSDK重新添加

iOS_release
zhangaotian 2024-06-17 19:41:52 +08:00
parent 504ae4ca72
commit fcfae0ba6b
2296 changed files with 1 additions and 249437 deletions

1
Forest/Assets/PhxhSDK Submodule

@ -0,0 +1 @@
Subproject commit c689899a54a45fe71f6a69d76961d47088f196e7

View File

@ -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

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: d56946792ef24427975f9f6ebdd85aa1
timeCreated: 1708490322

View File

@ -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
}

View File

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

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 6f5bc95ef7bf4aa2ae49466a309d9637
timeCreated: 1708574088

View File

@ -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

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 88d9df6663654361adc0bec9396b21c9
timeCreated: 1708574103

View File

@ -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;
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: d048804b8b42464d95190aa5ba3546a2
timeCreated: 1708576339

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 4d06325ab1cf455f88fb987aa35ddb2b
timeCreated: 1708574646

View File

@ -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);
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 202a545f2ec148c19eb199a62d92e0b8
timeCreated: 1708574653

View File

@ -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

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 33021c41fc0a4368a91312930aa72d0b
timeCreated: 1708574988

View File

@ -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);
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 91a500ba67764ceaa13e4305e58ed1d5
timeCreated: 1708576470

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 04d521a802e944d88b4e057cdb0fdf8f
timeCreated: 1708580107

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 273bf894badf42508bcf6b111faa5e5d
timeCreated: 1708921974

View File

@ -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
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 44eb7b74a8c94e1cb705377229681d81
timeCreated: 1708922010

View File

@ -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";
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 4eeb9040a2844743bec5c9b35105f806
timeCreated: 1708921897

View File

@ -1,27 +0,0 @@
namespace PhxhSDK.AOT.VersionUpdate
{
public enum EVersionUpdateType
{
/// <summary>
/// 不需要更新
/// </summary>
NoUpdate,
/// <summary>
/// 资源更新
/// </summary>
ResUpdate,
/// <summary>
/// 整包更新
/// </summary>
PackUpdate,
/// <summary>
/// 出错
/// </summary>
Error,
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 1b70d270da4c44dbaefd50e9835c573b
timeCreated: 1708580602

View File

@ -1,14 +0,0 @@
using Cysharp.Threading.Tasks;
namespace PhxhSDK.AOT.VersionUpdate
{
public interface IVersionUpdate
{
UniTask<EVersionUpdateType> CheckVersion();
UniTask<bool> UpdateRes();
VersionUpdateInfo GetVersionInfo();
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: dc873595eb49408794db5ba8c13a4878
timeCreated: 1708580756

View File

@ -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();
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 0d8b5e01044d4ecdb7f5ef7cf7435045
timeCreated: 1708580151

View File

@ -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();
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 3aaed81d361946f8ae7a260f2b3445b1
timeCreated: 1708580492

View File

@ -1,9 +0,0 @@
namespace PhxhSDK.AOT.VersionUpdate
{
public class VersionUpdateInfo
{
public string oldVersion = "unknown";
public string newVersion = "unknown";
public long totalBytes = 0;
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 32d04333b6a24d26a5707f5e4e619892
timeCreated: 1708581325

View File

@ -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

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 74a3780a1779428a88fbde5745bdc8b8
timeCreated: 1708580803

View File

@ -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;
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 00eeef6b6c104d20801654dbe19d0fc5
timeCreated: 1708580923

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 334ceaaa51174ec199be985764c31ac8
timeCreated: 1708514105

View File

@ -1,9 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
namespace PhxhSDK.AOT
{
public class BuildinFileManifest : ScriptableObject
{
public List<string> BuildinFiles = new List<string>();
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 56888749a2144af0929c016f5d24356c
timeCreated: 1708514040

View File

@ -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();
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: b780b30d69794883b021b86a210e69b0
timeCreated: 1708668162

View File

@ -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;
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 2ad9a3bb07b74d8dae76fdcc627d42c1
timeCreated: 1708514573

View File

@ -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
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: e22d54ed66a149198e471736a4e537d7
timeCreated: 1708513920

View File

@ -1,7 +0,0 @@
namespace PhxhSDK.AOT
{
public class StreamingAssetsDefine
{
public const string RootFolderName = "yoo";
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 3cd0086ebeeb48d0bbad9622c5c577b8
timeCreated: 1708514012

View File

@ -1,7 +0,0 @@
namespace PhxhSDK.AOT
{
public static class YooAssetBuildStatus
{
public static bool isInBuild = false;
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 0982954dec7e4817aacc6acdf44b9cf3
timeCreated: 1708490336

View File

@ -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);
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: a783ee08288c46c799a5f409eb5c65ea
timeCreated: 1708495618

View File

@ -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);
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 06fb2e9ce57845f0bdabda7c756334ba
timeCreated: 1708668451

View File

@ -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);
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 540fa3c1015f486aa3be05a496c9d170
timeCreated: 1708514119

View File

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

View File

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

View File

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

View File

@ -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"
};
}

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

@ -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;
}
}

View File

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

View File

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

View File

@ -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;
}
}

View File

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

View File

@ -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;
}
}

View File

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

View File

@ -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;
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 9a0edacf4f6b46e5b2b59d9b2a9f1e51
timeCreated: 1690528911

View File

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

View File

@ -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"
};
}

View File

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

View File

@ -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;
}
}

View File

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

View File

@ -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;
}
}

View File

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

View File

@ -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);
}
}

View File

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

View File

@ -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();
// }
}

View File

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

View File

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

View File

@ -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",
};
}

View File

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

View File

@ -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;
}
}

View File

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

View File

@ -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;
}

View File

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

View File

@ -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);
}
}

View File

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

View File

@ -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");
}
}
}

View File

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

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 2cc6cd0fb49146789026812735f60505
timeCreated: 1704259084

View File

@ -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;
}
}
}

View File

@ -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