Hygiene B4c: clean dedup helpers (knockback, bakers, editor rig)
- KnockbackUtil.Stamp: shared knockback-stamp used by AbilityFireSystem + MeleeComboSystem (guard + planar normalize + write; speed passed in). - BakerStructureExt: AddPlacedStructure/AddDamageable extensions on Baker<T>; rewired Turret/Structure/Harvester/Conveyor/Fabricator bakers (baked data + serialized fields unchanged). - EnemyPrefabBakeExt.AddEnemyPrefabPool: shared prefab-buffer bake for ZoneEnemyDirector/WaveDirector authoring (fields stay flat — no serialization change). - Editor AnimRigUtil (HasParam + root-yaw overlay clip) shared by PlayerRigTools/EnemyRigTools; EnemyRigTools.MakeMat now GUID-preserving (CopySerialized over existing) — the composite AnimatorController copy left as-is with a caveat comment. 466/466 EditMode tests pass, 0 warnings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -97,15 +97,26 @@ namespace ProjectM.EditorTools
|
||||
|
||||
static void MakeMat(string dst, string atlas, Color? tint)
|
||||
{
|
||||
if (AssetDatabase.LoadAssetAtPath<Material>(PlayerMat) == null)
|
||||
var src = AssetDatabase.LoadAssetAtPath<Material>(PlayerMat);
|
||||
if (src == null)
|
||||
{ Debug.LogError($"[EnemyRigTools] Source material missing: {PlayerMat}"); return; }
|
||||
|
||||
AssetDatabase.DeleteAsset(dst);
|
||||
if (!AssetDatabase.CopyAsset(PlayerMat, dst))
|
||||
{ Debug.LogError($"[EnemyRigTools] CopyAsset failed -> {dst}"); return; }
|
||||
AssetDatabase.ImportAsset(dst);
|
||||
|
||||
// GUID-preserving: overwrite an existing dst IN PLACE (CopySerialized keeps dst's GUID, so committed
|
||||
// prefab material refs never break); only CopyAsset when dst is absent (first creation). The old
|
||||
// DeleteAsset+CopyAsset minted a new GUID every run and silently orphaned those refs.
|
||||
var m = AssetDatabase.LoadAssetAtPath<Material>(dst);
|
||||
if (m == null)
|
||||
{
|
||||
if (!AssetDatabase.CopyAsset(PlayerMat, dst))
|
||||
{ Debug.LogError($"[EnemyRigTools] CopyAsset failed -> {dst}"); return; }
|
||||
AssetDatabase.ImportAsset(dst);
|
||||
m = AssetDatabase.LoadAssetAtPath<Material>(dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.CopySerialized(src, m);
|
||||
}
|
||||
|
||||
var tex = AssetDatabase.LoadAssetAtPath<Texture>(atlas);
|
||||
if (tex == null) Debug.LogWarning($"[EnemyRigTools] Atlas not found: {atlas}");
|
||||
if (m.HasProperty("_BaseColorMap") && tex != null) m.SetTexture("_BaseColorMap", tex);
|
||||
@@ -128,26 +139,19 @@ namespace ProjectM.EditorTools
|
||||
if (idle == null) { Debug.LogError("[EnemyRigTools] No Idle clip to base the attack on."); return; }
|
||||
var clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(AttackClip);
|
||||
if (clip == null) { clip = new AnimationClip { frameRate = 30f }; AssetDatabase.CreateAsset(clip, AttackClip); }
|
||||
clip.ClearCurves();
|
||||
foreach (var cb in AnimationUtility.GetCurveBindings(idle))
|
||||
{ if (cb.path == "Root") continue; AnimationUtility.SetEditorCurve(clip, cb, AnimationUtility.GetEditorCurve(idle, cb)); }
|
||||
var yaw = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(0.15f, -38f), new Keyframe(0.40f, 0f));
|
||||
AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve("Root", typeof(Transform), "localEulerAnglesRaw.y"), yaw);
|
||||
var s = AnimationUtility.GetAnimationClipSettings(clip);
|
||||
s.loopTime = false;
|
||||
AnimationUtility.SetAnimationClipSettings(clip, s);
|
||||
EditorUtility.SetDirty(clip);
|
||||
AssetDatabase.SaveAssets();
|
||||
AnimRigUtil.BuildRootYawOverlayClip(clip, idle, yaw);
|
||||
|
||||
if (AssetDatabase.LoadAssetAtPath<AnimatorController>(PlayerController) == null)
|
||||
{ Debug.LogError($"[EnemyRigTools] Source controller missing: {PlayerController}"); return; }
|
||||
|
||||
// GUID caveat: DeleteAsset+CopyAsset re-mints AC_EnemyTopDown's GUID each run; left as-is because CopySerialized onto a composite AnimatorController risks orphaning its sub-assets (states/transitions), unlike MakeMat's flat Material.
|
||||
AssetDatabase.DeleteAsset(EnemyController);
|
||||
AssetDatabase.CopyAsset(PlayerController, EnemyController);
|
||||
AssetDatabase.ImportAsset(EnemyController);
|
||||
var ac = AssetDatabase.LoadAssetAtPath<AnimatorController>(EnemyController);
|
||||
|
||||
if (!HasParam(ac, "IsAttacking"))
|
||||
if (!AnimRigUtil.HasParam(ac, "IsAttacking"))
|
||||
ac.AddParameter("IsAttacking", AnimatorControllerParameterType.Bool);
|
||||
|
||||
var sm = ac.layers[0].stateMachine;
|
||||
@@ -172,12 +176,6 @@ namespace ProjectM.EditorTools
|
||||
Debug.Log("[EnemyRigTools] AC_EnemyTopDown + EnemyAttackWindup clip built.");
|
||||
}
|
||||
|
||||
static bool HasParam(AnimatorController ac, string name)
|
||||
{
|
||||
foreach (var p in ac.parameters) if (p.name == name) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---- 3. Prefabs --------------------------------------------------------------------------------------
|
||||
|
||||
[MenuItem("ProjectM/Animation/Enemy Rigs - 3 Build Prefabs")]
|
||||
|
||||
Reference in New Issue
Block a user