Skip to content

Instantly share code, notes, and snippets.

@naelstrof
Created April 8, 2018 23:07
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save naelstrof/be215b5a5212dca88d5e45dc0102be1d to your computer and use it in GitHub Desktop.
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.
#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
@migero
Copy link

migero commented Aug 25, 2019

CopyAvatarData.cs(95,44): error CS0030: Cannot convert type DynamicBoneCollider' to DynamicBoneColliderBase'
CopyAvatarData.cs(98,20): error CS0029: Cannot implicitly convert type System.Collections.Generic.List<DynamicBoneColliderBase>' to System.Collections.Generic.List'

unity 2017.4.28f1

@naelstrof
Copy link
Author

CopyAvatarData.cs(95,44): error CS0030: Cannot convert type DynamicBoneCollider' to DynamicBoneColliderBase'
CopyAvatarData.cs(98,20): error CS0029: Cannot implicitly convert type System.Collections.Generic.List<DynamicBoneColliderBase>' to System.Collections.Generic.List'

unity 2017.4.28f1

You need dynamic bones, sorry. I think I've updated this script too. I'll check in a sec

@3dcinetv
Copy link

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