Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MCIllagersMod v1.0.4
Illagers.dll
Decompiled 13 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using REPOLib.Modules; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.Serialization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("Luca")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Illager enemies (Vindicator) for R.E.P.O.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+35c7f069872c93e96508ede468dac450cb04f289")] [assembly: AssemblyProduct("Illagers")] [assembly: AssemblyTitle("Illagers")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Illagers { public sealed class EvokerBehaviour : MonoBehaviour { private enum GroundMiss { None, NoGround, Blocked, HeightTolerance } [Header("引用(G1 第 7 条 / G5 第 7 条)")] [Tooltip("同一 Controller 上的表现层组件;由 EvokerVisuals 拖入这里。")] public EvokerVisuals Visuals; [Tooltip("恼鬼专用的 Enemy Setup(G8 第 4 条)。**不要**为它创建会进自然刷怪池的 EnemyContent。")] public EnemySetup VexSetup; [Tooltip("恼鬼 Prefab。用于独立注册网络 Prefab(不走 EnemyContent 的自然敌人注册路径)。")] public GameObject VexPrefab; [Tooltip("地刺 Prefab(G5 第 1 条)。仅作为本地展示物的模板,不注册网络 Prefab。")] public GameObject FangPrefab; [Tooltip("不死图腾 Prefab(G7)。掉落时走网络 Prefab 生成。")] public GameObject TotemPrefab; [Tooltip("施法表现的原点(G5 第 6 条):直线阵型的起点方向、召唤点的参考。必须挂在稳定节点下,**不要**放进会被双模型显隐关闭的子树。")] public Transform SpellOrigin; [Tooltip("E3 的 3 个出生点(G5 第 6 条)。数量与顺序对应 EvokerTuning.SummonCount。")] public Transform[] SummonPoints; private const float MovingSpeedThreshold = 0.1f; private const float IdleVoiceIntervalMin = 4f; private const float IdleVoiceIntervalMax = 7f; private const float DespawnDelay = 1.17f; private const float GroundSearchUp = 1.5f; private const float GroundSearchDown = 3f; private const float MinSupportNormalY = 0.5f; private const float OccupancyRadius = 0.15f; private const float OccupancyProbeHeight = 0.5f; private const int GroundBufferSize = 24; private int _skipNoGround; private int _skipBlocked; private int _skipHeight; private const float LineStartOffset = 1f; private const float WarnInterval = 10f; private EnemyBombThrower _bomb; private Enemy _enemy; private EnemyParent _parent; private EnemyHealth _health; private EnemyStateStunned _stunState; private EnemyNavMeshAgent _navMesh; private PhotonView _photonView; private bool _initDone; private bool _initOk; private bool _isAuthority; private EvokerCastPhase _phase = EvokerCastPhase.None; private int _spawnGeneration; private float _actionEndsAt; private EvokerSpell _currentSpell = EvokerSpell.None; private float _gapEndsAt; private int _castSequence; private float _summonReadyAt; private float _fangReadyAt; private bool _firstSummonDone; private bool _exitCleanupDone; private bool _summonAvailable; private bool _fangAvailable; private float _lastSummonWarnAt = -20f; private float _lastFangWarnAt = -20f; private float _lastGroundWarnAt = -20f; private int _lastHealthMax = -1; private int _lastHealthCurrent = -1; private EvokerVisualState _appliedVisual = (EvokerVisualState)(-1); private float _idleVoiceTimer; private EvokerCastPhase _netPhase = EvokerCastPhase.None; private EvokerSpell _netSpell = EvokerSpell.None; private float _netActionEndsAt; private EvokerCastPhase _lastSyncedCastPhase = (EvokerCastPhase)(-1); private bool _despawning; private float _despawnTimer; private bool _deathDropDone; private bool _healthEventsBound; private readonly RaycastHit[] _groundBuffer = (RaycastHit[])(object)new RaycastHit[24]; private readonly Collider[] _overlapBuffer = (Collider[])(object)new Collider[12]; private static int _playerLayer = int.MinValue; private static int _levelMask = int.MinValue; internal EvokerCastPhase CurrentPhase => _phase; internal bool CastInFlight => _phase != EvokerCastPhase.None; internal float CastRemainingSeconds => _actionEndsAt - Time.time; internal int SpawnGeneration => _spawnGeneration; private static bool DebugOn => Plugin.DebugLogging != null && Plugin.DebugLogging.Value; private static int PlayerLayer { get { if (_playerLayer == int.MinValue) { _playerLayer = LayerMask.NameToLayer("Player"); } return _playerLayer; } } private static int LevelMask { get { if (_levelMask == int.MinValue) { _levelMask = LayerMask.GetMask(new string[1] { "Default" }); } return _levelMask; } } private EvokerCastPhase DisplayPhase => _isAuthority ? _phase : _netPhase; private EvokerSpell DisplaySpell => _isAuthority ? _currentSpell : _netSpell; private float DisplayActionEndsAt => _isAuthority ? _actionEndsAt : _netActionEndsAt; private float CastNormalizedTime { get { float num = 1f; if (num <= 0f) { return 0f; } float num2 = Mathf.Clamp(DisplayActionEndsAt - Time.time, 0f, num); return Mathf.Clamp01((num - num2) / num); } } internal static EvokerBehaviour FindOn(EnemyBombThrower controller) { return ((Object)(object)controller == (Object)null) ? null : ((Component)controller).GetComponent<EvokerBehaviour>(); } internal static EvokerBehaviour FindOnAnim(EnemyBombThrowerAnim anim) { return ((Object)(object)anim == (Object)null) ? null : FindOn(anim.controller); } internal static EvokerBehaviour FindOnHead(EnemyBombThrowerHead head) { return ((Object)(object)head == (Object)null) ? null : FindOn(head.controller); } private void Awake() { EnsureInit(); } private void OnEnable() { if (EnsureInit()) { ResetForSpawn(); } } private void OnDisable() { if (_initOk) { EnterExitCleanup("退场/失活"); } } private void OnDestroy() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown if ((Object)(object)_health != (Object)null && _healthEventsBound) { UnityEvent onHurt = _health.onHurt; if (onHurt != null) { onHurt.RemoveListener(new UnityAction(OnHurtCallback)); } UnityEvent onDeath = _health.onDeath; if (onDeath != null) { onDeath.RemoveListener(new UnityAction(OnDeathCallback)); } _healthEventsBound = false; } } private void Update() { if (!EnsureInit()) { return; } try { _isAuthority = SemiFunc.IsMasterClientOrSingleplayer(); UpdateVisualState(); UpdateIdleVoice(Time.deltaTime); UpdateDespawn(); if (_isAuthority) { EnsureMaxHealth(); SyncHealthToClients(); SyncCastPhaseToClients(); TickCasting(Time.time); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Evoker] Update 异常(本帧已跳过,下帧继续):" + ex)); } } } private bool EnsureInit() { if (_initDone) { return _initOk; } _initDone = true; try { _bomb = ((Component)this).GetComponent<EnemyBombThrower>(); _enemy = ((Component)this).GetComponent<Enemy>() ?? ((Component)this).GetComponentInParent<Enemy>(); _parent = ((Component)this).GetComponentInParent<EnemyParent>(); _health = ((Component)this).GetComponent<EnemyHealth>(); _stunState = ((Component)this).GetComponent<EnemyStateStunned>(); _navMesh = ((Component)this).GetComponent<EnemyNavMeshAgent>(); if ((Object)(object)_bomb == (Object)null || (Object)(object)_enemy == (Object)null || (Object)(object)_parent == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)"[Evoker] EvokerBehaviour 必须与 EnemyBombThrower / Enemy 同挂 Enable/Controller,并通过父物体找到 EnemyParent。组件已停用,不做半死不活的静默运行。"); } _initOk = false; ((Behaviour)this).enabled = false; return false; } _photonView = (((Object)(object)_enemy.PhotonView != (Object)null) ? _enemy.PhotonView : ((Component)this).GetComponent<PhotonView>()); _fangAvailable = (Object)(object)FangPrefab != (Object)null; if (_fangAvailable) { EvokerNetwork.SetFangPrefab(FangPrefab); } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)"[Evoker] FangPrefab 未拖引用:地刺技能已关闭(不会用空壳假装释放成功,G5 第 1/7 条)。GUI 里请把 Prefabs/EvokerFang.prefab 拖到该字段。"); } } _summonAvailable = (Object)(object)VexSetup != (Object)null && (Object)(object)VexPrefab != (Object)null; if (_summonAvailable) { EvokerSummons.SetVexAssets(VexSetup, VexPrefab); } else { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)"[Evoker] VexSetup / VexPrefab 未拖引用:召唤技能已关闭(G8 第 4 条)。"); } } if ((Object)(object)TotemPrefab != (Object)null) { EvokerSummons.SetTotemPrefab(TotemPrefab); } else { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogWarning((object)"[Evoker] TotemPrefab 未拖引用:死亡不会掉落不死图腾(D1),其余功能不受影响。"); } } if ((Object)(object)Visuals == (Object)null) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogWarning((object)"[Evoker] EvokerVisuals 未拖引用:动画与语音全部静默跳过(G1 第 7 条)。"); } } if ((Object)(object)SpellOrigin == (Object)null) { ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogWarning((object)"[Evoker] SpellOrigin 未拖引用:直线阵型退回用自身 Transform 定方向(G5 第 6 条)。"); } } if (SummonPoints == null || SummonPoints.Length == 0) { ManualLogSource log7 = Plugin.Log; if (log7 != null) { log7.LogWarning((object)"[Evoker] SummonPoints 未配:召唤点为空,SummonBatch 会拿不到出生点(G5 第 6 条要求数量与 EvokerTuning.SummonCount 对应)。"); } } VerifyVisionDots(); DisableLegacyHurtCollider(); MuteLegacySounds(); SuppressLegacyParticles(); ResetLegacyHead(); BindHealthEvents(); _initOk = true; ManualLogSource log8 = Plugin.Log; if (log8 != null) { log8.LogInfo((object)("[Evoker] 初始化完成:" + EvokerTuning.Preview())); } ManualLogSource log9 = Plugin.Log; if (log9 != null) { log9.LogInfo((object)("[Evoker] 能力:地刺=" + (_fangAvailable ? "开" : "关") + ",召唤=" + (_summonAvailable ? "开" : "关") + ",图腾=" + (_healthEventsBound ? "开" : "关") + ",表现层=" + (((Object)(object)Visuals != (Object)null) ? "有" : "无"))); } return true; } catch (Exception ex) { _initOk = false; ManualLogSource log10 = Plugin.Log; if (log10 != null) { log10.LogError((object)("[Evoker] 初始化异常,组件已停用:" + ex)); } ((Behaviour)this).enabled = false; return false; } } internal void ResetForSpawn() { _spawnGeneration++; _phase = EvokerCastPhase.None; _currentSpell = EvokerSpell.None; _gapEndsAt = 0f; _actionEndsAt = 0f; _castSequence = 0; _firstSummonDone = false; _exitCleanupDone = false; _summonReadyAt = 0f; _fangReadyAt = 0f; _despawning = false; _despawnTimer = 0f; _deathDropDone = false; _appliedVisual = (EvokerVisualState)(-1); _idleVoiceTimer = Random.Range(4f, 7f); _lastHealthMax = -1; _lastHealthCurrent = -1; _netPhase = EvokerCastPhase.None; _netSpell = EvokerSpell.None; _netActionEndsAt = 0f; _lastSyncedCastPhase = (EvokerCastPhase)(-1); ResetLegacyHead(); Visuals?.ResetForSpawn(); if ((Object)(object)_parent != (Object)null && !_parent.Spawned) { Plugin.Debug("[Evoker] ResetForSpawn 时 EnemyParent.Spawned 仍为 false(SpawnRPC 尚未执行)"); } if (SemiFunc.IsMasterClientOrSingleplayer()) { EnsureMaxHealth(); EnemyHealth health = _health; if (health != null) { health.OnSpawn(); } } else if (SemiFunc.IsMultiplayer() && (Object)(object)_photonView != (Object)null && (Object)(object)_parent != (Object)null && _parent.Spawned) { _photonView.RPC("RequestSyncRPC", (RpcTarget)2, Array.Empty<object>()); } } private void EnterExitCleanup(string reason) { if (!_exitCleanupDone) { _exitCleanupDone = true; if (_phase != EvokerCastPhase.None) { Plugin.Debug($"[Evoker] 取消未释放的施法({reason})阶段={_phase} 技能={_currentSpell}"); ClearAction(); } _netPhase = EvokerCastPhase.None; _netSpell = EvokerSpell.None; _netActionEndsAt = 0f; Visuals?.ApplyState(EvokerVisualState.Stand); _appliedVisual = EvokerVisualState.Stand; Visuals?.HideCastParticles(); } } private void TickCasting(float now) { switch (_phase) { case EvokerCastPhase.None: { EvokerSpell evokerSpell = SelectSpell(now); if (evokerSpell != EvokerSpell.None) { BeginAction(now, evokerSpell); } break; } case EvokerCastPhase.Gap: if (!GateOk(requireDistance: true, "空档结束")) { CancelAction("空档结束时门控失效"); } else if (!(now < _gapEndsAt)) { _phase = EvokerCastPhase.Casting; Visuals?.PlayVoice(EvokerVoice.Cast); Plugin.Debug($"[Evoker] 开始施法 {_currentSpell},释放时刻 {_actionEndsAt:F2}"); } break; case EvokerCastPhase.Casting: { if (now < _actionEndsAt) { break; } if (!GateOk(requireDistance: true, "释放")) { CancelAction("释放时门控失效"); break; } EvokerSpell currentSpell = _currentSpell; if (!TryGetTarget(out var target)) { CancelAction("释放时无有效目标"); break; } if (currentSpell switch { EvokerSpell.Summon => ReleaseSummon(now), EvokerSpell.Fang => ReleaseFang(now, target), _ => false, }) { _castSequence++; switch (currentSpell) { case EvokerSpell.Summon: _firstSummonDone = true; _summonReadyAt = now + IllagerConfig.EvokerSummonCooldown.Value; break; case EvokerSpell.Fang: _fangReadyAt = now + IllagerConfig.EvokerFangCooldown.Value; break; } Plugin.Debug($"[Evoker] 释放#{_castSequence} {currentSpell}(召唤就绪 {_summonReadyAt:F2}," + $"地刺就绪 {_fangReadyAt:F2})"); } else { Plugin.Debug($"[Evoker] {currentSpell} 释放失败:不消耗 CD,下一帧重新走门控"); } ClearAction(); break; } } } private EvokerSpell SelectSpell(float now) { if (!GateOk(requireDistance: true, "选技能")) { return EvokerSpell.None; } if (!_firstSummonDone) { if (!_summonAvailable) { WarnThrottled(ref _lastSummonWarnAt, "[Evoker] 首次施法必须是召唤,但召唤能力已关闭(VexSetup/VexPrefab 缺失):唤魔者将一直不起手,直到补齐引用。"); return EvokerSpell.None; } return (now >= _summonReadyAt) ? EvokerSpell.Summon : EvokerSpell.None; } bool flag = _summonAvailable && now >= _summonReadyAt; bool flag2 = _fangAvailable && now >= _fangReadyAt; if (flag && flag2) { return (!(_fangReadyAt < _summonReadyAt)) ? EvokerSpell.Summon : EvokerSpell.Fang; } if (flag) { return EvokerSpell.Summon; } if (flag2) { return EvokerSpell.Fang; } return EvokerSpell.None; } private void BeginAction(float now, EvokerSpell spell) { float num = ((_castSequence == 0) ? 0f : 1.5f); _currentSpell = spell; _phase = EvokerCastPhase.Gap; _gapEndsAt = now + num; _actionEndsAt = _gapEndsAt + 1f; Plugin.Debug($"[Evoker] 起手 {spell}:空档 {num:F2}s," + $"施法 {1f:F2}s,释放 {_actionEndsAt:F2}"); } private void CancelAction(string reason) { if (_phase != EvokerCastPhase.None) { Plugin.Debug($"[Evoker] 取消施法({reason})阶段={_phase} 技能={_currentSpell}"); ClearAction(); } } private void ClearAction() { _phase = EvokerCastPhase.None; _currentSpell = EvokerSpell.None; _gapEndsAt = 0f; _actionEndsAt = 0f; } private bool GateOk(bool requireDistance, string phaseLabel) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Invalid comparison between Unknown and I4 //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Invalid comparison between Unknown and I4 //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Invalid comparison between Unknown and I4 //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_parent != (Object)null && !_parent.Spawned) { return false; } if ((Object)(object)_health != (Object)null && (_health.dead || _health.healthCurrent <= 0)) { return false; } if ((Object)(object)_enemy != (Object)null && (int)_enemy.CurrentState == 11) { return false; } if (IsStunned()) { return false; } State currentState = _bomb.currentState; if ((int)currentState != 5 && (int)currentState != 6) { return false; } if (!TryGetTarget(out var target)) { return false; } if (requireDistance) { float num = Vector3.Distance(((Component)target).transform.position, ((Component)this).transform.position); float value = IllagerConfig.EvokerEngageRange.Value; if (num > value) { if (DebugOn) { Plugin.Debug($"[Evoker] {phaseLabel}:目标 {num:F2}m > 接敌范围 {value:F1}m"); } return false; } } return true; } private bool TryGetTarget(out PlayerAvatar target) { target = (((Object)(object)_bomb != (Object)null) ? _bomb.playerTarget : null); if ((Object)(object)target == (Object)null || target.isDisabled) { target = null; return false; } if (target.deadSet) { target = null; return false; } return true; } private bool ReleaseSummon(float now) { if (!_summonAvailable) { WarnThrottled(ref _lastSummonWarnAt, "[Evoker] 召唤失败:VexSetup / VexPrefab 未配(技能已关闭)。"); return false; } if (SummonPoints == null || SummonPoints.Length == 0) { WarnThrottled(ref _lastSummonWarnAt, "[Evoker] 召唤失败:SummonPoints 为空(G5 第 6 条)。"); return false; } int num; try { num = EvokerSummons.SummonBatch(_parent, SummonPoints, 3, _spawnGeneration); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Evoker] 召唤抛异常,本次按失败处理(不消耗 CD):" + ex)); } return false; } if (num <= 0) { WarnThrottled(ref _lastSummonWarnAt, $"[Evoker] 召唤失败:SummonBatch 返回 {num}(期望 {3})。" + "首次标记与 CD 都不消耗,会限频重试。"); return false; } Plugin.Debug($"[Evoker] 召唤成功 {num}/{3} 只恼鬼(代次 {_spawnGeneration})"); return true; } private bool ReleaseFang(float now, PlayerAvatar target) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) if (!_fangAvailable) { WarnThrottled(ref _lastFangWarnAt, "[Evoker] 地刺失败:FangPrefab 未配(技能已关闭)。"); return false; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(((Component)this).transform.position.x, 0f, ((Component)this).transform.position.z); Vector3 forward = ((Component)this).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { forward = Vector3.forward; } else { ((Vector3)(ref forward)).Normalize(); } Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(((Component)target).transform.position.x, 0f, ((Component)target).transform.position.z); float baseYaw = YawOf(forward); float y; if (TryGetSurfaceBelowPoint(val2, ((Component)target).transform.position.y, out var ground)) { y = ground.y; } else { y = ((Component)this).transform.position.y; if (DebugOn) { Plugin.Debug("[Evoker] 玩家脚下采样不到支撑面,基准层退回施法者 Y(本次落点可能仍落在施法者那一层)"); } } List<EvokerFangShot> list = new List<EvokerFangShot>(10); int skipped = 0; _skipNoGround = 0; _skipBlocked = 0; _skipHeight = 0; float num = Vector3.Distance(val, val2); if (num <= 3f) { BuildCircle(val, baseYaw, y, list, ref skipped); } else { BuildLine(val, val2, forward, y, list, ref skipped); } if (skipped > 0) { string arg = $"{_skipNoGround} / 墙内 {_skipBlocked} / 高差 {_skipHeight}"; Plugin.Debug($"[Evoker] 地刺批次:跳过 {skipped} 个候选点(无地面 {arg})" + ",保留原序号与延迟"); WarnThrottled(ref _lastGroundWarnAt, $"[Evoker] 地刺批次有 {skipped} 个点没生成(无地面 {arg}),已跳过。" + $"高差那一档的阈值是 {2.5f:F1}m;" + "墙内那一档由 OccupancyRadius 控制。若整批都被跳过,检查 Scene 里地面层与采样搜索区间。"); } if (list.Count == 0) { WarnThrottled(ref _lastFangWarnAt, "[Evoker] 地刺批次为空:全部候选点都没有有效地面,本次不生成(不消耗 CD)。"); return false; } int casterViewId = (((Object)(object)_photonView != (Object)null) ? _photonView.ViewID : 0); int casterOwnerTag = PillagerNetwork.OwnerTagFromEnemyIndex(((Object)(object)_enemy != (Object)null) ? SemiFunc.EnemyGetIndex(_enemy) : (-1)); bool flag; try { flag = EvokerNetwork.RaiseFangBatch(casterViewId, casterOwnerTag, _spawnGeneration, _castSequence + 1, list); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Evoker] 地刺批次广播抛异常,本次按失败处理(不消耗 CD):" + ex)); } return false; } if (!flag) { WarnThrottled(ref _lastFangWarnAt, "[Evoker] 地刺批次未广播出去(网络未就绪 / 载荷非法):本批作废,不消耗 CD。"); return false; } Plugin.Debug($"[Evoker] 地刺释放#{_castSequence + 1}:{list.Count} 根" + string.Format("({0},距离 {1:F2}m,", (num <= 3f) ? "圆阵" : "直线", num) + $"首延迟 {0.5f:F2}s)"); return true; } private void BuildCircle(Vector3 center, float baseYaw, float groundLevelY, List<EvokerFangShot> shots, ref int skipped) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) int startIndex = 0; startIndex = AppendRing(center, baseYaw, 6, 2f, 1f, startIndex, groundLevelY, shots, ref skipped); AppendRing(center, baseYaw, 10, 3f, -1f, startIndex, groundLevelY, shots, ref skipped); } private int AppendRing(Vector3 center, float baseYaw, int count, float radius, float direction, int startIndex, float groundLevelY, List<EvokerFangShot> shots, ref int skipped) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (count <= 0) { return startIndex; } float num = 360f / (float)count; int num2 = startIndex; int num3 = 0; while (num3 < count) { float num4 = baseYaw + direction * num * (float)num3; Vector3 horizontalPoint = center + DirOfYaw(num4) * radius; TryAddFang(horizontalPoint, groundLevelY, num4, num2, shots, ref skipped); num3++; num2++; } return num2; } private void BuildLine(Vector3 casterHoriz, Vector3 targetHoriz, Vector3 forwardHoriz, float groundLevelY, List<EvokerFangShot> shots, ref int skipped) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) Vector3 val = targetHoriz - casterHoriz; val.y = 0f; Vector3 val2; Vector3 val3; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val2 = forwardHoriz; val3 = casterHoriz + val2 * 4f; } else { val2 = ((Vector3)(ref val)).normalized; val3 = casterHoriz + val2 * 15f; } Vector3 val4 = casterHoriz + val2 * 1f; int num = 16; for (int i = 0; i < num; i++) { float num2 = ((num <= 1) ? 0f : ((float)i / (float)(num - 1))); Vector3 val5 = Vector3.Lerp(val4, val3, num2); Vector3 direction = val5 - casterHoriz; direction.y = 0f; float yaw = ((((Vector3)(ref direction)).sqrMagnitude < 0.0001f) ? YawOf(forwardHoriz) : YawOf(direction)); TryAddFang(val5, groundLevelY, yaw, i, shots, ref skipped); } } private void TryAddFang(Vector3 horizontalPoint, float groundLevelY, float yaw, int index, List<EvokerFangShot> shots, ref int skipped) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!SampleGround(horizontalPoint, groundLevelY, out var ground, out var miss)) { skipped++; switch (miss) { case GroundMiss.Blocked: _skipBlocked++; break; case GroundMiss.HeightTolerance: _skipHeight++; break; default: _skipNoGround++; break; } } else { shots.Add(new EvokerFangShot { Delay = 0.5f + (float)index * 0.05f, Position = ground, Yaw = yaw }); } } private int GatherSupportCandidates(Vector3 horizontalPoint, float rayBaseY, out int blockedFiltered) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) blockedFiltered = 0; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(horizontalPoint.x, rayBaseY + 1.5f, horizontalPoint.z); float num = 4.5f; int num2 = Physics.RaycastNonAlloc(val, Vector3.down, _groundBuffer, num, LevelMask, (QueryTriggerInteraction)1); if (num2 <= 0) { return 0; } if (num2 >= _groundBuffer.Length) { WarnThrottled(ref _lastGroundWarnAt, $"[Evoker] 地面采样命中缓冲已满({num2}),该点跳过。房间结构过于密集时会看到这条日志。"); return 0; } for (int i = 1; i < num2; i++) { RaycastHit val2 = _groundBuffer[i]; int num3 = i - 1; while (num3 >= 0 && ((RaycastHit)(ref _groundBuffer[num3])).distance > ((RaycastHit)(ref val2)).distance) { _groundBuffer[num3 + 1] = _groundBuffer[num3]; num3--; } _groundBuffer[num3 + 1] = val2; } int result = 0; for (int j = 0; j < num2; j++) { RaycastHit val3 = _groundBuffer[j]; if (!((Object)(object)((RaycastHit)(ref val3)).collider == (Object)null) && !(((RaycastHit)(ref val3)).normal.y < 0.5f) && !IsMovableEntityCollider(((RaycastHit)(ref val3)).collider)) { if (IsBlockedAt(((RaycastHit)(ref val3)).point, ((RaycastHit)(ref val3)).collider)) { blockedFiltered++; } else { _groundBuffer[result++] = val3; } } } return result; } private bool TryGetSurfaceBelowPoint(Vector3 horizontalPoint, float rayBaseY, out Vector3 ground) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) ground = default(Vector3); int blockedFiltered; int num = GatherSupportCandidates(horizontalPoint, rayBaseY, out blockedFiltered); if (num <= 0) { return false; } float num2 = rayBaseY + 0.05f; for (int i = 0; i < num; i++) { if (!(((RaycastHit)(ref _groundBuffer[i])).point.y > num2)) { ground = ((RaycastHit)(ref _groundBuffer[i])).point; return true; } } return false; } private bool SampleGround(Vector3 horizontalPoint, float groundLevelY, out Vector3 ground, out GroundMiss miss) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) ground = default(Vector3); miss = GroundMiss.None; int blockedFiltered; int num = GatherSupportCandidates(horizontalPoint, groundLevelY, out blockedFiltered); if (num <= 0) { miss = ((blockedFiltered <= 0) ? GroundMiss.NoGround : GroundMiss.Blocked); return false; } int num2 = -1; float num3 = float.MaxValue; for (int i = 0; i < num; i++) { float num4 = Mathf.Abs(((RaycastHit)(ref _groundBuffer[i])).point.y - groundLevelY); if (num4 < num3) { num3 = num4; num2 = i; } } if (num2 < 0) { miss = GroundMiss.NoGround; return false; } if (num3 >= 2.5f) { miss = GroundMiss.HeightTolerance; return false; } ground = ((RaycastHit)(ref _groundBuffer[num2])).point; return true; } private bool IsBlockedAt(Vector3 ground, Collider support) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ground + Vector3.up * 0.5f; int num = Physics.OverlapSphereNonAlloc(val, 0.15f, _overlapBuffer, LevelMask, (QueryTriggerInteraction)1); if (num <= 0) { return false; } if (num >= _overlapBuffer.Length) { return true; } for (int i = 0; i < num; i++) { Collider val2 = _overlapBuffer[i]; if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)support) && !IsMovableEntityCollider(val2)) { return true; } } return false; } private static bool IsMovableEntityCollider(Collider c) { if ((Object)(object)c == (Object)null) { return true; } if (((Component)c).gameObject.layer == PlayerLayer) { return true; } if ((Object)(object)((Component)c).GetComponentInParent<PlayerAvatar>() != (Object)null || (Object)(object)((Component)c).GetComponentInParent<PlayerHealth>() != (Object)null) { return true; } if ((Object)(object)((Component)c).GetComponentInParent<EnemyParent>() != (Object)null) { return true; } if ((Object)(object)((Component)c).GetComponentInParent<PhysGrabObject>() != (Object)null) { return true; } return false; } private static Vector3 DirOfYaw(float yawDegrees) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) float num = yawDegrees * (MathF.PI / 180f); return new Vector3(Mathf.Sin(num), 0f, Mathf.Cos(num)); } private static float YawOf(Vector3 direction) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Mathf.Atan2(direction.x, direction.z) * 57.29578f; } private void UpdateVisualState() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) EvokerCastPhase displayPhase = DisplayPhase; EvokerVisualState evokerVisualState; if (displayPhase == EvokerCastPhase.Casting) { evokerVisualState = EvokerVisualState.Cast; goto IL_0079; } int num; if ((Object)(object)_navMesh != (Object)null && (Object)(object)_navMesh.Agent != (Object)null && ((Behaviour)_navMesh.Agent).enabled) { Vector3 velocity = _navMesh.Agent.velocity; if (((Vector3)(ref velocity)).sqrMagnitude > 0.010000001f) { num = 1; goto IL_0077; } } num = 0; goto IL_0077; IL_0077: evokerVisualState = (EvokerVisualState)num; goto IL_0079; IL_0079: if (evokerVisualState != _appliedVisual) { EvokerVisualState appliedVisual = _appliedVisual; _appliedVisual = evokerVisualState; Visuals?.ApplyState(evokerVisualState, (evokerVisualState == EvokerVisualState.Cast) ? CastNormalizedTime : 0f); if (evokerVisualState == EvokerVisualState.Cast) { Visuals?.ShowCastParticles(DisplaySpell); } else if (appliedVisual == EvokerVisualState.Cast) { Visuals?.HideCastParticles(); } } } private void UpdateIdleVoice(float dt) { if ((Object)(object)_health != (Object)null && (_health.dead || _health.healthCurrent <= 0)) { _idleVoiceTimer = 0f; return; } if ((Object)(object)_parent != (Object)null && !_parent.Spawned) { _idleVoiceTimer = 0f; return; } if (IsStunned()) { _idleVoiceTimer = 0f; return; } if (DisplayPhase != EvokerCastPhase.None) { _idleVoiceTimer = Random.Range(4f, 7f); return; } _idleVoiceTimer -= dt; if (!(_idleVoiceTimer > 0f)) { _idleVoiceTimer = Random.Range(4f, 7f); Visuals?.PlayVoice(EvokerVoice.Idle); } } private void UpdateDespawn() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 if (!_isAuthority || (Object)(object)_enemy == (Object)null) { return; } if ((int)_enemy.CurrentState != 11) { if (_despawning) { _despawning = false; _despawnTimer = 0f; } return; } EnemyParent val = (((Object)(object)_enemy.EnemyParent != (Object)null) ? _enemy.EnemyParent : _parent); if ((Object)(object)val == (Object)null) { return; } if (!_despawning) { _despawning = true; _despawnTimer = 1.17f; return; } _despawnTimer -= Time.deltaTime; if (!(_despawnTimer > 0f)) { _despawning = false; if (val.Spawned && (!((Object)(object)_health != (Object)null) || _health.healthCurrent > 0)) { Plugin.Debug("[Evoker] 到点补一次 EnemyParent.Despawn()(原版 Animator 已关,EventDespawn 不会触发)"); val.Despawn(); } } } private void EnsureMaxHealth() { int value = IllagerConfig.EvokerHealth.Value; if (!((Object)(object)_health == (Object)null) && _health.health != value) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Evoker] EnemyHealth.health {_health.health} → {value}" + "(来源:配置项 EvokerHealth)")); } _health.health = value; } } private void SyncHealthToClients() { if (!((Object)(object)_photonView == (Object)null) && SemiFunc.IsMultiplayer() && !((Object)(object)_health == (Object)null) && (_lastHealthMax != _health.health || _lastHealthCurrent != _health.healthCurrent)) { _lastHealthMax = _health.health; _lastHealthCurrent = _health.healthCurrent; _photonView.RPC("SyncHealthRPC", (RpcTarget)1, new object[2] { _health.health, _health.healthCurrent }); } } [PunRPC] private void SyncHealthRPC(int maxHealth, int currentHealth, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.MasterOnlyRPC(info) && !((Object)(object)_health == (Object)null)) { _health.health = maxHealth; _health.healthCurrent = currentHealth; } } [PunRPC] private void RequestSyncRPC(PhotonMessageInfo info = default(PhotonMessageInfo)) { if (SemiFunc.IsMasterClientOrSingleplayer()) { _lastHealthMax = -1; _lastHealthCurrent = -1; _lastSyncedCastPhase = (EvokerCastPhase)(-1); Plugin.Debug("[Evoker] 收到快照请求,重置广播标记"); } } private void SyncCastPhaseToClients() { if (!((Object)(object)_photonView == (Object)null) && SemiFunc.IsMultiplayer() && _lastSyncedCastPhase != _phase) { _lastSyncedCastPhase = _phase; float num = Mathf.Max(0f, _actionEndsAt - Time.time); _photonView.RPC("CastPhaseRPC", (RpcTarget)1, new object[3] { (int)_phase, (int)_currentSpell, num }); } } [PunRPC] private void CastPhaseRPC(int phase, int spell, float remainingSeconds, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.MasterOnlyRPC(info) && !_isAuthority) { bool flag = phase == 2 && _netPhase != EvokerCastPhase.Casting; _netPhase = (EvokerCastPhase)phase; _netSpell = (EvokerSpell)spell; _netActionEndsAt = Time.time + Mathf.Max(0f, remainingSeconds); if (flag) { Visuals?.PlayVoice(EvokerVoice.Cast); } Plugin.Debug($"[Evoker] 收到施法阶段 {(EvokerCastPhase)phase} / 技能 {_netSpell}(剩余 {remainingSeconds:F2}s),客户端只演出"); } } private void BindHealthEvents() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown if (!_healthEventsBound && !((Object)(object)_health == (Object)null)) { _healthEventsBound = true; EnemyHealth health = _health; if (health.onHurt == null) { health.onHurt = new UnityEvent(); } _health.onHurt.AddListener(new UnityAction(OnHurtCallback)); health = _health; if (health.onDeath == null) { health.onDeath = new UnityEvent(); } _health.onDeath.AddListener(new UnityAction(OnDeathCallback)); } } private void OnHurtCallback() { Visuals?.PlayVoice(EvokerVoice.Hurt); Visuals?.FlashHurt(); } private void OnDeathCallback() { Visuals?.PlayVoice(EvokerVoice.Death); if (!SemiFunc.IsMasterClientOrSingleplayer() || _deathDropDone) { return; } _deathDropDone = true; if ((Object)(object)TotemPrefab == (Object)null) { return; } try { bool flag = EvokerSummons.TryDropTotem(_parent); Plugin.Debug($"[Evoker] 死亡掉落掷签(D1 {IllagerConfig.TotemDropChance.Value:P0}):" + (flag ? "生成图腾" : "未掉落")); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Evoker] 图腾掉落异常(不影响死亡流程):" + ex)); } } } private void VerifyVisionDots() { EnemyVision component = ((Component)this).GetComponent<EnemyVision>(); if ((Object)(object)component == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Evoker] 找不到 EnemyVision:无法核对视野配置(G2)。"); } } else if (component.VisionDotStanding < 0f || component.VisionDotCrouch < 0f || component.VisionDotCrawl < 0f || component.PhysObjectVisionDot < 0f) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Evoker] 视野 Dot 仍是负数(全向感知)—— prefab `Enemy - Evoker` 的 `Controller > Enemy Vision` 没配(基线 Bomb 是四个 -1)。G2 期望 Standing/Crouch/Crawl = 0.4/0.6/0.9、PhysObjectVisionDot = 0.4;当前 = " + $"{component.VisionDotStanding:F2}/{component.VisionDotCrouch:F2}/" + $"{component.VisionDotCrawl:F2}/{component.PhysObjectVisionDot:F2}。")); } } else { Plugin.Debug($"[Evoker] 视野 Dot(来自 prefab):{component.VisionDotStanding:F2}/" + $"{component.VisionDotCrouch:F2}/{component.VisionDotCrawl:F2},物理对象 = {component.PhysObjectVisionDot:F2}"); } } private void DisableLegacyHurtCollider() { Transform val = (((Object)(object)_parent != (Object)null) ? ((Component)_parent).transform : ((Component)this).transform); HurtCollider[] componentsInChildren = ((Component)val).GetComponentsInChildren<HurtCollider>(true); int num = 0; foreach (HurtCollider val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null)) { ((Behaviour)val2).enabled = false; ((Component)val2).gameObject.SetActive(false); num++; Collider[] components = ((Component)val2).GetComponents<Collider>(); for (int j = 0; j < components.Length; j++) { components[j].enabled = false; } } } if (num == 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Evoker] 找不到任何 HurtCollider(预期是 Enable/Visuals 下的 Hurt Collider 节点):G1 第 4 条要求它 inactive 且组件 / 专用 Collider 都取消 enabled,GUI 里请核对。"); } } else { Plugin.Debug($"[Evoker] 已关闭 {num} 个原版 HurtCollider(含同一节点上的专用 Collider)。"); } } private void MuteLegacySounds() { EnemyBombThrowerAnim val = (((Object)(object)_bomb != (Object)null) ? _bomb.anim : null); if ((Object)(object)val == (Object)null) { val = ((Component)this).GetComponentInChildren<EnemyBombThrowerAnim>(true); } if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Evoker] 找不到 EnemyBombThrowerAnim:无法静音原版炸弹音(T1)。"); } return; } FieldInfo[] fields = typeof(EnemyBombThrowerAnim).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int num = MuteSoundFields(val, fields); EnemyBombThrowerHead val2 = (((Object)(object)_bomb != (Object)null) ? _bomb.head : null); if ((Object)(object)val2 != (Object)null) { num += MuteSoundFields(val2, typeof(EnemyBombThrowerHead).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); } if (num > 0) { Plugin.Debug($"[Evoker] 已静音 {num} 条原版炸弹音(清空 Sound.Sounds)。"); } } private static int MuteSoundFields(object target, FieldInfo[] fields) { if (target == null || fields == null) { return 0; } int num = 0; for (int i = 0; i < fields.Length; i++) { if (!(fields[i].FieldType != typeof(Sound))) { object? value = fields[i].GetValue(target); Sound val = (Sound)((value is Sound) ? value : null); if (val != null && (val.Sounds == null || val.Sounds.Length != 0)) { val.Sounds = (AudioClip[])(object)new AudioClip[0]; num++; } } } return num; } private void SuppressLegacyParticles() { EnemyBombThrowerAnim val = (((Object)(object)_bomb != (Object)null) ? _bomb.anim : null); if ((Object)(object)val == (Object)null) { val = ((Component)this).GetComponentInChildren<EnemyBombThrowerAnim>(true); } if (!((Object)(object)val == (Object)null)) { int num = 0; num += StopAll(val.teleportParticles); num += StopAll(val.headDetachParticles); num += StopAll(val.deathParticles); val.teleportParticles = (ParticleSystem[])(object)new ParticleSystem[0]; val.headDetachParticles = (ParticleSystem[])(object)new ParticleSystem[0]; val.deathParticles = (ParticleSystem[])(object)new ParticleSystem[0]; if (num > 0) { Plugin.Debug($"[Evoker] 已停掉 {num} 个原版炸弹粒子并清空 anim 的粒子数组。"); } } } private static int StopAll(ParticleSystem[] systems) { if (systems == null) { return 0; } int num = 0; foreach (ParticleSystem val in systems) { if (!((Object)(object)val == (Object)null)) { val.Stop(true, (ParticleSystemStopBehavior)0); ((Component)val).gameObject.SetActive(false); num++; } } return num; } private void ResetLegacyHead() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Invalid comparison between Unknown and I4 if (!((Object)(object)_bomb == (Object)null)) { if (!_bomb.headGrown) { _bomb.headGrown = true; } if ((Object)(object)_bomb.headCollider != (Object)null && !((Component)_bomb.headCollider).gameObject.activeSelf) { ((Component)_bomb.headCollider).gameObject.SetActive(true); } EnemyBombThrowerHead head = _bomb.head; if ((Object)(object)head != (Object)null && (int)head.currentState > 0) { head.UpdateState((State)0); } } } private bool IsStunned() { if ((Object)(object)_enemy == (Object)null) { return false; } if (_enemy.IsStunned()) { return true; } return (Object)(object)_stunState != (Object)null && _stunState.stunTimer > 0f; } private void WarnThrottled(ref float lastAt, string message) { if (!(Time.time - lastAt < 10f)) { lastAt = Time.time; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)message); } } } } internal static class EvokerBombThrowerPatches { } [HarmonyPatch(typeof(EnemyBombThrower), "MeleeSetLogic")] internal static class PatchEvokerNoMelee { private static bool Prefix(EnemyBombThrower __instance, ref bool __result) { if ((Object)(object)EvokerBehaviour.FindOn(__instance) == (Object)null) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(EnemyBombThrower), "AttackSetLogic")] internal static class PatchEvokerNoHeadAttack { private static bool Prefix(EnemyBombThrower __instance, ref bool __result) { if ((Object)(object)EvokerBehaviour.FindOn(__instance) == (Object)null) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(EnemyBombThrower), "HeadLogic")] internal static class PatchEvokerNoHeadLogic { private static bool Prefix(EnemyBombThrower __instance) { return (Object)(object)EvokerBehaviour.FindOn(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerHead), "UpdateState")] internal static class PatchEvokerNoHeadDetach { private static bool Prefix(EnemyBombThrowerHead __instance, State _state) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 if ((Object)(object)EvokerBehaviour.FindOnHead(__instance) == (Object)null) { return true; } return (int)_state == 0; } } [HarmonyPatch(typeof(EnemyBombThrowerHead), "OnHurtColliderHit")] internal static class PatchEvokerNoHeadImpact { private static bool Prefix(EnemyBombThrowerHead __instance) { return (Object)(object)EvokerBehaviour.FindOnHead(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrower), "TorsoHeadBreakerLogic")] internal static class PatchEvokerNoTorsoHeadBreaker { private static bool Prefix(EnemyBombThrower __instance) { return (Object)(object)EvokerBehaviour.FindOn(__instance) == (Object)null; } } internal static class EvokerCastHold { internal static void Apply(EnemyBombThrower bomb) { try { EvokerBehaviour evokerBehaviour = EvokerBehaviour.FindOn(bomb); if (!((Object)(object)evokerBehaviour == (Object)null) && evokerBehaviour.CastInFlight) { Enemy val = (((Object)(object)bomb != (Object)null) ? bomb.enemy : null); EnemyNavMeshAgent val2 = (((Object)(object)val != (Object)null && (Object)(object)val.NavMeshAgent != (Object)null) ? val.NavMeshAgent : ((Component)bomb).GetComponent<EnemyNavMeshAgent>()); if (!((Object)(object)val2 == (Object)null)) { val2.Stop(Mathf.Max(0.05f, evokerBehaviour.CastRemainingSeconds) + 0.5f); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Evoker] 施法站定异常(本帧不清导航):" + ex)); } } } } [HarmonyPatch(typeof(EnemyBombThrower), "StateGotoPlayer")] internal static class PatchEvokerCastHoldGoto { private static bool Prefix(EnemyBombThrower __instance) { EvokerCastHold.Apply(__instance); return true; } } [HarmonyPatch(typeof(EnemyBombThrower), "StateBackAwayPlayer")] internal static class PatchEvokerCastHoldBackAway { private static bool Prefix(EnemyBombThrower __instance) { EvokerCastHold.Apply(__instance); return true; } } [HarmonyPatch(typeof(EnemyBombThrower), "BackAwayLogic")] internal static class PatchEvokerHoldStillWhileCasting { private static bool Prefix(EnemyBombThrower __instance) { EvokerBehaviour evokerBehaviour = EvokerBehaviour.FindOn(__instance); return (Object)(object)evokerBehaviour == (Object)null || !evokerBehaviour.CastInFlight; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventAttack")] internal static class PatchEvokerNoEventAttack { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventDeath")] internal static class PatchEvokerNoEventDeath { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventHurt")] internal static class PatchEvokerNoEventHurt { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventMelee")] internal static class PatchEvokerNoEventMelee { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventMeleeEnd")] internal static class PatchEvokerNoEventMeleeEnd { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventLand")] internal static class PatchEvokerNoEventLand { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventJump")] internal static class PatchEvokerNoEventJump { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventTorsoHeadGrow01")] internal static class PatchEvokerNoEventTorsoHeadGrow01 { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventTorsoHeadGrow02")] internal static class PatchEvokerNoEventTorsoHeadGrow02 { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventTorsoHeadGrow03")] internal static class PatchEvokerNoEventTorsoHeadGrow03 { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventTorsoHeadsScream")] internal static class PatchEvokerNoEventTorsoHeadsScream { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventTorsoHeadsScreamTrigger")] internal static class PatchEvokerNoEventTorsoHeadsScreamTrigger { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventTorsoHeadsMeleeTrigger")] internal static class PatchEvokerNoEventTorsoHeadsMeleeTrigger { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventTorsoHeadsBreakerShake")] internal static class PatchEvokerNoEventTorsoHeadsBreakerShake { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventFootstepSkinLight")] internal static class PatchEvokerNoEventFootstepSkinLight { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventFootstepSkinHeavy")] internal static class PatchEvokerNoEventFootstepSkinHeavy { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventFootstepBootLight")] internal static class PatchEvokerNoEventFootstepBootLight { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventFootstepBootHeavy")] internal static class PatchEvokerNoEventFootstepBootHeavy { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventTeleportIn")] internal static class PatchEvokerNoEventTeleportIn { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrowerAnim), "EventTeleportOut")] internal static class PatchEvokerNoEventTeleportOut { private static bool Prefix(EnemyBombThrowerAnim __instance) { return (Object)(object)EvokerBehaviour.FindOnAnim(__instance) == (Object)null; } } [HarmonyPatch(typeof(EnemyBombThrower), "StateNotice")] internal static class PatchEvokerShortNotice { private const float NoticeSeconds = 1f; private static void Postfix(EnemyBombThrower __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)__instance.currentState == 4 && !((Object)(object)EvokerBehaviour.FindOn(__instance) == (Object)null)) { FieldRef<EnemyBombThrower, float> val = BombThrowerStateTimer.Get(); if (val != null && val.Invoke(__instance) > 1f) { val.Invoke(__instance) = 1f; } } } } internal static class BombThrowerStateTimer { private static FieldRef<EnemyBombThrower, float> _ref; private static bool _failed; internal static FieldRef<EnemyBombThrower, float> Get() { if (_failed) { return null; } if (_ref != null) { return _ref; } try { _ref = AccessTools.FieldRefAccess<EnemyBombThrower, float>("stateTimer"); } catch (Exception ex) { _failed = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Evoker] 找不到 EnemyBombThrower.stateTimer,相关补丁将保持原版行为:" + ex.Message)); } } return _ref; } } public enum EvokerCastPhase { None, Gap, Casting } public enum EvokerSpell { None, Summon, Fang } public enum EvokerVisualState { Stand, Walk, Cast } public enum EvokerVoice { Idle, Cast, Hurt, Death } public static class EvokerTuning { public const int MaxHealth = 250; public const float EngageRange = 10f; public const int SummonCount = 3; public const float SummonCooldown = 20f; public const float FangCooldown = 5f; public const float PreCastGap = 1.5f; public const float CastDuration = 1f; public const float NearFormationRange = 3f; public const int InnerRingCount = 6; public const int OuterRingCount = 10; public const float OuterRingRadius = 3f; public const float InnerRingRadius = 2f; public const int LineFangCount = 16; public const float FarReachMeters = 15f; public const float FangGroundHeightTolerance = 2.5f; public const float FangDelay = 0.5f; public const float FangInterval = 0.05f; public const int FangDamage = 50; public const int FangEnemyDamage = 50; public const float FangHitCooldownSeconds = 0.2f; public const float FangRiseSeconds = 0.25f; public const float FangHoldSeconds = 0.4f; public const float FangRetractSeconds = 0.3f; public const float FangHitVolumeYOffset = 0.5f; public const float TotemDropChance = 0.2f; public const float TotemRangeMultiplier = 5f; public const float TotemReviveSeconds = 2.5f; private static readonly float[] TotemHealPercentByMoon = new float[5] { 0.5f, 0.45f, 0.4f, 0.3f, 0.25f }; private static readonly string[] TotemHealMoonNames = new string[5] { "无月亮", "新月", "半月", "满月", "超级月亮" }; public const string AnimStateStand = "Stand"; public const string AnimStateWalk = "Walk"; public const string AnimStateCast = "Cast"; private static int ClampMoonLevel(int moonLevel) { if (moonLevel < 0) { return 0; } if (moonLevel >= TotemHealPercentByMoon.Length) { return TotemHealPercentByMoon.Length - 1; } return moonLevel; } public static float TotemHealPercentForMoon(int moonLevel) { return TotemHealPercentByMoon[ClampMoonLevel(moonLevel)]; } public static string TotemHealMoonName(int moonLevel) { return TotemHealMoonNames[ClampMoonLevel(moonLevel)]; } public static string TotemHealPreview() { string text = ""; for (int i = 0; i < TotemHealPercentByMoon.Length; i++) { if (i > 0) { text += " / "; } text = text + TotemHealMoonNames[i] + " " + TotemHealPercentByMoon[i].ToString("P0"); } return text; } public static string Preview() { int value = IllagerConfig.EvokerHealth.Value; float value2 = IllagerConfig.EvokerEngageRange.Value; float value3 = IllagerConfig.EvokerSummonCooldown.Value; float value4 = IllagerConfig.EvokerFangCooldown.Value; int value5 = IllagerConfig.EvokerFangDamage.Value; float value6 = IllagerConfig.TotemDropChance.Value; float value7 = IllagerConfig.TotemRangeMultiplier.Value; return $"血量={value},接敌≤{value2:F1}m" + $",节拍={1.5f:F1}s 空档 + {1f:F1}s 施法(CD:召唤 {value3:F0}s / 地刺 {value4:F0}s)" + $",召唤={3}只" + $",地刺={value5}(对玩家与对怪同源;延迟 {0.5f:F1}s + {0.05f:F2}s×n,受击跨根冷却 {0.2f:F1}s" + $";近圆阵 R{2f:F1}/{3f:F1} {6}+{10} 根" + $" / 远直线 {16} 根 {15f:F0}m,分界 {3f:F1}m)" + $",图腾掉落={value6:P0}(范围×{value7:F0},复活充能 {2.5f:F1}s)" + ",回血=按关卡月亮(" + TotemHealPreview() + ")" + $",协议序(Phase/Spell)={0}/{1}/{2}" + $" · {0}/{1}/{2}"; } } public static class EvokerEventNames { public const string FangBatchEventName = "Illagers.Evoker.FangBatch"; } public static class EvokerFangPayload { public const int HeaderCount = 6; public const int FieldsPerFang = 5; public const int IdxLevelGeneration = 0; public const int IdxCasterViewId = 1; public const int IdxCasterOwnerTag = 2; public const int IdxSpawnGeneration = 3; public const int IdxCastSequence = 4; public const int IdxFangCount = 5; public const int FangDelay = 0; public const int FangX = 1; public const int FangY = 2; public const int FangZ = 3; public const int FangYaw = 4; public static int ExpectedLength(int fangCount) { return 6 + fangCount * 5; } } public sealed class EvokerFang : MonoBehaviour { [Header("表现(G5 第 2/3 条)")] [Tooltip("模型实例的根。以模型地面基准建立,+Y 向上;闭合/埋地状态为初始姿态。")] public Transform VisualRoot; [Tooltip("伤害体积(专用 Trigger / 几何描述)。设 Trigger,不产生物理推挤。有效窗口与显示高度对齐,见 EvokerTuning.FangHitVolumeYOffset。")] public BoxCollider HitVolume; [Header("音效(G5 第 5 条:地刺声音挂自身,不依赖施法者存活)")] public AudioSource AudioSource; [Tooltip("entity.evoker_fangs.attack.fangs。留空则静默,不报错。")] public AudioClip AttackClip; [Header("粒子(破土扬起)")] [Tooltip("地刺「破土升起」时播放的粒子。**必须关掉 Play On Awake** —— 生命周期由本文件按时间线显式启停(升起段 Play、收回段停发射),自动播会和协程抢时机。留空则静默跳过,不报错。注意:这是地刺自己的资产,与唤魔者的施法粒子是**不同的**两份资产,不要复用同一个引用。")] public ParticleSystem RiseParticles; private const float DefaultRiseHeight = 1f; private static readonly Vector3 DefaultHitHalfExtents = new Vector3(0.5f, 0.5f, 0.5f); private static int _targetMask = int.MinValue; private static int _playerLayer = int.MinValue; private bool _configured; private bool _authoritative; private int _index; private int _enemyIndex; private float _delay; private Vector3 _buriedLocal; private Vector3 _risenLocal; private bool _posesCaptured; private readonly HashSet<Component> _hitTargets = new HashSet<Component>(); private static readonly Dictionary<Component, float> _lastHitAt = new Dictionary<Component, float>(); private const float LastHitMemorySeconds = 5f; private const int LastHitPruneThreshold = 16; private bool _warnedSampleError; private static int TargetMask { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (_targetMask == int.MinValue) { LayerMask val = SemiFunc.LayerMaskGetPlayersAndPhysObjects(); int num = ((LayerMask)(ref val)).value; if (num == 0) { num = LayerMask.GetMask(new string[1] { "Player" }); } int mask = LayerMask.GetMask(new string[1] { "Enemy" }); if (mask != 0) { num |= mask; } _targetMask = num; } return _targetMask; } } private static int PlayerLayer { get { if (_playerLayer == int.MinValue) { _playerLayer = LayerMask.NameToLayer("Player"); } return _playerLayer; } } internal void Configure(Vector3 groundPosition, float yaw, int index, float delay, bool authoritative, int enemyIndex) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if (!_configured) { _configured = true; _index = index; _delay = Mathf.Max(0f, delay); _authoritative = authoritative; _enemyIndex = enemyIndex; ((Component)this).transform.position = groundPosition; ((Component)this).transform.rotation = Quaternion.Euler(0f, yaw, 0f); CapturePoses(); ApplyLocalPose(_buriedLocal); Plugin.Debug($"[Evoker] 地刺#{_index} 生成于 ({groundPosition.x:F2},{groundPosition.y:F2},{groundPosition.z:F2})" + $",延迟 {_delay:F2}s,权威={_authoritative},升程 {_risenLocal.y - _buriedLocal.y:F2}m。"); ((MonoBehaviour)this).StartCoroutine(Lifecycle()); } } private IEnumerator Lifecycle() { if (_delay > 0f) { yield return (object)new WaitForSeconds(_delay); } PlayAttackSound(); PlayRiseParticles(); yield return MovePose(_buriedLocal, _risenLocal, 0.25f); yield return HoldWindow(); StopRiseParticles(); yield return MovePose(_risenLocal, _buriedLocal, 0.3f); Object.Destroy((Object)(object)((Component)this).gameObject); } private IEnumerator MovePose(Vector3 from, Vector3 to, float duration) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)VisualRoot == (Object)null) { if (duration > 0f) { yield return (object)new WaitForSeconds(duration); } yield break; } if (duration <= 0f) { ApplyLocalPose(to); yield break; } float elapsed = 0f; while (elapsed < duration) { elapsed += Time.deltaTime; ApplyLocalPose(Vector3.Lerp(from, to, Mathf.Clamp01(elapsed / duration))); yield return null; } ApplyLocalPose(to); } private IEnumerator HoldWindow() { float elapsed = 0f; SampleAndDamage(); while (elapsed < 0.4f) { elapsed += Time.deltaTime; if (elapsed < 0.4f) { SampleAndDamage(); } yield return null; } } private void ApplyLocalPose(Vector3 localPosition) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)VisualRoot == (Object)null)) { VisualRoot.localPosition = localPosition; } } private void PlayAttackSound() { if (!((Object)(object)AudioSource == (Object)null) && !((Object)(object)AttackClip == (Object)null)) { AudioSource.PlayOneShot(AttackClip); } } private void PlayRiseParticles() { if ((Object)(object)RiseParticles == (Object)null) { return; } try { RiseParticles.Play(true); } catch (Exception ex) { Plugin.Debug($"[Evoker] 地刺#{_index} 破土粒子播放失败(时间线不受影响):{ex.Message}"); } } private void StopRiseParticles() { if ((Object)(object)RiseParticles == (Object)null) { return; } try { RiseParticles.Stop(true, (ParticleSystemStopBehavior)1); } catch (Exception ex) { Plugin.Debug($"[Evoker] 地刺#{_index} 破土粒子停止失败(时间线不受影响):{ex.Message}"); } } private void CapturePoses() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (_posesCaptured) { return; } _posesCaptured = true; if ((Object)(object)VisualRoot == (Object)null) { return; } _buriedLocal = VisualRoot.localPosition; float num = 1f; if ((Object)(object)VisualRoot.parent != (Object)null) { num = Mathf.Abs(VisualRoot.parent.lossyScale.y); if (num < 0.0001f) { num = 1f; } } _risenLocal = _buriedLocal + Vector3.up * (MeasureRiseHeight() / num); } private float MeasureRiseHeight() { //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)VisualRoot != (Object)null) { Renderer[] componentsInChildren = ((Component)VisualRoot).GetComponentsInChildren<Renderer>(true); bool flag = false; float num = float.MaxValue; float num2 = float.MinValue; foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && (val is MeshRenderer || val is SkinnedMeshRenderer)) { Bounds bounds = val.bounds; if (((Bounds)(ref bounds)).min.y < num) { num = ((Bounds)(ref bounds)).min.y; } if (((Bounds)(ref bounds)).max.y > num2) { num2 = ((Bounds)(ref bounds)).max.y; } flag = true; } } if (flag && num2 - num > 0.01f) { return num2 - num; } } if ((Object)(object)HitVolume != (Object)null) { float num3 = Mathf.Abs(HitVolume.size.y * ((Component)HitVolume).transform.lossyScale.y); if (num3 > 0.01f) { return num3; } } return 1f; } private void SampleAndDamage() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) if (!_authoritative) { return; } try { Vector3 val = ((Component)this).transform.position + Vector3.up * 0.5f; Vector3 val2 = HitHalfExtents(); Collider[] array = Physics.OverlapBox(val, val2, ((Component)this).transform.rotation, TargetMask, (QueryTriggerInteraction)2); foreach (Collider val3 in array) { if ((Object)(object)val3 == (Object)null) { continue; } PlayerAvatar val4 = ResolvePlayer(val3, val); if ((Object)(object)val4 != (Object)null) { TryDamage(val4); continue; } Enemy val5 = ResolveEnemy(val3); if ((Object)(object)val5 != (Object)null) { TryDamageEnemy(val5, val); } } } catch (Exception arg) { if (!_warnedSampleError) { _warnedSampleError = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Evoker] 地刺#{_index} 命中采样异常(本根后续仍会尝试,只是不刷屏):{arg}"); } } } } private Vector3 HitHalfExtents() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)HitVolume == (Object)null) { return DefaultHitHalfExtents; } Vector3 size = HitVolume.size; Vector3 lossyScale = ((Component)HitVolume).transform.lossyScale; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(Mathf.Abs(size.x * lossyScale.x), Mathf.Abs(size.y * lossyScale.y), Mathf.Abs(size.z * lossyScale.z)); if (val.x <= 0.01f || val.y <= 0.01f || val.z <= 0.01f) { return DefaultHitHalfExtents; } return val * 0.5f; } private static PlayerAvatar ResolvePlayer(Collider collider, Vector3 sampleCenter) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) PlayerTumble componentInParent = ((Component)collider).GetComponentInParent<PlayerTumble>(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.playerAvatar != (Object)null) { return componentInParent.playerAvatar; } if (((Component)collider).gameObject.layer == PlayerLayer) { Bounds bounds = collider.bounds; return NearestPlayer(((Bounds)(ref bounds)).center); } return ((Component)collider).GetComponentInParent<PlayerAvatar>(); } private static PlayerAvatar NearestPlayer(Vector3 point) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) GameDirector instance = GameDirector.instance; List<PlayerAvatar> list = (((Object)(object)instance != (Object)null) ? instance.PlayerList : null); if (list == null) { return null; } PlayerAvatar result = null; float num = float.MaxValue; for (int i = 0; i < list.Count; i++) { PlayerAvatar val = list[i]; if (!((Object)(object)val == (Object)null)) { Vector3 val2 = ((Component)val).transform.position - point; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = val; } } } return result; } private static Enemy ResolveEnemy(Collider collider) { Enemy val = ((Component)collider).GetComponentInParent<Enemy>(); if ((Object)(object)val != (Object)null) { return val; } EnemyParent componentInParent = ((Component)collider).GetComponentInParent<EnemyParent>(); if ((Object)(object)componentInParent != (Object)null) { val = ((Component)componentInParent).GetComponentInChildren<Enemy>(true); } return val; } private void TryDamage(PlayerAvatar player) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (IsPlayerHittable(player) && _hitTargets.Add((Component)(object)player)) { float time = Time.time; if (!_lastHitAt.TryGetValue((Component)(object)player, out var value) || !(time - value < 0.2f)) { RecordLastHit((Component)(object)player, time); int value2 = IllagerConfig.EvokerFangDamage.Value; player.playerHealth.HurtOther(value2, ((Component)player).transform.position, true, _enemyIndex, false); Plugin.Debug($"[Evoker] 地刺#{_index} 命中 {((Object)player).name}:{value2} 点" + $"(归因 enemyIndex={_enemyIndex})。"); } } } private void TryDamageEnemy(Enemy enemy, Vector3 sampleCenter) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) if (!IsEnemyHittable(enemy) || !_hitTargets.Add((Component)(object)enemy)) { return; } float time = Time.time; if (!_lastHitAt.TryGetValue((Component)(object)enemy, out var value) || !(time - value < 0.2f)) { RecordLastHit((Component)(object)enemy, time); Vector3 val = ((Component)enemy).transform.position - sampleCenter; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 1E-06f) { val = Vector3.forward; } else { ((Vector3)(ref val)).Normalize(); } int value2 = IllagerConfig.EvokerFangDamage.Value; enemy.Health.Hurt(value2, val); Plugin.Debug($"[Evoker] 地刺#{_index} 命中怪物 {((Object)enemy).name}:{value2} 点" + $"(击退方向 ({val.x:F2},{val.y:F2},{val.z:F2}),归因 enemyIndex={_enemyIndex} —— 敌人侧无归因参数)。"); } } private bool IsEnemyHittable(Enemy enemy) { if ((Object)(object)enemy == (Object)null) { return false; } EnemyHealth health = enemy.Health; if ((Object)(object)health == (Object)null || !enemy.HasHealth) { return false; } if (health.dead || health.healthCurrent <= 0) { return false; } return !IsExcludedEnemy(enemy); } private bool IsExcludedEnemy(Enemy enemy) { if (_enemyIndex >= 0 && SemiFunc.EnemyGetIndex(enemy) == _enemyIndex) { return true; } if ((Object)(object)((Component)enemy).GetComponent<VexBehaviour>() != (Object)null) { return true; } return false; } private static void RecordLastHit(Component target, float now) { _lastHitAt[target] = now; if (_lastHitAt.Count <= 16) { return; } float num = now - 5f; List<Component> list = null; foreach (KeyValuePair<Component, float> item in _lastHitAt) { if ((Object)(object)item.Key == (Object)null || item.Value < num) { if (list == null) { list = new List<Component>(); } list.Add(item.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { _lastHitAt.Remove(list[i]); } } } internal static void ClearLevelState() { _lastHitAt.Clear(); } private static bool IsPlayerHittable(PlayerAvatar player) { return (Object)(object)player != (Object)null && !player.isDisabled && !player.deadSet && (Object)(object)player.playerHealth != (Object)null; } } internal struct EvokerFangShot { public float Delay; public Vector3 Position; public float Yaw; } internal static class EvokerNetwork { private const int MaxFangsPerBatch = 64; private const float MaxAbsCoordinate = 100000f; private const float MaxFangDelay = 10f; private const float FinishedBatchMemory = 20f; private const int FinishedBatchCap = 128; private static NetworkedEvent _fangEvent; private static bool _inited; private static GameObject _fangPrefab; private static readonly List<EvokerFang> _activeFangs = new List<EvokerFang>(); private static readonly Dictionary<string, float> _finished = new Dictionary<string, float>(); private static readonly List<string> _scratchKeys = new List<string>(); private static readonly List<EvokerFangShot> _parsedShots = new List<EvokerFangShot>(); private static bool _warnedNoPrefab; private static bool _warnedBadPayload; private static bool _warnedNotInited; private static bool _warnedNoIdentity; private static bool _warnedNoComponent; private static bool _warnedTooMany; internal static void Init() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown if (_inited) { return; } _inited = true; _fangEvent = new NetworkedEvent("Illagers.Evoker.FangBatch", (Action<EventData>)OnFangBatch); if (_fangEvent.EventCode == 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)"[Evoker] 网络事件注册失败(事件码为 0):地刺不会联机同步,本地仍可运行。"); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[Evoker] 网络事件已注册:Illagers.Evoker.FangBatch(code=" + _fangEvent.EventCode + ")")); } } } internal static void SetFangPrefab(GameObject fangPrefab) { if ((Object)(object)fangPrefab == (Object)null) { return; } bool flag = _fangPrefab != fangPrefab; _fangPrefab = fangPrefab; if (flag) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Evoker] 资源就绪:地刺 Prefab = " + ((Object)fangPrefab).name)); } } } internal static bool RaiseFangBatch(int casterViewId, int casterOwnerTag, int spawnGeneration, int castSequence, IList<EvokerFangShot> shots) { //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) if (!IsAuthority()) { return false; } if (shots == null || shots.Count == 0) { return false; } if (shots.Count > 64) { WarnOnce(ref _warnedTooMany, "[Evoker] 地刺批次被丢弃:根数超过上限(" + 64 + "),疑似载荷或阵型计算异常。"); return false; } int num = IdentityOf(casterViewId, casterOwnerTag); if (num <= 0) { WarnOnce(ref _warnedNoIdentity, "[Evoker] 地刺批次被丢弃:施法者拿不到 PhotonView.ViewID,也算不出本地合成标识(本批作废)。"); return false; } if (_fangEvent == null || _fangEvent.EventCode == 0) { WarnOnce(ref _warnedNotInited, "[Evoker] 地刺批次被丢弃:网络事件尚未就绪(Init 未成功)。"); return false; } int count = shots.Count; object[] array = new object[EvokerFangPayload.ExpectedLength(count)]; array[0] = LevelGeneration(); array[1] = casterViewId; array[2] = casterOwnerTag; array[3] = spawnGeneration; array[4] = castSequence; array[5] = count; for (int i = 0; i < count; i++) { EvokerFangShot evokerFangShot = shots[i]; int num2 = 6 + i * 5; array[num2] = (IsFinite(evokerFangShot.Delay) ? evokerFangShot.Delay : 0f); array[num2 + 1] = evokerFangShot.Position.x; array[num2 + 2] = evokerFangShot.Position.y; array[num2 + 3] = evokerFangShot.Position.z; array[num2 + 4] = (IsFinite(evokerFangShot.Yaw) ? evokerFangShot.Yaw : 0f); } _fangEvent.RaiseEvent((object)array, NetworkingEvents.RaiseAll, SendOptions.SendReliable); return true; } internal static void ClearLevel() { for (int i = 0; i < _activeFangs.Count; i++) { EvokerFang evokerFang = _activeFangs[i]; if ((Object)(object)evokerFang != (Object)null) { Object.Destroy((Object)(object)((Component)evokerFang).gameObject); } } _activeFangs.Clear(); _finished.Clear(); _parsedShots.Clear(); EvokerFang.ClearLevelState(); _warnedNoPrefab = false; _warnedBadPayload = false; _warnedNotInited = false; _warnedNoIdentity = false; _warnedNoComponent = false; _warnedTooMany = false; Plugin.Debug("[Evoker] ClearLevel:已清理活跃地刺与批次缓存。"); } private static void OnFangBatch(EventData data) { //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) if (!IsFromAuthority(data)) { return; } if (!(data.CustomData is object[] array) || array.Length < 6) { WarnOnce(ref _warnedBadPayload, "[Evoker] 丢弃字段数不符的地刺批次包(协议不一致?)。"); } else { if (!TryInt(array[0], out var value) || value != LevelGeneration() || !TryInt(array[1], out var value2) || !TryInt(array[2], out var value3) || !TryInt(array[3], out var value4) || !TryInt(array[4], out var value5) || value5 <= 0) { return; } if (!TryInt(array[5], out var value6) || value6 <= 0 || value6 > 64 || array.Length != EvokerFangPayload.ExpectedLength(value6)) { WarnOnce(ref _warnedBadPayload, "[Evoker] 丢弃根数非法 / 长度不符的地刺批次包(协议不一致?)。"); return; } int num = IdentityOf(value2, value3); if (num <= 0) { return; } string text = KeyOf(value, num, value4, value5); if (_finished.ContainsKey(text)) { return; } if ((Object)(object)_fangPrefab == (Object)null) { WarnOnce(ref _warnedNoPrefab, "[Evoker] 收到地刺批次但地刺 Prefab 尚未就绪,本批被丢弃。请检查 G5:EvokerBehaviour 的 FangPrefab 是否已拖引用。"); } else { if (!TryParseShots(array, value6)) { return; } bool flag = IsAuthority(); int enemyIndex = (flag ? ResolveEnemyIndex(value2, value3) : (-1)); MarkFinished(text); int num2 = 0; int num3 = 0; for (int i = 0; i < _parsedShots.Count; i++) { Vector3 position = _parsedShots[i].Position; float yaw = _parsedShots[i].Yaw; float delay = _parsedShots[i].Delay; if (!IsFinite(position.x) || !IsFinite(position.y) || !IsFinite(position.z)) { num3++; continue; } GameObject val = null; try { val = Object.Instantiate<GameObject>(_fangPrefab, position, Quaternion.Euler(0f, yaw, 0f)); EvokerFang component = val.GetComponent<EvokerFang>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val); WarnOnce(ref _warnedNoComponent, "[Evoker] 地刺 Prefab 根上没有 EvokerFang,本批地刺未被生成(G5 第 3 条)。"); break; } component.Configure(position, yaw, i, delay, flag, enemyIndex); _activeFangs.Add(component); num2++; } catch (Exception ex) { WarnOnce(ref _warnedNoComponent, "[Evoker] 生成地刺时出错,本批剩余地刺不再生成:" + ex.Message); break; } } Plugin.Debug("[Evoker] 地刺批次 " + text + ":生成 " + num2 + " 根" + ((num3 > 0) ? (",跳过 " + num3 + " 个失效点") : "") + ",权威=" + flag + ",enemyIndex=" + enemyIndex); } } } private static bool TryParseShots(object[] p, int fangCount) { //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) _parsedShots.Clear(); for (int i = 0; i < fangCount; i++) { int num = 6 + i * 5; if (!TryFloat(p[num], out var value) || value < 0f || value > 10f) { return false; } if (!TryFloatRaw(p[num + 1], out var value2) || !TryFloatRaw(p[num + 2], out var value3) || !TryFloatRaw(p[num + 3], out var value4)) { return false; } if (!TryFloat(p[num + 4], out var value5)) { return false; } if ((IsFinite(value2) && Mathf.Abs(value2) > 100000f) || (IsFinite(value3) && Mathf.Abs(value3) > 100000f) || (IsFinite(value4) && Mathf.Abs(value4) > 100000f)) { return false; } _parsedShots.Add(new EvokerFangShot { Delay = value, Position = new Vector3(value2, value3, value4), Yaw = value5 }); } return true; } private static int IdentityOf(int casterViewId, int casterOwnerTag) { return (casterViewId > 0) ? casterViewId : casterOwnerTag; } private static string KeyOf(int levelGen, int identity, int spawnGeneration, int castSequence) { return levelGen + ":" + identity + ":" + spawnGeneration + ":" + castSequence; } private static void MarkFinished(string key) { _finished[key] = Time.time; if (_finished.Count > 128) { PruneFinished(); } } private static void PruneFinished() { float num = Time.time - 20f; _scratchKeys.Clear(); foreach (KeyValuePair<string, float> item in _finished) { if (item.Value < num) { _scratchKeys.Add(item.Key); } } for (int i = 0; i < _scratchKeys.Count; i++) { _finished.Remove(_scratchKeys[i]); } if (_finished.Count > 128) { _scratchKeys.Clear(); _scratchKeys.AddRange(_finished.Keys); _scratchKeys.Sort((string a, string b) => _finished[a].CompareTo(_finished[b])); int num2 = _finished.Count - 128; for (int num3 = 0; num3 < num2 && num3 < _scratchKeys.Count; num3++) { _finished.Remove(_scratchKeys[num3]); } } } private static int ResolveEnemyIndex(int casterViewId, int casterOwnerTag) { try { if (casterViewId > 0) { PhotonView val = PhotonView.Find(casterViewId); if ((Object)(object)val != (Object)null) { Enemy val2 = ((Component)val).GetComponent<Enemy>(); if ((Object)(object)val2 == (Object)null) { EnemyParent componentInParent = ((Component)val).GetComponentInParent<EnemyParent>(); val2 = (((Object)(object)componentInParent != (Object)null) ? componentInParent.Enemy : null); } if ((Object)(object)val2 != (Object)null) { int num = SemiFunc.EnemyGetIndex(val2); if (num >= 0) { return num; } } } } if (casterOwnerTag >= 1000000) { int num2 = casterOwnerTag - 1000000; EnemyDirector instance = EnemyDirector.instance; if ((Object)(object)instance != (Object)null && instance.enemiesSpawned != null) { List<EnemyParent> enemiesSpawned = instance.enemiesSpawned; for (int i = 0; i < enemiesSpawned.Count; i++) { EnemyParent val3 = enemiesSpawned[i]; if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.Enemy == (Object)null) && SemiFunc.EnemyGetIndex(val3.Enemy) == num2) { return num2; } } } } } catch (Exception ex) { Plugin.Debug("[Evoker] 解析施法者敌人索引失败(本次不结