Add more precise life time manager for gfx

This commit is contained in:
Tran Hai Nam
2026-05-27 11:05:11 +07:00
parent ef5689055e
commit aaaf589ef7
18 changed files with 29802 additions and 48 deletions
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fd4abef93430bca4682d8ab452a246b7
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -93124,7 +93124,7 @@ ParticleSystem:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2701600085856382526}
serializedVersion: 8
lengthInSec: 20
lengthInSec: 2
simulationSpeed: 1
stopAction: 0
cullingMode: 0
@@ -181200,7 +181200,7 @@ ParticleSystem:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7464649752712418363}
serializedVersion: 8
lengthInSec: 20
lengthInSec: 2
simulationSpeed: 1
stopAction: 0
cullingMode: 0
@@ -5045,7 +5045,7 @@ ParticleSystem:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3552871021763365661}
serializedVersion: 8
lengthInSec: 100000
lengthInSec: 3
simulationSpeed: 1
stopAction: 0
cullingMode: 0
@@ -14770,14 +14770,14 @@ ParticleSystem:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5430282689790728998}
serializedVersion: 8
lengthInSec: 100000
lengthInSec: 3
simulationSpeed: 1
stopAction: 0
cullingMode: 0
ringBufferMode: 0
ringBufferLoopRange: {x: 0, y: 1}
emitterVelocityMode: 0
looping: 0
looping: 1
prewarm: 0
playOnAwake: 0
useUnscaledTime: 0
@@ -19661,7 +19661,7 @@ ParticleSystem:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5710796646422175874}
serializedVersion: 8
lengthInSec: 0.3
lengthInSec: 3
simulationSpeed: 1
stopAction: 0
cullingMode: 0
@@ -49,7 +49,7 @@ ParticleSystem:
ringBufferLoopRange: {x: 0, y: 1}
emitterVelocityMode: 0
looping: 1
prewarm: 1
prewarm: 0
playOnAwake: 1
useUnscaledTime: 0
autoRandomSeed: 1
@@ -9713,7 +9713,7 @@ ParticleSystem:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5361231896778627509}
serializedVersion: 8
lengthInSec: 7.2
lengthInSec: 0.72
simulationSpeed: 1
stopAction: 0
cullingMode: 0
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e90308105a31b6743aa5cfe1db61c2bf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,209 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: yuanhuanpurple
m_Shader: {fileID: 4800000, guid: 0a016a83287664641b867743f19faf14, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:
- _DISSOLVETEXUVS_NORMAL
- _DISTORTTEXUVS_NORMAL
- _MAINTEXUVS_NORMAL
- _MASKTEXUVS_NORMAL
m_InvalidKeywords:
- _DISSOLVETEXAR_ON
- _DISTORTTEXAR_ON
- _MASKTEXAR_ON
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DissolveTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DistortTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: 1714058caa22a3a478730e24f420b8fc, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MaskTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaCutoff: 0.5
- _AlphaToMask: 0
- _Blend: 0
- _BlendMode: 1
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _CullMode: 0
- _CustomDissolve: 0
- _CustomMainTex: 0
- _Cutoff: 0.5
- _DepthFade: 1
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DissolveFactor: 0
- _DissolveSoft: 0.1
- _DissolveTexAR: 1
- _DissolveTexClampU: 0
- _DissolveTexClampV: 0
- _DissolveTexRotate: 0
- _DissolveTexUSpeed: 0
- _DissolveTexUVS: 0
- _DissolveTexVSpeed: 0
- _DissolveWide: 0.05
- _DistortDissolveTex: 0
- _DistortFactor: 0
- _DistortMainTex: 0
- _DistortMaskTex: 0
- _DistortTexAR: 1
- _DistortTexClampU: 0
- _DistortTexClampV: 0
- _DistortTexRotate: 0
- _DistortTexUSpeed: 0
- _DistortTexUVS: 0
- _DistortTexVSpeed: 0
- _Dst: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _FDepth: 0
- _FDissolveTex: 0
- _FDistortTex: 0
- _FFnl: 0
- _FMaskTex: 0
- _FnlPower: 1
- _FnlScale: 0
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _MainAlpha: 1
- _MainTexAR: 0
- _MainTexClampU: 0
- _MainTexClampV: 0
- _MainTexRotate: 0
- _MainTexUSpeed: 0
- _MainTexUVS: 0
- _MainTexVSpeed: 0
- _MaskTexAR: 1
- _MaskTexClampU: 0
- _MaskTexClampV: 0
- _MaskTexRotate: 0
- _MaskTexUSpeed: 0
- _MaskTexUVS: 0
- _MaskTexVSpeed: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReFnl: 0
- _ReceiveShadows: 1
- _Scr: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _DissolveColor: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _FnlColor: {r: 1, g: 1, b: 1, a: 1}
- _MainColor: {r: 2.0000002, g: 2.0000002, b: 2.0000002, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &6085187289834300244
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 9
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 210db5088cb0298479121e14abbb039d
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: 1714058caa22a3a478730e24f420b8fc
IHVImageFormatImporter:
externalObjects: {}
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
isReadable: 0
sRGBTexture: 1
streamingMipmaps: 0
streamingMipmapsPriority: 0
ignoreMipmapLimit: 0
mipmapLimitGroupName:
userData:
assetBundleName:
assetBundleVariant:
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:56de257a0dc137130cb44b00462bc5a346cf8f292d1178fb31e138075b1fdb8c
size 137951
oid sha256:d6a8ecae27ef44213a7965bfcb0e1cfcf30a013734f9c6fd14095d6440259005
size 145407
@@ -0,0 +1,156 @@
using System.Collections.Generic;
using BrewMonster.Scripts;
namespace BrewMonster
{
public sealed class FadeOutGfx
{
public int m_dwTotalTTL;
public int m_dwTTL;
public GFX_BINDING m_pGfx;
public float m_fAlpha;
}
/// <summary>
/// Queues skill/combined-action GFX for delayed stop (fade-out window), aligned with A3DGFXExMan::UpdateFadeOutGfxLst.
/// </summary>
public class A3DGfxMan : IAutoInitialize, ITickable
{
public const int DefaultFadeOutMs = 1000;
private static A3DGfxMan _instance;
readonly Dictionary<int, List<GFX_BINDING>> _releaseByModel = new Dictionary<int, List<GFX_BINDING>>();
readonly List<FadeOutGfx> _fadeOutList = new List<FadeOutGfx>();
readonly List<GFX_BINDING> _flushBuffer = new List<GFX_BINDING>();
public static A3DGfxMan Instance => _instance ??= new A3DGfxMan();
public void Initialize()
{
_instance = this;
TickInvoker.Instance.RegisterTickable(this);
}
public bool Tick(uint dwDeltaTime)
{
if (_fadeOutList.Count == 0)
return true;
int deltaTime = (int)dwDeltaTime;
for (int i = _fadeOutList.Count - 1; i >= 0; i--)
{
FadeOutGfx entry = _fadeOutList[i];
GFX_BINDING gfx = entry.m_pGfx;
if (gfx == null)
{
_fadeOutList.RemoveAt(i);
continue;
}
entry.m_dwTTL -= deltaTime;
if (entry.m_dwTTL > 0)
{
_fadeOutList[i] = entry;
continue;
}
gfx.Stop();
_fadeOutList.RemoveAt(i);
}
return true;
}
public void Dispose()
{
_fadeOutList.Clear();
_releaseByModel.Clear();
_flushBuffer.Clear();
}
public void AddReleaseGfx(int modelId, GFX_BINDING gfx)
{
if (gfx == null)
return;
if (!_releaseByModel.TryGetValue(modelId, out List<GFX_BINDING> list))
{
list = new List<GFX_BINDING>(4);
_releaseByModel[modelId] = list;
}
list.Add(gfx);
}
public int GetPendingReleaseCount(int modelId)
{
return _releaseByModel.TryGetValue(modelId, out List<GFX_BINDING> list) ? list.Count : 0;
}
/// <summary>
/// Fade out the oldest <paramref name="maxCount"/> pending GFX for a model (cast/chant phase snapshot).
/// 淡出该模型最早注册的 maxCount 个待释放特效(吟唱阶段快照)。
/// </summary>
public void FadeOutReleaseUpTo(int modelId, int maxCount, int fadeMs = DefaultFadeOutMs)
{
if (maxCount <= 0
|| !_releaseByModel.TryGetValue(modelId, out List<GFX_BINDING> releaseList)
|| releaseList.Count == 0)
return;
int count = maxCount < releaseList.Count ? maxCount : releaseList.Count;
QueueFadeOutFromReleaseList(releaseList, count, fadeMs);
if (releaseList.Count == 0)
_releaseByModel.Remove(modelId);
}
/// <summary>
/// Fade out every pending combined-action GFX registered for a model.
/// 淡出该模型所有待释放的组合动作特效。
/// </summary>
public void FadeOutGfx(int modelId, int fadeMs = DefaultFadeOutMs)
{
if (!_releaseByModel.TryGetValue(modelId, out List<GFX_BINDING> releaseList)
|| releaseList.Count == 0)
return;
QueueFadeOutFromReleaseList(releaseList, releaseList.Count, fadeMs);
_releaseByModel.Remove(modelId);
}
void QueueFadeOutFromReleaseList(List<GFX_BINDING> releaseList, int count, int fadeMs)
{
_flushBuffer.Clear();
for (int i = 0; i < count; i++)
{
GFX_BINDING gfx = releaseList[i];
if (gfx != null)
_flushBuffer.Add(gfx);
}
releaseList.RemoveRange(0, count);
for (int i = 0; i < _flushBuffer.Count; i++)
{
GFX_BINDING gfx = _flushBuffer[i];
if (gfx == null)
continue;
_fadeOutList.Add(new FadeOutGfx
{
m_dwTotalTTL = fadeMs,
m_dwTTL = fadeMs,
m_pGfx = gfx,
m_fAlpha = 1f,
});
}
_flushBuffer.Clear();
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: befe34413c2133549ab038e380847780
@@ -72,9 +72,15 @@ namespace BrewMonster
[SerializeField] private Button channelCancelButton;
private Coroutine _channelingCoroutine;
private Coroutine _fadeChantGfxCoroutine;
private Coroutine _fadeAttackGfxCoroutine;
private int _channelingSkillId;
private bool _isChanneling;
private const float k_FadeChantGfxDelaySecs = 0.5f;
private const float k_DefaultAttackGfxDurationSecs = 2f;
private const float k_AttackGfxFadeBufferSecs = 0.25f;
/// <summary>
/// World position of the draggable target marker, read by CECSkillGfxMan.get_pos_by_id.
/// 可拖动目标标记的世界坐标,由 CECSkillGfxMan.get_pos_by_id 读取。
@@ -100,6 +106,7 @@ namespace BrewMonster
if (channelCancelButton != null)
channelCancelButton.onClick.RemoveListener(CancelChanneling);
StopChanneling();
StopFadeGfxCoroutines();
if (Instance == this)
Instance = null;
}
@@ -480,6 +487,61 @@ namespace BrewMonster
StopChanneling();
}
private void StopFadeGfxCoroutines()
{
if (_fadeChantGfxCoroutine != null)
{
StopCoroutine(_fadeChantGfxCoroutine);
_fadeChantGfxCoroutine = null;
}
if (_fadeAttackGfxCoroutine != null)
{
StopCoroutine(_fadeAttackGfxCoroutine);
_fadeAttackGfxCoroutine = null;
}
}
private int GetPlayerModelId() => player?.GetPlayerModel()?.GetId() ?? 0;
/// <summary>
/// CECModel path: release active channel FX into A3DGfxMan queue, then fade all pending GFX.
/// CECModel 路径:先把仍挂在通道上的特效 Release 进 A3DGfxMan,再统一淡出。
/// </summary>
private void FinishPlayerSkillGfx()
{
player?.GetPlayerModel()?.ClearComActFlagAllRankNodes(true);
}
private void FadeOutChantGfxUpTo(int maxCount, int fadeMs = A3DGfxMan.DefaultFadeOutMs)
{
int modelId = GetPlayerModelId();
if (modelId != 0)
A3DGfxMan.Instance.FadeOutReleaseUpTo(modelId, maxCount, fadeMs);
}
private void ScheduleFadeChantGfxAfterCast()
{
if (_fadeChantGfxCoroutine != null)
{
StopCoroutine(_fadeChantGfxCoroutine);
_fadeChantGfxCoroutine = null;
}
_fadeChantGfxCoroutine = StartCoroutine(FadeChantGfxAfterCastRoutine());
}
private void ScheduleFadeAllGfxWhenAttackStopped(int attackTimeMs)
{
if (_fadeAttackGfxCoroutine != null)
{
StopCoroutine(_fadeAttackGfxCoroutine);
_fadeAttackGfxCoroutine = null;
}
_fadeAttackGfxCoroutine = StartCoroutine(FadeOutAttackGfxAfterComplete(attackTimeMs));
}
private void StopChanneling()
{
_isChanneling = false;
@@ -491,11 +553,13 @@ namespace BrewMonster
_channelingCoroutine = null;
}
StopFadeGfxCoroutines();
if (player == null)
return;
player.StopSkillAttackAction();
EventBus.PublishChannel(player.GetCharacterID(), new ClearComActFlagAllRankNodesEvent(true));
FinishPlayerSkillGfx();
CECAttackerEvents attackerEvents =
CECAttacksMan.Instance?.FindAttackByAttacker(player.GetPlayerInfo().cid);
@@ -546,6 +610,8 @@ namespace BrewMonster
if (_isChanneling)
StopChanneling();
StopFadeGfxCoroutines();
logPanelAnimeScene.Reset();
int skillId = skill.GetSkillID();
logPanelAnimeScene.AddCopyTextButton("ID", skillId.ToString());
@@ -564,6 +630,10 @@ namespace BrewMonster
if (!animOk)
Debug.LogWarning($"[SkillTriggerPanel] PlaySkillCastAction returned false for skill {skillId} — animation may not play.");
// 0.5s: fade chant GFX only (A3DGfxMan snapshot). Cast release + attack fade together when attack ends.
// 0.5 秒:仅淡出吟唱特效;施法释放与攻击特效在攻击结束时同时淡出。
ScheduleFadeChantGfxAfterCast();
// // 2. Trigger VFX via the GFX composer — bypasses network entirely
// // 通过特效组合器触发特效,完全绕过网络
// var composerMan = CECAttacksMan.Instance?.GetSkillGfxComposerMan();
@@ -604,7 +674,7 @@ namespace BrewMonster
if (!_isChanneling || hostPlayer == null)
yield break;
TriggerLocalSkillAttack(hostPlayer, skillId, replayAttackAnim: false);
TriggerLocalSkillAttack(hostPlayer, skillId, replayAttackAnim: true);
while (_isChanneling && hostPlayer != null)
{
@@ -631,6 +701,57 @@ namespace BrewMonster
TriggerLocalSkillAttack(hostPlayer, skillId, replayAttackAnim);
}
/// <summary>
/// 0.5s after cast: fade chant GFX only via <see cref="A3DGfxMan.FadeOutReleaseUpTo"/>.
/// 施法 0.5 秒后:仅淡出已注册的吟唱特效。
/// </summary>
private IEnumerator FadeChantGfxAfterCastRoutine()
{
yield return null;
int modelId = GetPlayerModelId();
if (modelId == 0)
yield break;
yield return new WaitForSeconds(k_FadeChantGfxDelaySecs);
_fadeChantGfxCoroutine = null;
if (player == null)
yield break;
modelId = GetPlayerModelId();
if (modelId == 0)
yield break;
int chantGfxCount = A3DGfxMan.Instance.GetPendingReleaseCount(modelId);
FadeOutChantGfxUpTo(chantGfxCount);
}
/// <summary>
/// Wait for attack duration, flush active FX via CECModel.Release, then A3DGfxMan fade-out.
/// IsActionStopped() alone is unreliable here (empty channel reads as stopped before attack starts).
/// 等待攻击时长,经 CECModel 释放仍活跃的特效,再由 A3DGfxMan 淡出。
/// </summary>
private IEnumerator FadeOutAttackGfxAfterComplete(int attackTimeMs)
{
yield return null;
float attackSecs = attackTimeMs > 0
? attackTimeMs / 1000f
: k_DefaultAttackGfxDurationSecs;
yield return new WaitForSeconds(attackSecs + k_AttackGfxFadeBufferSecs);
_fadeAttackGfxCoroutine = null;
if (player == null)
yield break;
// One frame for UpdateChannelActs → Stop() → Release() → AddReleaseGfx.
yield return null;
FinishPlayerSkillGfx();
}
/// <summary>
/// Local-only skill hit: mirrors <see cref="CECPlayer.PlayAttackEffect"/> for debug panel.
/// When <paramref name="replayAttackAnim"/> is true (channeling tick), signal prior attack so anim replays.
@@ -686,8 +807,8 @@ namespace BrewMonster
if (!ok)
BMLogger.LogWarning($"[SkillTriggerPanel] PlaySkillAttackAction returned false for skill {skillId} — attack anim may not play.");
if (attackTime != 0)
attackTime = 0;
if(!replayAttackAnim)
ScheduleFadeAllGfxWhenAttackStopped(attackTime);
}
}
}
+18 -23
View File
@@ -7,13 +7,12 @@ using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using UnityEngine;
using ModelViewer.Common;
using BrewMonster;
using CombinedActMap = System.Collections.Generic.Dictionary<string, object>;
using CoGfxMap = System.Collections.Generic.Dictionary<string, object>;
using ConvexHullDataArray = System.Collections.Generic.List<object>;
using ECModelHookMap = System.Collections.Generic.Dictionary<string, object>;
using ActQueue = System.Collections.Generic.List<A3DCombActDynData>;
using BrewMonster;
using BrewMonster.Scripts.ECModel;
using Cysharp.Threading.Tasks;
using Unity.VisualScripting.FullSerializer;
@@ -70,6 +69,7 @@ public class FX_BINDING_BASE
public virtual bool IsStart() {return false;}
public virtual void Stop() {}
public virtual void Render() {}
public virtual void Release() {}
public virtual void UpdateParam(CECModel pECModel, int nDeltaTime) {}
public void SetInfo(EVENT_INFO pInfo) { m_pInfo = pInfo; }
public EVENT_INFO GetInfo() { return m_pInfo; }
@@ -100,6 +100,10 @@ public class GFX_BINDING : FX_BINDING_BASE
_destroyScheduled = true;
DestroyAfterParticlesFinish().Forget();
}
public override void Release()
{
A3DGfxMan.Instance.AddReleaseGfx(m_pDynData.GetHostModel().GetId(), this);
}
async UniTaskVoid DestroyAfterParticlesFinish()
{
@@ -414,7 +418,7 @@ public class A3DCombActDynData
GFX:
{
path = "gfx/" + path;
Debug.Log("[GFX_BINDING] LoadFXFromEventList: " + path);
BMLogger.Log("[GFX_BINDING] LoadFXFromEventList: " + path);
GameObject prefab = await AddressableManager.Instance.LoadPrefabAsync(path);
GFX_BINDING fx = new GFX_BINDING(this);
if(prefab != null && m_pECModel != null)
@@ -427,7 +431,7 @@ public class A3DCombActDynData
}
else if (prefab == null)
{
Debug.LogWarning("Missing gfx prefab, using placeholder: " + path);
BMLogger.LogWarning("Missing gfx prefab, using placeholder: " + path);
string path2 = "gfx/人物/技能/妖兽/NullDefault.gfx";
GameObject prefab2 = await AddressableManager.Instance.LoadPrefabAsync(path2);
var gfx = GameObject.Instantiate(prefab2, m_pECModel.transform);
@@ -507,8 +511,7 @@ public class A3DCombActDynData
}
public void Stop(bool bStopAct, bool bForceStopFx = false )
{
Debug.Log("[DefaultPolicy]Stop: " + m_pAct?.m_strName + " bStopAct: " + bStopAct + " bForceStopFx: " + bForceStopFx);
RemoveAllActiveFx();
RemoveAllActiveFx(bForceStopFx);
if (ActiveAttackEvent != null)
{
ActiveAttackEvent.m_bSignaled = true;
@@ -641,7 +644,7 @@ public class A3DCombActDynData
bool IsCurActFinished(ACTION_INFO pCur)
{
return !pCur.IsInfinite() || m_nCurActLoop >= m_arrActLoopNum[m_nCurActIndex].GetLoopNum();
return !pCur.IsInfinite() && m_nCurActLoop >= m_arrActLoopNum[m_nCurActIndex].GetLoopNum();
}
bool IsAllEventFinished() { return m_ActFxArray.Count == 0 ; }
public bool IsActionStopped()
@@ -671,14 +674,17 @@ public class A3DCombActDynData
Play(m_nChannel, m_fWeight, m_nTransTime, m_dwEventMask, false, m_bAbsTrack, m_bNoFx);
}
}
public void RemoveAllActiveFx()
public void RemoveAllActiveFx(bool bForceStopFx = false)
{
foreach(var fx in m_ActFxArray)
{
if(fx != null)
{
Debug.Log("RemoveAllActiveFx: " + fx.GetInfo()?.m_pAct?.m_strName);
fx.Stop();
if(bForceStopFx)
{
fx.Stop();
}
fx.Release();
}
}
m_ActFxArray.Clear();
@@ -1004,14 +1010,6 @@ public class CECModelStaticData
public IReadOnlyDictionary<int, uint> GetActionEventMaskSnapshot() => m_EventMasks;
public void OnScriptEndAction(CECModel pModel, int nChannel, string szActName)
{
if (!IsScriptEnabled(ECMScript.enumECMScriptEndActioin))
return;
Debug.LogWarning($"CECModelStaticData.OnScriptEndAction invoked for {szActName}, scripting runtime not yet ported.");
}
public void Reset()
{
m_OrgColor = 0xFFFFFFFF;
@@ -1340,7 +1338,6 @@ public class CECModel
if (!string.IsNullOrEmpty(hangerName) && childModel != null)
{
m_childModels[hangerName] = childModel;
BMLogger.Log($"[CECModel] Registered child model '{hangerName}'");
}
}
@@ -1355,7 +1352,6 @@ public class CECModel
{
if (m_childModels.Remove(hangerName))
{
BMLogger.Log($"[CECModel] Unregistered child model '{hangerName}'");
}
}
}
@@ -1575,6 +1571,7 @@ public class CECModel
{
foreach (var ca in m_ChannelActs)
ca?.Release();
A3DGfxMan.Instance.FadeOutGfx(GetId());
EventBus.PublishChannel(m_nId, new ClearComActFlagAllRankNodesEvent(bSignalCurrent));
return false;
}
@@ -1626,9 +1623,9 @@ public class CECModel
public void StopChannelAction(int nChannel, bool bStopAct, bool bStopFx = false)
{
ChannelAct ca = m_ChannelActs[nChannel];
A3DGfxMan.Instance.FadeOutGfx(GetId());
foreach (var node in ca.m_RankNodes)
{
Debug.Log("[DefaultPolicy]StopChannelAction: " + node.m_pActive?.GetComAct()?.m_strName);
node.m_pActive.Stop(bStopAct, bStopFx);
}
ca.m_RankNodes.Clear();
@@ -1671,12 +1668,10 @@ public class CECModel
bool bActFinished = false;
if (node.m_dwFlagMode == COMACT_FLAG_MODE_ONCE_IGNOREGFX || node.m_dwFlagMode == COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX)
{
BMLogger.Log("[DefaultPolicy] Checking IsActionStopped: " + node.m_pActive?.GetComAct()?.m_strName);
bActFinished = node.m_pActive.IsActionStopped();
}
else
{
BMLogger.Log("[DefaultPolicy] Checking IsAllFinished: " + node.m_pActive?.GetComAct()?.m_strName);
bActFinished = node.m_pActive.IsAllFinished();
}
if (bActFinished)
@@ -165,8 +165,6 @@ namespace BrewMonster
public void StopSkillAttackAction()
{
BMLogger.Log("[DefaultPolicy]StopSkillAttackAction: " + m_bSkillAttackActionPlayed);
BMLogger.Log("[DefaultPolicy]IsPlayingCastingSkillAction: " + m_actionPlayPolicy.IsPlayingCastingSkillAction());
if (m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction() && m_bSkillAttackActionPlayed)
{
m_actionPlayPolicy.StopSkillAction();
@@ -357,8 +357,6 @@ namespace BrewMonster
&& GetModel().PlayActionByName(szActName, 1.0f, bRestart, nTransTime, true, (uint)iAction , bNoFx, attackEvent, dwFlagMode);
if (!check)
{
// BMLogger.LogError($"Fall back to base implementation: {szActName} failed");
//fallback to base implementation(which is non policy based)
base.PlayNonSkillActionWithName(iAction, szActName, bRestart, nTransTime, bNoFx, attackEvent, dwFlagMode);
}
return check;
@@ -369,8 +367,6 @@ namespace BrewMonster
&& GetModel().QueueAction(szActName, nTransTime, (uint)iAction, bForceStopPrevAct, false, bNoFx, bResetSpeed, bResetActFlag, attackEvent, dwNewFlagMode);
if (!check)
{
// BMLogger.LogError($"Fall back to base implementation: {szActName} failed");
//fallback to base implementation(which is non policy based)
base.QueueNonSkillActionWithName(iAction, szActName, nTransTime, bForceStopPrevAct, bNoFx, bResetSpeed, bResetActFlag, attackEvent, dwNewFlagMode);
}
return check;
@@ -379,7 +375,6 @@ namespace BrewMonster
if (IsMoving()){
return false;
}
BMLogger.Log("[DefaultPolicy] PlaySkillCastActionWithName:" + szActName);
ClearComActFlagAllRankNodes(true);
bool check = GetModel()!=null
&& GetModel().PlayActionByName(szActName, 1.0f, true, 200, true, (uint)PLAYER_ACTION_TYPE.ACT_CASTSKILL, bNoFX);
@@ -389,7 +384,6 @@ namespace BrewMonster
if (IsMoving()){
return false;
}
BMLogger.Log("[DefaultPolicy] Checking PlaySkillAttackActionWithName:" + szActName);
ClearComActFlagAllRankNodes(true);
bool check = GetModel() != null
&& GetModel().PlayActionByName(szActName, 1.0f, true, 200, true, (uint)PLAYER_ACTION_TYPE.ACT_CASTSKILL, bNoFX, attackEvent, dwFlagMode);
@@ -415,14 +409,12 @@ namespace BrewMonster
}
public override void StopChannelAction(){
if (GetModel()!=null){
BMLogger.Log("[DefaultPolicy]StopChannelAction: " + GetModel().GetCurActionUserData());
ClearComActFlagAllRankNodes(true);
GetModel().StopChannelAction(0, true);
}
}
public override void StopSkillAction(){
if (GetModel()!=null && IsPlayingCastingSkillAction()){
BMLogger.Log("[DefaultPolicy]StopSkillAction: " + GetModel().GetCurActionUserData());
StopChannelAction();
}
}