Files
Cielonos/Packages/io.continis.subassets/Editor/DragAndDropAddon.cs
SoulliesOfficial f26f9fd374 爆更
2026-03-20 12:07:44 -04:00

241 lines
11 KiB
C#

using System.IO;
using System.Linq;
using SubAssetsToolbox.Utilities;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace SubAssetsToolbox.Editor
{
internal static class DragAndDropAddon
{
#if UNITY_6000_3_OR_NEWER
[InitializeOnLoadMethod]
public static void AddDragProjectHandler()
{
DragAndDrop.AddDropHandlerV2(ProjectWindowHandler);
}
private static DragAndDropVisualMode ProjectWindowHandler(EntityId id, string destinationPath, bool released)
{
#else
[InitializeOnLoadMethod]
public static void AddDragProjectHandler() => DragAndDrop.AddDropHandler(ProjectWindowHandler);
private static DragAndDropVisualMode ProjectWindowHandler(int id, string destinationPath, bool released)
{
#endif
if (DragAndDrop.paths.Length == 0 || DragAndDrop.objectReferences.Length == 0)
// Was not dragging from another window
return DragAndDropVisualMode.None;
bool destinationIsFolder = AssetDatabase.IsValidFolder(destinationPath);
if (released)
{
bool isDraggingSubAssets = DragAndDrop.objectReferences.Any(AssetDatabase.IsSubAsset);
foreach (string path in DragAndDrop.paths)
{
if (string.Equals(path, destinationPath)) return DragAndDropVisualMode.None;
if (destinationIsFolder) continue;
if (isDraggingSubAssets) continue;
if (!TypeChecker.ValidateSubAssetType(path)) return DragAndDropVisualMode.Rejected;
if (!TypeChecker.ValidateDestinationType(destinationPath)) return DragAndDropVisualMode.Rejected;
}
if (!destinationIsFolder)
{
// Adding sub-asset(s)
// (drag destination is an asset)
string objectName = Path.GetFileNameWithoutExtension(destinationPath);
bool isOne = DragAndDrop.objectReferences.Length == 1;
int choice = EditorUtility.DisplayDialogComplex(
isOne ? "Add as Sub-Asset" : "Add as Sub-Assets",
isOne
? string.Format(Constants.ConfirmAddAsSubAsset, DragAndDrop.objectReferences[0].name,
objectName)
: string.Format(Constants.ConfirmAddAsSubAssets, DragAndDrop.objectReferences[0].name,
DragAndDrop.objectReferences[1].name, objectName),
isOne ? "Add" : "Add all",
"Cancel",
isOne ? "Add and Keep Original" : "Add and Keep Originals");
int redirectRefChoice = -1;
if (choice == 0)
{
ReferencePatchingMode mode = SubAssetsToolboxSettings.PatchReferences.value;
if (mode == ReferencePatchingMode.AutoApply)
redirectRefChoice = 0;
else if (mode == ReferencePatchingMode.AskEachTime)
redirectRefChoice = EditorUtility.DisplayDialogComplex("Patch references",
Constants.PatchRefsToSubAssetPrompt,
"Patch References", "Don't Patch", "Cancel Moving Assets");
}
// Cancelled the operation
if (choice == 1 || redirectRefChoice == 2) return DragAndDropVisualMode.Rejected;
foreach (Object draggedObject in DragAndDrop.objectReferences)
{
string draggedObjectPath = AssetDatabase.GetAssetPath(draggedObject);
string draggedObjectName = draggedObject.name;
bool wasMainAsset = AssetDatabase.IsMainAsset(draggedObject);
// TODO: preserve selection if the object selected was the one being destroyed
SubAssetsToolbox.AddSubAsset(destinationPath, draggedObject, out Object newSubasset);
if (choice == 2) continue; // Keep previous objects
if (redirectRefChoice == 0)
{
AssetDatabase.SaveAssets();
if (!AssetReferenceRedirector.RedirectToSubAsset(draggedObject, newSubasset))
{
Debug.LogWarning(string.Format(Constants.RedirectionFailed, draggedObjectName));
continue;
}
}
// Do not keep previous
if (wasMainAsset)
{
#if ADDRESSABLES_INSTALLED
AddressableEntryMigrator.MigrateOrRemoveEntry(
AssetDatabase.AssetPathToGUID(draggedObjectPath),
AssetDatabase.AssetPathToGUID(destinationPath),
objectName);
#endif
AssetDatabase.DeleteAsset(draggedObjectPath);
}
else
{
// After redirect, Refresh() may have invalidated the original reference.
// Reload the sub-asset from disk if needed.
Object objectToRemove = draggedObject;
if (objectToRemove == null)
{
Object[] subAssets = AssetDatabase.LoadAllAssetRepresentationsAtPath(draggedObjectPath);
objectToRemove = subAssets.FirstOrDefault(a => a.name == draggedObjectName);
}
if (objectToRemove != null)
SubAssetsToolbox.RemoveSubAsset(draggedObjectPath, objectToRemove);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
return DragAndDropVisualMode.Link;
}
// Removing sub-asset(s)
// (drag destination is a folder or an empty space)
if (!DragAndDrop.objectReferences.Any(AssetDatabase.IsSubAsset))
return Path.GetDirectoryName(DragAndDrop.paths[0]) == destinationPath
? DragAndDropVisualMode.Move
: DragAndDropVisualMode.None;
ReferencePatchingMode redirectMode = SubAssetsToolboxSettings.PatchReferences.value;
int redirectRefsChoice;
if (redirectMode == ReferencePatchingMode.AutoApply)
redirectRefsChoice = 0;
else if (redirectMode == ReferencePatchingMode.AskEachTime)
redirectRefsChoice = EditorUtility.DisplayDialogComplex("Patch references",
Constants.PatchRefsToStandalonePrompt,
"Patch References", "Don't Patch", "Cancel Sub-Asset Removal");
else
redirectRefsChoice = 1;
if (redirectRefsChoice == 2) return DragAndDropVisualMode.Rejected;
int rejected = 0;
foreach (Object draggedObject in DragAndDrop.objectReferences)
{
string draggedObjectPath = AssetDatabase.GetAssetPath(draggedObject);
if (AssetDatabase.IsSubAsset(draggedObject))
{
// Was dragging a sub-asset: un-parent
// Check if its parent is in selection too
Object mainAssetAtPath = AssetDatabase.LoadMainAssetAtPath(draggedObjectPath);
string fileExtension = ExtensionMap.GetFileExtensionByType(draggedObject.GetType());
if (DragAndDrop.objectReferences.Contains(mainAssetAtPath)) continue;
// Verify if there's an object with the same name
string desiredName = Path.Combine(destinationPath, $"{draggedObject.name}.{fileExtension}");
if (AssetDatabase.LoadAssetAtPath<Object>(desiredName) != null)
{
Debug.LogWarning(string.Format(Constants.ImpossibleToExtract, draggedObject.name));
rejected++;
continue;
}
string draggedObjectName = draggedObject.name;
Object newObject = Object.Instantiate(draggedObject);
newObject.name = draggedObjectName;
AssetDatabase.CreateAsset(newObject, desiredName);
if (redirectRefsChoice == 0)
{
AssetDatabase.SaveAssets();
if (!AssetReferenceRedirector.RedirectToStandaloneAsset(draggedObject, newObject))
{
Debug.LogWarning(string.Format(Constants.RedirectionFailed, draggedObjectName));
continue;
}
}
// After redirect, Refresh() may have invalidated the original reference.
// Reload the sub-asset from disk if needed.
Object objectToRemove = draggedObject;
if (objectToRemove == null)
{
Object[] subAssets = AssetDatabase.LoadAllAssetRepresentationsAtPath(draggedObjectPath);
objectToRemove = subAssets.FirstOrDefault(a => a.name == draggedObjectName);
}
if (objectToRemove != null)
SubAssetsToolbox.RemoveSubAsset(draggedObjectPath, objectToRemove);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
if (rejected != 0) return DragAndDropVisualMode.Rejected;
if (Path.GetDirectoryName(DragAndDrop.paths[0]) != destinationPath)
return DragAndDropVisualMode.None; // Allows relocation of main assets
return DragAndDropVisualMode.Move; // Avoid confirmation popup when drag/dropping in the same folder
}
// While dragging
if (destinationIsFolder)
return DragAndDropVisualMode.Generic;
if (DragAndDrop.objectReferences.Any(AssetDatabase.IsSubAsset))
return DragAndDropVisualMode.Link;
foreach (string path in DragAndDrop.paths)
{
if (string.Equals(path, destinationPath)) return DragAndDropVisualMode.None;
if (!TypeChecker.ValidateSubAssetType(path, true)) return DragAndDropVisualMode.Rejected;
if (!TypeChecker.ValidateDestinationType(destinationPath, true)) return DragAndDropVisualMode.Rejected;
}
return DragAndDropVisualMode.Link;
}
}
}