Initial Commit
This commit is contained in:
405
PackageProcessor/Editor/ExportPostProcessor.cs
Normal file
405
PackageProcessor/Editor/ExportPostProcessor.cs
Normal file
@@ -0,0 +1,405 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using HarmonyLib;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace DreadScripts.PackageProcessor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public class ExportPostProcessor
|
||||
{
|
||||
#region Patching
|
||||
private static readonly System.Type packageExportType;
|
||||
private static readonly System.Type packageTreeGUIType;
|
||||
private static readonly FieldInfo includeDependenciesField;
|
||||
private static readonly FieldInfo exportItemsField;
|
||||
private static readonly MethodInfo refreshListMethod;
|
||||
private static readonly MethodInfo getTreeItemMethod;
|
||||
#endregion
|
||||
|
||||
#region Constants
|
||||
|
||||
private const string PARAM_FOLDERS = "exportDefaultOffFolders";
|
||||
private const string PARAM_EXTENSIONS = "exportDefaultOffExtensions";
|
||||
private const string PARAM_TYPES = "exportDefaultOffTypes";
|
||||
private const string PARAM_ASSETS = "exportDefaultOffAssets";
|
||||
#endregion
|
||||
|
||||
private static PackageProcessorData settings;
|
||||
private static EditorWindow exporterInstance;
|
||||
|
||||
private static object rawItems;
|
||||
private static ReflectedExportPackageItem[] reflectedItems;
|
||||
private static bool firstStart = true;
|
||||
|
||||
static ExportPostProcessor()
|
||||
{
|
||||
packageExportType = GetType("UnityEditor.PackageExport");
|
||||
packageTreeGUIType = GetType("UnityEditor.PackageExportTreeView+PackageExportTreeViewGUI");
|
||||
|
||||
includeDependenciesField = packageExportType.GetField("m_IncludeDependencies", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
exportItemsField = packageExportType.GetField("m_ExportPackageItems", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
|
||||
refreshListMethod = GetType("UnityEditor.PackageExportTreeView").GetMethod("ComputeEnabledStateForFolders", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
getTreeItemMethod = GetType("UnityEditor.PackageExportTreeView+PackageExportTreeViewItem").GetMethod("get_item", BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
var harmony = new Harmony("com.dreadscripts.exportpostprocessor.tool");
|
||||
|
||||
void QuickPatch(System.Type targetType, string ogMethod, string preMethod = "", string poMethod = "")
|
||||
{
|
||||
MethodInfo originalMethod = AccessTools.GetDeclaredMethods(targetType).Find(m => m.Name == ogMethod);
|
||||
HarmonyMethod prefixMethod = string.IsNullOrEmpty(preMethod) ? null : new HarmonyMethod(typeof(ExportPostProcessor).GetMethod(preMethod, BindingFlags.NonPublic | BindingFlags.Static));
|
||||
HarmonyMethod postMethod = string.IsNullOrEmpty(poMethod) ? null : new HarmonyMethod(typeof(ExportPostProcessor).GetMethod(poMethod, BindingFlags.NonPublic | BindingFlags.Static));
|
||||
harmony.Patch(originalMethod, prefixMethod, postMethod);
|
||||
}
|
||||
|
||||
QuickPatch(packageExportType, "ShowExportPackage", null, nameof(ShowExportPost));
|
||||
QuickPatch(packageExportType, "BuildAssetList", null, nameof(BuildAssetListPost));
|
||||
QuickPatch(packageExportType, "OnGUI", null, nameof(packageGUIPost));
|
||||
QuickPatch(packageTreeGUIType, "OnRowGUI", nameof(treeRowGUIPrefix));
|
||||
}
|
||||
|
||||
static void ShowExportPost()
|
||||
{
|
||||
settings = PackageProcessorData.instance;
|
||||
exporterInstance = EditorWindow.GetWindow(packageExportType);
|
||||
firstStart = true;
|
||||
if (settings.active)
|
||||
includeDependenciesField.SetValue(exporterInstance, settings.includeDependencies);
|
||||
|
||||
}
|
||||
|
||||
static void BuildAssetListPost()
|
||||
{
|
||||
GetExportItems();
|
||||
if (!firstStart || !settings.active) return;
|
||||
firstStart = false;
|
||||
|
||||
List<System.Type> offTypes = new List<System.Type>();
|
||||
settings.exportDefaultOffTypes.ForEach(t =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(t)) return;
|
||||
System.Type targetType = GetType(t);
|
||||
if (targetType != null)
|
||||
offTypes.Add(targetType);
|
||||
});
|
||||
foreach (var i in reflectedItems)
|
||||
{
|
||||
if (offTypes.Any(t => t == i.type) ||
|
||||
settings.exportDefaultOffFolders.Any(f => i.assetPath.Contains(f)) ||
|
||||
settings.exportDefaultOffExtensions.Any(s => s == Path.GetExtension(i.assetPath)) ||
|
||||
(!i.isFolder && settings.exportDefaultOffAssets.Any(g => g == i.guid)))
|
||||
|
||||
i.enabledState = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void packageGUIPost()
|
||||
{
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
|
||||
if (GUILayout.Button("Modified by Dreadrith#3238", "minilabel"))
|
||||
Application.OpenURL("https://github.com/Dreadrith/DreadScripts");
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
}
|
||||
|
||||
static ReflectedExportPackageItem reflectedTargetItem;
|
||||
static void treeRowGUIPrefix(Rect rowRect,UnityEditor.IMGUI.Controls.TreeViewItem tvItem)
|
||||
{
|
||||
if (Event.current.type == EventType.ContextClick && rowRect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
object targetItem = getTreeItemMethod.Invoke(tvItem, null);
|
||||
if (targetItem != null)
|
||||
{
|
||||
reflectedTargetItem = new ReflectedExportPackageItem(targetItem);
|
||||
if (!reflectedTargetItem.isFolder)
|
||||
{
|
||||
GenericMenu myMenu = new GenericMenu();
|
||||
myMenu.AddItem(new GUIContent("Toggle Type"), false, new GenericMenu.MenuFunction(ToggleSelectedType));
|
||||
myMenu.AddSeparator("");
|
||||
|
||||
if (!HasSelectedAsset())
|
||||
myMenu.AddItem(new GUIContent("Exclusions/Add Asset"), false, new GenericMenu.MenuFunction(ExcludeSelectedAsset));
|
||||
else
|
||||
myMenu.AddItem(new GUIContent("Exclusions/Remove Asset"), false, new GenericMenu.MenuFunction(IncludeSelectedAsset));
|
||||
|
||||
if (!HasSelectedType())
|
||||
myMenu.AddItem(new GUIContent("Exclusions/Add Type"), false, new GenericMenu.MenuFunction(ExcludeSelectedType));
|
||||
else
|
||||
myMenu.AddItem(new GUIContent("Exclusions/Remove Type"), false, new GenericMenu.MenuFunction(IncludeSelectedType));
|
||||
|
||||
if (!HasSelectedExtension())
|
||||
myMenu.AddItem(new GUIContent("Exclusions/Add Extension"), false, new GenericMenu.MenuFunction(ExcludeSelectedExtension));
|
||||
else
|
||||
myMenu.AddItem(new GUIContent("Exclusions/Remove Extension"), false, new GenericMenu.MenuFunction(IncludeSelectedExtension));
|
||||
|
||||
myMenu.ShowAsContext();
|
||||
Event.current.Use();
|
||||
}
|
||||
else
|
||||
{
|
||||
GenericMenu myMenu = new GenericMenu();
|
||||
if (!HasSelectedFolder())
|
||||
myMenu.AddItem(new GUIContent("Exclusions/Add Folder"), false, new GenericMenu.MenuFunction(ExcludeSelectedFolder));
|
||||
else
|
||||
myMenu.AddItem(new GUIContent("Exclusions/Remove Folder"), false, new GenericMenu.MenuFunction(IncludeSelectedFolder));
|
||||
myMenu.ShowAsContext();
|
||||
Event.current.Use();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GenericMenu myMenu = new GenericMenu();
|
||||
myMenu.AddDisabledItem(new GUIContent("Folder not being exported"));
|
||||
myMenu.ShowAsContext();
|
||||
Event.current.Use();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ToggleSelectedType()
|
||||
{
|
||||
List<ReflectedExportPackageItem> targetItems = new List<ReflectedExportPackageItem>();
|
||||
bool allOn = true;
|
||||
Iterate(reflectedItems, i =>
|
||||
{
|
||||
if (i.type == reflectedTargetItem.type)
|
||||
{
|
||||
targetItems.Add(i);
|
||||
if (i.enabledState == 0)
|
||||
{
|
||||
allOn = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
targetItems.ForEach(i => i.enabledState = allOn ? 0 : 1);
|
||||
RefreshTreeView();
|
||||
}
|
||||
|
||||
static bool HasExclusion(string property, string value)
|
||||
{
|
||||
SerializedObject data = new SerializedObject(PackageProcessorData.instance);
|
||||
SerializedProperty targetProperty = data.FindProperty(property);
|
||||
for (int i = 0; i < targetProperty.arraySize; i++)
|
||||
{
|
||||
if (targetProperty.GetArrayElementAtIndex(i).stringValue == value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void AddExclusion(string property, string value)
|
||||
{
|
||||
SerializedObject data = new SerializedObject(PackageProcessorData.instance);
|
||||
SerializedProperty targetProperty = data.FindProperty(property);
|
||||
targetProperty.arraySize++;
|
||||
targetProperty.GetArrayElementAtIndex(targetProperty.arraySize - 1).stringValue = value;
|
||||
data.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
static void RemoveExclusion(string property, string value)
|
||||
{
|
||||
SerializedObject data = new SerializedObject(PackageProcessorData.instance);
|
||||
SerializedProperty targetProperty = data.FindProperty(property);
|
||||
for (int i = 0; i < targetProperty.arraySize; i++)
|
||||
{
|
||||
if (targetProperty.GetArrayElementAtIndex(i).stringValue == value)
|
||||
{
|
||||
targetProperty.DeleteArrayElementAtIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
data.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
#region Extension Exclusion
|
||||
static bool HasSelectedExtension() => HasExclusion(PARAM_EXTENSIONS, Ext(reflectedTargetItem.assetPath));
|
||||
static void ExcludeSelectedExtension() => AddExclusion(PARAM_EXTENSIONS, Ext(reflectedTargetItem.assetPath));
|
||||
static void IncludeSelectedExtension() => RemoveExclusion(PARAM_EXTENSIONS, Ext(reflectedTargetItem.assetPath));
|
||||
#endregion
|
||||
|
||||
#region Folder Exclusion
|
||||
static bool HasSelectedFolder() => HasExclusion(PARAM_FOLDERS, reflectedTargetItem.assetPath);
|
||||
static void ExcludeSelectedFolder() => AddExclusion(PARAM_FOLDERS, reflectedTargetItem.assetPath);
|
||||
static void IncludeSelectedFolder() => RemoveExclusion(PARAM_FOLDERS, reflectedTargetItem.assetPath);
|
||||
#endregion
|
||||
|
||||
#region Type Exclusion
|
||||
static bool HasSelectedType() => PackageProcessorData.instance.exportDefaultOffTypes.Any(t => GetType(t) == reflectedTargetItem.type);
|
||||
static void ExcludeSelectedType() => AddExclusion(PARAM_TYPES, reflectedTargetItem.type.AssemblyQualifiedName);
|
||||
static void IncludeSelectedType()
|
||||
{
|
||||
SerializedObject data = new SerializedObject(PackageProcessorData.instance);
|
||||
SerializedProperty targetProperty = data.FindProperty(PARAM_TYPES);
|
||||
for (int i = 0; i < targetProperty.arraySize; i++)
|
||||
{
|
||||
Type currentType = GetType(targetProperty.GetArrayElementAtIndex(i).stringValue);
|
||||
if (currentType == reflectedTargetItem.type)
|
||||
{
|
||||
targetProperty.DeleteArrayElementAtIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
data.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Asset Exclusion
|
||||
static bool HasSelectedAsset() => HasExclusion(PARAM_ASSETS, reflectedTargetItem.guid);
|
||||
static void ExcludeSelectedAsset() => AddExclusion(PARAM_ASSETS, reflectedTargetItem.guid);
|
||||
static void IncludeSelectedAsset() => RemoveExclusion(PARAM_ASSETS, reflectedTargetItem.guid);
|
||||
#endregion
|
||||
|
||||
private static string Ext(string path) => Path.GetExtension(path);
|
||||
|
||||
private static void GetExportItems()
|
||||
{
|
||||
rawItems = exportItemsField.GetValue(exporterInstance);
|
||||
object[] exportItems = (object[])rawItems;
|
||||
exportItemsField.SetValue(exporterInstance, exportItems);
|
||||
|
||||
reflectedItems = new ReflectedExportPackageItem[exportItems.Length];
|
||||
for (int i = 0; i < exportItems.Length; i++)
|
||||
reflectedItems[i] = new ReflectedExportPackageItem(exportItems[i]);
|
||||
|
||||
}
|
||||
|
||||
private static void RefreshTreeView()
|
||||
{
|
||||
refreshListMethod.Invoke(packageExportType.GetField("m_Tree", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(exporterInstance), null);
|
||||
}
|
||||
|
||||
private class ReflectedExportPackageItem
|
||||
{
|
||||
private readonly object instance;
|
||||
|
||||
public bool isFolder => AssetDatabase.IsValidFolder(assetPath);
|
||||
|
||||
private string _assetPath;
|
||||
public string assetPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_assetPath))
|
||||
_assetPath = (string)assetPathField.GetValue(instance);
|
||||
return _assetPath;
|
||||
}
|
||||
}
|
||||
|
||||
private bool stateInit;
|
||||
private int _enabledState;
|
||||
public int enabledState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!stateInit)
|
||||
return 1;
|
||||
if (_enabledState == -2)
|
||||
_enabledState = (int)enabledStateField.GetValue(instance);
|
||||
return _enabledState;
|
||||
}
|
||||
set
|
||||
{
|
||||
stateInit = true;
|
||||
_enabledState = value;
|
||||
enabledStateField.SetValue(instance, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _guid;
|
||||
public string guid
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_guid))
|
||||
_guid = (string)guidField.GetValue(instance);
|
||||
return _guid;
|
||||
}
|
||||
}
|
||||
|
||||
private System.Type _type;
|
||||
public System.Type type
|
||||
{
|
||||
get
|
||||
{
|
||||
if (asset && _type == null)
|
||||
_type = asset.GetType();
|
||||
return _type;
|
||||
}
|
||||
}
|
||||
|
||||
private Object _asset;
|
||||
private bool _assetLoaded;
|
||||
|
||||
private Object asset
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_asset || _assetLoaded) return _asset;
|
||||
|
||||
_asset = AssetDatabase.LoadMainAssetAtPath(assetPath);
|
||||
_assetLoaded = true;
|
||||
return _asset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static FieldInfo assetPathField;
|
||||
static FieldInfo enabledStateField;
|
||||
static FieldInfo guidField;
|
||||
public ReflectedExportPackageItem(object instance)
|
||||
{
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
static void InitializeFields()
|
||||
{
|
||||
System.Type targetType = AccessTools.TypeByName("ExportPackageItem");
|
||||
assetPathField = targetType.GetField("assetPath", BindingFlags.Public | BindingFlags.Instance);
|
||||
enabledStateField = targetType.GetField("enabledStatus", BindingFlags.Public | BindingFlags.Instance);
|
||||
guidField = targetType.GetField("guid", BindingFlags.Public | BindingFlags.Instance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static System.Type GetType(string typeName)
|
||||
{
|
||||
System.Type myType = System.Type.GetType(typeName);
|
||||
if (myType != null)
|
||||
return myType;
|
||||
foreach (Assembly assembly in System.AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
myType = assembly.GetType(typeName);
|
||||
if (myType != null)
|
||||
return myType;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Iterate<T>(IEnumerable<T> collection, System.Action<T> action)
|
||||
{
|
||||
using (IEnumerator<T> myNum = collection.GetEnumerator())
|
||||
{
|
||||
while (myNum.MoveNext())
|
||||
{
|
||||
action(myNum.Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user