using System; using System.Collections.Generic; using BrewMonster.Scripts; using BrewMonster.Scripts.Skills; using ModelViewer.Common; using UnityEngine; namespace BrewMonster { public class LogPanelAnimeScene : MonoBehaviour { [SerializeField] private CopyTextButton copyTextButtonPrefab; [SerializeField] private List copyTextButtons; [SerializeField] private Transform copyTextButtonsParent; private int currentIndex = 0; public void Awake() { copyTextButtons = new List(); currentIndex = 0; Reset(); } public void Reset() { currentIndex = 0; foreach (var copyText in copyTextButtons) { copyText.gameObject.SetActive(false); } } public void AddCopyTextButton(string labeltext, string text, bool? inAddressables = null, string actionName = null) { if (currentIndex >= copyTextButtons.Count) { var copyTextButton = Instantiate(copyTextButtonPrefab, copyTextButtonsParent); copyTextButton.gameObject.SetActive(true); copyTextButton.SetText(labeltext, text, inAddressables, actionName); copyTextButtons.Add(copyTextButton); } else { copyTextButtons[currentIndex].gameObject.SetActive(true); copyTextButtons[currentIndex].SetText(labeltext, text, inAddressables, actionName); } currentIndex++; } /// /// Display name: last path segment only, no gfx/ prefix, no .gfx suffix. /// 显示名:仅最后一段,无 gfx/ 前缀、无 .gfx 后缀。 /// public static string GfxBasename(string path) { if (string.IsNullOrWhiteSpace(path)) return null; path = AFile.NormalizePath(path, true); if (path.StartsWith("gfx/", StringComparison.OrdinalIgnoreCase)) path = path.Substring(4); int slash = path.LastIndexOf('/'); string file = slash >= 0 ? path.Substring(slash + 1) : path; if (file.EndsWith(".gfx", StringComparison.OrdinalIgnoreCase)) file = file.Substring(0, file.Length - 4); return string.IsNullOrEmpty(file) ? null : file; } /// /// Candidate Addressables keys (runtime CECModel path + catalog .gfx tail). /// static IEnumerable GfxAddressableKeyCandidates(string rawPath) { if (string.IsNullOrWhiteSpace(rawPath)) yield break; string path = AFile.NormalizePath(rawPath, true); string runtimeKey = path.StartsWith("gfx/", StringComparison.OrdinalIgnoreCase) ? path : "gfx/" + path.TrimStart('/'); yield return runtimeKey; if (!runtimeKey.EndsWith(".gfx", StringComparison.OrdinalIgnoreCase)) yield return runtimeKey + ".gfx"; } public static bool GfxAddressableExists(string rawPath) { var mgr = AddressableManager.Instance; if (mgr == null || !mgr.IsInitialized()) return false; foreach (string key in GfxAddressableKeyCandidates(rawPath)) { if (AddressableManager.KeyExists(key, typeof(GameObject))) return true; } return false; } /// /// Has path → show row. Green if Addressables has key, red if not. No path → skip. /// 有路径则显示:Addressables 有则绿,无则红;无路径不显示。 /// void AddGfxPathRow(string label, string rawPath) { if (string.IsNullOrWhiteSpace(rawPath)) return; string displayText = GfxBasename(rawPath); if (string.IsNullOrEmpty(displayText)) return; AddCopyTextButton(label, displayText, GfxAddressableExists(rawPath), "—"); } public void LogSkillCastGfx(CECHostPlayer player, int skillId) { AddGfxEventsFromComAct(player?.GetSkillCastComAct(skillId), "Cast"); } public void LogPlayAttackEffectGfx(CECHostPlayer player, int skillId, int section = 0) { if (player == null) return; AddGfxEventsFromComAct(player.GetSkillAttackComActRise(skillId, section), "Attack"); AddGfxEventsFromComAct(player.GetSkillAttackComActFall(skillId, section), "Attack"); LogSkillStubFlyHitGfx(skillId, section); } public void LogAttackEventGfx(CECAttackEvent ev) { if (ev == null || ev.m_idSkill == 0) return; LogSkillStubFlyHitGfx(ev.m_idSkill, ev.m_nSkillSection); } public void AddGfxEventsFromComAct(A3DCombinedAction comAct, string label) { if (string.IsNullOrEmpty(label) || comAct?.m_EventInfoLst == null) { return; } var seen = new HashSet(); foreach (var ev in comAct.m_EventInfoLst) { if (ev is not FX_BASE_INFO gfx || gfx.m_strFilePaths == null) { continue; } foreach (string path in gfx.m_strFilePaths) { if(!path.Contains("gfx")) { continue; } if (string.IsNullOrWhiteSpace(path)) continue; string displayText = GfxBasename(path); if (string.IsNullOrEmpty(displayText) || !seen.Add(displayText)) continue; AddCopyTextButton(label, displayText, GfxAddressableExists(path), comAct.m_strName); } } } void LogSkillStubFlyHitGfx(int skillId, int section) { string fly = null; string hitGrnd = null; string hit = null; var atkMan = CECAttacksMan.Instance; if (section > 0 && atkMan?.m_pMultiSkillGfxComposerMan != null) { var composer = atkMan.m_pMultiSkillGfxComposerMan.GetSkillGfxComposer(skillId, section); if (composer != null) { fly = composer.flyGfxName; hit = composer.hitGfxName; hitGrnd = composer.hitGrdGfxName; } } else { var composer = atkMan?.GetSkillGfxComposerMan()?.GetSkillGfxComposer(skillId); if (composer != null) { fly = composer.flyGfxName; hit = composer.hitGfxName; hitGrnd = composer.hitGrdGfxName; } } if (string.IsNullOrEmpty(fly) && string.IsNullOrEmpty(hit) && string.IsNullOrEmpty(hitGrnd)) { var paths = ElementSkill.GetAllGFX((uint)skillId); fly = paths.Item1; hitGrnd = paths.Item2; hit = paths.Item3; } AddGfxPathRow("Fly", fly); AddGfxPathRow("Hit", hit); AddGfxPathRow("HitGrnd", hitGrnd); } } }