using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using System; using System.IO; using System.Collections; using System.Collections.Generic; using UMA; using UMA.Examples; namespace UMA.CharacterSystem.Examples { public class TestCustomizerDD : MonoBehaviour { //SharedColorTableItem makes it possible to have more color tables than just skin/hair/cloth //So a slot has a shared color name and this iterates over the shared color tables to see if a table with that name exists //if it does it uses it, if not it uses the GenericColorList [System.Serializable] public class SharedColorTableItem { public string name; public SharedColorTable sharedColorTable; public Sprite swatch; public Sprite swatchMetallic; } public DynamicCharacterAvatar Avatar; //public DynamicCharacterSystem characterSystem; //ConverterCustomizer is an editor only tool public DynamicDNAConverterCustomizer converterCustomizer; public SharedColorTable GenericColorList; public Sprite genericColorSwatch; public Sprite genericColorSwatchMetallic; [SerializeField] public List sharedColorTables = new List(); public Dropdown changeRaceDropdown; List raceDropdownOptions; public GameObject colorDropdownPrefab; public GameObject wardrobeDrodownPrefab; public GameObject raceDropdownPrefab; public GameObject loadableItemPrefab; public Button cancelLoadItem; public Button saveCompleteBut; public GameObject colorDropdownPanel; public GameObject wardrobeDropdownPanel; public DNAPanel faceEditor; public DNAPanel bodyEditor; [Tooltip("If set, ONLY the wardrobe slots specified have controls generated. TIP: you can limit this restriction to a race by prefixing the racename to the wardrobe slot name eg ToonFemale:Face")] public List limitWardrobeOptions = new List(); [Tooltip("If set, this prevents the SPECIFIED controls from being generated. TIP: you can limit this restriction to a race by prefixing the racename to the wardrobe slot name eg ToonFemale:Face")] public List hideWardrobeOptions = new List(); public UMAMouseOrbitImproved Orbitor; //Loading options when loading a recipe from a text file public bool _loadRace = true; public bool _loadDNA = true; public bool _loadWardrobe = true; public bool _loadBodyColors = true; public bool _loadWardrobeColors = true; public UMAContextBase Context; public bool LoadRace { get { return _loadRace; } set { _loadRace = value; } } public bool LoadDNA { get { return _loadDNA; } set { _loadDNA = value; } } public bool LoadWardrobe { get { return _loadWardrobe; } set { _loadWardrobe = value; } } public bool LoadBodyColors { get { return _loadBodyColors; } set { _loadBodyColors = value; } } public bool LoadWardrobeColors { get { return _loadWardrobeColors; } set { _loadWardrobeColors = value; } } //Loading options when Changing Race bool _keepDNA = false; bool _keepWardrobe = true; bool _keepBodyColors = true; public bool KeepDNA { get { return _keepDNA; } set { _keepDNA = value; } } public bool KeepWardrobe { get { return _keepWardrobe; } set { _keepWardrobe = value; } } public bool KeepBodyColors { get { return _keepBodyColors; } set { _keepBodyColors = value; } } //Loading options when Changing Race bool _saveDNA = true; bool _saveWardrobe = true; bool _saveColors = true; public bool SaveDNA { get { return _saveDNA; } set { _saveDNA = value; } } public bool SaveWardrobe { get { return _saveWardrobe; } set { _saveWardrobe = value; } } public bool SaveColors { get { return _saveColors; } set { _saveColors = value; } } string thisRace; public void Start() { if (Avatar == null) { return; } Avatar.CharacterCreated.AddListener(Init); //converterCustomizer is editor only #if UNITY_EDITOR if (converterCustomizer == null) { converterCustomizer = GameObject.FindObjectOfType(); } else { converterCustomizer.BonesCreated.AddListener(BonesCreated); } #endif } private void BonesCreated() { CloseAllPanels(); } public void Init(UMA.UMAData umaData) { Avatar.CharacterCreated.RemoveListener(Init); thisRace = Avatar.activeRace.name; } public void SetAvatar(GameObject newAvatarObject) { CloseAllPanels(); if (Avatar == null || newAvatarObject != Avatar.gameObject) { Avatar = newAvatarObject.GetComponent(); if (Avatar != null) { if (Orbitor != null) Orbitor.SwitchTarget(Avatar.gameObject.transform); thisRace = Avatar.activeRace.name; } else { //Its the Overview target object if (Orbitor != null) { Orbitor.SwitchTarget(newAvatarObject.transform); Orbitor.distance = 1.5f; } Avatar = null; } } else { if (newAvatarObject == Avatar.gameObject) return; if (Orbitor != null) { Orbitor.SwitchTarget(newAvatarObject.transform); Orbitor.distance = 1.5f; } Avatar = null; } } public void SetUpRacesDropdown(string selected = "") { string newSelected = selected; if (newSelected == "") { if (Avatar != null) { newSelected = Avatar.activeRace.name; } } changeRaceDropdown.options.Clear(); changeRaceDropdown.onValueChanged.RemoveListener(ChangeRace); var raceDropdownOptionsArray = Avatar.context.GetAllRacesBase(); raceDropdownOptions = new List(); //add the 'NoneSet' raceDropdownOptions.Add("None Set"); foreach (RaceData r in raceDropdownOptionsArray) { if (r.raceName != "PlaceholderRace" && r.raceName != "RaceDataPlaceholder") raceDropdownOptions.Add(r.raceName); } for (int i = 0; i < raceDropdownOptions.Count; i++) { var thisddOption = new Dropdown.OptionData(); thisddOption.text = raceDropdownOptions[i]; changeRaceDropdown.options.Add(thisddOption); } for (int i = 0; i < raceDropdownOptions.Count; i++) { if (raceDropdownOptions[i] == newSelected) { changeRaceDropdown.value = i; } } // we also need to make the raceChangeOptions toggles match the settings in the component Toggle[] thisChangeRaceToggles = null; if(changeRaceDropdown.template.Find("ChangeRaceOptsHolder") != null) if(changeRaceDropdown.template.Find("ChangeRaceOptsHolder").Find("ChangeRaceToggles") != null) if(changeRaceDropdown.template.Find("ChangeRaceOptsHolder").Find("ChangeRaceToggles").GetComponentsInChildren().Length != 0) thisChangeRaceToggles = changeRaceDropdown.template.Find("ChangeRaceOptsHolder").Find("ChangeRaceToggles").GetComponentsInChildren(); if(thisChangeRaceToggles != null) for(int i = 0; i < thisChangeRaceToggles.Length; i++) { if (thisChangeRaceToggles[i].gameObject.name == "KeepDNA") thisChangeRaceToggles[i].isOn = _keepDNA; else if (thisChangeRaceToggles[i].gameObject.name == "KeepWardrobe") thisChangeRaceToggles[i].isOn = _keepWardrobe; else if (thisChangeRaceToggles[i].gameObject.name == "KeepBodyColors") thisChangeRaceToggles[i].isOn = _keepBodyColors; } changeRaceDropdown.onValueChanged.AddListener(ChangeRace); } public void ChangeRace(string racename) { if (Avatar == null) return; CloseAllPanels(); int raceInt = -1; for (int i = 0; i < changeRaceDropdown.options.Count; i++) { if (changeRaceDropdown.options[i].text == racename) { raceInt = i; break; } } if (raceInt != -1) ChangeRace(raceInt); else { //this must be a newly Downloaded Race so just let CharacterAvatar deal with it... DynamicCharacterAvatar.ChangeRaceOptions thisLoadOptions = DynamicCharacterAvatar.ChangeRaceOptions.none; if (_keepDNA || _keepWardrobe || _keepBodyColors) { if (_keepDNA) thisLoadOptions |= DynamicCharacterAvatar.ChangeRaceOptions.keepDNA; if (_keepWardrobe) thisLoadOptions |= DynamicCharacterAvatar.ChangeRaceOptions.keepWardrobe; if (_keepBodyColors) thisLoadOptions |= DynamicCharacterAvatar.ChangeRaceOptions.keepBodyColors; thisLoadOptions &= ~DynamicCharacterAvatar.ChangeRaceOptions.none; } Avatar.ChangeRace(racename, thisLoadOptions); } } public void ChangeRace(int raceId) { var RaceToSet = raceDropdownOptions[raceId]; if (RaceToSet != Avatar.activeRace.name) { CloseAllPanels(); thisRace = RaceToSet; //Force CharacterSystem to find the new race - unless its None Set if(RaceToSet != "None Set") UMAContextBase.Instance.GetRace(RaceToSet); DynamicCharacterAvatar.ChangeRaceOptions thisLoadOptions = DynamicCharacterAvatar.ChangeRaceOptions.none; if (_keepDNA || _keepWardrobe || _keepBodyColors) { if (_keepDNA) thisLoadOptions |= DynamicCharacterAvatar.ChangeRaceOptions.keepDNA; if (_keepWardrobe) thisLoadOptions |= DynamicCharacterAvatar.ChangeRaceOptions.keepWardrobe; if (_keepBodyColors) thisLoadOptions |= DynamicCharacterAvatar.ChangeRaceOptions.keepBodyColors; thisLoadOptions &= ~DynamicCharacterAvatar.ChangeRaceOptions.none; } Avatar.ChangeRace(RaceToSet, thisLoadOptions); } } public void InitializeWardrobeDropDowns() { List slotsFromAllRaces = new List(); List races = UMAAssetIndexer.Instance.GetAllAssets(); foreach (RaceData rd in races) { string race = rd.raceName; int i = 0; var recipes = UMAAssetIndexer.Instance.GetRecipes(race); foreach (string slot in recipes.Keys) { if (!slotsFromAllRaces.Contains(slot) && ((limitWardrobeOptions.Count == 0 || limitWardrobeOptions.Contains(slot)) && !hideWardrobeOptions.Contains(slot))) { slotsFromAllRaces.Insert(i, slot); i++; } } } foreach (string slot in slotsFromAllRaces) { if (slot == "None") continue; if (wardrobeDropdownPanel.transform.Find(slot + "DropdownHolder") == null) { GameObject thisWardrobeDropdown = Instantiate(wardrobeDrodownPrefab) as GameObject; thisWardrobeDropdown.transform.SetParent(wardrobeDropdownPanel.transform, false); thisWardrobeDropdown.GetComponent().customizerScript = this; thisWardrobeDropdown.GetComponent().wardrobeSlotToChange = slot; thisWardrobeDropdown.name = slot + "DropdownHolder"; thisWardrobeDropdown.transform.Find("SlotLabel").GetComponent().text = slot; thisWardrobeDropdown.GetComponent().onValueChanged.AddListener(thisWardrobeDropdown.GetComponent().ChangeWardrobeSlot); } } } public void SetUpWardrobeDropdowns() { if (Avatar != null) thisRace = Avatar.activeRace.name; var raceRecipes = UMAAssetIndexer.Instance.GetRecipes(thisRace); InitializeWardrobeDropDowns(); foreach (Transform child in wardrobeDropdownPanel.transform) { child.gameObject.SetActive(true); var thisDD = child.GetComponent(); thisDD.captionImage.overrideSprite = null; var thisSlot = child.GetComponent().wardrobeSlotToChange; //We want to have the option of being able to write limitWardrobeOptions and hideWardrobeOptions like raceName:wrdrobeSlot bool showOption = false; if (!hideWardrobeOptions.Contains(thisSlot) && !hideWardrobeOptions.Contains(thisRace + ":" + thisSlot)) { showOption = true; } if (limitWardrobeOptions.Contains(thisSlot) || limitWardrobeOptions.Contains(thisRace + ":" + thisSlot)) { showOption = true; } if (raceRecipes.ContainsKey(thisSlot) && showOption) { if (thisSlot == "WardrobeCollection") { SetUpWardrobeCollectionDropdown(child, thisDD); } else { thisDD.options.Clear(); thisDD.onValueChanged.RemoveAllListeners(); var wardrobeOptions = new List(raceRecipes[thisSlot]); var thisUnsetThumb = Avatar.activeRace.racedata.raceThumbnails.GetThumbFor(thisSlot); var thisUnsetOption = new Dropdown.OptionData(); thisUnsetOption.text = thisSlot == "Face" ? "Standard" : "None"; thisUnsetOption.image = thisUnsetThumb; thisDD.options.Add(thisUnsetOption); for (int i = 0; i < wardrobeOptions.Count; i++) { var thisddOption = new Dropdown.OptionData(); thisddOption.text = wardrobeOptions[i].DisplayValue != "" ? wardrobeOptions[i].DisplayValue : wardrobeOptions[i].name; thisddOption.image = wardrobeOptions[i].GetWardrobeRecipeThumbFor(thisRace); thisDD.options.Add(thisddOption); } int selected = 0; UMATextRecipe thisDDRecipe = null; if (Avatar.WardrobeRecipes.Count > 0) { foreach (KeyValuePair kp in Avatar.WardrobeRecipes) { var recipeSlotName = kp.Value.wardrobeSlot; if (recipeSlotName == thisSlot && kp.Value.compatibleRaces.Contains(thisRace)) { for (int ri = 0; ri < raceRecipes[recipeSlotName].Count; ri++) { if (raceRecipes[recipeSlotName][ri].name == kp.Value.name) { //we could do alot more checks here to check equalness if this is the only way to make this work... selected = ri + 1; } } thisDDRecipe = kp.Value; } else if (recipeSlotName == thisSlot && (Avatar.activeRace.racedata.IsCrossCompatibleWith(kp.Value.compatibleRaces) && Avatar.activeRace.racedata.wardrobeSlots.Contains(thisSlot))) { //for cross compatible Races- races can be cross compatible with other races (set in the Race itself) and this enables one race to wear anothers wardrobe (if that race has the same wardrobe slots) selected = (raceRecipes[recipeSlotName].FindIndex(s => s.Equals(kp.Value)) + 1); thisDDRecipe = kp.Value; } } } thisDD.value = selected; if (selected == 0) { thisDD.captionImage.sprite = thisUnsetThumb; thisDD.captionImage.enabled = true; } else { thisDD.captionImage.sprite = thisDDRecipe.GetWardrobeRecipeThumbFor(thisRace); thisDD.captionImage.enabled = true; } thisDD.onValueChanged.AddListener(child.GetComponent().ChangeWardrobeSlot); var thisSuppressedTextGO = thisDD.gameObject.transform.Find("ActiveWSlot").Find("SuppressedIndicator"); thisDD.interactable = true; if (thisSuppressedTextGO) { thisSuppressedTextGO.GetComponent().enabled = false; thisSuppressedTextGO.GetComponentInChildren().text = ""; } } } else { child.gameObject.SetActive(false); } } if (Avatar != null) UpdateSuppressedWardrobeDropdowns(); } private void SetUpWardrobeCollectionDropdown(Transform childGO, Dropdown thisDD) { var raceRecipes = UMAAssetIndexer.Instance.GetRecipes(thisRace); var thisSlot = "WardrobeCollection"; thisDD.options.Clear(); thisDD.onValueChanged.RemoveAllListeners(); var wardrobeOptions = new List(raceRecipes[thisSlot]); var thisUnsetThumb = Avatar.activeRace.racedata.raceThumbnails.GetThumbFor(thisSlot); var thisDummyOption = new Dropdown.OptionData(); thisDummyOption.text = "Dummy"; thisDummyOption.image = thisUnsetThumb; thisDD.options.Add(thisDummyOption); var thisUnsetOption = new Dropdown.OptionData(); thisUnsetOption.text = "Remove All"; thisUnsetOption.image = thisUnsetThumb; thisDD.options.Add(thisUnsetOption); int activeWCs = 0; int appliedWCs = 0; for (int i = 0; i < wardrobeOptions.Count; i++) { var thisddOption = new Dropdown.OptionData(); thisddOption.text = wardrobeOptions[i].DisplayValue != "" ? wardrobeOptions[i].DisplayValue : wardrobeOptions[i].name; thisddOption.image = wardrobeOptions[i].GetWardrobeRecipeThumbFor(thisRace); thisDD.options.Add(thisddOption); if (Avatar.GetWardrobeCollection(wardrobeOptions[i].name)) { activeWCs++; if(Avatar.IsCollectionApplied(wardrobeOptions[i].name)) appliedWCs++; } } thisDD.value = 0; thisDD.transform.Find("SlotLabel").GetComponent().text = ""; thisDD.captionImage.sprite = thisUnsetThumb; thisDD.captionImage.enabled = true; if (thisDD.gameObject.GetComponent() == null) { var trigger = thisDD.gameObject.AddComponent(); EventTrigger.Entry entry = new EventTrigger.Entry(); entry.eventID = EventTriggerType.PointerClick; entry.callback.AddListener(UpdateWardrobeCollectionDropdownOpts); trigger.triggers.Add(entry); } thisDD.onValueChanged.AddListener(childGO.GetComponent().ChangeWardrobeSlot); var thisSuppressedTextGO = thisDD.gameObject.transform.Find("ActiveWSlot").Find("SuppressedIndicator"); thisDD.interactable = true; if (thisSuppressedTextGO) { thisSuppressedTextGO.GetComponent().enabled = true; var activeString = activeWCs > 0 ? "\r\n(" + activeWCs + " ACTIVE)" : ""; var appliedString = activeWCs > 0 ? "\r\n(" + appliedWCs + " APPLIED)" : ""; thisSuppressedTextGO.GetComponentInChildren().text = "WARDROBE COLLECTIONS "+ activeString + appliedString; thisSuppressedTextGO.GetComponentInChildren().fontStyle = FontStyle.Bold; } } public void UpdateWardrobeCollectionDropdownOpts(BaseEventData eventData) { var selectedItem = eventData.selectedObject; var selectedItemCheckMark = selectedItem.transform.Find("Item Checkmark"); //var selectedSprite = selectedItemCheckMark.GetComponent().sprite; selectedItemCheckMark.GetComponent().enabled = false; selectedItem.SetActive(false); var allItems = selectedItem.transform.parent.GetComponentsInChildren(); for (int i = 0; i < allItems.Length; i++) { if (allItems[i].gameObject == selectedItem) continue; var collectionName = allItems[i].gameObject.name.Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries)[1]; if (Avatar.GetWardrobeCollection(collectionName)) { var forcedCheckmark = Instantiate(selectedItemCheckMark.gameObject); forcedCheckmark.name = "forcedCheckmark"; forcedCheckmark.transform.SetParent(allItems[i].gameObject.transform, false); forcedCheckmark.GetComponent().enabled = true; } else { if (allItems[i].gameObject.transform.Find("forcedCheckMark") != null) { Destroy(allItems[i].gameObject.transform.Find("forcedCheckMark")); } } } } public void UpdateSuppressedWardrobeDropdowns() { if (Avatar.WardrobeRecipes.Count == 0) return; foreach (KeyValuePair kp in Avatar.WardrobeRecipes) { if (kp.Value.suppressWardrobeSlots == null) continue; var suppressedSlots = kp.Value.suppressWardrobeSlots; foreach (Transform child in wardrobeDropdownPanel.transform) { var thisDD = child.GetComponent(); var thisSuppressedTextGO = thisDD.gameObject.transform.Find("ActiveWSlot").Find("SuppressedIndicator"); thisDD.captionImage.overrideSprite = null; var thisSlot = child.GetComponent().wardrobeSlotToChange; if (suppressedSlots.Contains(thisSlot)) { thisDD.onValueChanged.RemoveAllListeners(); thisDD.value = 0; //make the suppressed slot show the image of the item it is being suppressed by thisDD.captionImage.overrideSprite = kp.Value.GetWardrobeRecipeThumbFor(thisRace); thisDD.interactable = false; if (thisSuppressedTextGO) { thisSuppressedTextGO.GetComponent().enabled = true; thisSuppressedTextGO.GetComponentInChildren().text = "Suppressed by " + kp.Value.name + " on " + kp.Value.wardrobeSlot; } } } } } public void SetUpColorDropdowns() { UMA.UMAData umaData = Avatar.umaData; thisRace = Avatar.activeRace.name; var currentColorDropdowns = colorDropdownPanel.transform.GetComponentsInChildren(true); List activeColorDropdowns = new List(); //foreach (DynamicCharacterAvatar.ColorValue colorType in Avatar.characterColors.Colors) //using new colorvaluestuff foreach (OverlayColorData colorType in Avatar.characterColors.Colors) { activeColorDropdowns.Add(colorType.name); bool dropdownExists = false; foreach (CSColorChangerDD colorDropdown in currentColorDropdowns) { if (colorDropdown.colorToChange == colorType.name) { dropdownExists = true; colorDropdown.gameObject.SetActive(true); SetUpColorDropdownValue(colorDropdown, colorType); break; } } if (!dropdownExists) { GameObject thisColorDropdown = Instantiate(colorDropdownPrefab) as GameObject; thisColorDropdown.transform.SetParent(colorDropdownPanel.transform, false); thisColorDropdown.GetComponent().customizerScript = this; thisColorDropdown.GetComponent().colorToChange = colorType.name; thisColorDropdown.name = colorType.name + "DropdownHolder"; thisColorDropdown.transform.Find("SlotLabel").GetComponent().text = colorType.name + " Color"; thisColorDropdown.GetComponent().onValueChanged.AddListener(thisColorDropdown.GetComponent().ChangeColor); SetUpColorDropdownValue(thisColorDropdown.GetComponent(), colorType); } } foreach (CSColorChangerDD colorDropdown in colorDropdownPanel.transform.GetComponentsInChildren()) { bool keepOptionActive = false; foreach (UMA.OverlayColorData ucd in umaData.umaRecipe.sharedColors) { if (colorDropdown.colorToChange == ucd.name) { keepOptionActive = true; break; } } if (!keepOptionActive) { colorDropdown.gameObject.SetActive(false); } } } public void SetUpColorDropdownValue(CSColorChangerDD colorDropdown, OverlayColorData colorType) { if (GenericColorList == null) { if (Debug.isDebugBuild) Debug.LogWarning("[TestCustomizerDD] the GenericColorList was null or missing, this must be set."); return; } int colorTableSelected = -1; SharedColorTable thisColorTable = null; if (sharedColorTables.FindIndex(s => s.name == colorType.name) > -1) { thisColorTable = sharedColorTables[sharedColorTables.FindIndex(s => s.name == colorType.name)].sharedColorTable; if (thisColorTable == null) { if (Debug.isDebugBuild) Debug.LogWarning("[TestCustomizerDD] the colorList for " + colorType.name + " was null or missing, please set this or remove it from the list."); return; } for (int i = 0; i < thisColorTable.colors.Length; i++) { if (ColorToHex(thisColorTable.colors[i].color) == ColorToHex(colorType.color)) { colorTableSelected = i; break; } } } else { thisColorTable = GenericColorList; for (int i = 0; i < GenericColorList.colors.Length; i++) { if (ColorToHex(GenericColorList.colors[i].color) == ColorToHex(colorType.color)) { colorTableSelected = i; break; } } } SetUpColorDropdownOptions(colorDropdown, thisColorTable, colorTableSelected, colorType); } public void SetUpColorDropdownOptions(CSColorChangerDD colorDropdown, SharedColorTable colorTable, int colorTableSelected, OverlayColorData activeColor) { var thisDD = colorDropdown.gameObject.GetComponent(); thisDD.ClearOptions(); thisDD.onValueChanged.RemoveAllListeners(); Color selectedColor = activeColor.color; var colorBlack = new Color(0, 0, 0, 0); bool selectedColorFound = false; for (int i = 0; i < colorTable.colors.Length; i++) { var thisddOption = new DropdownWithColor.OptionData(); thisddOption.text = colorTable.colors[i].name; thisddOption.color = colorTable.colors[i].color; Sprite spriteToUse = genericColorSwatch; if (colorTable.colors[i].channelAdditiveMask.Length >= 3) { if (colorTable.colors[i].channelAdditiveMask[2] != colorBlack) { spriteToUse = genericColorSwatchMetallic; } } if (i == colorTableSelected) { selectedColorFound = true; selectedColor = colorTable.colors[i].color; } thisddOption.image = spriteToUse; thisDD.options.Add(thisddOption); } if (selectedColorFound) { thisDD.value = colorTableSelected; thisDD.captionImage.color = selectedColor; } thisDD.RefreshShownValue(); thisDD.onValueChanged.AddListener(colorDropdown.ChangeColor); } public string ColorToHex(Color32 color) { string hex = color.r.ToString("X2") + color.g.ToString("X2") + color.b.ToString("X2") + color.a.ToString("X2"); return hex; } public void SetColor(string colorName, float fColor) { int Col = (int)fColor; if (sharedColorTables.FindIndex(s => s.name == colorName) > -1) { Avatar.SetColor(colorName, sharedColorTables[sharedColorTables.FindIndex(s => s.name == colorName)].sharedColorTable.colors[Col]); } else { Avatar.SetColor(colorName, GenericColorList.colors[Col]); } } /// /// Sets any wardrobe slot. If a negative value is passed, then the slot is cleared. /// /// name of the wordrobe slot to change /// Id number slot to change public void SetSlot(string slotToChange, float fSlotNumber) { var raceRecipes = UMAAssetIndexer.Instance.GetRecipes(thisRace); if (slotToChange == "WardrobeCollection") { SetWardrobeCollectionSlot(slotToChange, fSlotNumber); } else { var thisRace = Avatar.activeRace.name; int slotNumber = (int)fSlotNumber; UMATextRecipe tr = null; if (slotNumber >= 0) { tr = raceRecipes[slotToChange][slotNumber]; Avatar.SetSlot(tr); } else { Avatar.ClearSlot(slotToChange); Avatar.ReapplyWardrobeCollections(); } } Avatar.BuildCharacter(true); //Update the dropdowns to reflect any changes after the character has built SetUpWardrobeDropdowns(); } public void SetWardrobeCollectionSlot(string slotToChange, float fSlotNumber) { var raceRecipes = UMAAssetIndexer.Instance.GetRecipes(thisRace); int slotNumber = ((int)fSlotNumber) - 1; if (slotNumber >= 0) { var wc = raceRecipes[slotToChange][slotNumber]; if (Avatar.GetWardrobeCollection(wc.name)) { Avatar.UnloadWardrobeCollection(wc.name); } else { Avatar.SetSlot(wc); } } else { Avatar.UnloadAllWardrobeCollections(); } } public void CloseAllPanels() { faceEditor.transform.parent.gameObject.SetActive(false); bodyEditor.transform.parent.gameObject.SetActive(false); colorDropdownPanel.SetActive(false); wardrobeDropdownPanel.SetActive(false); } public void ShowHideWardrobeDropdowns() { if (wardrobeDropdownPanel.activeSelf) { wardrobeDropdownPanel.SetActive(false); } else { SetUpWardrobeDropdowns(); if (Orbitor != null) { TargetBody(); } wardrobeDropdownPanel.SetActive(true); colorDropdownPanel.SetActive(false); faceEditor.transform.parent.gameObject.SetActive(false); bodyEditor.transform.parent.gameObject.SetActive(false); } } public void ShowHideColorDropdowns() { if (colorDropdownPanel.activeSelf) { colorDropdownPanel.SetActive(false); } else { SetUpColorDropdowns(); if (Orbitor != null) { TargetBody(); } colorDropdownPanel.SetActive(true); wardrobeDropdownPanel.SetActive(false); faceEditor.transform.parent.gameObject.SetActive(false); bodyEditor.transform.parent.gameObject.SetActive(false); } } public void ShowHideFaceDNA() { if (faceEditor.transform.parent.gameObject.activeSelf) { faceEditor.transform.parent.gameObject.SetActive(false); if (Orbitor != null) { TargetBody(); } } else { faceEditor.Initialize(Avatar); if (Orbitor != null) { TargetFace(); } faceEditor.transform.parent.gameObject.SetActive(true); bodyEditor.transform.parent.gameObject.SetActive(false); colorDropdownPanel.SetActive(false); wardrobeDropdownPanel.SetActive(false); } } public void ShowHideBodyDNA() { if (bodyEditor.transform.parent.gameObject.activeSelf) { bodyEditor.transform.parent.gameObject.SetActive(false); } else { bodyEditor.Initialize(Avatar); if (Orbitor != null) { TargetBody(); } bodyEditor.transform.parent.gameObject.SetActive(true); faceEditor.transform.parent.gameObject.SetActive(false); colorDropdownPanel.SetActive(false); wardrobeDropdownPanel.SetActive(false); } } /// /// Point the mouse orbitor at the body center /// public void TargetBody() { if (Orbitor != null) { Orbitor.distance = 1.4f; Orbitor.TargetBone = UMAMouseOrbitImproved.targetOpts.Chest; } } /// /// Point the mouse orbitor at the neck, so you can see the face. /// public void TargetFace() { if (Orbitor != null) { Orbitor.distance = 0.5f; Orbitor.TargetBone = UMAMouseOrbitImproved.targetOpts.Head; } } #region Load and Save public void LoadRecipe() { if (Avatar != null) Avatar.DoLoad(); } public void SaveRecipe() { if (Avatar != null) Avatar.DoSave(); } public void ListLoadableFiles(ScrollRect ItemList) { var thisSubFolder = Avatar.loadPath.TrimStart('\\', '/').TrimEnd('\\', '/').Trim();//trim this at the start and the end of slashes. And then we may need to switch any slashes in the middle depending on the platform- for explode on them or something //we can find things in resources/thisSubFolder and in persistentDataPath/thisSubFolder //Clear the item list ItemList.content.GetComponent().enabled = false;//dont seem to be able to clear the content with this on... foreach (Transform child in ItemList.content.transform) { Destroy(child.gameObject); } ItemList.content.GetComponent().enabled = true; //- I need to basically get rid of the other oprions in CharacterAvatars enumerator since they are effectively useless apart from in the editor var persistentPath = Path.Combine(Application.persistentDataPath, thisSubFolder); if (Directory.Exists(persistentPath)) { string[] persistentDataFiles = Directory.GetFiles(persistentPath, "*.txt"); foreach (string path in persistentDataFiles) { GameObject thisLoadableItem = Instantiate(loadableItemPrefab) as GameObject; thisLoadableItem.transform.SetParent(ItemList.content.transform, false); thisLoadableItem.GetComponent().customizerScript = this; thisLoadableItem.GetComponent().filepath = path; thisLoadableItem.GetComponent().filename = Path.GetFileNameWithoutExtension(path); thisLoadableItem.GetComponentInChildren().text = Path.GetFileNameWithoutExtension(path); } } foreach (string s in UMAContext.Instance.GetRecipeFiles()) { GameObject thisLoadableItem = Instantiate(loadableItemPrefab) as GameObject; thisLoadableItem.transform.SetParent(ItemList.content.transform, false); thisLoadableItem.GetComponent().customizerScript = this; thisLoadableItem.GetComponent().filename = Path.GetFileNameWithoutExtension(s); thisLoadableItem.GetComponentInChildren().text = Path.GetFileNameWithoutExtension(s); } } public void LoadListedFile(string filename, string filepath = "") { cancelLoadItem.onClick.Invoke(); string recipeText = ""; if (filepath != "") { recipeText = FileUtils.ReadAllText(filepath); } else { recipeText = UMAContext.Instance.GetCharacterRecipe(filename); } if (recipeText != "") { DynamicCharacterAvatar.LoadOptions thisLoadOptions = DynamicCharacterAvatar.LoadOptions.useDefaults; if (_loadRace || _loadDNA || _loadWardrobe || _loadBodyColors || _loadWardrobeColors) { if(_loadRace) thisLoadOptions |= DynamicCharacterAvatar.LoadOptions.loadRace; if (_loadDNA) thisLoadOptions |= DynamicCharacterAvatar.LoadOptions.loadDNA; if (_loadWardrobe) thisLoadOptions |= DynamicCharacterAvatar.LoadOptions.loadWardrobe; if (_loadBodyColors) thisLoadOptions |= DynamicCharacterAvatar.LoadOptions.loadBodyColors; if (_loadWardrobeColors) thisLoadOptions |= DynamicCharacterAvatar.LoadOptions.loadWardrobeColors; thisLoadOptions &= ~DynamicCharacterAvatar.LoadOptions.useDefaults; } Avatar.LoadFromRecipeString(recipeText, thisLoadOptions); } } public void SaveFile(InputField inputField) { var thisFilename = inputField.text; if (thisFilename != "") { thisFilename = Path.GetFileNameWithoutExtension(thisFilename.Replace(" ", "")); if (Debug.isDebugBuild) Debug.Log("Saved File with filename " + thisFilename); Avatar.saveFilename = thisFilename; DynamicCharacterAvatar.SaveOptions thisSaveOptions = DynamicCharacterAvatar.SaveOptions.useDefaults; if (_saveDNA || _saveWardrobe || _saveColors) { if (_saveDNA) thisSaveOptions |= DynamicCharacterAvatar.SaveOptions.saveDNA; if (_saveWardrobe) thisSaveOptions |= DynamicCharacterAvatar.SaveOptions.saveWardrobe; if (_saveColors) thisSaveOptions |= DynamicCharacterAvatar.SaveOptions.saveColors; thisSaveOptions &= ~DynamicCharacterAvatar.SaveOptions.useDefaults; } Avatar.DoSave(false,"", thisSaveOptions); } StartCoroutine(FinishSaveFile()); } IEnumerator FinishSaveFile() { yield return new WaitForSeconds(1f); saveCompleteBut.interactable = true; saveCompleteBut.onClick.Invoke(); } #endregion } }