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.");
}
}
}
}