794 lines
22 KiB
C#
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;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|