update show skill tool
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9327b85e3d879a676a6928066162e7270af3c40f439dac47630f1325d3f925d5
|
||||
oid sha256:aa95dfb364ee6af6d4dac2c026057bfbba33638c76305b26a1611c3aeb134847
|
||||
size 150615
|
||||
|
||||
@@ -361,6 +361,8 @@ namespace PerfectWorld.Scripts
|
||||
await player.SetPlayerModel(prof, gen);
|
||||
Debug.Log("[AnimSceneBootstrap] SetPlayerModel pipeline finished.");
|
||||
|
||||
player.AnimSceneMarkResourcesReady();
|
||||
|
||||
ApplyWeaponForActiveSlot();
|
||||
|
||||
AnimSceneInitSkillModelAndRefreshPanel(prof, gen);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using BrewMonster.Scripts;
|
||||
using BrewMonster.Scripts.Skills;
|
||||
using BrewMonster.Config;
|
||||
|
||||
using ModelViewer.Common;
|
||||
|
||||
@@ -147,6 +149,75 @@ namespace BrewMonster
|
||||
LogSkillStubFlyHitGfx(ev.m_idSkill, ev.m_nSkillSection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs visible-state aura GFX and state-reaction ComAct GFX (skill_state_action + name fallback for local anim-test).
|
||||
/// </summary>
|
||||
public void LogSkillStateGfx(CECHostPlayer player, int skillId)
|
||||
{
|
||||
List<int> stateIds = SkillVisibleStateResolver.ResolveVisibleStateIds(skillId);
|
||||
bool hasConfigRows = SkillVisibleStateResolver.TryGetConfigRows(skillId, out IReadOnlyList<SkillStateActionRow> rows);
|
||||
|
||||
// #region agent log
|
||||
AgentDebugLog("LogSkillStateGfx:entry", "resolved visible states", "H3",
|
||||
$"{{\"skillId\":{skillId},\"stateIds\":\"{string.Join(",", stateIds)}\",\"hasConfigRows\":{hasConfigRows.ToString().ToLower()},\"configRowCount\":{(hasConfigRows ? rows.Count : 0)}}}");
|
||||
// #endregion
|
||||
|
||||
if (stateIds.Count == 0 && !hasConfigRows)
|
||||
return;
|
||||
|
||||
const string stateGfxBasePath = "gfx/策划联入/状态效果/";
|
||||
var seenStateGfx = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var seenBeHitActions = new HashSet<string>(StringComparer.Ordinal);
|
||||
var seenStayActions = new HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
CECModel playerModel = player?.GetPlayerCECModel();
|
||||
int profession = player != null ? player.GetProfession() : 0;
|
||||
|
||||
foreach (int stateId in stateIds)
|
||||
{
|
||||
VisibleState visibleState = VisibleState.Query(profession, stateId);
|
||||
string effect = visibleState?.GetEffect();
|
||||
// #region agent log
|
||||
AgentDebugLog("LogSkillStateGfx:query", "VisibleState resolved", "H2",
|
||||
$"{{\"skillId\":{skillId},\"stateId\":{stateId},\"profession\":{profession},\"effect\":\"{effect ?? ""}\",\"name\":\"{visibleState?.GetName() ?? ""}\"}}");
|
||||
// #endregion
|
||||
|
||||
if (string.IsNullOrWhiteSpace(effect))
|
||||
continue;
|
||||
|
||||
string rawPath = stateGfxBasePath + effect;
|
||||
string displayText = GfxBasename(rawPath);
|
||||
if (string.IsNullOrEmpty(displayText) || !seenStateGfx.Add(displayText))
|
||||
continue;
|
||||
|
||||
string stateLabel = visibleState.GetName();
|
||||
if (string.IsNullOrEmpty(stateLabel))
|
||||
stateLabel = $"state {stateId}";
|
||||
else
|
||||
stateLabel += $" (id {stateId})";
|
||||
|
||||
AddCopyTextButton("State", displayText, GfxAddressableExists(rawPath), stateLabel);
|
||||
}
|
||||
|
||||
if (!hasConfigRows)
|
||||
return;
|
||||
|
||||
foreach (SkillStateActionRow row in rows)
|
||||
{
|
||||
if (playerModel != null && !string.IsNullOrWhiteSpace(row.beHitAction) &&
|
||||
seenBeHitActions.Add(row.beHitAction))
|
||||
{
|
||||
AddGfxEventsFromComAct(playerModel.GetComActByName(row.beHitAction), "StateBeHit");
|
||||
}
|
||||
|
||||
if (playerModel != null && !string.IsNullOrWhiteSpace(row.stayDownAction) &&
|
||||
seenStayActions.Add(row.stayDownAction))
|
||||
{
|
||||
AddGfxEventsFromComAct(playerModel.GetComActByName(row.stayDownAction), "StateStay");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddGfxEventsFromComAct(A3DCombinedAction comAct, string label)
|
||||
{
|
||||
if (string.IsNullOrEmpty(label) || comAct?.m_EventInfoLst == null)
|
||||
@@ -221,5 +292,21 @@ namespace BrewMonster
|
||||
AddGfxPathRow("Hit", hit);
|
||||
AddGfxPathRow("HitGrnd", hitGrnd);
|
||||
}
|
||||
|
||||
// #region agent log
|
||||
public static void AgentDebugLog(string location, string message, string hypothesisId, string dataJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = Path.GetFullPath(Path.Combine(Application.dataPath, "..", "..", "debug-1197c4.log"));
|
||||
long ts = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
string line = "{\"sessionId\":\"1197c4\",\"location\":\"" + location + "\",\"message\":\"" + message + "\",\"hypothesisId\":\"" + hypothesisId + "\",\"timestamp\":" + ts + ",\"data\":" + dataJson + "}";
|
||||
File.AppendAllText(path, line + Environment.NewLine);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
// #endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BrewMonster.Config;
|
||||
using BrewMonster.Scripts;
|
||||
using BrewMonster.Scripts.Skills;
|
||||
|
||||
namespace BrewMonster
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves visible-state ids for anim-test (skill_state_action + name fallback) and applies ext-state bits locally (no server).
|
||||
/// </summary>
|
||||
public static class SkillVisibleStateResolver
|
||||
{
|
||||
const int ExtStateCount = 6;
|
||||
const int BitSize = 32;
|
||||
|
||||
public static List<int> ResolveVisibleStateIds(int skillId)
|
||||
{
|
||||
var ids = new HashSet<int>();
|
||||
|
||||
if (CECAttacksMan.Instance != null &&
|
||||
CECAttacksMan.Instance.TryGetSkillStateActions(skillId, out IReadOnlyList<SkillStateActionRow> rows))
|
||||
{
|
||||
for (int i = 0; i < rows.Count; i++)
|
||||
ids.Add(rows[i].state);
|
||||
}
|
||||
|
||||
SkillStub stub = SkillStub.GetStub((uint)skillId);
|
||||
if (stub != null && !string.IsNullOrEmpty(stub.name))
|
||||
{
|
||||
foreach (KeyValuePair<int, VisibleStateImp> kv in GNET.VisibleState)
|
||||
{
|
||||
string visibleName = kv.Value?.GetName();
|
||||
if (string.IsNullOrEmpty(visibleName))
|
||||
continue;
|
||||
|
||||
if (string.Equals(visibleName, stub.name, StringComparison.Ordinal) ||
|
||||
string.Equals(visibleName, stub.nativename, StringComparison.Ordinal))
|
||||
ids.Add(kv.Key);
|
||||
}
|
||||
}
|
||||
|
||||
return new List<int>(ids);
|
||||
}
|
||||
|
||||
public static bool TryGetConfigRows(int skillId, out IReadOnlyList<SkillStateActionRow> rows)
|
||||
{
|
||||
rows = null;
|
||||
return CECAttacksMan.Instance != null &&
|
||||
CECAttacksMan.Instance.TryGetSkillStateActions(skillId, out rows);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates server UPDATE_EXT_STATE for AnimationTest: sets bits and calls ShowExtendStates via SetNewExtendStates.
|
||||
/// </summary>
|
||||
public static void TryApplyLocalExtStates(int skillId, CECHostPlayer hostPlayer, CECMonsterTest targetMarker)
|
||||
{
|
||||
List<int> stateIds = ResolveVisibleStateIds(skillId);
|
||||
// #region agent log
|
||||
LogPanelAnimeScene.AgentDebugLog("TryApplyLocalExtStates", "resolved state ids", "H4",
|
||||
$"{{\"skillId\":{skillId},\"stateIds\":\"{string.Join(",", stateIds)}\",\"targetType\":{GetSkillTargetType((uint)skillId)}}}");
|
||||
// #endregion
|
||||
|
||||
if (stateIds.Count == 0 || hostPlayer == null)
|
||||
return;
|
||||
|
||||
if (!hostPlayer.IsAllResReady() && hostPlayer.IsPlayerModelReady)
|
||||
hostPlayer.AnimSceneMarkResourcesReady();
|
||||
|
||||
uint[] nextStates = BuildExtStates(hostPlayer.m_aExtStates, stateIds);
|
||||
int targetType = GetSkillTargetType((uint)skillId);
|
||||
|
||||
// #region agent log
|
||||
LogPanelAnimeScene.AgentDebugLog("TryApplyLocalExtStates:apply", "calling SetNewExtendStates", "H5",
|
||||
$"{{\"skillId\":{skillId},\"targetType\":{targetType},\"isAllResReady\":{hostPlayer.IsAllResReady().ToString().ToLower()},\"isModelReady\":{hostPlayer.IsPlayerModelReady.ToString().ToLower()},\"stateBits\":\"{string.Join(",", nextStates)}\"}}");
|
||||
// #endregion
|
||||
|
||||
if (targetType == 0)
|
||||
{
|
||||
hostPlayer.SetNewExtendStates(0, nextStates, ExtStateCount);
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetMarker != null)
|
||||
targetMarker.SetNewExtendStates(0, nextStates, ExtStateCount);
|
||||
}
|
||||
|
||||
static uint[] BuildExtStates(uint[] current, IEnumerable<int> stateIds)
|
||||
{
|
||||
var states = new uint[ExtStateCount];
|
||||
if (current != null && current.Length >= ExtStateCount)
|
||||
Array.Copy(current, states, ExtStateCount);
|
||||
|
||||
foreach (int stateId in stateIds)
|
||||
{
|
||||
if (stateId < 0)
|
||||
continue;
|
||||
|
||||
int dwordIndex = stateId / BitSize;
|
||||
int bit = stateId % BitSize;
|
||||
if (dwordIndex < ExtStateCount)
|
||||
states[dwordIndex] |= 1u << bit;
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
static int GetSkillTargetType(uint skillId)
|
||||
{
|
||||
SkillStub stub = SkillStub.GetStub(skillId);
|
||||
if (stub == null)
|
||||
return 1;
|
||||
|
||||
if (stub.restrict_corpse == 1)
|
||||
return 2;
|
||||
if (stub.restrict_corpse == 2)
|
||||
return 3;
|
||||
if (stub.type == (int)skill_type.TYPE_ATTACK || stub.type == (int)skill_type.TYPE_CURSE)
|
||||
return 1;
|
||||
if (stub.type == (int)skill_type.TYPE_BLESSPET)
|
||||
return 4;
|
||||
if (stub.GetRange().NoTarget())
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ba8d537bc3de3c49845d22a1f9a69ce
|
||||
@@ -614,6 +614,7 @@ namespace BrewMonster
|
||||
|
||||
logPanelAnimeScene.LogSkillCastGfx(player, skillId);
|
||||
logPanelAnimeScene.LogPlayAttackEffectGfx(player, skillId, 0);
|
||||
logPanelAnimeScene.LogSkillStateGfx(player, skillId);
|
||||
|
||||
// Self-cast skills target the host; all others target the draggable marker.
|
||||
// 自身施法技能以主角为目标;其余技能以可拖动标记为目标。
|
||||
@@ -805,6 +806,8 @@ namespace BrewMonster
|
||||
|
||||
if(!replayAttackAnim)
|
||||
ScheduleFadeAllGfxWhenAttackStopped(attackTime);
|
||||
|
||||
SkillVisibleStateResolver.TryApplyLocalExtStates(skillId, hostPlayer, targetMarker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +223,31 @@ namespace BrewMonster
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all skill_state_action rows for a skill (anim-test / debug lookup).
|
||||
/// </summary>
|
||||
public bool TryGetSkillStateActions(int skillId, out IReadOnlyList<SkillStateActionRow> rows)
|
||||
{
|
||||
rows = null;
|
||||
SkillStateActionConfig cfg = skillStateActionConfig;
|
||||
if (cfg?.Entries == null || cfg.Entries.Count == 0)
|
||||
return false;
|
||||
|
||||
var matches = new List<SkillStateActionRow>();
|
||||
for (int i = 0; i < cfg.Entries.Count; i++)
|
||||
{
|
||||
SkillStateActionRow row = cfg.Entries[i];
|
||||
if (row.skill == skillId)
|
||||
matches.Add(row);
|
||||
}
|
||||
|
||||
if (matches.Count == 0)
|
||||
return false;
|
||||
|
||||
rows = matches;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
uint dwDeltaTime = (uint)(Time.deltaTime * 1000);
|
||||
|
||||
@@ -111,6 +111,14 @@ namespace BrewMonster
|
||||
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 会在播放前失败或直接被拒。
|
||||
|
||||
@@ -915,7 +915,13 @@ namespace BrewMonster
|
||||
return;
|
||||
}
|
||||
if (!IsAllResReady() || !GetMajorModel())
|
||||
{
|
||||
// #region agent log
|
||||
LogPanelAnimeScene.AgentDebugLog("ShowExtendStates:blocked", "resource gate", "H5",
|
||||
$"{{\"isAllResReady\":{IsAllResReady().ToString().ToLower()},\"hasMajorModel\":{(GetMajorModel() != null).ToString().ToLower()},\"isModelReady\":{IsPlayerModelReady.ToString().ToLower()}}}");
|
||||
// #endregion
|
||||
return;
|
||||
}
|
||||
//TODO: Implement optimization
|
||||
// if (!bIgnoreOptimize &&
|
||||
// !CECOptimize::Instance().GetGFX().CanShowState(GetCharacterID(), GetClassID()))
|
||||
@@ -3086,6 +3092,10 @@ namespace BrewMonster
|
||||
if (prefab == null)
|
||||
{
|
||||
BMLogger.LogWarning($"[StateGFX] Failed to load prefab: {path}");
|
||||
// #region agent log
|
||||
LogPanelAnimeScene.AgentDebugLog("PlayStateGfxAsync:fail", "prefab load failed", "H6",
|
||||
$"{{\"path\":\"{path}\",\"hook\":\"{hook ?? ""}\"}}");
|
||||
// #endregion
|
||||
return;
|
||||
}
|
||||
// [中文] 查找挂点骨骼,未找到则回退到玩家根 transform
|
||||
@@ -3098,6 +3108,10 @@ namespace BrewMonster
|
||||
vfx.transform.localPosition = Vector3.zero;
|
||||
|
||||
_stateGfxObjects[key] = vfx;
|
||||
// #region agent log
|
||||
LogPanelAnimeScene.AgentDebugLog("PlayStateGfxAsync:spawned", "state gfx instantiated", "H6",
|
||||
$"{{\"path\":\"{path}\",\"hook\":\"{hook ?? ""}\",\"parent\":\"{parent.name}\"}}");
|
||||
// #endregion
|
||||
}
|
||||
|
||||
// [中文] 在武器 CECModel 上移除状态效果 GFX(武器挂点逻辑未接入,暂存桩)
|
||||
|
||||
Reference in New Issue
Block a user