#if ODIN_INSPECTOR
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Sirenix.OdinInspector;
using SerializationUtility = Sirenix.Serialization.SerializationUtility;
using UnityEditor;
using UnityEngine;
namespace ET.PackageManager.Editor
{
[Flags]
public enum EPackagesFilterType
{
[LabelText("全部")]
All = 1 << 30,
[LabelText("无")]
None = 1,
[LabelText("ET包")]
ET = 1 << 1,
[LabelText("更新")]
Update = 1 << 2,
[LabelText("请求")]
Req = 1 << 3,
[LabelText("禁用")]
Ban = 1 << 4,
[LabelText("解禁")]
ReBan = 1 << 5,
}
public enum EPackagesFilterOperationType
{
[LabelText("唯一")]
Only = 0,
[LabelText("或")]
Or = 1,
[LabelText("与")]
And = 2,
}
///
/// 版本管理
///
[ETPackageMenu("版本管理", 1000)]
public partial class ETPackageVersionModule : BasePackageToolModule
{
public static ETPackageVersionModule Inst;
[HideLabel]
[HideIf("CheckUpdateAllEnd")]
[ShowInInspector]
[DisplayAsString(false, 100, TextAlignment.Center, true)]
private const string m_CheckUpdateAllReqing = "请求所有包最新版本中...";
[BoxGroup("信息", centerLabel: true)]
[EnumToggleButtons]
[HideLabel]
[OnValueChanged("OnFilterOperationTypeChanged")]
[ShowIf("CheckUpdateAllEnd")]
[PropertyOrder(-666)]
public EPackagesFilterOperationType FilterOperationType;
private void OnFilterOperationTypeChanged()
{
if (FilterOperationType == EPackagesFilterOperationType.Only)
{
LastFilterType = EPackagesFilterType.None;
FilterType = EPackagesFilterType.None;
}
LoadFilterPackageInfoData();
}
[BoxGroup("信息", centerLabel: true)]
[EnumToggleButtons]
[HideLabel]
[OnValueChanged("OnFilterTypeChanged")]
[ShowIf("CheckUpdateAllEnd")]
[PropertyOrder(-666)]
public EPackagesFilterType FilterType;
private EPackagesFilterType LastFilterType;
private void OnFilterTypeChanged()
{
if (FilterOperationType == EPackagesFilterOperationType.Only)
{
if (FilterType != LastFilterType)
{
var current = (int)FilterType;
var last = (int)LastFilterType;
FilterType = (EPackagesFilterType)(current > last ? current - last : last - current);
}
}
LastFilterType = FilterType;
LoadFilterPackageInfoData();
}
[BoxGroup("信息", centerLabel: true)]
[LabelText("搜索 (支持正则)")]
[ShowIf("CheckUpdateAllEnd")]
[OnValueChanged("OnSearchChanged")]
[Delayed]
[ShowInInspector]
[PropertyOrder(-444)]
private string Search = "";
private void OnSearchChanged()
{
Search = Search.ToLower();
LoadFilterPackageInfoData();
}
private EnumPrefs FilterTypePrefs = new("ETPackageVersionModule_FilterType", null, EPackagesFilterType.ET);
private EnumPrefs FilterOperationTypePrefs = new("ETPackageVersionModule_FilterOperationType");
private BoolPrefs SyncDependencyPrefs = new("ETPackageVersionModule_SyncDependency", null, true);
private StringPrefs SearchPrefs = new("ETPackageVersionModule_Search", null, "");
public bool CheckUpdateAllEnd { get; private set; }
public bool RequestAllResult { get; private set; }
public override void Initialize()
{
CheckUpdateAllEnd = false;
RequestAllResult = false;
PackageHelper.CheckUpdateAll((result) =>
{
CheckUpdateAllEnd = true;
RequestAllResult = result;
if (!result) return;
Search = SearchPrefs.Value;
FilterType = FilterTypePrefs.Value;
LastFilterType = FilterType;
FilterOperationType = FilterOperationTypePrefs.Value;
LoadAllPackageInfoData();
LoadFilterPackageInfoData();
Inst = this;
});
}
public override void OnDestroy()
{
Inst = null;
SearchPrefs.Value = Search;
FilterTypePrefs.Value = FilterType;
FilterOperationTypePrefs.Value = FilterOperationType;
}
[Button("同步生成", 50)]
[GUIColor(1, 1, 0)]
[PropertyOrder(-888)]
[ShowIf("CheckUpdateAllEnd")]
public void SyncPackages()
{
UnityTipsHelper.CallBack($"确定同步生成当前所有改动版本?", () =>
{
#pragma warning disable CS4014 // 由于此调用不会等待,因此在调用完成前将继续执行当前方法
UpdatePackagesInfo();
#pragma warning restore CS4014 // 由于此调用不会等待,因此在调用完成前将继续执行当前方法
});
}
[Button("文档", 30, Icon = SdfIconType.Link45deg, IconAlignment = IconAlignment.LeftOfText)]
[PropertyOrder(-999)]
[ShowIf("CheckUpdateAllEnd")]
public void OpenDocument()
{
ETPackageDocumentModule.ETPackageVersion();
}
private async Task UpdatePackagesInfo(bool close = true)
{
var count = m_AllPackageInfoDataDic.Count;
var index = 0;
foreach (var data in m_AllPackageInfoDataDic)
{
index++;
var packageInfo = data.Value;
if (!CheckPackageChange(packageInfo)) continue;
EditorUtility.DisplayProgressBar("同步信息", $"更新{packageInfo.Name}", index * 1f / count);
await ChangePackageInfo(packageInfo);
}
ETPackageAutoTool.UnloadAllAssets();
if (close)
{
PackageExecuteMenuItemHelper.ET_Init_RepairDependencies();
EditorUtility.ClearProgressBar();
ETPackageAutoTool.CloseWindowRefresh();
}
}
private bool CheckPackageChange(PackageVersionData packageInfoData)
{
if (!packageInfoData.IsETPackage)
{
return false;
}
var oldAllPackage = PackageVersionHelper.PackageVersionAsset.AllPackageVersionData;
if (!oldAllPackage.ContainsKey(packageInfoData.Name))
{
return false;
}
var oldPackageInfo = oldAllPackage[packageInfoData.Name];
//对比版本
if (packageInfoData.Version != oldPackageInfo.Version)
{
return true;
}
//对比依赖
if (packageInfoData.Dependencies.Count != oldPackageInfo.Dependencies.Count)
{
return true;
}
for (int i = 0; i < packageInfoData.Dependencies.Count; i++)
{
var dependency = packageInfoData.Dependencies[i];
var oldDependency = oldPackageInfo.Dependencies[i];
if (dependency.Name != oldDependency.Name || dependency.Version != oldDependency.Version)
{
return true;
}
}
//对比依赖我
if (packageInfoData.DependenciesSelf.Count != oldPackageInfo.DependenciesSelf.Count)
{
return true;
}
for (int i = 0; i < packageInfoData.DependenciesSelf.Count; i++)
{
var dependency = packageInfoData.DependenciesSelf[i];
var oldDependency = oldPackageInfo.DependenciesSelf[i];
if (dependency.Name != oldDependency.Name || dependency.Version != oldDependency.Version)
{
return true;
}
}
return false;
}
private async Task ChangePackageInfo(PackageVersionData packageInfoData)
{
var assetPath = $"Packages/{packageInfoData.Name}/package.json";
var packagePath = $"{Application.dataPath}/../{assetPath}";
if (!File.Exists(packagePath))
{
//Debug.LogError($"包 {packageInfoData.Name} 路径 {packagePath} 不存在");
return;
}
var changeVersion = Regex.Replace(packageInfoData.Version, Pattern, "");
try
{
string fileContent = await File.ReadAllTextAsync(packagePath);
JObject json = JObject.Parse(fileContent);
json["version"] = changeVersion;
json["dependencies"] = NewDependencies(packageInfoData);
await File.WriteAllTextAsync(packagePath, json.ToString(), System.Text.Encoding.UTF8);
Debug.Log($"修改成功 {packageInfoData.Name}");
}
catch (Exception e)
{
Debug.LogError($"错误 修改包 {packageInfoData.Name} 失败 {e.Message}");
return;
}
}
private JObject NewDependencies(PackageVersionData packageInfoData)
{
JObject newDependencies = new JObject();
foreach (var dependency in packageInfoData.Dependencies)
{
newDependencies[dependency.Name] = Regex.Replace(dependency.Version, Pattern, "");
}
return newDependencies;
}
[TableList(DrawScrollView = true, AlwaysExpanded = true, IsReadOnly = true)]
[NonSerialized]
[BoxGroup("筛选包数据", centerLabel: true)]
[HideLabel]
[ShowInInspector]
[ShowIf("CheckUpdateAllEnd")]
[PropertyOrder(999)]
private List m_FilterPackageInfoDataList = new();
private readonly Dictionary m_FilterPackageInfoDataDic = new();
private Dictionary m_AllPackageInfoDataDic;
public PackageVersionData GetPackageInfoData(string packageName)
{
m_AllPackageInfoDataDic.TryGetValue(packageName, out PackageVersionData packageInfoData);
return packageInfoData;
}
private void LoadFilterPackageInfoData()
{
m_FilterPackageInfoDataList.Clear();
m_FilterPackageInfoDataDic.Clear();
var packagesFilterTypeValues = Enum.GetValues(typeof(EPackagesFilterType));
foreach (var data in m_AllPackageInfoDataDic)
{
var name = data.Key;
if (!string.IsNullOrEmpty(Search) && !Regex.IsMatch(name, Search))
{
continue;
}
var infoData = data.Value;
var add = false;
switch (FilterOperationType)
{
case EPackagesFilterOperationType.Only:
add = GetResult(FilterType);
break;
case EPackagesFilterOperationType.Or:
add = false;
foreach (var value in packagesFilterTypeValues)
{
var filterTypeValue = (EPackagesFilterType)value;
var hasReslut = FilterType.HasFlag(filterTypeValue);
if (hasReslut)
{
add = GetResult(filterTypeValue);
if (add)
{
break;
}
}
}
break;
case EPackagesFilterOperationType.And:
add = true;
foreach (var value in packagesFilterTypeValues)
{
var filterTypeValue = (EPackagesFilterType)value;
var hasReslut = FilterType.HasFlag(filterTypeValue);
if (hasReslut)
{
add = GetResult(filterTypeValue);
if (!add)
{
break;
}
}
}
break;
default:
//Debug.LogError($"未实现的操作类型 {FilterOperationType}");
break;
}
if (!add) continue;
m_FilterPackageInfoDataList.Add(infoData);
m_FilterPackageInfoDataDic.Add(name, infoData);
continue;
bool GetResult(EPackagesFilterType filterValue)
{
var result = false;
switch (filterValue)
{
case EPackagesFilterType.All:
result = true;
break;
case EPackagesFilterType.None:
result = false;
break;
case EPackagesFilterType.ET:
result = infoData.IsETPackage;
break;
case EPackagesFilterType.Update:
result = infoData.CanUpdateVersion;
break;
case EPackagesFilterType.Req:
result = infoData.ShowIfReqVersion();
break;
case EPackagesFilterType.Ban:
result = infoData.ShowIfBanReqVersion();
break;
case EPackagesFilterType.ReBan:
result = infoData.ShowIfReBanReqVersion();
break;
default:
//Debug.LogError($"新增了筛选条件 请扩展 {filterValue}");
break;
}
return result;
}
}
}
private void LoadAllPackageInfoData()
{
m_AllPackageInfoDataDic = (Dictionary)SerializationUtility.CreateCopy(PackageVersionHelper.PackageVersionAsset.AllPackageVersionData);
//处理依赖检查
foreach (var data in m_AllPackageInfoDataDic.Values)
{
var name = data.Name;
var dependencies = data.Dependencies;
foreach (var dependency in dependencies)
{
if (!m_AllPackageInfoDataDic.ContainsKey(dependency.Name))
{
if (dependency.Name.Contains("cn.etetet."))
{
Debug.LogError($"{name}依赖包{dependency.Name}不存在");
}
continue;
}
var target = m_AllPackageInfoDataDic[dependency.Name];
if (target.IsETPackage && !CheckVersion(dependency, target))
{
Debug.LogError($"[{name}]依赖包[{dependency.Name}] 版本不匹配,依赖版本[{dependency.Version}],当前版本[{target.Version}]");
}
}
}
}
private readonly Dictionary m_VersionValueDict = new();
public const string Pattern = "[^0-9.]";
private int[] GetVersionValue(string version)
{
if (m_VersionValueDict.TryGetValue(version, out int[] value))
{
return value;
}
var versionSplit = Regex.Replace(version, Pattern, "").Split('.');
m_VersionValueDict[version] = new int[versionSplit.Length];
for (int i = 0; i < versionSplit.Length; i++)
{
if (!int.TryParse(versionSplit[i], out m_VersionValueDict[version][i]))
{
Debug.LogError($"{version} {i} {versionSplit[i]} 不是数字");
}
}
return m_VersionValueDict[version];
}
private bool CheckVersion(DependencyInfo dependencyInfo, PackageVersionData targetData)
{
var dependencyVersion = dependencyInfo.Version;
var versionValue = GetVersionValue(dependencyVersion);
var targetVersionValue = targetData?.VersionValue;
if (targetVersionValue == null)
{
Debug.Log($"{targetData.Name} Version == null");
return false;
}
//长度判断
if (targetVersionValue.Length != versionValue.Length)
{
Debug.Log($"{targetData.Name} Version长度不一致,实际:{targetData.Version} 与 依赖:{dependencyVersion}不匹配");
return false;
}
//大版本号判断
if (targetVersionValue.Length >= 1 && targetVersionValue[0] != versionValue[0])
{
Debug.Log($"{targetData.Name} 大版本号不匹配,实际:{targetData.Version} 与 依赖:{dependencyVersion}不匹配");
return false;
}
//中版本号判断
if (targetVersionValue.Length >= 2 && targetVersionValue[1] != versionValue[1])
{
Debug.Log($"{targetData.Name} 中版本号不匹配,实际:{targetData.Version} 与 依赖:{dependencyVersion}不匹配");
return false;
}
//小版本号判断
if (targetVersionValue.Length >= 3 && targetVersionValue[2] < versionValue[2])
{
Debug.Log($"{targetData.Name} 小版本号不匹配,实际:{targetData.Version} 与 依赖:{dependencyVersion}不匹配");
return false;
}
return true;
}
}
}
#endif