using System; using System.Collections.Generic; using BrewMonster.Config; using BrewMonster.Scripts; using BrewMonster.Scripts.Skills; namespace BrewMonster { /// /// Resolves visible-state ids for anim-test (skill_state_action + name fallback) and applies ext-state bits locally (no server). /// public static class SkillVisibleStateResolver { const int ExtStateCount = 6; const int BitSize = 32; public static List ResolveVisibleStateIds(int skillId) { var ids = new HashSet(); if (CECAttacksMan.Instance != null && CECAttacksMan.Instance.TryGetSkillStateActions(skillId, out IReadOnlyList 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 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(ids); } public static bool TryGetConfigRows(int skillId, out IReadOnlyList rows) { rows = null; return CECAttacksMan.Instance != null && CECAttacksMan.Instance.TryGetSkillStateActions(skillId, out rows); } /// /// Simulates server UPDATE_EXT_STATE for AnimationTest: sets bits and calls ShowExtendStates via SetNewExtendStates. /// public static void TryApplyLocalExtStates(int skillId, CECHostPlayer hostPlayer, CECMonsterTest targetMarker) { List 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 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; } } }