This is a Prefab Instance Replacer in the form of a MonoBehaviour script. It requires both PrefabInstanceReplacer.cs and GameObjectTypeClassifier.cs
using Rovsau.Unity.Editor.Extensions;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Rovsau.Unity.Editor.Monos
{
[ExecuteInEditMode]
public class PrefabInstanceReplacer : MonoBehaviour
{
[Header("Config")]
[SerializeField] private bool _includeInactive;
[SerializeField] private GameObject _findAll;
[SerializeField] private GameObject _replaceWith;
[Header("Run")]
[SerializeField] private bool _FindAllPrefabInstances;
[SerializeField] private bool _InstantiateReplacements;
[SerializeField] private bool _RemoveOriginals;
[Header("Run")]
[SerializeField] private bool _DoEverything;
[Header("Objects in Scene")]
[SerializeField] private GameObject[] _found;
private void Update()
{
if (!Application.isPlaying)
{
if (_FindAllPrefabInstances)
{
_FindAllPrefabInstances = false;
FindAllInstances();
}
if (_InstantiateReplacements)
{
_InstantiateReplacements = false;
InstantiateReplacements();
}
if (_RemoveOriginals)
{
_RemoveOriginals = false;
RemoveOriginals();
}
if (_DoEverything)
{
_DoEverything = false;
FindAllInstances();
InstantiateReplacements();
RemoveOriginals();
}
}
}
public void FindAllInstances()
{
if (_findAll.IsSceneObject()) throw new System.ArgumentException("Scene Objects cannot have instances. Assign a Prefab.");
if (!_findAll) throw new System.ArgumentException("Cannot find null. Assign a Prefab.");
// If an instance was used, its corresponding asset is returned.
_findAll = _findAll.GetPrefabAsset();
// If an instance was used, its corresponding asset is returned.
if (_replaceWith) _replaceWith = _replaceWith.GetPrefabAsset();
#if UNITY_2021_3_OR_NEWER
_found = PrefabUtility.FindAllInstancesOfPrefab(_findAll);
if (!_includeInactive) RemoveInactive();
#else
_found = FindAllInstancesOfPrefab(_findAll, _includeInactive);
#endif
System.Array.Sort(_found, (a, b) => a.name.CompareTo(b.name));
}
private void RemoveInactive()
{
for (int i = _found.Length - 1; i >= 0; i--)
{
if (!_found[i].activeInHierarchy) ArrayUtility.RemoveAt(ref _found, i);
}
}
public static GameObject[] FindAllInstancesOfPrefab(GameObject prefab, bool includeInactive)
{
GameObject[] loadedSceneObjects = FindObjectsOfType<GameObject>(includeInactive);
List<GameObject> results = new List<GameObject>();
for (int i = 0; i < loadedSceneObjects.Length; i++)
{
if (PrefabUtility.GetCorrespondingObjectFromSource(loadedSceneObjects[i]) == prefab)
{
results.Add(loadedSceneObjects[i]);
}
}
return results.ToArray();
}
public void InstantiateReplacements()
{
if (_replaceWith.IsSceneObject()) throw new System.ArgumentException("Cannot replace with a Scene Object. Make it into a Prefab first.");
if (!_replaceWith) throw new System.ArgumentException("Cannot replace with null. Assign a replacement Prefab.");
// If an instance was used, its corresponding asset is returned.
_findAll = _findAll.GetPrefabAsset();
int n = 0;
foreach (GameObject go in _found)
{
GameObject g = (GameObject)PrefabUtility.InstantiatePrefab(_replaceWith);
Undo.RegisterCreatedObjectUndo(g, "Instantiate Prefab");
g.transform.position = go.transform.position;
g.transform.rotation = go.transform.rotation;
g.transform.parent = go.transform.parent;
g.name = $"{g.name}_{n++}";
}
}
public void RemoveOriginals()
{
GameObject go;
bool isAsset;
for (int i = _found.Length - 1; i >= 0; i--)
{
if (go = _found[i])
{
// Failsafe: Does not destroy files stored on disk.
isAsset = EditorUtility.IsPersistent(go);
if (!isAsset) Undo.DestroyObjectImmediate(_found[i]);
}
ArrayUtility.RemoveAt(ref _found, i);
}
}
}
}
using System;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
//using static Rovsau.Unity.Editor.Extensions.GameObjectTypeClassifierInternal;
namespace Rovsau.Unity.Editor.Extensions
{
public enum GameObjectType
{
SceneObject,
PrefabAsset,
PrefabInstance,
PrefabVariantAsset,
PrefabVariantInstance,
}
public static partial class GameObjectTypeClassifier
{
/// <summary>
/// Scene Objects only exist inside the scene file itself.
/// </summary>
/// <param name="componentOrGameObject"></param>
/// <returns>True if the object only exists in the scene. False if the object is an Asset or an Instance.</returns>
public static bool IsSceneObject(this UnityEngine.Object componentOrGameObject)
{
return PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject) == PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(componentOrGameObject) == PrefabAssetType.NotAPrefab;
}
public static bool IsPrefabAsset(this UnityEngine.Object componentOrGameObject)
{
return PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject) == PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(componentOrGameObject) == PrefabAssetType.Regular;
}
public static bool IsPrefabInstance(this UnityEngine.Object componentOrGameObject)
{
return PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject) != PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(componentOrGameObject) == PrefabAssetType.Regular;
}
public static bool IsPrefabVariantAsset(this UnityEngine.Object componentOrGameObject)
{
return PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject) == PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(componentOrGameObject) == PrefabAssetType.Variant;
}
public static bool IsPrefabVariantInstance(this UnityEngine.Object componentOrGameObject)
{
return PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject) != PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(componentOrGameObject) == PrefabAssetType.Variant;
}
public static GameObjectType GetGameObjectType(this UnityEngine.Object componentOrGameObject, out PrefabInstanceStatus instanceStatus, out PrefabAssetType assetType)
{
PrefabInstanceStatus i = PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject);
PrefabAssetType a = PrefabUtility.GetPrefabAssetType(componentOrGameObject);
instanceStatus = i;
assetType = a;
if (IsSceneObject(i, a)) return GameObjectType.SceneObject;
if (IsPrefabAsset(i, a)) return GameObjectType.PrefabAsset;
if (IsPrefabInstance(i, a)) return GameObjectType.PrefabInstance;
if (IsPrefabVariantAsset(i, a)) return GameObjectType.PrefabVariantAsset;
if (IsPrefabVariantInstance(i, a)) return GameObjectType.PrefabVariantInstance;
throw new NotSupportedException("GameObjectType could not be determined by PrefabInstanceStatus and PrefabAssetType.");
}
public static GameObjectType GetGameObjectType(this UnityEngine.Object componentOrGameObject)
{
PrefabInstanceStatus instanceStatus = PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject);
PrefabAssetType assetType = PrefabUtility.GetPrefabAssetType(componentOrGameObject);
if (IsSceneObject(instanceStatus, assetType)) return GameObjectType.SceneObject;
if (IsPrefabAsset(instanceStatus, assetType)) return GameObjectType.PrefabAsset;
if (IsPrefabInstance(instanceStatus, assetType)) return GameObjectType.PrefabInstance;
if (IsPrefabVariantAsset(instanceStatus, assetType)) return GameObjectType.PrefabVariantAsset;
if (IsPrefabVariantInstance(instanceStatus, assetType)) return GameObjectType.PrefabVariantInstance;
throw new NotSupportedException("GameObjectType could not be determined by PrefabInstanceStatus and PrefabAssetType.");
}
/// <summary>
/// Accurate for Prefabs, Variants and instances. Checking for Unpacked Models in the scene might return a false positive if the object is a distant Parent of a logical Model.
/// </summary>
/// <param name="componentOrGameObject"></param>
/// <returns>True if the object is part of a Model Prefab (Asset or Instance), or if it is not a prefab and contains known model components.</returns>
public static bool IsModel(this UnityEngine.Object componentOrGameObject)
{
GameObjectType t = GetGameObjectType(componentOrGameObject);
switch (t)
{
case GameObjectType.SceneObject: // SceneObjectHasModel() instead?
GameObject go = (componentOrGameObject is Component) ? (componentOrGameObject as Component).gameObject : (GameObject)componentOrGameObject;
return go.GetComponentInChildren<SkinnedMeshRenderer>() != null || (go.GetComponentInChildren<MeshRenderer>() != null && go.GetComponentInChildren<MeshFilter>() != null);
case GameObjectType.PrefabAsset:
case GameObjectType.PrefabInstance:
return PrefabUtility.IsPartOfModelPrefab(componentOrGameObject);
case GameObjectType.PrefabVariantAsset:
case GameObjectType.PrefabVariantInstance:
default:
return PrefabUtility.IsPartOfModelPrefab(PrefabUtility.GetCorrespondingObjectFromOriginalSource(componentOrGameObject));
}
}
public static void VariantIsModel(this UnityEngine.Object componentOrGameObject)
{
//PrefabUtility.IsPartOfModelPrefab
}
// unfinished // makes sense??
public static bool IsNestedAssetOrInstance(this UnityEngine.Object componentOrGameObject)
{
return PrefabUtility.IsPartOfPrefabAsset(componentOrGameObject) && PrefabUtility.IsPartOfPrefabInstance(componentOrGameObject);
}
// unfinished
public static bool IsAsset(this UnityEngine.Object componentOrGameObject)
{
return PrefabUtility.IsPartOfPrefabAsset(componentOrGameObject);
//return !PrefabUtility.IsPartOfNonAssetPrefabInstance(componentOrGameObject);
//return PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject) != PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(componentOrGameObject) != PrefabAssetType.NotAPrefab;
}
/// <summary>
/// Is part of the current Prefab Stage.
/// </summary>
/// <param name="gameObject"></param>
/// <returns>True if the GameObject is currently being edited in Prefab Mode, or being dragged from Project View to Scene View.</returns>
public static bool IsBeingEditedInPrefabMode(UnityEngine.Object componentOrGameObject)
{
GameObject gameObject = (componentOrGameObject is Component) ? (componentOrGameObject as Component).gameObject : (GameObject)componentOrGameObject;
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
return prefabStage != null && prefabStage.IsPartOfPrefabContents(gameObject);
}
public static bool IsInstance(this UnityEngine.Object componentOrGameObject)
{
PrefabUtility.IsPartOfPrefabInstance(componentOrGameObject);
return PrefabUtility.IsPartOfNonAssetPrefabInstance(componentOrGameObject);
//return PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject) != PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(componentOrGameObject) != PrefabAssetType.NotAPrefab;
}
public static bool IsMissingAsset(this UnityEngine.Object componentOrGameObject)
{
return PrefabUtility.IsPrefabAssetMissing(componentOrGameObject);
//return PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject) == PrefabInstanceStatus.MissingAsset || PrefabUtility.GetPrefabAssetType(componentOrGameObject) == PrefabAssetType.MissingAsset;
}
// unfinished
public static bool IsVariant(this UnityEngine.Object componentOrGameObject)
{
return PrefabUtility.IsPartOfVariantPrefab(componentOrGameObject);
//return PrefabUtility.GetPrefabInstanceStatus(componentOrGameObject) != PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(componentOrGameObject) != PrefabAssetType.NotAPrefab;
}
/// <summary>
/// If the gameObject is an instance, return its corresponding asset, else return the original gameObject.
/// </summary>
/// <param name="gameObject"></param>
/// <returns></returns>
public static GameObject GetPrefabAsset(this GameObject gameObject)
{
// Use IsInstance() instead.
GameObjectType t = GetGameObjectType(gameObject);
switch (t)
{
case GameObjectType.PrefabInstance:
case GameObjectType.PrefabVariantInstance:
return PrefabUtility.GetCorrespondingObjectFromSource(gameObject); // null check instead?
case GameObjectType.SceneObject:
case GameObjectType.PrefabAsset:
case GameObjectType.PrefabVariantAsset:
default:
return gameObject;
}
}
}
}