Files
test/Assets/ModelRenderer/Editor/CombinedActionGfxQuery.cs
2026-05-29 10:02:16 +07:00

214 lines
6.4 KiB
C#

// 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<CombinedActionGfxEntry> 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;
}
}