Created
April 8, 2018 23:07
-
-
Save naelstrof/be215b5a5212dca88d5e45dc0102be1d to your computer and use it in GitHub Desktop.
Copies all avatar components and children to another object. Such as Dynamic Bones, Guns, Animations, etc.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if UNITY_EDITOR | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEditor; | |
using System.Text.RegularExpressions; | |
public class CopyAvatarData : ScriptableWizard { | |
public GameObject from; | |
public GameObject to; | |
bool finished; | |
enum Options { AvatarDescriptor = 1, | |
DynamicBones = 2, | |
Animators = 4, | |
LooseGameObjects = 8 | |
}; | |
Options selected; | |
public CopyAvatarData() { | |
finished = false; | |
} | |
Component CopyComponent(Component original, GameObject destination) { | |
System.Type type = original.GetType(); | |
Component copy = destination.AddComponent(type); | |
// Copied fields can be restricted with BindingFlags | |
System.Reflection.FieldInfo[] fields = type.GetFields(); | |
foreach (System.Reflection.FieldInfo field in fields) | |
{ | |
field.SetValue(copy, field.GetValue(original)); | |
} | |
return copy; | |
} | |
[MenuItem("VRChat SDK/Copy Avatar Attributes to Other")] | |
static void CreateWizard() { | |
CopyAvatarData wiz = ScriptableWizard.DisplayWizard<CopyAvatarData>("Transfer Avatar Data"); | |
} | |
// Ensures that game object to and from have an identical hierarchy with the same components and the same properties on the components. | |
void CopyComponents( string current, GameObject obj, Options flags ) { | |
GameObject target = null; | |
if (current == "") { | |
target = to; | |
} else { | |
Transform test = to.transform.Find (current); | |
if (test) { | |
target = test.gameObject; | |
} | |
} | |
if (!target) { | |
string sparent = current.Substring (0, current.LastIndexOf ("/")); | |
Transform test = to.transform.Find (sparent); | |
GameObject parent = test ? test.gameObject : null; | |
if (!parent) { | |
throw new UnityException ("Somehow tried to create child " + current + ", but couldn't find " + current.Substring (0, current.LastIndexOf ("/"))); | |
} | |
GameObject copy = GameObject.Instantiate (obj); | |
copy.name = obj.name; | |
copy.transform.SetParent (parent.transform); | |
copy.transform.localPosition = obj.transform.localPosition; | |
copy.transform.localRotation = obj.transform.localRotation; | |
copy.transform.localScale = obj.transform.localScale; | |
} else { | |
foreach (Component c in obj.GetComponents<Component>()) { | |
CopyComponent (c, target); | |
} | |
} | |
for (int i = 0; i < obj.transform.childCount; i++) { | |
if (current != "") { | |
CopyComponents (current + "/" + obj.transform.GetChild (i).name, obj.transform.GetChild (i).gameObject, flags); | |
} else { | |
CopyComponents (obj.transform.GetChild (i).name, obj.transform.GetChild (i).gameObject, flags); | |
} | |
} | |
} | |
Transform RecurseFind( Transform obj, string name ) { | |
Transform find = obj.Find (name); | |
if (find) { | |
return find; | |
} | |
for( int i=0;i<obj.childCount;i++ ) { | |
find = RecurseFind (obj.GetChild (i), name); | |
if (find) { | |
return find; | |
} | |
} | |
return null; | |
} | |
// Updates dynamic bone references to refer to the new avatar bones rather than the old ones. | |
void ConvertDynamicBoneReferences() { | |
foreach (DynamicBone d in to.GetComponentsInChildren<DynamicBone>()) { | |
List<DynamicBoneColliderBase> newColliders = new List<DynamicBoneColliderBase> (); | |
foreach (DynamicBoneColliderBase c in d.m_Colliders) { | |
newColliders.Add (RecurseFind(to.transform,c.gameObject.name).gameObject.GetComponent<DynamicBoneColliderBase> ()); | |
} | |
d.m_Colliders = newColliders; | |
List<Transform> newExclusions = new List<Transform> (); | |
foreach (Transform t in d.m_Exclusions) { | |
newExclusions.Add (RecurseFind(to.transform,t.name)); | |
} | |
d.m_Exclusions = newExclusions; | |
d.m_Root = RecurseFind (to.transform, d.m_Root.name); | |
} | |
} | |
void ConvertAvatarDescriptor() { | |
VRCSDK2.VRC_AvatarDescriptor ava = to.GetComponent<VRCSDK2.VRC_AvatarDescriptor> (); | |
ava.VisemeSkinnedMesh = to.GetComponentInChildren<SkinnedMeshRenderer> (); | |
} | |
void OnGUI() { | |
EditorGUILayout.HelpBox ("This will mess with your `To` game object, it's destructive!", MessageType.Warning); | |
from = (GameObject)EditorGUILayout.ObjectField("From", from, typeof(GameObject), true); | |
to = (GameObject)EditorGUILayout.ObjectField("To", to, typeof(GameObject), true); | |
selected = (Options)EditorGUILayout.EnumMaskPopup ("Stuff to transfer (Does nothing):", selected); | |
if (from && to && GUILayout.Button ("Transfer!")) { | |
CopyComponents ("", from, selected); | |
ConvertDynamicBoneReferences (); | |
ConvertAvatarDescriptor (); | |
finished = true; | |
} | |
if (finished) { | |
EditorGUILayout.Space (); | |
EditorGUILayout.HelpBox ("Done! :)", MessageType.Info); | |
} | |
} | |
} | |
#endif |
Does it work to copy 1 VRM model with VRMSpring bones script to another vrm model? or does the script just works for dynamic bones script only?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You need dynamic bones, sorry. I think I've updated this script too. I'll check in a sec