284 lines
11 KiB
C#
284 lines
11 KiB
C#
using System.IO;
|
|
using System.Linq;
|
|
using artcfg.ArtDesign;
|
|
using Framework;
|
|
using MagicaCloth2;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
// ReSharper disable IdentifierTypo
|
|
|
|
namespace Art.temp.Editor.PrefabTool
|
|
{
|
|
public class CharacterAssetInfo
|
|
{
|
|
private readonly string nameId;
|
|
private readonly string personId;
|
|
private readonly string folderId;
|
|
private readonly string category;
|
|
|
|
public CharacterAssetInfo(string nameId, string category)
|
|
{
|
|
this.nameId = nameId; // AA01001
|
|
this.category = category;
|
|
char[] chars = nameId.ToCharArray();
|
|
chars[nameId.Length - 4] = '0';
|
|
personId = new string(chars);
|
|
folderId = new string(chars)[^6..];
|
|
}
|
|
|
|
private const string Head = "Root/Bip001/Bip001 Spine/Bip001 Spine1/Bip001 Neck/Bip001 Head/";
|
|
|
|
private const string Grip01 =
|
|
"Root/Bip001/Bip001 Spine/Bip001 Spine1/Bip001 R Clavicle/Bip001 R UpperArm/Bip001 R Forearm/Bip001 R Hand/Grip_point01/";
|
|
|
|
private const string Mount01 = "Root/Bip001/Bip001 Spine/Mount_point01/";
|
|
|
|
private const string AnimPath = "Assets/Art/Animations/Battle/Skill/ani_{0}_skill01.fbx";
|
|
private const string AutoPath = "Assets/Art_Out/AutoGen/Characters/character_{0}_{1}/character_{0}.prefab";
|
|
private const string ModelPath = "Assets/Art/Character/Models/{0}/{1}/{2}.fbx";
|
|
private const string PrefabPath = "Assets/Art/Character/Prefabs/{0}/P_{1}.prefab";
|
|
private const string DisplayPath = "Assets/Art/Character/Prefabs/{0}_S/P_S_{1}.prefab";
|
|
private const string BodyMaterialPath = "Assets/Art/Character/Models/{0}/{1}/Mat/M_{2}_body_01_Display.mat";
|
|
|
|
private DataPerson DataPerson =>
|
|
ArtTableManager.instance.tables.PersonConfig.DataList.FirstOrDefault(a => a.NameId == personId);
|
|
|
|
public GameObject Model =>
|
|
AssetDatabase.LoadAssetAtPath<GameObject>(string.Format(ModelPath, category, folderId, nameId));
|
|
|
|
private Material DisplayBodyMaterial =>
|
|
AssetDatabase.LoadAssetAtPath<Material>(string.Format(BodyMaterialPath, category, folderId, nameId));
|
|
|
|
public GameObject Prefab =>
|
|
AssetDatabase.LoadAssetAtPath<GameObject>(string.Format(PrefabPath, category, nameId));
|
|
|
|
public GameObject DisplayPrefab =>
|
|
AssetDatabase.LoadAssetAtPath<GameObject>(string.Format(DisplayPath, category, nameId));
|
|
|
|
public GameObject AutoPrefab =>
|
|
AssetDatabase.LoadAssetAtPath<GameObject>(string.Format(AutoPath, nameId, DataPerson.WeaponId));
|
|
|
|
public Object Skill => AssetDatabase.LoadAssetAtPath<Object>(string.Format(AnimPath, personId));
|
|
|
|
public GameObject objInstance;
|
|
|
|
// rebuild prefab and display prefab
|
|
public void Rebuild()
|
|
{
|
|
if (Model == null)
|
|
{
|
|
Debug.LogWarning("基础信息不正确,找不到模型文件");
|
|
return;
|
|
}
|
|
|
|
// preset model
|
|
var objPath = AssetDatabase.GetAssetPath(Model);
|
|
var modelImporter = AssetImporter.GetAtPath(objPath) as ModelImporter;
|
|
if (modelImporter != null)
|
|
{
|
|
modelImporter.avatarSetup = ModelImporterAvatarSetup.CreateFromThisModel;
|
|
AssetDatabase.Refresh();
|
|
modelImporter.SaveAndReimport();
|
|
}
|
|
|
|
// Create empty GameObject and parent instantiate asset to it.
|
|
GameObject prefab = new("P_S_" + nameId);
|
|
GameObject prefabInstance = (GameObject)PrefabUtility.InstantiatePrefab(Model, prefab.transform);
|
|
|
|
// Add emoji
|
|
Transform head = prefabInstance.transform.Find(Head);
|
|
GameObject emoji =
|
|
AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Art/Character/Models/Emoji/G_emoji.FBX");
|
|
GameObject emojiInstance = (GameObject)PrefabUtility.InstantiatePrefab(emoji);
|
|
emojiInstance.transform.parent = head;
|
|
|
|
// Add magicaCloth component.
|
|
AddMagicaCloth(prefab);
|
|
|
|
if (DataPerson is null)
|
|
{
|
|
Debug.LogWarning("无配置信息");
|
|
}
|
|
else
|
|
{
|
|
// add gun
|
|
if (DataPerson.WeaponId != "")
|
|
{
|
|
GunInfo gun = new("G" + DataPerson.WeaponId.PadLeft(5, '0'));
|
|
Transform grip = prefabInstance.transform.Find(Grip01);
|
|
if (grip == null)
|
|
{
|
|
Debug.LogError("没有武器挂点,终止");
|
|
return;
|
|
}
|
|
|
|
PrefabUtility.InstantiatePrefab(gun.Prefab, grip);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("未配置武器,跳过");
|
|
}
|
|
|
|
// add bag AA01001
|
|
var bagNameId = nameId[^4] == '0' ? DataPerson.Bag1 : DataPerson.Bag2;
|
|
|
|
if (bagNameId != "")
|
|
{
|
|
BagInfo bag = new(bagNameId);
|
|
Transform mount01 = prefabInstance.transform.Find(Mount01);
|
|
var bagInstance = (GameObject)PrefabUtility.InstantiatePrefab(bag.Prefab, mount01);
|
|
bagInstance.transform.GetChild(0).Find("B_Root").localEulerAngles = Vector3.zero;
|
|
}
|
|
|
|
// add animator controller
|
|
if (DataPerson.GroupName != "")
|
|
{
|
|
string groupName = DataPerson.GroupName[..3];
|
|
// ReSharper disable once StringLiteralTypo
|
|
string acPath =
|
|
$"Assets/Art/Animations/animator/display_ovrride_{groupName}.overrideController";
|
|
Debug.Log(DataPerson.GroupName + "<-set->" + groupName);
|
|
// config animator controller
|
|
Animator animator = prefabInstance.GetComponent<Animator>();
|
|
var controller = AssetDatabase.LoadAssetAtPath<RuntimeAnimatorController>(acPath);
|
|
if (controller)
|
|
{
|
|
animator.runtimeAnimatorController = controller;
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"没有找到 controller: {acPath}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"缺少武器模组配置,无法指定 controller");
|
|
}
|
|
}
|
|
|
|
|
|
// save to Player
|
|
string prefabPath = string.Format(PrefabPath, category, nameId);
|
|
PrefabUtility.SaveAsPrefabAsset(prefab, prefabPath);
|
|
Debug.Log(prefabPath);
|
|
|
|
// save to Player_S
|
|
if (Model.name.StartsWith("A"))
|
|
{
|
|
Transform body = prefabInstance.transform.Find($"G_{nameId}_body");
|
|
if (body == null)
|
|
{
|
|
Debug.LogError($"{nameId}: 无法找到 body mesh");
|
|
return;
|
|
}
|
|
|
|
if (DisplayBodyMaterial != null &&
|
|
DisplayBodyMaterial.shader == Shader.Find("NLD_URP/NLD_Charactor_Display"))
|
|
{
|
|
body.GetComponent<SkinnedMeshRenderer>().materials = new[] { DisplayBodyMaterial };
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"{nameId}: 缺少 display 材质");
|
|
}
|
|
}
|
|
|
|
string displayPath = string.Format(DisplayPath, category, nameId);
|
|
PrefabUtility.SaveAsPrefabAssetAndConnect(prefab, displayPath, InteractionMode.AutomatedAction);
|
|
Debug.Log(displayPath);
|
|
}
|
|
|
|
// ReSharper disable once IdentifierTypo
|
|
private static void AddMagicaCloth(GameObject go)
|
|
{
|
|
Transform assetInstance = go.transform.GetChild(0);
|
|
// root bone list
|
|
var allBones = assetInstance.GetComponentsInChildren<Transform>();
|
|
var dynamicBones = allBones.Where(x => x.name.Contains("Hair") || x.name.Contains("Fabric"));
|
|
var rootBones = dynamicBones.Where(x => x.parent.name.Contains("Bip001") && x.childCount != 0).ToArray();
|
|
|
|
if (!rootBones.Any())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// add new
|
|
GameObject magicaCloth = new("Magica Cloth")
|
|
{
|
|
transform =
|
|
{
|
|
parent = assetInstance.transform
|
|
}
|
|
};
|
|
MagicaCloth magicaClothComp = magicaCloth.AddComponent<MagicaCloth>();
|
|
|
|
// set boneCloth
|
|
magicaClothComp.SerializeData.clothType = ClothProcess.ClothType.BoneCloth;
|
|
magicaClothComp.SerializeData.rootBones = rootBones.ToList();
|
|
|
|
// Import preset json.
|
|
string presetPath = Application.dataPath + "/Art/Temp/Editor/PrefabTool/MC2_Preset_(hair).json";
|
|
string hairPreset = File.ReadAllText(presetPath);
|
|
magicaClothComp.SerializeData.ImportJson(hairPreset);
|
|
|
|
// Add magica wind zone
|
|
GameObject wind = new("Magica Wind Zone")
|
|
{
|
|
transform =
|
|
{
|
|
parent = assetInstance
|
|
}
|
|
};
|
|
var windComponent = wind.AddComponent<MagicaWindZone>();
|
|
windComponent.directionAngleY = -180f;
|
|
windComponent.main = 3;
|
|
|
|
// backstop setting
|
|
MotionConstraint.SerializeData ms = new()
|
|
{
|
|
useBackstop = true,
|
|
backstopRadius = 1f,
|
|
backstopDistance = new(0.05f)
|
|
};
|
|
magicaClothComp.SerializeData.motionConstraint = ms;
|
|
}
|
|
|
|
public void ShotShow(int weaponId, AnimationClip clip)
|
|
{
|
|
GameObject prefab = new(nameId + "_" + weaponId);
|
|
GameObject prefabInstance = (GameObject)PrefabUtility.InstantiatePrefab(Model, prefab.transform);
|
|
this.objInstance = prefab;
|
|
|
|
// get gun
|
|
GunInfo gun = new("G" + weaponId.ToString().PadLeft(5, '0'));
|
|
Transform grip = prefabInstance.transform.Find(Grip01);
|
|
if (grip == null)
|
|
{
|
|
Debug.LogError("没有武器挂点,终止");
|
|
return;
|
|
}
|
|
|
|
// Add emoji
|
|
Transform head = prefabInstance.transform.Find(Head);
|
|
GameObject emoji =
|
|
AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Art/Character/Models/Emoji/G_emoji.FBX");
|
|
GameObject emojiInstance = (GameObject)PrefabUtility.InstantiatePrefab(emoji);
|
|
emojiInstance.transform.parent = head;
|
|
|
|
PrefabUtility.InstantiatePrefab(gun.Prefab, grip);
|
|
|
|
// set anim
|
|
AnimationMode.StartAnimationMode();
|
|
AnimationMode.SampleAnimationClip(prefabInstance.gameObject, clip, 0f);
|
|
}
|
|
}
|
|
|
|
|
|
public static class CharacterFactory
|
|
{
|
|
public static CharacterAssetInfo CreatePlayer(string nameId) => new CharacterAssetInfo(nameId, "Players");
|
|
public static CharacterAssetInfo CreateNpc(string nameId) => new CharacterAssetInfo(nameId, "Npc");
|
|
public static CharacterAssetInfo CreateEmeny(string nameId) => new CharacterAssetInfo(nameId, "Enemy");
|
|
}
|
|
} |