Загрузка данных
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
#if UNITY_EDITOR
public class AvatarTransfer : MonoBehaviour
{
[Header("Source → Target")]
public GameObject source; // Kipfelv20
public GameObject target; // Kipfel
[ContextMenu("Transfer Everything")]
public void TransferEverything()
{
if (source == null || target == null)
{
Debug.LogError("Назначь Source и Target!");
return;
}
Undo.RegisterCompleteObjectUndo(target, "Avatar Transfer");
// 1. Копируем все дочерние объекты (одежда, волосы, аксессуары и т.д.)
TransferChildren(source.transform, target.transform);
// 2. Копируем Animator + Avatar
TransferAnimator(source, target);
// 3. Копируем все SkinnedMeshRenderer + BlendShapes
TransferSkinnedMeshes(source, target);
// 4. Копируем обычные MeshRenderer
TransferMeshRenderers(source, target);
// 5. Копируем PhysBones / Constraints / Colliders и прочие компоненты
TransferComponents(source, target);
Debug.Log("<color=lime>Перенос завершён!</color>");
EditorUtility.SetDirty(target);
}
void TransferChildren(Transform srcRoot, Transform dstRoot)
{
// Удаляем всё, что уже есть на таргете (кроме арматуры)
List<Transform> toDestroy = new List<Transform>();
foreach (Transform child in dstRoot)
{
if (child.name != "Armature" && child.name != "armature" &&
!child.name.ToLower().Contains("body") &&
!child.name.ToLower().Contains("hips"))
{
toDestroy.Add(child);
}
}
foreach (var t in toDestroy) DestroyImmediate(t.gameObject);
// Копируем все дочерние объекты с сорса
foreach (Transform child in srcRoot)
{
if (child.name.ToLower().Contains("armature") ||
child.name.ToLower().Contains("body") ||
child.name.ToLower().Contains("hips") ||
child.name.ToLower().Contains("spine"))
continue; // арматуру не трогаем
GameObject copy = Instantiate(child.gameObject, dstRoot);
copy.name = child.name;
copy.transform.localPosition = child.localPosition;
copy.transform.localRotation = child.localRotation;
copy.transform.localScale = child.localScale;
}
}
void TransferAnimator(GameObject src, GameObject dst)
{
Animator srcAnim = src.GetComponent<Animator>();
if (srcAnim == null) return;
Animator dstAnim = dst.GetComponent<Animator>();
if (dstAnim == null) dstAnim = dst.AddComponent<Animator>();
dstAnim.runtimeAnimatorController = srcAnim.runtimeAnimatorController;
dstAnim.avatar = srcAnim.avatar;
dstAnim.applyRootMotion = srcAnim.applyRootMotion;
dstAnim.updateMode = srcAnim.updateMode;
dstAnim.cullingMode = srcAnim.cullingMode;
}
void TransferSkinnedMeshes(GameObject src, GameObject dst)
{
SkinnedMeshRenderer[] srcMeshes = src.GetComponentsInChildren<SkinnedMeshRenderer>(true);
foreach (var srcMesh in srcMeshes)
{
// Ищем такой же объект на таргете по имени
Transform dstTr = FindChildRecursive(dst.transform, srcMesh.name);
if (dstTr == null)
{
// Если не нашли — создаём
GameObject go = new GameObject(srcMesh.name);
go.transform.SetParent(dst.transform);
go.transform.localPosition = srcMesh.transform.localPosition;
go.transform.localRotation = srcMesh.transform.localRotation;
go.transform.localScale = srcMesh.transform.localScale;
dstTr = go.transform;
}
SkinnedMeshRenderer dstMesh = dstTr.GetComponent<SkinnedMeshRenderer>();
if (dstMesh == null) dstMesh = dstTr.gameObject.AddComponent<SkinnedMeshRenderer>();
// Копируем всё
dstMesh.sharedMesh = srcMesh.sharedMesh;
dstMesh.sharedMaterials = srcMesh.sharedMaterials;
dstMesh.rootBone = FindBone(dst.transform, srcMesh.rootBone);
dstMesh.bones = srcMesh.bones.Select(b => FindBone(dst.transform, b)).ToArray();
dstMesh.updateWhenOffscreen = srcMesh.updateWhenOffscreen;
dstMesh.quality = srcMesh.quality;
dstMesh.skinnedMotionVectors = srcMesh.skinnedMotionVectors;
// BlendShapes
for (int i = 0; i < srcMesh.sharedMesh.blendShapeCount; i++)
{
float weight = srcMesh.GetBlendShapeWeight(i);
dstMesh.SetBlendShapeWeight(i, weight);
}
}
}
void TransferMeshRenderers(GameObject src, GameObject dst)
{
MeshRenderer[] srcRends = src.GetComponentsInChildren<MeshRenderer>(true);
foreach (var srcRend in srcRends)
{
Transform dstTr = FindChildRecursive(dst.transform, srcRend.name);
if (dstTr == null) continue;
MeshRenderer dstRend = dstTr.GetComponent<MeshRenderer>();
if (dstRend == null) dstRend = dstTr.gameObject.AddComponent<MeshRenderer>();
MeshFilter srcFilter = srcRend.GetComponent<MeshFilter>();
MeshFilter dstFilter = dstTr.GetComponent<MeshFilter>();
if (dstFilter == null) dstFilter = dstTr.gameObject.AddComponent<MeshFilter>();
if (srcFilter != null) dstFilter.sharedMesh = srcFilter.sharedMesh;
dstRend.sharedMaterials = srcRend.sharedMaterials;
}
}
void TransferComponents(GameObject src, GameObject dst)
{
// Копируем все компоненты с корня
Component[] components = src.GetComponents<Component>();
foreach (var comp in components)
{
if (comp is Transform || comp is Animator) continue;
// Пробуем скопировать
System.Type type = comp.GetType();
Component newComp = dst.GetComponent(type);
if (newComp == null) newComp = dst.AddComponent(type);
// Копируем через SerializedObject (самый надёжный способ)
EditorUtility.CopySerialized(comp, newComp);
}
}
Transform FindChildRecursive(Transform parent, string name)
{
if (parent.name == name) return parent;
foreach (Transform child in parent)
{
Transform found = FindChildRecursive(child, name);
if (found != null) return found;
}
return null;
}
Transform FindBone(Transform root, Transform originalBone)
{
if (originalBone == null) return null;
return FindChildRecursive(root, originalBone.name);
}
}
#endif