Files
test/Assets/PerfectWorld/Scripts/Move/CECPlayer.AnimSceneWeapon.cs
2026-05-29 11:05:10 +07:00

162 lines
6.9 KiB
C#

using UnityEngine;
namespace BrewMonster
{
/// <summary>
/// Animation test scene helpers for editor/bootstrap weapon iteration.
/// 动画测试场景:编辑器 / Bootstrap 武器调试辅助。
/// </summary>
public abstract partial class CECPlayer
{
/// <summary>
/// Attach weapon prefabs like <see cref="CECPlayer_Inventory.ShowEquipments"/> (hand hooks), and set <see cref="m_uAttackType"/> for <see cref="GetShowingWeaponType"/>.
/// Omit both prefabs (or pass <see cref="DEFAULT_ACTION_TYPE"/>) to clear meshes and reset attack type.
/// 与 ShowEquipments 相同挂点挂接武器,并设置 m_uAttackType 以驱动动作后缀。两预制体均为空则清除并还原默认攻击类型。
/// </summary>
public void AnimSceneAttachWeaponPrefabs(GameObject rightPrefab, GameObject leftPrefab, uint weaponActionType)
{
if (_currentRightHandWeapon != null)
{
Destroy(_currentRightHandWeapon);
_currentRightHandWeapon = null;
}
if (_currentLeftHandWeapon != null)
{
Destroy(_currentLeftHandWeapon);
_currentLeftHandWeapon = null;
}
bool anyAttached = false;
if (rightPrefab != null)
{
GameObject hookGo = FindChildObjectRecursive(transform, _hh_right_hand_weapon);
if (hookGo != null)
{
GameObject weaponObject = Instantiate(rightPrefab);
weaponObject.transform.SetParent(hookGo.transform);
weaponObject.transform.localPosition = rightPrefab.transform.localPosition;
weaponObject.transform.localRotation = rightPrefab.transform.localRotation;
weaponObject.transform.localScale = Vector3.one;
weaponObject.SetActive(true);
_currentRightHandWeapon = weaponObject;
anyAttached = true;
}
else
{
Debug.LogWarning(
"[AnimSceneBootstrap] AnimSceneAttachWeaponPrefabs: hook not found: " + _hh_right_hand_weapon);
}
}
if (leftPrefab != null)
{
GameObject hookGo = FindChildObjectRecursive(transform, _hh_left_hand_weapon);
if (hookGo != null)
{
GameObject weaponObject = Instantiate(leftPrefab);
weaponObject.transform.SetParent(hookGo.transform);
weaponObject.transform.localPosition = leftPrefab.transform.localPosition;
weaponObject.transform.localRotation = leftPrefab.transform.localRotation;
weaponObject.transform.localScale = Vector3.one;
weaponObject.SetActive(true);
_currentLeftHandWeapon = weaponObject;
anyAttached = true;
}
else
{
Debug.LogWarning(
"[AnimSceneBootstrap] AnimSceneAttachWeaponPrefabs: hook not found: " + _hh_left_hand_weapon);
}
}
if (anyAttached)
{
m_uAttackType = weaponActionType;
m_bWeaponAttached = true;
}
else
{
m_uAttackType = DEFAULT_ACTION_TYPE;
AttachWeapon();
}
}
/// <summary>
/// <see cref="Awake"/> assigns <see cref="m_PlayerActions"/> = <see cref="_default_actions"/> before <see cref="InitStaticRes"/> fills the static table — rebind after bootstrap calls <c>InitStaticRes</c>.
/// Mirrors <see cref="SetNewExtendStates"/> (state 111 → turning table).
/// Awake 时静态动作表可能尚未构建;Bootstrap 在 InitStaticRes 之后调用本方法。逻辑与 SetNewExtendStates 一致(扩展状态 111 用旋转表)。
/// </summary>
public void AnimSceneRebindPlayerActions()
{
if (GetExtState(111) && _turning_actions != null)
{
m_PlayerActions = _turning_actions;
}
else
{
m_PlayerActions = _default_actions;
}
}
/// <summary>
/// Animation test scene: <c>elementdataman</c> may not register <c>DT_FASHION_WEAPON_CONFIG</c>, so <see cref="IsFashionWeaponTypeFit"/>
/// can NRE on a null <c>action_mask</c> when <see cref="m_iFashionWeaponType"/> is in <c>[0, NUM_WEAPON_TYPE)</c>.
/// Setting <c>-1</c> makes <see cref="GetShowingWeaponType"/> skip the fashion branch (early out in IsFashionWeaponTypeFit).
/// 动画测试:元素表可能未注册时装武器配置;将时尚武器类型置为 -1 避免 IsFashionWeaponTypeFit 空引用。
/// </summary>
public void AnimSceneSanitizeFashionWeaponStateForElementDataCompat()
{
m_iFashionWeaponType = -1;
}
/// <summary>
/// Animation test scene skips server LoadResources; mark all resource flags so ShowExtendStates can play state GFX.
/// </summary>
public void AnimSceneMarkResourcesReady()
{
m_dwResFlags = (uint)PlayerResourcesReadyFlag.RESFG_ALL;
}
/// <summary>
/// Inspector/debug: non-null string means <see cref="PlayAction"/> will no-op or return false before Animancer runs.
/// 非空表示 PlayAction 会在播放前失败或直接被拒。
/// </summary>
public string AnimSceneTryExplainPlayActionFailure(int iAction)
{
if (iAction < 0 || iAction >= (int)PLAYER_ACTION_TYPE.ACT_MAX)
{
return $"Action index must be 0..{(int)PLAYER_ACTION_TYPE.ACT_MAX - 1}.";
}
if (m_pPlayerCECModel == null)
{
return "CECModel is null — wait for SetPlayerModel / Switch model to finish.";
}
if (m_PlayerActions == null)
{
return "m_PlayerActions is null — click Play again after bootstrap runs, or call AnimSceneRebindPlayerActions().";
}
if (m_PlayerActions[iAction].data.id == 0)
{
return $"No PLAYER_ACTION_INFO_CONFIG for index {iAction} (data.id==0). Check actions_player / element data for this action.";
}
if (m_pActionController == null)
{
return "m_pActionController is null — model setup did not call RecreateActionController (SetPlayerModel incomplete?).";
}
if (iAction >= (int)PLAYER_ACTION_TYPE.ACT_ATTACK_1 && iAction <= (int)PLAYER_ACTION_TYPE.ACT_ATTACK_4)
{
return "ACT_ATTACK_1..4 are blocked in PlayActionWithConfig — use skill/combat paths.";
}
return null;
}
}
}