Decompiled source of CleanUp v1.0.1

CleanUp.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
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 Peak;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CleanUpManager")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+636c9d182888bea82857a27b7c94293f4f5cc77a")]
[assembly: AssemblyProduct("CleanUpManager")]
[assembly: AssemblyTitle("CleanUpManager")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 CleanupManager
{
	public class CleanupManagerCore : IDisposable
	{
		public static class CleanupPatterns
		{
			public static readonly HashSet<string> RopePatterns = new HashSet<string>
			{
				"RopeDynamic", "RopeAnchor", "RopeShooter", "RopeSpool", "RopeDynamic2 Variant", "RopeAnchorForRopeShooter", "RopeDynamicAntigrav", "RopeAnchorAnti", "Anti-Rope", "ChainShooter",
				"ChainShootable", "Piton", "RavenVoiceThief"
			};

			public static readonly HashSet<string> ItemPatterns = new HashSet<string>
			{
				"SpawnedMushroom", "SpawnedRope", "SpawnedLuggage", "SpawnedTree", "SpawnedRock", "ShelfShroom", "ShelfShroomSpawn", "MagicBeanVine", "Shell Big", "ClimbingSpike",
				"ClimbingSpikeHammered", "ScoutCannon", "ScoutCannonItem", "ScoutCannon_Placed", "Berrynana", "Apple Berry", "Clusterberry", "Item_Coconut", "Cure-All", "Shooter"
			};

			public static readonly HashSet<string> VoiceCursePatterns = new HashSet<string> { "TornadoPoints", "TornadoTarget", "Tumbleweed", "GhostBall", "Frog", "Tornado", "BeeSwarm", "tumbleweed" };
		}

		private readonly ManualLogSource _log;

		private readonly Config _config;

		private float _cleanupTimer;

		private bool _isCleaning;

		private bool _disposed;

		private static HashSet<GameObject>? _cachedBackpackVisuals;

		private static float _cacheTimestamp;

		private const float CacheDuration = 1f;

		public CleanupManagerCore(ManualLogSource log, Config config)
		{
			_log = log;
			_config = config;
			_cleanupTimer = 0f;
			_isCleaning = false;
			_cachedBackpackVisuals = null;
			_cacheTimestamp = 0f;
		}

		public void Update(float deltaTime)
		{
			if (!_disposed && _config.AutoCleanupEnabled.Value)
			{
				_cleanupTimer += deltaTime;
				if (_cleanupTimer >= _config.AutoCleanupInterval.Value)
				{
					_cleanupTimer = 0f;
					CleanupAllSpawnedObjects();
				}
			}
		}

		public void CleanupAllSpawnedObjects()
		{
			if (_isCleaning)
			{
				_log.LogInfo((object)"[Cleanup] Already cleaning, skipping duplicate request.");
				return;
			}
			_isCleaning = true;
			try
			{
				if (!PhotonNetwork.InRoom)
				{
					_log.LogInfo((object)"[Cleanup] Not in a room, skipping cleanup.");
					return;
				}
				BuildBackpackVisualCache();
				if (PhotonNetwork.IsMasterClient)
				{
					_log.LogInfo((object)"[Cleanup] Host initiating cleanup...");
					Dictionary<int, List<int>> dictionary = CollectObjectsByOwner();
					_log.LogInfo((object)$"[Cleanup] Found {dictionary.Count} owners with objects to clean.");
					foreach (KeyValuePair<int, List<int>> item in dictionary)
					{
						int key = item.Key;
						List<int> value = item.Value;
						if (key == PhotonNetwork.LocalPlayer.ActorNumber)
						{
							_log.LogInfo((object)$"[Cleanup] Host cleaning {value.Count} own objects.");
							if (_config.EnableDebugLogs.Value)
							{
								foreach (int item2 in value)
								{
									PhotonView val = PhotonView.Find(item2);
									if ((Object)(object)val != (Object)null)
									{
										_log.LogInfo((object)$"[Cleanup] Destroying view: {((Object)((Component)val).gameObject).name} (ID: {item2})");
									}
								}
							}
							foreach (int item3 in value)
							{
								DestroyViewLocally(item3);
							}
						}
						else
						{
							_log.LogInfo((object)$"[Cleanup] Requesting owner {key} to clean {value.Count} objects.");
							NetworkHelper.RequestOwnerCleanup(key, value);
						}
					}
					NetworkHelper.BroadcastCleanup();
					int num = CleanLocalObjects();
					_log.LogInfo((object)$"[Cleanup] Host cleaned {num} local objects.");
					if (_config.ShowNotifications.Value)
					{
						NotificationManager.ForceDisplay($"<color=#FFA500>Cleanup Manager</color> Cleaned {num} local objects!");
					}
				}
				else
				{
					int num2 = CleanOwnedObjects();
					if (num2 > 0)
					{
						_log.LogInfo((object)$"[Cleanup] Client cleaned {num2} owned objects.");
					}
				}
			}
			catch (Exception ex)
			{
				_log.LogError((object)("[Cleanup] Cleanup failed: " + ex.Message));
				_log.LogError((object)ex.StackTrace);
			}
			finally
			{
				_isCleaning = false;
				_cachedBackpackVisuals = null;
			}
		}

		private void BuildBackpackVisualCache()
		{
			if (_cachedBackpackVisuals != null && Time.time - _cacheTimestamp < 1f)
			{
				return;
			}
			_cachedBackpackVisuals = new HashSet<GameObject>();
			BackpackVisuals[] array = Object.FindObjectsByType<BackpackVisuals>((FindObjectsSortMode)0);
			foreach (BackpackVisuals val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				foreach (KeyValuePair<byte, Item> spawnedVisualItem in val.spawnedVisualItems)
				{
					if ((Object)(object)spawnedVisualItem.Value != (Object)null && (Object)(object)((Component)spawnedVisualItem.Value).gameObject != (Object)null)
					{
						_cachedBackpackVisuals.Add(((Component)spawnedVisualItem.Value).gameObject);
					}
				}
			}
			BackpackOnBackVisuals[] array2 = Object.FindObjectsByType<BackpackOnBackVisuals>((FindObjectsSortMode)0);
			foreach (BackpackOnBackVisuals val2 in array2)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				foreach (KeyValuePair<byte, Item> spawnedVisualItem2 in ((BackpackVisuals)val2).spawnedVisualItems)
				{
					if ((Object)(object)spawnedVisualItem2.Value != (Object)null && (Object)(object)((Component)spawnedVisualItem2.Value).gameObject != (Object)null)
					{
						_cachedBackpackVisuals.Add(((Component)spawnedVisualItem2.Value).gameObject);
					}
				}
			}
			_cacheTimestamp = Time.time;
			if (_config.EnableDebugLogs.Value)
			{
				_log.LogInfo((object)$"[Cleanup] Cached {_cachedBackpackVisuals.Count} backpack visual objects.");
			}
		}

		private bool IsBackpackVisualCached(GameObject obj)
		{
			if (_cachedBackpackVisuals == null)
			{
				return false;
			}
			if (_cachedBackpackVisuals.Contains(obj))
			{
				return true;
			}
			if ((Object)(object)obj.GetComponent<BackpackVisuals>() != (Object)null || (Object)(object)obj.GetComponent<BackpackOnBackVisuals>() != (Object)null || (Object)(object)obj.GetComponent<Backpack>() != (Object)null)
			{
				return true;
			}
			if ((Object)(object)obj.transform.parent != (Object)null)
			{
				string name = ((Object)obj.transform.parent).name;
				if (name.Contains("backpackSlot") || name.Contains("BackpackSlot") || name.Contains("OnBack_") || name.Contains("Pocket") || name.Contains("pocket"))
				{
					return true;
				}
			}
			Item component = obj.GetComponent<Item>();
			if ((Object)(object)component != (Object)null && component.data != null)
			{
				foreach (Character allCharacter in Character.AllCharacters)
				{
					if (!((Object)(object)allCharacter != (Object)null) || !((Object)(object)allCharacter.player != (Object)null))
					{
						continue;
					}
					ItemSlot tempFullSlot = allCharacter.player.tempFullSlot;
					if (tempFullSlot != null && !tempFullSlot.IsEmpty() && tempFullSlot.data != null && tempFullSlot.data.guid == component.data.guid)
					{
						if (_config.EnableDebugLogs.Value)
						{
							_log.LogInfo((object)("[CleanupManagerCore] Skipping temporary slot item (by GUID): " + ((Object)obj).name));
						}
						return true;
					}
				}
			}
			return false;
		}

		private bool ShouldCleanObject(string objName, GameObject obj)
		{
			if (IsBackpackVisualCached(obj))
			{
				if (_config.EnableDebugLogs.Value)
				{
					_log.LogInfo((object)("[Cleanup] Skipping backpack visual: " + objName));
				}
				return false;
			}
			string name = ((Object)((Component)obj.transform.root).gameObject).name;
			if ((Object)(object)obj.transform.parent != (Object)null)
			{
				Item componentInParent = obj.GetComponentInParent<Item>();
				if ((Object)(object)componentInParent != (Object)null && (Object)(object)((Component)componentInParent).gameObject != (Object)(object)obj)
				{
					if (_config.EnableDebugLogs.Value)
					{
						_log.LogInfo((object)("[Cleanup] Skipping child of Item: " + objName));
					}
					return false;
				}
			}
			if (_config.CleanupRopes.Value)
			{
				foreach (string ropePattern in CleanupPatterns.RopePatterns)
				{
					if (name.Contains(ropePattern))
					{
						return true;
					}
				}
			}
			if (_config.CleanupItems.Value)
			{
				foreach (string itemPattern in CleanupPatterns.ItemPatterns)
				{
					if (name.Contains(itemPattern))
					{
						return true;
					}
				}
			}
			if (_config.CleanupVoiceCurse.Value)
			{
				foreach (string voiceCursePattern in CleanupPatterns.VoiceCursePatterns)
				{
					if (name.Contains(voiceCursePattern))
					{
						return true;
					}
				}
			}
			return false;
		}

		private Dictionary<int, List<int>> CollectObjectsByOwner()
		{
			Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
			GameObject[] array = Object.FindObjectsByType<GameObject>((FindObjectsSortMode)0);
			if (_config.EnableDebugLogs.Value)
			{
				_log.LogInfo((object)"[Cleanup] Scanning for objects to clean...");
			}
			GameObject[] array2 = array;
			foreach (GameObject val in array2)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Character>() != (Object)null)
				{
					continue;
				}
				PhotonView component = val.GetComponent<PhotonView>();
				if (!((Object)(object)component == (Object)null) && ShouldCleanObject(((Object)val).name, val))
				{
					int ownerActorNr = component.OwnerActorNr;
					if (!dictionary.ContainsKey(ownerActorNr))
					{
						dictionary[ownerActorNr] = new List<int>();
					}
					dictionary[ownerActorNr].Add(component.ViewID);
					if (_config.EnableDebugLogs.Value)
					{
						_log.LogInfo((object)$"[Cleanup] Found object: {((Object)val).name} (ID: {component.ViewID}, Owner: {ownerActorNr})");
					}
				}
			}
			if (_config.EnableDebugLogs.Value)
			{
				_log.LogInfo((object)$"[Cleanup] Scan complete. Found {dictionary.Count} owners.");
			}
			return dictionary;
		}

		private void DestroyViewLocally(int viewId)
		{
			PhotonView val = PhotonView.Find(viewId);
			if ((Object)(object)val == (Object)null)
			{
				if (_config.EnableDebugLogs.Value)
				{
					_log.LogInfo((object)$"[Cleanup] View {viewId} not found.");
				}
				return;
			}
			if (_config.EnableDebugLogs.Value)
			{
				_log.LogInfo((object)$"[Cleanup] Destroying local view: {((Object)((Component)val).gameObject).name} ({viewId})");
			}
			try
			{
				if (val.IsMine || val.AmOwner)
				{
					PhotonNetwork.Destroy(val);
				}
				else
				{
					ForceDestroyView(val);
				}
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)$"[Cleanup] Failed to destroy view {viewId}: {ex.Message}");
				try
				{
					ForceDestroyView(val);
				}
				catch (Exception ex2)
				{
					_log.LogWarning((object)("[Cleanup] Force destroy failed: " + ex2.Message));
				}
			}
		}

		private void ForceDestroyView(PhotonView view)
		{
			if ((Object)(object)view == (Object)null || (Object)(object)((Component)view).gameObject == (Object)null)
			{
				return;
			}
			try
			{
				if (view.IsMine || view.AmOwner)
				{
					PhotonNetwork.RemoveRPCs(view);
					PhotonNetwork.LocalCleanPhotonView(view);
				}
			}
			catch
			{
			}
			try
			{
				PhotonCleanupHelper component = ((Component)view).GetComponent<PhotonCleanupHelper>();
				if ((Object)(object)component != (Object)null)
				{
					TriggerPhotonCleanupHelper(component);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)view).gameObject);
				}
			}
			catch
			{
			}
		}

		private void TriggerPhotonCleanupHelper(PhotonCleanupHelper helper)
		{
			try
			{
				MethodInfo method = typeof(PhotonCleanupHelper).GetMethod("OnSceneChange", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method != null)
				{
					method.Invoke(helper, new object[1] { "CleanupManagerCleanup" });
				}
				else if ((Object)(object)((MonoBehaviourPun)helper).photonView != (Object)null)
				{
					PhotonNetwork.Destroy(((MonoBehaviourPun)helper).photonView);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)helper).gameObject);
				}
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[Cleanup] Failed to trigger PhotonCleanupHelper: " + ex.Message));
				if ((Object)(object)((MonoBehaviourPun)helper).photonView != (Object)null)
				{
					try
					{
						PhotonNetwork.Destroy(((MonoBehaviourPun)helper).photonView);
						return;
					}
					catch
					{
						return;
					}
				}
				try
				{
					Object.Destroy((Object)(object)((Component)helper).gameObject);
				}
				catch
				{
				}
			}
		}

		private int CleanLocalObjects()
		{
			int num = 0;
			GameObject[] array = Object.FindObjectsByType<GameObject>((FindObjectsSortMode)0);
			foreach (GameObject val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.GetComponent<Character>() != (Object)null) && !((Object)(object)val.GetComponent<PhotonView>() != (Object)null) && ShouldCleanObject(((Object)val).name, val))
				{
					try
					{
						Object.Destroy((Object)(object)val);
						num++;
					}
					catch
					{
					}
				}
			}
			return num;
		}

		private int CleanOwnedObjects()
		{
			int num = 0;
			GameObject[] array = Object.FindObjectsByType<GameObject>((FindObjectsSortMode)0);
			foreach (GameObject val in array)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Character>() != (Object)null)
				{
					continue;
				}
				PhotonView component = val.GetComponent<PhotonView>();
				if (!((Object)(object)component == (Object)null) && (component.IsMine || component.AmOwner) && ShouldCleanObject(((Object)val).name, val))
				{
					try
					{
						PhotonNetwork.Destroy(component);
						num++;
					}
					catch
					{
					}
				}
			}
			return num;
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				_cachedBackpackVisuals = null;
				_log.LogInfo((object)"[Cleanup] Disposing CleanupManagerCore");
			}
		}
	}
	public class Config
	{
		public ConfigEntry<KeyCode> CleanupKey { get; private set; }

		public ConfigEntry<bool> EnableDebugLogs { get; private set; }

		public ConfigEntry<bool> AutoCleanupEnabled { get; private set; }

		public ConfigEntry<float> AutoCleanupInterval { get; private set; }

		public ConfigEntry<bool> ShowNotifications { get; private set; }

		public ConfigEntry<bool> CleanupRopes { get; private set; }

		public ConfigEntry<bool> CleanupItems { get; private set; }

		public ConfigEntry<bool> CleanupVoiceCurse { get; private set; }

		public Config(ConfigFile config)
		{
			CleanupKey = config.Bind<KeyCode>("General", "CleanupKey", (KeyCode)291, "Key to manually trigger object cleanup.");
			EnableDebugLogs = config.Bind<bool>("General", "EnableDebugLogs", false, "Enable detailed debug logging.");
			AutoCleanupEnabled = config.Bind<bool>("General", "AutoCleanupEnabled", false, "Enable automatic periodic cleanup.");
			AutoCleanupInterval = config.Bind<float>("General", "AutoCleanupInterval", 300f, "Interval in seconds between automatic cleanups (only when AutoCleanupEnabled is true).");
			ShowNotifications = config.Bind<bool>("General", "ShowNotifications", true, "Show notification when cleanup is performed.");
			CleanupRopes = config.Bind<bool>("Categories", "CleanupRopes", true, "Clean up rope-related objects.");
			CleanupItems = config.Bind<bool>("Categories", "CleanupItems", true, "Clean up spawned items.");
			CleanupVoiceCurse = config.Bind<bool>("Categories", "CleanupVoiceCurse", true, "Clean up VoiceCurse spawned objects.");
		}
	}
	public static class NetworkHelper
	{
		private const byte CleanupEventCode = 188;

		private const byte CleanupRequestEventCode = 189;

		private const byte CleanupResponseEventCode = 190;

		private static ManualLogSource? _log;

		private static bool _initialized;

		public static void Initialize(ManualLogSource log)
		{
			if (!_initialized)
			{
				_log = log;
				PhotonNetwork.NetworkingClient.EventReceived += OnPhotonEvent;
				_initialized = true;
				_log.LogInfo((object)"[NetworkHelper] Initialized.");
			}
		}

		public static void Cleanup()
		{
			if (_initialized)
			{
				PhotonNetwork.NetworkingClient.EventReceived -= OnPhotonEvent;
				_initialized = false;
			}
		}

		public static void RequestOwnerCleanup(int targetActor, List<int> viewIds)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsMasterClient)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)"[NetworkHelper] Only master client can request owner cleanup.");
				}
				return;
			}
			object[] array = new object[1] { viewIds.ToArray() };
			RaiseEventOptions val = new RaiseEventOptions();
			val.TargetActors = new int[1] { targetActor };
			RaiseEventOptions val2 = val;
			PhotonNetwork.RaiseEvent((byte)189, (object)array, val2, SendOptions.SendReliable);
			if (_log != null)
			{
				_log.LogInfo((object)$"[NetworkHelper] Sent cleanup request to actor {targetActor} for {viewIds.Count} objects.");
			}
		}

		public static void BroadcastCleanup()
		{
			//IL_0008: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsMasterClient)
			{
				RaiseEventOptions val = new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)1
				};
				PhotonNetwork.RaiseEvent((byte)188, (object)null, val, SendOptions.SendReliable);
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)"[NetworkHelper] Broadcasted cleanup event to all clients.");
				}
			}
		}

		public static void SendCleanupResponse(int actorNumber, int[] viewIds)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			object[] array = new object[2] { actorNumber, viewIds };
			RaiseEventOptions val = new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)2
			};
			PhotonNetwork.RaiseEvent((byte)190, (object)array, val, SendOptions.SendReliable);
		}

		private static void OnPhotonEvent(EventData photonEvent)
		{
			try
			{
				switch (photonEvent.Code)
				{
				case 189:
					HandleCleanupRequest(photonEvent);
					break;
				case 188:
					HandleBroadcastCleanup(photonEvent);
					break;
				case 190:
					HandleCleanupResponse(photonEvent);
					break;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogError((object)("[NetworkHelper] Event handler error: " + ex.Message));
				}
			}
		}

		private static void HandleCleanupRequest(EventData photonEvent)
		{
			if (!(photonEvent.CustomData is object[] array) || array.Length < 1 || !(array[0] is int[] array2) || array2.Length == 0)
			{
				return;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[NetworkHelper] Received cleanup request for {array2.Length} objects.");
			}
			int num = 0;
			int[] array3 = array2;
			foreach (int num2 in array3)
			{
				PhotonView val = PhotonView.Find(num2);
				if (!((Object)(object)val != (Object)null) || (!val.IsMine && !val.AmOwner))
				{
					continue;
				}
				try
				{
					PhotonNetwork.Destroy(val);
					num++;
				}
				catch (Exception ex)
				{
					ManualLogSource? log2 = _log;
					if (log2 != null)
					{
						log2.LogWarning((object)$"[NetworkHelper] Failed to destroy view {num2}: {ex.Message}");
					}
				}
			}
			if (num > 0)
			{
				ManualLogSource? log3 = _log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"[NetworkHelper] Destroyed {num} requested objects.");
				}
			}
		}

		private static void HandleBroadcastCleanup(EventData photonEvent)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				return;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)"[NetworkHelper] Received broadcast cleanup event.");
			}
			Config configInstance = Plugin.ConfigInstance;
			if (configInstance == null)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[NetworkHelper] Config is null, skipping broadcast cleanup.");
				}
				return;
			}
			GameObject[] array = Object.FindObjectsByType<GameObject>((FindObjectsSortMode)0);
			int num = 0;
			GameObject[] array2 = array;
			foreach (GameObject val in array2)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Character>() != (Object)null)
				{
					continue;
				}
				PhotonView component = val.GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null || (!component.IsMine && !component.AmOwner) || IsBackpackVisualCached(val))
				{
					continue;
				}
				if ((Object)(object)val.transform.parent != (Object)null)
				{
					Item componentInParent = val.GetComponentInParent<Item>();
					if ((Object)(object)componentInParent != (Object)null && (Object)(object)((Component)componentInParent).gameObject != (Object)(object)val)
					{
						continue;
					}
				}
				string name = ((Object)((Component)val.transform.root).gameObject).name;
				bool flag = false;
				if (configInstance.CleanupRopes.Value)
				{
					foreach (string ropePattern in CleanupManagerCore.CleanupPatterns.RopePatterns)
					{
						if (name.Contains(ropePattern))
						{
							flag = true;
							break;
						}
					}
				}
				if (!flag && configInstance.CleanupItems.Value)
				{
					foreach (string itemPattern in CleanupManagerCore.CleanupPatterns.ItemPatterns)
					{
						if (name.Contains(itemPattern))
						{
							flag = true;
							break;
						}
					}
				}
				if (!flag && configInstance.CleanupVoiceCurse.Value)
				{
					foreach (string voiceCursePattern in CleanupManagerCore.CleanupPatterns.VoiceCursePatterns)
					{
						if (name.Contains(voiceCursePattern))
						{
							flag = true;
							break;
						}
					}
				}
				if (flag)
				{
					try
					{
						PhotonNetwork.Destroy(component);
						num++;
					}
					catch
					{
					}
				}
			}
			if (num > 0)
			{
				ManualLogSource? log3 = _log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"[NetworkHelper] Cleaned {num} owned objects.");
				}
			}
		}

		private static void HandleCleanupResponse(EventData photonEvent)
		{
			if (photonEvent.CustomData is object[] array && array.Length >= 2)
			{
				int num = (int)array[0];
				int[] array2 = array[1] as int[];
				if (_log != null && Plugin.ConfigInstance.EnableDebugLogs.Value)
				{
					_log.LogInfo((object)$"[NetworkHelper] Received cleanup response from actor {num} for {((array2 != null) ? array2.Length : 0)} objects.");
				}
			}
		}

		private static bool IsBackpackVisualCached(GameObject obj)
		{
			if ((Object)(object)obj.GetComponent<BackpackVisuals>() != (Object)null || (Object)(object)obj.GetComponent<BackpackOnBackVisuals>() != (Object)null || (Object)(object)obj.GetComponent<Backpack>() != (Object)null)
			{
				return true;
			}
			if ((Object)(object)obj.transform.parent != (Object)null)
			{
				string name = ((Object)obj.transform.parent).name;
				if (name.Contains("backpackSlot") || name.Contains("BackpackSlot") || name.Contains("OnBack_") || name.Contains("Pocket") || name.Contains("pocket"))
				{
					return true;
				}
			}
			Item component = obj.GetComponent<Item>();
			if ((Object)(object)component != (Object)null && component.data != null)
			{
				foreach (Character allCharacter in Character.AllCharacters)
				{
					if ((Object)(object)allCharacter != (Object)null && (Object)(object)allCharacter.player != (Object)null)
					{
						ItemSlot tempFullSlot = allCharacter.player.tempFullSlot;
						if (tempFullSlot != null && !tempFullSlot.IsEmpty() && tempFullSlot.data != null && tempFullSlot.data.guid == component.data.guid)
						{
							return true;
						}
					}
				}
			}
			return false;
		}
	}
	public static class NotificationManager
	{
		private static ManualLogSource? _log;

		private static PlayerConnectionLog? _connectionLog;

		private static MethodInfo? _addMessageMethod;

		private static bool _found;

		public static void Initialize(ManualLogSource log)
		{
			_log = log;
			_found = false;
			_connectionLog = null;
			_addMessageMethod = null;
			FindConnectionLog();
		}

		public static void FindConnectionLog()
		{
			if (_found)
			{
				return;
			}
			try
			{
				_connectionLog = Object.FindFirstObjectByType<PlayerConnectionLog>();
				if ((Object)(object)_connectionLog == (Object)null)
				{
					GameObject val = GameObject.Find("PlayerConnectionLog");
					if ((Object)(object)val != (Object)null)
					{
						_connectionLog = val.GetComponent<PlayerConnectionLog>();
					}
				}
				if (!((Object)(object)_connectionLog != (Object)null))
				{
					return;
				}
				_addMessageMethod = typeof(PlayerConnectionLog).GetMethod("AddMessage", BindingFlags.Instance | BindingFlags.NonPublic);
				if (_addMessageMethod != null)
				{
					_found = true;
					ManualLogSource? log = _log;
					if (log != null)
					{
						log.LogInfo((object)"[NotificationManager] PlayerConnectionLog found.");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[NotificationManager] Error finding connection log: " + ex.Message));
				}
			}
		}

		public static void ForceDisplay(string message)
		{
			if (!_found)
			{
				FindConnectionLog();
				if (!_found)
				{
					return;
				}
			}
			try
			{
				_addMessageMethod?.Invoke(_connectionLog, new object[1] { message });
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)("[NotificationManager] Displayed: " + message));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[NotificationManager] Failed to display: " + ex.Message));
				}
			}
		}
	}
	[BepInPlugin("jill920.CleanupManager", "CleanupManager", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony? _harmony;

		private CleanupManagerCore _core;

		internal static ManualLogSource Log { get; private set; }

		internal static Config ConfigInstance { get; private set; }

		private void Awake()
		{
			//IL_002f: 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_00cb: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigInstance = new Config(((BaseUnityPlugin)this).Config);
			Log.LogInfo((object)$"CleanupKey: {ConfigInstance.CleanupKey.Value}");
			Log.LogInfo((object)$"DebugLogging: {ConfigInstance.EnableDebugLogs.Value}");
			Log.LogInfo((object)$"AutoCleanup: {ConfigInstance.AutoCleanupEnabled.Value}");
			Log.LogInfo((object)$"AutoCleanupInterval: {ConfigInstance.AutoCleanupInterval.Value}s");
			try
			{
				_harmony = new Harmony("jill920.CleanupManager");
				_harmony.PatchAll();
				Log.LogInfo((object)"Harmony patches applied.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Harmony patch failed: " + ex.Message));
			}
			_core = new CleanupManagerCore(Log, ConfigInstance);
			NotificationManager.Initialize(Log);
			NetworkHelper.Initialize(Log);
			Log.LogInfo((object)"CleanupManager 1.0.1 loaded successfully.");
		}

		private void Update()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(ConfigInstance.CleanupKey.Value))
			{
				Log.LogInfo((object)"Cleanup key pressed!");
				_core.CleanupAllSpawnedObjects();
			}
			_core.Update(Time.deltaTime);
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_core?.Dispose();
			NetworkHelper.Cleanup();
			if (Log != null)
			{
				Log.LogInfo((object)"CleanupManager unloaded.");
			}
		}
	}
}