1978 lines
77 KiB
C#
1978 lines
77 KiB
C#
#if UNITY_EDITOR
|
|
using MonKey.Commands;
|
|
using MonKey.Editor.Internal;
|
|
using MonKey.Extensions;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditor;
|
|
|
|
#if UNITY_2022_1_OR_NEWER
|
|
using UnityEditor.SceneManagement;
|
|
#else
|
|
|
|
#endif
|
|
|
|
using UnityEditorInternal;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.SceneManagement;
|
|
using GameObject = UnityEngine.GameObject;
|
|
using Object = UnityEngine.Object;
|
|
using Random = UnityEngine.Random;
|
|
|
|
namespace MonKey.Editor.Commands
|
|
{
|
|
public static class CreationUtilities
|
|
{
|
|
[Command("New Siblings",
|
|
Help = "Creates new siblings for the selected game objects",
|
|
QuickName = "NS", DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
Category = "GameObject")]
|
|
public static void CreateNewSibling(
|
|
[CommandParameter(Help = "The amount of siblings to create")]
|
|
int siblingAmount = 1)
|
|
{
|
|
if (!Selection.activeTransform)
|
|
return;
|
|
|
|
Undo.IncrementCurrentGroup();
|
|
Undo.SetCurrentGroupName("Create Siblings");
|
|
int group = Undo.GetCurrentGroup();
|
|
|
|
foreach (var gameObject in Selection.gameObjects)
|
|
{
|
|
for (int i = 0; i < siblingAmount; i++)
|
|
{
|
|
GameObject go = new GameObject(gameObject.name);
|
|
go.transform.SetParent(gameObject.transform.parent);
|
|
Undo.RegisterCreatedObjectUndo(go, "sibling created");
|
|
go.transform.position = gameObject.transform.position;
|
|
}
|
|
}
|
|
|
|
Undo.CollapseUndoOperations(group);
|
|
}
|
|
|
|
[Command("New Children",
|
|
Help = "Creates new children for the selected game objects",
|
|
QuickName = "NC", DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
Category = "GameObject")]
|
|
public static void CreateNewChildren(
|
|
[CommandParameter(Help = "The amount of children to create")]
|
|
int amount = 1)
|
|
{
|
|
if (!Selection.activeTransform)
|
|
return;
|
|
|
|
Undo.IncrementCurrentGroup();
|
|
Undo.SetCurrentGroupName("Create Children");
|
|
int group = Undo.GetCurrentGroup();
|
|
|
|
List<Object> childrenCreated = new List<Object>();
|
|
foreach (var gameObject in Selection.gameObjects)
|
|
{
|
|
for (int i = 0; i < amount; i++)
|
|
{
|
|
GameObject go = new GameObject(gameObject.name);
|
|
go.transform.SetParent(gameObject.transform);
|
|
Undo.RegisterCreatedObjectUndo(go, "Children created");
|
|
go.transform.position = gameObject.transform.position;
|
|
childrenCreated.Add(go);
|
|
}
|
|
}
|
|
|
|
Selection.objects = childrenCreated.ToArray();
|
|
|
|
Undo.CollapseUndoOperations(group);
|
|
}
|
|
|
|
|
|
[Command("New Parent", Help = "Creates a parent object for the selection",
|
|
AlwaysShow = true, QuickName = "NP", Order = -6,
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
MenuItemLink = "CreateParentForSelection",
|
|
Category = "GameObject")]
|
|
public static void ParentSelection(
|
|
[CommandParameter("The name of the new parent object")]
|
|
string parentName = "New Parent", bool centerParent = false)
|
|
{
|
|
if (Selection.gameObjects.Length == 0)
|
|
return;
|
|
|
|
int group = MonkeyEditorUtils.CreateUndoGroup("Create Parent");
|
|
|
|
Vector3 center = Vector3.zero;
|
|
int i = 0;
|
|
|
|
GameObject[] selected =
|
|
Selection.gameObjects.Where(_ => _.scene.IsValid() && _.hideFlags == HideFlags.None)
|
|
.ToArray();
|
|
|
|
foreach (GameObject o in selected)
|
|
{
|
|
Undo.RecordObject(o.transform, "Recording transform");
|
|
center += o.transform.position;
|
|
i++;
|
|
}
|
|
|
|
center /= i;
|
|
|
|
GameObject parentObject = new GameObject(parentName);
|
|
SceneManager.MoveGameObjectToScene(parentObject, Selection.gameObjects[0].scene);
|
|
Undo.RegisterCreatedObjectUndo(parentObject, "Parent Object Creation");
|
|
|
|
foreach (GameObject obj in selected)
|
|
{
|
|
if (obj.GetComponent<RectTransform>())
|
|
{
|
|
parentObject.AddComponent<RectTransform>();
|
|
break;
|
|
}
|
|
}
|
|
|
|
Transform common = ParentingUtilities.FindEarliestCommonParent(selected);
|
|
Transform commonParent = common != null &&
|
|
selected.Contains(common.gameObject)
|
|
? common.parent
|
|
: common;
|
|
int siblingIndex = 0;
|
|
|
|
if (common == null)
|
|
{
|
|
GameObject first = Selection.gameObjects[0];
|
|
if (!MonkeyEditorUtils.OrderedSelectedGameObjects.Any())
|
|
first = MonkeyEditorUtils.OrderedSelectedGameObjects.First();
|
|
|
|
int j = 0;
|
|
foreach (GameObject o in first.scene.GetRootGameObjects())
|
|
{
|
|
if (selected.Contains(o))
|
|
{
|
|
siblingIndex = j;
|
|
break;
|
|
}
|
|
|
|
j++;
|
|
}
|
|
}
|
|
else if (selected.Contains(common.gameObject))
|
|
siblingIndex = common.GetSiblingIndex();
|
|
|
|
if (centerParent)
|
|
parentObject.transform.SetParent(commonParent);
|
|
else
|
|
parentObject.transform.SetParent(commonParent, false);
|
|
parentObject.transform.SetSiblingIndex(siblingIndex);
|
|
|
|
if (centerParent)
|
|
parentObject.transform.position = center;
|
|
|
|
List<int> siblingIndexes = new List<int>();
|
|
|
|
foreach (GameObject obj in selected)
|
|
{
|
|
siblingIndexes.Add(obj.transform.GetSiblingIndex());
|
|
Undo.SetTransformParent(obj.transform, parentObject.transform, "Re - Parenting");
|
|
}
|
|
|
|
for (var index = 0; index < selected.Length; index++)
|
|
{
|
|
GameObject obj = selected[index];
|
|
obj.transform.SetSiblingIndex(siblingIndexes[index]);
|
|
}
|
|
|
|
Selection.objects = new Object[] { parentObject };
|
|
|
|
Selection.activeObject = parentObject;
|
|
|
|
parentObject.transform.SetSiblingIndex(siblingIndexes.OrderBy(_ => _).First());
|
|
|
|
Undo.CollapseUndoOperations(group);
|
|
}
|
|
|
|
[Command("New Parent For Each", "Creates a new parent for each of the selected objects",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_TRANSFORM, QuickName = "NPE",
|
|
MenuItemLink = "NewParentForEach", MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject")]
|
|
public static void CreateParentForEach()
|
|
{
|
|
int undoId = MonkeyEditorUtils.CreateUndoGroup("Parent For Each");
|
|
List<GameObject> createdParents = new List<GameObject>();
|
|
foreach (var gameObject in Selection.gameObjects.Where(_ => _.scene.IsValid()))
|
|
{
|
|
GameObject go = new GameObject(gameObject.name + " Parent");
|
|
createdParents.Add(go);
|
|
go.transform.SetParent(gameObject.transform.parent);
|
|
go.transform.Reset();
|
|
|
|
Undo.RegisterCreatedObjectUndo(go, "created new parent");
|
|
Undo.SetTransformParent(gameObject.transform, go.transform, "ReParenting");
|
|
go.transform.CopyLocal(gameObject.transform);
|
|
Undo.RecordObject(gameObject.transform, "Resetting transform");
|
|
gameObject.transform.Reset();
|
|
}
|
|
|
|
Selection.objects = createdParents.Convert(_ => (Object)_).ToArray();
|
|
Undo.CollapseUndoOperations(undoId);
|
|
}
|
|
|
|
[Command("New Instances",
|
|
"Instantiates the specified prefabs under the selected objects " +
|
|
"(by default one of each prefab selected)", QuickName = "NI", MenuItemLink = "NewInstance",
|
|
MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject")]
|
|
public static void InstantiateAsChildren(
|
|
[CommandParameter(ForceAutoCompleteUsage = true, PreventDefaultValueUsage = true,
|
|
DefaultValueNameOverride = "No Prefab Selected",
|
|
Help = "the prefabs you want to instantiate",
|
|
AutoCompleteMethodName = "PrefabAssets")]
|
|
string[] prefabs,
|
|
[CommandParameter(Help = "The amount of instances of each prefabs to create")]
|
|
int amount = 1)
|
|
{
|
|
GameObject[] parents = Selection.gameObjects.Where(_ => _.scene.IsValid()).ToArray();
|
|
|
|
int undoId = MonkeyEditorUtils.CreateUndoGroup("Instantiate Prefabs");
|
|
|
|
if (parents.Length == 0)
|
|
{
|
|
#if UNITY_2019_1_OR_NEWER
|
|
var stage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
|
|
if (stage != null)
|
|
{
|
|
parents = new[] { stage.prefabContentsRoot };
|
|
}
|
|
else
|
|
{
|
|
parents = new GameObject[] { null };
|
|
}
|
|
#else
|
|
parents = new GameObject[] { null };
|
|
#endif
|
|
}
|
|
|
|
if (prefabs == null || prefabs.Length == 0)
|
|
{
|
|
Debug.LogWarning("Monkey Warning: the prefab could not be " +
|
|
"instantiated because none were selected or could be recognized");
|
|
return;
|
|
}
|
|
|
|
List<Object> createdObjects = new List<Object>();
|
|
int j = 0;
|
|
int k = 0;
|
|
Object[] selected = prefabs.Convert(_ => AssetDatabase.LoadAssetAtPath<Object>(_)).ToArray();
|
|
foreach (Object o in selected)
|
|
{
|
|
foreach (var parent in parents)
|
|
{
|
|
if (o != parent && PrefabUtility.GetPrefabAssetType(o) != PrefabAssetType.NotAPrefab ||
|
|
PrefabUtility.GetPrefabInstanceStatus(o) != PrefabInstanceStatus.NotAPrefab)
|
|
{
|
|
for (int i = 0; i < amount; i++)
|
|
{
|
|
if (EditorUtility.DisplayCancelableProgressBar("Instantiating Prefabs",
|
|
"Instantiating " + o.name,
|
|
((float)i + i * j + i * j * k)
|
|
/ (amount * parents.Length * selected.Count())))
|
|
break;
|
|
|
|
Object newObject = PrefabUtility.InstantiatePrefab(o,
|
|
(!parent) ? SceneManager.GetActiveScene() : parent.scene);
|
|
Undo.RegisterCreatedObjectUndo(newObject, "prefab creation");
|
|
createdObjects.Add(newObject);
|
|
if (parent)
|
|
{
|
|
GameObject obj = newObject as GameObject;
|
|
if (obj != null)
|
|
{
|
|
Undo.SetTransformParent(obj.transform,
|
|
parent.transform, "re-parenting");
|
|
obj.transform.Reset();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
k++;
|
|
}
|
|
|
|
j++;
|
|
}
|
|
|
|
EditorUtility.ClearProgressBar();
|
|
Selection.objects = createdObjects.ToArray();
|
|
Undo.CollapseUndoOperations(undoId);
|
|
}
|
|
|
|
public static AssetNameAutoComplete PrefabAssets()
|
|
{
|
|
return new AssetNameAutoComplete() { IncludeDirectories = false, CustomType = "GameObject" };
|
|
}
|
|
|
|
[Command("New Scriptable Object",
|
|
"Creates a new ScriptableObject of the type specified in the first folder selected",
|
|
AlwaysShow = true, QuickName = "NSO", MenuItemLink = "NewScriptableObject", Order = -5,
|
|
MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "Assets")]
|
|
public static void CreateNewScriptableObject(
|
|
[CommandParameter(Help = "The type of the ScriptableObject to create",
|
|
ForceAutoCompleteUsage = true, PreventDefaultValueUsage = true,
|
|
AutoCompleteMethodName = "ScriptableObjectAutoComplete")]
|
|
Type type)
|
|
{
|
|
ScriptableObject obj = ScriptableObject.CreateInstance(type);
|
|
|
|
NameAndCreateNewAsset(obj, "New" + type.Name, type.Name);
|
|
}
|
|
|
|
|
|
[Command("Attach New Material",
|
|
"Creates and attaches a new material in the selected folder to the selected objects",
|
|
ValidationMethodName = "ObjectsWithRenderer", QuickName = "AM",
|
|
Category = "Assets")]
|
|
public static void CreateAndAttachMaterial(
|
|
[CommandParameter(Help = "the name of the shader to use for the new material",
|
|
AutoCompleteMethodName = "ShaderAutoComplete", ForceAutoCompleteUsage = true,
|
|
DefaultValueNameOverride = "Standard Shader")]
|
|
string shaderName = "")
|
|
{
|
|
int undoGroup = MonkeyEditorUtils.CreateUndoGroup("New Material");
|
|
|
|
Shader shader = (shaderName.IsNullOrEmpty())
|
|
? Shader.Find("Standard")
|
|
: AssetDatabase.LoadAssetAtPath<Shader>(shaderName);
|
|
Material mat = new Material(shader);
|
|
|
|
Object obj = (Object)mat;
|
|
|
|
IEnumerable<GameObject> gosWithRenderer =
|
|
Selection.gameObjects.Where(_ => _.GetComponentInChildren<Renderer>() != null);
|
|
|
|
if (!NameAndCreateNewAsset(obj, "New Material", "Material")) return;
|
|
|
|
foreach (GameObject o in gosWithRenderer)
|
|
{
|
|
Renderer rend = o.GetComponentInChildren<Renderer>();
|
|
Undo.RecordObject(rend, "Setting Material");
|
|
rend.sharedMaterial = mat;
|
|
}
|
|
|
|
Undo.CollapseUndoOperations(undoGroup);
|
|
}
|
|
|
|
[Command("Replace Material", "Replaces the first material on all the meshrenderers of the objects selected",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT, QuickName = "RM",
|
|
Category = "Assets")]
|
|
public static void ReplaceMaterial(
|
|
[CommandParameter("The material to replace the old one with", OverrideTypeName = "Material",
|
|
ForceAutoCompleteUsage = true,
|
|
PreventDefaultValueUsage = true, AutoCompleteMethodName = "MaterialAutoComplete")]
|
|
string materialReplacement)
|
|
{
|
|
Material mat = AssetDatabase.LoadAssetAtPath<Material>(materialReplacement);
|
|
int undoID = MonkeyEditorUtils.CreateUndoGroup("Replace Material");
|
|
foreach (MeshRenderer renderer in
|
|
Selection.gameObjects.Convert(_ => _.GetComponentInChildren<MeshRenderer>()))
|
|
{
|
|
Undo.RecordObject(renderer, "change of material");
|
|
if (renderer)
|
|
renderer.sharedMaterial = mat;
|
|
}
|
|
|
|
Undo.CollapseUndoOperations(undoID);
|
|
}
|
|
|
|
public static GenericCommandParameterAutoComplete MaterialAutoComplete()
|
|
{
|
|
return new AssetNameAutoComplete() { CustomType = "Material" };
|
|
}
|
|
|
|
|
|
public static bool NameAndCreateNewAsset(Object obj, string name, string type)
|
|
{
|
|
obj.name = name;
|
|
|
|
string savePath;
|
|
if (!Selection.objects.Any(_ => _.IsDirectory()))
|
|
{
|
|
savePath = MonkeyEditorUtils.GetProjectWindowFocusedFolder();
|
|
if (savePath.IsNullOrEmpty())
|
|
{
|
|
Debug.Log("Monkey Create New " + type + ":" +
|
|
"No Folder Selected, manual folder selection mode");
|
|
savePath = EditorUtility.SaveFilePanelInProject(type + " Creation",
|
|
"New " + type, "", "Select the object's folder", "Assets");
|
|
}
|
|
}
|
|
else
|
|
savePath = AssetDatabase.GetAssetPath(Selection.objects.First(_ => _.IsDirectory()));
|
|
|
|
if (savePath.Length <= 0)
|
|
return false;
|
|
|
|
savePath += "/" + obj.name + ".asset";
|
|
EditorUtility.DisplayProgressBar("Object creation", "In Progress!", 1);
|
|
savePath = AssetDatabase.GenerateUniqueAssetPath(savePath);
|
|
AssetDatabase.CreateAsset(obj, savePath);
|
|
EditorUtility.ClearProgressBar();
|
|
Selection.objects = new Object[] { obj };
|
|
EditorGUIUtility.PingObject(obj);
|
|
return true;
|
|
}
|
|
|
|
[CommandValidation("Select some GameObjects with renderers")]
|
|
private static bool ObjectsWithRenderer()
|
|
{
|
|
return Selection.gameObjects.Any(_ => _.GetComponentInChildren<Renderer>());
|
|
}
|
|
|
|
private static AssetNameAutoComplete ShaderAutoComplete()
|
|
{
|
|
return new AssetNameAutoComplete() { IncludeDirectories = false, CustomType = "Shader" };
|
|
}
|
|
|
|
[Command("New Scene",
|
|
"Creates a new scene in the first selected folder, or the focused one in the project window",
|
|
MenuItemLink = "NewScene", MenuItemLinkTypeOwner = "MonkeyMenuItems", QuickName = "NSC",
|
|
Category = "Scene")]
|
|
public static void CreateNewScene()
|
|
{
|
|
ProjectWindowUtil.CreateScene();
|
|
}
|
|
|
|
[Command("New Folder",
|
|
"Creates a new folder in the first selected folder, or the focused one in the project window",
|
|
QuickName = "NF",
|
|
Category = "Assets")]
|
|
public static void CreateNewFolder()
|
|
{
|
|
ProjectWindowUtil.CreateFolder();
|
|
}
|
|
|
|
[Command("Add Components",
|
|
"Creates new components on the selected GameObjects, with the types specified",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
AlwaysShow = true, QuickName = "AC", MenuItemLink = "AddComponents",
|
|
MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject/Component")]
|
|
public static void AddComponents(
|
|
[CommandParameter(Help = "The types of components to add",
|
|
ForceAutoCompleteUsage = true,
|
|
PreventDefaultValueUsage = true,
|
|
AutoCompleteMethodName = "ComponentAutoComplete")]
|
|
Type[] componentTypes)
|
|
{
|
|
if (componentTypes == null || componentTypes.Length == 0)
|
|
{
|
|
Debug.LogWarning("Monkey Warning: Error parsing the component types");
|
|
return;
|
|
}
|
|
|
|
int undoID = MonkeyEditorUtils.CreateUndoGroup("Adding Components");
|
|
|
|
foreach (var gameObject in Selection.gameObjects)
|
|
{
|
|
foreach (var type in componentTypes)
|
|
{
|
|
if (type == null)
|
|
continue;
|
|
|
|
Component comp = gameObject.AddComponent(type);
|
|
if (comp)
|
|
Undo.RegisterCreatedObjectUndo(comp, "component attached");
|
|
}
|
|
}
|
|
|
|
Undo.CollapseUndoOperations(undoID);
|
|
}
|
|
|
|
[Command("Replace Components",
|
|
"Replaces the first component of the type specified " +
|
|
"by another one of another type on all objects",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
AlwaysShow = true, QuickName = "RC",
|
|
MenuItemLink = "ReplaceComponents", MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject/Component")]
|
|
public static void ReplaceComponents(
|
|
[CommandParameter(Help = "The type of component to replace",
|
|
ForceAutoCompleteUsage = true,
|
|
PreventDefaultValueUsage = true,
|
|
AutoCompleteMethodName = "TypeAuto")]
|
|
Type componentType,
|
|
[CommandParameter(Help = "The types of components to add",
|
|
ForceAutoCompleteUsage = true,
|
|
PreventDefaultValueUsage = true,
|
|
AutoCompleteMethodName = "ComponentAutoComplete")]
|
|
Type newType)
|
|
{
|
|
if (componentType == null || newType == null)
|
|
{
|
|
Debug.LogWarning("Monkey Warning: Error parsing the component types");
|
|
return;
|
|
}
|
|
|
|
int undoID = MonkeyEditorUtils.CreateUndoGroup("Replacing Components");
|
|
|
|
foreach (var gameObject in Selection.gameObjects)
|
|
{
|
|
Component oldcomp = gameObject.GetComponent(componentType);
|
|
if (oldcomp)
|
|
Undo.DestroyObjectImmediate(oldcomp);
|
|
Component comp = gameObject.AddComponent(newType);
|
|
if (comp)
|
|
Undo.RegisterCreatedObjectUndo(comp, "component attached");
|
|
}
|
|
|
|
Undo.CollapseUndoOperations(undoID);
|
|
}
|
|
|
|
[Command("Remove Component",
|
|
"Removes the first components of the type specified " +
|
|
"on all objects",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
QuickName = "REC",
|
|
Category = "GameObject/Component")]
|
|
public static void RemoveComponents(
|
|
[CommandParameter(Help = "The type of component to remove",
|
|
ForceAutoCompleteUsage = true,
|
|
PreventDefaultValueUsage = true,
|
|
AutoCompleteMethodName = "TypeAuto")]
|
|
Type componentType
|
|
)
|
|
{
|
|
if (componentType == null)
|
|
{
|
|
Debug.LogWarning("Monkey Warning: Error parsing the component types");
|
|
return;
|
|
}
|
|
|
|
int undoID = MonkeyEditorUtils.CreateUndoGroup("Removing Components");
|
|
|
|
foreach (var gameObject in Selection.gameObjects)
|
|
{
|
|
Component[] oldcomps = gameObject.GetComponents(componentType);
|
|
|
|
foreach (var oldcomp in oldcomps)
|
|
{
|
|
if (oldcomp)
|
|
Undo.DestroyObjectImmediate(oldcomp);
|
|
}
|
|
}
|
|
|
|
Undo.CollapseUndoOperations(undoID);
|
|
}
|
|
|
|
|
|
public static TypeAutoComplete ScriptableObjectAutoComplete()
|
|
{
|
|
return new TypeAutoComplete(false, false, false);
|
|
}
|
|
|
|
public static TypeAutoComplete ObjectAutoComplete()
|
|
{
|
|
return new TypeAutoComplete(true, false, false, true, false);
|
|
}
|
|
|
|
|
|
public static TypeAutoComplete ComponentAutoComplete()
|
|
{
|
|
return new TypeAutoComplete(false, true, true, false);
|
|
}
|
|
|
|
[Command("Duplicate", "Duplicates the selected objects, by default once",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_OBJECT,
|
|
MenuItemLink = "Duplicate", MenuItemLinkTypeOwner = "MonkeyMenuItems", QuickName = "D",
|
|
Category = "GameObject")]
|
|
public static void Duplicate(
|
|
[CommandParameter(Help = "The amount of duplicates that will be created")]
|
|
int amount = 1)
|
|
{
|
|
List<Object> createdObjects = new List<Object>();
|
|
int undoID = MonkeyEditorUtils.CreateUndoGroup("Duplicate");
|
|
foreach (GameObject toDup in Selection.gameObjects)
|
|
{
|
|
for (int i = 0; i < amount; i++)
|
|
{
|
|
if (EditorUtility.DisplayCancelableProgressBar("Duplicating Objects",
|
|
"Duplicating " + toDup.name, (float)i / amount))
|
|
{
|
|
Undo.CollapseUndoOperations(undoID);
|
|
Selection.objects = createdObjects.ToArray();
|
|
EditorUtility.ClearProgressBar();
|
|
return;
|
|
}
|
|
|
|
Object newObj;
|
|
GameObject go = null;
|
|
#if UNITY_2019_1_OR_NEWER
|
|
if (PrefabUtility.IsPartOfPrefabInstance(toDup))
|
|
{
|
|
GameObject prefabParent = (GameObject)
|
|
PrefabUtilities.GetPrefabParentPlatformIndependant(toDup);
|
|
|
|
newObj = PrefabUtility.InstantiatePrefab(prefabParent,
|
|
toDup.scene);
|
|
go = newObj as GameObject;
|
|
}
|
|
else if ( /*!PrefabUtility.IsPartOfPrefabAsset(toDup) || */!toDup.scene.IsValid())
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
newObj = Object.Instantiate(toDup);
|
|
go = newObj as GameObject;
|
|
}
|
|
|
|
if (toDup.scene.IsValid())
|
|
#else
|
|
if (PrefabUtility.GetPrefabType(toDup) == PrefabType.PrefabInstance)
|
|
{
|
|
GameObject prefabParent = (GameObject)
|
|
PrefabUtilities.GetPrefabParentPlatformIndependant(toDup);
|
|
|
|
newObj = PrefabUtility.
|
|
InstantiatePrefab(prefabParent,
|
|
toDup.scene);
|
|
go = newObj as GameObject;
|
|
}
|
|
else if (!toDup.scene.IsValid())
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
#if UNITY_2017_1_OR_NEWER
|
|
newObj = Object.Instantiate(toDup, toDup.transform.parent);
|
|
go = newObj as GameObject;
|
|
#else
|
|
newObj = Object.Instantiate(toDup);
|
|
go = newObj as GameObject;
|
|
#endif
|
|
}
|
|
#endif
|
|
if (go)
|
|
{
|
|
go.transform.SetSiblingIndex(toDup.transform.GetSiblingIndex() + 1 + i);
|
|
go.transform.SetParent(toDup.transform.parent);
|
|
go.transform.CopyLocalPositionRotation(toDup.transform);
|
|
go.transform.localScale = toDup.transform.localScale;
|
|
}
|
|
|
|
createdObjects.Add(newObj);
|
|
|
|
Undo.RegisterCreatedObjectUndo(newObj, "new Duplicate");
|
|
EditorApplication.RepaintHierarchyWindow();
|
|
}
|
|
}
|
|
|
|
foreach (Object o in Selection.objects)
|
|
{
|
|
GameObject go = o as GameObject;
|
|
#if UNITY_2019_1_OR_NEWER
|
|
if (go && !PrefabUtility.IsPartOfPrefabAsset(go))
|
|
continue;
|
|
#else
|
|
if (go && Selection.transforms.Contains(go.transform))
|
|
continue;
|
|
#endif
|
|
for (int i = 0; i < amount; i++)
|
|
{
|
|
if (EditorUtility.DisplayCancelableProgressBar("Duplicating Objects",
|
|
"Duplicating " + o.name, (float)i / amount))
|
|
{
|
|
Undo.CollapseUndoOperations(undoID);
|
|
Selection.objects = createdObjects.ToArray();
|
|
EditorUtility.ClearProgressBar();
|
|
return;
|
|
}
|
|
|
|
string path = AssetDatabase.GetAssetPath(o);
|
|
string newPath = AssetDatabase.GenerateUniqueAssetPath(path);
|
|
AssetDatabase.CopyAsset(path, newPath);
|
|
Object newlyCreated = AssetDatabase.LoadAssetAtPath(newPath, typeof(Object));
|
|
//Undo.RegisterCreatedObjectUndo(newlyCreated, "new Duplicate");
|
|
createdObjects.Add(newlyCreated);
|
|
}
|
|
}
|
|
|
|
Undo.CollapseUndoOperations(undoID);
|
|
Selection.objects = createdObjects.Append(Selection.gameObjects).ToArray();
|
|
EditorUtility.ClearProgressBar();
|
|
EditorApplication.RepaintHierarchyWindow();
|
|
EditorApplication.DirtyHierarchyWindowSorting();
|
|
EditorApplication.RepaintProjectWindow();
|
|
}
|
|
|
|
private static GameObject FirstSelected()
|
|
{
|
|
return MonkeyEditorUtils.OrderedSelectedGameObjects.FirstOrDefault();
|
|
}
|
|
|
|
[Command("Duplicate And Mirror", "Duplicates an objects following a point symmetry"
|
|
, QuickName = "DMP",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
Category = "GameObject")]
|
|
public static void DuplicateMirrorPoint()
|
|
{
|
|
MonkeyEditorUtils.AddSceneCommand(new MirrorCreationCommand(Selection.activeGameObject));
|
|
}
|
|
|
|
public class MirrorCreationCommand : ConfirmedCommand
|
|
{
|
|
public GameObject MirrorCenter;
|
|
public GameObject ObjectToMirror;
|
|
|
|
public bool UseRotation;
|
|
|
|
public MirrorCreationCommand(GameObject toMirror)
|
|
{
|
|
SceneCommandName = "Mirror Creation";
|
|
ObjectToMirror = toMirror;
|
|
}
|
|
|
|
public override void DisplayParameters()
|
|
{
|
|
base.DisplayParameters();
|
|
DisplayObjectOption("Mirror Center", ref MirrorCenter);
|
|
DisplayBoolOption("Use Rotation", ref UseRotation);
|
|
DisplayObjectOption("Object To Mirror", ref ObjectToMirror);
|
|
DisplayButton("Create Mirror", CreateNewMirror);
|
|
}
|
|
|
|
public void CreateNewMirror()
|
|
{
|
|
var go = ObjectToMirror.InstantiateObjectAsInstance();
|
|
|
|
go.transform.SetParent(ObjectToMirror.transform.parent);
|
|
go.transform.SetSiblingIndex(ObjectToMirror.transform.GetSiblingIndex() + 1);
|
|
|
|
Vector3 direction = MirrorCenter.transform.position - ObjectToMirror.transform.position;
|
|
|
|
go.transform.position = MirrorCenter.transform.position + direction;
|
|
|
|
if (UseRotation)
|
|
{
|
|
go.transform.rotation = Quaternion.Inverse(go.transform.rotation);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Command("New Instances Under Mouse", QuickName = "NIM", Order = -6,
|
|
Help = "Instantiates prefabs interactively at the mouse position, " +
|
|
"randomly from a list of selected prefabs", AlwaysShow = true,
|
|
MenuItemLink = "InstantiateMousePrefab",
|
|
MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject")]
|
|
public static void InstantiatePrefabUnderMouse(
|
|
[CommandParameter(Help = "The list of prefabs you want to instantiate," +
|
|
" they will be randomly chosen",
|
|
AutoCompleteMethodName = "PrefabAssets",
|
|
ForceAutoCompleteUsage = true, DefaultValueMethod = "DefaultAssets",
|
|
DefaultValueNameOverride = "The Selected Prefabs",
|
|
OverrideTypeName = "Prefab Names")]
|
|
string[] prefabs)
|
|
|
|
{
|
|
List<GameObject> prefabsObjects = new List<GameObject>();
|
|
foreach (string prefab in prefabs)
|
|
{
|
|
prefabsObjects.Add(AssetDatabase.LoadAssetAtPath<GameObject>(prefab));
|
|
}
|
|
|
|
MonkeyEditorUtils.AddSceneCommand(
|
|
new RaycastCreationSceneCommand(prefabsObjects, 0, DirectionAxis.UP,
|
|
Vector2.zero, true));
|
|
}
|
|
|
|
|
|
[Command("New Instances Under Mouse 2D", QuickName = "NIM2", Order = -6,
|
|
Help = "Instantiates prefabs interactively at the mouse position in 2D, " +
|
|
"randomly from a list of selected prefabs", AlwaysShow = true,
|
|
Category = "2D/Creation")]
|
|
public static void InstantiatePrefabUnderMouse2D(
|
|
[CommandParameter(Help = "The list of prefabs you want to instantiate," +
|
|
" they will be randomly chosen",
|
|
AutoCompleteMethodName = "PrefabAssets",
|
|
ForceAutoCompleteUsage = true, DefaultValueMethod = "DefaultAssets",
|
|
DefaultValueNameOverride = "The Selected Prefabs",
|
|
OverrideTypeName = "Prefab Names")]
|
|
string[] prefabs)
|
|
|
|
{
|
|
List<GameObject> prefabsObjects = new List<GameObject>();
|
|
foreach (string prefab in prefabs)
|
|
{
|
|
prefabsObjects.Add(AssetDatabase.LoadAssetAtPath<GameObject>(prefab));
|
|
}
|
|
|
|
MonkeyEditorUtils.AddSceneCommand(new Raycast2DCreationSceneCommand(prefabsObjects, Vector2.one, true));
|
|
}
|
|
|
|
|
|
[Command("Duplicate Under Mouse", QuickName = "DM", AlwaysShow = true, Order = -6,
|
|
Help = "Duplicates the selected objects randomly under the raycasted position of the mouse " +
|
|
"(new instance for prefabs)",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
MenuItemLink = "DuplicateMouseRay", MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject")]
|
|
public static void DuplicateObjectUnderMouse()
|
|
|
|
{
|
|
MonkeyEditorUtils.AddSceneCommand(
|
|
new RaycastCreationSceneCommand(Selection.gameObjects.ToList(), 0, DirectionAxis.UP,
|
|
Vector2.zero, true));
|
|
}
|
|
|
|
[Command("Duplicate Under Mouse 2D", QuickName = "DM2", AlwaysShow = true, Order = -6,
|
|
Help = "Duplicates the selected objects randomly under the 2D position of the mouse " +
|
|
"(new instance for prefabs)",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
Category = "2D/Creation")]
|
|
public static void DuplicateObjectUnderMouse2D()
|
|
{
|
|
MonkeyEditorUtils.AddSceneCommand(
|
|
new Raycast2DCreationSceneCommand(Selection.gameObjects.ToList(), Vector2.zero, true));
|
|
}
|
|
|
|
[Command("New GameObjects Under Mouse", QuickName = "NG",
|
|
Help = "Creates new objects under the raycasted position of the mouse",
|
|
Category = "GameObject")]
|
|
public static void CreateObjectUnderMouse()
|
|
|
|
{
|
|
MonkeyEditorUtils.AddSceneCommand(
|
|
new RaycastCreationSceneCommand(null, 0, DirectionAxis.UP,
|
|
Vector2.zero, false));
|
|
}
|
|
|
|
|
|
[Command("New GameObjects Under Mouse 2D", QuickName = "NG2",
|
|
Help = "Creates new objects under the 2D position of the mouse",
|
|
Category = "2D/Creation")]
|
|
public static void CreateObjectUnderMouse2D()
|
|
{
|
|
MonkeyEditorUtils.AddSceneCommand(
|
|
new Raycast2DCreationSceneCommand(null, Vector2.one, false));
|
|
}
|
|
|
|
public class RaycastCreationSceneCommand : ConfirmedCommand
|
|
{
|
|
public GameObject ParentObject;
|
|
|
|
public float Offset = 0;
|
|
|
|
private Vector3 lastProjectionPosition;
|
|
private Vector3 lastProjectionNormal;
|
|
|
|
private readonly List<GameObject> prefabs;
|
|
private Vector2 scaleRandomRange;
|
|
|
|
private List<GameObject> createdObjects = new List<GameObject>();
|
|
private bool collision;
|
|
|
|
private DirectionAxis axisToNormal;
|
|
private DirectionAxis forwardAxis;
|
|
|
|
private bool orientAlongSurface;
|
|
|
|
private Vector3? lastPositionCreated = null;
|
|
|
|
private GameObject debugDrawObject;
|
|
private GameObject lastCreated;
|
|
|
|
public float angleOffset;
|
|
|
|
public Vector2 RandomRotationRange;
|
|
|
|
|
|
public float orientationFactor = 1;
|
|
|
|
private bool IgnoreInvisibleColliders;
|
|
|
|
public RaycastCreationSceneCommand(List<GameObject> prefabs, float offset,
|
|
DirectionAxis axisToNormal, Vector2 scaleRandomRange, bool followCreationCurve)
|
|
{
|
|
ConfirmationMode = ActionConfirmationMode.ESCAPE;
|
|
SceneCommandName = "RayCast Mouse Creation";
|
|
IgnoreInvisibleColliders = true;
|
|
forwardAxis = DirectionAxis.FORWARD;
|
|
scaleRandomRange = Vector2.one;
|
|
this.prefabs = prefabs;
|
|
Offset = offset;
|
|
this.axisToNormal = axisToNormal;
|
|
this.scaleRandomRange = scaleRandomRange;
|
|
RandomRotationRange = new Vector2(-180, 180);
|
|
|
|
if (UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage() != null)
|
|
{
|
|
//then by default the parent should be the current prefab
|
|
ParentObject = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage().prefabContentsRoot;
|
|
}
|
|
}
|
|
|
|
public override string ConfirmationMessage()
|
|
{
|
|
return "Press SPACE or Click to instantiate, ESCAPE to stop";
|
|
}
|
|
|
|
public override void DisplayParameters()
|
|
{
|
|
base.DisplayParameters();
|
|
|
|
|
|
DisplayBoolOption("Orient Along Surface", ref orientAlongSurface);
|
|
if (orientAlongSurface)
|
|
DisplayFloatOption("Orientation Factor", ref orientationFactor);
|
|
DisplayVector2Option("Random Rotation Range", ref RandomRotationRange);
|
|
DisplayVector2Option("Scale Range", ref scaleRandomRange);
|
|
|
|
DisplayBoolOption("Ignore Invisible Colliders", ref IgnoreInvisibleColliders);
|
|
|
|
DisplayObjectOption("Parent Object", ref ParentObject);
|
|
if (prefabs != null)
|
|
DisplayObjectListOption("Objects To Instantiate", prefabs);
|
|
|
|
DisplayFloatOption("Surface Offset", ref Offset);
|
|
DisplayFloatOption("Angle Offset", ref angleOffset);
|
|
Enum axis = axisToNormal;
|
|
DisplayEnumOption("Up Axis", ref axis);
|
|
axisToNormal = (DirectionAxis)axis;
|
|
axis = forwardAxis;
|
|
DisplayEnumOption("Forward Axis", ref axis);
|
|
forwardAxis = (DirectionAxis)axis;
|
|
}
|
|
|
|
public override void OnSceneGUI()
|
|
{
|
|
base.OnSceneGUI();
|
|
|
|
if (stopping)
|
|
return;
|
|
|
|
if (!lastCreated ||
|
|
Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Space ||
|
|
Event.current.type == EventType.MouseDown && Event.current.button == 0)
|
|
{
|
|
Event.current.Use();
|
|
|
|
if (lastCreated && RandomRotationRange != Vector2.zero)
|
|
lastCreated.transform.rotation =
|
|
Quaternion.AngleAxis(Random.Range(RandomRotationRange.x, RandomRotationRange.y),
|
|
lastProjectionNormal) * lastCreated.transform.rotation;
|
|
|
|
UpdateCreatedObject();
|
|
Selection.objects = new Object[0];
|
|
|
|
if (lastCreated)
|
|
{
|
|
lastCreated.SetActive(false);
|
|
Undo.RegisterCreatedObjectUndo(lastCreated, "Mouse Raycast Object Creation");
|
|
}
|
|
}
|
|
|
|
if (lastCreated)
|
|
lastCreated.transform.AlignTransformToCollision(lastProjectionPosition, lastProjectionNormal, true,
|
|
axisToNormal, forwardAxis);
|
|
|
|
if (orientAlongSurface && lastCreated)
|
|
{
|
|
if (lastPositionCreated != null)
|
|
{
|
|
Quaternion rotation = Quaternion.LookRotation(
|
|
(Vector3)(lastPositionCreated - lastCreated.transform.position),
|
|
lastCreated.transform.AxisToVector(axisToNormal, true));
|
|
var initialRotation = lastCreated.transform.rotation;
|
|
lastCreated.transform.rotation = Quaternion.Lerp(initialRotation, initialRotation * rotation,
|
|
orientationFactor);
|
|
}
|
|
|
|
lastPositionCreated = lastCreated.transform.position;
|
|
}
|
|
|
|
if (lastCreated)
|
|
lastCreated.transform.rotation =
|
|
Quaternion.AngleAxis(angleOffset,
|
|
lastProjectionNormal) * lastCreated.transform.rotation;
|
|
|
|
if (collision)
|
|
{
|
|
#if UNITY_2017_1_OR_NEWER
|
|
Handles.zTest = CompareFunction.Always;
|
|
#endif
|
|
Handles.Label(lastProjectionPosition + lastProjectionNormal, "MonKey Creation",
|
|
MonkeyStyle.Instance.CommandNameStyle);
|
|
|
|
#if UNITY_2017_1_OR_NEWER
|
|
Handles.zTest = CompareFunction.LessEqual;
|
|
#endif
|
|
Handles.color = MonkeyStyle.Instance.WindowColor.Alphaed(.1f);
|
|
Handles.DrawSolidDisc(lastProjectionPosition + lastProjectionNormal * 0.05f,
|
|
lastProjectionNormal, .5f);
|
|
Handles.color = MonkeyStyle.Instance.WindowColor.Alphaed(.9f);
|
|
Handles.DrawSolidDisc(lastProjectionPosition + lastProjectionNormal * 0.05f,
|
|
lastProjectionNormal, .1f);
|
|
Handles.DrawLine(lastProjectionPosition,
|
|
lastProjectionPosition + lastProjectionNormal * 1);
|
|
|
|
Handles.color = MonkeyStyle.Instance.WindowColor.Alphaed(.5f).Inverted();
|
|
#if UNITY_2017_1_OR_NEWER
|
|
Handles.zTest = CompareFunction.Greater;
|
|
#endif
|
|
Handles.DrawWireDisc(lastProjectionPosition + lastProjectionNormal * 0.05f,
|
|
lastProjectionNormal, .5f);
|
|
Handles.DrawDottedLine(lastProjectionPosition,
|
|
lastProjectionPosition + lastProjectionNormal * 1, 1);
|
|
|
|
Handles.color = Color.white;
|
|
}
|
|
}
|
|
|
|
private GameObject UpdateCreatedObject()
|
|
{
|
|
if (lastCreated)
|
|
{
|
|
lastCreated.SetActive(true);
|
|
if (debugDrawObject)
|
|
Object.DestroyImmediate(debugDrawObject);
|
|
createdObjects.Add(lastCreated);
|
|
if (ParentObject)
|
|
{
|
|
lastCreated.transform.SetParent(ParentObject.transform, true);
|
|
}
|
|
|
|
if (createdObjects.Count > 0)
|
|
createdObjects = createdObjects.Where(_ => _ != null).ToList();
|
|
}
|
|
|
|
GameObject go;
|
|
if (prefabs == null || prefabs.Count == 0)
|
|
go = new GameObject("Mouse Raycast Object " + createdObjects.Count);
|
|
else
|
|
{
|
|
GameObject pref = prefabs.GetRandom();
|
|
if (!pref.IsPrefab())
|
|
{
|
|
go = pref.InstantiateObjectAsInstance();
|
|
|
|
if (pref.scene.IsValid())
|
|
{
|
|
go.transform.SetParent(pref.transform.parent);
|
|
go.transform.SetSiblingIndex(pref.transform.GetSiblingIndex() + 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
go = (GameObject)
|
|
PrefabUtility.InstantiatePrefab(pref, SceneManager.GetActiveScene());
|
|
}
|
|
}
|
|
|
|
if (!go)
|
|
return null;
|
|
|
|
debugDrawObject = new GameObject("MonKey Debug Draw");
|
|
MonKeyDebugMeshDrawer drawer = debugDrawObject.AddComponent<MonKeyDebugMeshDrawer>();
|
|
drawer.reference = go;
|
|
drawer.MeshColor = Color.white.Alphaed(.6f);
|
|
drawer.OutlineColor = MonkeyStyle.Instance.WarningColor.Alphaed(.9f);
|
|
|
|
lastCreated = go;
|
|
lastCreated.transform.localScale =
|
|
go.transform.localScale * Random.Range(scaleRandomRange.x, scaleRandomRange.y);
|
|
|
|
|
|
return go;
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
|
|
lastProjectionPosition = MonkeyEditorUtils.GetMouseRayCastedPosition(null, Offset,
|
|
out collision, out lastProjectionNormal, IgnoreInvisibleColliders);
|
|
}
|
|
|
|
private bool stopping = false;
|
|
|
|
public override void Stop()
|
|
{
|
|
if (lastCreated)
|
|
{
|
|
Object.DestroyImmediate(lastCreated);
|
|
}
|
|
|
|
if (debugDrawObject)
|
|
{
|
|
Object.DestroyImmediate(debugDrawObject);
|
|
}
|
|
|
|
base.Stop();
|
|
Selection.objects = createdObjects.ToArray();
|
|
stopping = true;
|
|
}
|
|
}
|
|
|
|
public class Raycast2DCreationSceneCommand : ConfirmedCommand
|
|
{
|
|
private Vector2 lastProjectionPosition;
|
|
private Vector2 lastProjectionNormal;
|
|
|
|
private readonly List<GameObject> prefabs;
|
|
private Vector2 scaleRandomRange;
|
|
|
|
private List<GameObject> createdObjects = new List<GameObject>();
|
|
private bool collision;
|
|
|
|
private DirectionAxis axisToNormal;
|
|
|
|
private bool followCreationCurve;
|
|
|
|
private Vector2? lastPositionCreated = null;
|
|
|
|
public Raycast2DCreationSceneCommand(List<GameObject> prefabs, Vector2 scaleRandomRange,
|
|
bool followCreationCurve)
|
|
{
|
|
ConfirmationMode = ActionConfirmationMode.ESCAPE;
|
|
SceneCommandName = "RayCast Mouse Creation";
|
|
|
|
this.prefabs = prefabs;
|
|
this.scaleRandomRange = scaleRandomRange;
|
|
}
|
|
|
|
public override string ConfirmationMessage()
|
|
{
|
|
return "Press SPACE to Instantiate a new object, ESCAPE to stop";
|
|
}
|
|
|
|
public override void OnSceneGUI()
|
|
{
|
|
base.OnSceneGUI();
|
|
if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Space)
|
|
{
|
|
Event.current.Use();
|
|
GameObject go;
|
|
if (prefabs == null || prefabs.Count == 0)
|
|
go = new GameObject("Mouse Raycast Object " + createdObjects.Count);
|
|
else
|
|
{
|
|
GameObject pref = prefabs.GetRandom();
|
|
if (!pref.IsPrefab())
|
|
{
|
|
go = pref.InstantiateObjectAsInstance();
|
|
|
|
if (pref.scene.IsValid())
|
|
{
|
|
go.transform.SetParent(pref.transform.parent);
|
|
go.transform.SetSiblingIndex(pref.transform.GetSiblingIndex() + 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
go = (GameObject)
|
|
PrefabUtility.InstantiatePrefab(pref, SceneManager.GetActiveScene());
|
|
}
|
|
}
|
|
|
|
createdObjects.Add(go);
|
|
go.transform.AlignTransformToCollision(lastProjectionPosition, lastProjectionNormal, true,
|
|
axisToNormal);
|
|
|
|
|
|
if (followCreationCurve)
|
|
{
|
|
if (lastPositionCreated != null)
|
|
{
|
|
Quaternion rotation = Quaternion.LookRotation(
|
|
(Vector3)(lastPositionCreated - go.transform.position),
|
|
go.transform.AxisToVector(axisToNormal, true));
|
|
go.transform.rotation = go.transform.rotation * rotation;
|
|
}
|
|
|
|
lastPositionCreated = go.transform.position;
|
|
}
|
|
|
|
if (scaleRandomRange != Vector2.zero)
|
|
go.transform.localScale = Vector3.one *
|
|
Random.Range(scaleRandomRange.x, scaleRandomRange.y);
|
|
Undo.RegisterCreatedObjectUndo(go, "Mouse Raycast Object Creation");
|
|
}
|
|
|
|
createdObjects = createdObjects.Where(_ => _ != null).ToList();
|
|
|
|
if (collision)
|
|
{
|
|
#if UNITY_2017_1_OR_NEWER
|
|
Handles.zTest = CompareFunction.Always;
|
|
#endif
|
|
Handles.Label(lastProjectionPosition + lastProjectionNormal, "MonKey Creation",
|
|
MonkeyStyle.Instance.CommandNameStyle);
|
|
|
|
#if UNITY_2017_1_OR_NEWER
|
|
Handles.zTest = CompareFunction.LessEqual;
|
|
#endif
|
|
Handles.color = MonkeyStyle.Instance.WindowColor.Alphaed(.1f);
|
|
Handles.DrawSolidDisc(lastProjectionPosition + lastProjectionNormal * 0.05f,
|
|
lastProjectionNormal, .5f);
|
|
Handles.color = MonkeyStyle.Instance.WindowColor.Alphaed(.9f);
|
|
Handles.DrawSolidDisc(lastProjectionPosition + lastProjectionNormal * 0.05f,
|
|
lastProjectionNormal, .1f);
|
|
Handles.DrawLine(lastProjectionPosition,
|
|
lastProjectionPosition + lastProjectionNormal * 1);
|
|
|
|
Handles.color = MonkeyStyle.Instance.WindowColor.Alphaed(.5f).Inverted();
|
|
#if UNITY_2017_1_OR_NEWER
|
|
Handles.zTest = CompareFunction.Greater;
|
|
#endif
|
|
Handles.DrawWireDisc(lastProjectionPosition + lastProjectionNormal * 0.05f,
|
|
lastProjectionNormal, .5f);
|
|
Handles.DrawDottedLine(lastProjectionPosition,
|
|
lastProjectionPosition + lastProjectionNormal * 1, 1);
|
|
|
|
Handles.color = Color.white;
|
|
}
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
|
|
if (!MonkeyEditorUtils.CurrentSceneView)
|
|
MonkeyEditorUtils.CurrentSceneView = SceneView.currentDrawingSceneView;
|
|
|
|
lastProjectionPosition =
|
|
MonkeyEditorUtils.CurrentSceneView.camera.ScreenToWorldPoint(MonkeyEditorUtils
|
|
.SceneViewMousePosition);
|
|
}
|
|
|
|
public override void Stop()
|
|
{
|
|
base.Stop();
|
|
Selection.objects = createdObjects.ToArray();
|
|
}
|
|
}
|
|
|
|
[Command("Replace Selected GameObjects", "Replaces the selection with objects specified",
|
|
QuickName = "RS",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
Category = "GameObject")]
|
|
public static void ReplaceSelection(
|
|
[CommandParameter(Help = "The objects that will replace the selected ones." +
|
|
" If less objects than selected ones, will loop",
|
|
ForceAutoCompleteUsage = true, PreventDefaultValueUsage = true,
|
|
AutoCompleteMethodName = "AssetObjectsAuto")]
|
|
string[] toReplaceWith,
|
|
[CommandParameter(Help = "should the objects to replace be chosen randomly")]
|
|
bool replaceRandomly = true,
|
|
[CommandParameter(Help = "Should the scale of the replaced objects be kept")]
|
|
bool keepScale = false,
|
|
[CommandParameter(Help = "Should the names of the replaced objects be kept")]
|
|
bool keepNames = false)
|
|
{
|
|
int undoID = MonkeyEditorUtils.CreateUndoGroup("Replace Game Objects");
|
|
|
|
List<GameObject> gos =
|
|
MonkeyEditorUtils.OrderedSelectedGameObjects.Where(_ => _.scene.IsValid()).ToList();
|
|
List<GameObject> newGos = new List<GameObject>(gos.Count);
|
|
|
|
if (toReplaceWith == null)
|
|
return;
|
|
|
|
int i = 0;
|
|
foreach (var go in gos)
|
|
{
|
|
if (i >= toReplaceWith.Length)
|
|
i = 0;
|
|
|
|
GameObject newGo;
|
|
GameObject prefab =
|
|
AssetDatabase.LoadAssetAtPath<GameObject>(
|
|
toReplaceWith[replaceRandomly ? Random.Range(0, toReplaceWith.Length) : i]);
|
|
#if UNITY_2019_1_OR_NEWER
|
|
|
|
if (PrefabUtility.GetPrefabAssetType(prefab) != PrefabAssetType.NotAPrefab)
|
|
{
|
|
newGo = (GameObject)PrefabUtility.InstantiatePrefab(prefab, go.scene);
|
|
}
|
|
else
|
|
{
|
|
newGo = Object.Instantiate(prefab);
|
|
}
|
|
#else
|
|
if (PrefabUtility.GetPrefabType(prefab) == PrefabType.Prefab)
|
|
{
|
|
newGo = (GameObject)PrefabUtility.InstantiatePrefab(prefab, go.scene);
|
|
}
|
|
else
|
|
{
|
|
newGo = Object.Instantiate(prefab);
|
|
}
|
|
#endif
|
|
newGo.name = keepNames ? go.name : prefab.name;
|
|
|
|
Undo.RegisterCreatedObjectUndo(newGo, "New Object Created");
|
|
|
|
newGo.transform.SetParent(go.transform.parent);
|
|
if (keepScale)
|
|
newGo.transform.CopyLocal(go.transform);
|
|
else
|
|
newGo.transform.CopyLocalPositionRotation(go.transform);
|
|
|
|
newGo.SetActive(go.activeSelf);
|
|
|
|
if (go)
|
|
Undo.DestroyObjectImmediate(go);
|
|
|
|
i++;
|
|
}
|
|
|
|
Selection.objects = newGos.Convert(_ => _ as Object).ToArray();
|
|
|
|
Undo.CollapseUndoOperations(undoID);
|
|
}
|
|
|
|
public static AssetNameAutoComplete AssetObjectsAuto()
|
|
{
|
|
return new AssetNameAutoComplete() { IncludeDirectories = false, CustomType = "GameObject" };
|
|
}
|
|
|
|
private static Type componentCopiedType;
|
|
|
|
[Command("Copy Component",
|
|
"Copies the first component of the first selected object " +
|
|
"of the type specified to use later", QuickName = "CC",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
MenuItemLink = "CopyComponent", MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject/Component")]
|
|
public static void CopyComponent(
|
|
[CommandParameter(Help = "The type of component to copy", AutoCompleteMethodName = "TypeAuto",
|
|
ForceAutoCompleteUsage = true)]
|
|
Type type)
|
|
{
|
|
componentCopiedType = type;
|
|
if (!MonkeyEditorUtils.OrderedSelectedGameObjects.Any())
|
|
{
|
|
Debug.LogWarning("Monkey Copy Component:".Bold() +
|
|
" GameObjects were deselected before the method could complete");
|
|
return;
|
|
}
|
|
|
|
GameObject first = MonkeyEditorUtils.OrderedSelectedGameObjects.ElementAt(0);
|
|
Component comp = first.GetComponent(type);
|
|
ComponentUtility.CopyComponent(comp);
|
|
}
|
|
|
|
/// <summary>
|
|
/// creates an auto complete that returns all the component types attached to a gameobject
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static TypeAutoComplete TypeAuto()
|
|
{
|
|
TypeAutoComplete auto = new TypeAutoComplete(false, false, false, false);
|
|
foreach (GameObject gameObject in Selection.gameObjects)
|
|
{
|
|
foreach (var component in gameObject.GetComponents<Component>())
|
|
{
|
|
if (!component)
|
|
continue;
|
|
Type type = component.GetType();
|
|
|
|
while (type != typeof(Component))
|
|
{
|
|
if (!auto.ContainsKey(type.Name))
|
|
auto.AddNewType(type.Name, type);
|
|
|
|
type = type.BaseType;
|
|
|
|
if (type == null || type == typeof(Object))
|
|
{
|
|
//never too sure
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return auto;
|
|
}
|
|
|
|
private static CommandParameterObjectAutoComplete<Rigidbody> RigidBodyAutoComplete()
|
|
{
|
|
CommandParameterObjectAutoComplete<Rigidbody> autoComplete =
|
|
new CommandParameterObjectAutoComplete<Rigidbody>();
|
|
|
|
foreach (var gameObject in Selection.gameObjects)
|
|
{
|
|
Rigidbody rb = gameObject.GetComponent<Rigidbody>();
|
|
if (rb)
|
|
{
|
|
autoComplete.AddValue(gameObject.name, rb);
|
|
}
|
|
}
|
|
|
|
return autoComplete;
|
|
}
|
|
|
|
|
|
[Command("Paste Component As New", QuickName = "PN",
|
|
Help = "Paste the previously copied component as a new one on the selected gameObjects ",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
MenuItemLink = "PasteComponentAsNew", MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject/Component")]
|
|
public static void PasteComponentAsNew()
|
|
{
|
|
foreach (GameObject o in Selection.gameObjects)
|
|
{
|
|
ComponentUtility.PasteComponentAsNew(o);
|
|
}
|
|
}
|
|
|
|
[Command("Paste Component Value",
|
|
"Paste the previously copied component values " +
|
|
"in place of the first one of its type in the selected object", QuickName = "PV",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT,
|
|
MenuItemLink = "PasteComponentValues", MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject/Component")]
|
|
public static void ReplaceComponent()
|
|
{
|
|
if (componentCopiedType == null)
|
|
return;
|
|
|
|
foreach (GameObject o in Selection.gameObjects)
|
|
{
|
|
Component comp = o.GetComponent(componentCopiedType);
|
|
if (comp)
|
|
ComponentUtility.PasteComponentValues(comp);
|
|
}
|
|
}
|
|
|
|
[Command("Paste Component Value All",
|
|
"Paste the previously copied component values " +
|
|
"in place of all of its type in the selected object",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_GAME_OBJECT, QuickName = "PVA",
|
|
Category = "GameObject/Component")]
|
|
public static void ReplaceComponents()
|
|
{
|
|
if (componentCopiedType == null)
|
|
return;
|
|
|
|
foreach (GameObject o in Selection.gameObjects)
|
|
{
|
|
Component[] comp = o.GetComponents(componentCopiedType);
|
|
foreach (var component in comp)
|
|
{
|
|
ComponentUtility.PasteComponentValues(component);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
[Command("Duplicate On Axis", QuickName = "DA",
|
|
Help = "Duplicates the selected object along the axis indicated, separated by a given distance",
|
|
DefaultValidation = DefaultValidation.AT_LEAST_ONE_TRANSFORM, MenuItemLink = "DuplicateOnAxis",
|
|
MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject")]
|
|
public static void DuplicateOnAxis()
|
|
{
|
|
MonkeyEditorUtils.AddSceneCommand(new DuplicateAxisSceneCommand(Selection.gameObjects, 3, 1));
|
|
}
|
|
|
|
public class DuplicateAxisSceneCommand : TimedSceneCommand
|
|
{
|
|
public List<GameObject> ToDup = new List<GameObject>();
|
|
public Vector3 Offset;
|
|
|
|
public bool LocalAxis;
|
|
public DirectionAxis Axis;
|
|
public int DuplicateAmount;
|
|
public float DuplicateDistance;
|
|
|
|
private readonly Dictionary<GameObject, List<GameObject>> duplicated =
|
|
new Dictionary<GameObject, List<GameObject>>();
|
|
|
|
private bool applyDuplicate = false;
|
|
|
|
public DuplicateAxisSceneCommand(GameObject[] toDuplicate, int duplicateAmount, float duplicateDistance) :
|
|
base(0)
|
|
{
|
|
SceneCommandName = "Duplicate On Axis";
|
|
|
|
ToDup.AddRange(toDuplicate);
|
|
|
|
DuplicateAmount = duplicateAmount;
|
|
DuplicateDistance = duplicateDistance;
|
|
|
|
foreach (var o in ToDup)
|
|
{
|
|
duplicated.Add(o, new List<GameObject>());
|
|
}
|
|
|
|
Duplicate();
|
|
}
|
|
|
|
private List<GameObject> toRemove = new List<GameObject>();
|
|
|
|
public override void DisplayParameters()
|
|
{
|
|
int preAmount = DuplicateAmount;
|
|
DisplayIntOption("Duplicate Amount", ref DuplicateAmount);
|
|
|
|
if (DuplicateAmount < 1)
|
|
DuplicateAmount = 1;
|
|
|
|
float prevDistance = DuplicateDistance;
|
|
|
|
DisplayFloatOption("Duplicate Distance", ref DuplicateDistance);
|
|
DisplayVectorOption("Offset", ref Offset);
|
|
|
|
if (DuplicateDistance < 0)
|
|
DuplicateDistance = 0;
|
|
|
|
DisplayBoolOption("Use Local Axis", ref LocalAxis);
|
|
|
|
DirectionAxis prevAxis = Axis;
|
|
Enum ax = Axis;
|
|
DisplayEnumOption("Axis", ref ax);
|
|
Axis = (DirectionAxis)ax;
|
|
|
|
bool changed = DisplayObjectListOption("Objects To Duplicate", ToDup) != -1;
|
|
|
|
if (changed)
|
|
ResolveNewObjects();
|
|
|
|
if (preAmount != DuplicateAmount || changed || !Mathf.Approximately(prevDistance, DuplicateDistance)
|
|
|| ToDup.Any(_ => _.transform.hasChanged) || prevAxis != Axis)
|
|
Duplicate();
|
|
|
|
DisplayButton("Refresh Duplicate", Duplicate);
|
|
|
|
DisplayButton("Apply Duplicate", ApplyDuplicate);
|
|
}
|
|
|
|
private void ResolveNewObjects()
|
|
{
|
|
toRemove.Clear();
|
|
|
|
foreach (var pair in duplicated)
|
|
{
|
|
if (ToDup.Contains(pair.Key))
|
|
continue;
|
|
|
|
foreach (var o in pair.Value)
|
|
{
|
|
Object.DestroyImmediate(o);
|
|
}
|
|
|
|
toRemove.Add(pair.Key);
|
|
}
|
|
|
|
foreach (var gameObject in toRemove)
|
|
{
|
|
duplicated.Remove(gameObject);
|
|
}
|
|
|
|
foreach (var gameObject in ToDup)
|
|
{
|
|
if (!duplicated.ContainsKey(gameObject))
|
|
duplicated.Add(gameObject, new List<GameObject>());
|
|
}
|
|
}
|
|
|
|
private void ApplyDuplicate()
|
|
{
|
|
applyDuplicate = true;
|
|
Stop();
|
|
}
|
|
|
|
public void Duplicate()
|
|
{
|
|
if (stopped)
|
|
return;
|
|
|
|
if (ToDup.Count == 0)
|
|
{
|
|
DestroyAll();
|
|
|
|
return;
|
|
}
|
|
|
|
if (duplicated[ToDup[0]].Count > DuplicateAmount)
|
|
{
|
|
foreach (var pair in duplicated)
|
|
{
|
|
for (int i = 0; i < pair.Value.Count - DuplicateAmount; i++)
|
|
{
|
|
Object.DestroyImmediate(pair.Value[i]);
|
|
}
|
|
|
|
pair.Value.RemoveAll(_ => !_);
|
|
}
|
|
}
|
|
else if (duplicated[ToDup[0]].Count < DuplicateAmount)
|
|
{
|
|
int count = duplicated[ToDup[0]].Count;
|
|
|
|
foreach (var pair in duplicated)
|
|
{
|
|
for (int i = 0; i < DuplicateAmount - count; i++)
|
|
{
|
|
var dup = pair.Key.InstantiateObjectAsInstance();
|
|
dup.transform.localScale = dup.transform.localScale;
|
|
dup.transform.SetParent(pair.Key.transform.parent, true);
|
|
pair.Value.Add(dup);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var pair in duplicated)
|
|
{
|
|
Vector3 direction = pair.Key.transform.AxisToVector(Axis, LocalAxis);
|
|
Vector3 currentOff = LocalAxis ? pair.Key.transform.TransformDirection(Offset) : Offset;
|
|
float distance = DuplicateDistance;
|
|
|
|
for (int i = 0; i < DuplicateAmount; i++)
|
|
{
|
|
var newGo = pair.Value[i];
|
|
newGo.transform.position = pair.Key.transform.position
|
|
+ distance * direction + currentOff * (i + 1);
|
|
newGo.transform.rotation = pair.Key.transform.rotation;
|
|
|
|
distance += DuplicateDistance;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DestroyAll()
|
|
{
|
|
foreach (var pair in duplicated)
|
|
{
|
|
foreach (var gameObject in pair.Value)
|
|
{
|
|
Object.DestroyImmediate(gameObject);
|
|
}
|
|
|
|
pair.Value.Clear();
|
|
}
|
|
}
|
|
|
|
private bool stopped = false;
|
|
|
|
public override void Stop()
|
|
{
|
|
if (!applyDuplicate)
|
|
{
|
|
DestroyAll();
|
|
stopped = true;
|
|
base.Stop();
|
|
return;
|
|
}
|
|
|
|
int undoId = MonkeyEditorUtils.CreateUndoGroup("MonKey Object Duplicate");
|
|
|
|
foreach (var pair in duplicated)
|
|
{
|
|
foreach (var gameObject in pair.Value)
|
|
{
|
|
Undo.RegisterCreatedObjectUndo(gameObject, gameObject.name);
|
|
}
|
|
|
|
Selection.objects = Selection.objects.Append(pair.Value.Convert(_ => _ as Object)).ToArray();
|
|
}
|
|
|
|
Undo.CollapseUndoOperations(undoId);
|
|
|
|
|
|
base.Stop();
|
|
}
|
|
}
|
|
|
|
[Command("New GameObject With Components",
|
|
"Creates a new object with the selected component types", QuickName = "NGC",
|
|
Category = "GameObject/Component")]
|
|
public static void CreateObjectWithComponents(
|
|
[CommandParameter("The types of components to add", AutoCompleteMethodName = "ComponentAutoComplete")]
|
|
Type[] componentTypes)
|
|
{
|
|
int undoID = MonkeyEditorUtils.CreateUndoGroup("Object with Components");
|
|
GameObject go = new GameObject();
|
|
|
|
Undo.RegisterCreatedObjectUndo(go, "New Object created");
|
|
|
|
foreach (Type componentType in componentTypes)
|
|
{
|
|
Component comp = go.AddComponent(componentType);
|
|
Undo.RegisterCreatedObjectUndo(comp, "New component created");
|
|
}
|
|
|
|
Selection.objects = new Object[] { go };
|
|
Undo.CollapseUndoOperations(undoID);
|
|
}
|
|
|
|
[Command("New Primitive Under Mouse",
|
|
"Creates a new primitive object under the mouse", QuickName = "NPM",
|
|
Category = "GameObject")]
|
|
public static void CreatePrimitiveMouseRaycast(
|
|
[CommandParameter("The primitive type to create")]
|
|
PrimitiveType primitiveType = PrimitiveType.Cube)
|
|
{
|
|
MonkeyEditorUtils.AddSceneCommand(
|
|
new MoveUtilities.RaycastSceneCommand(
|
|
new[] { GameObject.CreatePrimitive(primitiveType) }, .5f, DirectionAxis.UP));
|
|
}
|
|
|
|
[Command("New Instances Between", QuickName = "NB",
|
|
Help = "Creates new prefab instances between the two objects",
|
|
MenuItemLink = "CreateInstancesBetween", MenuItemLinkTypeOwner = "MonkeyMenuItems",
|
|
Category = "GameObject")]
|
|
public static void InstantiateBetweenTwo(
|
|
[CommandParameter(Help = "The list of prefabs you want to instantiate",
|
|
AutoCompleteMethodName = "PrefabAssets",
|
|
ForceAutoCompleteUsage = true, DefaultValueMethod = "DefaultAssets",
|
|
DefaultValueNameOverride = "The Selected Prefabs",
|
|
OverrideTypeName = "Prefab Names")]
|
|
string[] prefabNames)
|
|
{
|
|
GameObject[] selected = prefabNames.Convert(AssetDatabase.LoadAssetAtPath<GameObject>).ToArray();
|
|
|
|
MonkeyEditorUtils.AddSceneCommand(new NewInstancesBetweenSceneCommand(selected));
|
|
}
|
|
|
|
public class NewInstancesBetweenSceneCommand : TimedSceneCommand
|
|
{
|
|
public GameObject StartObject;
|
|
public GameObject EndObject;
|
|
|
|
public List<GameObject> ObjectsToCreate;
|
|
private List<GameObject> prevObjectsToCreate;
|
|
|
|
public int Amount = 1;
|
|
|
|
private List<GameObject> createdObjects = new List<GameObject>();
|
|
|
|
private bool commitCreated = false;
|
|
|
|
private bool stopped = false;
|
|
|
|
public NewInstancesBetweenSceneCommand(GameObject[] objs) : base(0)
|
|
{
|
|
SceneCommandName = "New Instance Between";
|
|
ObjectsToCreate = objs.ToList();
|
|
StartObject = MonKeySelectionUtils.OrderedGameObjects.FirstOrDefault();
|
|
EndObject = MonKeySelectionUtils.OrderedGameObjects.ElementAtOrDefault(1);
|
|
prevObjectsToCreate = new List<GameObject>(ObjectsToCreate);
|
|
}
|
|
|
|
public override void DisplayParameters()
|
|
{
|
|
base.DisplayParameters();
|
|
var prevStart = StartObject;
|
|
var prevEnd = EndObject;
|
|
var prevAmount = Amount;
|
|
|
|
DisplayObjectOption("Start Object", ref StartObject);
|
|
DisplayObjectOption("End Object", ref EndObject);
|
|
|
|
DisplayObjectListOption("Objects To Create", ObjectsToCreate);
|
|
DisplayIntOption("Amount To Create", ref Amount);
|
|
|
|
bool shouldRegenerate = false;
|
|
|
|
if (ObjectsToCreate.Count != prevObjectsToCreate.Count)
|
|
{
|
|
shouldRegenerate = true;
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < ObjectsToCreate.Count; i++)
|
|
{
|
|
if (prevObjectsToCreate[i] != ObjectsToCreate[i])
|
|
{
|
|
shouldRegenerate = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (shouldRegenerate)
|
|
{
|
|
foreach (var gameObject in createdObjects)
|
|
{
|
|
Object.DestroyImmediate(gameObject);
|
|
}
|
|
|
|
createdObjects.Clear();
|
|
prevObjectsToCreate = ObjectsToCreate;
|
|
}
|
|
|
|
if (StartObject && EndObject && (prevAmount != Amount || shouldRegenerate
|
|
|| prevStart != StartObject ||
|
|
prevEnd != EndObject
|
|
|| StartObject.transform.hasChanged
|
|
|| EndObject.transform.hasChanged))
|
|
{
|
|
Create();
|
|
}
|
|
|
|
|
|
DisplayButton("Apply New Instances", Apply);
|
|
}
|
|
|
|
private void Apply()
|
|
{
|
|
commitCreated = true;
|
|
Stop();
|
|
}
|
|
|
|
public override void Stop()
|
|
{
|
|
if (!commitCreated)
|
|
{
|
|
foreach (var gameObject in createdObjects)
|
|
{
|
|
Object.DestroyImmediate(gameObject);
|
|
}
|
|
|
|
createdObjects.Clear();
|
|
stopped = true;
|
|
|
|
base.Stop();
|
|
return;
|
|
}
|
|
|
|
int undoId = MonkeyEditorUtils.CreateUndoGroup("MonKey Object Creation");
|
|
foreach (var gameObject in createdObjects)
|
|
{
|
|
Undo.RegisterCreatedObjectUndo(gameObject, gameObject.name);
|
|
}
|
|
|
|
Undo.CollapseUndoOperations(undoId);
|
|
|
|
base.Stop();
|
|
}
|
|
|
|
public void Create()
|
|
{
|
|
if (stopped || !StartObject || !EndObject)
|
|
return;
|
|
|
|
if (createdObjects.Count > Amount)
|
|
{
|
|
for (int i = Amount; i < createdObjects.Count; i++)
|
|
{
|
|
if (!createdObjects[i])
|
|
continue;
|
|
|
|
Object.DestroyImmediate(createdObjects[i]);
|
|
}
|
|
|
|
createdObjects.RemoveAll(_ => !_);
|
|
}
|
|
else if (createdObjects.Count < Amount)
|
|
{
|
|
int count = createdObjects.Count;
|
|
int k = 0;
|
|
for (int i = 0; i < Amount - count; i++)
|
|
{
|
|
var o = ObjectsToCreate[k];
|
|
// Debug.Log(o);
|
|
k++;
|
|
if (k >= ObjectsToCreate.Count)
|
|
k = 0;
|
|
/* if (EditorUtility.DisplayCancelableProgressBar("Instantiating Prefabs",
|
|
"Instantiating " + o.name,
|
|
(float)i / (Amount)))
|
|
break;*/
|
|
|
|
var dup = o.InstantiateObjectAsInstance();
|
|
createdObjects.Add(dup);
|
|
}
|
|
|
|
// EditorUtility.ClearProgressBar();
|
|
}
|
|
|
|
|
|
Vector3 direction = EndObject.transform.position - StartObject.transform.position;
|
|
float distance = direction.magnitude / (Amount + 1);
|
|
Vector3 currentPosition = StartObject.transform.position + distance * direction.normalized;
|
|
|
|
for (int i = 0; i < Amount; i++)
|
|
{
|
|
GameObject go = createdObjects[i];
|
|
|
|
if (go)
|
|
{
|
|
go.transform.position = currentPosition;
|
|
currentPosition += distance * direction.normalized;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public static string[] DefaultAssets()
|
|
{
|
|
List<string> selectedAssets = new List<string>();
|
|
|
|
foreach (GameObject o in Selection.gameObjects)
|
|
{
|
|
if (o.scene.IsValid())
|
|
continue;
|
|
selectedAssets.Add(AssetDatabase.GetAssetPath(o));
|
|
}
|
|
|
|
return selectedAssets.ToArray();
|
|
}
|
|
|
|
#if UNITY_2019_1_OR_NEWER
|
|
[Command("New Material", "Creates a new Material with a default shader", QuickName = "NM")]
|
|
public static void NewMaterial(
|
|
[CommandParameter("The shader to use", AutoCompleteMethodName = "ShaderTypes",
|
|
ForceAutoCompleteUsage = false,
|
|
DefaultValueNameOverride = "Default Pipeline Shader", DefaultValueMethod = "DefaultShader")]
|
|
ShaderInfo shaderInfo)
|
|
{
|
|
Shader source = Shader.Find(shaderInfo.name);
|
|
Material mat = new Material(source);
|
|
AssetDatabase.CreateAsset(mat, MonkeyEditorUtils.GetProjectWindowFocusedFolder() + "/New Material.mat");
|
|
Selection.objects = new Object[] { mat };
|
|
ProjectWindowUtil.ShowCreatedAsset(mat);
|
|
}
|
|
|
|
public static ShaderInfo DefaultShader()
|
|
{
|
|
switch (MonkeyEditorUtils.GetPipelineType())
|
|
{
|
|
case MonkeyEditorUtils.PipelineType.HDRP:
|
|
return ShaderUtil.GetAllShaderInfo().First(_ => _.name == "HDRP/Lit");
|
|
case MonkeyEditorUtils.PipelineType.URP:
|
|
return ShaderUtil.GetAllShaderInfo().First(_ => _.name == "Universal Render Pipeline/Lit");
|
|
default:
|
|
return ShaderUtil.GetAllShaderInfo().First(_ => _.name == "Standard");
|
|
}
|
|
}
|
|
|
|
public static StaticCommandParameterAutoComplete ShaderTypes()
|
|
{
|
|
StaticCommandParameterAutoComplete autoComp = new StaticCommandParameterAutoComplete(typeof(ShaderInfo));
|
|
var infos = ShaderUtil.GetAllShaderInfo();
|
|
|
|
var dic = new Dictionary<string, object>();
|
|
foreach (var shaderInfo in infos)
|
|
{
|
|
if (shaderInfo.supported && !shaderInfo.hasErrors && !shaderInfo.name.Contains("Hidden") &&
|
|
!shaderInfo.name.Contains("Legacy"))
|
|
dic.Add(shaderInfo.name, shaderInfo);
|
|
}
|
|
|
|
autoComp.ObjectsPerName = dic;
|
|
return autoComp;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#endif |