mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
重置2.0.0(beta)
重置2.0.0(beta)
This commit is contained in:
8
Assets/TEngine/Scripts/Editor.meta
Normal file
8
Assets/TEngine/Scripts/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a0c24f23d48a91647bf83b825da86e1d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Editor/AssetBundleBuild.meta
Normal file
8
Assets/TEngine/Scripts/Editor/AssetBundleBuild.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9df4e841d128615429b14a4d4499748e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1941
Assets/TEngine/Scripts/Editor/AssetBundleBuild/AssetbundleBuilder.cs
Normal file
1941
Assets/TEngine/Scripts/Editor/AssetBundleBuild/AssetbundleBuilder.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe5a4e2b6631946439ff7cee706d0890
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
534
Assets/TEngine/Scripts/Editor/AssetBundleBuild/Builder.cs
Normal file
534
Assets/TEngine/Scripts/Editor/AssetBundleBuild/Builder.cs
Normal file
@@ -0,0 +1,534 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using TEngine.Editor;
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEditor.Callbacks;
|
||||
using UnityEditor.Compilation;
|
||||
using Assembly = System.Reflection.Assembly;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
public class Builder : IBuilder
|
||||
{
|
||||
internal static readonly Builder Instance = new Builder();
|
||||
|
||||
/// <summary>
|
||||
/// 数据部分
|
||||
/// </summary>
|
||||
internal BuilderEditor CurBuilderData;
|
||||
|
||||
/// <summary>
|
||||
/// AB构建器
|
||||
/// </summary>
|
||||
internal AssetbundleBuilder AssetbundleBuilder = new AssetbundleBuilder();
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前的BuidlerConfigData
|
||||
/// </summary>
|
||||
/// <param name="platform"></param>
|
||||
/// <param name="configName"></param>
|
||||
public void SetBuilderConfig(BuilderUtility.PlatformType platform, string configName, string configPath = "")
|
||||
{
|
||||
CurBuilderData = BuilderUtility.LoadConfig(platform, configName, configPath);
|
||||
if (CurBuilderData == null)
|
||||
{
|
||||
TLogger.LogError("未找到配置,config:" + configName);
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
|
||||
CurBuilderData.platform = platform;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前的BuidlerConfigData
|
||||
/// </summary>
|
||||
/// <param name="platform"></param>
|
||||
/// <param name="configName"></param>
|
||||
public void SetBuilderConfig(BuilderEditor tmpBuilder)
|
||||
{
|
||||
CurBuilderData = tmpBuilder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 切换平台
|
||||
/// </summary>
|
||||
/// <param name="platform"></param>
|
||||
public void SwitchPlatform(BuilderUtility.PlatformType platform)
|
||||
{
|
||||
if (CurBuilderData == null)
|
||||
{
|
||||
TLogger.LogError("未设置BuilderData,请先调用接口:SetBuilderConfig");
|
||||
return;
|
||||
}
|
||||
CurBuilderData.platform = platform;
|
||||
switch (CurBuilderData.platform)
|
||||
{
|
||||
case BuilderUtility.PlatformType.Windows:
|
||||
{
|
||||
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone,
|
||||
BuildTarget.StandaloneWindows64);
|
||||
|
||||
PlayerSettings.SetScriptingBackend(BuildTargetGroup.Standalone, ScriptingImplementation.Mono2x);
|
||||
PlayerSettings.stripEngineCode = false;
|
||||
PlayerSettings.SetManagedStrippingLevel(BuildTargetGroup.Standalone, ManagedStrippingLevel.Disabled);
|
||||
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Standalone, CurBuilderData.bundleIdentifier);
|
||||
}
|
||||
break;
|
||||
case BuilderUtility.PlatformType.Android:
|
||||
{
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android);
|
||||
|
||||
EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
|
||||
PlayerSettings.Android.bundleVersionCode = 1;
|
||||
PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android,
|
||||
CurBuilderData.scriptingBackend == BuilderUtility.ScriptBackend.Mono ? ScriptingImplementation.Mono2x : ScriptingImplementation.IL2CPP);
|
||||
Debug.Log("=============CurBuilderData.scriptingBackend:" + CurBuilderData.scriptingBackend);
|
||||
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, CurBuilderData.bundleIdentifier);
|
||||
PlayerSettings.SetApiCompatibilityLevel(BuildTargetGroup.Android, ApiCompatibilityLevel.NET_4_6);
|
||||
}
|
||||
break;
|
||||
case BuilderUtility.PlatformType.iOS:
|
||||
{
|
||||
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.iOS, BuildTarget.iOS);
|
||||
|
||||
PlayerSettings.iOS.appleEnableAutomaticSigning = false;
|
||||
PlayerSettings.iOS.scriptCallOptimization = ScriptCallOptimizationLevel.SlowAndSafe;
|
||||
PlayerSettings.iOS.targetOSVersionString = "8.0";
|
||||
PlayerSettings.iOS.buildNumber = "1";
|
||||
PlayerSettings.SetScriptingBackend(BuildTargetGroup.iOS, ScriptingImplementation.IL2CPP);
|
||||
PlayerSettings.stripEngineCode = false;
|
||||
PlayerSettings.SetManagedStrippingLevel(BuildTargetGroup.iOS, ManagedStrippingLevel.Disabled);
|
||||
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.iOS, CurBuilderData.bundleIdentifier);
|
||||
PlayerSettings.SetApiCompatibilityLevel(BuildTargetGroup.iOS, ApiCompatibilityLevel.NET_4_6);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 构建包体
|
||||
/// </summary>
|
||||
/// <param name="isDirect">是否直接出包</param>
|
||||
internal void Build(bool isDirect = false, BuildOptions option = BuildOptions.None)
|
||||
{
|
||||
var platform = CurBuilderData.platform;
|
||||
|
||||
SwitchPlatform(platform);
|
||||
|
||||
DoBuild(isDirect, option);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 执行完整构建流程
|
||||
/// </summary>
|
||||
/// <param name="isDirectBuild"></param>
|
||||
/// <param name="option"></param>
|
||||
void DoBuild(bool isDirectBuild, BuildOptions option)
|
||||
{
|
||||
var buildStart = DateTime.Now;
|
||||
|
||||
if (!isDirectBuild)
|
||||
{
|
||||
if (!BuildAssetBundle())
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Instance.AssetbundleBuilder.CopyAssetBundles();
|
||||
}
|
||||
|
||||
BuildPackage(option);
|
||||
Debug.Log("Apk打包总耗时:" + (DateTime.Now - buildStart).TotalMinutes.ToString("F2") + " 分钟");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建AB包部分
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool BuildAssetBundle()
|
||||
{
|
||||
if (CurBuilderData == null)
|
||||
{
|
||||
TLogger.LogError("未设置BuilderData,请先调用接口:SetBuilderConfig");
|
||||
return false;
|
||||
}
|
||||
|
||||
var start = DateTime.Now;
|
||||
|
||||
BuilderInjectorHandler(BuilderInjectorMoment.BeforeCollect_AssetBundle);
|
||||
if (!Instance.AssetbundleBuilder.CollectAssetBundles(CurBuilderData.builderBundlePolicy, CurBuilderData.bundleConfig))
|
||||
return false;
|
||||
|
||||
if (CurBuilderData.bCollectShaderVariant)
|
||||
{
|
||||
Debug.Log("CollectShaderVariant");
|
||||
var list = ShaderVariantCollector.ClollectSharderAndVariant();
|
||||
string abName = ShaderVariantCollector.GetShaderVariantAbName();
|
||||
Dictionary<string, string> additionalRes = new Dictionary<string, string>();
|
||||
foreach (var sv in list)
|
||||
{
|
||||
if (!additionalRes.ContainsKey(sv))
|
||||
additionalRes.Add(sv, abName);
|
||||
else
|
||||
Debug.LogError("重复的变体路径:" + sv);
|
||||
}
|
||||
|
||||
list.Clear();
|
||||
Instance.AssetbundleBuilder.InsertAdditionalTopRes(additionalRes, false);
|
||||
}
|
||||
|
||||
Instance.AssetbundleBuilder.SetAndCheckAssetDependencies();
|
||||
|
||||
BuilderInjectorHandler(BuilderInjectorMoment.BeforeBuild_AssetBundle);
|
||||
|
||||
Instance.AssetbundleBuilder.BuildAssetBundlesAfterCollect(CurBuilderData.buildType == BuilderUtility.BuildType.Development, CurBuilderData.bIncrementBuildAB);
|
||||
BuilderInjectorHandler(BuilderInjectorMoment.AfterBuild_AssetBundle);
|
||||
Debug.Log("AB打包总耗时:" + (DateTime.Now - start).TotalMinutes.ToString("F2") + " 分钟");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出apk或安卓工程
|
||||
/// </summary>
|
||||
/// <param name="option"></param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public void BuildPackage(BuildOptions option = BuildOptions.None)
|
||||
{
|
||||
if (CurBuilderData == null)
|
||||
{
|
||||
TLogger.LogError("未设置BuilderData,请先调用接口:SetBuilderConfig");
|
||||
return;
|
||||
}
|
||||
CurBuilderData.ApplyArgs("");
|
||||
|
||||
PlayerSettings.productName = CurBuilderData.productName;
|
||||
PlayerSettings.bundleVersion = CurBuilderData.bundleVersion + "." + CurBuilderData._bBaseVersion;
|
||||
|
||||
if (EditorUserBuildSettings.development)
|
||||
option |= BuildOptions.Development;
|
||||
if (EditorUserBuildSettings.connectProfiler)
|
||||
option |= BuildOptions.ConnectWithProfiler;
|
||||
if (EditorUserBuildSettings.buildWithDeepProfilingSupport)
|
||||
option |= BuildOptions.EnableDeepProfilingSupport;
|
||||
|
||||
string applicationName = string.Empty;
|
||||
BuildTarget target = BuildTarget.NoTarget;
|
||||
switch (CurBuilderData.platform)
|
||||
{
|
||||
case BuilderUtility.PlatformType.Android:
|
||||
applicationName = CurBuilderData.bExportAndroidProject ? $"{CurBuilderData.productName}" : $"{CurBuilderData.productName}.apk";
|
||||
target = BuildTarget.Android;
|
||||
break;
|
||||
case BuilderUtility.PlatformType.iOS:
|
||||
applicationName = $"{CurBuilderData.productName}.ipa";
|
||||
target = BuildTarget.iOS;
|
||||
break;
|
||||
case BuilderUtility.PlatformType.Windows:
|
||||
applicationName = $"{CurBuilderData.productName}.exe";
|
||||
target = BuildTarget.StandaloneWindows64;
|
||||
break;
|
||||
default:
|
||||
UnityEngine.Debug.LogError("Not supported target platform");
|
||||
return;
|
||||
}
|
||||
|
||||
SetAppStoreUrl();
|
||||
|
||||
LoaderUtilities.DeleteFolder(FileSystem.ResourceRoot);
|
||||
|
||||
BuilderInjectorHandler(BuilderInjectorMoment.BeforeBuild_Apk);
|
||||
|
||||
BuilderInjectorHandler(BuilderInjectorMoment.BeforeBuild_FirstZip);
|
||||
|
||||
MakeFirstZip();
|
||||
|
||||
BuilderInjectorHandler(BuilderInjectorMoment.AfterBuild_FirstZip);
|
||||
|
||||
CopyRawBytes();
|
||||
|
||||
string export = CurBuilderData.ProjectExportPath;
|
||||
if (string.IsNullOrEmpty(export))
|
||||
export = $"{FileSystem.BuildPath}/{(CurBuilderData.platform).ToString()}/{applicationName}";
|
||||
|
||||
BuildReport result = BuildPipeline.BuildPlayer(new string[] { EditorBuildSettings.scenes[0].path },
|
||||
export, target, option);
|
||||
|
||||
switch (result.summary.result)
|
||||
{
|
||||
case BuildResult.Unknown:
|
||||
TLogger.LogInfo("Build Package FAIL! 未知错误!");
|
||||
break;
|
||||
case BuildResult.Succeeded:
|
||||
TLogger.LogInfo("Build Package OK!");
|
||||
break;
|
||||
case BuildResult.Failed:
|
||||
TLogger.LogInfo("Build Package FAIL!");
|
||||
break;
|
||||
case BuildResult.Cancelled:
|
||||
TLogger.LogInfo("Build Package Cancelled!");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (Application.isBatchMode && result.summary.result != BuildResult.Succeeded)
|
||||
{
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
|
||||
BuilderInjectorHandler(BuilderInjectorMoment.AfterBuild_Apk);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Builder流程插入处理器
|
||||
/// </summary>
|
||||
/// <param name="moment"></param>
|
||||
internal void BuilderInjectorHandler(BuilderInjectorMoment moment)
|
||||
{
|
||||
try
|
||||
{
|
||||
var compilationAssemblies = CompilationPipeline.GetAssemblies();
|
||||
List<Assembly> assemblies = new List<Assembly>();
|
||||
foreach (var assembly in compilationAssemblies)
|
||||
{
|
||||
assemblies.Add(Assembly.LoadFrom(assembly.outputPath));
|
||||
}
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
var types = assembly.GetTypes();
|
||||
foreach (var type in types)
|
||||
{
|
||||
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static |
|
||||
BindingFlags.Public | BindingFlags.IgnoreCase);
|
||||
foreach (var method in methods)
|
||||
{
|
||||
foreach (var att in method.GetCustomAttributes(false))
|
||||
{
|
||||
if (att is TEngineBuilderInjectorAttribute a)
|
||||
{
|
||||
if (!assembly.FullName.Contains("Editor"))
|
||||
{
|
||||
Debug.LogError($"{type.Name}.cs不在Editor中,已跳过");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type.IsSubclassOf(typeof(UnityEngine.Object)))
|
||||
{
|
||||
Debug.LogError(
|
||||
$"{type.Name}.cs中函数:{method.Name},标记了BuilderInjectorHandler,请勿在mono脚本上调用,已跳过");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!a.IsInMoment(moment))
|
||||
continue;
|
||||
|
||||
if (method.IsStatic)
|
||||
{
|
||||
method.Invoke(null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var obj = Activator.CreateInstance(type);
|
||||
method.Invoke(obj, null);
|
||||
}
|
||||
Debug.Log($"已完成执行插入方法:{method.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"BuilderInjectorHandler_{moment.ToString()}:" + e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拷贝RawBytes文件部分
|
||||
/// </summary>
|
||||
private static void CopyRawBytes()
|
||||
{
|
||||
//复制到StreamingAsset下
|
||||
string target = $"{string.Format("{0}/RawBytes", FileSystem.ResourceRootInStreamAsset)}";
|
||||
if (Directory.Exists(target))
|
||||
Directory.Delete(target, true);
|
||||
Directory.CreateDirectory(target);
|
||||
|
||||
LoaderUtilities.CopyDirectory(AssetConfig.AssetRootPath + "/" + "RawBytes", target);
|
||||
|
||||
LoaderUtilities.ClearMeta(target);
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
|
||||
[PostProcessBuild(1)]
|
||||
static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
|
||||
{
|
||||
Debug.Log($"target: {target.ToString()}");
|
||||
Debug.Log($"pathToBuiltProject: {pathToBuiltProject}");
|
||||
Debug.Log($"productName: {PlayerSettings.productName}");
|
||||
Debug.Log($"version:{GameConfig.Instance.GameBundleVersion}");
|
||||
string versionStr = GameConfig.Instance.GameBundleVersion.Replace(".", "");
|
||||
long versionLong = long.Parse(versionStr);
|
||||
Debug.Log($"versionStr:{versionStr}");
|
||||
|
||||
GameConfig.Instance.WriteBaseResVersion(GameConfig.Instance.ResId);
|
||||
|
||||
if (target == BuildTarget.Android)
|
||||
{
|
||||
string explore = BuilderUtility.GetArgumentValue("ExploreAndroidProject");
|
||||
if (Instance.CurBuilderData.scriptingBackend == BuilderUtility.ScriptBackend.Mono && !string.IsNullOrEmpty(explore) && explore == "true")
|
||||
{
|
||||
byte[] versionByte = new byte[8];
|
||||
for (int i = 0; i < versionByte.Length; ++i)
|
||||
versionByte[i] = (byte)((versionLong >> (i * 8)) & 0xff);
|
||||
#if UNITY_2019_4_OR_NEWER
|
||||
string dllPath =
|
||||
$"{pathToBuiltProject}/unityLibrary/src/main/assets/bin/Data/Managed/Assembly-CSharp.dll";
|
||||
#else
|
||||
string dllPath =
|
||||
$"{pathToBuiltProject}/{PlayerSettings.productName}/src/main/assets/bin/Data/Managed/Assembly-CSharp.dll";
|
||||
#endif
|
||||
|
||||
if (File.Exists(dllPath))
|
||||
{
|
||||
Debug.Log("Encrypt Assembly-CSharp.dll Start");
|
||||
|
||||
byte[] bytes = File.ReadAllBytes(dllPath);
|
||||
for (int i = 0; i < 901; ++i)
|
||||
bytes[i] ^= 0x31;
|
||||
for (int i = 0; i < bytes.Length; i += 2)
|
||||
bytes[i] ^= bytes[bytes.Length - i - 1];
|
||||
using (FileStream dllStream = File.OpenWrite(dllPath))
|
||||
{
|
||||
dllStream.WriteByte((byte)'L');
|
||||
dllStream.WriteByte((byte)'U');
|
||||
dllStream.WriteByte((byte)'A');
|
||||
dllStream.WriteByte((byte)'C');
|
||||
foreach (var t in versionByte)
|
||||
dllStream.WriteByte(t);
|
||||
|
||||
dllStream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
Debug.Log("Encrypt Assembly-CSharp.dll Success");
|
||||
|
||||
Debug.Log("Encrypt libmonobdwgc-2.0.so Start !!");
|
||||
|
||||
Debug.Log($"Current is : {(EditorUserBuildSettings.development ? "development" : "release")}");
|
||||
|
||||
#if UNITY_2019_4_OR_NEWER
|
||||
string armv7ASoPath =
|
||||
$"{pathToBuiltProject}/unityLibrary/src/main/jniLibs/armeabi-v7a/libmonobdwgc-2.0.so";
|
||||
string x86SoPath = $"{pathToBuiltProject}/unityLibrary/src/main/jniLibs/x86/libmonobdwgc-2.0.so";
|
||||
#else
|
||||
string armv7ASoPath =
|
||||
$"{pathToBuiltProject}/{PlayerSettings.productName}/src/main/jniLibs/armeabi-v7a/libmonobdwgc-2.0.so";
|
||||
string x86SoPath = $"{pathToBuiltProject}/{PlayerSettings.productName}/src/main/jniLibs/x86/libmonobdwgc-2.0.so";
|
||||
#endif
|
||||
#if UNITY_2019_4_OR_NEWER
|
||||
AppendDll(dllPath, $"{pathToBuiltProject}/unityLibrary/src/main/assets/");
|
||||
#else
|
||||
AppendDll(dllPath, $"{pathToBuiltProject}/{PlayerSettings.productName}/src/main/assets/");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError(dllPath + " Not Found!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string[] dirList = { $"{Environment.CurrentDirectory}/Library/il2cpp_android_armeabi-v7a/il2cpp_cache", $"{Environment.CurrentDirectory}/Library/il2cpp_android_arm64-v8a/il2cpp_cache" };
|
||||
foreach (var dir in dirList)
|
||||
{
|
||||
if (Directory.Exists(dir))
|
||||
{
|
||||
DirectoryInfo root = new DirectoryInfo(dir);
|
||||
DirectoryInfo[] dics = root.GetDirectories();
|
||||
foreach (var childDir in dics)
|
||||
{
|
||||
if (childDir.Name.Contains("linkresult_"))
|
||||
{
|
||||
DirectoryInfo directory = new DirectoryInfo(childDir.FullName);
|
||||
FileInfo[] files = directory.GetFiles();
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
if (files[i].Name == "libil2cpp.sym.so")
|
||||
{
|
||||
string newPath = null;
|
||||
if (files[i].FullName.Contains("armeabi-v7a"))
|
||||
newPath = $"{Environment.CurrentDirectory}/SymbolsTemp/armeabi-v7a";
|
||||
else if (files[i].FullName.Contains("arm64-v8a"))
|
||||
newPath = $"{Environment.CurrentDirectory}/SymbolsTemp/arm64-v8a";
|
||||
if (!Directory.Exists(newPath))
|
||||
{
|
||||
Directory.CreateDirectory(newPath);
|
||||
}
|
||||
|
||||
File.Copy(files[i].FullName, $"{newPath}/libil2cpp.sym.so", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//TLogger.LogWarning($"文件夹不存在:{dir}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加塞一下dll
|
||||
/// </summary>
|
||||
/// <param name="dll_path"></param>
|
||||
/// <param name="des_path"></param>
|
||||
static void AppendDll(string dll_path, string des_path)
|
||||
{
|
||||
//备份到本地目录
|
||||
File.Copy(dll_path, $"{FileSystem.BuildPath}/{"Script.bin"}", true);
|
||||
//备份到streamAsset目录
|
||||
File.Copy(dll_path, $"{des_path}/TEngineResRoot/{"Script.bin"}", true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置跳转地址
|
||||
/// </summary>
|
||||
internal void SetAppStoreUrl()
|
||||
{
|
||||
#if UNITY_IOS
|
||||
BuilderUtility.SetAppURL(CurBuilderData.appUrl);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否首包压缩
|
||||
/// </summary>
|
||||
internal void MakeFirstZip()
|
||||
{
|
||||
string outputPath = $"{Application.streamingAssetsPath}/{"First.zip"}";
|
||||
if (File.Exists(outputPath))
|
||||
{
|
||||
File.Delete(outputPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a94ae73de7a025f428761ee662f37b87
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 打包流程插入(Builder流程插入处理器)
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public class TEngineBuilderInjectorAttribute : System.Attribute
|
||||
{
|
||||
private int _moment = -1;
|
||||
public int Moment
|
||||
{
|
||||
get => _moment;
|
||||
set => _moment = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 插入Builder流程
|
||||
/// </summary>
|
||||
/// <param name="monments"></param>
|
||||
public TEngineBuilderInjectorAttribute(params BuilderInjectorMoment[] monments)
|
||||
{
|
||||
if (monments == null || monments.Length == 0)
|
||||
return;
|
||||
|
||||
Moment = 0;
|
||||
foreach (var builderInjectorMoment in monments)
|
||||
{
|
||||
Moment += 1 << (int)builderInjectorMoment;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInMoment(BuilderInjectorMoment moment)
|
||||
{
|
||||
return ((1 << (int)moment) & Moment) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public enum BuilderInjectorMoment
|
||||
{
|
||||
/// <summary>
|
||||
/// 收集AB包之前
|
||||
/// </summary>
|
||||
BeforeCollect_AssetBundle,
|
||||
/// <summary>
|
||||
/// 打AB包之前
|
||||
/// </summary>
|
||||
BeforeBuild_AssetBundle,
|
||||
/// <summary>
|
||||
/// 打AB包之后
|
||||
/// </summary>
|
||||
AfterBuild_AssetBundle,
|
||||
/// <summary>
|
||||
/// 打APK之前
|
||||
/// </summary>
|
||||
BeforeBuild_Apk,
|
||||
/// <summary>
|
||||
/// 打APK之后
|
||||
/// </summary>
|
||||
AfterBuild_Apk,
|
||||
/// <summary>
|
||||
/// 打APK之后
|
||||
/// </summary>
|
||||
AfterBuild_FirstZip,
|
||||
/// <summary>
|
||||
/// 打APK之前
|
||||
/// </summary>
|
||||
BeforeBuild_FirstZip
|
||||
}
|
||||
|
||||
public static class CusInjectorDemoEditor
|
||||
{
|
||||
[TEngineBuilderInjector(BuilderInjectorMoment.AfterBuild_AssetBundle)]
|
||||
public static void TestInjector()
|
||||
{
|
||||
UnityEngine.Debug.Log($"productName: {PlayerSettings.productName}");
|
||||
UnityEngine.Debug.Log($"version:{GameConfig.Instance.GameBundleVersion}");
|
||||
string versionStr = GameConfig.Instance.GameBundleVersion.Replace(".", "");
|
||||
long versionLong = long.Parse(versionStr);
|
||||
UnityEngine.Debug.Log($"versionStr:{versionStr}");
|
||||
UnityEngine.Debug.LogError("BuilderInjectorMoment.AfterBuild_AssetBundle");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 653a3ac97936eb646b84bf6ec13eaa86
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
724
Assets/TEngine/Scripts/Editor/AssetBundleBuild/BuilderUtility.cs
Normal file
724
Assets/TEngine/Scripts/Editor/AssetBundleBuild/BuilderUtility.cs
Normal file
@@ -0,0 +1,724 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using TEngine.Runtime;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
public class BuilderUtility
|
||||
{
|
||||
public enum PlatformType
|
||||
{
|
||||
Windows,
|
||||
OSX,
|
||||
Android,
|
||||
iOS
|
||||
}
|
||||
|
||||
public enum BuildType
|
||||
{
|
||||
Editor,
|
||||
Release,
|
||||
Development
|
||||
}
|
||||
|
||||
public enum AssetSourceType
|
||||
{
|
||||
GameSource,
|
||||
ArtSource
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public enum EnableLogLevel
|
||||
{
|
||||
Info,
|
||||
Assert,
|
||||
Warning,
|
||||
Error,
|
||||
Exception
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public enum ScriptBackend
|
||||
{
|
||||
Mono,
|
||||
IL2CPP,
|
||||
}
|
||||
|
||||
|
||||
//Bundle配置策略
|
||||
[Serializable]
|
||||
public enum BundlePolicy
|
||||
{
|
||||
[Tooltip("目录下所有文件都会都会分配一个ab名")]
|
||||
SingleFile,
|
||||
[Tooltip("目录下所有文件都以当前目录名为ab名")]
|
||||
Directory,
|
||||
[Tooltip("(只检索第一层子目录)\n当前目录下的第一层子目录文件,都会以该目录+其子目录命名。\n若第一层有单文件则该目录+single命名。")]
|
||||
ChildDirectory,
|
||||
[Tooltip("当前目录下的文件会采取其已定义好的ab名作为AB名,否则会采用单文件策略命名")]
|
||||
CustomAbName,
|
||||
}
|
||||
//打包Builder策略
|
||||
[Serializable]
|
||||
public enum BuilderBundlePolicy
|
||||
{
|
||||
SingleFile,
|
||||
Directory,
|
||||
Configuration,
|
||||
}
|
||||
|
||||
//配置位置
|
||||
private const string CONFIG_FOLDER_PATH = FileSystem.BuildPath;
|
||||
|
||||
[MenuItem("Assets/Create/[TEngine] 新建打包配置", priority = -10)]
|
||||
private static void CreateBuilderConfig()
|
||||
{
|
||||
|
||||
if (Selection.activeObject == null)
|
||||
{
|
||||
Debug.LogError("请选择目标文件夹");
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR_OSX
|
||||
string filter = $"{CONFIG_FOLDER_PATH}/IOS";
|
||||
#elif UNITY_EDITOR_WIN
|
||||
string filter = $"{CONFIG_FOLDER_PATH}/Win";
|
||||
#else
|
||||
string filter = $"{CONFIG_FOLDER_PATH}/Android";
|
||||
#endif
|
||||
|
||||
string targetDirPath = AssetDatabase.GetAssetPath(Selection.activeObject);
|
||||
if (!targetDirPath.StartsWith(filter))
|
||||
{
|
||||
Debug.LogError($"请在{filter}下新建打包配置\n------------------也可使用菜单栏“TEngine/创建AB配置”");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(targetDirPath))
|
||||
Directory.CreateDirectory(targetDirPath);
|
||||
|
||||
string defaultName = "Default";
|
||||
string suffix = ".asset";
|
||||
var path = $"{targetDirPath}/{defaultName}{suffix}";
|
||||
int index = 0;
|
||||
|
||||
int safeCount = 50;
|
||||
while (File.Exists(path) && safeCount-- > 0)
|
||||
{
|
||||
path = $"{targetDirPath}/{defaultName}_{++index}{suffix}";
|
||||
}
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
Debug.LogError($"已存在超过50的配置,请整理或选择另外文件夹下创建");
|
||||
return;
|
||||
}
|
||||
|
||||
path = AssetDatabase.GenerateUniqueAssetPath(path);
|
||||
var builder = ScriptableObject.CreateInstance<BuilderEditor>();
|
||||
AssetDatabase.CreateAsset(builder, path);
|
||||
EditorGUIUtility.PingObject(builder);
|
||||
AssetDatabase.OpenAsset(builder);
|
||||
}
|
||||
|
||||
internal static void SetMacroDefines(ref string macroDefines, BuildType buildType, bool updateMacros = true)
|
||||
{
|
||||
//逻辑上需最后一个调用
|
||||
SetBuildTypeMacroDefines(ref macroDefines, buildType, false);
|
||||
|
||||
if (updateMacros)
|
||||
UpdateMacros(macroDefines);
|
||||
}
|
||||
|
||||
internal static void SetBuildTypeMacroDefines(ref string macroDefines, BuildType buildType, bool updateMacros = true)
|
||||
{
|
||||
EditorUserBuildSettings.development = buildType == BuildType.Development;
|
||||
ModifyMacroDefine(ref macroDefines, "HOT_FIX", true);
|
||||
switch (buildType)
|
||||
{
|
||||
case BuildType.Editor:
|
||||
ClearMacros(ref macroDefines, false);
|
||||
break;
|
||||
case BuildType.Release:
|
||||
ModifyMacroDefine(ref macroDefines, "RELEASE_BUILD", true);
|
||||
ModifyMacroDefine(ref macroDefines, "_DEVELOPMENT_BUILD_", false);
|
||||
ModifyMacroDefine(ref macroDefines, "ASSETBUNDLE_ENABLE", true);
|
||||
break;
|
||||
case BuildType.Development:
|
||||
ModifyMacroDefine(ref macroDefines, "_DEVELOPMENT_BUILD_", true);
|
||||
ModifyMacroDefine(ref macroDefines, "RELEASE_BUILD", false);
|
||||
ModifyMacroDefine(ref macroDefines, "ASSETBUNDLE_ENABLE", true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (updateMacros)
|
||||
{
|
||||
UpdateMacros(macroDefines);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 设置bugly宏定义
|
||||
/// </summary>
|
||||
/// <param name="enable"></param>
|
||||
internal static void EnableGMSymbols(ref string macro, bool enable, bool immediateUpdate = true)
|
||||
{
|
||||
ModifyMacroDefine(ref macro, "ENABLE_GM", enable);
|
||||
|
||||
if (immediateUpdate)
|
||||
UpdateMacros(macro);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 设置是否忽略首包解压
|
||||
/// </summary>
|
||||
/// <param name="enable"></param>
|
||||
internal static void IgnorFirstZip(ref string macro, bool enable, bool immediateUpdate = true)
|
||||
{
|
||||
ModifyMacroDefine(ref macro, "IGNOR_FIRST_ZIP", enable);
|
||||
|
||||
if (immediateUpdate)
|
||||
UpdateMacros(macro);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置应用商店地址
|
||||
/// <param name = "param"></param>
|
||||
/// </summary>
|
||||
internal static void SetAppURL(string param)
|
||||
{
|
||||
try
|
||||
{
|
||||
var stream = new FileStream($"{Application.dataPath}/Resources/{FileSystem.ArtResourcePath}.txt", FileMode.OpenOrCreate);
|
||||
var writer = new StreamWriter(stream);
|
||||
writer.Write(param);
|
||||
writer.Flush();
|
||||
writer.Dispose();
|
||||
writer.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UnityEngine.Debug.LogException(e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 清除宏
|
||||
/// </summary>
|
||||
/// <param name="macroDefines"></param>
|
||||
internal static void ClearMacros(ref string macroDefines, bool immediateUpdate = true)
|
||||
{
|
||||
ModifyMacroDefine(ref macroDefines, "ENABLE_MONO", false);
|
||||
ModifyMacroDefine(ref macroDefines, "RELEASE_BUILD", false);
|
||||
ModifyMacroDefine(ref macroDefines, "_DEVELOPMENT_BUILD_", false);
|
||||
ModifyMacroDefine(ref macroDefines, "IGNOR_FIRST_ZIP", false);
|
||||
ModifyMacroDefine(ref macroDefines, "HOT_FIX", false);
|
||||
ModifyMacroDefine(ref macroDefines, "USE_LUA_PAK_FILE", false);
|
||||
ModifyMacroDefine(ref macroDefines, "USE_LUA_DISCRETE_FILE", false);
|
||||
ModifyMacroDefine(ref macroDefines, "ASSETBUNDLE_ENABLE", false);
|
||||
ModifyMacroDefine(ref macroDefines, "MONO_ENCRYPT", false);
|
||||
ModifyMacroDefine(ref macroDefines, "ENABLE_GM", false);
|
||||
ModifyMacroDefine(ref macroDefines, "IGNOR_FIRST_ZIP", false);
|
||||
|
||||
if (immediateUpdate)
|
||||
UpdateMacros(macroDefines);
|
||||
}
|
||||
|
||||
public static void RefreshBackendMacro(ref string macro, ScriptBackend backend, bool immediateUpdate = true)
|
||||
{
|
||||
switch (backend)
|
||||
{
|
||||
case ScriptBackend.Mono:
|
||||
ModifyMacroDefine(ref macro, "ENABLE_MONO", true);
|
||||
break;
|
||||
case ScriptBackend.IL2CPP:
|
||||
ModifyMacroDefine(ref macro, "ENABLE_MONO", false);
|
||||
break;
|
||||
}
|
||||
if (immediateUpdate)
|
||||
UpdateMacros(macro);
|
||||
}
|
||||
|
||||
public static void RefreshLogLevelMacro(ref string macro, EnableLogLevel logLevel, bool immediateUpdate = true)
|
||||
{
|
||||
switch (logLevel)
|
||||
{
|
||||
case EnableLogLevel.Info:
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_INFO", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ASSERT", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_WARNING", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ERROR", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_EXCEPTION", true);
|
||||
break;
|
||||
case EnableLogLevel.Assert:
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_INFO", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ASSERT", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_WARNING", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ERROR", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_EXCEPTION", true);
|
||||
break;
|
||||
case EnableLogLevel.Warning:
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_INFO", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ASSERT", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_WARNING", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ERROR", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_EXCEPTION", true);
|
||||
break;
|
||||
case EnableLogLevel.Error:
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_INFO", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ASSERT", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_WARNING", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ERROR", true);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_EXCEPTION", true);
|
||||
break;
|
||||
case EnableLogLevel.Exception:
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_INFO", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ASSERT", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_WARNING", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_ERROR", false);
|
||||
ModifyMacroDefine(ref macro, "ENABLE_LOG_EXCEPTION", true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (immediateUpdate)
|
||||
UpdateMacros(macro);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新projectsetting宏定义
|
||||
/// </summary>
|
||||
/// <param name="bMacroChanged"></param>
|
||||
internal static void UpdateMacros(string macroDefines)
|
||||
{
|
||||
string _macroDefines = String.Empty;
|
||||
switch (EditorUserBuildSettings.activeBuildTarget)
|
||||
{
|
||||
case BuildTarget.StandaloneWindows64:
|
||||
case BuildTarget.StandaloneWindows:
|
||||
_macroDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone);
|
||||
EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Standalone;
|
||||
break;
|
||||
case BuildTarget.Android:
|
||||
_macroDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android);
|
||||
EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Android;
|
||||
break;
|
||||
case BuildTarget.iOS:
|
||||
_macroDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS);
|
||||
EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.iOS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_macroDefines.Equals(macroDefines))
|
||||
PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, macroDefines);
|
||||
}
|
||||
|
||||
internal static void ModifyMacroDefine(ref string macroDefines, string macro, bool flag)
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
if (macroDefines.IndexOf(macro, StringComparison.Ordinal) < 0)
|
||||
macroDefines = macroDefines.Length > 0 ? $"{macroDefines};{macro}" : macro;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = macroDefines.IndexOf(macro, StringComparison.Ordinal);
|
||||
if (index >= 0)
|
||||
{
|
||||
macroDefines = macroDefines.Remove(index, macro.Length);
|
||||
|
||||
index = Mathf.Max(index - 1, 0);
|
||||
if (macroDefines.Length > 0 && macroDefines[index] == ';')
|
||||
macroDefines = macroDefines.Remove(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static BuilderEditor LoadConfig(PlatformType target, string config, string configPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(configPath))
|
||||
{
|
||||
configPath = CONFIG_FOLDER_PATH;
|
||||
}
|
||||
|
||||
string path;
|
||||
switch (target)
|
||||
{
|
||||
case PlatformType.Android:
|
||||
path = $"{configPath}/Android/{config}.asset";
|
||||
break;
|
||||
case PlatformType.iOS:
|
||||
path = $"{configPath}/iOS/{config}.asset";
|
||||
break;
|
||||
case PlatformType.Windows:
|
||||
path = $"{configPath}/Win/{config}.asset";
|
||||
break;
|
||||
default:
|
||||
path = $"{configPath}/New Builder.asset";
|
||||
break;
|
||||
}
|
||||
|
||||
string defualtPath;
|
||||
switch (target)
|
||||
{
|
||||
case PlatformType.Android:
|
||||
defualtPath = $"{configPath}/Android_Release.asset";
|
||||
break;
|
||||
case PlatformType.Windows:
|
||||
defualtPath = $"{configPath}/Win_Release.asset";
|
||||
break;
|
||||
default:
|
||||
defualtPath = $"{configPath}/iOS_Release.asset";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
path = defualtPath;
|
||||
}
|
||||
|
||||
Debug.Log("当前使用配置:" + path);
|
||||
return AssetDatabase.LoadAssetAtPath<BuilderEditor>(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提取控制台参数
|
||||
/// </summary>
|
||||
/// <param name="keyString"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetArgumentValue(string keyString)
|
||||
{
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
|
||||
keyString = $"-{keyString}";
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
if (args[i].Equals(keyString))
|
||||
{
|
||||
i++;
|
||||
return i < args.Length ? args[i] : null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从序列化对象中获取数据
|
||||
/// </summary>
|
||||
/// <param name="serializedObject"></param>
|
||||
/// <param name="argv"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static T GetArgvsFromSerializedObject<T>(SerializedObject serializedObject, string argv)
|
||||
{
|
||||
object result = null;
|
||||
if (typeof(T) == typeof(Boolean))
|
||||
{
|
||||
if (serializedObject.FindProperty(argv) != null)
|
||||
{
|
||||
result = (object)serializedObject.FindProperty(argv).boolValue;
|
||||
}
|
||||
}
|
||||
else if (typeof(T) == typeof(int))
|
||||
{
|
||||
if (serializedObject.FindProperty(argv) != null)
|
||||
{
|
||||
result = (object)serializedObject.FindProperty(argv).intValue;
|
||||
}
|
||||
}
|
||||
else if (typeof(T) == typeof(string))
|
||||
{
|
||||
if (serializedObject.FindProperty(argv) != null)
|
||||
{
|
||||
result = (object)serializedObject.FindProperty(argv).stringValue;
|
||||
}
|
||||
}
|
||||
else if (typeof(T) == typeof(BuilderBundlePolicy))
|
||||
{
|
||||
if (serializedObject.FindProperty(argv) != null)
|
||||
{
|
||||
result = (object)serializedObject.FindProperty(argv).enumValueIndex;
|
||||
}
|
||||
}
|
||||
else if (typeof(T) == typeof(BundlePolicyConfig))
|
||||
{
|
||||
if (serializedObject.FindProperty(argv) != null)
|
||||
{
|
||||
result = (object)serializedObject.FindProperty(argv).objectReferenceValue;
|
||||
}
|
||||
}
|
||||
else if (typeof(T) == typeof(EnableLogLevel))
|
||||
{
|
||||
if (serializedObject.FindProperty(argv) != null)
|
||||
{
|
||||
result = (object)serializedObject.FindProperty(argv).enumValueIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return (T)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 策略快查
|
||||
/// </summary>
|
||||
/// <param name="bundleBundlePolicy"></param>
|
||||
/// <param name="assetBundleConfig"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool PolicyEasyCheck(BuilderBundlePolicy bundleBundlePolicy, List<BundleConfigItem> assetBundleConfig)
|
||||
{
|
||||
if (bundleBundlePolicy != BuilderBundlePolicy.Configuration)
|
||||
{
|
||||
Debug.Log("非策略模式,资源已全部覆盖");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (assetBundleConfig == null || assetBundleConfig.Count == 0)
|
||||
{
|
||||
Debug.LogError("不正常的策略:策略为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
EditorUtility.DisplayProgressBar("正在进行资源检查", "快速检查中", 0.7f);
|
||||
|
||||
bool result = true;
|
||||
|
||||
HashSet<string> filter = new HashSet<string>();
|
||||
HashSet<string> customDirs = new HashSet<string>();
|
||||
string suffix = Application.dataPath.Substring(0, Application.dataPath.Length - 6);
|
||||
|
||||
foreach (var dir in assetBundleConfig)
|
||||
{
|
||||
string path = AssetDatabase.GetAssetPath(dir.mObject);
|
||||
var policy = (BundlePolicy)(dir.buildType);
|
||||
|
||||
if (policy == BundlePolicy.CustomAbName)
|
||||
customDirs.Add(suffix + path);
|
||||
filter.Add(suffix + path);
|
||||
}
|
||||
|
||||
Check(new DirectoryInfo(Application.dataPath + "/Game/AssetSource/GameResources/"));
|
||||
|
||||
//针对自定义AB名
|
||||
foreach (string dir in customDirs)
|
||||
{
|
||||
using (FileTree fileTree =
|
||||
FileTree.CreateWithExcludeFilter(dir, new[] { ".meta", ".unity", ".DS_Store" }))
|
||||
{
|
||||
List<FileInfo> files = fileTree.GetAllFiles();
|
||||
for (int i = 0; i < files.Count; ++i)
|
||||
{
|
||||
if (string.IsNullOrEmpty(AssetImporter.GetAtPath(files[i].GetAssetPath()).assetBundleName))
|
||||
{
|
||||
result = false;
|
||||
Debug.LogError("(自定义AB名策略)发现未命名的资源:" + files[i].GetAssetPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
Debug.Log("策略已完全覆盖");
|
||||
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
return result;
|
||||
|
||||
void Check(FileSystemInfo info)
|
||||
{
|
||||
if (filter.Contains(info.FullName.Replace("\\", "/")))
|
||||
return;
|
||||
if (!info.Exists) return;
|
||||
DirectoryInfo dir = info as DirectoryInfo;
|
||||
//不是目录
|
||||
if (dir == null) return;
|
||||
if (dir.Name.Equals("RawBytes")) return;
|
||||
|
||||
FileSystemInfo[] files = dir.GetFileSystemInfos();
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
FileInfo file = files[i] as FileInfo;
|
||||
//是文件
|
||||
if (file != null && !file.FullName.EndsWith(".meta"))
|
||||
{
|
||||
Debug.LogError("发现无任何策略的单文件!:" + file.FullName);
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
Check(files[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 策略快查
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal static bool PolicyEasyCheck(BuilderBundlePolicy bundleBundlePolicy, BundlePolicyConfig assetBundleConfig = null)
|
||||
{
|
||||
if (assetBundleConfig == null || assetBundleConfig.directoryBuild == null || assetBundleConfig.directoryBuild.Count == 0)
|
||||
{
|
||||
if (bundleBundlePolicy == BuilderBundlePolicy.Configuration)
|
||||
{
|
||||
Debug.LogError("不正常的策略:策略为空");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var targets = assetBundleConfig.directoryBuild;
|
||||
|
||||
return PolicyEasyCheck(bundleBundlePolicy, targets);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将数据导出成CSV
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="content"></param>
|
||||
public static void ExportCsv(string name, StringBuilder content)
|
||||
{
|
||||
string suffix = Application.dataPath.Substring(0, Application.dataPath.Length - 6);
|
||||
string logFilePath = suffix + "/BuildBundleInfo/" + name;
|
||||
if (File.Exists(logFilePath))
|
||||
File.Delete(logFilePath);
|
||||
|
||||
if (!Directory.Exists(suffix + "/BuildBundleInfo"))
|
||||
Directory.CreateDirectory(suffix + "/BuildBundleInfo");
|
||||
|
||||
using (var writer = System.IO.File.CreateText(logFilePath))
|
||||
{
|
||||
writer.Write(Encoding.UTF8.GetString(Encoding.Default.GetBytes(content.ToString())));
|
||||
writer.Close();
|
||||
}
|
||||
|
||||
string str = string.Empty;
|
||||
using (StreamReader sr = new StreamReader(logFilePath, Encoding.UTF8))
|
||||
{
|
||||
str = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
}
|
||||
|
||||
//以UTF-8带BOM格式重新写入文件
|
||||
Encoding newEncoding = new UTF8Encoding(true);
|
||||
using (StreamWriter sw = new StreamWriter(logFilePath, false, newEncoding))
|
||||
{
|
||||
sw.Write(str);
|
||||
sw.Close();
|
||||
}
|
||||
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
UnityEngine.Debug.Log(logFilePath + $" 导出完成.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理路径下数据
|
||||
/// </summary>
|
||||
internal static void ClearAllByPath(string path = null, bool deleteZip = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
path = FileSystem.ResourceRootInStreamAsset;
|
||||
}
|
||||
if (Directory.Exists(path))
|
||||
Directory.Delete(path, true);
|
||||
|
||||
if (File.Exists($"{path}.meta"))
|
||||
File.Delete($"{path}.meta");
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
//if (deleteZip)
|
||||
//{
|
||||
// LoaderUtilities.DeleteFile(FileSystem.FirstZipSteamAssetsPath);
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void RunExternalCommand(string cmd, string args, string workDir = ".")
|
||||
{
|
||||
Process p = new Process();
|
||||
p.StartInfo.FileName = cmd;
|
||||
p.StartInfo.Arguments = args;
|
||||
//p.StartInfo.UseShellExecute = false;
|
||||
//p.StartInfo.RedirectStandardInput = false;
|
||||
//p.StartInfo.RedirectStandardOutput = true;
|
||||
//p.StartInfo.RedirectStandardError = true;
|
||||
//p.StartInfo.CreateNoWindow = false;
|
||||
p.StartInfo.WorkingDirectory = workDir;
|
||||
p.Start();
|
||||
//Debug.Log(p.StandardOutput.ReadToEnd());
|
||||
p.WaitForExit();
|
||||
p.Close();
|
||||
}
|
||||
public static void RunPythonExternalCommand(string cmd, string args, string workDir = ".")
|
||||
{
|
||||
Process p = new Process();
|
||||
p.StartInfo.FileName = "python";
|
||||
p.StartInfo.Arguments = cmd + " " + args;
|
||||
|
||||
//p.StartInfo.UseShellExecute = false;
|
||||
//p.StartInfo.RedirectStandardInput = false;
|
||||
//p.StartInfo.RedirectStandardOutput = true;
|
||||
//p.StartInfo.RedirectStandardError = true;
|
||||
//p.StartInfo.CreateNoWindow = false;
|
||||
p.StartInfo.WorkingDirectory = workDir;
|
||||
p.Start();
|
||||
//Debug.Log(p.StandardOutput.ReadToEnd());
|
||||
p.WaitForExit();
|
||||
p.Close();
|
||||
}
|
||||
|
||||
internal static uint GetIntHash(string str)
|
||||
{
|
||||
int h = 0;
|
||||
int len = str.Length;
|
||||
if (len > 0)
|
||||
{
|
||||
int off = 0;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char c = str[off++];
|
||||
h = 31 * h + c;
|
||||
}
|
||||
}
|
||||
return (uint)h;
|
||||
}
|
||||
|
||||
internal static string GetStringHash(string str)
|
||||
{
|
||||
return GetIntHash(str).ToString();
|
||||
}
|
||||
}
|
||||
public static class FileInfoExtension
|
||||
{
|
||||
public static string GetAssetPath(this FileInfo fileInfo)
|
||||
{
|
||||
string uniPath = fileInfo.FullName.Replace('\\', '/');
|
||||
return uniPath.Substring(uniPath.IndexOf("Assets/"));
|
||||
}
|
||||
|
||||
public static string NameNoExtension(this FileInfo fileInfo)
|
||||
{
|
||||
return fileInfo.Name.Substring(0, fileInfo.Name.LastIndexOf('.'));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ecb34ed98b96f14b956d6d9206c5d5a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,220 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Scripting.APIUpdating;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
[CreateAssetMenu]
|
||||
[MovedFrom(true, null, null, "MakeBuildConfig")]
|
||||
public class BundlePolicyConfig : ScriptableObject
|
||||
{
|
||||
[SerializeField]
|
||||
public List<BundleConfigItem> directoryBuild;
|
||||
[SerializeField]
|
||||
public List<BuildFilter> filters;
|
||||
private string _path = TEngine.Constant.Setting.AssetRootPath;
|
||||
public void OnEnable()
|
||||
{
|
||||
if (filters == null || filters.Count == 0)
|
||||
{
|
||||
List<BuildFilter> list_filter = new List<BuildFilter>();
|
||||
BuildFilter filter = new BuildFilter { filterPath = TEngine.Constant.Setting.AssetFilterPath };
|
||||
list_filter.Add(filter);
|
||||
filters = list_filter;
|
||||
}
|
||||
|
||||
if (directoryBuild == null || directoryBuild.Count == 0)
|
||||
{
|
||||
var dir = new DirectoryInfo(_path);
|
||||
var directorise = dir.GetDirectories();
|
||||
List<BundleConfigItem> temp = new List<BundleConfigItem>();
|
||||
for (int i = 0; i < directorise.Length; i++)
|
||||
{
|
||||
if (directorise[i].Name.EndsWith(".meta"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
BundleConfigItem item = new BundleConfigItem();
|
||||
item.mObject = AssetDatabase.LoadAssetAtPath<Object>(_path + directorise[i].Name);
|
||||
item.buildType = 1;
|
||||
temp.Add(item);
|
||||
}
|
||||
this.directoryBuild = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public class BundleConfigItem
|
||||
{
|
||||
[SerializeField]
|
||||
public Object mObject;
|
||||
|
||||
[SerializeField]
|
||||
public int buildType;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class BuildFilter
|
||||
{
|
||||
[SerializeField]
|
||||
public string filterPath;
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(BundlePolicyConfig)), CanEditMultipleObjects]
|
||||
public class BundlePolicyConfigInspector : UnityEditor.Editor
|
||||
{
|
||||
private ReorderableList _reorderableList;
|
||||
private SerializedProperty prop;
|
||||
|
||||
private ReorderableList _filterableList;
|
||||
private SerializedProperty filter;
|
||||
|
||||
private BundlePolicyConfig Configuration { get { return target as BundlePolicyConfig; } }
|
||||
private void OnEnable()
|
||||
{
|
||||
prop = serializedObject.FindProperty("directoryBuild");
|
||||
_reorderableList = new ReorderableList(serializedObject, prop);
|
||||
_reorderableList.elementHeight = 30;
|
||||
_reorderableList.drawElementCallback =
|
||||
(rect, index, isActive, isFocused) =>
|
||||
{
|
||||
var element = prop.GetArrayElementAtIndex(index);
|
||||
rect.height -= 4;
|
||||
rect.y += 3;
|
||||
EditorGUI.PropertyField(rect, element);
|
||||
};
|
||||
|
||||
var defaultColor = GUI.backgroundColor;
|
||||
_reorderableList.drawElementBackgroundCallback = (rect, index, isActive, isFocused) =>
|
||||
{
|
||||
|
||||
};
|
||||
_reorderableList.drawHeaderCallback = (rect) =>
|
||||
EditorGUI.LabelField(rect, prop.displayName);
|
||||
|
||||
//过滤规则
|
||||
filter = serializedObject.FindProperty("filters");
|
||||
_filterableList = new ReorderableList(serializedObject, filter);
|
||||
_filterableList.elementHeight = 30;
|
||||
_filterableList.drawElementCallback =
|
||||
(rect, index, isActive, isFocused) =>
|
||||
{
|
||||
var element = filter.GetArrayElementAtIndex(index);
|
||||
rect.height -= 4;
|
||||
rect.y += 3;
|
||||
EditorGUI.PropertyField(rect, element);
|
||||
};
|
||||
|
||||
_filterableList.drawElementBackgroundCallback = (rect, index, isActive, isFocused) =>
|
||||
{
|
||||
|
||||
};
|
||||
_filterableList.drawHeaderCallback = (rect) =>
|
||||
EditorGUI.LabelField(rect, filter.displayName);
|
||||
}
|
||||
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
GUILayout.Label("打包配置");
|
||||
_reorderableList.DoLayoutList();
|
||||
|
||||
GUILayout.Label("美术资源检测路径");
|
||||
_filterableList.DoLayoutList();
|
||||
|
||||
//剔除错误目录
|
||||
if (_reorderableList.serializedProperty?.serializedObject != null)
|
||||
{
|
||||
var s = _reorderableList.serializedProperty.serializedObject.targetObject;
|
||||
if (s != null && s is BundlePolicyConfig bundleConfig)
|
||||
{
|
||||
List<BundleConfigItem> tDNodes = new List<BundleConfigItem>();
|
||||
foreach (var cur in bundleConfig.directoryBuild)
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(cur.mObject);
|
||||
if (!path.StartsWith(FileSystem.GameResourcePath))
|
||||
{
|
||||
Debug.LogError("剔除!不合法的路径:" + path + ",当前只支持GameResources下路径");
|
||||
tDNodes.Add(cur);
|
||||
}
|
||||
else if (path.StartsWith(FileSystem.ArtResourcePath))
|
||||
{
|
||||
Debug.LogWarning(path + ",该路径不会加入Bundle配置");
|
||||
tDNodes.Add(cur);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var node in tDNodes)
|
||||
{
|
||||
bundleConfig.directoryBuild.Remove(node);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomPropertyDrawer(typeof(BundleConfigItem))]
|
||||
public class CharacterDrawer : PropertyDrawer
|
||||
{
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
using (new EditorGUI.PropertyScope(position, label, property))
|
||||
{
|
||||
EditorGUIUtility.labelWidth = 50;
|
||||
position.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
Rect iconRect = new Rect(position)
|
||||
{
|
||||
width = 300,
|
||||
height = 20
|
||||
};
|
||||
|
||||
Rect nameRect = new Rect(position)
|
||||
{
|
||||
width = position.width - 300,
|
||||
x = position.x + 300,
|
||||
};
|
||||
|
||||
SerializedProperty Object = property.FindPropertyRelative("mObject");
|
||||
SerializedProperty BulidType = property.FindPropertyRelative("buildType");
|
||||
|
||||
Object.objectReferenceValue = EditorGUI.ObjectField(iconRect, Object.objectReferenceValue, typeof(Object), false);
|
||||
BulidType.intValue = (int)(BuilderUtility.BundlePolicy)EditorGUI.EnumPopup(nameRect, (BuilderUtility.BundlePolicy)BulidType.intValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CustomPropertyDrawer(typeof(BuildFilter))]
|
||||
public class BuildFilterDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
using (new EditorGUI.PropertyScope(position, label, property))
|
||||
{
|
||||
EditorGUIUtility.labelWidth = 50;
|
||||
position.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
Rect textRect = new Rect(position)
|
||||
{
|
||||
width = 400,
|
||||
height = 20
|
||||
};
|
||||
|
||||
SerializedProperty filterPath = property.FindPropertyRelative("filterPath");
|
||||
|
||||
filterPath.stringValue = EditorGUI.TextField(textRect, filterPath.stringValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8476ab2f16f7faf4cad514ee5ff937b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f51ddcdee52d8634095dc2379dc26c70
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,893 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using TEngine;
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
public class BuilderEditor : SoEditorBase
|
||||
{
|
||||
#region 顶端
|
||||
|
||||
[BuilderEditor("全局宏展示:", ContentType.Label, EditorContent.HorizontalStart + ",FlowA:disPlayType:1")]
|
||||
internal string symbolLaebl;
|
||||
private ContentLayout _symbolLaeblLayout = new ContentLayout(GUILayout.Height(100), GUILayout.MaxWidth(70));
|
||||
|
||||
|
||||
[SerializeField]
|
||||
[BuilderEditor("", ContentType.ScrollLabel, "FlowA:disPlayType:1")]
|
||||
private string symbolWin;
|
||||
private ContentLayout _symbolWinLayout = new ContentLayout(GUILayout.MaxHeight(100), GUILayout.ExpandWidth(true));
|
||||
|
||||
[SerializeField]
|
||||
[BuilderEditor("↓↑", ContentType.Button, EditorContent.HorizontalEnd + ",FlowA:disPlayType:1,CB:SwitchSymbolWinLayout")]
|
||||
private int _switchSymbolWinL;
|
||||
private ContentLayout _switchSymbolWinLLayout = new ContentLayout(GUILayout.Height(100), GUILayout.MaxWidth(25));
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 说明部分
|
||||
|
||||
//[BuilderEditor("使用说明", ContentType.Button, ",CB:DoHelper")]
|
||||
//private int helper;
|
||||
//private ContentLayout _helperLayout = new ContentLayout(GUILayout.Width(100));
|
||||
|
||||
|
||||
[SerializeField]
|
||||
[BuilderEditor("打包模式切换", ContentType.Enum)]
|
||||
internal BuilderDisplayType disPlayType = BuilderDisplayType.普通模式;
|
||||
private ContentLayout _disPlayTypeLayout = new ContentLayout();
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 标题
|
||||
|
||||
[BuilderEditor("普通模式", ContentType.Label, "FlowA:disPlayType:0")]
|
||||
internal string titleEasy;
|
||||
private ContentLayout _titleEasyLayout = new ContentLayout(null);
|
||||
|
||||
|
||||
[BuilderEditor("专业模式", ContentType.Label, "FlowA:disPlayType:1")]
|
||||
internal string titleDev;
|
||||
private ContentLayout _titleDevLayout = new ContentLayout(null);
|
||||
|
||||
|
||||
[BuilderEditor("30", ContentType.Space)]
|
||||
internal char space1;
|
||||
|
||||
[BuilderEditor("参数", ContentType.Label, "")]
|
||||
internal string titleArgs;
|
||||
private ContentLayout _titleArgsLayout = new ContentLayout(null);
|
||||
|
||||
[SerializeField]
|
||||
[BuilderEditor("检测到未应用的操作!!请应用参数", ContentType.Label, "FlowA:hasSave:0&autoUdate:0")]
|
||||
internal bool hasSave = false;
|
||||
private ContentLayout _hasSaveLayout = new ContentLayout(null);
|
||||
|
||||
|
||||
[BuilderEditor("0", ContentType.Space, EditorContent.HorizontalStart)]
|
||||
internal char spaceautoUdate1;
|
||||
|
||||
[SerializeField]
|
||||
[BuilderEditor("参数自动应用", ContentType.Toggle, "CB:SwitchApplyArgs")]
|
||||
internal bool autoUdate = false;
|
||||
|
||||
[BuilderEditor("应用参数", ContentType.Button, "FlowA:autoUdate:0,CB:ApplyArgs")]
|
||||
internal string autoUdateBtn;
|
||||
|
||||
[BuilderEditor("0", ContentType.Space, EditorContent.HorizontalEnd)]
|
||||
internal char spaceautoUdate2;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 打包选项
|
||||
|
||||
[SerializeField]
|
||||
[BuilderEditor("目标平台", ContentType.Enum, "CB:SwitchPlatform")]
|
||||
internal BuilderUtility.PlatformType platform = BuilderUtility.PlatformType.Android;
|
||||
private ContentLayout _platformLayout = new ContentLayout(null);
|
||||
|
||||
[SerializeField]
|
||||
[BuilderEditor("打包模式", ContentType.Enum, "CB:SwitchBuildType")]
|
||||
internal BuilderUtility.BuildType buildType = BuilderUtility.BuildType.Release;
|
||||
|
||||
[FormerlySerializedAs("_enableLogLevel")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("Log输出等级(仅针对Release版本)", ContentType.Enum, "FlowA:disPlayType:1,CB:SwitchLogLevel")]
|
||||
internal BuilderUtility.EnableLogLevel enableLogLevel = BuilderUtility.EnableLogLevel.Warning;
|
||||
|
||||
[FormerlySerializedAs("_scriptingBackend")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("编译类型", ContentType.Enum, "FlowA:disPlayType:1&platform:0r1r2,CB:SwitchScriptingBackend")]
|
||||
internal BuilderUtility.ScriptBackend scriptingBackend = BuilderUtility.ScriptBackend.Mono;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 额外开关
|
||||
|
||||
|
||||
[FormerlySerializedAs("_bCleanAssetBundleCache")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("增量构建AssetBundle", ContentType.Toggle, "FlowA:buildType:0r2&disPlayType:1")]
|
||||
internal bool bIncrementBuildAB = false;
|
||||
|
||||
[FormerlySerializedAs("_bEnableProfiler")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("Enable Profiler", ContentType.Toggle, "FlowA:buildType:2&disPlayType:1,CB:EnableProfiler")]
|
||||
internal bool bEnableProfiler = false;
|
||||
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
[FormerlySerializedAs("_bEnableDeepProfiler")]
|
||||
[SerializeField] [BuilderEditor("Enable DeepProfiling Support", ContentType.Toggle, "FlowA:buildType:2&disPlayType:1,CB:EnableDeepProfiler")]
|
||||
internal bool bEnableDeepProfiler = false;
|
||||
#endif
|
||||
|
||||
[FormerlySerializedAs("_bExportAndroidProject")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("导出Android工程", ContentType.Toggle, "FlowA:buildType:1r2&disPlayType:1,CB:EnableExportAndroidProject")]
|
||||
internal bool bExportAndroidProject = false;
|
||||
|
||||
[FormerlySerializedAs("_bCollectShaderVariant")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("单独打包Shader", ContentType.Toggle, "FlowA:disPlayType:1")]
|
||||
internal bool bCollectShaderVariant = false;
|
||||
|
||||
[SerializeField]
|
||||
[BuilderEditor("启动GM", ContentType.Toggle, "FlowA:disPlayType:1,CB:EnableGM")]
|
||||
private bool bEnableGM = false;
|
||||
|
||||
//[SerializeField]
|
||||
//[BuilderEditor("剔除首包解压", ContentType.Toggle, "FlowA:disPlayType:1,CB:EnableIgnoreFirstZip")]
|
||||
//internal bool bIgnoreFirstZip = false;
|
||||
|
||||
//[FormerlySerializedAs("_bIgnorHotFix")]
|
||||
//[SerializeField]
|
||||
//[BuilderEditor("忽略热更", ContentType.Toggle, "FlowA:disPlayType:1,CB:IgnoreHotFix")]
|
||||
//private bool bIgnoreHotFix = false;
|
||||
//private ContentLayout _bIgnoreHotFixLayout = new ContentLayout();
|
||||
|
||||
//[FormerlySerializedAs("_bUseDlc")]
|
||||
//[SerializeField]
|
||||
//[BuilderEditor("启用大小包模式", ContentType.Toggle, "FlowA:disPlayType:1,CB:UseDlc")]
|
||||
//internal bool bUseDlc = false;
|
||||
//private ContentLayout _bUseDlcLayout = new ContentLayout();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region 加密部分
|
||||
[SerializeField]
|
||||
[BuilderEditor("开启加密", ContentType.Toggle, "FlowA:disPlayType:1")]
|
||||
internal bool bEnableEncrypt = true;
|
||||
|
||||
//[SerializeField]
|
||||
//[BuilderEditor(" \u2022 Lua加密", ContentType.Toggle, "FlowA:bEnableEncrypt:1,FlowS:bEnableEncrypt:1")]
|
||||
//internal bool bEnableLuaEncrypt = true;
|
||||
|
||||
|
||||
[SerializeField]
|
||||
[BuilderEditor(" \u2022AB加密偏移(0:不加密):", ContentType.TextField, "FlowA:bEnableEncrypt:1,FlowS:bEnableEncrypt:1")]
|
||||
internal string abEncryptOffset = "0";
|
||||
private ContentLayout _abEncryptOffsetLayout = new ContentLayout(GUILayout.ExpandWidth(true));
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 打包参数
|
||||
[FormerlySerializedAs("_builderPolicy")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("AssetBundle策略", ContentType.Enum, "")]
|
||||
internal BuilderUtility.BuilderBundlePolicy builderBundlePolicy = BuilderUtility.BuilderBundlePolicy.Directory;
|
||||
|
||||
[FormerlySerializedAs("_assetBundleConfig")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("AssetBundle配置", ContentType.Obj, ",FlowA:builderBundlePolicy:2")]
|
||||
internal BundlePolicyConfig bundleConfig;
|
||||
|
||||
[FormerlySerializedAs("_bundleIdentifier")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("包名", ContentType.TextField, "FlowA:disPlayType:1,CB:ChangeBundleIdentifier")]
|
||||
internal string bundleIdentifier = "com.TEngine.TEngineDemo";
|
||||
|
||||
[FormerlySerializedAs("_productName")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("产品名", ContentType.TextField, "FlowA:disPlayType:1,CB:ChangeProductName")]
|
||||
internal string productName = "TEngine";
|
||||
|
||||
[FormerlySerializedAs("_bundleVersion")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("APP版本号", ContentType.TextField, "FlowA:disPlayType:1,CB:ChangeBundleVersion")]
|
||||
internal string bundleVersion = "1.0";
|
||||
|
||||
[FormerlySerializedAs("_ABVersion")]
|
||||
[SerializeField]
|
||||
[BuilderEditor("资源版本号", ContentType.TextField, "FlowA:disPlayType:1,CB:ChangeABVersion")]
|
||||
internal string ABVersion = "0";
|
||||
|
||||
[BuilderEditor("15", ContentType.Space)]
|
||||
private char space12;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 打包按钮
|
||||
[BuilderEditor("Copy And Encrpt DLL", ContentType.Button, ",CB:CopyDLL,FlowA:disPlayType:1")]
|
||||
private int copydll;
|
||||
|
||||
[BuilderEditor("Build AssetBundle", ContentType.Button, ",CB:BuildAssetBundle,FlowA:disPlayType:1")]
|
||||
private int buildAssetBundle;
|
||||
|
||||
[BuilderEditor("Gen Md5(生成MD5)", ContentType.Button, ",CB:GenMd5,FlowA:disPlayType:1")]
|
||||
private int genMd5;
|
||||
|
||||
[BuilderEditor("Build", ContentType.Button, "CB:BuildApk")]
|
||||
private int build;
|
||||
|
||||
[BuilderEditor("直接出包(跳过ab环节)", ContentType.Button, "CB:DirectBuildApk,FlowA:disPlayType:1")]
|
||||
private int directBuild;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 工程导出目录
|
||||
/// </summary>
|
||||
[SerializeField] internal string ProjectExportPath;
|
||||
[SerializeField] internal string _bBaseVersion = "0";
|
||||
[SerializeField] internal string _bResVersion = "0";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 用于额外补充风格\必要的初始化
|
||||
/// </summary>
|
||||
public override void AdditionalInit()
|
||||
{
|
||||
SwitchSymbolWinLayout("Const");
|
||||
|
||||
|
||||
_symbolWinLayout.SetStyles(EditorStyles.helpBox);
|
||||
_symbolWinLayout.EditorStyles.fontSize = 12;
|
||||
|
||||
_titleEasyLayout.EditorStyles = new GUIStyle() { fontSize = 50 };
|
||||
_titleEasyLayout.EditorStyles.normal.textColor = Color.white;
|
||||
_titleDevLayout.EditorStyles = new GUIStyle() { fontSize = 50 };
|
||||
_titleDevLayout.EditorStyles.normal.textColor = Color.white;
|
||||
|
||||
//参数Label
|
||||
_titleArgsLayout.EditorStyles = new GUIStyle("boldLabel");
|
||||
_titleArgsLayout.EditorStyles.fontSize = 12;
|
||||
//未保存的警告
|
||||
_hasSaveLayout.EditorStyles = new GUIStyle("boldLabel");
|
||||
_hasSaveLayout.EditorStyles.normal.textColor = Color.red;
|
||||
_hasSaveLayout.EditorStyles.fontSize = 12;
|
||||
|
||||
//目标平台
|
||||
_platformLayout.EditorStyles = new GUIStyle("MiniPopup");
|
||||
_platformLayout.EditorStyles.normal.textColor = new Color(30 / 255f, 144 / 255f, 255 / 255f);
|
||||
|
||||
//_bIgnoreHotFixLayout.EditorStyles = EditorStyles.radioButton;
|
||||
//_bUseDlcLayout.EditorStyles = EditorStyles.radioButton;
|
||||
|
||||
}
|
||||
|
||||
public override void OnAnyThingChange(string args)
|
||||
{
|
||||
hasSave = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用说明
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void DoHelper(string args)
|
||||
{
|
||||
//打开本地MD
|
||||
var scriptObj = MonoScript.FromScriptableObject(this);
|
||||
var path = AssetDatabase.GetAssetPath(scriptObj).Replace("\\", "/");
|
||||
path = path.Substring(0, path.LastIndexOf("/", StringComparison.Ordinal)) + "/BuilderUserHelper.md";
|
||||
|
||||
EditorUtility.OpenWithDefaultApp(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 切换平台
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
internal void SwitchPlatform(string args)
|
||||
{
|
||||
if (BuilderUtility.PlatformType.TryParse<BuilderUtility.PlatformType>(args, out var plat))
|
||||
{
|
||||
switch (plat)
|
||||
{
|
||||
case BuilderUtility.PlatformType.Windows:
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone,
|
||||
BuildTarget.StandaloneWindows);
|
||||
break;
|
||||
case BuilderUtility.PlatformType.OSX:
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone,
|
||||
BuildTarget.StandaloneOSX);
|
||||
break;
|
||||
case BuilderUtility.PlatformType.Android:
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android);
|
||||
break;
|
||||
case BuilderUtility.PlatformType.iOS:
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.iOS, BuildTarget.iOS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LoadMacroConfigures();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 切换日志等级
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void SwitchLogLevel(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
LoadMacroConfigures();
|
||||
if (BuilderUtility.EnableLogLevel.TryParse<BuilderUtility.EnableLogLevel>(args, out var plat))
|
||||
{
|
||||
BuilderUtility.RefreshLogLevelMacro(ref _macroDefines, plat);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SwitchScriptingBackend(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
LoadMacroConfigures();
|
||||
if (BuilderUtility.ScriptBackend.TryParse<BuilderUtility.ScriptBackend>(args, out var scriptBackend))
|
||||
{
|
||||
BuilderUtility.RefreshBackendMacro(ref _macroDefines, scriptBackend);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更改打包方式:Editor、Android、IOS
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
internal void SwitchBuildType(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
LoadMacroConfigures();
|
||||
if (BuilderUtility.BuildType.TryParse<BuilderUtility.BuildType>(args, out var plat))
|
||||
{
|
||||
BuilderUtility.SetBuildTypeMacroDefines(ref _macroDefines, plat);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableProfiler(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
bool enable = args.Equals("1");
|
||||
EditorUserBuildSettings.connectProfiler = enable;
|
||||
}
|
||||
private void EnableDeepProfiler(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
bool enable = args.Equals("1");
|
||||
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
EditorUserBuildSettings.buildWithDeepProfilingSupport = enable;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void EnableExportAndroidProject(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
bool enable = args.Equals("1");
|
||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = enable;
|
||||
}
|
||||
|
||||
private void EnableGM(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
LoadMacroConfigures();
|
||||
BuilderUtility.EnableGMSymbols(ref _macroDefines, args.Equals("1"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 忽略首包解压
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void EnableIgnoreFirstZip(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
LoadMacroConfigures();
|
||||
BuilderUtility.IgnorFirstZip(ref _macroDefines, args.Equals("1"));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 策略快查
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void DoCheckPolicy(string args)
|
||||
{
|
||||
BuilderUtility.PolicyEasyCheck(builderBundlePolicy, bundleConfig);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更改包名
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void ChangeBundleIdentifier(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
PlayerSettings.SetApplicationIdentifier(EditorUserBuildSettings.selectedBuildTargetGroup, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更改产品名
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void ChangeProductName(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
PlayerSettings.productName = args;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更改版本号
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void ChangeBundleVersion(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
PlayerSettings.bundleVersion = args;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更改AB版本号
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void ChangeABVersion(string args)
|
||||
{
|
||||
if (!autoUdate)
|
||||
return;
|
||||
GameConfig.Instance.WriteResVersion(args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用商店地址
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void ChangeAppUrl(string args)
|
||||
{
|
||||
BuilderUtility.SetAppURL(args);
|
||||
}
|
||||
|
||||
private void SwitchApplyArgs(string args)
|
||||
{
|
||||
if (args.Equals("1"))
|
||||
ApplyArgs("");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一应用参数
|
||||
/// </summary>
|
||||
internal void ApplyArgs(string args)
|
||||
{
|
||||
LoadMacroConfigures();
|
||||
BuilderUtility.ClearMacros(ref _macroDefines, false);
|
||||
|
||||
//分平台关闭开关
|
||||
switch (buildType)
|
||||
{
|
||||
case BuilderUtility.BuildType.Editor:
|
||||
break;
|
||||
case BuilderUtility.BuildType.Release:
|
||||
{
|
||||
//关闭Profiler
|
||||
bEnableProfiler = false;
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
bEnableDeepProfiler = false;
|
||||
#endif
|
||||
//禁止增量打包
|
||||
bIncrementBuildAB = false;
|
||||
}
|
||||
break;
|
||||
case BuilderUtility.BuildType.Development:
|
||||
break;
|
||||
}
|
||||
if (!bExportAndroidProject)
|
||||
{
|
||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
|
||||
}
|
||||
|
||||
//加密部分
|
||||
if (!bEnableEncrypt)
|
||||
{
|
||||
//bEnableLuaEncrypt = false;
|
||||
}
|
||||
|
||||
//宏部分
|
||||
BuilderUtility.RefreshLogLevelMacro(ref _macroDefines, enableLogLevel, false);
|
||||
BuilderUtility.RefreshBackendMacro(ref _macroDefines, scriptingBackend, false);
|
||||
BuilderUtility.EnableGMSymbols(ref _macroDefines, bEnableGM, false);
|
||||
//必须最后一个调用
|
||||
BuilderUtility.SetMacroDefines(ref _macroDefines, buildType, false);
|
||||
|
||||
//Setting部分
|
||||
EditorUserBuildSettings.connectProfiler = bEnableProfiler;
|
||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = bExportAndroidProject;
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
EditorUserBuildSettings.buildWithDeepProfilingSupport = bEnableDeepProfiler;
|
||||
#endif
|
||||
//参数部分
|
||||
PlayerSettings.SetApplicationIdentifier(EditorUserBuildSettings.selectedBuildTargetGroup, bundleIdentifier);
|
||||
PlayerSettings.productName = productName;
|
||||
PlayerSettings.bundleVersion = bundleVersion;
|
||||
|
||||
BuilderUtility.UpdateMacros(_macroDefines);
|
||||
|
||||
hasSave = true;
|
||||
|
||||
Save();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private void GenMd5(string args)
|
||||
{
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Build AssetBundle", "请等待编译完成", "ok");
|
||||
return;
|
||||
}
|
||||
TEngineEditorUtil.GenMd5List();
|
||||
GUIUtility.ExitGUI();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private void BuildAssetBundle(string args)
|
||||
{
|
||||
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Build AssetBundle", "请等待编译完成", "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyArgs("");
|
||||
|
||||
if (!BuilderUtility.PolicyEasyCheck(builderBundlePolicy, bundleConfig))
|
||||
{
|
||||
if (!EditorUtility.DisplayDialog("资源检查警告", "发现策略未覆盖到的资源,是否继续", "继续", "退出打包"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Builder.Instance.SetBuilderConfig(this);
|
||||
|
||||
Builder.Instance.BuildAssetBundle();
|
||||
GUIUtility.ExitGUI();
|
||||
|
||||
}
|
||||
|
||||
public static void CopyFilefolder(string sourceFilePath, string targetFilePath)
|
||||
{
|
||||
string[] files = Directory.GetFiles(sourceFilePath);
|
||||
string fileName;
|
||||
string destFile;
|
||||
if (!Directory.Exists(targetFilePath))
|
||||
{
|
||||
Directory.CreateDirectory(targetFilePath);
|
||||
}
|
||||
foreach (string s in files)
|
||||
{
|
||||
fileName = Path.GetFileName(s);
|
||||
destFile = Path.Combine(targetFilePath, fileName);
|
||||
File.Copy(s, destFile, true);
|
||||
}
|
||||
|
||||
string[] filefolders = Directory.GetFiles(sourceFilePath);
|
||||
|
||||
DirectoryInfo dirinfo = new DirectoryInfo(sourceFilePath);
|
||||
|
||||
DirectoryInfo[] subFileFolder = dirinfo.GetDirectories();
|
||||
for (int j = 0; j < subFileFolder.Length; j++)
|
||||
{
|
||||
string subSourcePath = sourceFilePath + "\\" + subFileFolder[j].ToString();
|
||||
string subTargetPath = targetFilePath + "\\" + subFileFolder[j].ToString();
|
||||
CopyFilefolder(subSourcePath, subTargetPath);
|
||||
}
|
||||
}
|
||||
|
||||
public bool FileRename(string sourceFile, string destinationPath, string destinationFileName)
|
||||
{
|
||||
FileInfo tempFileInfo;
|
||||
FileInfo tempBakFileInfo;
|
||||
DirectoryInfo tempDirectoryInfo;
|
||||
|
||||
tempFileInfo = new FileInfo(sourceFile);
|
||||
tempDirectoryInfo = new DirectoryInfo(destinationPath);
|
||||
tempBakFileInfo = new FileInfo(destinationPath + "\\" + destinationFileName);
|
||||
try
|
||||
{
|
||||
if (!tempDirectoryInfo.Exists)
|
||||
{
|
||||
tempDirectoryInfo.Create();
|
||||
}
|
||||
if (tempBakFileInfo.Exists)
|
||||
{
|
||||
tempBakFileInfo.Delete();
|
||||
}
|
||||
tempFileInfo.MoveTo(destinationPath + "\\" + destinationFileName);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
TLogger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void CopyDLL(string args)
|
||||
{
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Build AssetBundle", "请等待编译完成", "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyArgs("");
|
||||
|
||||
if (File.Exists(Application.dataPath + $"\\TResources\\DLL\\{Constant.Setting.HotFixedDllName}.dll.bytes"))
|
||||
{
|
||||
TLogger.LogWarning("存在DLL的bytes 执行删除操作");
|
||||
FileInfo del = new FileInfo(Application.dataPath + $"\\TResources\\DLL\\{Constant.Setting.HotFixedDllName}.dll.bytes");
|
||||
del.Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
TLogger.LogInfo("不存在DLL的bytes 直接拷贝加密");
|
||||
}
|
||||
|
||||
FileInfo fi = new FileInfo(Application.dataPath + $"/DLL/{Constant.Setting.HotFixedDllName}.dll");
|
||||
|
||||
fi.CopyTo(Path.Combine(Path.GetDirectoryName(Application.dataPath + "\\TResources\\DLL\\"), $"{Constant.Setting.HotFixedDllName}.dll.bytes"));
|
||||
|
||||
TLogger.LogInfoSuccessd("拷贝加密DLL的bytes成功");
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
private void BuildApk(string args)
|
||||
{
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Build Apk", "请等待编译完成", "ok");
|
||||
return;
|
||||
}
|
||||
Save();
|
||||
|
||||
if (bundleVersion.Split('.').Length != 2)
|
||||
{
|
||||
Debug.LogError("版本号需要两位(*.*)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (buildType == (BuilderUtility.BuildType)BuilderUtility.BuildType.Editor)
|
||||
{
|
||||
Debug.LogError("编辑器模式不支持打包,请看描述");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (!BuilderUtility.PolicyEasyCheck(builderBundlePolicy, bundleConfig))
|
||||
{
|
||||
if (!EditorUtility.DisplayDialog("资源检查警告", "发现策略未覆盖到的资源,是否继续", "继续", "退出打包"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyArgs("");
|
||||
Builder.Instance.SetBuilderConfig(this);
|
||||
Builder.Instance.Build(false);
|
||||
|
||||
}
|
||||
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接打APK包
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void DirectBuildApk(string args)
|
||||
{
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Direct Build Apk", "请等待编译完成", "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
Save();
|
||||
|
||||
if (bundleVersion.Split('.').Length != 2)
|
||||
{
|
||||
Debug.LogError("版本号需要两位(*.*)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (buildType == (BuilderUtility.BuildType)BuilderUtility.BuildType.Editor)
|
||||
{
|
||||
Debug.LogError("编辑器模式不支持打包,请看描述");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Directory.Exists(FileSystem.AssetBundleBuildPath) ||
|
||||
Directory.GetFileSystemEntries(FileSystem.AssetBundleBuildPath).Length <= 0)
|
||||
{
|
||||
Debug.LogWarning("未打包assetbundle资源");
|
||||
}
|
||||
|
||||
ApplyArgs("");
|
||||
Builder.Instance.SetBuilderConfig(this);
|
||||
Builder.Instance.Build(true);
|
||||
}
|
||||
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
|
||||
internal void SwitchSymbolWinLayout(string args)
|
||||
{
|
||||
if (!args.Equals("Const"))
|
||||
{
|
||||
if (_switchSymbolWinL == 0)
|
||||
{
|
||||
_switchSymbolWinL = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_switchSymbolWinL = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_switchSymbolWinL == 1)
|
||||
symbolWin = _macroDefines.Replace(";", "------");
|
||||
else
|
||||
symbolWin = _macroDefines.Replace(";", "\n");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存数据
|
||||
/// </summary>
|
||||
internal void Save()
|
||||
{
|
||||
EditorUtility.SetDirty(this);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
[MenuItem("TEngine/A B 配置|Create Asset Bundle Config", priority = 1500)]
|
||||
internal static void OpenBuilder()
|
||||
{
|
||||
bool isExists = false;
|
||||
string[] assetGuids = AssetDatabase.FindAssets("t:BuilderEditor");
|
||||
for (int i = 0, len = assetGuids.Length; i < len; i++)
|
||||
{
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(assetGuids[i]);
|
||||
if (assetPath.EndsWith(".asset"))
|
||||
{
|
||||
Type type = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
|
||||
if (type == typeof(BuilderEditor) && !assetPath.StartsWith("Packages/"))
|
||||
{
|
||||
isExists = true;
|
||||
string directory = assetPath.Substring(0, assetPath.LastIndexOf('/'));
|
||||
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<Object>(directory));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExists)
|
||||
{
|
||||
if (!EditorUtility.DisplayDialog("创建打包配置定位失败", "是否自动创建,默认为Release", "继续", "退出"))
|
||||
return;
|
||||
|
||||
string androidDir = "Assets/BuildConfig/Editor" + "/Android";
|
||||
if (!Directory.Exists(androidDir))
|
||||
Directory.CreateDirectory(androidDir);
|
||||
|
||||
string iosDir = "Assets/BuildConfig/Editor" + "/iOS";
|
||||
if (!Directory.Exists(iosDir))
|
||||
Directory.CreateDirectory(iosDir);
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
string path = androidDir + "/Android_Release.asset";
|
||||
int index = 1;
|
||||
while (File.Exists(path))
|
||||
{
|
||||
path = androidDir + $"/Android_Release_{index++}.asset";
|
||||
}
|
||||
|
||||
BuilderEditor builder = CreateInstance<BuilderEditor>();
|
||||
AssetDatabase.CreateAsset(builder, path);
|
||||
EditorGUIUtility.PingObject(builder);
|
||||
AssetDatabase.OpenAsset(builder);
|
||||
}
|
||||
}
|
||||
internal void OnInit()
|
||||
{
|
||||
LoadMacroConfigures();
|
||||
if (autoUdate)
|
||||
MacroInit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 宏初始化
|
||||
/// </summary>
|
||||
internal void MacroInit()
|
||||
{
|
||||
ApplyArgs("");
|
||||
}
|
||||
|
||||
#region 宏同步
|
||||
|
||||
private static string _macroDefines = "";
|
||||
|
||||
internal static void LoadMacroConfigures()
|
||||
{
|
||||
switch (EditorUserBuildSettings.activeBuildTarget)
|
||||
{
|
||||
case BuildTarget.StandaloneWindows64:
|
||||
case BuildTarget.StandaloneWindows:
|
||||
_macroDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone);
|
||||
EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Standalone;
|
||||
break;
|
||||
case BuildTarget.StandaloneOSX:
|
||||
_macroDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone);
|
||||
EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Standalone;
|
||||
break;
|
||||
case BuildTarget.Android:
|
||||
_macroDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android);
|
||||
EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Android;
|
||||
break;
|
||||
case BuildTarget.iOS:
|
||||
_macroDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS);
|
||||
EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.iOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal enum BuilderDisplayType
|
||||
{
|
||||
普通模式,
|
||||
专业模式
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b3e95ad218591b42a781ca61fd7e22e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
internal class BuilderEditorAttribute : Attribute
|
||||
{
|
||||
public EditorContent Content;
|
||||
|
||||
public BuilderEditorAttribute(string title)
|
||||
{
|
||||
Content = new EditorContent();
|
||||
Content.Title = title;
|
||||
}
|
||||
|
||||
public BuilderEditorAttribute(string title, ContentType component, string extra)
|
||||
{
|
||||
Content = new EditorContent();
|
||||
Content.Title = title;
|
||||
Content.Component = component;
|
||||
Content.Extra = extra;
|
||||
}
|
||||
|
||||
|
||||
public BuilderEditorAttribute(string title, ContentType component)
|
||||
{
|
||||
Content = new EditorContent();
|
||||
Content.Title = title;
|
||||
Content.Component = component;
|
||||
Content.Extra = "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal enum ContentType
|
||||
{
|
||||
Space,
|
||||
Button,
|
||||
Label,
|
||||
SelectableLabel,
|
||||
Enum,
|
||||
Toggle,
|
||||
TextField,
|
||||
Obj,
|
||||
ScrollLabel,
|
||||
}
|
||||
|
||||
internal class EditorContent
|
||||
{
|
||||
public const string HorizontalStart = "HorizontalStart";
|
||||
public const string HorizontalEnd = "HorizontalEnd";
|
||||
|
||||
public string Title;
|
||||
public ContentType Component;
|
||||
public string Extra;
|
||||
public GUIStyle EditorStyles = default;
|
||||
public GUILayoutOption[] LayoutOptions = null;
|
||||
|
||||
public string FieldName;
|
||||
public Type Type;
|
||||
public string[] EnumOptions;
|
||||
public bool IsShow = true;
|
||||
public Vector3 ScrollPos;
|
||||
}
|
||||
|
||||
internal class ContentLayout
|
||||
{
|
||||
[NonSerialized]
|
||||
public GUIStyle EditorStyles = default;
|
||||
[NonSerialized]
|
||||
public GUILayoutOption[] LayoutOptions = null;
|
||||
|
||||
public ContentLayout(params GUILayoutOption[] layoutOptions)
|
||||
{
|
||||
LayoutOptions = layoutOptions;
|
||||
}
|
||||
|
||||
public void SetStyles(GUIStyle style)
|
||||
{
|
||||
EditorStyles = style;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bfaf12499eab7344925c43fff46ed19
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,18 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
[CustomEditor(typeof(BuilderEditor))]
|
||||
public class BuilderInspector : InspectorBase
|
||||
{
|
||||
private BuilderEditor _target;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
_target = target as BuilderEditor;
|
||||
if (_target != null)
|
||||
_target.OnInit();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcbf4b4324520da4eb6d97c19cb3b80d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,453 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using TEngineCore.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
public class InspectorBase : UnityEditor.Editor
|
||||
{
|
||||
|
||||
private Dictionary<string, SerializedProperty> _serializedProperties = new Dictionary<string, SerializedProperty>();
|
||||
|
||||
List<EditorContent> coms = new List<EditorContent>();
|
||||
|
||||
private Dictionary<string, EditorContent> _comDic = new Dictionary<string, EditorContent>();
|
||||
|
||||
private SoEditorBase _baseTarget;
|
||||
|
||||
private bool _hasDispose;
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
SetTarget((SoEditorBase)serializedObject.targetObject);
|
||||
}
|
||||
|
||||
protected void SetTarget(SoEditorBase target)
|
||||
{
|
||||
_baseTarget = target;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
_baseTarget.AdditionalInit();
|
||||
var type = _baseTarget.GetType().GetTypeInfo();
|
||||
_serializedProperties = new Dictionary<string, SerializedProperty>();
|
||||
ContentLayout layout = null;
|
||||
foreach (var member in type.DeclaredMembers)
|
||||
{
|
||||
var fie = type.GetDeclaredField(member.Name);
|
||||
if (fie != null)
|
||||
{
|
||||
if (fie.FieldType.IsAssignableFrom(typeof(ContentLayout)))
|
||||
{
|
||||
layout = (ContentLayout)fie.GetValue(_baseTarget);
|
||||
coms[coms.Count - 1].EditorStyles = layout.EditorStyles;
|
||||
coms[coms.Count - 1].LayoutOptions = layout.LayoutOptions;
|
||||
layout = null;
|
||||
}
|
||||
|
||||
foreach (var att in member.GetCustomAttributes(false))
|
||||
{
|
||||
if (att is BuilderEditorAttribute a)
|
||||
{
|
||||
if (a.Content != null)
|
||||
{
|
||||
_serializedProperties.Add(member.Name, serializedObject.FindProperty(member.Name));
|
||||
coms.Add(new EditorContent()
|
||||
{
|
||||
Title = a.Content.Title,
|
||||
Component = a.Content.Component,
|
||||
Extra = a.Content.Extra,
|
||||
|
||||
FieldName = member.Name,
|
||||
});
|
||||
coms[coms.Count - 1].Type = type.GetDeclaredField(member.Name).FieldType;
|
||||
if (coms[coms.Count - 1].Type.IsSubclassOf(typeof(Enum)))
|
||||
{
|
||||
List<string> enums = new List<string>();
|
||||
var box = coms[coms.Count - 1].Type.GetTypeInfo().DeclaredMembers;
|
||||
bool skipFirst = true;
|
||||
foreach (var field in box)
|
||||
{
|
||||
if (skipFirst)
|
||||
{
|
||||
skipFirst = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
enums.Add(field.Name);
|
||||
}
|
||||
|
||||
coms[coms.Count - 1].EnumOptions = enums.ToArray();
|
||||
continue;
|
||||
}
|
||||
if (!coms[coms.Count - 1].Type.IsSubclassOf(typeof(Enum)) && a.Content.Component == ContentType.Enum)
|
||||
{
|
||||
Debug.LogError(coms[coms.Count - 1].FieldName + "的类型非枚举! 已剔除");
|
||||
coms.RemoveAt(coms.Count - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var com in coms)
|
||||
{
|
||||
_comDic.Add(com.FieldName, com);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int saveCount = 0;
|
||||
private const int saveCriticalPoint = 1000;
|
||||
private bool needSave = false;
|
||||
private bool canDraw = false;
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
if (coms == null || coms.Count == 0)
|
||||
{
|
||||
Init();
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckIfDispose())
|
||||
return;
|
||||
|
||||
needSave = false;
|
||||
for (int i = 0; i < coms.Count; ++i)
|
||||
{
|
||||
var extra = coms[i].Extra.Split(',');
|
||||
|
||||
bool canShow = true;
|
||||
string cbName = null;
|
||||
for (int j = 0; j < extra.Length; ++j)
|
||||
{
|
||||
if (extra[j].StartsWith("Hori"))
|
||||
continue;
|
||||
if (extra[j].StartsWith("CB:"))
|
||||
{
|
||||
cbName = extra[j].Substring(3);
|
||||
}
|
||||
else if (extra[j].StartsWith("Flow"))
|
||||
{
|
||||
if (!canShow)
|
||||
continue;
|
||||
|
||||
bool isFlowShow = extra[j].StartsWith("FlowS");
|
||||
extra[j] = extra[j].Substring(6);
|
||||
if (extra[j].Contains("|"))
|
||||
{
|
||||
var parents = extra[j].Split('|');
|
||||
foreach (var parentInfo in parents)
|
||||
{
|
||||
canShow = CheckIfCanShowByParentInfo(parentInfo, isFlowShow);
|
||||
|
||||
if (canShow)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var parents = extra[j].Split('&');
|
||||
foreach (var parentInfo in parents)
|
||||
{
|
||||
canShow = CheckIfCanShowByParentInfo(parentInfo, isFlowShow);
|
||||
if (!canShow)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
coms[i].IsShow = canShow;
|
||||
|
||||
if (UnityEngine.Event.current.type == EventType.Layout)
|
||||
{
|
||||
canDraw = true;
|
||||
}
|
||||
if (!canDraw)
|
||||
return;
|
||||
bool horizontalStart = extra.Length > 0 && extra[0].Equals(EditorContent.HorizontalStart);
|
||||
bool horizontalEnd = extra.Length > 0 && extra[0].Equals(EditorContent.HorizontalEnd);
|
||||
if (horizontalStart)
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (canShow)
|
||||
{
|
||||
DisplayComponets(i, cbName, ref needSave);
|
||||
}
|
||||
|
||||
if (horizontalEnd)
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (canShow)
|
||||
GUILayout.Space(5);
|
||||
|
||||
}
|
||||
|
||||
saveCount++;
|
||||
|
||||
if (needSave)
|
||||
{
|
||||
FunctionCall("OnAnyThingChange", "");
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayComponets(int i, string cbName, ref bool needSave)
|
||||
{
|
||||
|
||||
switch (coms[i].Component)
|
||||
{
|
||||
case ContentType.Space:
|
||||
float space = (float)Convert.ToDouble(coms[i].Title);
|
||||
GUILayout.Space(space);
|
||||
break;
|
||||
case ContentType.Label:
|
||||
string valueLabel = coms[i].Title;
|
||||
if (string.IsNullOrEmpty(valueLabel))
|
||||
{
|
||||
valueLabel = _serializedProperties[coms[i].FieldName].stringValue;
|
||||
}
|
||||
|
||||
if (coms[i].EditorStyles != null && coms[i].LayoutOptions != null)
|
||||
GUILayout.Label(valueLabel, coms[i].EditorStyles, coms[i].LayoutOptions);
|
||||
else if (coms[i].EditorStyles != null)
|
||||
GUILayout.Label(valueLabel, coms[i].EditorStyles);
|
||||
else if (coms[i].LayoutOptions != null)
|
||||
GUILayout.Label(valueLabel, coms[i].LayoutOptions);
|
||||
else
|
||||
GUILayout.Label(valueLabel);
|
||||
break;
|
||||
case ContentType.SelectableLabel:
|
||||
string valueSLabel = coms[i].Title;
|
||||
if (string.IsNullOrEmpty(valueSLabel))
|
||||
{
|
||||
valueSLabel = _serializedProperties[coms[i].FieldName].stringValue;
|
||||
}
|
||||
|
||||
if (coms[i].EditorStyles != null && coms[i].LayoutOptions != null)
|
||||
EditorGUILayout.SelectableLabel(valueSLabel, coms[i].EditorStyles, coms[i].LayoutOptions);
|
||||
else if (coms[i].EditorStyles != null)
|
||||
EditorGUILayout.SelectableLabel(valueSLabel, coms[i].EditorStyles);
|
||||
else if (coms[i].LayoutOptions != null)
|
||||
EditorGUILayout.SelectableLabel(valueSLabel, coms[i].LayoutOptions);
|
||||
else
|
||||
EditorGUILayout.SelectableLabel(valueSLabel);
|
||||
break;
|
||||
case ContentType.Button:
|
||||
bool click = false;
|
||||
if (coms[i].EditorStyles != null && coms[i].LayoutOptions != null)
|
||||
click = GUILayout.Button(coms[i].Title, coms[i].EditorStyles, coms[i].LayoutOptions);
|
||||
else if (coms[i].EditorStyles != null)
|
||||
click = GUILayout.Button(coms[i].Title, coms[i].EditorStyles);
|
||||
else if (coms[i].LayoutOptions != null)
|
||||
click = GUILayout.Button(coms[i].Title, coms[i].LayoutOptions);
|
||||
else
|
||||
click = GUILayout.Button(coms[i].Title);
|
||||
|
||||
if (click)
|
||||
{
|
||||
//通知
|
||||
if (!string.IsNullOrEmpty(cbName))
|
||||
FunctionCall(cbName, "Button");
|
||||
}
|
||||
|
||||
break;
|
||||
case ContentType.Enum:
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (coms[i].EditorStyles != null && coms[i].LayoutOptions != null)
|
||||
_serializedProperties[coms[i].FieldName].intValue = EditorGUILayout.Popup(coms[i].Title, _serializedProperties[coms[i].FieldName].intValue, coms[i].EnumOptions, coms[i].EditorStyles, coms[i].LayoutOptions);
|
||||
else if (coms[i].EditorStyles != null)
|
||||
_serializedProperties[coms[i].FieldName].intValue = EditorGUILayout.Popup(coms[i].Title, _serializedProperties[coms[i].FieldName].intValue, coms[i].EnumOptions, coms[i].EditorStyles);
|
||||
else if (coms[i].LayoutOptions != null)
|
||||
_serializedProperties[coms[i].FieldName].intValue = EditorGUILayout.Popup(coms[i].Title, _serializedProperties[coms[i].FieldName].intValue, coms[i].EnumOptions, coms[i].LayoutOptions);
|
||||
else
|
||||
_serializedProperties[coms[i].FieldName].intValue = EditorGUILayout.Popup(coms[i].Title, _serializedProperties[coms[i].FieldName].intValue, coms[i].EnumOptions);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
needSave = true;
|
||||
//通知
|
||||
|
||||
if (!string.IsNullOrEmpty(cbName))
|
||||
FunctionCall(cbName, coms[i].EnumOptions[_serializedProperties[coms[i].FieldName].enumValueIndex]);
|
||||
}
|
||||
|
||||
break;
|
||||
case ContentType.Toggle:
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (coms[i].EditorStyles != null && coms[i].LayoutOptions != null)
|
||||
_serializedProperties[coms[i].FieldName].boolValue = EditorGUILayout.Toggle(coms[i].Title, _serializedProperties[coms[i].FieldName].boolValue, coms[i].EditorStyles, coms[i].LayoutOptions);
|
||||
else if (coms[i].EditorStyles != null)
|
||||
_serializedProperties[coms[i].FieldName].boolValue = EditorGUILayout.Toggle(coms[i].Title, _serializedProperties[coms[i].FieldName].boolValue, coms[i].EditorStyles);
|
||||
else if (coms[i].LayoutOptions != null)
|
||||
_serializedProperties[coms[i].FieldName].boolValue = EditorGUILayout.Toggle(coms[i].Title, _serializedProperties[coms[i].FieldName].boolValue, coms[i].LayoutOptions);
|
||||
else
|
||||
_serializedProperties[coms[i].FieldName].boolValue = EditorGUILayout.Toggle(coms[i].Title, _serializedProperties[coms[i].FieldName].boolValue);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
needSave = true;
|
||||
//通知
|
||||
|
||||
if (!string.IsNullOrEmpty(cbName))
|
||||
FunctionCall(cbName, _serializedProperties[coms[i].FieldName].boolValue ? "1" : "0");
|
||||
}
|
||||
|
||||
break;
|
||||
case ContentType.TextField:
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
if (coms[i].EditorStyles != null && coms[i].LayoutOptions != null)
|
||||
_serializedProperties[coms[i].FieldName].stringValue = EditorGUILayout.TextField(coms[i].Title, _serializedProperties[coms[i].FieldName].stringValue, coms[i].EditorStyles, coms[i].LayoutOptions);
|
||||
else if (coms[i].EditorStyles != null)
|
||||
_serializedProperties[coms[i].FieldName].stringValue = EditorGUILayout.TextField(coms[i].Title, _serializedProperties[coms[i].FieldName].stringValue, coms[i].EditorStyles);
|
||||
else if (coms[i].LayoutOptions != null)
|
||||
_serializedProperties[coms[i].FieldName].stringValue = EditorGUILayout.TextField(coms[i].Title, _serializedProperties[coms[i].FieldName].stringValue, coms[i].LayoutOptions);
|
||||
else
|
||||
_serializedProperties[coms[i].FieldName].stringValue = EditorGUILayout.TextField(coms[i].Title, _serializedProperties[coms[i].FieldName].stringValue);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
needSave = true;
|
||||
//通知
|
||||
|
||||
if (!string.IsNullOrEmpty(cbName))
|
||||
FunctionCall(cbName, _serializedProperties[coms[i].FieldName].stringValue);
|
||||
}
|
||||
|
||||
break;
|
||||
case ContentType.Obj:
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Object obj = null;
|
||||
if (_serializedProperties[coms[i].FieldName] != null)
|
||||
obj = _serializedProperties[coms[i].FieldName].objectReferenceValue;
|
||||
if (coms[i].LayoutOptions != null)
|
||||
_serializedProperties[coms[i].FieldName].objectReferenceValue =
|
||||
EditorGUILayout.ObjectField(coms[i].Title, _serializedProperties[coms[i].FieldName].objectReferenceValue, coms[i].Type, false, coms[i].LayoutOptions);
|
||||
else
|
||||
obj = EditorGUILayout.ObjectField(coms[i].Title, obj, coms[i].Type, false);
|
||||
if (obj != null)
|
||||
{
|
||||
_serializedProperties[coms[i].FieldName].objectReferenceValue = obj;
|
||||
}
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
needSave = true;
|
||||
//通知
|
||||
|
||||
if (!string.IsNullOrEmpty(cbName))
|
||||
FunctionCall(cbName, _serializedProperties[coms[i].FieldName].stringValue);
|
||||
}
|
||||
break;
|
||||
case ContentType.ScrollLabel:
|
||||
string valueSCLabel = coms[i].Title;
|
||||
if (string.IsNullOrEmpty(valueSCLabel))
|
||||
{
|
||||
valueSCLabel = _serializedProperties[coms[i].FieldName].stringValue;
|
||||
}
|
||||
if (coms[i].LayoutOptions != null)
|
||||
coms[i].ScrollPos = GUILayout.BeginScrollView(coms[i].ScrollPos, false, false, coms[i].LayoutOptions);
|
||||
else
|
||||
coms[i].ScrollPos = GUILayout.BeginScrollView(coms[i].ScrollPos, false, false);
|
||||
|
||||
if (coms[i].EditorStyles != null && coms[i].LayoutOptions != null)
|
||||
{
|
||||
GUILayout.Label(valueSCLabel, coms[i].EditorStyles, coms[i].LayoutOptions);
|
||||
}
|
||||
else if (coms[i].EditorStyles != null)
|
||||
GUILayout.Label(valueSCLabel, coms[i].EditorStyles);
|
||||
else if (coms[i].LayoutOptions != null)
|
||||
GUILayout.Label(valueSCLabel, coms[i].LayoutOptions);
|
||||
else
|
||||
GUILayout.Label(valueSCLabel);
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
break;
|
||||
default:
|
||||
Debug.LogError("请勿使用不支持的类型,字段:" + coms[i].FieldName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void FunctionCall(string cbName, string parameter)
|
||||
{
|
||||
if (_baseTarget != null)
|
||||
{
|
||||
var ty = _baseTarget.GetType();
|
||||
var method = ty.GetTypeInfo().GetDeclaredMethod(cbName);
|
||||
if (method != null)
|
||||
{
|
||||
var parameters = new object[] { parameter };
|
||||
method.Invoke(_baseTarget, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckIfCanShowByParentInfo(string parentInfo, bool checkShow)
|
||||
{
|
||||
if (CheckIfDispose())
|
||||
return false;
|
||||
|
||||
var p2v = parentInfo.Split(':');
|
||||
|
||||
if (p2v.Length < 2)
|
||||
{
|
||||
Debug.LogError("不规范的输入,参数后需包含 ‘:值’ :" + parentInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_comDic.TryGetValue(p2v[0], out var parent))
|
||||
{
|
||||
if (!checkShow)
|
||||
{
|
||||
var or = p2v[1].Split('r');
|
||||
foreach (var index in or)
|
||||
{
|
||||
if (index.Equals(_serializedProperties[p2v[0]].intValue.ToString()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent.IsShow;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheckIfDispose()
|
||||
{
|
||||
if (_hasDispose)
|
||||
{
|
||||
Selection.activeObject = null;
|
||||
}
|
||||
return _hasDispose;
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
_hasDispose = true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69c90344d16f40941a5f3d724c6ffa4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
public class SoEditorBase : ScriptableObject
|
||||
{
|
||||
|
||||
public virtual void AdditionalInit()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnAnyThingChange(string args)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2c6ea7ddafc411449933609a046e5df
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
247
Assets/TEngine/Scripts/Editor/AssetBundleBuild/FileTree.cs
Normal file
247
Assets/TEngine/Scripts/Editor/AssetBundleBuild/FileTree.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
public class FileTree : IDisposable
|
||||
{
|
||||
private bool _disposed = false;
|
||||
private string[] _extIncludeFilter;
|
||||
private string[] _extExcludeFilter;
|
||||
|
||||
private List<FileInfo> _files = new List<FileInfo>();
|
||||
private DirectoryInfo[] _subFolders;
|
||||
private DirectoryInfo _directoryInfo;
|
||||
private FileTree[] _subTrees;
|
||||
private bool _isLeafFolder;
|
||||
private FileTree _parent;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _directoryInfo.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
|
||||
if (null != _subTrees)
|
||||
{
|
||||
for (var i = 0; i < _subTrees.Length; ++i)
|
||||
{
|
||||
_subTrees[i].Dispose();
|
||||
}
|
||||
_subTrees = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
~FileTree()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private FileTree() { }
|
||||
|
||||
public static FileTree CreateWithIncludeFilter(string rootPath, string[] includeFilter = null)
|
||||
{
|
||||
FileTree fileTree = new FileTree();
|
||||
fileTree._extIncludeFilter = includeFilter;
|
||||
fileTree._directoryInfo = new DirectoryInfo(rootPath);
|
||||
fileTree.MakeSubTree();
|
||||
|
||||
return fileTree;
|
||||
}
|
||||
|
||||
public static FileTree CreateWithExcludeFilter(string rootPath, string[] excludeFilter = null)
|
||||
{
|
||||
FileTree fileTree = new FileTree();
|
||||
fileTree._extExcludeFilter = excludeFilter;
|
||||
fileTree._directoryInfo = new DirectoryInfo(rootPath);
|
||||
fileTree.MakeSubTree();
|
||||
|
||||
return fileTree;
|
||||
}
|
||||
|
||||
public static FileTree CreateWithIncludeFilter(DirectoryInfo directoryInfo, string[] includeFilter = null)
|
||||
{
|
||||
if (directoryInfo != null)
|
||||
{
|
||||
FileTree fileTree = new FileTree();
|
||||
fileTree._extIncludeFilter = includeFilter;
|
||||
fileTree._directoryInfo = directoryInfo;
|
||||
fileTree.MakeSubTree();
|
||||
|
||||
return fileTree;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Create FileTree with null DirectoryInfo");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static FileTree CreateWithExcludeFilter(DirectoryInfo directoryInfo, string[] excludeFilter = null)
|
||||
{
|
||||
if (directoryInfo != null)
|
||||
{
|
||||
FileTree fileTree = new FileTree();
|
||||
fileTree._extExcludeFilter = excludeFilter;
|
||||
fileTree._directoryInfo = directoryInfo;
|
||||
fileTree.MakeSubTree();
|
||||
|
||||
return fileTree;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Create FileTree with null DirectoryInfo");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void FiltFiles(FileInfo[] vFiles)
|
||||
{
|
||||
_files.Clear();
|
||||
|
||||
FileInfo curFileInfo;
|
||||
for (var i = 0; i < vFiles.Length; ++i)
|
||||
{
|
||||
curFileInfo = vFiles[i];
|
||||
|
||||
if (_extIncludeFilter != null)
|
||||
{
|
||||
for (int f = 0; f < _extIncludeFilter.Length; ++f)
|
||||
{
|
||||
if (_extIncludeFilter[f] == curFileInfo.Extension)
|
||||
{
|
||||
_files.Add(curFileInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_extExcludeFilter != null)
|
||||
{
|
||||
bool filtered = false;
|
||||
for (int f = 0; f < _extExcludeFilter.Length; ++f)
|
||||
{
|
||||
if (_extExcludeFilter[f] == curFileInfo.Extension)
|
||||
filtered = true;
|
||||
}
|
||||
if (!filtered) this._files.Add(curFileInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
_files.Add(curFileInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MakeSubTree()
|
||||
{
|
||||
FiltFiles(_directoryInfo.GetFiles());
|
||||
_subFolders = _directoryInfo.GetDirectories();
|
||||
_isLeafFolder = (_subFolders == null || _subFolders.Length == 0);
|
||||
if (!_isLeafFolder)
|
||||
{
|
||||
_subTrees = new FileTree[_subFolders.Length];
|
||||
for (var i = 0; i < _subFolders.Length; ++i)
|
||||
{
|
||||
var subDir = _subFolders[i];
|
||||
if (_extIncludeFilter != null)
|
||||
_subTrees[i] = CreateWithIncludeFilter(subDir, _extIncludeFilter);
|
||||
else
|
||||
_subTrees[i] = CreateWithExcludeFilter(subDir, _extExcludeFilter);
|
||||
_subTrees[i]._parent = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<FileTree> GetTotalLeafFolders(List<FileTree> ret = null)
|
||||
{
|
||||
if (null == ret)
|
||||
{
|
||||
ret = new List<FileTree>();
|
||||
}
|
||||
if (_isLeafFolder)
|
||||
{
|
||||
ret.Add(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < _subTrees.Length; ++i)
|
||||
{
|
||||
_subTrees[i].GetTotalLeafFolders(ret);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<FileInfo> GetAllFiles(List<FileInfo> ret = null)
|
||||
{
|
||||
if (ret == null)
|
||||
ret = new List<FileInfo>();
|
||||
|
||||
ret.AddRange(this._files);
|
||||
if (!_isLeafFolder)
|
||||
{
|
||||
for (int i = 0; i < _subTrees.Length; ++i)
|
||||
{
|
||||
_subTrees[i].GetAllFiles(ret);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试接口,用来查看信息是否正确
|
||||
/// </summary>
|
||||
public StringBuilder GetInfo(bool printSubFolder = false, StringBuilder builder = null)
|
||||
{
|
||||
if (null == builder)
|
||||
{
|
||||
builder = new StringBuilder(1024 * 8);
|
||||
}
|
||||
builder.AppendLine("文件夹:" + _directoryInfo.FullName);
|
||||
if (_files.Count > 0)
|
||||
{
|
||||
builder.AppendLine("子文件数量:" + _files.Count);
|
||||
for (var i = 0; i < _files.Count; ++i)
|
||||
{
|
||||
builder.AppendLine("\t第" + (i + 1) + "个文件: " + _files[i].FullName);
|
||||
}
|
||||
}
|
||||
if (_isLeafFolder)
|
||||
{
|
||||
builder.Append("\t\t isLeafFolder");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine("子文件夹数量:" + _subFolders.Length);
|
||||
for (var i = 0; i < _subFolders.Length; ++i)
|
||||
{
|
||||
builder.AppendLine("\t第" + (i + 1) + "个文件夹: " + _subFolders[i].FullName);
|
||||
}
|
||||
if (printSubFolder)
|
||||
{
|
||||
for (var i = 0; i < _subTrees.Length; ++i)
|
||||
{
|
||||
_subTrees[i].GetInfo(true, builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61234e3fa3cae86479930f7c7849cc42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
15
Assets/TEngine/Scripts/Editor/AssetBundleBuild/IBuilder.cs
Normal file
15
Assets/TEngine/Scripts/Editor/AssetBundleBuild/IBuilder.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
internal interface IBuilder
|
||||
{
|
||||
void SetBuilderConfig(BuilderUtility.PlatformType target, string configName, string configPath = "");
|
||||
void SetBuilderConfig(BuilderEditor tmpBuilder);
|
||||
|
||||
void SwitchPlatform(BuilderUtility.PlatformType target);
|
||||
bool BuildAssetBundle();
|
||||
|
||||
void BuildPackage(BuildOptions option = BuildOptions.None);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba1b14df4e3810e4fb2c5362717ce5ed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: faf0505604af6d54fa306ce917376347
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,38 @@
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
public static class EditorCoroutineExtensions
|
||||
{
|
||||
public static EditorCoroutines.EditorCoroutine StartCoroutine(this EditorWindow thisRef, IEnumerator coroutine)
|
||||
{
|
||||
return EditorCoroutines.StartCoroutine(coroutine, thisRef);
|
||||
}
|
||||
|
||||
public static EditorCoroutines.EditorCoroutine StartCoroutine(this EditorWindow thisRef, string methodName)
|
||||
{
|
||||
return EditorCoroutines.StartCoroutine(methodName, thisRef);
|
||||
}
|
||||
|
||||
public static EditorCoroutines.EditorCoroutine StartCoroutine(this EditorWindow thisRef, string methodName, object value)
|
||||
{
|
||||
return EditorCoroutines.StartCoroutine(methodName, value, thisRef);
|
||||
}
|
||||
|
||||
public static void StopCoroutine(this EditorWindow thisRef, IEnumerator coroutine)
|
||||
{
|
||||
EditorCoroutines.StopCoroutine(coroutine, thisRef);
|
||||
}
|
||||
|
||||
public static void StopCoroutine(this EditorWindow thisRef, string methodName)
|
||||
{
|
||||
EditorCoroutines.StopCoroutine(methodName, thisRef);
|
||||
}
|
||||
|
||||
public static void StopAllCoroutines(this EditorWindow thisRef)
|
||||
{
|
||||
EditorCoroutines.StopAllCoroutines(thisRef);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f555afdd2ccdf224cabc9150f8d1c7e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,435 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
public class EditorCoroutines
|
||||
{
|
||||
public class EditorCoroutine
|
||||
{
|
||||
public ICoroutineYield currentYield = new YieldDefault();
|
||||
public IEnumerator routine;
|
||||
public string routineUniqueHash;
|
||||
public string ownerUniqueHash;
|
||||
public string MethodName = "";
|
||||
|
||||
public int ownerHash;
|
||||
public string ownerType;
|
||||
|
||||
public bool finished = false;
|
||||
|
||||
public EditorCoroutine(IEnumerator routine, int ownerHash, string ownerType)
|
||||
{
|
||||
this.routine = routine;
|
||||
this.ownerHash = ownerHash;
|
||||
this.ownerType = ownerType;
|
||||
ownerUniqueHash = ownerHash + "_" + ownerType;
|
||||
|
||||
if (routine != null)
|
||||
{
|
||||
string[] split = routine.ToString().Split('<', '>');
|
||||
if (split.Length == 3)
|
||||
{
|
||||
this.MethodName = split[1];
|
||||
}
|
||||
}
|
||||
|
||||
routineUniqueHash = ownerHash + "_" + ownerType + "_" + MethodName;
|
||||
}
|
||||
|
||||
public EditorCoroutine(string methodName, int ownerHash, string ownerType)
|
||||
{
|
||||
MethodName = methodName;
|
||||
this.ownerHash = ownerHash;
|
||||
this.ownerType = ownerType;
|
||||
ownerUniqueHash = ownerHash + "_" + ownerType;
|
||||
routineUniqueHash = ownerHash + "_" + ownerType + "_" + MethodName;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICoroutineYield
|
||||
{
|
||||
bool IsDone(float deltaTime);
|
||||
}
|
||||
|
||||
struct YieldDefault : ICoroutineYield
|
||||
{
|
||||
public bool IsDone(float deltaTime)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
struct YieldWaitForSeconds : ICoroutineYield
|
||||
{
|
||||
public float timeLeft;
|
||||
|
||||
public bool IsDone(float deltaTime)
|
||||
{
|
||||
timeLeft -= deltaTime;
|
||||
return timeLeft < 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct YieldCustomYieldInstruction : ICoroutineYield
|
||||
{
|
||||
public CustomYieldInstruction customYield;
|
||||
|
||||
public bool IsDone(float deltaTime)
|
||||
{
|
||||
return !customYield.keepWaiting;
|
||||
}
|
||||
}
|
||||
|
||||
struct YieldUnityWebRequest : ICoroutineYield
|
||||
{
|
||||
public UnityWebRequest unityWebRequest;
|
||||
|
||||
public bool IsDone(float deltaTime)
|
||||
{
|
||||
return unityWebRequest.isDone;
|
||||
}
|
||||
}
|
||||
|
||||
struct YieldAsync : ICoroutineYield
|
||||
{
|
||||
public AsyncOperation asyncOperation;
|
||||
|
||||
public bool IsDone(float deltaTime)
|
||||
{
|
||||
return asyncOperation.isDone;
|
||||
}
|
||||
}
|
||||
|
||||
struct YieldNestedCoroutine : ICoroutineYield
|
||||
{
|
||||
public EditorCoroutine coroutine;
|
||||
|
||||
public bool IsDone(float deltaTime)
|
||||
{
|
||||
return coroutine.finished;
|
||||
}
|
||||
}
|
||||
|
||||
static EditorCoroutines instance = null;
|
||||
|
||||
Dictionary<string, List<EditorCoroutine>> coroutineDict = new Dictionary<string, List<EditorCoroutine>>();
|
||||
List<List<EditorCoroutine>> tempCoroutineList = new List<List<EditorCoroutine>>();
|
||||
|
||||
Dictionary<string, Dictionary<string, EditorCoroutine>> coroutineOwnerDict =
|
||||
new Dictionary<string, Dictionary<string, EditorCoroutine>>();
|
||||
|
||||
DateTime previousTimeSinceStartup;
|
||||
|
||||
public static int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance != null ? instance.coroutineDict.Count : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Starts a coroutine.</summary>
|
||||
/// <param name="routine">The coroutine to start.</param>
|
||||
/// <param name="thisReference">Reference to the instance of the class containing the method.</param>
|
||||
public static EditorCoroutine StartCoroutine(IEnumerator routine, object thisReference)
|
||||
{
|
||||
CreateInstanceIfNeeded();
|
||||
return instance.GoStartCoroutine(routine, thisReference);
|
||||
}
|
||||
|
||||
/// <summary>Starts a coroutine.</summary>
|
||||
/// <param name="methodName">The name of the coroutine method to start.</param>
|
||||
/// <param name="thisReference">Reference to the instance of the class containing the method.</param>
|
||||
public static EditorCoroutine StartCoroutine(string methodName, object thisReference)
|
||||
{
|
||||
return StartCoroutine(methodName, null, thisReference);
|
||||
}
|
||||
|
||||
/// <summary>Starts a coroutine.</summary>
|
||||
/// <param name="methodName">The name of the coroutine method to start.</param>
|
||||
/// <param name="value">The parameter to pass to the coroutine.</param>
|
||||
/// <param name="thisReference">Reference to the instance of the class containing the method.</param>
|
||||
public static EditorCoroutine StartCoroutine(string methodName, object value, object thisReference)
|
||||
{
|
||||
MethodInfo methodInfo = thisReference.GetType()
|
||||
.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (methodInfo == null)
|
||||
{
|
||||
Debug.LogError("Coroutine '" + methodName + "' couldn't be started, the method doesn't exist!");
|
||||
}
|
||||
object returnValue;
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
returnValue = methodInfo.Invoke(thisReference, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = methodInfo.Invoke(thisReference, new object[] { value });
|
||||
}
|
||||
|
||||
if (returnValue is IEnumerator)
|
||||
{
|
||||
CreateInstanceIfNeeded();
|
||||
return instance.GoStartCoroutine((IEnumerator)returnValue, thisReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Coroutine '" + methodName + "' couldn't be started, the method doesn't return an IEnumerator!");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Stops all coroutines being the routine running on the passed instance.</summary>
|
||||
/// <param name="routine"> The coroutine to stop.</param>
|
||||
/// <param name="thisReference">Reference to the instance of the class containing the method.</param>
|
||||
public static void StopCoroutine(IEnumerator routine, object thisReference)
|
||||
{
|
||||
CreateInstanceIfNeeded();
|
||||
instance.GoStopCoroutine(routine, thisReference);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops all coroutines named methodName running on the passed instance.</summary>
|
||||
/// <param name="methodName"> The name of the coroutine method to stop.</param>
|
||||
/// <param name="thisReference">Reference to the instance of the class containing the method.</param>
|
||||
public static void StopCoroutine(string methodName, object thisReference)
|
||||
{
|
||||
CreateInstanceIfNeeded();
|
||||
instance.GoStopCoroutine(methodName, thisReference);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops all coroutines running on the passed instance.</summary>
|
||||
/// <param name="thisReference">Reference to the instance of the class containing the method.</param>
|
||||
public static void StopAllCoroutines(object thisReference)
|
||||
{
|
||||
CreateInstanceIfNeeded();
|
||||
instance.GoStopAllCoroutines(thisReference, true);
|
||||
}
|
||||
|
||||
public static void StopAllCoroutines()
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
instance.GoStopAllCoroutines(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void CreateInstanceIfNeeded()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new EditorCoroutines();
|
||||
instance.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
previousTimeSinceStartup = DateTime.Now;
|
||||
EditorApplication.update += OnUpdate;
|
||||
}
|
||||
|
||||
void GoStopCoroutine(IEnumerator routine, object thisReference)
|
||||
{
|
||||
GoStopActualRoutine(CreateCoroutine(routine, thisReference));
|
||||
}
|
||||
|
||||
void GoStopCoroutine(string methodName, object thisReference)
|
||||
{
|
||||
GoStopActualRoutine(CreateCoroutineFromString(methodName, thisReference));
|
||||
}
|
||||
|
||||
void GoStopActualRoutine(EditorCoroutine routine)
|
||||
{
|
||||
if (coroutineDict.ContainsKey(routine.routineUniqueHash))
|
||||
{
|
||||
coroutineOwnerDict[routine.ownerUniqueHash].Remove(routine.routineUniqueHash);
|
||||
coroutineDict.Remove(routine.routineUniqueHash);
|
||||
}
|
||||
}
|
||||
|
||||
void GoStopAllCoroutines(object thisReference, bool onlyInstance = true)
|
||||
{
|
||||
if (thisReference != null && onlyInstance)
|
||||
{
|
||||
EditorCoroutine coroutine = CreateCoroutine(null, thisReference);
|
||||
if (coroutineOwnerDict.ContainsKey(coroutine.ownerUniqueHash))
|
||||
{
|
||||
foreach (var couple in coroutineOwnerDict[coroutine.ownerUniqueHash])
|
||||
{
|
||||
coroutineDict.Remove(couple.Value.routineUniqueHash);
|
||||
}
|
||||
coroutineOwnerDict.Remove(coroutine.ownerUniqueHash);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
coroutineDict.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
EditorCoroutine GoStartCoroutine(IEnumerator routine, object thisReference)
|
||||
{
|
||||
if (routine == null)
|
||||
{
|
||||
Debug.LogException(new Exception("IEnumerator is null!"), null);
|
||||
}
|
||||
EditorCoroutine coroutine = CreateCoroutine(routine, thisReference);
|
||||
GoStartCoroutine(coroutine);
|
||||
return coroutine;
|
||||
}
|
||||
|
||||
void GoStartCoroutine(EditorCoroutine coroutine)
|
||||
{
|
||||
if (!coroutineDict.ContainsKey(coroutine.routineUniqueHash))
|
||||
{
|
||||
List<EditorCoroutine> newCoroutineList = new List<EditorCoroutine>();
|
||||
coroutineDict.Add(coroutine.routineUniqueHash, newCoroutineList);
|
||||
}
|
||||
coroutineDict[coroutine.routineUniqueHash].Add(coroutine);
|
||||
|
||||
if (!coroutineOwnerDict.ContainsKey(coroutine.ownerUniqueHash))
|
||||
{
|
||||
Dictionary<string, EditorCoroutine> newCoroutineDict = new Dictionary<string, EditorCoroutine>();
|
||||
coroutineOwnerDict.Add(coroutine.ownerUniqueHash, newCoroutineDict);
|
||||
}
|
||||
|
||||
// If the method from the same owner has been stored before, it doesn't have to be stored anymore,
|
||||
// One reference is enough in order for "StopAllCoroutines" to work
|
||||
if (!coroutineOwnerDict[coroutine.ownerUniqueHash].ContainsKey(coroutine.routineUniqueHash))
|
||||
{
|
||||
coroutineOwnerDict[coroutine.ownerUniqueHash].Add(coroutine.routineUniqueHash, coroutine);
|
||||
}
|
||||
|
||||
MoveNext(coroutine);
|
||||
}
|
||||
|
||||
EditorCoroutine CreateCoroutine(IEnumerator routine, object thisReference)
|
||||
{
|
||||
return new EditorCoroutine(routine, thisReference.GetHashCode(), thisReference.GetType().ToString());
|
||||
}
|
||||
|
||||
EditorCoroutine CreateCoroutineFromString(string methodName, object thisReference)
|
||||
{
|
||||
return new EditorCoroutine(methodName, thisReference.GetHashCode(), thisReference.GetType().ToString());
|
||||
}
|
||||
|
||||
void OnUpdate()
|
||||
{
|
||||
float deltaTime = (float)(DateTime.Now.Subtract(previousTimeSinceStartup).TotalMilliseconds / 1000.0f);
|
||||
|
||||
previousTimeSinceStartup = DateTime.Now;
|
||||
if (coroutineDict.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tempCoroutineList.Clear();
|
||||
foreach (var pair in coroutineDict)
|
||||
tempCoroutineList.Add(pair.Value);
|
||||
|
||||
for (var i = tempCoroutineList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
List<EditorCoroutine> coroutines = tempCoroutineList[i];
|
||||
|
||||
for (int j = coroutines.Count - 1; j >= 0; j--)
|
||||
{
|
||||
EditorCoroutine coroutine = coroutines[j];
|
||||
|
||||
if (!coroutine.currentYield.IsDone(deltaTime))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!MoveNext(coroutine))
|
||||
{
|
||||
coroutines.RemoveAt(j);
|
||||
coroutine.currentYield = null;
|
||||
coroutine.finished = true;
|
||||
}
|
||||
|
||||
if (coroutines.Count == 0)
|
||||
{
|
||||
coroutineDict.Remove(coroutine.ownerUniqueHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool MoveNext(EditorCoroutine coroutine)
|
||||
{
|
||||
if (coroutine.routine.MoveNext())
|
||||
{
|
||||
return Process(coroutine);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns false if no next, returns true if OK
|
||||
static bool Process(EditorCoroutine coroutine)
|
||||
{
|
||||
object current = coroutine.routine.Current;
|
||||
if (current == null)
|
||||
{
|
||||
coroutine.currentYield = new YieldDefault();
|
||||
}
|
||||
else if (current is WaitForSeconds)
|
||||
{
|
||||
float seconds = float.Parse(GetInstanceField(typeof(WaitForSeconds), current, "m_Seconds").ToString());
|
||||
coroutine.currentYield = new YieldWaitForSeconds() { timeLeft = seconds };
|
||||
}
|
||||
else if (current is CustomYieldInstruction)
|
||||
{
|
||||
coroutine.currentYield = new YieldCustomYieldInstruction()
|
||||
{
|
||||
customYield = current as CustomYieldInstruction
|
||||
};
|
||||
}
|
||||
else if (current is UnityWebRequest)
|
||||
{
|
||||
coroutine.currentYield = new YieldUnityWebRequest() { unityWebRequest = (UnityWebRequest)current };
|
||||
}
|
||||
else if (current is WaitForFixedUpdate || current is WaitForEndOfFrame)
|
||||
{
|
||||
coroutine.currentYield = new YieldDefault();
|
||||
}
|
||||
else if (current is AsyncOperation)
|
||||
{
|
||||
coroutine.currentYield = new YieldAsync { asyncOperation = (AsyncOperation)current };
|
||||
}
|
||||
else if (current is EditorCoroutine)
|
||||
{
|
||||
coroutine.currentYield = new YieldNestedCoroutine { coroutine = (EditorCoroutine)current };
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!current.GetType().IsPrimitive)
|
||||
{
|
||||
Debug.LogException(
|
||||
new Exception("<" + coroutine.MethodName + "> yielded an unknown or unsupported type! (" + current.GetType() + ")"),
|
||||
null);
|
||||
}
|
||||
coroutine.currentYield = new YieldDefault();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static object GetInstanceField(Type type, object instance, string fieldName)
|
||||
{
|
||||
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
|
||||
FieldInfo field = type.GetField(fieldName, bindFlags);
|
||||
return field.GetValue(instance);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e908baad613dc042abacf50d0a7ec51
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,483 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 用于游戏中shader自动收集变体
|
||||
/// </summary>
|
||||
public static class ShaderVariantCollector
|
||||
{
|
||||
private static UnityEngine.Object _saveAddr;
|
||||
private static readonly string _buildPath = "Build";
|
||||
private static readonly string _shaderAssetBundleName = "shader_variant";
|
||||
private static string _variantPath = $"Assets/VariantCollection.shadervariants";
|
||||
/// <summary>
|
||||
/// GUI部分
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/Shader工具|Shader/变体收集")]
|
||||
private static void Open()
|
||||
{
|
||||
var window = EditorWindow.GetWindow(typeof(CustomMessageBox), true, "收集变体") as CustomMessageBox;
|
||||
if (window == null) return;
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
EditorCoroutines.EditorCoroutine it = null;
|
||||
|
||||
window.Info = "收集项目中使用了的变体";
|
||||
window.minSize = new Vector2(600, 150);
|
||||
window.maxSize = new Vector2(600, 150);
|
||||
window.Show();
|
||||
window.OnClose = (button, returnValue) =>
|
||||
{
|
||||
EditorCoroutines.StopAllCoroutines();
|
||||
EditorUtility.ClearProgressBar();
|
||||
};
|
||||
|
||||
window.OnGUIFunc = () =>
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("保存地址:", GUILayout.Width(60));
|
||||
_saveAddr = EditorGUILayout.ObjectField(_saveAddr, typeof(UnityEngine.Object), true, GUILayout.Width(450));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("开始收集变体"))
|
||||
{
|
||||
string tempPath = AssetDatabase.GetAssetPath(_saveAddr);
|
||||
if (string.IsNullOrEmpty(tempPath))
|
||||
{
|
||||
Debug.LogError("请选择路径");
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.enabled = it == null;
|
||||
it = window.StartCoroutine(ShaderVariantsCollector());
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// 收集变体
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerator ShaderVariantsCollector()
|
||||
{
|
||||
ClearCurrentShaderVariantCollection();
|
||||
|
||||
var shaderCount1 = GetCurrentShaderVariantCollectionShaderCount();
|
||||
var shaderVariantCount1 = GetCurrentShaderVariantCollectionVariantCount();
|
||||
Debug.LogErrorFormat("{0} shaders {1} total variants.", shaderCount1, shaderVariantCount1);
|
||||
|
||||
yield return null;
|
||||
|
||||
var scenePath = _GetScenes();
|
||||
if (scenePath.Count <= 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var allMaterials = _CollectAllMaterials();
|
||||
Debug.LogFormat("========开始遍历场景收集变体========");
|
||||
//int index = 0;
|
||||
foreach (var item in scenePath)
|
||||
{
|
||||
EditorSceneManager.OpenScene(item);
|
||||
yield return null;
|
||||
_CreateProxyRenderers(allMaterials);
|
||||
yield return null;
|
||||
var shaderCount = GetCurrentShaderVariantCollectionShaderCount();
|
||||
var shaderVariantCount = GetCurrentShaderVariantCollectionVariantCount();
|
||||
Debug.LogFormat("{0} shaders {1} total variants.", shaderCount, shaderVariantCount);
|
||||
yield return new WaitForEndOfFrame();
|
||||
}
|
||||
Debug.LogFormat("========完成变体收集========");
|
||||
yield return new WaitForSeconds(1);
|
||||
SaveShaderVariant();
|
||||
}
|
||||
|
||||
|
||||
public static void ShaderVariantsCollector(Action action = null)
|
||||
{
|
||||
ClearCurrentShaderVariantCollection();
|
||||
var scenePath = _GetScenes();
|
||||
if (scenePath.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var allMaterials = _CollectAllMaterials();
|
||||
Debug.LogFormat("========开始遍历场景收集变体========");
|
||||
int index = 0;
|
||||
foreach (var item in scenePath)
|
||||
{
|
||||
EditorSceneManager.OpenScene(item);
|
||||
_CreateProxyRenderers(allMaterials);
|
||||
var shaderCount = GetCurrentShaderVariantCollectionShaderCount();
|
||||
var shaderVariantCount = GetCurrentShaderVariantCollectionVariantCount();
|
||||
Debug.LogFormat("{0} shaders {1} total variants.", shaderCount, shaderVariantCount);
|
||||
EditorUtility.DisplayProgressBar("进度", item, index / scenePath.Count);
|
||||
}
|
||||
Debug.LogFormat("========完成变体收集========");
|
||||
EditorUtility.ClearProgressBar();
|
||||
SaveShaderVariant();
|
||||
action?.Invoke();
|
||||
}
|
||||
|
||||
static void _CreateProxyRenderers(List<string> materials)
|
||||
{
|
||||
int totalMaterials = materials.Count;
|
||||
var camera = GameObject.FindObjectOfType<Camera>();
|
||||
if (camera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float aspect = camera.aspect;
|
||||
float height = Mathf.Sqrt(totalMaterials / aspect) + 1;
|
||||
float width = Mathf.Sqrt(totalMaterials / aspect) * aspect + 1;
|
||||
|
||||
float halfHeight = Mathf.CeilToInt(height / 2f);
|
||||
float halfWidth = Mathf.CeilToInt(width / 2f);
|
||||
|
||||
camera.orthographic = true;
|
||||
camera.orthographicSize = halfHeight;
|
||||
camera.transform.position = new Vector3(0f, 0f, -10f);
|
||||
|
||||
Selection.activeGameObject = camera.gameObject;
|
||||
|
||||
int xMax = (int)(width - 1);
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
for (int i = 0; i < materials.Count; i++)
|
||||
{
|
||||
var material = AssetDatabase.LoadAssetAtPath<Material>(materials[i]);
|
||||
var position = new Vector3(x - halfWidth + 1f, y - halfHeight + 1f, 0f);
|
||||
CreateSphere(material, position, x, y, i);
|
||||
|
||||
if (x == xMax)
|
||||
{
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
else
|
||||
{
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateSphere(Material material, Vector3 position, int x, int y, int index)
|
||||
{
|
||||
var go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
||||
go.GetComponent<Renderer>().material = material;
|
||||
go.transform.position = position;
|
||||
go.name = string.Format("Sphere_{0}|{1}_{2}|{3}", index, x, y, material.name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 收集所有的材质
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
static List<string> _CollectAllMaterials()
|
||||
{
|
||||
List<string> material = new List<string>();
|
||||
string[] temp = AssetDatabase.FindAssets("t:material");
|
||||
for (int i = 0; i < temp.Length; i++)
|
||||
{
|
||||
material.Add(AssetDatabase.GUIDToAssetPath(temp[i]));
|
||||
}
|
||||
|
||||
if (material.Count <= 0)
|
||||
{
|
||||
Debug.LogError("未收集到材质");
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 收集场景
|
||||
/// </summary>
|
||||
static List<string> _GetScenes()
|
||||
{
|
||||
List<string> scenes = new List<string>();
|
||||
string[] temp = AssetDatabase.FindAssets("t:scene");
|
||||
for (int i = 0; i < temp.Length; i++)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(temp[i]);
|
||||
if (path.StartsWith($"Assets/"))
|
||||
{
|
||||
scenes.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
if (scenes.Count <= 0)
|
||||
{
|
||||
Debug.LogError("未收集到场景信息");
|
||||
}
|
||||
return scenes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新导入shader,防止shader修改了
|
||||
/// </summary>
|
||||
[UnityEditor.MenuItem("TEngine/Shader工具|Shader/重新导入shader资源")]
|
||||
public static void ReimportAllShaderAssets()
|
||||
{
|
||||
try
|
||||
{
|
||||
var all = ShaderUtil.GetAllShaderInfo();
|
||||
for (var i = 0; i < all.Length; ++i)
|
||||
{
|
||||
var shader = Shader.Find(all[i].name);
|
||||
if (shader == null) continue;
|
||||
if (EditorUtility.DisplayCancelableProgressBar("Reimport Shader...", shader.name, (float)i / all.Length))
|
||||
{
|
||||
break;
|
||||
}
|
||||
var assetPath = AssetDatabase.GetAssetPath(shader);
|
||||
//路径为空或者是内置shader就不处理了
|
||||
if (string.IsNullOrEmpty(assetPath) || _IsUnityDefaultResource(assetPath)) continue;
|
||||
var importer = AssetImporter.GetAtPath(assetPath) as ShaderImporter;
|
||||
if (importer == null) continue;
|
||||
var before = AssetDatabase.GetDependencies(assetPath);
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.DontDownloadFromCacheServer);
|
||||
var after = AssetDatabase.GetDependencies(assetPath);
|
||||
if (!before.SequenceEqual(after))
|
||||
{
|
||||
Debug.LogWarningFormat("Reimport shader: {0} for error dependencies!", shader.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
|
||||
public static HashSet<string> ClollectSharderAndVariant()
|
||||
{
|
||||
var shaders = new HashSet<string>();
|
||||
var all = ShaderUtil.GetAllShaderInfo();
|
||||
for (int i = 0; i < all.Length; i++)
|
||||
{
|
||||
var shader = Shader.Find(all[i].name);
|
||||
var assetPath = AssetDatabase.GetAssetPath(shader);
|
||||
_CollectShaderDependencies(assetPath, shaders);
|
||||
}
|
||||
|
||||
if (File.Exists(_variantPath))
|
||||
{
|
||||
//AssetImporter importer = AssetImporter.GetAtPath(_variantPath);
|
||||
//importer.assetBundleName = _shaderAssetBundleName;
|
||||
shaders.Add(_variantPath);
|
||||
}
|
||||
|
||||
return shaders;
|
||||
}
|
||||
|
||||
internal static string GetShaderVariantAbName()
|
||||
{
|
||||
return _shaderAssetBundleName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打包shader,将shader和变体集合打包到同一个ab文件里面
|
||||
/// </summary>
|
||||
public static void BuildAllShaderAssets()
|
||||
{
|
||||
HashSet<string> shaders = ClollectSharderAndVariant();
|
||||
if (shaders.Count == 0)
|
||||
{
|
||||
Debug.LogError("No Shader asset in project");
|
||||
return;
|
||||
}
|
||||
|
||||
string buildPath = $"{Application.dataPath}/{_buildPath}";
|
||||
if (!File.Exists(buildPath))
|
||||
{
|
||||
Directory.CreateDirectory(buildPath);
|
||||
}
|
||||
|
||||
BuildTarget target = BuildTarget.NoTarget;
|
||||
#if UNITY_EDITOR_WIN
|
||||
target = BuildTarget.StandaloneWindows64;
|
||||
#endif
|
||||
|
||||
_BuildShaderAssetBundle(shaders.ToList(), buildPath, target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取shader得引用关系
|
||||
/// </summary>
|
||||
static void _CollectShaderDependencies(string shaderAssetPath, HashSet<string> shaderPaths)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(shaderAssetPath) && !_IsUnityDefaultResource(shaderAssetPath))
|
||||
{
|
||||
var deps = AssetDatabase.GetDependencies(shaderAssetPath);
|
||||
for (int j = 0; j < deps.Length; j++)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(deps[j]) && !_IsUnityDefaultResource(deps[j]) && deps[j].EndsWith(".shader"))
|
||||
{
|
||||
shaderPaths.Add(deps[j]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void _BuildShaderAssetBundle(List<string> shader, string outputPath, BuildTarget buildTarget)
|
||||
{
|
||||
outputPath = $"{outputPath}/{EditorUserBuildSettings.activeBuildTarget.ToString()}";
|
||||
if (!Directory.Exists(outputPath))
|
||||
{
|
||||
Directory.CreateDirectory(outputPath);
|
||||
}
|
||||
|
||||
var assetBuild = new AssetBundleBuild
|
||||
{
|
||||
assetBundleName = _shaderAssetBundleName,
|
||||
assetBundleVariant = string.Empty,
|
||||
assetNames = shader.ToArray()
|
||||
};
|
||||
|
||||
var options = BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.ChunkBasedCompression;
|
||||
BuildPipeline.BuildAssetBundles(outputPath, new[] { assetBuild }, options, buildTarget);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存收集到的变体
|
||||
/// </summary>
|
||||
public static void SaveShaderVariant()
|
||||
{
|
||||
if (File.Exists(_variantPath))
|
||||
{
|
||||
AssetDatabase.DeleteAsset(_variantPath);
|
||||
}
|
||||
|
||||
SaveCurrentShaderVariantCollection(_variantPath);
|
||||
AssetDatabase.Refresh();
|
||||
AssetDatabase.SaveAssets();
|
||||
EditorUtility.ClearProgressBar();
|
||||
Debug.LogError("保存成功");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是不是unity内置资源
|
||||
/// </summary>
|
||||
/// <param name="path">资源路径</param>
|
||||
/// <returns></returns>
|
||||
static bool _IsUnityDefaultResource(String path)
|
||||
{
|
||||
return String.IsNullOrEmpty(path) == false &&
|
||||
(path == "Resources/unity_builtin_extra" ||
|
||||
path == "Library/unity default resources");
|
||||
}
|
||||
|
||||
#region 内部方法
|
||||
static readonly object[] BoxedEmpty = new object[] { };
|
||||
|
||||
public static void SaveCurrentShaderVariantCollection(String path)
|
||||
{
|
||||
RflxStaticCall(
|
||||
typeof(ShaderUtil),
|
||||
"SaveCurrentShaderVariantCollection", new object[] { path });
|
||||
}
|
||||
|
||||
internal static void ClearCurrentShaderVariantCollection()
|
||||
{
|
||||
RflxStaticCall(
|
||||
typeof(ShaderUtil),
|
||||
"ClearCurrentShaderVariantCollection", null);
|
||||
}
|
||||
|
||||
internal static int GetCurrentShaderVariantCollectionShaderCount()
|
||||
{
|
||||
var shaderCount = RflxStaticCall(
|
||||
typeof(ShaderUtil),
|
||||
"GetCurrentShaderVariantCollectionShaderCount", null);
|
||||
return (int)shaderCount;
|
||||
}
|
||||
|
||||
internal static int GetCurrentShaderVariantCollectionVariantCount()
|
||||
{
|
||||
var shaderVariantCount = RflxStaticCall(
|
||||
typeof(ShaderUtil),
|
||||
"GetCurrentShaderVariantCollectionVariantCount", null);
|
||||
return (int)shaderVariantCount;
|
||||
}
|
||||
|
||||
internal static object RflxStaticCall(Type type, String funcName, object[] parameters = null)
|
||||
{
|
||||
if (type != null)
|
||||
{
|
||||
var f = type.GetMethod(funcName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
if (f != null)
|
||||
{
|
||||
var r = f.Invoke(null, parameters ?? BoxedEmpty);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
Debug.LogErrorFormat("RflxStaticCall( \"{0}\", \"{1}\", {2} ) failed!",
|
||||
type != null ? type.FullName : "null", funcName, parameters ?? BoxedEmpty);
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 编辑器方法
|
||||
public class CustomMessageBox : EditorWindow
|
||||
{
|
||||
public delegate void OnWindowClose(int button, int returnValue);
|
||||
public string Info = string.Empty;
|
||||
public Func<int> OnGUIFunc;
|
||||
public OnWindowClose OnClose;
|
||||
public string[] Buttons = null;
|
||||
public int ReturnValue;
|
||||
int _CloseButton = -1;
|
||||
|
||||
public void OnDestroy()
|
||||
{
|
||||
if (OnClose != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnClose(_CloseButton, ReturnValue);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
if (!string.IsNullOrEmpty(Info))
|
||||
{
|
||||
EditorGUILayout.HelpBox(Info, MessageType.None);
|
||||
}
|
||||
GUILayout.Space(10);
|
||||
if (OnGUIFunc != null)
|
||||
{
|
||||
ReturnValue = OnGUIFunc();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71016a50ab48c6d4191338880d87f40a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using TEngine.Runtime;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
|
||||
[Serializable]
|
||||
public struct fileMd5
|
||||
{
|
||||
public string fileName;
|
||||
public string md5;
|
||||
public long fileSize;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Serialization<T>
|
||||
{
|
||||
[SerializeField]
|
||||
List<T> _target;
|
||||
|
||||
public List<T> ToList()
|
||||
{
|
||||
return _target;
|
||||
}
|
||||
|
||||
public Serialization(List<T> target)
|
||||
{
|
||||
this._target = target;
|
||||
}
|
||||
}
|
||||
|
||||
public class TEngineEditorUtil
|
||||
{
|
||||
public static void GenMd5List()
|
||||
{
|
||||
try
|
||||
{
|
||||
string source = FileSystem.ResourceRootInStreamAsset;
|
||||
var files = Directory.GetFiles(source, "*", SearchOption.AllDirectories);
|
||||
var fileNames = new List<string>();
|
||||
var fileInfos = new Dictionary<string, long>();
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (file.EndsWith(".meta"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file.Contains("Md5List.json"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file.Contains("version.json"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fileNames.Add(file.Substring(source.Length + 1));
|
||||
fileInfos.Add(file, GetFileSize(file));
|
||||
}
|
||||
|
||||
GeneralMd5CheckList(source, files, fileInfos, fileNames);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TLogger.LogError(e.ToString());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件大小
|
||||
/// </summary>
|
||||
/// <param name="sFullName"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetFileSize(string sFullName)
|
||||
{
|
||||
long lSize = 0;
|
||||
if (File.Exists(sFullName))
|
||||
{
|
||||
lSize = new FileInfo(sFullName).Length;
|
||||
}
|
||||
return lSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成md5文件列表
|
||||
/// </summary>
|
||||
/// <param name="source">目录</param>
|
||||
/// <param name="files">文件列表</param>
|
||||
/// <param name="fileList">压缩的文件列表</param>
|
||||
/// <param name="fileNames">文件名字列表</param>
|
||||
private static void GeneralMd5CheckList(string source, string[] files, Dictionary<string, long> fileInfos, List<string> fileNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
var md5List = new List<fileMd5>();
|
||||
foreach (var fileInfo in fileInfos)
|
||||
{
|
||||
var file = fileInfo.Key;
|
||||
|
||||
if (file.EndsWith(".meta") || file.EndsWith(".DS_Store"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var md5 = GetMd5Hash(file);
|
||||
var fd5 = new fileMd5
|
||||
{
|
||||
fileName = file.Substring(source.Length + 1).Replace('\\', '/'),
|
||||
md5 = md5,
|
||||
fileSize = fileInfo.Value,
|
||||
|
||||
};
|
||||
md5List.Add(fd5);
|
||||
}
|
||||
|
||||
var configPath = $"{source}/{"Md5List.json"}";
|
||||
var stream = new FileStream(configPath, FileMode.OpenOrCreate);
|
||||
|
||||
var writer = new StreamWriter(stream);
|
||||
writer.Write(UnityEngine.JsonUtility.ToJson(new Serialization<fileMd5>(md5List)));
|
||||
writer.Flush();
|
||||
writer.Dispose();
|
||||
writer.Close();
|
||||
|
||||
fileNames.Add("Md5List.json");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TLogger.LogError(e.ToString());
|
||||
throw;
|
||||
}
|
||||
TLogger.LogInfoSuccessd("Gen Md5 List Success");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件的md5码
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMd5Hash(string fileName)
|
||||
{
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
TLogger.LogWarning($"not exit file,path:{fileName}");
|
||||
return string.Empty;
|
||||
}
|
||||
try
|
||||
{
|
||||
using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
MD5 md5 = new MD5CryptoServiceProvider();
|
||||
byte[] retVal = md5.ComputeHash(file);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < retVal.Length; i++)
|
||||
{
|
||||
sb.Append(retVal[i].ToString("x2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
TLogger.LogError("GetMD5Hash() fail,error:" + ex.Message);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4562ad10f9b80534cb0e84f8b4d73c06
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Editor/AssetBundleBuild/Util.meta
Normal file
8
Assets/TEngine/Scripts/Editor/AssetBundleBuild/Util.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28aedf920dcf7e4488b9e9d5c928dad0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
public class AssetbundleEncryption
|
||||
{
|
||||
public static void EncryptAssetBundlesByDirectory(string bundlePath, ulong offset)
|
||||
{
|
||||
if (offset < 1)
|
||||
{
|
||||
Debug.LogWarning("无法生效的偏移值:" + offset);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(bundlePath))
|
||||
{
|
||||
Debug.LogError("bundlePath为空");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(bundlePath))
|
||||
{
|
||||
Debug.LogError("不存在的AB包路径:" + bundlePath);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
using (FileTree fileTree =
|
||||
FileTree.CreateWithExcludeFilter(bundlePath, new[] { ".manifest", ".bin" }))
|
||||
{
|
||||
foreach (FileInfo file in fileTree.GetAllFiles())
|
||||
{
|
||||
byte[] fileData = File.ReadAllBytes(file.FullName);
|
||||
ulong newLength = (ulong)fileData.Length + offset;
|
||||
byte[] buffer = new byte[newLength];
|
||||
|
||||
Array.Copy(fileData, buffer, (int)offset);
|
||||
Array.Copy(fileData, 0, buffer, (int)offset, fileData.Length);
|
||||
|
||||
|
||||
FileStream fs = File.OpenWrite(file.FullName);
|
||||
fs.Write(buffer, 0, (int)newLength);
|
||||
fs.Close();
|
||||
|
||||
Debug.Log(file.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23a97b273f8c4c0438c5f1e173c94c25
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Editor/Helper.meta
Normal file
8
Assets/TEngine/Scripts/Editor/Helper.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0321a804bac01c64fada18ff62de3c8b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
33
Assets/TEngine/Scripts/Editor/Helper/AssetTagEditor.cs
Normal file
33
Assets/TEngine/Scripts/Editor/Helper/AssetTagEditor.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
[CustomEditor(typeof(AssetTag), true)]
|
||||
public class AssetTagEditor : UnityEditor.Editor
|
||||
{
|
||||
private AssetTag _target;
|
||||
private void OnEnable()
|
||||
{
|
||||
_target = (AssetTag)target;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.TextField("AssetPath", _target.Path);
|
||||
if (GUILayout.Button("定位资源", GUILayout.Width(68)))
|
||||
{
|
||||
UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>($"{AssetConfig.AssetRootPath}/{_target.Path}");
|
||||
if (obj)
|
||||
{
|
||||
EditorGUIUtility.PingObject(obj);
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/TEngine/Scripts/Editor/Helper/AssetTagEditor.cs.meta
Normal file
11
Assets/TEngine/Scripts/Editor/Helper/AssetTagEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef484fe7f7264394f945fc7c90d6c7c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
90
Assets/TEngine/Scripts/Editor/Helper/TEngineEditor.cs
Normal file
90
Assets/TEngine/Scripts/Editor/Helper/TEngineEditor.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
public class TEngineEditor
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
internal class EditorMenus
|
||||
{
|
||||
[MenuItem("TEngine/打开文档|Open TEngine Document", priority = 1500)]
|
||||
public static void OpenTEngineDocument()
|
||||
{
|
||||
Application.OpenURL("http://1.12.241.46:5000/");
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadData(string filePath, ICollection<string> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate);
|
||||
StreamReader streamReader = new StreamReader(fileStream);
|
||||
string content = streamReader.ReadLine();
|
||||
while (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
data.Add(content);
|
||||
content = streamReader.ReadLine();
|
||||
}
|
||||
streamReader.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError("读取文件失败:" + ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveData(string filePath, ICollection<string> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileStream fileStream = new FileStream(filePath, FileMode.Create);
|
||||
StreamWriter streamWriter = new StreamWriter(fileStream);
|
||||
foreach (var content in data)
|
||||
{
|
||||
streamWriter.WriteLine(content);
|
||||
}
|
||||
streamWriter.Flush();
|
||||
streamWriter.Close();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError("写入文件失败:" + ex);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Assets/导出Unity资源包", false, 20)]
|
||||
static void ExportPackage()
|
||||
{
|
||||
if (Selection.objects.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var assetPaths = new string[Selection.objects.Length];
|
||||
for (var i = 0; i < assetPaths.Length; i++)
|
||||
{
|
||||
assetPaths[i] = AssetDatabase.GetAssetPath(Selection.objects[i]);
|
||||
}
|
||||
|
||||
ExportPackage(assetPaths);
|
||||
}
|
||||
|
||||
public static void ExportPackage(string[] assetPaths)
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanel("导出Unity资源包", "", "", "unitypackage");
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
assetPaths = AssetDatabase.GetDependencies(assetPaths);
|
||||
AssetDatabase.ExportPackage(assetPaths, path, ExportPackageOptions.Interactive | ExportPackageOptions.Recurse | ExportPackageOptions.IncludeDependencies);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
11
Assets/TEngine/Scripts/Editor/Helper/TEngineEditor.cs.meta
Normal file
11
Assets/TEngine/Scripts/Editor/Helper/TEngineEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac81bad87e606294582d5fb4e1be4814
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Editor/Inspector.meta
Normal file
8
Assets/TEngine/Scripts/Editor/Inspector.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93fcab8ff2625fc49b46fb54b83af21b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Editor/Inspector/Base.meta
Normal file
8
Assets/TEngine/Scripts/Editor/Inspector/Base.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 454f812e3f7fc7c469cc878382e5cf00
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,57 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏框架 Inspector 抽象类。
|
||||
/// </summary>
|
||||
public abstract class TEngineInspector : UnityEditor.Editor
|
||||
{
|
||||
private bool m_IsCompiling = false;
|
||||
|
||||
/// <summary>
|
||||
/// 绘制事件。
|
||||
/// </summary>
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (m_IsCompiling && !EditorApplication.isCompiling)
|
||||
{
|
||||
m_IsCompiling = false;
|
||||
OnCompileComplete();
|
||||
}
|
||||
else if (!m_IsCompiling && EditorApplication.isCompiling)
|
||||
{
|
||||
m_IsCompiling = true;
|
||||
OnCompileStart();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编译开始事件。
|
||||
/// </summary>
|
||||
protected virtual void OnCompileStart()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编译完成事件。
|
||||
/// </summary>
|
||||
protected virtual void OnCompileComplete()
|
||||
{
|
||||
}
|
||||
|
||||
protected bool IsPrefabInHierarchy(UnityEngine.Object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
return PrefabUtility.GetPrefabAssetType(obj) != PrefabAssetType.Regular;
|
||||
#else
|
||||
return PrefabUtility.GetPrefabType(obj) != PrefabType.Prefab;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05b15d046064d604d8cbdb1c30c2617b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,61 @@
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
[CustomEditor(typeof(DebuggerComponent))]
|
||||
internal sealed class DebuggerComponentInspector : TEngineInspector
|
||||
{
|
||||
private SerializedProperty m_Skin = null;
|
||||
private SerializedProperty m_ActiveWindow = null;
|
||||
private SerializedProperty m_ShowFullWindow = null;
|
||||
private SerializedProperty m_ConsoleWindow = null;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
DebuggerComponent t = (DebuggerComponent)target;
|
||||
|
||||
EditorGUILayout.PropertyField(m_Skin);
|
||||
|
||||
if (EditorApplication.isPlaying && IsPrefabInHierarchy(t.gameObject))
|
||||
{
|
||||
bool activeWindow = EditorGUILayout.Toggle("Active Window", t.ActiveWindow);
|
||||
if (activeWindow != t.ActiveWindow)
|
||||
{
|
||||
t.ActiveWindow = activeWindow;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_ActiveWindow);
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(m_ShowFullWindow);
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
if (GUILayout.Button("Reset Layout"))
|
||||
{
|
||||
t.ResetLayout();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(m_ConsoleWindow, true);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_Skin = serializedObject.FindProperty("m_Skin");
|
||||
m_ActiveWindow = serializedObject.FindProperty("m_ActiveWindow");
|
||||
m_ShowFullWindow = serializedObject.FindProperty("m_ShowFullWindow");
|
||||
m_ConsoleWindow = serializedObject.FindProperty("m_ConsoleWindow");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f2b744f6280e2e4eb581bb87ead911b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,44 @@
|
||||
using UnityEditor;
|
||||
using TEngine.Runtime;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
[CustomEditor(typeof(FsmManager))]
|
||||
internal sealed class FsmManagerInspector : TEngineInspector
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Available during runtime only.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
FsmManager t = (FsmManager)target;
|
||||
|
||||
if (IsPrefabInHierarchy(t.gameObject))
|
||||
{
|
||||
EditorGUILayout.LabelField("FSM Count", t.Count.ToString());
|
||||
|
||||
FsmBase[] fsms = t.GetAllFsms();
|
||||
foreach (FsmBase fsm in fsms)
|
||||
{
|
||||
DrawFsm(fsm);
|
||||
}
|
||||
}
|
||||
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
}
|
||||
|
||||
private void DrawFsm(FsmBase fsm)
|
||||
{
|
||||
EditorGUILayout.LabelField(fsm.FullName, fsm.IsRunning ? Utility.Text.Format("{0}, {1} s", fsm.CurrentStateName, fsm.CurrentStateTime.ToString("F1")) : (fsm.IsDestroyed ? "Destroyed" : "Not Running"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f12b5f20a2a98574796ade4b3839099e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
[CustomEditor(typeof(MemoryPoolComponent))]
|
||||
internal sealed class MemoryPoolComponentInspector : TEngineInspector
|
||||
{
|
||||
private readonly Dictionary<string, List<MemoryPoolInfo>> m_MemoryPoolInfos = new Dictionary<string, List<MemoryPoolInfo>>(StringComparer.Ordinal);
|
||||
private readonly HashSet<string> m_OpenedItems = new HashSet<string>();
|
||||
|
||||
private SerializedProperty m_EnableStrictCheck = null;
|
||||
|
||||
private bool m_ShowFullClassName = false;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
MemoryPoolComponent t = (MemoryPoolComponent)target;
|
||||
|
||||
if (EditorApplication.isPlaying && IsPrefabInHierarchy(t.gameObject))
|
||||
{
|
||||
bool enableStrictCheck = EditorGUILayout.Toggle("Enable Strict Check", t.EnableStrictCheck);
|
||||
if (enableStrictCheck != t.EnableStrictCheck)
|
||||
{
|
||||
t.EnableStrictCheck = enableStrictCheck;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Memory Pool Count", MemoryPool.Count.ToString());
|
||||
m_ShowFullClassName = EditorGUILayout.Toggle("Show Full Class Name", m_ShowFullClassName);
|
||||
m_MemoryPoolInfos.Clear();
|
||||
MemoryPoolInfo[] memoryPoolInfos = MemoryPool.GetAllMemoryPoolInfos();
|
||||
foreach (MemoryPoolInfo memoryPoolInfo in memoryPoolInfos)
|
||||
{
|
||||
string assemblyName = memoryPoolInfo.Type.Assembly.GetName().Name;
|
||||
List<MemoryPoolInfo> results = null;
|
||||
if (!m_MemoryPoolInfos.TryGetValue(assemblyName, out results))
|
||||
{
|
||||
results = new List<MemoryPoolInfo>();
|
||||
m_MemoryPoolInfos.Add(assemblyName, results);
|
||||
}
|
||||
|
||||
results.Add(memoryPoolInfo);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, List<MemoryPoolInfo>> assemblyMemoryPoolInfo in m_MemoryPoolInfos)
|
||||
{
|
||||
bool lastState = m_OpenedItems.Contains(assemblyMemoryPoolInfo.Key);
|
||||
bool currentState = EditorGUILayout.Foldout(lastState, assemblyMemoryPoolInfo.Key);
|
||||
if (currentState != lastState)
|
||||
{
|
||||
if (currentState)
|
||||
{
|
||||
m_OpenedItems.Add(assemblyMemoryPoolInfo.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_OpenedItems.Remove(assemblyMemoryPoolInfo.Key);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentState)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
{
|
||||
EditorGUILayout.LabelField(m_ShowFullClassName ? "Full Class Name" : "Class Name", "Unused\tUsing\tAcquire\tRelease\tAdd\tRemove");
|
||||
assemblyMemoryPoolInfo.Value.Sort(Comparison);
|
||||
foreach (MemoryPoolInfo memoryPoolInfo in assemblyMemoryPoolInfo.Value)
|
||||
{
|
||||
DrawMemoryPoolInfo(memoryPoolInfo);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Export CSV Data"))
|
||||
{
|
||||
string exportFileName = EditorUtility.SaveFilePanel("Export CSV Data", string.Empty, Utility.Text.Format("Memory Pool Data - {0}.csv", assemblyMemoryPoolInfo.Key), string.Empty);
|
||||
if (!string.IsNullOrEmpty(exportFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
int index = 0;
|
||||
string[] data = new string[assemblyMemoryPoolInfo.Value.Count + 1];
|
||||
data[index++] = "Class Name,Full Class Name,Unused,Using,Acquire,Release,Add,Remove";
|
||||
foreach (MemoryPoolInfo memoryPoolInfo in assemblyMemoryPoolInfo.Value)
|
||||
{
|
||||
data[index++] = Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7}", memoryPoolInfo.Type.Name, memoryPoolInfo.Type.FullName, memoryPoolInfo.UnusedMemoryCount.ToString(), memoryPoolInfo.UsingMemoryCount.ToString(), memoryPoolInfo.AcquireMemoryCount.ToString(), memoryPoolInfo.ReleaseMemoryCount.ToString(), memoryPoolInfo.AddMemoryCount.ToString(), memoryPoolInfo.RemoveMemoryCount.ToString());
|
||||
}
|
||||
|
||||
File.WriteAllLines(exportFileName, data, Encoding.UTF8);
|
||||
Debug.Log(Utility.Text.Format("Export memory pool CSV data to '{0}' success.", exportFileName));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogError(Utility.Text.Format("Export memory pool CSV data to '{0}' failure, exception is '{1}'.", exportFileName, exception.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_EnableStrictCheck);
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_EnableStrictCheck = serializedObject.FindProperty("m_EnableStrictCheck");
|
||||
}
|
||||
|
||||
private void DrawMemoryPoolInfo(MemoryPoolInfo memoryPoolInfo)
|
||||
{
|
||||
EditorGUILayout.LabelField(m_ShowFullClassName ? memoryPoolInfo.Type.FullName : memoryPoolInfo.Type.Name, Utility.Text.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", memoryPoolInfo.UnusedMemoryCount.ToString(), memoryPoolInfo.UsingMemoryCount.ToString(), memoryPoolInfo.AcquireMemoryCount.ToString(), memoryPoolInfo.ReleaseMemoryCount.ToString(), memoryPoolInfo.AddMemoryCount.ToString(), memoryPoolInfo.RemoveMemoryCount.ToString()));
|
||||
}
|
||||
|
||||
private int Comparison(MemoryPoolInfo a, MemoryPoolInfo b)
|
||||
{
|
||||
if (m_ShowFullClassName)
|
||||
{
|
||||
return a.Type.FullName.CompareTo(b.Type.FullName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return a.Type.Name.CompareTo(b.Type.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c56705de5d84bd4b80ed19e50515179
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,164 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
[CustomEditor(typeof(ProcedureComponent))]
|
||||
internal sealed class ProcedureComponentInspector :TEngineInspector
|
||||
{
|
||||
private SerializedProperty m_AvailableProcedureTypeNames = null;
|
||||
private SerializedProperty m_EntranceProcedureTypeName = null;
|
||||
|
||||
private string[] m_ProcedureTypeNames = null;
|
||||
private List<string> m_CurrentAvailableProcedureTypeNames = null;
|
||||
private int m_EntranceProcedureIndex = -1;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
ProcedureComponent t = (ProcedureComponent)target;
|
||||
|
||||
if (string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue))
|
||||
{
|
||||
EditorGUILayout.HelpBox("Entrance procedure is invalid.", MessageType.Error);
|
||||
}
|
||||
else if (EditorApplication.isPlaying)
|
||||
{
|
||||
EditorGUILayout.LabelField("Current Procedure", t.CurrentProcedure == null ? "None" : t.CurrentProcedure.GetType().ToString());
|
||||
}
|
||||
|
||||
EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode);
|
||||
{
|
||||
GUILayout.Label("Available Procedures", EditorStyles.boldLabel);
|
||||
if (m_ProcedureTypeNames.Length > 0)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
{
|
||||
foreach (string procedureTypeName in m_ProcedureTypeNames)
|
||||
{
|
||||
bool selected = m_CurrentAvailableProcedureTypeNames.Contains(procedureTypeName);
|
||||
if (selected != EditorGUILayout.ToggleLeft(procedureTypeName, selected))
|
||||
{
|
||||
if (!selected)
|
||||
{
|
||||
m_CurrentAvailableProcedureTypeNames.Add(procedureTypeName);
|
||||
WriteAvailableProcedureTypeNames();
|
||||
}
|
||||
else if (procedureTypeName != m_EntranceProcedureTypeName.stringValue)
|
||||
{
|
||||
m_CurrentAvailableProcedureTypeNames.Remove(procedureTypeName);
|
||||
WriteAvailableProcedureTypeNames();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("There is no available procedure.", MessageType.Warning);
|
||||
}
|
||||
|
||||
if (m_CurrentAvailableProcedureTypeNames.Count > 0)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
int selectedIndex = EditorGUILayout.Popup("Entrance Procedure", m_EntranceProcedureIndex, m_CurrentAvailableProcedureTypeNames.ToArray());
|
||||
if (selectedIndex != m_EntranceProcedureIndex)
|
||||
{
|
||||
m_EntranceProcedureIndex = selectedIndex;
|
||||
m_EntranceProcedureTypeName.stringValue = m_CurrentAvailableProcedureTypeNames[selectedIndex];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("Select available procedures first.", MessageType.Info);
|
||||
}
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
Repaint();
|
||||
}
|
||||
|
||||
protected override void OnCompileComplete()
|
||||
{
|
||||
base.OnCompileComplete();
|
||||
|
||||
RefreshTypeNames();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_AvailableProcedureTypeNames = serializedObject.FindProperty("m_AvailableProcedureTypeNames");
|
||||
m_EntranceProcedureTypeName = serializedObject.FindProperty("m_EntranceProcedureTypeName");
|
||||
|
||||
RefreshTypeNames();
|
||||
}
|
||||
|
||||
private void RefreshTypeNames()
|
||||
{
|
||||
m_ProcedureTypeNames = Type.GetRuntimeTypeNames(typeof(ProcedureBase));
|
||||
ReadAvailableProcedureTypeNames();
|
||||
int oldCount = m_CurrentAvailableProcedureTypeNames.Count;
|
||||
m_CurrentAvailableProcedureTypeNames = m_CurrentAvailableProcedureTypeNames.Where(x => m_ProcedureTypeNames.Contains(x)).ToList();
|
||||
if (m_CurrentAvailableProcedureTypeNames.Count != oldCount)
|
||||
{
|
||||
WriteAvailableProcedureTypeNames();
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue))
|
||||
{
|
||||
m_EntranceProcedureIndex = m_CurrentAvailableProcedureTypeNames.IndexOf(m_EntranceProcedureTypeName.stringValue);
|
||||
if (m_EntranceProcedureIndex < 0)
|
||||
{
|
||||
m_EntranceProcedureTypeName.stringValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void ReadAvailableProcedureTypeNames()
|
||||
{
|
||||
m_CurrentAvailableProcedureTypeNames = new List<string>();
|
||||
int count = m_AvailableProcedureTypeNames.arraySize;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
m_CurrentAvailableProcedureTypeNames.Add(m_AvailableProcedureTypeNames.GetArrayElementAtIndex(i).stringValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteAvailableProcedureTypeNames()
|
||||
{
|
||||
m_AvailableProcedureTypeNames.ClearArray();
|
||||
if (m_CurrentAvailableProcedureTypeNames == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_CurrentAvailableProcedureTypeNames.Sort();
|
||||
int count = m_CurrentAvailableProcedureTypeNames.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
m_AvailableProcedureTypeNames.InsertArrayElementAtIndex(i);
|
||||
m_AvailableProcedureTypeNames.GetArrayElementAtIndex(i).stringValue = m_CurrentAvailableProcedureTypeNames[i];
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue))
|
||||
{
|
||||
m_EntranceProcedureIndex = m_CurrentAvailableProcedureTypeNames.IndexOf(m_EntranceProcedureTypeName.stringValue);
|
||||
if (m_EntranceProcedureIndex < 0)
|
||||
{
|
||||
m_EntranceProcedureTypeName.stringValue = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b6a1a49416939a48b84538399389568
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
17
Assets/TEngine/Scripts/Editor/TEngine.Editor.asmdef
Normal file
17
Assets/TEngine/Scripts/Editor/TEngine.Editor.asmdef
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "TEngine.Editor",
|
||||
"references": [
|
||||
"GUID:f4ecd6f7bd8993043b6cec60dd0cf2b2"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
7
Assets/TEngine/Scripts/Editor/TEngine.Editor.asmdef.meta
Normal file
7
Assets/TEngine/Scripts/Editor/TEngine.Editor.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63410924b4df8de43b318f32296693f7
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Editor/UI.meta
Normal file
8
Assets/TEngine/Scripts/Editor/UI.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b1b0efc98a99fa4db30cb92737d06f0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
332
Assets/TEngine/Scripts/Editor/UI/ScriptGenerator.cs
Normal file
332
Assets/TEngine/Scripts/Editor/UI/ScriptGenerator.cs
Normal file
@@ -0,0 +1,332 @@
|
||||
using ScriptGenerator = TEngine.Editor.ScriptGenerator;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
public class ScriptGenerator
|
||||
{
|
||||
private static string gap = "/";
|
||||
|
||||
[MenuItem("GameObject/ScriptGenerator/UIProperty", priority = 49)]
|
||||
public static void MemberProperty()
|
||||
{
|
||||
Generate(false);
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/ScriptGenerator/UIPropertyAndListener", priority = 49)]
|
||||
public static void MemberPropertyAndListener()
|
||||
{
|
||||
Generate(true);
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/ScriptGenerator/UISwitchGroup", priority = 49)]
|
||||
public static void UISwitchGroup()
|
||||
{
|
||||
var root = Selection.activeTransform;
|
||||
if (root == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var content = ScriptGenerator.SwitchGroupGenerator.Instance.Process(root);
|
||||
TextEditor te = new TextEditor();
|
||||
te.text = content;
|
||||
te.SelectAll();
|
||||
te.Copy();
|
||||
}
|
||||
|
||||
private static void Generate(bool includeListener)
|
||||
{
|
||||
var root = Selection.activeTransform;
|
||||
if (root != null)
|
||||
{
|
||||
StringBuilder strVar = new StringBuilder();
|
||||
StringBuilder strBind = new StringBuilder();
|
||||
StringBuilder strOnCreate = new StringBuilder();
|
||||
StringBuilder strCallback = new StringBuilder();
|
||||
Ergodic(root, root, ref strVar, ref strBind, ref strOnCreate, ref strCallback);
|
||||
StringBuilder strFile = new StringBuilder();
|
||||
|
||||
if (includeListener)
|
||||
{
|
||||
strFile.Append("using TEngine;\n");
|
||||
strFile.Append("using UnityEngine;\n");
|
||||
strFile.Append("using UnityEngine.UI;\n\n");
|
||||
strFile.Append("\tclass " + root.name + " : UIWindow\n");
|
||||
strFile.Append("\t{\n");
|
||||
}
|
||||
|
||||
// 脚本工具生成的代码
|
||||
strFile.Append("\t#region 脚本工具生成的代码\n");
|
||||
strFile.Append(strVar);
|
||||
strFile.Append("\tprotected override void ScriptGenerator()\n");
|
||||
strFile.Append("\t{\n");
|
||||
strFile.Append(strBind);
|
||||
strFile.Append(strOnCreate);
|
||||
strFile.Append("\t}\n");
|
||||
strFile.Append("\t#endregion");
|
||||
|
||||
if (includeListener)
|
||||
{
|
||||
strFile.Append("\n\n");
|
||||
// #region 事件
|
||||
strFile.Append("\t#region 事件\n");
|
||||
strFile.Append(strCallback);
|
||||
strFile.Append("\t#endregion\n\n");
|
||||
|
||||
strFile.Append("}\n");
|
||||
}
|
||||
|
||||
TextEditor te = new TextEditor();
|
||||
te.text = strFile.ToString();
|
||||
te.SelectAll();
|
||||
te.Copy();
|
||||
}
|
||||
}
|
||||
|
||||
private static void Ergodic(Transform root, Transform transform, ref StringBuilder strVar, ref StringBuilder strBind, ref StringBuilder strOnCreate, ref StringBuilder strCallback)
|
||||
{
|
||||
for (int i = 0; i < transform.childCount; ++i)
|
||||
{
|
||||
Transform child = transform.GetChild(i);
|
||||
WriteScript(root, child, ref strVar, ref strBind, ref strOnCreate, ref strCallback);
|
||||
if (child.name.StartsWith("m_item"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Ergodic(root, child, ref strVar, ref strBind, ref strOnCreate, ref strCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetRelativePath(Transform child, Transform root)
|
||||
{
|
||||
StringBuilder path = new StringBuilder();
|
||||
path.Append(child.name);
|
||||
while (child.parent != null && child.parent != root)
|
||||
{
|
||||
child = child.parent;
|
||||
path.Insert(0, gap);
|
||||
path.Insert(0, child.name);
|
||||
}
|
||||
return path.ToString();
|
||||
}
|
||||
|
||||
private static string GetBtnFuncName(string varName)
|
||||
{
|
||||
return "OnClick" + varName.Replace("m_btn", string.Empty) + "Btn";
|
||||
}
|
||||
|
||||
private static string GetToggleFuncName(string varName)
|
||||
{
|
||||
return "OnToggle" + varName.Replace("m_toggle", string.Empty) + "Change";
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> dicWidget = new Dictionary<string, string>()
|
||||
{
|
||||
{"m_go", "GameObject"},
|
||||
{"m_item", "GameObject"},
|
||||
{"m_tf", "Transform"},
|
||||
{"m_rect","RectTransform"},
|
||||
{"m_text","Text"},
|
||||
{"m_richText","RichTextItem"},
|
||||
{"m_tbtn","TextButtonItem"},
|
||||
{"m_btn","Button"},
|
||||
{"m_img","Image"},
|
||||
{"m_rimg","RawImage"},
|
||||
{"m_scroll","ScrollRect"},
|
||||
{"m_input","InputField"},
|
||||
{"m_grid","GridLayoutGroup"},
|
||||
{"m_clay","CircleLayoutGroup"},
|
||||
{"m_hlay","HorizontalLayoutGroup"},
|
||||
{"m_vlay","VerticalLayoutGroup"},
|
||||
{"m_slider","Slider"},
|
||||
{"m_group","ToggleGroup"},
|
||||
{"m_toggle","Toggle"},
|
||||
{"m_curve","AnimationCurve"},
|
||||
};
|
||||
|
||||
private static void WriteScript(Transform root, Transform child, ref StringBuilder strVar, ref StringBuilder strBind, ref StringBuilder strOnCreate, ref StringBuilder strCallback)
|
||||
{
|
||||
string varName = child.name;
|
||||
string varType = string.Empty;
|
||||
foreach (var pair in dicWidget)
|
||||
{
|
||||
if (varName.StartsWith(pair.Key))
|
||||
{
|
||||
varType = pair.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (varType == string.Empty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
string varPath = GetRelativePath(child, root);
|
||||
if (!string.IsNullOrEmpty(varName))
|
||||
{
|
||||
strVar.Append("\t\tprivate " + varType + " " + varName + ";\n");
|
||||
switch (varType)
|
||||
{
|
||||
case "Transform":
|
||||
strBind.Append(string.Format("\t\t\t{0} = FindChild(\"{1}\");\n", varName, varPath));
|
||||
break;
|
||||
case "GameObject":
|
||||
strBind.Append(string.Format("\t\t\t{0} = FindChild(\"{1}\").gameObject;\n", varName, varPath));
|
||||
break;
|
||||
case "AnimationCurve":
|
||||
strBind.Append(string.Format("\t\t\t{0} = FindChildComponent<AnimCurveObject>(\"{1}\").m_animCurve;\n", varName, varPath));
|
||||
break;
|
||||
case "RichItemIcon":
|
||||
strBind.Append(string.Format("\t\t\t{0} = CreateWidgetByType<{1}>(\"{2}\");\n", varName, varType, varPath));
|
||||
break;
|
||||
case "RedNoteBehaviour":
|
||||
case "TextButtonItem":
|
||||
case "SwitchTabItem":
|
||||
case "UIActorWidget":
|
||||
case "UIEffectWidget":
|
||||
strBind.Append(string.Format("\t\t\t{0} = CreateWidget<{1}>(\"{2}\");\n", varName, varType, varPath));
|
||||
break;
|
||||
default:
|
||||
strBind.Append(string.Format("\t\t\t{0} = FindChildComponent<{1}>(\"{2}\");\n", varName, varType, varPath));
|
||||
break;
|
||||
}
|
||||
if (varType == "Button")
|
||||
{
|
||||
string varFuncName = GetBtnFuncName(varName);
|
||||
strOnCreate.Append(string.Format("\t\t\t{0}.onClick.AddListener({1});\n", varName, varFuncName));
|
||||
strCallback.Append(string.Format("\t\tprivate void {0}()\n", varFuncName));
|
||||
strCallback.Append("\t\t{\n\t\t}\n");
|
||||
}
|
||||
if (varType == "Toggle")
|
||||
{
|
||||
string varFuncName = GetToggleFuncName(varName);
|
||||
strOnCreate.Append(string.Format("\t\t\t{0}.onValueChanged.AddListener({1});\n", varName, varFuncName));
|
||||
strCallback.Append(string.Format("\t\tprivate void {0}(bool isOn)\n", varFuncName));
|
||||
strCallback.Append("\t\t{\n\t\t}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class GeneratorHelper : EditorWindow
|
||||
{
|
||||
[MenuItem("GameObject/ScriptGenerator/About", priority = 49)]
|
||||
public static void About()
|
||||
{
|
||||
ScriptGenerator.GeneratorHelper welcomeWindow = (ScriptGenerator.GeneratorHelper)EditorWindow.GetWindow(typeof(ScriptGenerator.GeneratorHelper), false, "About ScriptGenerator");
|
||||
}
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
minSize = new Vector2(400, 600);
|
||||
}
|
||||
|
||||
protected void OnGUI()
|
||||
{
|
||||
GUILayout.BeginVertical();
|
||||
foreach (var item in ScriptGenerator.dicWidget)
|
||||
{
|
||||
GUILayout.Label(item.Key + ":\t" + item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class SwitchGroupGeneratorHelper : EditorWindow
|
||||
{
|
||||
[MenuItem("GameObject/ScriptGenerator/AboutSwitchGroup", priority = 50)]
|
||||
public static void About()
|
||||
{
|
||||
GetWindow(typeof(SwitchGroupGeneratorHelper), false, "AboutSwitchGroup");
|
||||
}
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
minSize = new Vector2(400, 600);
|
||||
}
|
||||
|
||||
protected void OnGUI()
|
||||
{
|
||||
GUILayout.BeginVertical();
|
||||
GUILayout.Label(SwitchGroupGenerator.CONDITION + ":\t" + "SwitchTabItem[]");
|
||||
}
|
||||
}
|
||||
|
||||
public class SwitchGroupGenerator
|
||||
{
|
||||
/*
|
||||
遍历子节点,找到所有名为 m_switchGroup 开始的节点,输出该节点
|
||||
*/
|
||||
|
||||
public const string CONDITION = "m_switchGroup";
|
||||
|
||||
public static readonly SwitchGroupGenerator Instance = new SwitchGroupGenerator();
|
||||
|
||||
public string Process(Transform root)
|
||||
{
|
||||
var sbd = new StringBuilder();
|
||||
var list = new List<Transform>();
|
||||
Collect(root, list);
|
||||
foreach (var node in list)
|
||||
{
|
||||
sbd.AppendLine(Process(root, node)).AppendLine();
|
||||
}
|
||||
return sbd.ToString();
|
||||
}
|
||||
|
||||
public void Collect(Transform node, List<Transform> nodeList)
|
||||
{
|
||||
if (node.name.StartsWith(CONDITION))
|
||||
{
|
||||
nodeList.Add(node);
|
||||
return;
|
||||
}
|
||||
var childCnt = node.childCount;
|
||||
for (var i = 0; i < childCnt; i++)
|
||||
{
|
||||
var child = node.GetChild(i);
|
||||
Collect(child, nodeList);
|
||||
}
|
||||
}
|
||||
|
||||
public string Process(Transform root, Transform groupTf)
|
||||
{
|
||||
var parentPath = GetPath(root, groupTf);
|
||||
var _name = groupTf.name;
|
||||
var sbd = new StringBuilder(@"
|
||||
var _namePath = ""#parentPath"";
|
||||
var _nameTf = FindChild(_namePath);
|
||||
var childCnt = _nameTf.childCount;
|
||||
SwitchTabItem[] _name;
|
||||
_name = new SwitchTabItem[childCnt];
|
||||
for (var i = 0; i < childCnt; i++)
|
||||
{
|
||||
var child = _nameTf.GetChild(i);
|
||||
_name[i] = CreateWidget<SwitchTabItem>(_namePath + ""/"" + child.name);
|
||||
}");
|
||||
sbd.Replace("_name", _name);
|
||||
sbd.Replace("#parentPath", parentPath);
|
||||
return sbd.ToString();
|
||||
}
|
||||
|
||||
public string GetPath(Transform root, Transform childTf)
|
||||
{
|
||||
if (childTf == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
if (childTf == root)
|
||||
{
|
||||
return childTf.name;
|
||||
}
|
||||
|
||||
var parentPath = GetPath(root, childTf.parent);
|
||||
if (parentPath == string.Empty)
|
||||
{
|
||||
return childTf.name;
|
||||
}
|
||||
return parentPath + "/" + childTf.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/TEngine/Scripts/Editor/UI/ScriptGenerator.cs.meta
Normal file
11
Assets/TEngine/Scripts/Editor/UI/ScriptGenerator.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94d31d88c0f4b3f4a8a672a755e356d5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1428
Assets/TEngine/Scripts/Editor/UI/UIStyleSkin.guiskin
Normal file
1428
Assets/TEngine/Scripts/Editor/UI/UIStyleSkin.guiskin
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb91232a4fb2efd47b8d8b4da4f22229
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Editor/Utility.meta
Normal file
8
Assets/TEngine/Scripts/Editor/Utility.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5643953d0e0f87d4db82f6ab1e38aa77
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
11
Assets/TEngine/Scripts/Editor/Utility/ConfigPathAttribute.cs
Normal file
11
Assets/TEngine/Scripts/Editor/Utility/ConfigPathAttribute.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置路径属性。
|
||||
/// </summary>
|
||||
public abstract class ConfigPathAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebec4c251a948e84fa46d59d31a07f6e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,172 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志脚本宏定义。
|
||||
/// </summary>
|
||||
public static class LogScriptingDefineSymbols
|
||||
{
|
||||
private const string EnableLogScriptingDefineSymbol = "ENABLE_LOG";
|
||||
private const string EnableDebugAndAboveLogScriptingDefineSymbol = "ENABLE_DEBUG_AND_ABOVE_LOG";
|
||||
private const string EnableInfoAndAboveLogScriptingDefineSymbol = "ENABLE_INFO_AND_ABOVE_LOG";
|
||||
private const string EnableWarningAndAboveLogScriptingDefineSymbol = "ENABLE_WARNING_AND_ABOVE_LOG";
|
||||
private const string EnableErrorAndAboveLogScriptingDefineSymbol = "ENABLE_ERROR_AND_ABOVE_LOG";
|
||||
private const string EnableFatalAndAboveLogScriptingDefineSymbol = "ENABLE_FATAL_AND_ABOVE_LOG";
|
||||
private const string EnableDebugLogScriptingDefineSymbol = "ENABLE_DEBUG_LOG";
|
||||
private const string EnableInfoLogScriptingDefineSymbol = "ENABLE_LOG_INFO";
|
||||
private const string EnableWarningLogScriptingDefineSymbol = "ENABLE_LOG_WARNING";
|
||||
private const string EnableErrorLogScriptingDefineSymbol = "ENABLE_LOG_ERROR";
|
||||
private const string EnableFatalLogScriptingDefineSymbol = "ENABLE_LOG_EXCEPTION";
|
||||
|
||||
private static readonly string[] AboveLogScriptingDefineSymbols = new string[]
|
||||
{
|
||||
EnableDebugAndAboveLogScriptingDefineSymbol,
|
||||
EnableInfoAndAboveLogScriptingDefineSymbol,
|
||||
EnableWarningAndAboveLogScriptingDefineSymbol,
|
||||
EnableErrorAndAboveLogScriptingDefineSymbol,
|
||||
EnableFatalAndAboveLogScriptingDefineSymbol
|
||||
};
|
||||
|
||||
private static readonly string[] SpecifyLogScriptingDefineSymbols = new string[]
|
||||
{
|
||||
EnableDebugLogScriptingDefineSymbol,
|
||||
EnableInfoLogScriptingDefineSymbol,
|
||||
EnableWarningLogScriptingDefineSymbol,
|
||||
EnableErrorLogScriptingDefineSymbol,
|
||||
EnableFatalLogScriptingDefineSymbol
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 禁用所有日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/设置日志|Log Scripting Define Symbols/Disable All Logs", false, 151)]
|
||||
public static void DisableAllLogs()
|
||||
{
|
||||
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(EnableLogScriptingDefineSymbol);
|
||||
|
||||
foreach (string specifyLogScriptingDefineSymbol in SpecifyLogScriptingDefineSymbols)
|
||||
{
|
||||
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(specifyLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
foreach (string aboveLogScriptingDefineSymbol in AboveLogScriptingDefineSymbols)
|
||||
{
|
||||
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(aboveLogScriptingDefineSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启所有日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/设置日志|Log Scripting Define Symbols/Enable All Logs", false, 152)]
|
||||
public static void EnableAllLogs()
|
||||
{
|
||||
DisableAllLogs();
|
||||
ScriptingDefineSymbols.AddScriptingDefineSymbol(EnableLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启调试及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/设置日志|Log Scripting Define Symbols/Enable Debug And Above Logs", false, 153)]
|
||||
public static void EnableDebugAndAboveLogs()
|
||||
{
|
||||
SetAboveLogScriptingDefineSymbol(EnableDebugAndAboveLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启信息及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/设置日志|Log Scripting Define Symbols/Enable Info And Above Logs", false, 154)]
|
||||
public static void EnableInfoAndAboveLogs()
|
||||
{
|
||||
SetAboveLogScriptingDefineSymbol(EnableInfoAndAboveLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启警告及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/设置日志|Log Scripting Define Symbols/Enable Warning And Above Logs", false, 155)]
|
||||
public static void EnableWarningAndAboveLogs()
|
||||
{
|
||||
SetAboveLogScriptingDefineSymbol(EnableWarningAndAboveLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启错误及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/设置日志|Log Scripting Define Symbols/Enable Error And Above Logs", false, 156)]
|
||||
public static void EnableErrorAndAboveLogs()
|
||||
{
|
||||
SetAboveLogScriptingDefineSymbol(EnableErrorAndAboveLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启严重错误及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/设置日志|Log Scripting Define Symbols/Enable Fatal And Above Logs", false, 157)]
|
||||
public static void EnableFatalAndAboveLogs()
|
||||
{
|
||||
SetAboveLogScriptingDefineSymbol(EnableFatalAndAboveLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置日志脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="aboveLogScriptingDefineSymbol">要设置的日志脚本宏定义。</param>
|
||||
public static void SetAboveLogScriptingDefineSymbol(string aboveLogScriptingDefineSymbol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(aboveLogScriptingDefineSymbol))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string i in AboveLogScriptingDefineSymbols)
|
||||
{
|
||||
if (i == aboveLogScriptingDefineSymbol)
|
||||
{
|
||||
DisableAllLogs();
|
||||
ScriptingDefineSymbols.AddScriptingDefineSymbol(aboveLogScriptingDefineSymbol);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置日志脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="specifyLogScriptingDefineSymbols">要设置的日志脚本宏定义。</param>
|
||||
public static void SetSpecifyLogScriptingDefineSymbols(string[] specifyLogScriptingDefineSymbols)
|
||||
{
|
||||
if (specifyLogScriptingDefineSymbols == null || specifyLogScriptingDefineSymbols.Length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool removed = false;
|
||||
foreach (string specifyLogScriptingDefineSymbol in specifyLogScriptingDefineSymbols)
|
||||
{
|
||||
if (string.IsNullOrEmpty(specifyLogScriptingDefineSymbol))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (string i in SpecifyLogScriptingDefineSymbols)
|
||||
{
|
||||
if (i == specifyLogScriptingDefineSymbol)
|
||||
{
|
||||
if (!removed)
|
||||
{
|
||||
removed = true;
|
||||
DisableAllLogs();
|
||||
}
|
||||
|
||||
ScriptingDefineSymbols.AddScriptingDefineSymbol(specifyLogScriptingDefineSymbol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa2eb2851a9052e468b2c14e66f604a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
94
Assets/TEngine/Scripts/Editor/Utility/OpenFolder.cs
Normal file
94
Assets/TEngine/Scripts/Editor/Utility/OpenFolder.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 打开文件夹相关的实用函数。
|
||||
/// </summary>
|
||||
public static class OpenFolder
|
||||
{
|
||||
/// <summary>
|
||||
/// 打开 Data Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/打开文件夹|Open Folder/Data Path", false, 10)]
|
||||
public static void OpenFolderDataPath()
|
||||
{
|
||||
Execute(Application.dataPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开 Persistent Data Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/打开文件夹|Open Folder/Persistent Data Path", false, 11)]
|
||||
public static void OpenFolderPersistentDataPath()
|
||||
{
|
||||
Execute(Application.persistentDataPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开 Streaming Assets Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/打开文件夹|Open Folder/Streaming Assets Path", false, 12)]
|
||||
public static void OpenFolderStreamingAssetsPath()
|
||||
{
|
||||
Execute(Application.streamingAssetsPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开 Temporary Cache Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/打开文件夹|Open Folder/Temporary Cache Path", false, 13)]
|
||||
public static void OpenFolderTemporaryCachePath()
|
||||
{
|
||||
Execute(Application.temporaryCachePath);
|
||||
}
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
/// <summary>
|
||||
/// 打开 Console Log Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/打开文件夹|Open Folder/Console Log Path", false, 14)]
|
||||
public static void OpenFolderConsoleLogPath()
|
||||
{
|
||||
Execute(System.IO.Path.GetDirectoryName(Application.consoleLogPath));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 打开 TEngine Log Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("TEngine/打开文件夹|Open Folder/TEngine Log Path", false, 14)]
|
||||
public static void OpenFolderTEngineLogPath()
|
||||
{
|
||||
Execute(System.IO.Path.GetDirectoryName(Application.dataPath) + "../TEnginePersistentDataPath/");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开指定路径的文件夹。
|
||||
/// </summary>
|
||||
/// <param name="folder">要打开的文件夹的路径。</param>
|
||||
public static void Execute(string folder)
|
||||
{
|
||||
folder = Utility.Text.Format("\"{0}\"", folder);
|
||||
switch (Application.platform)
|
||||
{
|
||||
case RuntimePlatform.WindowsEditor:
|
||||
Process.Start("Explorer.exe", folder.Replace('/', '\\'));
|
||||
break;
|
||||
|
||||
case RuntimePlatform.OSXEditor:
|
||||
Process.Start("open", folder);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception(Utility.Text.Format("Not support open folder on '{0}' platform.", Application.platform.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/TEngine/Scripts/Editor/Utility/OpenFolder.cs.meta
Normal file
11
Assets/TEngine/Scripts/Editor/Utility/OpenFolder.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f92badcbe48d6542a826527ab8d006b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
150
Assets/TEngine/Scripts/Editor/Utility/ScriptingDefineSymbols.cs
Normal file
150
Assets/TEngine/Scripts/Editor/Utility/ScriptingDefineSymbols.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 脚本宏定义。
|
||||
/// </summary>
|
||||
public static class ScriptingDefineSymbols
|
||||
{
|
||||
private static readonly BuildTargetGroup[] BuildTargetGroups = new BuildTargetGroup[]
|
||||
{
|
||||
BuildTargetGroup.Standalone,
|
||||
BuildTargetGroup.iOS,
|
||||
BuildTargetGroup.Android,
|
||||
BuildTargetGroup.WSA,
|
||||
BuildTargetGroup.WebGL
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 检查指定平台是否存在指定的脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="buildTargetGroup">要检查脚本宏定义的平台。</param>
|
||||
/// <param name="scriptingDefineSymbol">要检查的脚本宏定义。</param>
|
||||
/// <returns>指定平台是否存在指定的脚本宏定义。</returns>
|
||||
public static bool HasScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] scriptingDefineSymbols = GetScriptingDefineSymbols(buildTargetGroup);
|
||||
foreach (string i in scriptingDefineSymbols)
|
||||
{
|
||||
if (i == scriptingDefineSymbol)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为指定平台增加指定的脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="buildTargetGroup">要增加脚本宏定义的平台。</param>
|
||||
/// <param name="scriptingDefineSymbol">要增加的脚本宏定义。</param>
|
||||
public static void AddScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> scriptingDefineSymbols = new List<string>(GetScriptingDefineSymbols(buildTargetGroup))
|
||||
{
|
||||
scriptingDefineSymbol
|
||||
};
|
||||
|
||||
SetScriptingDefineSymbols(buildTargetGroup, scriptingDefineSymbols.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为指定平台移除指定的脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="buildTargetGroup">要移除脚本宏定义的平台。</param>
|
||||
/// <param name="scriptingDefineSymbol">要移除的脚本宏定义。</param>
|
||||
public static void RemoveScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> scriptingDefineSymbols = new List<string>(GetScriptingDefineSymbols(buildTargetGroup));
|
||||
while (scriptingDefineSymbols.Contains(scriptingDefineSymbol))
|
||||
{
|
||||
scriptingDefineSymbols.Remove(scriptingDefineSymbol);
|
||||
}
|
||||
|
||||
SetScriptingDefineSymbols(buildTargetGroup, scriptingDefineSymbols.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为所有平台增加指定的脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="scriptingDefineSymbol">要增加的脚本宏定义。</param>
|
||||
public static void AddScriptingDefineSymbol(string scriptingDefineSymbol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (BuildTargetGroup buildTargetGroup in BuildTargetGroups)
|
||||
{
|
||||
AddScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为所有平台移除指定的脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="scriptingDefineSymbol">要移除的脚本宏定义。</param>
|
||||
public static void RemoveScriptingDefineSymbol(string scriptingDefineSymbol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (BuildTargetGroup buildTargetGroup in BuildTargetGroups)
|
||||
{
|
||||
RemoveScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定平台的脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="buildTargetGroup">要获取脚本宏定义的平台。</param>
|
||||
/// <returns>平台的脚本宏定义。</returns>
|
||||
public static string[] GetScriptingDefineSymbols(BuildTargetGroup buildTargetGroup)
|
||||
{
|
||||
return PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup).Split(';');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定平台的脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="buildTargetGroup">要设置脚本宏定义的平台。</param>
|
||||
/// <param name="scriptingDefineSymbols">要设置的脚本宏定义。</param>
|
||||
public static void SetScriptingDefineSymbols(BuildTargetGroup buildTargetGroup, string[] scriptingDefineSymbols)
|
||||
{
|
||||
PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, string.Join(";", scriptingDefineSymbols));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c68b2caa25d7904b9f7045e21cf5d33
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
114
Assets/TEngine/Scripts/Editor/Utility/Type.cs
Normal file
114
Assets/TEngine/Scripts/Editor/Utility/Type.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using TEngine.Runtime;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型相关的实用函数。
|
||||
/// </summary>
|
||||
internal static class Type
|
||||
{
|
||||
private static readonly string[] RuntimeAssemblyNames =
|
||||
{
|
||||
"TEngine.Runtime",
|
||||
"Assembly-CSharp",
|
||||
};
|
||||
|
||||
private static readonly string[] RuntimeOrEditorAssemblyNames =
|
||||
{
|
||||
"TEngine.Runtime",
|
||||
"Assembly-CSharp",
|
||||
"TEngine.Editor",
|
||||
"Assembly-CSharp-Editor",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 获取配置路径。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">配置类型。</typeparam>
|
||||
/// <returns>配置路径。</returns>
|
||||
internal static string GetConfigurationPath<T>() where T : ConfigPathAttribute
|
||||
{
|
||||
foreach (System.Type type in Utility.Assembly.GetTypes())
|
||||
{
|
||||
if (!type.IsAbstract || !type.IsSealed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
|
||||
{
|
||||
if (fieldInfo.FieldType == typeof(string) && fieldInfo.IsDefined(typeof(T), false))
|
||||
{
|
||||
return (string)fieldInfo.GetValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
|
||||
{
|
||||
if (propertyInfo.PropertyType == typeof(string) && propertyInfo.IsDefined(typeof(T), false))
|
||||
{
|
||||
return (string)propertyInfo.GetValue(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在运行时程序集中获取指定基类的所有子类的名称。
|
||||
/// </summary>
|
||||
/// <param name="typeBase">基类类型。</param>
|
||||
/// <returns>指定基类的所有子类的名称。</returns>
|
||||
internal static string[] GetRuntimeTypeNames(System.Type typeBase)
|
||||
{
|
||||
return GetTypeNames(typeBase, RuntimeAssemblyNames);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在运行时或编辑器程序集中获取指定基类的所有子类的名称。
|
||||
/// </summary>
|
||||
/// <param name="typeBase">基类类型。</param>
|
||||
/// <returns>指定基类的所有子类的名称。</returns>
|
||||
internal static string[] GetRuntimeOrEditorTypeNames(System.Type typeBase)
|
||||
{
|
||||
return GetTypeNames(typeBase, RuntimeOrEditorAssemblyNames);
|
||||
}
|
||||
|
||||
private static string[] GetTypeNames(System.Type typeBase, string[] assemblyNames)
|
||||
{
|
||||
List<string> typeNames = new List<string>();
|
||||
foreach (string assemblyName in assemblyNames)
|
||||
{
|
||||
Assembly assembly = null;
|
||||
try
|
||||
{
|
||||
assembly = Assembly.Load(assemblyName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assembly == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
System.Type[] types = assembly.GetTypes();
|
||||
foreach (System.Type type in types)
|
||||
{
|
||||
if (type.IsClass && !type.IsAbstract && typeBase.IsAssignableFrom(type))
|
||||
{
|
||||
typeNames.Add(type.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typeNames.Sort();
|
||||
return typeNames.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/TEngine/Scripts/Editor/Utility/Type.cs.meta
Normal file
11
Assets/TEngine/Scripts/Editor/Utility/Type.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a11122d3f4a70749870f268c612df21
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Runtime.meta
Normal file
8
Assets/TEngine/Scripts/Runtime.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f09a3719e6e4b544bfb383d1f31a327
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Runtime/Audio.meta
Normal file
8
Assets/TEngine/Scripts/Runtime/Audio.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7477a3a5f2acedc468c305e71c9a0edd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
556
Assets/TEngine/Scripts/Runtime/Audio/AudioMgr.cs
Normal file
556
Assets/TEngine/Scripts/Runtime/Audio/AudioMgr.cs
Normal file
@@ -0,0 +1,556 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 音频类型
|
||||
/// </summary>
|
||||
public enum AudioType
|
||||
{
|
||||
/// <summary>
|
||||
/// 声音
|
||||
/// </summary>
|
||||
Sound,
|
||||
/// <summary>
|
||||
/// 背景音乐
|
||||
/// </summary>
|
||||
Music,
|
||||
/// <summary>
|
||||
/// 人声
|
||||
/// </summary>
|
||||
Voice,
|
||||
/// <summary>
|
||||
/// 最大
|
||||
/// </summary>
|
||||
Max
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 音频控制管理器
|
||||
/// </summary>
|
||||
public class AudioMgr : UnitySingleton<AudioMgr>
|
||||
{
|
||||
#region Propreties
|
||||
private float _volume = 1f;
|
||||
private bool _enable = true;
|
||||
private bool _disabled = false;
|
||||
public AudioMixer audioMixer { get; set; }
|
||||
float[] _agentVolume = new float[(int)AudioType.Max];
|
||||
private AudioAgent[] _audioAgents = new AudioAgent[(int)AudioType.Max];
|
||||
public Dictionary<string, AssetData> AudioClipPool = new Dictionary<string, AssetData>();
|
||||
#endregion
|
||||
|
||||
#region 控制器
|
||||
/// <summary>
|
||||
/// 总音量
|
||||
/// </summary>
|
||||
public float Volume
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
return _volume;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_volume = value;
|
||||
AudioListener.volume = _volume;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 总开关
|
||||
/// </summary>
|
||||
public bool Enable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _enable;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_enable = value;
|
||||
AudioListener.volume = _enable ? _volume : 0f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 背景音量
|
||||
/// </summary>
|
||||
public float MusicVolume
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
return _agentVolume[(int)AudioType.Music];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float volume = Mathf.Clamp(value, 0.0001f, 1.0f);
|
||||
_agentVolume[(int)AudioType.Music] = volume;
|
||||
audioMixer.SetFloat("MusicVolume", Mathf.Log10(volume) * 20f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 音效音量
|
||||
/// </summary>
|
||||
public float SoundVolume
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
return _agentVolume[(int)AudioType.Sound];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float volume = Mathf.Clamp(value, 0.0001f, 1.0f);
|
||||
_agentVolume[(int)AudioType.Sound] = volume;
|
||||
audioMixer.SetFloat("SoundVolume", Mathf.Log10(volume) * 20f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Voice音量
|
||||
/// </summary>
|
||||
public float VoiceVolume
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
return _agentVolume[(int)AudioType.Voice];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float volume = Mathf.Clamp(value, 0.0001f, 1.0f);
|
||||
_agentVolume[(int)AudioType.Voice] = volume;
|
||||
audioMixer.SetFloat("VoiceVolume", Mathf.Log10(volume) * 20f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许Music
|
||||
/// </summary>
|
||||
public bool MusicEnable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
float db;
|
||||
if (audioMixer.GetFloat("MusicVolume", out db))
|
||||
{
|
||||
return db > -80f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (value)
|
||||
{
|
||||
audioMixer.SetFloat("MusicVolume", Mathf.Log10(_agentVolume[(int)AudioType.Music]) * 20f);
|
||||
}
|
||||
else
|
||||
{
|
||||
audioMixer.SetFloat("MusicVolume", -80f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许Sound
|
||||
/// </summary>
|
||||
public bool SoundEnable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _audioAgents[(int)AudioType.Sound].Enable;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_audioAgents[(int)AudioType.Sound].Enable = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许Voice
|
||||
/// </summary>
|
||||
public bool VoiceEnable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _audioAgents[(int)AudioType.Voice].Enable;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_audioAgents[(int)AudioType.Voice].Enable = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
protected override void OnLoad()
|
||||
{
|
||||
try
|
||||
{
|
||||
TypeInfo typeInfo = typeof(AudioSettings).GetTypeInfo();
|
||||
PropertyInfo propertyInfo = typeInfo.GetDeclaredProperty("unityAudioDisabled");
|
||||
_disabled = (bool)propertyInfo.GetValue(null);
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TLogger.LogError(e.ToString());
|
||||
}
|
||||
|
||||
audioMixer = Resources.Load<AudioMixer>("Audio/TEngineAudioMixer");
|
||||
|
||||
for (int i = 0; i < (int)AudioType.Max; ++i)
|
||||
{
|
||||
int channelMaxNum = 0;
|
||||
if (i == (int)AudioType.Sound)
|
||||
{
|
||||
channelMaxNum = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
channelMaxNum = 1;
|
||||
}
|
||||
_audioAgents[i] = new AudioAgent(channelMaxNum, audioMixer.FindMatchingGroups(((AudioType)i).ToString())[0]);
|
||||
_agentVolume[i] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
#region 外部调用播放操作
|
||||
public TAudio Play(AudioType type, string path, bool bLoop = false, float volume = 1.0f, bool bAsync = false, bool bInPool = false)
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
TAudio audio = _audioAgents[(int)type].Play(path, bAsync, bInPool);
|
||||
{
|
||||
if (audio != null)
|
||||
{
|
||||
audio.IsLoop = bLoop;
|
||||
audio.Volume = volume;
|
||||
}
|
||||
return audio;
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop(AudioType type, bool fadeout)
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_audioAgents[(int)type].Stop(fadeout);
|
||||
}
|
||||
|
||||
public void StopAll(bool fadeout)
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < (int)AudioType.Max; ++i)
|
||||
{
|
||||
if (_audioAgents[i] != null)
|
||||
{
|
||||
_audioAgents[i].Stop(fadeout);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
CleanSoundPool();
|
||||
for (int i = 0; i < (int)AudioType.Max; ++i)
|
||||
{
|
||||
if (_audioAgents[i] != null)
|
||||
{
|
||||
for (int j = 0; j < _audioAgents[i]._audioObjects.Count; ++j)
|
||||
{
|
||||
if (_audioAgents[i]._audioObjects[j] != null)
|
||||
{
|
||||
_audioAgents[i]._audioObjects[j].Destroy();
|
||||
_audioAgents[i]._audioObjects[j] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
_audioAgents[i] = null;
|
||||
}
|
||||
OnLoad();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Pool
|
||||
public void PutInAudioPool(List<string> list)
|
||||
{
|
||||
if (_disabled)
|
||||
return;
|
||||
foreach (string path in list)
|
||||
{
|
||||
if (!AudioClipPool.ContainsKey(path))
|
||||
{
|
||||
AssetData assetData = ResMgr.Instance.GetAsset(path, false);
|
||||
AudioClipPool?.Add(assetData.Path, assetData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveClipFromPool(List<string> list)
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (string path in list)
|
||||
{
|
||||
if (AudioClipPool.ContainsKey(path))
|
||||
{
|
||||
AudioClipPool[path].DecRef();
|
||||
AudioClipPool.Remove(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CleanSoundPool()
|
||||
{
|
||||
if (_disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (var dic in AudioClipPool)
|
||||
{
|
||||
dic.Value.DecRef();
|
||||
}
|
||||
AudioClipPool.Clear();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
for (int i = 0; i < _audioAgents.Length; ++i)
|
||||
{
|
||||
if (_audioAgents[i] != null)
|
||||
{
|
||||
_audioAgents[i].Update(Time.deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region AudioAgent
|
||||
public class AudioAgent
|
||||
{
|
||||
public List<TAudio> _audioObjects;
|
||||
AudioMixerGroup _audioMixerGroup;
|
||||
int _maxChannel;
|
||||
bool _bEnable = true;
|
||||
|
||||
public bool Enable
|
||||
{
|
||||
get
|
||||
{
|
||||
return _bEnable;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_bEnable != value)
|
||||
{
|
||||
_bEnable = value;
|
||||
if (!_bEnable)
|
||||
{
|
||||
for (int i = 0; i < _audioObjects.Count; ++i)
|
||||
{
|
||||
if (_audioObjects[i] != null)
|
||||
{
|
||||
_audioObjects[i].Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AudioAgent(int maxChannel, AudioMixerGroup audioMixerGroup)
|
||||
{
|
||||
_maxChannel = maxChannel;
|
||||
_audioObjects = new List<TAudio>();
|
||||
for (int i = 0; i < _maxChannel; i++)
|
||||
{
|
||||
TAudio tAudio = new TAudio();
|
||||
tAudio.Init(audioMixerGroup);
|
||||
_audioObjects.Add(tAudio);
|
||||
}
|
||||
_audioMixerGroup = audioMixerGroup;
|
||||
|
||||
}
|
||||
|
||||
public void AddAudio(int Num)
|
||||
{
|
||||
_maxChannel += Num;
|
||||
for (int i = 0; i < Num; i++)
|
||||
{
|
||||
_audioObjects.Add(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public TAudio Play(string path, bool bAsync, bool bInPool = false)
|
||||
{
|
||||
if (!_bEnable)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int freeChannel = -1;
|
||||
float duration = -1;
|
||||
int num = 0;
|
||||
for (int i = 0; i < _audioObjects.Count; ++i)
|
||||
{
|
||||
if (_audioObjects[i] != null && _audioObjects[i]._assetData != null && _audioObjects[i].IsFinish == false)
|
||||
{
|
||||
if (path.Equals(_audioObjects[i]._assetData.Path))
|
||||
{
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _audioObjects.Count; i++)
|
||||
{
|
||||
if (_audioObjects[i]._assetData == null || _audioObjects[i].IsFinish == true)
|
||||
{
|
||||
freeChannel = i;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (_audioObjects[i].Duration > duration)
|
||||
{
|
||||
duration = _audioObjects[i].Duration;
|
||||
|
||||
freeChannel = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (freeChannel >= 0)
|
||||
{
|
||||
if (_audioObjects[freeChannel] == null)
|
||||
{
|
||||
_audioObjects[freeChannel] = TAudio.Create(path, bAsync, _audioMixerGroup, bInPool);
|
||||
}
|
||||
else
|
||||
{
|
||||
_audioObjects[freeChannel].Load(path, bAsync, bInPool);
|
||||
}
|
||||
return _audioObjects[freeChannel];
|
||||
}
|
||||
else
|
||||
{
|
||||
TLogger.LogError($"Here is no channel to play audio {path}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop(bool fadeout)
|
||||
{
|
||||
for (int i = 0; i < _audioObjects.Count; ++i)
|
||||
{
|
||||
if (_audioObjects[i] != null)
|
||||
{
|
||||
_audioObjects[i].Stop(fadeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float delta)
|
||||
{
|
||||
for (int i = 0; i < _audioObjects.Count; ++i)
|
||||
{
|
||||
if (_audioObjects[i] != null)
|
||||
{
|
||||
_audioObjects[i].Update(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
11
Assets/TEngine/Scripts/Runtime/Audio/AudioMgr.cs.meta
Normal file
11
Assets/TEngine/Scripts/Runtime/Audio/AudioMgr.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f29360ec6919864bba8e9983366acad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Runtime/Audio/Resources.meta
Normal file
8
Assets/TEngine/Scripts/Runtime/Audio/Resources.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5848718449093574fad8b7310b176a10
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a28c58ed649f9ff46a7c8a483765b835
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,194 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!244 &-5700573295807266226
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_EffectID: 4484537926adf3943b8d15631fe4c9a8
|
||||
m_EffectName: Attenuation
|
||||
m_MixLevel: 2a6cc932f56dd434391cf093c811be4a
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!243 &-2688087525938382097
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Voice
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_GroupID: 3385c639676b0174a96c1ba9d8e7d7e8
|
||||
m_Children: []
|
||||
m_Volume: 351c3633d7a368b48b9993d12d4b49d1
|
||||
m_Pitch: 9ae2cf17f804a73499b51997d4703eee
|
||||
m_Send: 00000000000000000000000000000000
|
||||
m_Effects:
|
||||
- {fileID: 3233559901938498695}
|
||||
m_UserColorIndex: 0
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!244 &-2140790635248599779
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_EffectID: 45c78cf1965841c4cb0d3c8abef208ec
|
||||
m_EffectName: Send
|
||||
m_MixLevel: 6a8d829224d69b046b7ea67a0682d9e8
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!241 &24100000
|
||||
AudioMixerController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: TEngineAudioMixer
|
||||
m_OutputGroup: {fileID: 0}
|
||||
m_MasterGroup: {fileID: 24300002}
|
||||
m_Snapshots:
|
||||
- {fileID: 24500006}
|
||||
m_StartSnapshot: {fileID: 24500006}
|
||||
m_SuspendThreshold: -80
|
||||
m_EnableSuspend: 1
|
||||
m_UpdateMode: 0
|
||||
m_ExposedParameters:
|
||||
- guid: 5542a83cb62d88f4bb57676181f23921
|
||||
name: MusicVolume
|
||||
- guid: c48081496ad8d11438c24892996c3a81
|
||||
name: SoundVolume
|
||||
- guid: 351c3633d7a368b48b9993d12d4b49d1
|
||||
name: VoiceVolume
|
||||
m_AudioMixerGroupViews:
|
||||
- guids:
|
||||
- 5a6f013f4ed308e49981ccc37373e521
|
||||
- 1f218ab66c2b2b641b0d2ac1c8714263
|
||||
- 503f9da271c2c6543b27f7c13a51e875
|
||||
- 3385c639676b0174a96c1ba9d8e7d7e8
|
||||
name: View
|
||||
m_CurrentViewIndex: 0
|
||||
m_TargetSnapshot: {fileID: 24500006}
|
||||
--- !u!243 &24300002
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Master
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_GroupID: 5a6f013f4ed308e49981ccc37373e521
|
||||
m_Children:
|
||||
- {fileID: 9185764251035995994}
|
||||
- {fileID: -2688087525938382097}
|
||||
- {fileID: 3168079212996900356}
|
||||
m_Volume: f0efd2d64837bfe4d98d42033680eafc
|
||||
m_Pitch: 86a3dfc09cd72544983864f031c3d96c
|
||||
m_Send: 00000000000000000000000000000000
|
||||
m_Effects:
|
||||
- {fileID: 24400004}
|
||||
- {fileID: -2140790635248599779}
|
||||
m_UserColorIndex: 0
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!244 &24400004
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_EffectID: 43f3c3fd8be9c2649aaef2ae5860bb30
|
||||
m_EffectName: Attenuation
|
||||
m_MixLevel: c02fd21fa18282e498be1c97d0eef2ac
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!245 &24500006
|
||||
AudioMixerSnapshotController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Snapshot
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_SnapshotID: 5f631808614c40848b912e405ee09d3c
|
||||
m_FloatValues: {}
|
||||
m_TransitionOverrides: {}
|
||||
--- !u!243 &3168079212996900356
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Sound
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_GroupID: 503f9da271c2c6543b27f7c13a51e875
|
||||
m_Children: []
|
||||
m_Volume: c48081496ad8d11438c24892996c3a81
|
||||
m_Pitch: 8806fa02b4e88c64b9bc81979e7cbe4e
|
||||
m_Send: 00000000000000000000000000000000
|
||||
m_Effects:
|
||||
- {fileID: 8680063345532094417}
|
||||
m_UserColorIndex: 0
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
||||
--- !u!244 &3233559901938498695
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_EffectID: 7e159eaf73c3d5f4d8b9cb86ca2fbdc9
|
||||
m_EffectName: Attenuation
|
||||
m_MixLevel: 35f98f9c693a7ad4f84978dca6c3cb3e
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!244 &8680063345532094417
|
||||
AudioMixerEffectController:
|
||||
m_ObjectHideFlags: 3
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_EffectID: 14375aad2b8c71942bb00259d2b03c8f
|
||||
m_EffectName: Attenuation
|
||||
m_MixLevel: 733f99698ea57374f807c226629a12c5
|
||||
m_Parameters: []
|
||||
m_SendTarget: {fileID: 0}
|
||||
m_EnableWetMix: 0
|
||||
m_Bypass: 0
|
||||
--- !u!243 &9185764251035995994
|
||||
AudioMixerGroupController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Music
|
||||
m_AudioMixer: {fileID: 24100000}
|
||||
m_GroupID: 1f218ab66c2b2b641b0d2ac1c8714263
|
||||
m_Children: []
|
||||
m_Volume: 5542a83cb62d88f4bb57676181f23921
|
||||
m_Pitch: d1b13bce1c2d3c047975c89e79aeff05
|
||||
m_Send: 00000000000000000000000000000000
|
||||
m_Effects:
|
||||
- {fileID: -5700573295807266226}
|
||||
m_UserColorIndex: 0
|
||||
m_Mute: 0
|
||||
m_Solo: 0
|
||||
m_BypassEffects: 0
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3162afbd7fefd6c40bce53982808aa3c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
326
Assets/TEngine/Scripts/Runtime/Audio/TAudio.cs
Normal file
326
Assets/TEngine/Scripts/Runtime/Audio/TAudio.cs
Normal file
@@ -0,0 +1,326 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
public class TAudio
|
||||
{
|
||||
#region Propreties
|
||||
private int _id = 0;
|
||||
public AssetData _assetData = null;
|
||||
public AudioSource _source = null;
|
||||
Transform _transform = null;
|
||||
private float _volume = 1.0f;
|
||||
private float _duration = 0;
|
||||
private float _fadeoutTimer = 0f;
|
||||
private const float FadeoutDuration = 0.2f;
|
||||
private bool _inPool = false;
|
||||
#endregion
|
||||
|
||||
#region Public Propreties
|
||||
enum State
|
||||
{
|
||||
None,
|
||||
Loading,
|
||||
Playing,
|
||||
FadingOut,
|
||||
End,
|
||||
};
|
||||
|
||||
State _state = State.None;
|
||||
|
||||
class LoadRequest
|
||||
{
|
||||
public string path;
|
||||
public bool bAsync;
|
||||
}
|
||||
|
||||
LoadRequest _pendingLoad = null;
|
||||
|
||||
public int ID
|
||||
{
|
||||
get
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
}
|
||||
|
||||
public float Volume
|
||||
{
|
||||
set
|
||||
{
|
||||
if (_source != null)
|
||||
{
|
||||
_volume = value;
|
||||
_source.volume = _volume;
|
||||
}
|
||||
}
|
||||
get
|
||||
{
|
||||
return _volume;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFinish
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_source != null)
|
||||
{
|
||||
return _state == State.End;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float Duration
|
||||
{
|
||||
get
|
||||
{
|
||||
return _duration;
|
||||
}
|
||||
}
|
||||
|
||||
public float Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_source != null && _source.clip != null)
|
||||
{
|
||||
return _source.clip.length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _transform.position;
|
||||
}
|
||||
set
|
||||
{
|
||||
_transform.position = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLoop
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_source != null)
|
||||
{
|
||||
return _source.loop;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_source != null)
|
||||
{
|
||||
_source.loop = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal bool IsPlaying
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_source != null && _source.isPlaying)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public AudioSource AudioResource()
|
||||
{
|
||||
return _source;
|
||||
}
|
||||
|
||||
public static TAudio Create(string path, bool bAsync, AudioMixerGroup audioMixerGroup = null, bool bInPool = false)
|
||||
{
|
||||
TAudio audio = new TAudio();
|
||||
audio.Init(audioMixerGroup);
|
||||
audio.Load(path, bAsync, bInPool);
|
||||
|
||||
return audio;
|
||||
}
|
||||
|
||||
public void Init(AudioMixerGroup audioMixerGroup = null)
|
||||
{
|
||||
GameObject root = new GameObject("Audio");
|
||||
root.transform.SetParent(AudioMgr.Instance.transform);
|
||||
root.transform.localPosition = Vector3.zero;
|
||||
_transform = root.transform;
|
||||
_source = root.AddComponent<AudioSource>();
|
||||
_source.playOnAwake = false;
|
||||
if (audioMixerGroup != null)
|
||||
{
|
||||
_source.outputAudioMixerGroup = audioMixerGroup;
|
||||
}
|
||||
_id = _source.GetInstanceID();
|
||||
}
|
||||
|
||||
public void Load(string path, bool bAsync, bool bInPool = false)
|
||||
{
|
||||
_inPool = bInPool;
|
||||
if (_state == State.None || _state == State.End)
|
||||
{
|
||||
_duration = 0;
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
if (AudioMgr.Instance.AudioClipPool.ContainsKey(path))
|
||||
{
|
||||
OnAssetLoadComplete(AudioMgr.Instance.AudioClipPool[path]);
|
||||
return;
|
||||
}
|
||||
if (bAsync)
|
||||
{
|
||||
_state = State.Loading;
|
||||
ResMgr.Instance.GetAssetAsync(path, false, OnAssetLoadComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnAssetLoadComplete(ResMgr.Instance.GetAsset(path, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_pendingLoad = new LoadRequest { path = path, bAsync = bAsync };
|
||||
|
||||
if (_state == State.Playing)
|
||||
{
|
||||
Stop(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop(bool fadeout = false)
|
||||
{
|
||||
if (_source != null)
|
||||
{
|
||||
if (fadeout)
|
||||
{
|
||||
_fadeoutTimer = FadeoutDuration;
|
||||
_state = State.FadingOut;
|
||||
}
|
||||
else
|
||||
{
|
||||
_source.Stop();
|
||||
_state = State.End;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnAssetLoadComplete(AssetData assetData)
|
||||
{
|
||||
if (assetData != null)
|
||||
{
|
||||
assetData.OnAsyncLoadComplete -= OnAssetLoadComplete;
|
||||
if (_inPool && !AudioMgr.Instance.AudioClipPool.ContainsKey(assetData.Path))
|
||||
{
|
||||
assetData.AddRef();
|
||||
AudioMgr.Instance.AudioClipPool.Add(assetData.Path, assetData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_pendingLoad != null)
|
||||
{
|
||||
assetData.AddRef();
|
||||
if (assetData != null)
|
||||
{
|
||||
assetData.DecRef();
|
||||
}
|
||||
_state = State.End;
|
||||
string path = _pendingLoad.path;
|
||||
bool bAsync = _pendingLoad.bAsync;
|
||||
_pendingLoad = null;
|
||||
Load(path, bAsync);
|
||||
}
|
||||
else if (assetData != null)
|
||||
{
|
||||
assetData.AddRef();
|
||||
if (_assetData != null)
|
||||
{
|
||||
_assetData.DecRef();
|
||||
}
|
||||
_assetData = assetData;
|
||||
_source.clip = _assetData.AssetObject as AudioClip;
|
||||
if (_source.clip != null)
|
||||
{
|
||||
_source.Play();
|
||||
_state = State.Playing;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = State.End;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = State.End;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float delta)
|
||||
{
|
||||
if (_state == State.Playing)
|
||||
{
|
||||
if (!_source.isPlaying)
|
||||
{
|
||||
_state = State.End;
|
||||
}
|
||||
}
|
||||
else if (_state == State.FadingOut)
|
||||
{
|
||||
if (_fadeoutTimer > 0f)
|
||||
{
|
||||
_fadeoutTimer -= delta;
|
||||
_source.volume = _volume * _fadeoutTimer / FadeoutDuration;
|
||||
}
|
||||
else
|
||||
{
|
||||
Stop();
|
||||
if (_pendingLoad != null)
|
||||
{
|
||||
string path = _pendingLoad.path;
|
||||
bool bAsync = _pendingLoad.bAsync;
|
||||
_pendingLoad = null;
|
||||
Load(path, bAsync);
|
||||
}
|
||||
_source.volume = _volume;
|
||||
}
|
||||
}
|
||||
|
||||
_duration += delta;
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
if (_transform != null)
|
||||
{
|
||||
Object.Destroy(_transform.gameObject);
|
||||
}
|
||||
|
||||
if (_assetData != null)
|
||||
{
|
||||
_assetData.DecRef();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/TEngine/Scripts/Runtime/Audio/TAudio.cs.meta
Normal file
11
Assets/TEngine/Scripts/Runtime/Audio/TAudio.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 640620be2dcc1d34ca617d92b2bac265
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Runtime/Config.meta
Normal file
8
Assets/TEngine/Scripts/Runtime/Config.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b6cc1f73b60ad749b2c4528bd5fc051
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
192
Assets/TEngine/Scripts/Runtime/Config/ResConfigUtil.cs
Normal file
192
Assets/TEngine/Scripts/Runtime/Config/ResConfigUtil.cs
Normal file
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 过滤配置
|
||||
/// </summary>
|
||||
/// <typeparam name="TType"></typeparam>
|
||||
/// <param name="val"></param>
|
||||
/// <returns></returns>
|
||||
public delegate bool FilterResBin<TType>(TType val);
|
||||
/// <summary>
|
||||
/// 计算拼接Key
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="val"></param>
|
||||
/// <returns></returns>
|
||||
public delegate TKey ConvertDictionaryKey<TKey, TValue>(TValue val);
|
||||
|
||||
public class ResConfigUtil
|
||||
{
|
||||
private static StringBuilder m_strBuilder = new StringBuilder();
|
||||
private static readonly string m_split = "_";
|
||||
|
||||
#region 读取接口
|
||||
public static List<T> ReadConfigListRes<T>(string fileName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = typeof(T).Name;
|
||||
}
|
||||
string resPath = string.Format("Config/{0}.json",fileName);
|
||||
TextAsset jsonStr = TResources.Load<TextAsset>(resPath);
|
||||
if (jsonStr == null)
|
||||
{
|
||||
TLogger.LogError("Config {0} Read Json Error", fileName);
|
||||
return null;
|
||||
}
|
||||
|
||||
List<T> list = new List<T>();
|
||||
var jsonData = JsonHelper.Instance.Deserialize<List<T>>(jsonStr.text);
|
||||
list = jsonData;
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<T> ReadResBinDict<K,T>(Dictionary<K, T> dic,ConvertDictionaryKey<K,T> convKey ,string fileName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = typeof(T).Name;
|
||||
}
|
||||
|
||||
string resPath = string.Format("Config/{0}.json", fileName);
|
||||
TextAsset jsonStr = TResources.Load<TextAsset>(resPath);
|
||||
if (jsonStr == null)
|
||||
{
|
||||
TLogger.LogError("Config {0} Read Json Error", fileName);
|
||||
return null;
|
||||
}
|
||||
|
||||
var jsonData = JsonHelper.Instance.Deserialize<List<T>>(jsonStr.text);
|
||||
|
||||
var etr = jsonData.GetEnumerator();
|
||||
|
||||
if(dic == null)
|
||||
{
|
||||
dic = new Dictionary<K, T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dic.Clear();
|
||||
}
|
||||
|
||||
while (etr.MoveNext())
|
||||
{
|
||||
var key = convKey(etr.Current);
|
||||
{
|
||||
if (dic.ContainsKey(key))
|
||||
{
|
||||
TLogger.LogError("Config {0} Load Error, Repeat config {1}",typeof(T).ToString(),key.ToString());
|
||||
}
|
||||
dic.Add(key, etr.Current);
|
||||
}
|
||||
}
|
||||
|
||||
etr.Dispose();
|
||||
|
||||
return jsonData;
|
||||
}
|
||||
|
||||
public static List<T> ReadResBinDict<K, T>(Dictionary<K, List<T>> dict, ConvertDictionaryKey<K, T> convKey, string fileName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = typeof(T).Name;
|
||||
}
|
||||
|
||||
string resPath = string.Format("Config/{0}.json", fileName);
|
||||
TextAsset jsonStr = TResources.Load<TextAsset>(resPath);
|
||||
if (jsonStr == null)
|
||||
{
|
||||
TLogger.LogError("Config {0} Read Json Error", fileName);
|
||||
return null;
|
||||
}
|
||||
|
||||
var jsonData = JsonHelper.Instance.Deserialize<List<T>>(jsonStr.text);
|
||||
|
||||
var etr = jsonData.GetEnumerator();
|
||||
if (dict == null)
|
||||
{
|
||||
dict = new Dictionary<K, List<T>>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dict.Clear();
|
||||
}
|
||||
while (etr.MoveNext())
|
||||
{
|
||||
var data = etr.Current;
|
||||
var key = convKey(data);
|
||||
List<T> listItem;
|
||||
if (!dict.TryGetValue(key, out listItem))
|
||||
{
|
||||
listItem = new List<T>();
|
||||
dict.Add(key, listItem);
|
||||
}
|
||||
listItem.Add(data);
|
||||
}
|
||||
etr.Dispose();
|
||||
|
||||
return jsonData;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static UInt64 Make64Key(uint key1, uint key2)
|
||||
{
|
||||
return (((UInt64)key1) << 32) | key2;
|
||||
}
|
||||
|
||||
public static string MakeStringKey(uint key1, uint key2, uint key3)
|
||||
{
|
||||
m_strBuilder.Length = 0;
|
||||
m_strBuilder.Append(key1);
|
||||
m_strBuilder.Append(m_split);
|
||||
m_strBuilder.Append(key2);
|
||||
m_strBuilder.Append(m_split);
|
||||
m_strBuilder.Append(key3);
|
||||
return m_strBuilder.ToString();
|
||||
}
|
||||
|
||||
public static string MakeStringKey(string key1, uint key2)
|
||||
{
|
||||
m_strBuilder.Length = 0;
|
||||
m_strBuilder.Append(key1);
|
||||
m_strBuilder.Append(m_split);
|
||||
m_strBuilder.Append(key2);
|
||||
return m_strBuilder.ToString();
|
||||
}
|
||||
|
||||
public static string MakeStringKey(string key1, string key2)
|
||||
{
|
||||
m_strBuilder.Length = 0;
|
||||
m_strBuilder.Append(key1);
|
||||
m_strBuilder.Append(m_split);
|
||||
m_strBuilder.Append(key2);
|
||||
return m_strBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
===》 example 《===
|
||||
public class BufferMgr : Singleton<BufferMgr>
|
||||
{
|
||||
private Dictionary<string, BuffConfig> m_dictBaseConfig = new Dictionary<string, BuffConfig>();
|
||||
|
||||
public BufferMgr()
|
||||
{
|
||||
m_dictBaseConfig = ResConfigUtil.ReadConfigRes<BuffConfig>();
|
||||
}
|
||||
|
||||
public Dictionary<string, BuffConfig> GetBuffConfig()
|
||||
{
|
||||
return m_dictBaseConfig;
|
||||
}
|
||||
}
|
||||
*
|
||||
*/
|
11
Assets/TEngine/Scripts/Runtime/Config/ResConfigUtil.cs.meta
Normal file
11
Assets/TEngine/Scripts/Runtime/Config/ResConfigUtil.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47732fcfbdbefb94e9922877e93e81ae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Runtime/Config/ResDataBase.meta
Normal file
8
Assets/TEngine/Scripts/Runtime/Config/ResDataBase.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ddadc0410f1c53a46b575aee186bc96a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,90 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
public interface IResRawListInterface<T>
|
||||
{
|
||||
List<T> RawList { get; }
|
||||
}
|
||||
|
||||
public class ResDataBase<T> : IResRawListInterface<T>
|
||||
{
|
||||
private IResRawListInterface<T> m_sourceRawList = null;
|
||||
|
||||
private string m_fileName = null;
|
||||
private List<T> m_rawList = null;
|
||||
private bool m_loaded = false;
|
||||
|
||||
public List<T> RawList
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckLoad();
|
||||
return m_rawList;
|
||||
}
|
||||
}
|
||||
|
||||
protected void InitBase(string fileName)
|
||||
{
|
||||
m_fileName = fileName;
|
||||
}
|
||||
|
||||
protected void InitBase(IResRawListInterface<T> sourceList)
|
||||
{
|
||||
m_sourceRawList = sourceList;
|
||||
}
|
||||
|
||||
protected void ClearBase()
|
||||
{
|
||||
m_loaded = false;
|
||||
m_rawList = null;
|
||||
}
|
||||
|
||||
protected void CheckLoad()
|
||||
{
|
||||
if (m_loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
GameTickWatcher tickWatcher = new GameTickWatcher();
|
||||
#endif
|
||||
|
||||
m_loaded = true;
|
||||
if (m_sourceRawList != null)
|
||||
{
|
||||
m_rawList = LoadFromSourceList(m_sourceRawList);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rawList = LoadFromFile(m_fileName);
|
||||
}
|
||||
|
||||
if (m_rawList == null)
|
||||
{
|
||||
m_rawList = new List<T>();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
TLogger.LogInfoSuccessd("Read Config {0} Used Time: {1}", typeof(T).ToString(), tickWatcher.ElapseTime());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#region 处理载入
|
||||
|
||||
protected virtual List<T> LoadFromFile(string fileName)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual List<T> LoadFromSourceList(IResRawListInterface<T> sourceList)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f66e08f903a6801468e66394daca48d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,104 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
public class ResDictionary<K, T> : ResDataBase<T> where T : new()
|
||||
{
|
||||
private FilterResBin<T> m_filter = null;
|
||||
private ConvertDictionaryKey<K, T> m_convKey = null;
|
||||
private Dictionary<K, T> m_data = null;
|
||||
|
||||
public Dictionary<K, T> Data
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckLoad();
|
||||
return m_data;
|
||||
}
|
||||
}
|
||||
|
||||
public void Init(string fileName, ConvertDictionaryKey<K, T> convKey)
|
||||
{
|
||||
InitBase(fileName);
|
||||
m_convKey = convKey;
|
||||
m_filter = null;
|
||||
}
|
||||
|
||||
public void Init(ConvertDictionaryKey<K, T> convKey)
|
||||
{
|
||||
Init(string.Empty, convKey);
|
||||
}
|
||||
|
||||
public void Init(IResRawListInterface<T> rawList, ConvertDictionaryKey<K, T> convKey, FilterResBin<T> filter = null)
|
||||
{
|
||||
InitBase(rawList);
|
||||
m_convKey = convKey;
|
||||
m_filter = filter;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_data = null;
|
||||
ClearBase();
|
||||
}
|
||||
|
||||
protected override List<T> LoadFromSourceList(IResRawListInterface<T> sourceList)
|
||||
{
|
||||
m_data = new Dictionary<K, T>();
|
||||
var rawList = sourceList.RawList;
|
||||
for (int i = 0; i < rawList.Count; i++)
|
||||
{
|
||||
var config = rawList[i];
|
||||
if (m_filter != null && !m_filter(config))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var key = m_convKey(config);
|
||||
if (m_data.ContainsKey(key))
|
||||
{
|
||||
TLogger.LogError("Config {0} load error, repeat config: {0}", typeof(T).ToString(), key.ToString());
|
||||
continue;
|
||||
}
|
||||
|
||||
m_data.Add(key, config);
|
||||
}
|
||||
|
||||
return rawList;
|
||||
}
|
||||
|
||||
protected override List<T> LoadFromFile(string fileName)
|
||||
{
|
||||
m_data = new Dictionary<K, T>();
|
||||
|
||||
//读取文件不支持filter,实际也没这个需求
|
||||
TLogger.LogAssert(m_filter == null);
|
||||
|
||||
List<T> rawList;
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
rawList = ResConfigUtil.ReadResBinDict(m_data, m_convKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
rawList = ResConfigUtil.ReadResBinDict(m_data, m_convKey,fileName);
|
||||
}
|
||||
|
||||
return rawList;
|
||||
}
|
||||
|
||||
public bool TryGetValue(K key, out T itemData, bool showLog = false)
|
||||
{
|
||||
if (Data.TryGetValue(key, out itemData))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (showLog)
|
||||
{
|
||||
TLogger.LogError("get config {0} failed, key: {1}!", typeof(T), key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efcf1d5d517018a4795f384a746dcb5b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,87 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
class ResDictionaryList<K, T> : ResDataBase<T> where T : new()
|
||||
{
|
||||
private ConvertDictionaryKey<K, T> m_convKey = null;
|
||||
private Dictionary<K, List<T>> m_data = null;
|
||||
|
||||
public Dictionary<K, List<T>> Data
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckLoad();
|
||||
return m_data;
|
||||
}
|
||||
}
|
||||
|
||||
public void Init(string fileName, ConvertDictionaryKey<K, T> convKey, FilterResBin<T> filter = null)
|
||||
{
|
||||
InitBase(fileName);
|
||||
m_convKey = convKey;
|
||||
}
|
||||
|
||||
public void Init(ConvertDictionaryKey<K, T> convKey)
|
||||
{
|
||||
Init(string.Empty, convKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造list数据结构,依赖基础的数据源
|
||||
/// </summary>
|
||||
/// <param name="sourceList"></param>
|
||||
/// <param name="convKey"></param>
|
||||
/// <param name="filter"></param>
|
||||
public void Init(IResRawListInterface<T> sourceList, ConvertDictionaryKey<K, T> convKey, FilterResBin<T> filter = null)
|
||||
{
|
||||
InitBase(sourceList);
|
||||
m_convKey = convKey;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_data = null;
|
||||
ClearBase();
|
||||
}
|
||||
|
||||
protected override List<T> LoadFromSourceList(IResRawListInterface<T> sourceList)
|
||||
{
|
||||
m_data = new Dictionary<K, List<T>>();
|
||||
|
||||
var rawList = sourceList.RawList;
|
||||
for (int i = 0; i < rawList.Count; i++)
|
||||
{
|
||||
var config = rawList[i];
|
||||
var key = m_convKey(config);
|
||||
List<T> listData;
|
||||
if (!m_data.TryGetValue(key, out listData))
|
||||
{
|
||||
listData = new List<T>();
|
||||
m_data.Add(key, listData);
|
||||
}
|
||||
|
||||
listData.Add(config);
|
||||
}
|
||||
|
||||
return rawList;
|
||||
}
|
||||
|
||||
protected override List<T> LoadFromFile(string fileName)
|
||||
{
|
||||
m_data = new Dictionary<K, List<T>>();
|
||||
|
||||
List<T> list;
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
list = ResConfigUtil.ReadResBinDict(m_data, m_convKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
list = ResConfigUtil.ReadResBinDict(m_data, m_convKey,fileName);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1c0c610ab7c2404992367ef40ec7a9c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
81
Assets/TEngine/Scripts/Runtime/Config/ResDataBase/ResList.cs
Normal file
81
Assets/TEngine/Scripts/Runtime/Config/ResDataBase/ResList.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
public class ResList<T> : ResDataBase<T> where T : new()
|
||||
{
|
||||
private Comparison<T> m_comparer;
|
||||
|
||||
public List<T> Data
|
||||
{
|
||||
get { return RawList; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化配置
|
||||
/// </summary>
|
||||
/// <param name="comparer">如果需要排序,那么传入排序函数</param>
|
||||
public void Init(Comparison<T> comparer = null)
|
||||
{
|
||||
InitBase(string.Empty);
|
||||
m_comparer = comparer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化配置
|
||||
/// </summary>
|
||||
/// <param name="fileName">指定配置文件名</param>
|
||||
/// <param name="comparer">如果需要排序,那么传入排序函数</param>
|
||||
public void Init(string fileName, Comparison<T> comparer = null)
|
||||
{
|
||||
InitBase(fileName);
|
||||
m_comparer = comparer;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ClearBase();
|
||||
}
|
||||
|
||||
protected override List<T> LoadFromFile(string fileName)
|
||||
{
|
||||
List<T> listData;
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
listData = ResConfigUtil.ReadConfigListRes<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
listData = ResConfigUtil.ReadConfigListRes<T>(fileName);
|
||||
}
|
||||
|
||||
if (m_comparer != null)
|
||||
{
|
||||
listData.Sort(m_comparer);
|
||||
}
|
||||
|
||||
return listData;
|
||||
}
|
||||
|
||||
protected override List<T> LoadFromSourceList(IResRawListInterface<T> sourceList)
|
||||
{
|
||||
if (m_comparer != null)
|
||||
{
|
||||
List<T> listSorted = new List<T>();
|
||||
|
||||
var list = sourceList.RawList;
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
listSorted.Add(list[i]);
|
||||
}
|
||||
|
||||
listSorted.Sort(m_comparer);
|
||||
|
||||
return listSorted;
|
||||
}
|
||||
|
||||
return sourceList.RawList;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e387a6e0873c0724981315547f5d83c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Runtime/Core.meta
Normal file
8
Assets/TEngine/Scripts/Runtime/Core.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be542af7cb61ded4797e1c811f855e89
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Runtime/Core/Base.meta
Normal file
8
Assets/TEngine/Scripts/Runtime/Core/Base.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e1909ecd7ab1cf4fb32c7aae20b74b9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct.meta
Normal file
8
Assets/TEngine/Scripts/Runtime/Core/Base/DataStruct.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0429f063053ec3c47b11dcbcb8a6a25d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型和名称的组合值。
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
internal struct TypeNamePair : IEquatable<TypeNamePair>
|
||||
{
|
||||
private readonly Type m_Type;
|
||||
private readonly string m_Name;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化类型和名称的组合值的新实例。
|
||||
/// </summary>
|
||||
/// <param name="type">类型。</param>
|
||||
public TypeNamePair(Type type)
|
||||
: this(type, string.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化类型和名称的组合值的新实例。
|
||||
/// </summary>
|
||||
/// <param name="type">类型。</param>
|
||||
/// <param name="name">名称。</param>
|
||||
public TypeNamePair(Type type, string name)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
throw new Exception("Type is invalid.");
|
||||
}
|
||||
|
||||
m_Type = type;
|
||||
m_Name = name ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型。
|
||||
/// </summary>
|
||||
public Type Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取名称。
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型和名称的组合值字符串。
|
||||
/// </summary>
|
||||
/// <returns>类型和名称的组合值字符串。</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
if (m_Type == null)
|
||||
{
|
||||
throw new Exception("Type is invalid.");
|
||||
}
|
||||
|
||||
string typeName = m_Type.FullName;
|
||||
return string.IsNullOrEmpty(m_Name) ? typeName : string.Format("{0}.{1}", typeName, m_Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象的哈希值。
|
||||
/// </summary>
|
||||
/// <returns>对象的哈希值。</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return m_Type.GetHashCode() ^ m_Name.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 比较对象是否与自身相等。
|
||||
/// </summary>
|
||||
/// <param name="obj">要比较的对象。</param>
|
||||
/// <returns>被比较的对象是否与自身相等。</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is TypeNamePair && Equals((TypeNamePair)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 比较对象是否与自身相等。
|
||||
/// </summary>
|
||||
/// <param name="value">要比较的对象。</param>
|
||||
/// <returns>被比较的对象是否与自身相等。</returns>
|
||||
public bool Equals(TypeNamePair value)
|
||||
{
|
||||
return m_Type == value.m_Type && m_Name == value.m_Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断两个对象是否相等。
|
||||
/// </summary>
|
||||
/// <param name="a">值 a。</param>
|
||||
/// <param name="b">值 b。</param>
|
||||
/// <returns>两个对象是否相等。</returns>
|
||||
public static bool operator ==(TypeNamePair a, TypeNamePair b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断两个对象是否不相等。
|
||||
/// </summary>
|
||||
/// <param name="a">值 a。</param>
|
||||
/// <param name="b">值 b。</param>
|
||||
/// <returns>两个对象是否不相等。</returns>
|
||||
public static bool operator !=(TypeNamePair a, TypeNamePair b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user