Decompiled source of Zombie Survival World v1.0.0
plugins/Zombie_Survival.dll
Decompiled a day 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.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using AK_Gun; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.Networking; using UnityEngine.SceneManagement; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("좀비서바이벌")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("좀비서바이벌")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("36367a36-a880-4ba0-9250-87e7bd78aa73")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace Reload { [BepInPlugin("reload.akhotkey.spawninhand", "AK Reload NativeUseUI", "4.0.0")] public class Plugin : BaseUnityPlugin, IOnEventCallback { [CompilerGenerated] private sealed class <>c__DisplayClass40_0 { public bool success; internal void <UseThenRefillRoutine>b__0(bool result) { success = result; } } [CompilerGenerated] private sealed class <LoadReloadSoundCoroutine>d__35 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Plugin <>4__this; private string <fileName>5__1; private string <pluginDir>5__2; private string <candidate>5__3; private string <url>5__4; private UnityWebRequest <req>5__5; private DownloadHandlerAudioClip <dl>5__6; private AudioClip <clip>5__7; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadReloadSoundCoroutine>d__35(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <fileName>5__1 = null; <pluginDir>5__2 = null; <candidate>5__3 = null; <url>5__4 = null; <req>5__5 = null; <dl>5__6 = null; <clip>5__7 = null; <>1__state = -2; } private bool MoveNext() { //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Invalid comparison between Unknown and I4 bool result; try { switch (<>1__state) { default: result = false; break; case 0: { <>1__state = -1; <>4__this._reloadSoundLoadTried = true; <fileName>5__1 = <>4__this.GetReloadSoundFileName(); <pluginDir>5__2 = Path.GetDirectoryName(((BaseUnityPlugin)<>4__this).Info.Location); <candidate>5__3 = Path.Combine(<pluginDir>5__2 ?? "", <fileName>5__1); <>4__this._resolvedReloadSoundPath = <candidate>5__3; if (!File.Exists(<candidate>5__3)) { <>4__this.WRN("재장전 사운드 파일을 찾지 못함: " + <candidate>5__3); result = false; break; } <url>5__4 = new Uri(<candidate>5__3).AbsoluteUri; <req>5__5 = UnityWebRequestMultimedia.GetAudioClip(<url>5__4, (AudioType)14); <>1__state = -3; ref DownloadHandlerAudioClip reference = ref <dl>5__6; DownloadHandler downloadHandler = <req>5__5.downloadHandler; reference = (DownloadHandlerAudioClip)(object)((downloadHandler is DownloadHandlerAudioClip) ? downloadHandler : null); if (<dl>5__6 != null) { <dl>5__6.streamAudio = false; } <>2__current = <req>5__5.SendWebRequest(); <>1__state = 1; result = true; break; } case 1: <>1__state = -3; if ((int)<req>5__5.result != 1) { <>4__this.ERR("장전 사운드 로드 실패: " + <req>5__5.error); result = false; } else { <clip>5__7 = DownloadHandlerAudioClip.GetContent(<req>5__5); if (!((Object)(object)<clip>5__7 == (Object)null)) { ((Object)<clip>5__7).name = "CustomReloadSound"; <>4__this._reloadSoundClip = <clip>5__7; <>4__this.DBG("장전 사운드 로드 성공: " + <candidate>5__3 + " / length=" + <clip>5__7.length); <dl>5__6 = null; <clip>5__7 = null; <>m__Finally1(); <req>5__5 = null; result = false; break; } <>4__this.ERR("장전 사운드 AudioClip 생성 실패"); result = false; } <>m__Finally1(); break; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<req>5__5 != null) { ((IDisposable)<req>5__5).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RefillCurrentHeldAKRoutine>d__47 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Action<bool> done; public Plugin <>4__this; private Component <heldAK>5__1; private int <totalUses>5__2; private bool <hasData>5__3; private int <usesValue>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RefillCurrentHeldAKRoutine>d__47(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <heldAK>5__1 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>4__this.DBG("RefillCurrentHeldAKRoutine 진입"); if (!<>4__this.TryGetHeldAK(out <heldAK>5__1) || (Object)(object)<heldAK>5__1 == (Object)null) { <>4__this.ERR("현재 장착된 AK를 찾지 못함"); done(obj: false); return false; } <totalUses>5__2 = <>4__this.ReadIntMember(<heldAK>5__1, "totalUses"); if (<totalUses>5__2 <= 0) { <>4__this.ERR("AK totalUses 값을 읽지 못했거나 0 이하임"); done(obj: false); return false; } if (!<>4__this.TrySetItemUsesToMax(<heldAK>5__1, <totalUses>5__2)) { <>4__this.ERR("현재 들고 있는 AK의 ItemUses 최대치 복원 실패"); done(obj: false); return false; } <>4__this.TryRefreshUseBar(<heldAK>5__1, <totalUses>5__2); <>4__this.TrySyncItemInstanceData(<heldAK>5__1); <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if ((<>4__this.TryReadItemUses(<heldAK>5__1, out <hasData>5__3, out <usesValue>5__4) & <hasData>5__3) && <usesValue>5__4 == <totalUses>5__2) { <>4__this.DBG("현재 들고 있는 AK 재장전 성공: " + <usesValue>5__4 + "/" + <totalUses>5__2); done(obj: true); return false; } <>4__this.ERR("재장전 후 검증 실패"); done(obj: false); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <TryMoveUseProgressUIRoutine>d__36 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Plugin <>4__this; private float <timeout>5__1; private float <elapsed>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TryMoveUseProgressUIRoutine>d__36(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <timeout>5__1 = 10f; <elapsed>5__2 = 0f; break; case 1: <>1__state = -1; break; } if (<elapsed>5__2 < <timeout>5__1) { if (<>4__this.TryMoveUseProgressUI()) { return false; } <elapsed>5__2 += Time.unscaledDeltaTime; <>2__current = null; <>1__state = 1; return true; } <>4__this.WRN("UI_UseItemProgress를 끝내 찾지 못함"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <UseThenRefillRoutine>d__40 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Plugin <>4__this; private Component <heldAK>5__1; private bool <prevShowUseProgress>5__2; private bool <prevOverrideForceProgress>5__3; private float <prevOverrideProgress>5__4; private float <reloadTime>5__5; private <>c__DisplayClass40_0 <>8__6; private float <elapsed>5__7; private Component <currentHeld>5__8; private float <progress>5__9; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <UseThenRefillRoutine>d__40(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 3u) { try { } finally { <>m__Finally1(); } } <heldAK>5__1 = null; <>8__6 = null; <currentHeld>5__8 = null; <>1__state = -2; } private bool MoveNext() { //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) bool result2; try { switch (<>1__state) { default: result2 = false; goto end_IL_0000; case 0: <>1__state = -1; <>4__this._isUsing = true; <>4__this.DBG("UseThenRefillRoutine 시작"); <heldAK>5__1 = null; <prevShowUseProgress>5__2 = true; <prevOverrideForceProgress>5__3 = false; <prevOverrideProgress>5__4 = 0f; <reloadTime>5__5 = <>4__this.GetReloadUseTime(); <>1__state = -3; <>8__6 = new <>c__DisplayClass40_0(); if (!<>4__this.TryGetHeldAK(out <heldAK>5__1) || (Object)(object)<heldAK>5__1 == (Object)null) { <>4__this.ERR("재장전 시작 시 현재 AK를 찾지 못함"); result2 = false; break; } <prevShowUseProgress>5__2 = <>4__this.ReadBoolMember(<heldAK>5__1, "showUseProgress"); <prevOverrideForceProgress>5__3 = <>4__this.ReadBoolMember(<heldAK>5__1, "overrideForceProgress"); <prevOverrideProgress>5__4 = <>4__this.ReadFloatMember(<heldAK>5__1, "overrideProgress"); <>4__this.StartNativeUseProgress(<heldAK>5__1); <>4__this.BroadcastReloadSound(<heldAK>5__1.transform.position); if (<reloadTime>5__5 > 0f) { <elapsed>5__7 = 0f; goto IL_024c; } goto IL_0264; case 1: <>1__state = -3; <currentHeld>5__8 = null; goto IL_024c; case 2: <>1__state = -3; <>8__6.success = false; <>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.RefillCurrentHeldAKRoutine(delegate(bool result) { <>8__6.success = result; })); <>1__state = 3; result2 = true; goto end_IL_0000; case 3: <>1__state = -3; if (<>8__6.success) { <>4__this.DBG("장전 성공"); } else { <>4__this.ERR("장전 실패"); } <>2__current = (object)new WaitForSecondsRealtime(0.05f); <>1__state = 4; result2 = true; goto end_IL_0000; case 4: { <>1__state = -3; <>8__6 = null; <>m__Finally1(); result2 = false; goto end_IL_0000; } IL_0264: <>4__this.UpdateNativeUseProgress(<heldAK>5__1, 1f); <>2__current = null; <>1__state = 2; result2 = true; goto end_IL_0000; IL_024c: if (!(<elapsed>5__7 < <reloadTime>5__5)) { goto IL_0264; } if (!<>4__this.TryGetHeldAK(out <currentHeld>5__8) || (Object)(object)<currentHeld>5__8 == (Object)null || (Object)(object)<currentHeld>5__8 != (Object)(object)<heldAK>5__1) { <>4__this.WRN("재장전 중 손에 든 AK가 바뀌어서 취소"); result2 = false; break; } <elapsed>5__7 += Time.unscaledDeltaTime; <progress>5__9 = Mathf.Clamp01(<elapsed>5__7 / <reloadTime>5__5); <>4__this.UpdateNativeUseProgress(<heldAK>5__1, <progress>5__9); <>2__current = null; <>1__state = 1; result2 = true; goto end_IL_0000; } <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result2; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if ((Object)(object)<heldAK>5__1 != (Object)null) { <>4__this.RestoreNativeUseProgress(<heldAK>5__1, <prevShowUseProgress>5__2, <prevOverrideForceProgress>5__3, <prevOverrideProgress>5__4); } <>4__this._isUsing = false; <>4__this.DBG("UseThenRefillRoutine 종료"); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal static Plugin Instance; private const int AK_ITEM_ID = 9351; private const byte RELOAD_SFX_EVENT_CODE = 143; private Harmony _harmony; private bool _runActionPatched; private float _lastBlockLogTime; private bool _useProgressUiMoved; private bool _isUsing; private Type _cachedCharacterType; private Type _cachedDataEntryKeyType; private Type _cachedOptionableIntItemDataType; private ConfigEntry<float> _reloadUseTime; private ConfigEntry<KeyCode> _reloadKey; private ConfigEntry<string> _reloadSoundFileName; private ConfigEntry<float> _reloadSoundVolume; private ConfigEntry<float> _reloadSoundStartOffset; private ConfigEntry<float> _reloadSoundMinDistance; private ConfigEntry<float> _reloadSoundMaxDistance; private ConfigEntry<bool> _verboseLogging; private AudioClip _reloadSoundClip; private string _resolvedReloadSoundPath; private bool _reloadSoundLoadTried; private void Awake() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) Instance = this; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; BindConfigEntries(); DBG("Plugin Awake()"); _harmony = new Harmony("reload.akhotkey.spawninhand"); TryPatchRunAction(); SceneManager.sceneLoaded += OnSceneLoaded; PhotonNetwork.AddCallbackTarget((object)this); _useProgressUiMoved = false; ((MonoBehaviour)this).StartCoroutine(TryMoveUseProgressUIRoutine()); ((MonoBehaviour)this).StartCoroutine(LoadReloadSoundCoroutine()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"========================================"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[AKReloadDBG] AK Reload NativeUseUI loaded"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[AKReloadDBG] Reload Time = " + GetReloadUseTime() + " sec")); ManualLogSource logger = ((BaseUnityPlugin)this).Logger; KeyCode reloadKey = GetReloadKey(); logger.LogInfo((object)("[AKReloadDBG] Reload Key = " + ((object)(KeyCode)(ref reloadKey)).ToString())); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[AKReloadDBG] Reload Sound File = " + GetReloadSoundFileName())); ((BaseUnityPlugin)this).Logger.LogInfo((object)"========================================"); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; PhotonNetwork.RemoveCallbackTarget((object)this); } public void OnEvent(EventData photonEvent) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) try { if (photonEvent != null && photonEvent.Code == 143 && photonEvent.CustomData is object[] array && array.Length >= 3) { float num = Convert.ToSingle(array[0]); float num2 = Convert.ToSingle(array[1]); float num3 = Convert.ToSingle(array[2]); PlayReloadSoundLocal(new Vector3(num, num2, num3)); } } catch (Exception ex) { ERR("OnEvent 예외: " + ex); } } private void BindConfigEntries() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown _reloadUseTime = ((BaseUnityPlugin)this).Config.Bind<float>("Reload", "Reload Time", 3f, new ConfigDescription("AK 재장전 시간(초). 0이면 즉시 재장전.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>())); _reloadKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Reload", "Reload Key", (KeyCode)114, "재장전 키"); _reloadSoundFileName = ((BaseUnityPlugin)this).Config.Bind<string>("Reload Sound", "Reload Sound File", "장전소리.ogg", "재장전 사운드 파일명. DLL과 같은 폴더에 둔다."); _reloadSoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Reload Sound", "Reload Sound Volume", 1f, new ConfigDescription("재장전 사운드 볼륨", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); _reloadSoundStartOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Reload Sound", "Reload Sound Start Offset", 0.78f, new ConfigDescription("사운드 시작 오프셋(초). 파일 앞 무음을 건너뛸 때 사용", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); _reloadSoundMinDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Reload Sound", "Reload Sound Min Distance", 3f, new ConfigDescription("3D 사운드 최소 거리", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>())); _reloadSoundMaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Reload Sound", "Reload Sound Max Distance", 25f, new ConfigDescription("3D 사운드 최대 거리", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>())); _verboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Verbose Logging", true, "상세 재장전 로그 출력 여부"); } private float GetReloadUseTime() { if (_reloadUseTime == null) { return 3f; } if (_reloadUseTime.Value < 0f) { return 0f; } return _reloadUseTime.Value; } private KeyCode GetReloadKey() { //IL_0019: 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) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (_reloadKey == null) { return (KeyCode)114; } return _reloadKey.Value; } private string GetReloadSoundFileName() { if (_reloadSoundFileName == null || string.IsNullOrWhiteSpace(_reloadSoundFileName.Value)) { return "장전소리.ogg"; } return _reloadSoundFileName.Value.Trim(); } private float GetReloadSoundVolume() { if (_reloadSoundVolume == null) { return 1f; } return Mathf.Clamp(_reloadSoundVolume.Value, 0f, 2f); } private float GetReloadSoundStartOffset() { if (_reloadSoundStartOffset == null) { return 0f; } return Mathf.Max(0f, _reloadSoundStartOffset.Value); } private float GetReloadSoundMinDistance() { if (_reloadSoundMinDistance == null) { return 3f; } return Mathf.Max(0f, _reloadSoundMinDistance.Value); } private float GetReloadSoundMaxDistance() { if (_reloadSoundMaxDistance == null) { return 25f; } return Mathf.Max(1f, _reloadSoundMaxDistance.Value); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { DBG("Scene loaded: " + ((Scene)(ref scene)).name); _useProgressUiMoved = false; ((MonoBehaviour)this).StartCoroutine(TryMoveUseProgressUIRoutine()); if ((Object)(object)_reloadSoundClip == (Object)null && !_reloadSoundLoadTried) { ((MonoBehaviour)this).StartCoroutine(LoadReloadSoundCoroutine()); } } private void Update() { //IL_0018: 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) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (!_runActionPatched) { TryPatchRunAction(); } if (Input.GetKeyDown(GetReloadKey()) && !_isUsing) { if (!TryGetHeldAK(out var _)) { WRN("현재 손에 든 AK가 없어서 재장전을 시작하지 않음"); return; } KeyCode reloadKey = GetReloadKey(); DBG("HOTKEY 입력 감지: " + ((object)(KeyCode)(ref reloadKey)).ToString() + " / ReloadTime = " + GetReloadUseTime()); ((MonoBehaviour)this).StartCoroutine(UseThenRefillRoutine()); } } [IteratorStateMachine(typeof(<LoadReloadSoundCoroutine>d__35))] private IEnumerator LoadReloadSoundCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadReloadSoundCoroutine>d__35(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<TryMoveUseProgressUIRoutine>d__36))] private IEnumerator TryMoveUseProgressUIRoutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TryMoveUseProgressUIRoutine>d__36(0) { <>4__this = this }; } private bool TryMoveUseProgressUI() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) if (_useProgressUiMoved) { return true; } Type type = FindTypeByName("UI_UseItemProgress"); if (type == null) { return false; } Object[] array = Resources.FindObjectsOfTypeAll(type); if (array == null || array.Length == 0) { return false; } Object[] array2 = array; foreach (Object val in array2) { Component val2 = (Component)(object)((val is Component) ? val : null); if ((Object)(object)val2 == (Object)null || (Object)(object)val2.gameObject == (Object)null) { continue; } Scene scene = val2.gameObject.scene; if (((Scene)(ref scene)).IsValid()) { RectTransform component = val2.GetComponent<RectTransform>(); if (!((Object)(object)component == (Object)null)) { component.anchoredPosition += new Vector2(180f, 0f); _useProgressUiMoved = true; Vector2 anchoredPosition = component.anchoredPosition; DBG("UI_UseItemProgress 위치 이동 완료: " + ((object)(Vector2)(ref anchoredPosition)).ToString()); return true; } } } return false; } private void TryPatchRunAction() { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown if (_runActionPatched) { return; } try { Type type = FindTypeByFullName("AK_Gun.Action_Gun"); if (type == null) { WRN("AK_Gun.Action_Gun 타입을 아직 찾지 못함"); return; } MethodInfo method = type.GetMethod("RunAction", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { ERR("AK_Gun.Action_Gun.RunAction 메서드를 찾지 못함"); return; } MethodInfo method2 = typeof(Plugin).GetMethod("Prefix_BlockRunActionWhileReloading", BindingFlags.Static | BindingFlags.NonPublic); if (method2 == null) { ERR("Prefix_BlockRunActionWhileReloading 메서드를 찾지 못함"); return; } _harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _runActionPatched = true; DBG("Harmony Patch 성공: AK_Gun.Action_Gun.RunAction"); } catch (Exception ex) { ERR("TryPatchRunAction 예외: " + ex); } } private static bool Prefix_BlockRunActionWhileReloading() { try { if ((Object)(object)Instance == (Object)null) { return true; } if (!Instance._isUsing) { return true; } if (Time.unscaledTime - Instance._lastBlockLogTime >= 0.25f) { Instance._lastBlockLogTime = Time.unscaledTime; ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[AKReloadDBG] 재장전 중 발사 차단: RunAction 스킵"); } return false; } catch { return true; } } [IteratorStateMachine(typeof(<UseThenRefillRoutine>d__40))] private IEnumerator UseThenRefillRoutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <UseThenRefillRoutine>d__40(0) { <>4__this = this }; } private void StartNativeUseProgress(Component itemComponent) { try { WriteMemberValue(itemComponent, "showUseProgress", true); WriteMemberValue(itemComponent, "overrideForceProgress", true); WriteMemberValue(itemComponent, "overrideProgress", 0f); DBG("UI-only reload progress 시작"); } catch (Exception ex) { WRN("StartNativeUseProgress 예외: " + ex.Message); } } private void UpdateNativeUseProgress(Component itemComponent, float progress) { try { float num = Mathf.Clamp01(progress); WriteMemberValue(itemComponent, "showUseProgress", true); WriteMemberValue(itemComponent, "overrideForceProgress", true); WriteMemberValue(itemComponent, "overrideProgress", num); TryRefreshUseBar(itemComponent, ReadCurrentUsesSafe(itemComponent)); } catch (Exception ex) { WRN("UpdateNativeUseProgress 예외: " + ex.Message); } } private void RestoreNativeUseProgress(Component itemComponent, bool prevShowUseProgress, bool prevOverrideForceProgress, float prevOverrideProgress) { try { WriteMemberValue(itemComponent, "showUseProgress", prevShowUseProgress); WriteMemberValue(itemComponent, "overrideForceProgress", prevOverrideForceProgress); WriteMemberValue(itemComponent, "overrideProgress", prevOverrideProgress); DBG("UI-only reload progress 상태 복원"); } catch (Exception ex) { WRN("RestoreNativeUseProgress 예외: " + ex.Message); } } private void BroadcastReloadSound(Vector3 position) { //IL_00ae: 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) //IL_0054: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_007c: Expected O, but got Unknown //IL_0083: 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) try { if ((Object)(object)_reloadSoundClip == (Object)null) { WRN("장전 사운드가 아직 로드되지 않아 재생하지 못함"); return; } if (!PhotonNetwork.InRoom) { PlayReloadSoundLocal(position); return; } object[] array = new object[3] { position.x, position.y, position.z }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)1 }; PhotonNetwork.RaiseEvent((byte)143, (object)array, val, SendOptions.SendReliable); } catch (Exception ex) { WRN("BroadcastReloadSound 예외: " + ex.Message); try { PlayReloadSoundLocal(position); } catch { } } } private void PlayReloadSoundLocal(Vector3 position) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_reloadSoundClip == (Object)null) { WRN("재장전 사운드 클립이 null임"); return; } float reloadSoundStartOffset = GetReloadSoundStartOffset(); float num = Mathf.Max(0.01f, _reloadSoundClip.length - reloadSoundStartOffset); GameObject val = new GameObject("AKReloadCustomSFX"); val.transform.position = position; AudioSource val2 = val.AddComponent<AudioSource>(); val2.playOnAwake = false; val2.loop = false; val2.spatialBlend = 1f; val2.rolloffMode = (AudioRolloffMode)1; val2.minDistance = GetReloadSoundMinDistance(); val2.maxDistance = GetReloadSoundMaxDistance(); val2.volume = GetReloadSoundVolume(); val2.clip = _reloadSoundClip; if (reloadSoundStartOffset > 0f && reloadSoundStartOffset < _reloadSoundClip.length - 0.01f) { val2.time = reloadSoundStartOffset; } val2.Play(); Object.Destroy((Object)(object)val, num + 0.5f); Vector3 val3 = position; DBG("커스텀 장전 사운드 재생 / pos=" + ((object)(Vector3)(ref val3)).ToString() + " / offset=" + reloadSoundStartOffset); } catch (Exception ex) { WRN("PlayReloadSoundLocal 예외: " + ex.Message); } } private int ReadCurrentUsesSafe(Component itemComponent) { try { if (TryReadItemUses(itemComponent, out var hasData, out var value) && hasData) { return value; } } catch { } return 0; } [IteratorStateMachine(typeof(<RefillCurrentHeldAKRoutine>d__47))] private IEnumerator RefillCurrentHeldAKRoutine(Action<bool> done) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RefillCurrentHeldAKRoutine>d__47(0) { <>4__this = this, done = done }; } private bool TryGetHeldAK(out Component heldAK) { heldAK = null; try { if (!TryGetLocalCharacter(out var localCharacter) || localCharacter == null) { return false; } heldAK = GetCurrentItemComponentFromCharacter(localCharacter); if ((Object)(object)heldAK == (Object)null) { return false; } return IsAKItem(heldAK); } catch (Exception ex) { WRN("TryGetHeldAK 예외: " + ex.Message); heldAK = null; return false; } } private Type GetCharacterType() { if (_cachedCharacterType != null) { return _cachedCharacterType; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type[] array; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type t) => t != null).ToArray(); } catch { continue; } Type[] array2 = array; foreach (Type type in array2) { if (type == null || type.Name != "Character") { continue; } string text = type.Namespace ?? ""; if (!text.StartsWith("UnityEngine.TextCore.Text", StringComparison.OrdinalIgnoreCase)) { BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; if (type.GetField("localCharacter", bindingAttr) != null || type.GetProperty("localCharacter", bindingAttr) != null || type.GetField("LocalCharacter", bindingAttr) != null || type.GetProperty("LocalCharacter", bindingAttr) != null) { _cachedCharacterType = type; DBG("게임 Character 타입 확정 = " + (_cachedCharacterType.FullName ?? _cachedCharacterType.Name)); return _cachedCharacterType; } } } } WRN("게임 Character 타입을 찾지 못함"); return null; } private Type GetDataEntryKeyType() { if (_cachedDataEntryKeyType != null) { return _cachedDataEntryKeyType; } _cachedDataEntryKeyType = FindTypeByName("DataEntryKey"); if (_cachedDataEntryKeyType == null) { WRN("DataEntryKey 타입을 찾지 못함"); } return _cachedDataEntryKeyType; } private Type GetOptionableIntItemDataType() { if (_cachedOptionableIntItemDataType != null) { return _cachedOptionableIntItemDataType; } _cachedOptionableIntItemDataType = FindTypeByName("OptionableIntItemData"); if (_cachedOptionableIntItemDataType == null) { WRN("OptionableIntItemData 타입을 찾지 못함"); } return _cachedOptionableIntItemDataType; } private Type FindTypeByName(string typeName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type[] array; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type t) => t != null).ToArray(); } catch { continue; } Type[] array2 = array; foreach (Type type in array2) { if (type != null && type.Name == typeName) { return type; } } } return null; } private Type FindTypeByFullName(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type[] array; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type t) => t != null).ToArray(); } catch { continue; } Type[] array2 = array; foreach (Type type in array2) { if (!(type == null) && string.Equals(type.FullName, fullName, StringComparison.Ordinal)) { return type; } } } return null; } private bool TryGetLocalCharacter(out object localCharacter) { localCharacter = null; try { Type characterType = GetCharacterType(); if (characterType == null) { return false; } BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; FieldInfo field = characterType.GetField("localCharacter", bindingAttr); if (field != null) { localCharacter = field.GetValue(null); if (localCharacter != null) { DBG("localCharacter 필드로 찾음"); return true; } } PropertyInfo property = characterType.GetProperty("localCharacter", bindingAttr); if (property != null) { localCharacter = property.GetValue(null, null); if (localCharacter != null) { DBG("localCharacter 프로퍼티로 찾음"); return true; } } field = characterType.GetField("LocalCharacter", bindingAttr); if (field != null) { localCharacter = field.GetValue(null); if (localCharacter != null) { DBG("LocalCharacter 필드로 찾음"); return true; } } property = characterType.GetProperty("LocalCharacter", bindingAttr); if (property != null) { localCharacter = property.GetValue(null, null); if (localCharacter != null) { DBG("LocalCharacter 프로퍼티로 찾음"); return true; } } } catch (Exception ex) { WRN("TryGetLocalCharacter 예외: " + ex.Message); } return false; } private Component GetCurrentItemComponentFromCharacter(object characterObj) { try { if (characterObj == null) { return null; } object memberValue = GetMemberValue(characterObj, "data"); if (memberValue == null) { return null; } object memberValue2 = GetMemberValue(memberValue, "currentItem"); return (Component)((memberValue2 is Component) ? memberValue2 : null); } catch (Exception ex) { WRN("GetCurrentItemComponentFromCharacter 예외: " + ex.Message); return null; } } private bool IsAKItem(Component itemComponent) { if ((Object)(object)itemComponent == (Object)null) { return false; } try { object memberValue = GetMemberValue(itemComponent, "itemID"); if (memberValue != null) { int num = Convert.ToInt32(memberValue); if (num == 9351) { return true; } } } catch { } string text = ((Object)itemComponent).name ?? ""; if (text.IndexOf("AK", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (text.IndexOf("com.github.TheCodinPro.AK_Gun", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return false; } private bool TryReadItemUses(Component itemComponent, out bool hasData, out int value) { hasData = false; value = 0; try { Type type = ((object)itemComponent).GetType(); Type keyType = GetDataEntryKeyType(); Type optionableIntItemDataType = GetOptionableIntItemDataType(); if (type == null || keyType == null || optionableIntItemDataType == null) { return false; } object obj = Enum.Parse(keyType, "ItemUses"); MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetData" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == keyType); if (methodInfo == null) { WRN("GetData<T>(DataEntryKey) 메서드를 찾지 못함"); return false; } MethodInfo methodInfo2 = methodInfo.MakeGenericMethod(optionableIntItemDataType); object obj2 = methodInfo2.Invoke(itemComponent, new object[1] { obj }); if (obj2 == null) { return false; } hasData = ReadBoolMember(obj2, "HasData"); value = ReadIntMember(obj2, "Value"); return true; } catch (Exception ex) { WRN("TryReadItemUses 예외: " + ex.Message); return false; } } private bool TrySetItemUsesToMax(Component itemComponent, int totalUses) { try { Type keyType = GetDataEntryKeyType(); Type optionableIntItemDataType = GetOptionableIntItemDataType(); if (keyType == null || optionableIntItemDataType == null) { return false; } object obj = Enum.Parse(keyType, "ItemUses"); object obj2 = null; MethodInfo methodInfo = ((object)itemComponent).GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetData" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == keyType); if (methodInfo != null) { MethodInfo methodInfo2 = methodInfo.MakeGenericMethod(optionableIntItemDataType); obj2 = methodInfo2.Invoke(itemComponent, new object[1] { obj }); } if (obj2 == null) { try { obj2 = Activator.CreateInstance(optionableIntItemDataType); } catch (Exception ex) { ERR("OptionableIntItemData 인스턴스 생성 실패: " + ex.Message); return false; } } WriteMemberValue(obj2, "HasData", true); WriteMemberValue(obj2, "Value", totalUses); bool flag = false; object memberValue = GetMemberValue(itemComponent, "data"); flag |= TrySetDataEntryViaDictionary(memberValue, obj, obj2); flag |= TryInvokePossibleSetter(memberValue, keyType, obj, optionableIntItemDataType, obj2); flag |= TryInvokePossibleSetter(itemComponent, keyType, obj, optionableIntItemDataType, obj2); if (TryReadItemUses(itemComponent, out var hasData, out var value) && hasData && value == totalUses) { DBG("ItemUses 최대치 설정 성공: " + value); return true; } if (!flag) { WRN("ItemUses 엔트리 쓰기 경로를 명시적으로 찾지 못함"); } return TryReadItemUses(itemComponent, out hasData, out value) && hasData && value == totalUses; } catch (Exception ex2) { ERR("TrySetItemUsesToMax 예외: " + ex2); return false; } } private bool TrySetDataEntryViaDictionary(object itemDataObj, object key, object value) { try { if (itemDataObj == null) { return false; } object memberValue = GetMemberValue(itemDataObj, "data"); if (!(memberValue is IDictionary dictionary)) { return false; } if (dictionary.Contains(key)) { dictionary[key] = value; } else { dictionary.Add(key, value); } return true; } catch { return false; } } private bool TryInvokePossibleSetter(object target, Type keyType, object itemUsesKey, Type dataType, object entryObj) { if (target == null) { return false; } string[] array = new string[5] { "SetDataEntry", "AddDataEntry", "SetData", "AddData", "Set" }; MethodInfo[] methods = target.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); string[] array2 = array; foreach (string text in array2) { MethodInfo[] array3 = methods; foreach (MethodInfo methodInfo in array3) { if (methodInfo.Name != text) { continue; } MethodInfo methodInfo2 = methodInfo; try { if (!methodInfo.IsGenericMethodDefinition) { goto IL_00d4; } Type[] genericArguments = methodInfo.GetGenericArguments(); if (genericArguments.Length != 1) { continue; } methodInfo2 = methodInfo.MakeGenericMethod(dataType); goto IL_00d4; IL_00d4: ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length == 2) { if (parameters[0].ParameterType == keyType && parameters[1].ParameterType.IsAssignableFrom(dataType)) { methodInfo2.Invoke(target, new object[2] { itemUsesKey, entryObj }); return true; } if (parameters[1].ParameterType == keyType && parameters[0].ParameterType.IsAssignableFrom(dataType)) { methodInfo2.Invoke(target, new object[2] { entryObj, itemUsesKey }); return true; } } if (parameters.Length == 1 && parameters[0].ParameterType.IsAssignableFrom(dataType)) { methodInfo2.Invoke(target, new object[1] { entryObj }); return true; } } catch { } } } return false; } private void TryRefreshUseBar(Component itemComponent, int currentUses) { try { int num = ReadIntMember(itemComponent, "totalUses"); if (num > 0) { MethodInfo method = ((object)itemComponent).GetType().GetMethod("SetUseRemainingPercentage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(float) }, null); if (method != null) { float num2 = Mathf.Clamp01((float)currentUses / (float)num); method.Invoke(itemComponent, new object[1] { num2 }); } } } catch (Exception ex) { WRN("TryRefreshUseBar 예외: " + ex.Message); } } private bool TrySyncItemInstanceData(Component itemComponent) { try { MethodInfo method = ((object)itemComponent).GetType().GetMethod("ForceSyncForFrames", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null); if (method != null) { method.Invoke(itemComponent, new object[1] { 10 }); } if (!PhotonNetwork.InRoom) { DBG("Photon 룸 밖 상태. 로컬 갱신만 수행"); return true; } PhotonView component = itemComponent.GetComponent<PhotonView>(); if ((Object)(object)component == (Object)null) { WRN("PhotonView를 찾지 못해 동기화 스킵"); return false; } object memberValue = GetMemberValue(itemComponent, "data"); if (memberValue == null) { WRN("item.data가 null이라 동기화 스킵"); return false; } component.RPC("SetItemInstanceDataRPC", (RpcTarget)1, new object[1] { memberValue }); DBG("현재 AK ItemInstanceData 동기화 완료"); return true; } catch (Exception ex) { WRN("TrySyncItemInstanceData 예외: " + ex.Message); return false; } } private object GetMemberValue(object target, string memberName) { if (target == null) { return null; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo property = target.GetType().GetProperty(memberName, bindingAttr); if (property != null) { return property.GetValue(target, null); } FieldInfo field = target.GetType().GetField(memberName, bindingAttr); if (field != null) { return field.GetValue(target); } FieldInfo field2 = target.GetType().GetField("<" + memberName + ">k__BackingField", bindingAttr); if (field2 != null) { return field2.GetValue(target); } return null; } private void WriteMemberValue(object target, string memberName, object value) { if (target == null) { return; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo property = target.GetType().GetProperty(memberName, bindingAttr); if (property != null) { MethodInfo setMethod = property.GetSetMethod(nonPublic: true); if (setMethod != null) { setMethod.Invoke(target, new object[1] { value }); return; } } FieldInfo field = target.GetType().GetField(memberName, bindingAttr); if (field != null) { field.SetValue(target, value); return; } FieldInfo field2 = target.GetType().GetField("<" + memberName + ">k__BackingField", bindingAttr); if (field2 != null) { field2.SetValue(target, value); } } private bool ReadBoolMember(object target, string memberName) { object memberValue = GetMemberValue(target, memberName); if (memberValue == null) { return false; } try { return Convert.ToBoolean(memberValue); } catch { return false; } } private int ReadIntMember(object target, string memberName) { object memberValue = GetMemberValue(target, memberName); if (memberValue == null) { return 0; } try { return Convert.ToInt32(memberValue); } catch { return 0; } } private float ReadFloatMember(object target, string memberName) { object memberValue = GetMemberValue(target, memberName); if (memberValue == null) { return 0f; } try { return Convert.ToSingle(memberValue); } catch { return 0f; } } private void DBG(string msg) { if (_verboseLogging == null || _verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[AKReloadDBG] " + msg)); } } private void WRN(string msg) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[AKReloadDBG] " + msg)); } private void ERR(string msg) { ((BaseUnityPlugin)this).Logger.LogError((object)("[AKReloadDBG] " + msg)); } } } namespace AKGun_RuntimePatch { [BepInPlugin("com.sol.akgunruntimepatch", "AK Gun Runtime Patch", "1.0.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("com.sol.akgunruntimepatch"); _harmony.PatchAll(); Log.LogInfo((object)"AK Gun Runtime Patch loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class PatchCache { internal static readonly FieldInfo CharacterGettingShotField = AccessTools.Field(typeof(GunCharacterLaunch), "characterGettingShot"); internal static readonly FieldInfo ShotDirectionField = AccessTools.Field(typeof(GunCharacterLaunch), "shotDirection"); private static Type _mushroomZombieType; private static FieldInfo _achievementTestTickField; private static MethodInfo _dieMethod; private static bool _searchedZombieType; internal static bool TryGetCharacterGettingShot(GunCharacterLaunch instance, out Character target) { target = null; try { if (CharacterGettingShotField == null) { return false; } object? value = CharacterGettingShotField.GetValue(instance); target = (Character)((value is Character) ? value : null); return (Object)(object)target != (Object)null; } catch (Exception arg) { Plugin.Log.LogError((object)$"[PatchCache] TryGetCharacterGettingShot failed: {arg}"); return false; } } internal static bool TryGetShotDirection(GunCharacterLaunch instance, out Vector3 direction) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_0043: 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) direction = default(Vector3); try { if (ShotDirectionField == null) { return false; } if (ShotDirectionField.GetValue(instance) is Vector3 val) { direction = val; return true; } return false; } catch (Exception arg) { Plugin.Log.LogError((object)$"[PatchCache] TryGetShotDirection failed: {arg}"); return false; } } internal static bool TryResolveMushroomZombieMembers() { if (_searchedZombieType) { return _mushroomZombieType != null && _achievementTestTickField != null && _dieMethod != null; } _searchedZombieType = true; try { _mushroomZombieType = AccessTools.TypeByName("MushroomZombie"); if (_mushroomZombieType == null) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type type = null; try { type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == "MushroomZombie"); } catch { } if (type != null) { _mushroomZombieType = type; break; } } } if (_mushroomZombieType == null) { Plugin.Log.LogWarning((object)"[PatchCache] MushroomZombie type not found."); return false; } _achievementTestTickField = AccessTools.Field(_mushroomZombieType, "achievementTestTick"); _dieMethod = AccessTools.Method(_mushroomZombieType, "Die", (Type[])null, (Type[])null); if (_achievementTestTickField == null) { Plugin.Log.LogWarning((object)"[PatchCache] achievementTestTick field not found."); return false; } if (_dieMethod == null) { Plugin.Log.LogWarning((object)"[PatchCache] Die() method not found."); return false; } return true; } catch (Exception arg) { Plugin.Log.LogError((object)$"[PatchCache] TryResolveMushroomZombieMembers failed: {arg}"); return false; } } internal static Component GetMushroomZombieComponent(Character target) { try { if ((Object)(object)target == (Object)null) { return null; } if (!TryResolveMushroomZombieMembers()) { return null; } return ((Component)target).GetComponent(_mushroomZombieType); } catch (Exception arg) { Plugin.Log.LogError((object)$"[PatchCache] GetMushroomZombieComponent failed: {arg}"); return null; } } internal static bool TryAddAchievementTickAndKill(Component mushroomZombieComponent) { try { if ((Object)(object)mushroomZombieComponent == (Object)null) { return false; } if (!TryResolveMushroomZombieMembers()) { return false; } object value = _achievementTestTickField.GetValue(mushroomZombieComponent); float num = 0f; if (value != null) { num = Convert.ToSingle(value); } num += 1f; _achievementTestTickField.SetValue(mushroomZombieComponent, num); if (num >= 10f) { _dieMethod.Invoke(mushroomZombieComponent, null); } return true; } catch (Exception arg) { Plugin.Log.LogError((object)$"[PatchCache] TryAddAchievementTickAndKill failed: {arg}"); return false; } } } [HarmonyPatch(typeof(GunCharacterLaunch), "RPC_ShootSelfT")] internal static class Patch_RPC_ShootSelfT { [HarmonyPostfix] private static void Postfix(GunCharacterLaunch __instance) { try { if (PatchCache.TryGetCharacterGettingShot(__instance, out var target) && !((Object)(object)target == (Object)null)) { Component mushroomZombieComponent = PatchCache.GetMushroomZombieComponent(target); if (!((Object)(object)mushroomZombieComponent == (Object)null)) { PatchCache.TryAddAchievementTickAndKill(mushroomZombieComponent); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Patch_RPC_ShootSelfT] Postfix failed: {arg}"); } } } [HarmonyPatch(typeof(GunCharacterLaunch), "UpdateShotPhysicsT")] internal static class Patch_UpdateShotPhysicsT { [HarmonyPrefix] private static bool Prefix(GunCharacterLaunch __instance) { //IL_003e: 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_004e: 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_0055: Unknown result type (might be due to invalid IL or missing references) try { if (!PatchCache.TryGetCharacterGettingShot(__instance, out var target)) { return false; } if ((Object)(object)target == (Object)null) { return false; } if (!PatchCache.TryGetShotDirection(__instance, out var direction)) { return false; } Vector3 val = direction * 25f * -1f; CharacterExtensions.AddForce(target, val, 1f, 1f, (ForceMode)5); return false; } catch (Exception arg) { Plugin.Log.LogError((object)$"[Patch_UpdateShotPhysicsT] Prefix failed: {arg}"); return false; } } } } namespace SegmentZombieRules { [BepInPlugin("com.sol.segmentzombierules", "Segment Zombie Rules", "1.3.0")] public class Plugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <HandleSegmentChangedRoutine>d__61 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Segment targetSegment; public Plugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <HandleSegmentChangedRoutine>d__61(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.35f); <>1__state = 2; return true; case 2: <>1__state = -1; SyncExternalZombieCaps(forceLog: true); DestroyAllOwnedZombies(forceLog: true); <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 3; return true; case 3: <>1__state = -1; SyncExternalZombieCaps(forceLog: true); RestartPeakZombiesSpawningForCurrentSegment(forceLog: true); <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 4; return true; case 4: <>1__state = -1; SyncExternalZombieCaps(forceLog: true); TrimZombieCountToSegmentCap(forceLog: true); <>4__this._segmentTransitionRoutine = null; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal static ManualLogSource Log; internal static Plugin Instance; private Harmony _harmony; private static ConfigEntry<int> _beachMaxZombies; private static ConfigEntry<int> _tropicsMaxZombies; private static ConfigEntry<int> _alpineMaxZombies; private static ConfigEntry<int> _calderaMaxZombies; private static ConfigEntry<int> _theKilnMaxZombies; private static ConfigEntry<int> _peakMaxZombies; private static ConfigEntry<int> _beachHitsToKill; private static ConfigEntry<int> _tropicsHitsToKill; private static ConfigEntry<int> _alpineHitsToKill; private static ConfigEntry<int> _calderaHitsToKill; private static ConfigEntry<int> _theKilnHitsToKill; private static ConfigEntry<int> _peakHitsToKill; private static ConfigEntry<bool> _verboseLogging; private static FieldInfo _akCharacterGettingShotField; private static FieldInfo _akShotTimeField; private static FieldInfo _akShotDirectionField; private static FieldInfo _mushroomZombieAchievementTestTickField; private static MethodInfo _mushroomZombieDieMethod; private static Type _peakZombiesType; private static FieldInfo _peakZombiesInstanceField; private static FieldInfo _peakZombiesCustomMaxZombiesField; private static FieldInfo _peakZombiesBypassMaxZombieLimitField; private static FieldInfo _peakZombiesInitialSpawnCountField; private static FieldInfo _peakZombiesAutoSpawnIntervalField; private static FieldInfo _peakZombiesAutoSpawnRadiusField; private static MethodInfo _peakZombiesGetSpawnCenterMethod; private static MethodInfo _peakZombiesSpawnZombiesAroundMethod; private static MethodInfo _peakZombiesStartAutoSpawningMethod; private static MethodInfo _peakZombiesStopAutoSpawningMethod; private static MethodInfo _peakZombiesSpawnInitialZombiesMethod; private static object _lastPeakZombiesInstance; private static int _lastAppliedExternalCap = -1; private static Segment? _lastAppliedSegment = null; private float _nextExternalSyncTime; private Segment? _lastObservedSegment; private Coroutine _segmentTransitionRoutine; private void Awake() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; BindConfigs(); _harmony = new Harmony("com.sol.segmentzombierules"); try { _mushroomZombieAchievementTestTickField = AccessTools.Field(typeof(MushroomZombie), "achievementTestTick"); _mushroomZombieDieMethod = AccessTools.Method(typeof(MushroomZombie), "Die", (Type[])null, (Type[])null); if (_mushroomZombieAchievementTestTickField != null) { Log.LogInfo((object)"Found MushroomZombie.achievementTestTick"); } else { Log.LogWarning((object)"Could not find MushroomZombie.achievementTestTick"); } if (_mushroomZombieDieMethod != null) { Log.LogInfo((object)"Found MushroomZombie.Die()"); } else { Log.LogWarning((object)"Could not find MushroomZombie.Die()"); } CachePeakZombiesReflection(); MethodInfo methodInfo = AccessTools.Method(typeof(MushroomZombieSpawner), "Spawn", (Type[])null, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "MushroomZombieSpawner_Spawn_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Patched MushroomZombieSpawner.Spawn"); } else { Log.LogWarning((object)"Could not find MushroomZombieSpawner.Spawn"); } MethodInfo methodInfo2 = AccessTools.Method(typeof(MapHandler), "JumpToSegmentLogic", new Type[4] { typeof(Segment), typeof(HashSet<int>), typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "MapHandler_JumpToSegmentLogic_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Patched MapHandler.JumpToSegmentLogic"); } else { Log.LogWarning((object)"Could not find MapHandler.JumpToSegmentLogic"); } PatchExternalMethod("Zombies_Anywhere.ZombiesAnywhereMod", "SpawnZombieAt", new Type[3] { typeof(Vector3), typeof(Quaternion), typeof(MushroomZombie) }, "PeakZombies_SpawnZombieAt_Prefix"); PatchExternalMethod("Zombies_Anywhere.ZombiesAnywhereMod", "SpawnZombiesAround", new Type[3] { typeof(Vector3), typeof(float), typeof(int) }, "PeakZombies_SpawnZombiesAround_Prefix"); PatchExternalMethod("Zombies_Anywhere.ZombiesAnywhereMod", "SpawnInitialZombies", Type.EmptyTypes, "PeakZombies_SpawnInitialZombies_Prefix"); PatchExternalMethod("AK_Gun.GunCharacterLaunch", "RPC_ShootSelfT", new Type[3] { typeof(float), typeof(int), typeof(Vector3) }, "AKGun_RPC_ShootSelfT_Prefix"); Log.LogInfo((object)"========================================"); Log.LogInfo((object)"Segment Zombie Rules loaded"); Log.LogInfo((object)"Config-driven values enabled"); Log.LogInfo((object)"Map transition zombie resync enabled"); Log.LogInfo((object)"PEAK_Zombies auto-spawn restart on segment change enabled"); LogCurrentConfigValues(); Log.LogInfo((object)"========================================"); } catch (Exception ex) { Log.LogError((object)("Plugin Awake exception: " + ex)); } } private void Update() { //IL_001d: 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) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_006a: Unknown result type (might be due to invalid IL or missing references) try { if (!PhotonNetwork.IsMasterClient) { return; } if (MapHandler.Exists) { Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber; if (!_lastObservedSegment.HasValue) { _lastObservedSegment = currentSegmentNumber; } else if (_lastObservedSegment.Value != currentSegmentNumber) { _lastObservedSegment = currentSegmentNumber; HandleSegmentChanged(currentSegmentNumber, "UpdateFallback"); } } if (!(Time.time < _nextExternalSyncTime)) { _nextExternalSyncTime = Time.time + 0.5f; SyncExternalZombieCaps(forceLog: false); TrimZombieCountToSegmentCap(forceLog: false); } } catch (Exception ex) { Log.LogError((object)("Plugin Update exception: " + ex)); } } private void OnDestroy() { try { if (_segmentTransitionRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_segmentTransitionRoutine); _segmentTransitionRoutine = null; } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { Log.LogError((object)("Plugin OnDestroy exception: " + ex)); } } private void BindConfigs() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Expected O, but got Unknown //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Expected O, but got Unknown //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Expected O, but got Unknown //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Expected O, but got Unknown _verboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Verbose Logging", true, "세그먼트별 스폰 차단/피격/전환 로그를 자세히 출력할지 여부"); _beachMaxZombies = ((BaseUnityPlugin)this).Config.Bind<int>("Zombie Cap", "Beach Max Zombies", 3, new ConfigDescription("Beach 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); _tropicsMaxZombies = ((BaseUnityPlugin)this).Config.Bind<int>("Zombie Cap", "Tropics Max Zombies", 5, new ConfigDescription("Tropics 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); _alpineMaxZombies = ((BaseUnityPlugin)this).Config.Bind<int>("Zombie Cap", "Alpine Max Zombies", 7, new ConfigDescription("Alpine 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); _calderaMaxZombies = ((BaseUnityPlugin)this).Config.Bind<int>("Zombie Cap", "Caldera Max Zombies", 10, new ConfigDescription("Caldera 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); _theKilnMaxZombies = ((BaseUnityPlugin)this).Config.Bind<int>("Zombie Cap", "TheKiln Max Zombies", 10, new ConfigDescription("TheKiln 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); _peakMaxZombies = ((BaseUnityPlugin)this).Config.Bind<int>("Zombie Cap", "Peak Max Zombies", 15, new ConfigDescription("Peak 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); _beachHitsToKill = ((BaseUnityPlugin)this).Config.Bind<int>("Hits To Kill", "Beach Hits To Kill", 3, new ConfigDescription("Beach 세그먼트 좀비 처치 타수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>())); _tropicsHitsToKill = ((BaseUnityPlugin)this).Config.Bind<int>("Hits To Kill", "Tropics Hits To Kill", 5, new ConfigDescription("Tropics 세그먼트 좀비 처치 타수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>())); _alpineHitsToKill = ((BaseUnityPlugin)this).Config.Bind<int>("Hits To Kill", "Alpine Hits To Kill", 7, new ConfigDescription("Alpine 세그먼트 좀비 처치 타수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>())); _calderaHitsToKill = ((BaseUnityPlugin)this).Config.Bind<int>("Hits To Kill", "Caldera Hits To Kill", 10, new ConfigDescription("Caldera 세그먼트 좀비 처치 타수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>())); _theKilnHitsToKill = ((BaseUnityPlugin)this).Config.Bind<int>("Hits To Kill", "TheKiln Hits To Kill", 10, new ConfigDescription("TheKiln 세그먼트 좀비 처치 타수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>())); _peakHitsToKill = ((BaseUnityPlugin)this).Config.Bind<int>("Hits To Kill", "Peak Hits To Kill", 15, new ConfigDescription("Peak 세그먼트 좀비 처치 타수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>())); } private static void LogCurrentConfigValues() { Log.LogInfo((object)"Zombie max by segment:"); Log.LogInfo((object)$"Beach={ReadMaxZombieValue(_beachMaxZombies, 3)}, Tropics={ReadMaxZombieValue(_tropicsMaxZombies, 5)}, Alpine={ReadMaxZombieValue(_alpineMaxZombies, 7)}, Caldera={ReadMaxZombieValue(_calderaMaxZombies, 10)}, TheKiln={ReadMaxZombieValue(_theKilnMaxZombies, 10)}, Peak={ReadMaxZombieValue(_peakMaxZombies, 15)}"); Log.LogInfo((object)"Hits-to-kill by segment:"); Log.LogInfo((object)$"Beach={ReadHitsToKillValue(_beachHitsToKill, 3)}, Tropics={ReadHitsToKillValue(_tropicsHitsToKill, 5)}, Alpine={ReadHitsToKillValue(_alpineHitsToKill, 7)}, Caldera={ReadHitsToKillValue(_calderaHitsToKill, 10)}, TheKiln={ReadHitsToKillValue(_theKilnHitsToKill, 10)}, Peak={ReadHitsToKillValue(_peakHitsToKill, 15)}"); } private void PatchExternalMethod(string typeName, string methodName, Type[] argTypes, string prefixMethodName) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown try { Type type = AccessTools.TypeByName(typeName); if (type == null) { Log.LogWarning((object)("Type not found: " + typeName)); return; } MethodInfo methodInfo = AccessTools.Method(type, methodName, argTypes, (Type[])null); if (methodInfo == null) { Log.LogWarning((object)("Method not found: " + typeName + "." + methodName)); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(Plugin), prefixMethodName, (Type[])null, (Type[])null); if (methodInfo2 == null) { Log.LogWarning((object)("Prefix method not found: " + prefixMethodName)); return; } _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)("Patched " + typeName + "." + methodName)); } catch (Exception ex) { Log.LogError((object)("PatchExternalMethod exception for " + typeName + "." + methodName + ": " + ex)); } } private static void CachePeakZombiesReflection() { try { _peakZombiesType = AccessTools.TypeByName("Zombies_Anywhere.ZombiesAnywhereMod"); if (_peakZombiesType == null) { Log.LogWarning((object)"PEAK_Zombies type not found: Zombies_Anywhere.ZombiesAnywhereMod"); return; } _peakZombiesInstanceField = AccessTools.Field(_peakZombiesType, "_instance"); _peakZombiesCustomMaxZombiesField = AccessTools.Field(_peakZombiesType, "customMaxZombies"); _peakZombiesBypassMaxZombieLimitField = AccessTools.Field(_peakZombiesType, "bypassMaxZombieLimit"); _peakZombiesInitialSpawnCountField = AccessTools.Field(_peakZombiesType, "initialSpawnCount"); _peakZombiesAutoSpawnIntervalField = AccessTools.Field(_peakZombiesType, "autoSpawnInterval"); _peakZombiesAutoSpawnRadiusField = AccessTools.Field(_peakZombiesType, "autoSpawnRadius"); _peakZombiesGetSpawnCenterMethod = AccessTools.Method(_peakZombiesType, "GetSpawnCenter", Type.EmptyTypes, (Type[])null); _peakZombiesSpawnZombiesAroundMethod = AccessTools.Method(_peakZombiesType, "SpawnZombiesAround", new Type[3] { typeof(Vector3), typeof(float), typeof(int) }, (Type[])null); _peakZombiesStartAutoSpawningMethod = AccessTools.Method(_peakZombiesType, "StartAutoSpawning", new Type[2] { typeof(float), typeof(float) }, (Type[])null); _peakZombiesStopAutoSpawningMethod = AccessTools.Method(_peakZombiesType, "StopAutoSpawning", Type.EmptyTypes, (Type[])null); _peakZombiesSpawnInitialZombiesMethod = AccessTools.Method(_peakZombiesType, "SpawnInitialZombies", Type.EmptyTypes, (Type[])null); Log.LogInfo((object)"PEAK_Zombies reflection cache result:"); Log.LogInfo((object)(" - _instance: " + (_peakZombiesInstanceField != null))); Log.LogInfo((object)(" - customMaxZombies: " + (_peakZombiesCustomMaxZombiesField != null))); Log.LogInfo((object)(" - bypassMaxZombieLimit: " + (_peakZombiesBypassMaxZombieLimitField != null))); Log.LogInfo((object)(" - initialSpawnCount: " + (_peakZombiesInitialSpawnCountField != null))); Log.LogInfo((object)(" - autoSpawnInterval: " + (_peakZombiesAutoSpawnIntervalField != null))); Log.LogInfo((object)(" - autoSpawnRadius: " + (_peakZombiesAutoSpawnRadiusField != null))); Log.LogInfo((object)(" - GetSpawnCenter(): " + (_peakZombiesGetSpawnCenterMethod != null))); Log.LogInfo((object)(" - SpawnZombiesAround(): " + (_peakZombiesSpawnZombiesAroundMethod != null))); Log.LogInfo((object)(" - StartAutoSpawning(): " + (_peakZombiesStartAutoSpawningMethod != null))); Log.LogInfo((object)(" - StopAutoSpawning(): " + (_peakZombiesStopAutoSpawningMethod != null))); } catch (Exception ex) { Log.LogError((object)("CachePeakZombiesReflection exception: " + ex)); } } private static int ReadMaxZombieValue(ConfigEntry<int> entry, int fallback) { if (entry == null) { return fallback; } return Mathf.Max(0, entry.Value); } private static int ReadHitsToKillValue(ConfigEntry<int> entry, int fallback) { if (entry == null) { return fallback; } return Mathf.Max(1, entry.Value); } private static int GetSegmentMaxZombies() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected I4, but got Unknown if (!MapHandler.Exists) { return ReadMaxZombieValue(_beachMaxZombies, 3); } Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber; Segment val = currentSegmentNumber; return (int)val switch { 0 => ReadMaxZombieValue(_beachMaxZombies, 3), 1 => ReadMaxZombieValue(_tropicsMaxZombies, 5), 2 => ReadMaxZombieValue(_alpineMaxZombies, 7), 3 => ReadMaxZombieValue(_calderaMaxZombies, 10), 4 => ReadMaxZombieValue(_theKilnMaxZombies, 10), 5 => ReadMaxZombieValue(_peakMaxZombies, 15), _ => ReadMaxZombieValue(_beachMaxZombies, 3), }; } private static float GetHitsToKillBySegment() { //IL_001f: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected I4, but got Unknown if (!MapHandler.Exists) { return ReadHitsToKillValue(_beachHitsToKill, 3); } Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber; Segment val = currentSegmentNumber; return (int)val switch { 0 => ReadHitsToKillValue(_beachHitsToKill, 3), 1 => ReadHitsToKillValue(_tropicsHitsToKill, 5), 2 => ReadHitsToKillValue(_alpineHitsToKill, 7), 3 => ReadHitsToKillValue(_calderaHitsToKill, 10), 4 => ReadHitsToKillValue(_theKilnHitsToKill, 10), 5 => ReadHitsToKillValue(_peakHitsToKill, 15), _ => ReadHitsToKillValue(_beachHitsToKill, 3), }; } private static string GetCurrentSegmentName() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!MapHandler.Exists) { return "Unknown"; } Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber; return ((object)(Segment)(ref currentSegmentNumber)).ToString(); } private static int GetCurrentZombieCount() { try { if ((Object)(object)ZombieManager.Instance != (Object)null && ZombieManager.Instance.zombies != null) { return ZombieManager.Instance.zombies.Count; } } catch { } try { MushroomZombie[] array = Object.FindObjectsByType<MushroomZombie>((FindObjectsInactive)0, (FindObjectsSortMode)0); return array.Length; } catch { return 0; } } private static int GetRemainingSpawnSlots() { int segmentMaxZombies = GetSegmentMaxZombies(); int currentZombieCount = GetCurrentZombieCount(); return Mathf.Max(0, segmentMaxZombies - currentZombieCount); } private static object GetPeakZombiesInstance() { if (_peakZombiesInstanceField == null) { return null; } try { return _peakZombiesInstanceField.GetValue(null); } catch { return null; } } private static int ReadPeakIntConfig(FieldInfo field, object instance, int fallback) { try { if (field == null || instance == null) { return fallback; } if (!(field.GetValue(instance) is ConfigEntry<int> val)) { return fallback; } return val.Value; } catch { return fallback; } } private static float ReadPeakFloatConfig(FieldInfo field, object instance, float fallback) { try { if (field == null || instance == null) { return fallback; } if (!(field.GetValue(instance) is ConfigEntry<float> val)) { return fallback; } return val.Value; } catch { return fallback; } } private static void SyncExternalZombieCaps(bool forceLog) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_01df: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient) { return; } int segmentMaxZombies = GetSegmentMaxZombies(); Segment val = (Segment)(MapHandler.Exists ? ((int)MapHandler.CurrentSegmentNumber) : 0); try { if ((Object)(object)ZombieManager.Instance != (Object)null && ZombieManager.Instance.maxActiveZombies != segmentMaxZombies) { ZombieManager.Instance.maxActiveZombies = segmentMaxZombies; if ((_verboseLogging != null && _verboseLogging.Value) || forceLog) { Log.LogInfo((object)$"[ZombieCapSync] ZombieManager.maxActiveZombies -> {segmentMaxZombies} ({val})"); } } } catch (Exception ex) { Log.LogError((object)("SyncExternalZombieCaps ZombieManager exception: " + ex)); } try { if (_peakZombiesType == null || _peakZombiesInstanceField == null || _peakZombiesCustomMaxZombiesField == null || _peakZombiesBypassMaxZombieLimitField == null) { return; } object value = _peakZombiesInstanceField.GetValue(null); if (value == null) { return; } ConfigEntry<int> val2 = _peakZombiesCustomMaxZombiesField.GetValue(value) as ConfigEntry<int>; ConfigEntry<bool> val3 = _peakZombiesBypassMaxZombieLimitField.GetValue(value) as ConfigEntry<bool>; if (val2 == null || val3 == null) { Log.LogWarning((object)"[ZombieCapSync] PEAK_Zombies config entries not found"); return; } bool flag = false; if (val3.Value) { val3.Value = false; flag = true; } if (val2.Value != segmentMaxZombies) { val2.Value = segmentMaxZombies; flag = true; } if ((forceLog || flag || _lastPeakZombiesInstance != value || _lastAppliedExternalCap != segmentMaxZombies || !_lastAppliedSegment.HasValue || _lastAppliedSegment.Value != val) && ((_verboseLogging != null && _verboseLogging.Value) || forceLog)) { Log.LogInfo((object)$"[ZombieCapSync] PEAK_Zombies override applied | Segment={val} | customMaxZombies={val2.Value} | bypassMaxZombieLimit={val3.Value}"); } _lastPeakZombiesInstance = value; _lastAppliedExternalCap = segmentMaxZombies; _lastAppliedSegment = val; } catch (Exception ex2) { Log.LogError((object)("SyncExternalZombieCaps PEAK_Zombies exception: " + ex2)); } } private static bool IsSpawnBlockedBySegmentCap() { int currentZombieCount = GetCurrentZombieCount(); int segmentMaxZombies = GetSegmentMaxZombies(); if (currentZombieCount >= segmentMaxZombies) { if (_verboseLogging != null && _verboseLogging.Value) { Log.LogInfo((object)$"[ZombieCap] Blocked spawn in {GetCurrentSegmentName()} ({currentZombieCount}/{segmentMaxZombies})"); } return true; } return false; } private static void TrimZombieCountToSegmentCap(bool forceLog) { try { if (!PhotonNetwork.IsMasterClient) { return; } int segmentMaxZombies = GetSegmentMaxZombies(); MushroomZombie[] array = Object.FindObjectsByType<MushroomZombie>((FindObjectsInactive)1, (FindObjectsSortMode)0); if (array == null || array.Length <= segmentMaxZombies) { return; } int num = array.Length - segmentMaxZombies; int num2 = 0; int num3 = array.Length - 1; while (num3 >= 0 && num2 < num) { MushroomZombie val = array[num3]; if (!((Object)(object)val == (Object)null)) { PhotonView component = ((Component)val).GetComponent<PhotonView>(); if (!((Object)(object)component != (Object)null) || component.IsMine) { val.DestroyZombie(); num2++; } } num3--; } if (((_verboseLogging != null && _verboseLogging.Value) || forceLog) && num2 > 0) { Log.LogInfo((object)$"[ZombieTrim] Removed {num2} excess zombies in {GetCurrentSegmentName()} (limit={segmentMaxZombies})"); } } catch (Exception ex) { Log.LogError((object)("TrimZombieCountToSegmentCap exception: " + ex)); } } private static void DestroyAllOwnedZombies(bool forceLog) { try { if (!PhotonNetwork.IsMasterClient) { return; } MushroomZombie[] array = Object.FindObjectsByType<MushroomZombie>((FindObjectsInactive)1, (FindObjectsSortMode)0); int num = 0; MushroomZombie[] array2 = array; foreach (MushroomZombie val in array2) { if (!((Object)(object)val == (Object)null)) { PhotonView component = ((Component)val).GetComponent<PhotonView>(); if (!((Object)(object)component != (Object)null) || component.IsMine) { val.DestroyZombie(); num++; } } } if (((_verboseLogging != null && _verboseLogging.Value) || forceLog) && num > 0) { Log.LogInfo((object)("[ZombieReset] Destroyed zombies on segment change = " + num)); } } catch (Exception ex) { Log.LogError((object)("DestroyAllOwnedZombies exception: " + ex)); } } private void HandleSegmentChanged(Segment targetSegment, string reason) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsMasterClient) { if (_verboseLogging != null && _verboseLogging.Value) { Log.LogInfo((object)$"[SegmentChange] {reason} -> {targetSegment}"); } if (_segmentTransitionRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_segmentTransitionRoutine); _segmentTransitionRoutine = null; } _segmentTransitionRoutine = ((MonoBehaviour)this).StartCoroutine(HandleSegmentChangedRoutine(targetSegment)); } } [IteratorStateMachine(typeof(<HandleSegmentChangedRoutine>d__61))] private IEnumerator HandleSegmentChangedRoutine(Segment targetSegment) { //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) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <HandleSegmentChangedRoutine>d__61(0) { <>4__this = this, targetSegment = targetSegment }; } private static void RestartPeakZombiesSpawningForCurrentSegment(bool forceLog) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) try { if (!PhotonNetwork.IsMasterClient) { return; } object peakZombiesInstance = GetPeakZombiesInstance(); if (peakZombiesInstance == null) { if ((_verboseLogging != null && _verboseLogging.Value) || forceLog) { Log.LogInfo((object)"[SegmentChange] PEAK_Zombies instance not found, skipping restart"); } return; } try { _peakZombiesStopAutoSpawningMethod?.Invoke(peakZombiesInstance, null); } catch (Exception ex) { Log.LogError((object)("StopAutoSpawning invoke exception: " + ex)); } SyncExternalZombieCaps(forceLog); float num = ReadPeakFloatConfig(_peakZombiesAutoSpawnRadiusField, peakZombiesInstance, 50f); float num2 = ReadPeakFloatConfig(_peakZombiesAutoSpawnIntervalField, peakZombiesInstance, 10f); int num3 = ReadPeakIntConfig(_peakZombiesInitialSpawnCountField, peakZombiesInstance, 0); Vector3 val = Vector3.zero; try { if (_peakZombiesGetSpawnCenterMethod != null) { object obj = _peakZombiesGetSpawnCenterMethod.Invoke(peakZombiesInstance, null); if (obj is Vector3) { Vector3 val2 = (Vector3)obj; if (true) { val = val2; } } } } catch (Exception ex2) { Log.LogError((object)("GetSpawnCenter invoke exception: " + ex2)); } if (val != Vector3.zero && num3 > 0) { int num4 = Mathf.Min(num3, GetSegmentMaxZombies()); if ((_verboseLogging != null && _verboseLogging.Value) || forceLog) { Log.LogInfo((object)$"[SegmentChange] Respawning initial zombies | Segment={GetCurrentSegmentName()} | Requested={num3} | Clamped={num4} | Radius={num}"); } _peakZombiesSpawnZombiesAroundMethod?.Invoke(null, new object[3] { val, num, num4 }); } else if (_peakZombiesSpawnInitialZombiesMethod != null) { if ((_verboseLogging != null && _verboseLogging.Value) || forceLog) { Log.LogInfo((object)"[SegmentChange] Fallback invoking SpawnInitialZombies()"); } _peakZombiesSpawnInitialZombiesMethod.Invoke(peakZombiesInstance, null); } if (num2 > 0f) { _peakZombiesStartAutoSpawningMethod?.Invoke(null, new object[2] { num2, num }); if ((_verboseLogging != null && _verboseLogging.Value) || forceLog) { Log.LogInfo((object)$"[SegmentChange] Restarted auto spawn | Interval={num2} | Radius={num}"); } } } catch (Exception ex3) { Log.LogError((object)("RestartPeakZombiesSpawningForCurrentSegment exception: " + ex3)); } } public static void MapHandler_JumpToSegmentLogic_Postfix(Segment segment) { //IL_0018: 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) try { if (!((Object)(object)Instance == (Object)null)) { Instance._lastObservedSegment = segment; Instance.HandleSegmentChanged(segment, "JumpToSegmentLogic"); } } catch (Exception ex) { Log.LogError((object)("MapHandler_JumpToSegmentLogic_Postfix exception: " + ex)); } } public static bool MushroomZombieSpawner_Spawn_Prefix() { try { if (!PhotonNetwork.IsMasterClient) { return true; } SyncExternalZombieCaps(forceLog: false); if (IsSpawnBlockedBySegmentCap()) { return false; } } catch (Exception ex) { Log.LogError((object)("MushroomZombieSpawner_Spawn_Prefix exception: " + ex)); } return true; } public static bool PeakZombies_SpawnInitialZombies_Prefix() { try { if (!PhotonNetwork.IsMasterClient) { return true; } SyncExternalZombieCaps(forceLog: false); } catch (Exception ex) { Log.LogError((object)("PeakZombies_SpawnInitialZombies_Prefix exception: " + ex)); } return true; } public static bool PeakZombies_SpawnZombieAt_Prefix(ref MushroomZombie __result) { try { if (!PhotonNetwork.IsMasterClient) { return true; } SyncExternalZombieCaps(forceLog: false); if (IsSpawnBlockedBySegmentCap()) { __result = null; return false; } } catch (Exception ex) { Log.LogError((object)("PeakZombies_SpawnZombieAt_Prefix exception: " + ex)); } return true; } public static bool PeakZombies_SpawnZombiesAround_Prefix(ref List<MushroomZombie> __result, ref int count) { try { if (!PhotonNetwork.IsMasterClient) { return true; } SyncExternalZombieCaps(forceLog: false); int currentZombieCount = GetCurrentZombieCount(); int segmentMaxZombies = GetSegmentMaxZombies(); int num = Mathf.Max(0, segmentMaxZombies - currentZombieCount); if (num <= 0) { if (_verboseLogging != null && _verboseLogging.Value) { Log.LogInfo((object)$"[ZombieCap] Blocked SpawnZombiesAround in {GetCurrentSegmentName()} ({currentZombieCount}/{segmentMaxZombies})"); } __result = new List<MushroomZombie>(); return false; } if (count > num) { if (_verboseLogging != null && _verboseLogging.Value) { Log.LogInfo((object)$"[ZombieCap] Clamp SpawnZombiesAround count in {GetCurrentSegmentName()}: requested={count}, remaining={num}, current={currentZombieCount}, limit={segmentMaxZombies}"); } count = num; } } catch (Exception ex) { Log.LogError((object)("PeakZombies_SpawnZombiesAround_Prefix exception: " + ex)); } return true; } private static void EnsureAKFields(Type gunLaunchType) { if (!(gunLaunchType == null)) { if (_akCharacterGettingShotField == null) { _akCharacterGettingShotField = AccessTools.Field(gunLaunchType, "characterGettingShot"); } if (_akShotTimeField == null) { _akShotTimeField = AccessTools.Field(gunLaunchType, "shotTime"); } if (_akShotDirectionField == null) { _akShotDirectionField = AccessTools.Field(gunLaunchType, "shotDirection"); } } } public static bool AKGun_RPC_ShootSelfT_Prefix(object __instance, float howLongToFly, int CharacterViewID, Vector3 whichDirectionShooting) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) try { if (__instance == null) { return true; } EnsureAKFields(__instance.GetType()); Character val = null; PhotonView val2 = PhotonView.Find(CharacterViewID); if ((Object)(object)val2 != (Object)null) { Character component = ((Component)val2).GetComponent<Character>(); if ((Object)(object)component != (Object)null) { val = component; } else { Debug.LogError((object)$"Character {CharacterViewID} not found"); val = Character.localCharacter; } } else { Debug.LogError((object)$"PhotonView {CharacterViewID} not found"); val = Character.localCharacter; } _akCharacterGettingShotField?.SetValue(__instance, val); _akShotTimeField?.SetValue(__instance, howLongToFly); _akShotDirectionField?.SetValue(__instance, whichDirectionShooting); if ((Object)(object)val != (Object)null) { Component component2 = ((Component)val).GetComponent(typeof(MushroomZombie)); MushroomZombie val3 = (MushroomZombie)(object)((component2 is MushroomZombie) ? component2 : null); if ((Object)(object)val3 != (Object)null) { float hitsToKillBySegment = GetHitsToKillBySegment(); if (_mushroomZombieAchievementTestTickField == null) { Log.LogError((object)"achievementTestTick field not found"); return false; } float num = 0f; if (_mushroomZombieAchievementTestTickField.GetValue(val3) is float num2) { num = num2; } num += 1f; _mushroomZombieAchievementTestTickField.SetValue(val3, num); if (_verboseLogging != null && _verboseLogging.Value) { Log.LogInfo((object)$"[ZombieHit] {GetCurrentSegmentName()}: {num}/{hitsToKillBySegment}"); } if (num >= hitsToKillBySegment) { Log.LogInfo((object)$"[ZombieKill] {GetCurrentSegmentName()}: zombie killed at {hitsToKillBySegment} hits"); if (_mushroomZombieDieMethod != null) { _mushroomZombieDieMethod.Invoke(val3, null); } else { Log.LogWarning((object)"Die() not found, fallback to DestroyZombie()"); val3.DestroyZombie(); } } } } return false; } catch (Exception ex) { Log.LogError((object)("AKGun_RPC_ShootSelfT_Prefix exception: " + ex)); return true; } } } } namespace AutoSegmentCycle { [BepInPlugin("com.sol.autosegmentcycle", "Auto Segment Cycle", "1.4.0")] public class Plugin : BaseUnityPlugin { [HarmonyPatch] private static class MapHandlerJumpToSegmentLogicPatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(MapHandler), "JumpToSegmentLogic", new Type[4] { typeof(Segment), typeof(HashSet<int>), typeof(bool), typeof(bool) }, (Type[])null); } private static void Prefix(Segment segment) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) try { OverrideSpawnPoint(segment); } catch (Exception ex) { Log.LogError((object)("[SpawnOverride] Exception: " + ex)); } try { if (PhotonNetwork.IsMasterClient) { DestroyAllOwnedZombies(); } } catch (Exception ex2) { Log.LogError((object)("[ZombieCleanup] Exception: " + ex2)); } } private static void OverrideSpawnPoint(Segment segment) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected I4, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) if (!MapHandler.Exists) { return; } MapHandler instance = Singleton<MapHandler>.Instance; if ((Object)(object)instance == (Object)null) { return; } Vector3 val; if ((int)segment == 5) { if ((Object)(object)instance.respawnThePeak != (Object)null) { instance.respawnThePeak.position = FinalPeakSpawnPosition; ManualLogSource log = Log; val = FinalPeakSpawnPosition; log.LogInfo((object)("[SpawnOverride] Peak respawnThePeak -> " + ((object)(Vector3)(ref val)).ToString())); } else { Log.LogWarning((object)"[SpawnOverride] respawnThePeak is null"); } return; } int num = (int)segment; if (num < 0 || num >= instance.segments.Length) { Log.LogWarning((object)("[SpawnOverride] Invalid segment index: " + num)); return; } MapSegment val2 = instance.segments[num]; if (val2 == null) { Log.LogWarning((object)("[SpawnOverride] mapSegment is null for " + ((object)(Segment)(ref segment)).ToString())); return; } if ((Object)(object)val2.segmentCampfire == (Object)null) { Log.LogWarning((object)("[SpawnOverride] segmentCampfire is null for " + ((object)(Segment)(ref segment)).ToString())); return; } Campfire componentInChildren = val2.segmentCampfire.GetComponentInChildren<Campfire>(true); if ((Object)(object)componentInChildren == (Object)null) { Log.LogWarning((object)("[SpawnOverride] Campfire component not found for " + ((object)(Segment)(ref segment)).ToString())); return; } if ((Object)(object)val2.reconnectSpawnPos == (Object)null) { Log.LogWarning((object)("[SpawnOverride] reconnectSpawnPos is null for " + ((object)(Segment)(ref segment)).ToString())); return; } val2.reconnectSpawnPos.position = ((Component)componentInChildren).transform.position; if (_verboseLogging != null && _verboseLogging.V