private void DoUpgrade() { var originalName = _target.gameObject.name; DynamicDNAConverterController newController = _target.DoUpgrade(); if (newController != null) { drawAsLegacy = true; EditorGUIUtility.PingObject(newController); EditorUtility.DisplayDialog("Upgrade Complete!", "Your SkeletonModifiers and StartingPose (if set) can now be found in the new 'Converter Controller'. The old " + originalName + " has been stored in a 'LegacyDNA' folder", "Got it!"); //We need to make the new asset the one that ConverterCustomizer is inspecting if it was inspecting the old one if (thisDDCC != null) { for (int i = 0; i < thisDDCC.availableConverters.Count; i++) { if (thisDDCC.availableConverters[i] is DynamicDNAConverterBehaviour && (thisDDCC.availableConverters[i] as DynamicDNAConverterBehaviour) == _target) { thisDDCC.availableConverters[i] = newController; } } if (thisDDCC.selectedConverter is DynamicDNAConverterBehaviour && (thisDDCC.selectedConverter as DynamicDNAConverterBehaviour) == _target) { thisDDCC.selectedConverter = newController; } } //otherwise select the new controller so it shows in the inspector else { Selection.activeObject = newController; } } }
private void DrawObjectReferenceField(Rect position, SerializedProperty property, GUIContent label) { Vector2 iconSize = EditorGUIUtility.GetIconSize(); EditorGUIUtility.SetIconSize(new Vector2(12f, 12f)); DynamicDNAConverterController converterControllerObject = null; if (property.objectReferenceValue != null) { converterControllerObject = property.objectReferenceValue.GetType() == typeof(DynamicDNAConverterController) ? property.objectReferenceValue as DynamicDNAConverterController : null; } var dummyFieldStyle = new GUIStyle(EditorStyles.objectField); //could be objectFieldMiniThumb dummyFieldStyle.normal.background = null; var labelPos = new Rect(position.xMin, position.yMin, EditorGUIUtility.labelWidth, position.height); var fieldPos = new Rect(labelPos.xMax, position.yMin, position.width - labelPos.width, position.height); //unfortunately we can use PrefixLabel because it inherits the GUI.content color of the field (which is transparent) //the result is the label doesn't highlight- but I think we can live with that! EditorGUI.LabelField(labelPos, label); var prevContentColor = GUI.contentColor; GUI.contentColor = new Color(0, 0, 0, 0); //hide the content of the field so we can use our own label EditorGUI.BeginChangeCheck(); //We use a converterController field rather than an object field so that the 'dot' button shows ConverterControllers when clicked converterControllerObject = (DynamicDNAConverterController)EditorGUI.ObjectField(fieldPos, "", converterControllerObject, typeof(DynamicDNAConverterController), false); if (EditorGUI.EndChangeCheck()) { property.objectReferenceValue = converterControllerObject; } GUI.contentColor = prevContentColor; Rect dropRect = fieldPos; dropRect.width = dropRect.width - 18f; System.Type fieldType = typeof(DynamicDNAConverterController); if (property.objectReferenceValue != null) { fieldType = property.objectReferenceValue.GetType(); } GUIContent typeContent = EditorGUIUtility.ObjectContent(property.objectReferenceValue, fieldType); if (property.objectReferenceValue == null) { typeContent.text = "None (DNAConverterController/Behaviour)"; typeContent.image = null; } GUI.Box(dropRect, typeContent, dummyFieldStyle); DoDropArea(dropRect, property); EditorGUIUtility.SetIconSize(iconSize); }
private bool Init() { if (!_initialized) { bool stylesSet = false; if (EditorStyles.helpBox == null || EditorStyles.foldout == null || EditorStyles.label == null) { //Dont set any styles } else { //Style for subHeaders _subHeaderStyle = new GUIStyle(EditorStyles.helpBox); _subHeaderStyle.margin = new RectOffset(_subHeaderStyle.margin.left, _subHeaderStyle.margin.right, _subHeaderStyle.margin.top, 0); //Style for Tips _foldoutTipStyle = new GUIStyle(EditorStyles.foldout); _foldoutTipStyle.fontStyle = FontStyle.Bold; //Help Icon & style _helpIcon = EditorGUIUtility.FindTexture("_Help"); _helpStyle = new GUIStyle(EditorStyles.label); _helpStyle.fixedHeight = _helpIcon.height + 4f; _helpStyle.contentOffset = new Vector2(-4f, 0f); //Styles for the Add Converter area var reorderableListDefaults = new ReorderableList.Defaults(); _pluginChooserAreaStyle = new GUIStyle(reorderableListDefaults.boxBackground); _pluginChooserAreaStyle.margin = new RectOffset(4, 4, 2, 2); _pluginChooserAreaStyle.stretchHeight = false; _pluginChooserAreaStyle.padding = new RectOffset(8, 8, 4, 8); _pluginsByDNAAreaStyle = new GUIStyle(EditorStyles.textField); _pluginsByDNAAreaStyle.margin = new RectOffset(0, 0, 0, 0); _pluginsByDNAAreaStyle.padding = new RectOffset(4, 4, 4, 4); stylesSet = true; } _initialized = stylesSet; _target = target as DynamicDNAConverterController; _dnaAsset = _target.DNAAsset; InitPlugins(); } return(_initialized); }
/// <summary> /// Replaces all references to this asset in RaceDatas and SlotDataAssets with a reference to the given DynamicDNAConverterController /// </summary> /// <param name="replacingAsset"></param> public void FindAndReplaceUsage(DynamicDNAConverterController replacingAsset) { if (replacingAsset == null) { Debug.LogWarning("Could not find and replace usage of the behaviour because nor replacement was supplied"); return; } var original = this; //In Unity 2018.3+ this asset may be being inspected in its own Prefab scene (rather than via customizer). //If that is the case 'this' will be a clone rather than the object that is actually assigned to Races/Slots, so... #if UNITY_2018_3_OR_NEWER var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetPrefabStage(this.gameObject); if (prefabStage != null) { var origGO = (GameObject)AssetDatabase.LoadAssetAtPath(prefabStage.prefabAssetPath, typeof(GameObject)); if (origGO != null && origGO.GetComponent <DynamicDNAConverterBehaviour>() != null) { original = origGO.GetComponent <DynamicDNAConverterBehaviour>(); } } #endif if (original == null) { Debug.LogWarning("Could not find and replace usage of the behaviour because the original could not be determined"); return; } string[] raceGuids = AssetDatabase.FindAssets("t:RaceData", null); string[] slotGuids = AssetDatabase.FindAssets("t:SlotDataAsset", null); string[] rangeGuids = AssetDatabase.FindAssets("t:DNARangeAsset", null); int updatedRaces = 0; int updatedSlots = 0; int updatedRanges = 0; //store for found items so we dont gobble memory RaceData foundRace; SlotDataAsset foundSlot; DNARangeAsset foundDNARange; //Find races that need updating for (int i = 0; i < raceGuids.Length; i++) { foundRace = (RaceData)AssetDatabase.LoadAssetAtPath((AssetDatabase.GUIDToAssetPath(raceGuids[i])), typeof(RaceData)); if (foundRace) { if (foundRace.UpgradeFromLegacy(original, replacingAsset)) { Debug.Log("RaceData: " + foundRace.raceName + " was updated to use new ConverterController " + replacingAsset.name); EditorUtility.SetDirty(foundRace); updatedRaces++; } } } //Find slots that need Updating for (int i = 0; i < slotGuids.Length; i++) { foundSlot = (SlotDataAsset)AssetDatabase.LoadAssetAtPath((AssetDatabase.GUIDToAssetPath(slotGuids[i])), typeof(SlotDataAsset)); if (foundSlot) { if (foundSlot.UpgradeFromLegacy(original, replacingAsset)) { Debug.Log("SlotData: " + foundSlot.slotName + " was updated to use new ConverterController " + replacingAsset.name); EditorUtility.SetDirty(foundSlot); updatedSlots++; } } } //Find DNARangeAssets that need updating for (int i = 0; i < rangeGuids.Length; i++) { foundDNARange = (DNARangeAsset)AssetDatabase.LoadAssetAtPath((AssetDatabase.GUIDToAssetPath(slotGuids[i])), typeof(DNARangeAsset)); if (foundDNARange) { if (foundDNARange.UpgradeFromLegacy(original, replacingAsset)) { Debug.Log("DNARangeAsset: " + foundDNARange.name + " was updated to use new ConverterController " + replacingAsset.name); EditorUtility.SetDirty(foundDNARange); updatedRanges++; } } } var processCompleteMessage = updatedRaces + " RaceDatas, " + updatedSlots + " SlotDataAssets, and " + updatedRanges + " DNARangeAssets were updated to use the new controller (" + replacingAsset.name + ")"; Debug.Log("DynamicDNAConverterBehaviour FindAndReplaceUsage: " + processCompleteMessage); UnityEditor.EditorUtility.DisplayDialog("Find and Replace Complete!", processCompleteMessage, "Ok, Great"); }
/// <summary> /// Upgrades a DynamicDNAConverter Prefab to a new ConverterController asset and replaces any usage of the old asset. Stores the original asset in a relative 'Legacy' folder. /// </summary> /// <returns>Returns the path of the new converterController asset</returns> public DynamicDNAConverterController DoUpgrade() { var DCBPath = AssetDatabase.GetAssetPath(this.gameObject); //In Unity 2018.3+ this asset may be being inspected in its own Prefab scene (rather than via customizer). //If that is the case we need to get the path differently #if UNITY_2018_3_OR_NEWER var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetPrefabStage(this.gameObject); if (prefabStage != null) { DCBPath = prefabStage.prefabAssetPath; } #endif if (string.IsNullOrEmpty(DCBPath)) { Debug.LogWarning("Upgrade could not be completed. Could not get asset path for the DNAConverterBehaviour to upgrade"); return(null); } var newControllerName = this.name.Replace("DynamicDNAConverterBehaviour", "").Replace("DynamicDNAConverter", "").Replace("DNAConverterBehaviour", "").Replace("ConverterBehaviour", "").Replace("Legacy", ""); if (_converterController != null) { Debug.LogWarning("Upgrading " + this.gameObject.name + " failed because it already references a previously converted version. If you need to Upgrade again please inspect this assets 'Legacy Settings' and click 'Revert To Legacy Settings'"); return(null); } DynamicDNAConverterController newController = null; DynamicDNAPlugin skelModsPlug = null; DynamicDNAPlugin startingPosePlug = null; newControllerName += "DNAConverterController"; var path = DCBPath; path = path.Replace("/" + Path.GetFileName(path), ""); var assetPathAndName = AssetDatabase.GenerateUniqueAssetPath(path + "/" + newControllerName + ".asset"); newController = DynamicDNAConverterController.CreateDynamicDNAConverterControllerAsset(assetPathAndName, false); if (newController == null) { //bail if the converterController was not created Debug.LogWarning("DynamicDNAConverterBehaviour BackupAndUpgrade failed because it was unable to create the new ConverterController."); return(null); } //Add skeletonModifiers if (_skeletonModifiers.Count > 0) { skelModsPlug = newController.AddPlugin(typeof(SkeletonDNAConverterPlugin)); if (!((SkeletonDNAConverterPlugin)skelModsPlug).ImportSettings(this.gameObject, 0)) { Debug.LogWarning("Your SkeletonModifiers did not import correctly into the new plugin. Please try importing then manually"); } } //Add startingPose if (_startingPose != null) { startingPosePlug = newController.AddPlugin(typeof(BonePoseDNAConverterPlugin)); if (((BonePoseDNAConverterPlugin)startingPosePlug).ImportSettings(this.gameObject, 0)) { Debug.LogWarning("Your StartingPose did not import correctly into the new plugin. Please try importing it manually"); } } //Import the rest of our data newController.ImportConverterBehaviourData(this); //Set this last because the backwards compatible public properties get values from it if its set _converterController = newController; EditorUtility.SetDirty(newController); if (skelModsPlug != null) { EditorUtility.SetDirty(skelModsPlug); } if (startingPosePlug != null) { EditorUtility.SetDirty(startingPosePlug); } //Find and replace the usage of this FindAndReplaceUsage(newController); //If this asset is not inside a 'LegacyDNA' folder move it inside one //We need to keep the old one because downloaded content may still require it //The RaceDatas and SlotDataAssets will warn the user if they are using a legacy DynamicDNAConverterBehaviour var DCBFilename = System.IO.Path.GetFileName(DCBPath); string moveAssetResult = ""; #pragma warning disable 0219 string newDCBPath = DCBPath; #pragma warning restore if (DCBPath.IndexOf("LegacyDNA" + "/" + DCBFilename) == -1) { var DCBDir = System.IO.Path.GetDirectoryName(DCBPath); if (!AssetDatabase.IsValidFolder(DCBDir + "/" + "LegacyDNA")) { AssetDatabase.CreateFolder(DCBDir, "LegacyDNA"); } if (DCBFilename.IndexOf("Legacy") == -1) { DCBFilename = System.IO.Path.GetFileNameWithoutExtension(DCBPath) + " Legacy" + System.IO.Path.GetExtension(DCBPath); } moveAssetResult = AssetDatabase.MoveAsset(DCBPath, DCBDir + "/" + "LegacyDNA" + "/" + DCBFilename); if (string.IsNullOrEmpty(moveAssetResult)) { newDCBPath = DCBDir + "/" + "LegacyDNA" + "/" + DCBFilename; } } if (!string.IsNullOrEmpty(moveAssetResult)) { Debug.LogWarning(moveAssetResult); } #if UNITY_2018_3_OR_NEWER //If this happenned in a prefab stage (rather than via customizer) it wont save the prefab with the added converterController so if (prefabStage != null) { PrefabUtility.SaveAsPrefabAsset(this.gameObject, newDCBPath); } #endif EditorUtility.SetDirty(this.gameObject); AssetDatabase.SaveAssets(); return(_converterController); }
void OnUpdate() { if (haveValidContext) { if (activeBoneIndex != editBoneIndex) { activeBoneIndex = BAD_INDEX; mirrorBoneIndex = BAD_INDEX; if (editBoneIndex != BAD_INDEX) { int boneHash = targetPose.poses[editBoneIndex].hash; context.activeTransform = context.activeUMA.skeleton.GetBoneTransform(boneHash); if (context.activeTransform != null) { activeBoneIndex = editBoneIndex; } if (context.mirrorTransform != null) { int mirrorHash = UMASkeleton.StringToHash(context.mirrorTransform.name); for (int i = 0; i < targetPose.poses.Length; i++) { if (targetPose.poses[i].hash == mirrorHash) { mirrorBoneIndex = i; break; } } } } else { context.activeTransform = null; } } if (!dynamicDNAConverterMode) { context.activeUMA.skeleton.ResetAll(); if (context.startingPose != null) { context.startingPose.ApplyPose(context.activeUMA.skeleton, context.startingPoseWeight); } foreach (IDNAConverter id in context.activeUMA.umaRecipe.raceData.dnaConverterList) { if (id is DynamicDNAConverterController) { DynamicDNAConverterController Dcc = id as DynamicDNAConverterController; List <DynamicDNAPlugin> LBpp = Dcc.GetPlugins(typeof(BonePoseDNAConverterPlugin)); foreach (DynamicDNAPlugin ddp in LBpp) { BonePoseDNAConverterPlugin bc = ddp as BonePoseDNAConverterPlugin; foreach (BonePoseDNAConverterPlugin.BonePoseDNAConverter converter in bc.poseDNAConverters) { converter.poseToApply.ApplyPose(context.activeUMA.skeleton, converter.startingPoseWeight); } } Dcc.overallModifiers.UpdateCharacter(context.activeUMA, context.activeUMA.skeleton, false); } } if (haveEditTarget) { targetPose.ApplyPose(context.activeUMA.skeleton, 1f); } else { targetPose.ApplyPose(context.activeUMA.skeleton, previewWeight); } } else { //TODO //how do we deal with poses that are not applied? The user will see the character in its current pose and bone positions for that //which makes no sense //also because this will be hooked up to dna, the dna itself might be causing other changes to happen ('overallScale' for example) //So I think the editor for bonePoseConverters, needs to jump in here and ask the user if they want to apply the dna that makes the pose active? //OR //maybe we create a skeleton how it would be IF the pose was applied to it and the user edits those transforms? //If the pose is applied they will see their character change, if its not it might be clearer that is the case } } if (!Application.isPlaying) { _livePopupEditor = null; } }
private void CreateBonePoseCallback(UMAData umaData) { UMA.PoseTools.UMABonePose bonePose = CreatePoseAsset("", bonePoseSaveName); //I dont think this should have ever overwritten the existing one /*if (selectedConverter.startingPose == null) * { * bonePose = CreatePoseAsset("", bonePoseSaveName); * } * else * { * bonePose = selectedConverter.startingPose; * bonePose.poses = new UMABonePose.PoseBone[1]; * }*/ UMASkeleton skeletonPreDNA = tempAvatarPreDNA.GetComponent <UMADynamicAvatar>().umaData.skeleton; UMASkeleton skeletonPostDNA = tempAvatarPostDNA.GetComponent <UMADynamicAvatar>().umaData.skeleton; Transform transformPreDNA; Transform transformPostDNA; bool transformDirty; int parentHash; foreach (int boneHash in skeletonPreDNA.BoneHashes) { skeletonPreDNA.TryGetBoneTransform(boneHash, out transformPreDNA, out transformDirty, out parentHash); skeletonPostDNA.TryGetBoneTransform(boneHash, out transformPostDNA, out transformDirty, out parentHash); if ((transformPreDNA == null) || (transformPostDNA == null)) { Debug.LogWarning("Bad bone hash in skeleton: " + boneHash); continue; } if (!LocalTransformsMatch(transformPreDNA, transformPostDNA)) { bonePose.AddBone(transformPreDNA, transformPostDNA.localPosition, transformPostDNA.localRotation, transformPostDNA.localScale); } } UMAUtils.DestroySceneObject(tempAvatarPreDNA); UMAUtils.DestroySceneObject(tempAvatarPostDNA); // This can be very helpful for testing /* * bonePose.ApplyPose(skeletonPreDNA, 1.0f); */ EditorUtility.SetDirty(bonePose); AssetDatabase.SaveAssets(); if (_applyAndResetOnCreateBP) { DynamicDNAConverterController converterController = (selectedConverter is DynamicDNAConverterController) ? (selectedConverter as DynamicDNAConverterController) : null; DynamicDNAConverterBehaviour converterBehaviour = (selectedConverter is DynamicDNAConverterBehaviour) ? (selectedConverter as DynamicDNAConverterBehaviour) : null; //UMA2.8+ fixDNAPrefabs Removed the converterBehaviour.ConverterController field, it should be directly assigned to the Races/Slots now //if (converterBehaviour.ConverterController != null) // converterController = converterBehaviour.ConverterController; if (converterController != null) { //find the first BonePoseDNAConverterPlugin and add the pose to it var existingBPCPs = converterController.GetPlugins(typeof(BonePoseDNAConverterPlugin)); BonePoseDNAConverterPlugin thisBPCP; if (existingBPCPs.Count > 0) { thisBPCP = existingBPCPs[0] as BonePoseDNAConverterPlugin; //Turn off any other starting poses? for (int i = 0; i < existingBPCPs.Count; i++) { for (int bi = 0; bi < (existingBPCPs[i] as BonePoseDNAConverterPlugin).poseDNAConverters.Count; bi++) { (existingBPCPs[i] as BonePoseDNAConverterPlugin).poseDNAConverters[bi].startingPoseWeight = 0f; } } } else { //if there isn't one create it thisBPCP = converterController.AddPlugin(typeof(BonePoseDNAConverterPlugin)) as BonePoseDNAConverterPlugin; } thisBPCP.poseDNAConverters.Add(new BonePoseDNAConverterPlugin.BonePoseDNAConverter(bonePose, 1f)); Debug.Log(bonePose.name + " added as a starting pose to " + thisBPCP.name); } else if (converterBehaviour != null) { // Set this asset as the converters pose asset converterBehaviour.startingPose = bonePose; //make sure its fully applied converterBehaviour.startingPoseWeight = 1f; } // Reset all the DNA values for target Avatar to default UMADnaBase[] targetDNA = activeUMA.umaData.GetAllDna(); foreach (UMADnaBase dnaEntry in targetDNA) { for (int i = 0; i < dnaEntry.Values.Length; i++) { dnaEntry.SetValue(i, 0.5f); } } // Optionally clear the DNA from the base recipe, // since it's now included in the new starting pose UMARecipeBase baseRaceRecipe = activeUMA.umaData.umaRecipe.GetRace().baseRaceRecipe; if (baseRaceRecipe != null) { if (EditorUtility.DisplayDialog("Base Recipe Cleanup", "Starting Pose created. Remove DNA from base recipe of active race? Choose 'RemoveDNA' if your intention is to replace modifications made by a recipes starting DNA values with the created pose.", "Remove DNA", "Keep DNA")) { UMAData.UMARecipe baseRecipeData = new UMAData.UMARecipe(); baseRaceRecipe.Load(baseRecipeData, activeUMA.context); baseRecipeData.ClearDna(); baseRaceRecipe.Save(baseRecipeData, activeUMA.context); } } } }
public static void CreateDynamicDNAConverterController() { DynamicDNAConverterController.CreateDynamicDNAConverterControllerAsset(); }