You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
543 lines
19 KiB
C#
543 lines
19 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.Serialization;
|
|
using Random = System.Random;
|
|
|
|
/*
|
|
* Prefab Child Manager is meant to make it a bit easier to set up and manage large amounts of prefab options, whether
|
|
* they are prefabs added at runtime or children of an object turned on/off. It makes it easier to create groups of
|
|
* objects, and then activate and deactivate them at runtime with a single line of code.
|
|
*
|
|
* Use with "Wardrobe Prefab Manager" to include rigging and blend shape handling (for Infinity PBR characters)
|
|
*/
|
|
|
|
namespace InfinityPBR
|
|
{
|
|
[System.Serializable]
|
|
public class PrefabAndObjectManager : MonoBehaviour
|
|
{
|
|
public PrefabChildEvent _event;
|
|
|
|
public List<PrefabGroup> prefabGroups = new List<PrefabGroup>();
|
|
public bool onlyOneGroupActivePerType = true;
|
|
public bool unpackPrefabs = true;
|
|
public bool revertToDefaultGroupByType = true;
|
|
|
|
public WardrobePrefabManager WardrobePrefabManager => GetWardrobePrefabManager();
|
|
private WardrobePrefabManager _wardrobePrefabManager;
|
|
|
|
public BlendShapesManager BlendShapesManager => GetBlendShapesManager();
|
|
private BlendShapesManager _blendShapesManager;
|
|
|
|
private BlendShapesManager GetBlendShapesManager()
|
|
{
|
|
if (_blendShapesManager != null) return _blendShapesManager;
|
|
if (TryGetComponent(out BlendShapesManager foundManager))
|
|
_blendShapesManager = foundManager;
|
|
return _blendShapesManager;
|
|
}
|
|
|
|
private WardrobePrefabManager GetWardrobePrefabManager()
|
|
{
|
|
if (_wardrobePrefabManager != null) return _wardrobePrefabManager;
|
|
if (TryGetComponent(out WardrobePrefabManager foundManager))
|
|
_wardrobePrefabManager = foundManager;
|
|
return _wardrobePrefabManager;
|
|
}
|
|
|
|
public Transform thisTransform => transform;
|
|
[HideInInspector] public bool showHelpBoxes = true;
|
|
[HideInInspector] public bool showSetup = true;
|
|
[HideInInspector] public bool showFullInspector = false;
|
|
[HideInInspector] public bool showPrefabGroups = true;
|
|
[HideInInspector] public bool instantiatePrefabsAsAdded = true;
|
|
|
|
public List<string> GroupTypeNames => GetGroupTypeNames();
|
|
private List<string> _groupTypeNames = new List<string>();
|
|
public bool cacheTypes = true;
|
|
|
|
private void Start()
|
|
{
|
|
if (_event == null)
|
|
_event = new PrefabChildEvent();
|
|
|
|
cacheTypes = true; // Set true on start, so this will trigger the first time it's called.
|
|
}
|
|
|
|
public void CreateNewPrefabGroup(string groupType = null)
|
|
{
|
|
var newGroup = new PrefabGroup {name = GetNextDefaultName(), groupType = groupType};
|
|
newGroup.CreateNewUid();
|
|
|
|
prefabGroups.Add(newGroup);
|
|
}
|
|
|
|
private string GetNextDefaultName()
|
|
{
|
|
int g = prefabGroups.Count;
|
|
var newName = "Prefab Group " + g;
|
|
while (NameExists(newName))
|
|
{
|
|
g++;
|
|
newName = "Prefab Group " + g;
|
|
}
|
|
|
|
return newName;
|
|
}
|
|
|
|
private bool NameExists(string newName)
|
|
{
|
|
if (prefabGroups.FirstOrDefault(x => x.name == newName) != null)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public void ActivateRandomGroupType()
|
|
{
|
|
Debug.Log($"Count: {GroupTypeNames.Count}");
|
|
var groupType = GroupTypeNames[UnityEngine.Random.Range(0, GroupTypeNames.Count)];
|
|
ActivateRandomGroup(groupType);
|
|
}
|
|
|
|
public void ActivateRandomAllGroups()
|
|
{
|
|
foreach (var groupType in GroupTypeNames)
|
|
ActivateRandomGroup(groupType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Will activate a random group of a named type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <param name="allTypes"></param>
|
|
public void ActivateRandomGroup(string type)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(type)) return;
|
|
|
|
var groupsOfType = GetGroupsOfType(type);
|
|
ActivateGroup(groupsOfType[UnityEngine.Random.Range(0, groupsOfType.Count)]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Activate a group by name
|
|
/// </summary>
|
|
/// <param name="groupName"></param>
|
|
public void ActivateGroup(string groupName)
|
|
{
|
|
var prefabGroup = prefabGroups.FirstOrDefault(x => x.name == groupName);
|
|
if (prefabGroup == null)
|
|
{
|
|
Debug.LogWarning("Warning: No prefab group found with the name " + groupName);
|
|
return;
|
|
}
|
|
|
|
ActivateGroup(prefabGroup);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Activate a group by index
|
|
/// </summary>
|
|
/// <param name="groupIndex"></param>
|
|
public void ActivateGroup(int groupIndex)
|
|
{
|
|
if (prefabGroups.Count < groupIndex || prefabGroups.Count == 0)
|
|
{
|
|
Debug.LogWarning("Warning: Group index (" + groupIndex + ") out of range.");
|
|
return;
|
|
}
|
|
|
|
ActivateGroup(prefabGroups[groupIndex]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Will activate a group which is passed into this. Will also deactivate others of the same type, if any and
|
|
/// onlyOneGroupActivePerType = true.
|
|
/// </summary>
|
|
/// <param name="group"></param>
|
|
public void ActivateGroup(PrefabGroup group)
|
|
{
|
|
// If we are only allowing one group per type, and the group has a type, then deactivate the other groups
|
|
// of this type. Don't check for default, as we will be activating this group right after.
|
|
if (onlyOneGroupActivePerType && !String.IsNullOrWhiteSpace(group.groupType))
|
|
DeactivateGroupsOfType(group.groupType, false);
|
|
|
|
group.isActive = true; // Set this to be true -- group is now active
|
|
|
|
// This is where we activate each group. Instantiate prefabs or turn on game objects.
|
|
foreach (var groupObject in group.groupObjects)
|
|
{
|
|
if (groupObject.isPrefab && groupObject.inGameObject == groupObject.objectToHandle)
|
|
groupObject.inGameObject = null;
|
|
|
|
//groupObject.inGameObject = null;
|
|
|
|
// This is where we instantiate the prefab
|
|
if (groupObject.isPrefab && groupObject.objectToHandle && groupObject.inGameObject == null)
|
|
{
|
|
// Instantiate the object, set it's transform info, and make sure it's active.
|
|
groupObject.inGameObject = Instantiate(groupObject.objectToHandle, groupObject.parentTransform.position, groupObject.parentTransform.rotation, groupObject.parentTransform);
|
|
groupObject.inGameObject.SetActive(true);
|
|
#if UNITY_EDITOR
|
|
// If we are in the editor, then we will unpack this prefab
|
|
if (unpackPrefabs && PrefabUtility.IsAnyPrefabInstanceRoot(groupObject.inGameObject))
|
|
PrefabUtility.UnpackPrefabInstance(groupObject.inGameObject, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction);
|
|
#endif
|
|
|
|
// TryBlendShapesManager(); // March 13, 2022 -- We can do this once later, we don't have to do it each time.
|
|
|
|
}
|
|
else if (!groupObject.isPrefab)
|
|
{
|
|
// The object is not a prefab, so we will just turn on the object.
|
|
if (groupObject.objectToHandle)
|
|
{
|
|
groupObject.objectToHandle.SetActive(true);
|
|
groupObject.inGameObject = groupObject.objectToHandle;
|
|
}
|
|
}
|
|
}
|
|
|
|
TryWardrobePrefabManagerAutoRig();
|
|
|
|
TryWardrobePrefabManagerOnActivate(group);
|
|
|
|
TryBlendShapesManager();
|
|
}
|
|
|
|
private void TryWardrobePrefabManagerOnActivate(PrefabGroup group)
|
|
{
|
|
if (!WardrobePrefabManager) return;
|
|
|
|
WardrobePrefabManager.OnActivate(group.name);
|
|
}
|
|
|
|
// If the Wardrobe Prefab Manager is attached, then we may want to auto rig the new objects
|
|
private void TryWardrobePrefabManagerAutoRig()
|
|
{
|
|
if (!WardrobePrefabManager) return; // Return if there is none
|
|
if (!WardrobePrefabManager.autoRigWhenActivated) return; // Return if we aren't auto rigging
|
|
|
|
// IPBR_CharacterEquip.EquipCharacter(gameObject); // THIS IS THE OLD METHOD
|
|
EquipObject.Equip(gameObject);
|
|
}
|
|
|
|
// If the Blend Shapes Manager is attached, then we will LoadBlendShapeData to make sure the new
|
|
// objects get the right information set.
|
|
private void TryBlendShapesManager()
|
|
{
|
|
if (!BlendShapesManager) return;
|
|
|
|
BlendShapesManager.LoadBlendShapeData();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deactivate a group by PrefabGroup
|
|
/// </summary>
|
|
/// <param name="group"></param>
|
|
/// <param name="checkForDefault"></param>
|
|
public void DeactivateGroup(PrefabGroup group, bool checkForDefault = true)
|
|
{
|
|
group.isActive = false;
|
|
|
|
if (WardrobePrefabManager)
|
|
WardrobePrefabManager.OnDeactivate(group.name);
|
|
|
|
// ITEMS
|
|
foreach (var groupObject in group.groupObjects)
|
|
{
|
|
if (groupObject.isPrefab)
|
|
{
|
|
DestroyObject(groupObject.inGameObject);
|
|
groupObject.inGameObject = null;
|
|
continue;
|
|
}
|
|
|
|
if (groupObject.objectToHandle)
|
|
groupObject.objectToHandle.SetActive(false);
|
|
}
|
|
|
|
if (checkForDefault && !String.IsNullOrWhiteSpace(group.groupType))
|
|
CheckForDefaultGroup(group.groupType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deactivate a group by name.
|
|
/// </summary>
|
|
/// <param name="groupName"></param>
|
|
/// <param name="checkForDefault"></param>
|
|
public void DeactivateGroup(string groupName, bool checkForDefault = true)
|
|
{
|
|
var prefabGroup = prefabGroups.FirstOrDefault(x => x.name == groupName);
|
|
if (prefabGroup == null)
|
|
{
|
|
Debug.LogWarning("Warning: No prefab group found with the name " + groupName);
|
|
return;
|
|
}
|
|
|
|
DeactivateGroup(prefabGroup, checkForDefault);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deactivate a group by the index
|
|
/// </summary>
|
|
/// <param name="groupIndex"></param>
|
|
/// <param name="checkForDefault"></param>
|
|
public void DeactivateGroup(int groupIndex, bool checkForDefault = true)
|
|
{
|
|
if (prefabGroups.Count < groupIndex || prefabGroups.Count == 0)
|
|
{
|
|
Debug.LogWarning("Warning: Group index (" + groupIndex + ") out of range.");
|
|
return;
|
|
}
|
|
|
|
DeactivateGroup(prefabGroups[groupIndex], checkForDefault);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deactivate all groups of a specific type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <param name="checkForDefault"></param>
|
|
public void DeactivateGroupsOfType(string type, bool checkForDefault = true)
|
|
{
|
|
for (int g = 0; g < prefabGroups.Count; g++)
|
|
{
|
|
if (prefabGroups[g].groupType != type)
|
|
continue;
|
|
|
|
DeactivateGroup(g, checkForDefault);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will activate the default group of the named type, if there is one.
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
private void CheckForDefaultGroup(string type)
|
|
{
|
|
int defaultGroupIndex = -1;
|
|
for (int g = 0; g < prefabGroups.Count; g++)
|
|
{
|
|
if (prefabGroups[g].groupType != type) continue; // Continue if the type is wrong
|
|
if (!prefabGroups[g].isDefault) continue; // Continue if this isn't the default
|
|
if (GroupIsActive(g) > 0) return; // If it is the default, and active, return
|
|
|
|
ActivateGroup(prefabGroups[g]); // Activate the default group
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void DestroyObject(GameObject inGameObject)
|
|
{
|
|
if (inGameObject)
|
|
{
|
|
#if UNITY_EDITOR
|
|
DestroyImmediate(inGameObject);
|
|
#else
|
|
Destroy(inGameObject);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public int GroupIsActive(PrefabGroup group)
|
|
{
|
|
int prefabs = 0;
|
|
int inGameObjects = 0;
|
|
|
|
for (int i = 0; i < group.groupObjects.Count; i++)
|
|
{
|
|
if (!group.groupObjects[i].objectToHandle)
|
|
continue;
|
|
|
|
prefabs++;
|
|
if (group.groupObjects[i].isPrefab && group.groupObjects[i].inGameObject)
|
|
inGameObjects++;
|
|
else if (!group.groupObjects[i].isPrefab && group.groupObjects[i].objectToHandle.activeSelf)
|
|
inGameObjects++;
|
|
}
|
|
|
|
if (prefabs == inGameObjects && (prefabs > 0 || group.isActive))
|
|
return 2;
|
|
if (prefabs > inGameObjects && inGameObjects > 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
public int GroupIsActive(int groupIndex) => GroupIsActive(prefabGroups[groupIndex]);
|
|
public int GroupIsActive(string groupName) => GroupIsActive(GetPrefabGroup(groupName));
|
|
|
|
public void AddPrefabToGroup(GameObject prefab, PrefabGroup group)
|
|
{
|
|
var newGroupObject = new GroupObject
|
|
{
|
|
objectToHandle = group.newPrefab, parentTransform = thisTransform, isPrefab = true
|
|
};
|
|
group.groupObjects.Add(newGroupObject);
|
|
}
|
|
|
|
public void AddGameObjectToGroup(GameObject newObject, PrefabGroup group)
|
|
{
|
|
var newGroupObject = new GroupObject
|
|
{
|
|
objectToHandle = group.newPrefab, isPrefab = false
|
|
};
|
|
group.groupObjects.Add(newGroupObject);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a List<string> with the group names of a type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
public List<string> GetGroupsOfType(string type)
|
|
{
|
|
return prefabGroups
|
|
.Where(x => x.groupType == type)
|
|
.Select(x => x.name)
|
|
.ToList();
|
|
|
|
/*
|
|
List<string> newList = new List<string>();
|
|
for (int i = 0; i < prefabGroups.Count; i++)
|
|
{
|
|
if (prefabGroups[i].groupType != type)
|
|
continue;
|
|
|
|
newList.Add(prefabGroups[i].name);
|
|
}
|
|
|
|
return newList;
|
|
*/
|
|
}
|
|
|
|
public void MarkPrefabs ()
|
|
{
|
|
foreach(PrefabGroup prefabGroup in prefabGroups)
|
|
{
|
|
foreach (GroupObject groupObject in prefabGroup.groupObjects)
|
|
{
|
|
if (!groupObject.objectToHandle) continue;
|
|
|
|
if (groupObject.isPrefab && groupObject.inGameObject == groupObject.objectToHandle)
|
|
groupObject.inGameObject = null;
|
|
|
|
groupObject.isPrefab = !groupObject.objectToHandle.transform.IsChildOf(transform); // Not a prefab if it's a child of the prefab manager object
|
|
|
|
if (groupObject.isPrefab && groupObject.inGameObject == groupObject.objectToHandle)
|
|
groupObject.inGameObject = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a PrefabGroup of a given name.
|
|
/// </summary>
|
|
/// <param name="groupName"></param>
|
|
/// <returns></returns>
|
|
public PrefabGroup GetPrefabGroup(string groupName)
|
|
{
|
|
for (int i = 0; i < prefabGroups.Count; i++)
|
|
{
|
|
if (prefabGroups[i].name == groupName)
|
|
return GetPrefabGroup(i);
|
|
}
|
|
|
|
Debug.LogWarning("Warning: Could not find prefab group named " + groupName);
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a List<string> with all Prefab Group types.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public List<string> GetGroupTypeNames()
|
|
{
|
|
if (!cacheTypes) return _groupTypeNames;
|
|
_groupTypeNames = CacheGroupTypeNames();
|
|
cacheTypes = false;
|
|
return _groupTypeNames;
|
|
}
|
|
|
|
private List<string> CacheGroupTypeNames() => _groupTypeNames = prefabGroups.OrderBy(x => x.groupType).Select(x => x.groupType).Distinct().ToList();
|
|
|
|
public PrefabGroup GetPrefabGroup(int index)
|
|
{
|
|
if (prefabGroups.Count < index)
|
|
return prefabGroups[index];
|
|
|
|
Debug.Log($"Warning: The index {index} is out of range of the prefab groups {prefabGroups.Count}");
|
|
return null;
|
|
}
|
|
|
|
public void RemovePrefabGroup(PrefabGroup prefabGroup) => prefabGroups.RemoveAll(x => x == prefabGroup);
|
|
|
|
public void SetUid()
|
|
{
|
|
foreach (var group in prefabGroups)
|
|
{
|
|
if (string.IsNullOrEmpty(group.uid))
|
|
group.CreateNewUid();
|
|
}
|
|
}
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class PrefabGroup
|
|
{
|
|
[HideInInspector] public bool showPrefabs = false;
|
|
[HideInInspector] public bool showShapes = false;
|
|
[HideInInspector] public bool showObjectsOnActivate = false;
|
|
[HideInInspector] public bool showObjectsOnDeactivate = false;
|
|
public string uid;
|
|
public bool isDefault = false;
|
|
public string name;
|
|
public string groupType;
|
|
public bool isActive;
|
|
|
|
[FormerlySerializedAs("prefabObjects")] public List<GroupObject> groupObjects = new List<GroupObject>();
|
|
|
|
[HideInInspector] public GameObject newPrefab;
|
|
[HideInInspector] public GameObject newGameObject;
|
|
|
|
public void RemoveGroupObject(GroupObject groupObject) => groupObjects.Remove(groupObject);
|
|
|
|
public void CreateNewUid(bool forceNew = false)
|
|
{
|
|
if (!string.IsNullOrEmpty(uid) && !forceNew) return;
|
|
uid = GetUid();
|
|
}
|
|
|
|
private string GetUid()
|
|
{
|
|
#if UNITY_EDITOR
|
|
return GUID.Generate().ToString();
|
|
#endif
|
|
return "ThisShoutNotHappen";
|
|
}
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class GroupObject
|
|
{
|
|
[FormerlySerializedAs("prefab")] public GameObject objectToHandle;
|
|
public Transform parentTransform;
|
|
public GameObject inGameObject;
|
|
public MeshRenderer meshRenderer;
|
|
public SkinnedMeshRenderer skinnedMeshRenderer;
|
|
|
|
public bool isPrefab = false;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class PrefabChildEvent : UnityEvent<string>
|
|
{
|
|
|
|
}
|
|
}
|
|
|