// UTF-8 with BOM — required for Chinese character paths using System; using System.Collections.Generic; using BrewMonster; using BrewMonster.Scripts.ECModel; using ModelViewer.Common; using UnityEditor; using UnityEngine; public enum CombinedActionGfxPhase { All, Cast, Attack, Other, } public readonly struct CombinedActionGfxEntry { public CombinedActionGfxEntry( A3DCombinedAction action, FX_BASE_INFO fxEvent, string path, string actionName, string gfxBasename, CombinedActionGfxPhase phase) { Action = action; FxEvent = fxEvent; Path = path; ActionName = actionName; GfxBasename = gfxBasename; Phase = phase; } public A3DCombinedAction Action { get; } public FX_BASE_INFO FxEvent { get; } public string Path { get; } public string ActionName { get; } public string GfxBasename { get; } public CombinedActionGfxPhase Phase { get; } } public static class CombinedActionGfxQuery { const string CastToken = "_\u541f\u5531_"; const string AttackRiseToken = "_\u65bd\u653e\u8d77_"; const string AttackFallToken = "_\u65bd\u653e\u843d_"; public static CombinedActionGfxPhase GetPhase(string actionName) { if (string.IsNullOrEmpty(actionName)) return CombinedActionGfxPhase.Other; if (actionName.Contains(CastToken, StringComparison.Ordinal)) return CombinedActionGfxPhase.Cast; if (actionName.Contains(AttackRiseToken, StringComparison.Ordinal) || actionName.Contains(AttackFallToken, StringComparison.Ordinal)) return CombinedActionGfxPhase.Attack; return CombinedActionGfxPhase.Other; } public static string GetPhaseLabel(CombinedActionGfxPhase phase) { return phase switch { CombinedActionGfxPhase.Cast => "Cast", CombinedActionGfxPhase.Attack => "Attack", CombinedActionGfxPhase.Other => "Other", _ => "All", }; } public static IEnumerable Scan(CombinedActionSO so) { if (so?.CombinedActionData == null) yield break; foreach (A3DCombinedAction action in so.CombinedActionData) { if (action?.m_EventInfoLst == null) continue; string actionName = action.m_strName ?? string.Empty; CombinedActionGfxPhase phase = GetPhase(actionName); foreach (EVENT_INFO eventInfo in action.m_EventInfoLst) { if (eventInfo is not FX_BASE_INFO fx || fx.m_strFilePaths == null) continue; foreach (string path in fx.m_strFilePaths) { if (string.IsNullOrWhiteSpace(path) || !path.Contains("gfx", StringComparison.OrdinalIgnoreCase)) continue; string basename = LogPanelAnimeScene.GfxBasename(path); if (string.IsNullOrEmpty(basename)) continue; yield return new CombinedActionGfxEntry(action, fx, path, actionName, basename, phase); } } } } public static bool MatchesFilters( CombinedActionGfxEntry entry, CombinedActionGfxPhase phaseFilter, string actionFilter, string basenameFilter) { if (phaseFilter != CombinedActionGfxPhase.All && entry.Phase != phaseFilter) return false; if (!string.IsNullOrWhiteSpace(actionFilter) && entry.ActionName.IndexOf(actionFilter, StringComparison.OrdinalIgnoreCase) < 0) return false; if (!string.IsNullOrWhiteSpace(basenameFilter) && entry.GfxBasename.IndexOf(basenameFilter, StringComparison.OrdinalIgnoreCase) < 0) return false; return true; } public static bool RemoveEntry(CombinedActionSO so, CombinedActionGfxEntry entry) { return RemovePath(so, entry.Action, entry.FxEvent, entry.Path); } public static bool RemovePath(CombinedActionSO so, A3DCombinedAction action, FX_BASE_INFO fxEvent, string path) { if (so == null || action == null || fxEvent == null || string.IsNullOrWhiteSpace(path)) return false; Undo.RecordObject(so, "Remove GFX Event"); if (!ApplyRemoval(action, fxEvent, path)) return false; EditorUtility.SetDirty(so); AssetDatabase.SaveAssets(); return true; } public static int RemoveMatchingBasenameFromPhase( CombinedActionSO so, string basename, CombinedActionGfxPhase phase) { if (so == null || string.IsNullOrWhiteSpace(basename) || phase == CombinedActionGfxPhase.All) return 0; Undo.RecordObject(so, "Remove GFX Events"); int removed = 0; var toRemove = new List<(A3DCombinedAction action, FX_BASE_INFO fx, string path)>(); foreach (CombinedActionGfxEntry entry in Scan(so)) { if (entry.Phase != phase) continue; if (!string.Equals(entry.GfxBasename, basename, StringComparison.OrdinalIgnoreCase)) continue; toRemove.Add((entry.Action, entry.FxEvent, entry.Path)); } foreach ((A3DCombinedAction action, FX_BASE_INFO fx, string path) item in toRemove) { if (ApplyRemoval(item.action, item.fx, item.path)) removed++; } if (removed > 0) { EditorUtility.SetDirty(so); AssetDatabase.SaveAssets(); } return removed; } static bool ApplyRemoval(A3DCombinedAction action, FX_BASE_INFO fxEvent, string path) { if (action == null || fxEvent == null || string.IsNullOrWhiteSpace(path)) return false; if (fxEvent.m_strFilePaths != null && fxEvent.m_strFilePaths.Count > 1) { if (!fxEvent.m_strFilePaths.Remove(path)) return false; if (fxEvent.m_strFilePaths.Count == 0 && action.m_EventInfoLst != null) action.m_EventInfoLst.Remove(fxEvent); } else if (action.m_EventInfoLst != null) { if (!action.m_EventInfoLst.Remove(fxEvent)) return false; } else { return false; } return true; } }