Files
Shopping_UnityVR/Assets/BoZo_ModularAnimeCharacters/Scripts/Outfit.cs

794 lines
22 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.Events;
namespace Bozo.AnimeCharacters
{
public class Outfit : OutfitBase
{
public bool Initalized { get; set; }
[SerializeField] bool AttachInEditMode;
private OutfitSystem system;
//[Header("Character Creator Settings")]
public string OutfitName;
public Sprite OutfitIcon;
public string[] ColorChannels = new string[] { "Base" };
public string TextureCatagory;
public bool supportDecals;
public bool supportPatterns;
public bool showCharacterCreator = true;
public SkinnedMeshRenderer skinnedRenderer
{ get
{ if (skinnedRenderers.Length > 0) return skinnedRenderers[0];
else return null;
}
}
public SkinnedMeshRenderer[] skinnedRenderers { get; private set; }
public Renderer outfitRenderer { get; private set; }
//[field: Header("Outfit Settings")]
[SerializeField] public OutfitType Type;
public string AttachPoint;
[Range(-1,11)]public int materialIndex = -1;
[Range(0,100)]public int materialPriority = 0;
public Color[] defaultColors;
public string[] tags;
public GameObject[] optionalPieces;
public Transform[] additionalBones;
private Dictionary<string, int> tagShapes = new Dictionary<string, int>();
private Dictionary<string, int> shapes = new Dictionary<string, int>();
public LinkedColorSets[] LinkedColorSets;
public OutfitType[] IncompatibleSets;
public OutfitType[] HideTypes;
//[Header("User Settings")]
public int currentSwatch;
public List<OutfitSwatch> outfitSwatches = new List<OutfitSwatch>();
public Transform[] originalBones;
public Transform originalRootBone;
public Transform editorAttachPoint;
//Materials
public bool customShader;
public Material material;
public Renderer controlMaterial;
public int controlIndex;
public Dictionary<string, Material> editMaterials = new Dictionary<string, Material>();
private MaterialPropertyBlock block;
public List<DecalData> decalDatas;
//Events
public UnityAction<Outfit> OnColorChanged;
//
public bool editMode;
public Color[] colors = new Color[9];
private void OnValidate()
{
if (Application.isPlaying && gameObject.scene.isLoaded)
{
if (system == null) system = GetComponentInParent<OutfitSystem>();
SetColorInital();
}
#if UNITY_EDITOR
if (AttachInEditMode && !Application.isPlaying) SoftAttach();
#endif
}
private void Awake()
{
outfitRenderer = GetComponentInChildren<Renderer>();
skinnedRenderers = GetComponentsInChildren<SkinnedMeshRenderer>(true);
if (outfitRenderer) material = outfitRenderer.sharedMaterial;
block = new MaterialPropertyBlock();
foreach (var smr in skinnedRenderers)
{
smr.sharedMaterial = material;
}
InitSetUpShapes();
}
private void OnEnable()
{
Attach();
}
private void OnDisable()
{
if (!system) return;
system.OnOutfitChanged -= OnOutfitUpdate;
system.OnShapeChanged -= SetShape;
system.RemoveOutfit(this, false);
}
private void OnDestroy()
{
if (!system) return;
system.OnOutfitChanged -= OnOutfitUpdate;
}
private void Start()
{
if (!Initalized) Attach();
SetColorInital();
}
public void Attach(Transform parent)
{
transform.parent = parent;
Attach();
}
public void Attach(OutfitSystem system)
{
transform.parent = system.transform;
Attach();
}
public void Attach(bool force = false)
{
system = GetComponentInParent<OutfitSystem>();
outfitRenderer = GetComponentInChildren<Renderer>();
if (system == null) return;
if (!system.initalized) return;
RemoveIncompatible();
CheckTags();
CopySystemShapes();
system.OnOutfitChanged += OnOutfitUpdate;
system.OnShapeChanged += SetShape;
if (Initalized && !force) { system.ReattachOutfit(this); return; }
var extensions = GetComponentsInChildren<IOutfitExtension>();
foreach (var item in extensions) { item.Initalize(system, this); }
//Reassigning original bones incase it was attached in editor
if (originalBones.Length > 0 && skinnedRenderer)
{
skinnedRenderer.bones = originalBones;
skinnedRenderer.rootBone = originalRootBone;
}
system.AttachOutfit(this);
foreach (var item in extensions) { item.Execute(system, this); }
}
public void ReturnBones()
{
foreach (var item in additionalBones)
{
if (item == null) continue;
item.parent = transform;
}
}
#region OnUpdate Methods
private void OnOutfitUpdate(Outfit newOutfit)
{
if (RemoveIfIncompatible(newOutfit)) return;
CheckTags();
}
private void CheckTags()
{
var shapes = new List<string>(tagShapes.Keys);
foreach (var smr in skinnedRenderers)
{
for (int i = 0; i < shapes.Count; i++)
{
var yes = system.ContainsTag(shapes[i]);
if (yes) { smr.SetBlendShapeWeight(tagShapes[shapes[i]], 100); }
else { smr.SetBlendShapeWeight(tagShapes[shapes[i]], 0); }
}
}
}
#endregion
#region Shapes Methods
private void CopySystemShapes()
{
if (system)
{
var shapesKeys = shapes.Keys.ToArray();
for (int i = 0; i < shapesKeys.Length; i++)
{
var systemValue = system.GetShape(shapesKeys[i]);
if (systemValue == -10000) continue;
SetShape(shapesKeys[i], systemValue);
}
}
}
private void InitSetUpShapes()
{
if (!skinnedRenderer) return;
var mesh = skinnedRenderer.sharedMesh;
var blendShapeCount = skinnedRenderer.sharedMesh.blendShapeCount;
for (int i = 0; i < blendShapeCount; i++)
{
var blendFullName = mesh.GetBlendShapeName(i);
var blendName = mesh.GetBlendShapeName(i);
//removing nameshape that maya gives
var sort = blendName.Split(".");
if (sort.Length > 1) { blendName = sort[1]; }
sort = blendName.Split("_");
if (sort.Length > 1)
{
if (sort[0] == "Tag") { tagShapes.Add(sort[1], i); }
if (sort[0] == "Shape")
{
shapes.Add(sort[1], i);
}
}
}
}
public void SetShape(string key, float value)
{
if (value <= -10000) return;
if (!skinnedRenderer) return;
var sort = key.Split(".");
if (sort.Length > 1) { key = sort[1]; }
if (!shapes.TryGetValue(key, out int index)) { return; }
foreach (var smr in skinnedRenderers)
{
if (smr.sharedMesh.blendShapeCount <= index) continue;
smr.SetBlendShapeWeight(index, value);
}
}
#endregion
#region Incompatible Outfit Methods
private void RemoveIncompatible()
{
foreach (var item in IncompatibleSets)
{
system.RemoveOutfit(item, true);
}
}
private bool RemoveIfIncompatible(Outfit outfit)
{
if (outfit == null) return false;
foreach (var item in IncompatibleSets)
{
if (outfit.Type == item)
{
system.RemoveOutfit(this, true);
return true;
}
}
return false;
}
#endregion
#region Color Methods
public void SetControlMaterial(Renderer mat, int index)
{
//This is for controlling a proxy material so the outfit can use another shader entirely
controlMaterial = mat;
controlIndex = index;
}
public void SetMaterial(Material mat)
{
if(outfitRenderer) outfitRenderer.sharedMaterial = mat;
foreach (var smr in skinnedRenderers)
{
smr.sharedMaterial = mat;
}
}
#region colors
private void SetColorInital()
{
if (!outfitRenderer) return;
for (int i = 0; i < defaultColors.Length; i++)
{
SetColor(defaultColors[i], i + 1);
}
}
public void SetColor(Color color, int index, bool linkedChanged = false)
{
colors[index - 1] = color;
if (system == null) { system = GetComponentInParent<OutfitSystem>(); }
if (outfitRenderer == null) { outfitRenderer = GetComponentInChildren<Renderer>(); }
var material = SelectBlock();
try
{
if (customShader)
{
SetColor(color);
}
else
{
material.SetColor("_Color_" + index, color);
}
}
catch
{
Debug.LogError(name + " Failed to load colors. Is it missing its material or renderer?");
}
foreach (var item in LinkedColorSets)
{
if (!linkedChanged)
{
var linkedOutfit = system.GetOutfit(item.linkedType);
if (linkedOutfit == null) continue;
if (index > item.linkedChannelRange) continue;
linkedOutfit.SetColor(color, index, true);
}
}
UpdateMaterialBlock();
OnColorChanged?.Invoke(this);
}
public virtual void SetColor(Color color)
{
var material = SelectBlock();
if (material.HasProperty("_Color_1"))
{
material.SetColor("_Color_1", color);
}
else if (material.HasProperty("_Color"))
{
material.SetColor("_Color", color);
}
else if (material.HasProperty("_MainColor"))
{
material.SetColor("_MainColor", color);
}
UpdateMaterialBlock();
}
public virtual List<Color> GetColors()
{
var colors = new List<Color>();
var material = SelectMaterial();
if (!material) return colors;
for (int i = 1; i <= 9; i++)
{
if(block.HasProperty("_Color_" + i))
{
colors.Add(SelectBlock().GetColor("_Color_" + i));
}
else
{
colors.Add(material.GetColor("_Color_" + i));
}
}
return colors;
}
public virtual Color GetColor(int channel)
{
var material = SelectMaterial();
if (customShader)
{
if (material.HasProperty("_Color_1"))
{
return material.GetColor("_Color_1");
}
else if (material.HasProperty("_Color"))
{
return material.GetColor("_Color");
}
else if (material.HasProperty("_MainColor"))
{
return material.GetColor("_MainColor");
}
else
{
return Color.white;
}
}
if(block.HasProperty("_Color_" + channel)) return SelectBlock().GetColor("_Color_" + channel);
return material.GetColor("_Color_" + channel);
}
public virtual void SetDecal(Texture texture)
{
var material = SelectBlock();
if (texture == null) return;
material.SetTexture("_DecalMap", texture);
UpdateMaterialBlock();
}
public virtual void SetDecalSize(Vector4 size)
{
var material = SelectBlock();
if (!material.HasProperty("_DecalScale")) return;
material.SetVector("_DecalScale", size);
UpdateMaterialBlock();
}
public virtual Vector4 GetDecalSize()
{
var material = SelectMaterial();
if (!material.HasProperty("_DecalScale")) return new Vector4(0, 0, 0, 0);
var v = material.GetVector("_DecalScale");
return new Vector4(v.x, v.y, 0, 0);
}
public virtual Texture GetDecal()
{
var material = SelectMaterial();
if (!material.HasProperty("_DecalMap")) return null;
return material.GetTexture("_DecalMap");
}
public virtual void SetDecalColor(Color color, int index)
{
var material = SelectBlock();
material.SetColor("_DecalColor_" + index, color);
UpdateMaterialBlock();
}
public virtual Color GetDecalColor(int index)
{
var material = SelectMaterial();
return material.GetColor("_DecalColor_" + index);
}
public virtual List<Color> GetDecalColors()
{
var material = SelectMaterial();
var colors = new List<Color>();
for (int i = 1; i < 4; i++)
{
colors.Add(material.GetColor("_DecalColor_" + i));
}
return colors;
}
public virtual void SetPattern(Texture texture)
{
var material = SelectBlock();
if (texture == null) texture = Texture2D.blackTexture;
material.SetTexture("_PatternMap", texture);
UpdateMaterialBlock();
OnColorChanged?.Invoke(this);
}
public virtual Texture GetPattern()
{
var material = SelectMaterial();
if (!material.HasProperty("_PatternMap")) return null;
return material.GetTexture("_PatternMap");
}
public virtual void SetPatternColor(Color color, int index)
{
var material = SelectBlock();
material.SetColor("_PatternColor_" + index, color);
UpdateMaterialBlock();
OnColorChanged?.Invoke(this);
}
public virtual Color GetPatternColor(int index)
{
var material = SelectMaterial();
return material.GetColor("_PatternColor_" + index);
}
public virtual List<Color> GetPatternColors()
{
var material = SelectMaterial();
var colors = new List<Color>();
for (int i = 1; i < 4; i++)
{
colors.Add(material.GetColor("_PatternColor_" + i));
}
return colors;
}
public virtual void SetPatternSize(Vector2 size)
{
var material = SelectBlock();
material.SetVector("_PatternScale", size);
UpdateMaterialBlock();
OnColorChanged?.Invoke(this);
}
public virtual Vector4 GetPatternSize()
{
var material = SelectMaterial();
if (!material.HasProperty("_PatternScale")) return new Vector4(0, 0, 0, 0);
var v = material.GetVector("_PatternScale");
return new Vector4(v.x, v.y, 0, 0);
}
public virtual void SetBaseTexture(Texture texture, Texture normalTexture = null)
{
}
protected MaterialPropertyBlock SelectBlock()
{
if (controlMaterial) controlMaterial.GetPropertyBlock(block, controlIndex);
else if (outfitRenderer) outfitRenderer.GetPropertyBlock(block);
return block;
}
protected Material SelectMaterial()
{
Material mat = null;
if (controlMaterial) mat = controlMaterial.sharedMaterials[controlIndex];
else if (outfitRenderer) mat = outfitRenderer.sharedMaterial;
else if (material) mat = material;
return mat;
}
public void UpdateMaterialBlock()
{
if (controlMaterial) controlMaterial.SetPropertyBlock(block, controlIndex);
else
{
if (outfitRenderer)
{
outfitRenderer.SetPropertyBlock(block);
foreach (var item in skinnedRenderers)
{
item.SetPropertyBlock(block, controlIndex);
}
}
}
}
#endregion
public override void SetSwatch(int swatchIndex, bool linkedChanged = false)
{
if (!customShader) return;
if (!material) { material = GetComponentInChildren<Renderer>().material; }
if (swatchIndex + 1 > outfitSwatches.Count) return;
var swatchID = outfitSwatches[swatchIndex].swatchID;
var tex = Resources.Load<Texture>(swatchID);
material.mainTexture = tex;
currentSwatch = swatchIndex;
foreach (var item in LinkedColorSets)
{
if (!linkedChanged)
{
var linkedOutfit = system.GetOutfit(item.linkedType);
if (linkedOutfit == null) continue;
linkedOutfit.SetSwatch(swatchIndex, true);
}
}
}
public OutfitData GetOutfitData()
{
var outfitData = new OutfitData();
var path = Type.name + "/" + name;
path = path.Replace("(Clone)", "");
outfitData.outfit = path;
if (customShader)
{
outfitData.color = GetColor(1);
outfitData.swatch = currentSwatch;
}
else
{
outfitData.colors = GetColors();
var decal = GetDecal();
if (decal != null)
{
outfitData.decal = "Decal/" + decal.name;
outfitData.decalColors = GetDecalColors();
outfitData.decalScale = GetDecalSize();
}
else
{
outfitData.decal = "";
}
var pattern = GetPattern();
if (pattern != null)
{
outfitData.pattern = "Pattern/" + pattern.name;
outfitData.patternColors = GetPatternColors();
outfitData.patternScale = GetPatternSize();
}
else
{
outfitData.pattern = "";
}
}
var vis = new bool[optionalPieces.Length];
for (int i = 0; i < optionalPieces.Length; i++)
{
if (optionalPieces[i] == null) continue;
vis[i] = optionalPieces[i].activeSelf;
}
outfitData.partVisibility = vis;
outfitData.decalDatas = decalDatas;
return outfitData;
}
#endregion
#region Soft Attach
#if UNITY_EDITOR
public void SoftAttach()
{
var system = GetComponentInParent<OutfitSystem>();
if (system == null)
{
//return bones if no longer attach to system
SoftDetach();
return;
}
system.SoftAttach(this);
}
public void SoftDetach()
{
editorAttachPoint = null;
if (originalBones.Length > 0)
{
var skinnedRenderer = GetComponentInChildren<SkinnedMeshRenderer>();
if (skinnedRenderer == null) return;
skinnedRenderer.bones = originalBones;
skinnedRenderer.rootBone = originalRootBone;
originalBones = new Transform[0];
originalRootBone = null;
}
}
#endif
#endregion
#region Magicka Cloth2
private void InitCloth()
{
/*
#if MAGICACLOTH2
var cloth = GetComponentInChildren<MagicaCloth2.MagicaCloth>();
if (!cloth) return;
cloth.enabled = false;
cloth.Initialize();
cloth.DisableAutoBuild();
#endif
*/
}
public void ActivateCloth(Dictionary<string, Transform> boneMap)
{
/*
#if MAGICACLOTH2
var cloth = GetComponentInChildren<MagicaCloth2.MagicaCloth>();
if (!cloth) return;
cloth.ReplaceTransform(boneMap);
var col = system.GetClothColliders();
List<MagicaCloth2.ColliderComponent> ClothColliders = col
.Where(m => m != null)
.Select(m => m.GetComponent<MagicaCloth2.ColliderComponent>())
.ToList();
cloth.SerializeData.colliderCollisionConstraint.colliderList = ClothColliders;
cloth.enabled = true;
#endif
*/
}
#endregion
#region Utility Scripts
[ContextMenu("QuickName")]
private void QuickName()
{
int underscoreIndex = name.IndexOf('_');
string trimmed = underscoreIndex >= 0
? name.Substring(underscoreIndex + 1)
: name;
string spaced = Regex.Replace(trimmed, "(?<!^)([A-Z])", " $1");
OutfitName = spaced;
}
#endregion
}
[System.Serializable]
public class OutfitSwatch
{
public string swatchID;
public Color IconColorTop = Color.white;
public Color IconColorBottom = Color.black;
}
[System.Serializable]
public class LinkedColorSets
{
public OutfitType linkedType;
[Range(1, 9)] public int linkedChannelRange;
}
}