Decompiled source of HowToFishDroppedPersistence v1.1.0

plugins\HowToFishDroppedPersistence\HowToFishDroppedPersistence.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using FishNet.Object;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
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("HowToFishDroppedPersistence")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HowToFishDroppedPersistence")]
[assembly: AssemblyTitle("HowToFishDroppedPersistence")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HowToFishDroppedPersistence
{
	[BepInPlugin("local.howtofish.droppedpersistence", "How to Fish Dropped Item Persistence", "1.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[Serializable]
		private sealed class PersistenceFile
		{
			public int Version = 1;

			public string ServerName;

			public DroppedItemRecord[] Items = Array.Empty<DroppedItemRecord>();
		}

		[Serializable]
		private sealed class DroppedItemRecord
		{
			public bool Exists = true;

			public byte InventorySlot = byte.MaxValue;

			public byte ItemId;

			public float PositionX;

			public float PositionY;

			public float PositionZ;

			public float RotationX;

			public float RotationY;

			public float RotationZ;

			public float RotationW;

			public float Cookness;

			public float BettingMultiplier = 1f;

			public float Weight = 1f;

			public float KillScoreMultiplier = 1f;

			public byte SkinIndex;

			public bool IsDripCreature;

			public byte Sharpness;

			public byte Sight;

			public byte BarrelAttachment;

			public byte AmmoType;

			public bool ExtendedMag;

			public bool LaserSight;

			public float LinearVelocityX;

			public float LinearVelocityY;

			public float LinearVelocityZ;

			public float AngularVelocityX;

			public float AngularVelocityY;

			public float AngularVelocityZ;
		}

		public const string PluginGuid = "local.howtofish.droppedpersistence";

		public const string PluginName = "How to Fish Dropped Item Persistence";

		public const string PluginVersion = "1.1.0";

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<int> _maxItems;

		private readonly HashSet<int> _baselineItems = new HashSet<int>();

		private readonly HashSet<int> _trackedDroppedItems = new HashSet<int>();

		private readonly HashSet<int> _seenHeldItems = new HashSet<int>();

		private bool _loaded;

		private bool _baselineCaptured;

		private string _path;

		private float _nextSave;

		private float _restoreAt;

		private bool _quitting;

		private bool _errorLogged;

		private void Awake()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable dropped item persistence");
			_maxItems = ((BaseUnityPlugin)this).Config.Bind<int>("Persistence", "MaxDroppedItems", 256, new ConfigDescription("Maximum dropped items saved per server", (AcceptableValueBase)(object)new AcceptableValueRange<int>(32, 1024), Array.Empty<object>()));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded How to Fish Dropped Item Persistence 1.1.0.");
		}

		private void OnApplicationQuit()
		{
			_quitting = true;
		}

		private void Update()
		{
			if (!_enabled.Value || _quitting || !Object.op_Implicit((Object)(object)Player.LocalPlayer))
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)Server.Instance) || !((NetworkBehaviour)Server.Instance).IsServerInitialized || !Object.op_Implicit((Object)(object)ItemManager.Instance) || SaveManager.CurServerSave == null)
			{
				_loaded = false;
				_path = null;
				_baselineCaptured = false;
				_baselineItems.Clear();
				_trackedDroppedItems.Clear();
				_seenHeldItems.Clear();
				return;
			}
			string persistencePath = GetPersistencePath();
			if (!_loaded || !string.Equals(_path, persistencePath, StringComparison.OrdinalIgnoreCase))
			{
				_path = persistencePath;
				_loaded = true;
				_baselineCaptured = false;
				_baselineItems.Clear();
				_trackedDroppedItems.Clear();
				_seenHeldItems.Clear();
				_restoreAt = Time.unscaledTime + 1.25f;
				_nextSave = Time.unscaledTime + 0.25f;
			}
			if (!_baselineCaptured)
			{
				if (Time.unscaledTime < _restoreAt && ItemManager.Items.Count == 0)
				{
					return;
				}
				CaptureBaseline();
				Restore(persistencePath);
			}
			Track();
			if (Time.unscaledTime >= _nextSave)
			{
				_nextSave = Time.unscaledTime + 0.5f;
				Save(persistencePath);
			}
		}

		private string GetPersistencePath()
		{
			string text = ((SaveManager.CurServerSave != null) ? SaveManager.CurServerSave.Name : "default");
			if (string.IsNullOrWhiteSpace(text))
			{
				text = "default";
			}
			string text2 = string.Concat(text.Select((char value) => (!char.IsLetterOrDigit(value)) ? '_' : value));
			if (string.IsNullOrWhiteSpace(text2))
			{
				text2 = "default";
			}
			return Path.Combine(Paths.ConfigPath, "local.howtofish.droppedpersistence.drops." + text2 + ".json");
		}

		private string GetLegacyPath()
		{
			string text = ((SaveManager.CurServerSave != null) ? SaveManager.CurServerSave.Name : "default");
			if (string.IsNullOrWhiteSpace(text))
			{
				text = "default";
			}
			string text2 = string.Concat(text.Select((char value) => (!char.IsLetterOrDigit(value)) ? '_' : value));
			if (string.IsNullOrWhiteSpace(text2))
			{
				text2 = "default";
			}
			return Path.Combine(Paths.ConfigPath, "local.howtofish.funpack.drops." + text2 + ".json");
		}

		private void Track()
		{
			HashSet<int> liveItems = new HashSet<int>();
			Item[] array = ItemManager.Items.Values.ToArray();
			foreach (Item val in array)
			{
				if (!Object.op_Implicit((Object)(object)val) || ((NetworkBehaviour)val).IsDeinitializing)
				{
					continue;
				}
				int instanceID = ((Object)val).GetInstanceID();
				liveItems.Add(instanceID);
				if (Object.op_Implicit((Object)(object)val.Holder) || Object.op_Implicit((Object)(object)val.SyncedHolder) || Object.op_Implicit((Object)(object)val.LastHolder) || val.IsInInventory)
				{
					_seenHeldItems.Add(instanceID);
				}
				if (Object.op_Implicit((Object)(object)val.Holder) || Object.op_Implicit((Object)(object)val.SyncedHolder) || val.IsInInventory || Object.op_Implicit((Object)(object)val.AttachedRod) || Object.op_Implicit((Object)(object)val.BirdHolder) || Object.op_Implicit((Object)(object)val.DeadPlayer))
				{
					_trackedDroppedItems.Remove(instanceID);
				}
				else if (!_baselineItems.Contains(instanceID) || _seenHeldItems.Contains(instanceID) || Object.op_Implicit((Object)(object)val.LastHolder))
				{
					if (!_trackedDroppedItems.Contains(instanceID))
					{
						_nextSave = Time.unscaledTime;
					}
					_trackedDroppedItems.Add(instanceID);
				}
			}
			_trackedDroppedItems.RemoveWhere((int value) => !liveItems.Contains(value));
			_seenHeldItems.RemoveWhere((int value) => !liveItems.Contains(value));
		}

		private void CaptureBaseline()
		{
			_baselineItems.Clear();
			Item[] array = ItemManager.Items.Values.ToArray();
			foreach (Item val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && !((NetworkBehaviour)val).IsDeinitializing)
				{
					_baselineItems.Add(((Object)val).GetInstanceID());
				}
			}
			_baselineCaptured = true;
		}

		private void Save(string path)
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_0451: Unknown result type (might be due to invalid IL or missing references)
			//IL_047d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a9: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(path) || !Object.op_Implicit((Object)(object)ItemManager.Instance))
			{
				return;
			}
			try
			{
				Track();
				List<DroppedItemRecord> list = new List<DroppedItemRecord>();
				Item[] array = ItemManager.Items.Values.ToArray();
				foreach (Item val in array)
				{
					if (Object.op_Implicit((Object)(object)val) && !((NetworkBehaviour)val).IsDeinitializing && !val.IsDestroying && !Object.op_Implicit((Object)(object)val.Holder) && !Object.op_Implicit((Object)(object)val.SyncedHolder) && !val.IsInInventory && !Object.op_Implicit((Object)(object)val.AttachedRod) && !Object.op_Implicit((Object)(object)val.BirdHolder) && !Object.op_Implicit((Object)(object)val.DeadPlayer) && (_trackedDroppedItems.Contains(((Object)val).GetInstanceID()) || !_baselineItems.Contains(((Object)val).GetInstanceID()) || _seenHeldItems.Contains(((Object)val).GetInstanceID()) || Object.op_Implicit((Object)(object)val.LastHolder)) && IsFinite(((Component)val).transform.position) && IsFinite(((Component)val).transform.rotation))
					{
						list.Add(new DroppedItemRecord
						{
							Exists = true,
							InventorySlot = byte.MaxValue,
							ItemId = val.ID,
							PositionX = ((Component)val).transform.position.x,
							PositionY = ((Component)val).transform.position.y,
							PositionZ = ((Component)val).transform.position.z,
							RotationX = ((Component)val).transform.rotation.x,
							RotationY = ((Component)val).transform.rotation.y,
							RotationZ = ((Component)val).transform.rotation.z,
							RotationW = ((Component)val).transform.rotation.w,
							Cookness = val.Cookness,
							BettingMultiplier = val.BettingMultiplier,
							Weight = val.RandomizedWeight,
							KillScoreMultiplier = val.KillScoreMultiplier,
							SkinIndex = val.CurSkin,
							IsDripCreature = (Object.op_Implicit((Object)(object)val.Creature) && val.Creature.IsDrip),
							Sharpness = (byte)(Object.op_Implicit((Object)(object)val.Melee) ? val.Melee.SharpnessIndex : 0),
							Sight = (byte)((Object.op_Implicit((Object)(object)val.Weapon) && Object.op_Implicit((Object)(object)val.Weapon.Attachments)) ? val.Weapon.Attachments.Sight : 0),
							BarrelAttachment = (byte)((Object.op_Implicit((Object)(object)val.Weapon) && Object.op_Implicit((Object)(object)val.Weapon.Attachments)) ? val.Weapon.Attachments.BarrelAttachment : 0),
							AmmoType = (byte)((Object.op_Implicit((Object)(object)val.Weapon) && Object.op_Implicit((Object)(object)val.Weapon.Attachments)) ? val.Weapon.Attachments.AmmoType : 0),
							ExtendedMag = (Object.op_Implicit((Object)(object)val.Weapon) && Object.op_Implicit((Object)(object)val.Weapon.Attachments) && val.Weapon.Attachments.ExtendedMag),
							LaserSight = (Object.op_Implicit((Object)(object)val.Weapon) && Object.op_Implicit((Object)(object)val.Weapon.Attachments) && val.Weapon.Attachments.LaserSight),
							LinearVelocityX = (Object.op_Implicit((Object)(object)val.Rig) ? val.Rig.linearVelocity.x : 0f),
							LinearVelocityY = (Object.op_Implicit((Object)(object)val.Rig) ? val.Rig.linearVelocity.y : 0f),
							LinearVelocityZ = (Object.op_Implicit((Object)(object)val.Rig) ? val.Rig.linearVelocity.z : 0f),
							AngularVelocityX = (Object.op_Implicit((Object)(object)val.Rig) ? val.Rig.angularVelocity.x : 0f),
							AngularVelocityY = (Object.op_Implicit((Object)(object)val.Rig) ? val.Rig.angularVelocity.y : 0f),
							AngularVelocityZ = (Object.op_Implicit((Object)(object)val.Rig) ? val.Rig.angularVelocity.z : 0f)
						});
						if (list.Count >= _maxItems.Value)
						{
							break;
						}
					}
				}
				if (list.Count != 0 || !HasNonEmptySnapshot(path))
				{
					PersistenceFile persistenceFile = new PersistenceFile
					{
						ServerName = ((SaveManager.CurServerSave != null) ? SaveManager.CurServerSave.Name : "default"),
						Items = list.ToArray()
					};
					Directory.CreateDirectory(Paths.ConfigPath);
					string text = path + ".tmp";
					File.WriteAllText(text, JsonConvert.SerializeObject((object)persistenceFile, (Formatting)1));
					File.Copy(text, path, overwrite: true);
					File.Delete(text);
					_errorLogged = false;
				}
			}
			catch (Exception ex)
			{
				if (!_errorLogged)
				{
					_errorLogged = true;
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Dropped item persistence save failed: " + ex.Message));
				}
			}
		}

		private bool HasNonEmptySnapshot(string path)
		{
			if (string.IsNullOrEmpty(path) || !File.Exists(path))
			{
				return false;
			}
			try
			{
				PersistenceFile persistenceFile = JsonConvert.DeserializeObject<PersistenceFile>(File.ReadAllText(path));
				return persistenceFile != null && persistenceFile.Items != null && persistenceFile.Items.Length != 0;
			}
			catch
			{
				return false;
			}
		}

		private void Restore(string path)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: 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_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Expected O, but got Unknown
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			string path2 = (File.Exists(path) ? path : GetLegacyPath());
			if (!File.Exists(path2))
			{
				return;
			}
			try
			{
				PersistenceFile persistenceFile = JsonConvert.DeserializeObject<PersistenceFile>(File.ReadAllText(path2));
				if (persistenceFile == null || persistenceFile.Items == null)
				{
					return;
				}
				DroppedItemRecord[] items = persistenceFile.Items;
				Vector3 val = default(Vector3);
				Quaternion val2 = default(Quaternion);
				foreach (DroppedItemRecord droppedItemRecord in items)
				{
					if (droppedItemRecord == null || !droppedItemRecord.Exists)
					{
						continue;
					}
					((Vector3)(ref val))..ctor(droppedItemRecord.PositionX, droppedItemRecord.PositionY, droppedItemRecord.PositionZ);
					((Quaternion)(ref val2))..ctor(droppedItemRecord.RotationX, droppedItemRecord.RotationY, droppedItemRecord.RotationZ, droppedItemRecord.RotationW);
					if (!IsFinite(val) || !IsFinite(val2))
					{
						continue;
					}
					Item spawnable = GameInfo.GetSpawnable(droppedItemRecord.ItemId);
					if (!Object.op_Implicit((Object)(object)spawnable) || HasLooseItemAt(droppedItemRecord.ItemId, val))
					{
						continue;
					}
					Item val3 = ItemManager.Instance.SpawnNewItem(spawnable, val, val2);
					if (Object.op_Implicit((Object)(object)val3))
					{
						val3.LoadFromSave(new SavedItem
						{
							Exists = droppedItemRecord.Exists,
							InventorySlot = droppedItemRecord.InventorySlot,
							ItemID = droppedItemRecord.ItemId,
							Cookness = droppedItemRecord.Cookness,
							BettingMultiplier = droppedItemRecord.BettingMultiplier,
							Weight = droppedItemRecord.Weight,
							KillScoreMultiplier = droppedItemRecord.KillScoreMultiplier,
							SkinIndex = droppedItemRecord.SkinIndex,
							Sharpness = droppedItemRecord.Sharpness,
							Sight = droppedItemRecord.Sight,
							BarrelAttachment = droppedItemRecord.BarrelAttachment,
							AmmoType = droppedItemRecord.AmmoType,
							ExtendedMag = droppedItemRecord.ExtendedMag,
							LaserSight = droppedItemRecord.LaserSight,
							IsDripCreature = droppedItemRecord.IsDripCreature
						});
						val3._cookness.Value = droppedItemRecord.Cookness;
						val3._bettingMultiplier.Value = droppedItemRecord.BettingMultiplier;
						val3._syncedRandomWeight.Value = droppedItemRecord.Weight;
						val3._killScoreMultiplier.Value = droppedItemRecord.KillScoreMultiplier;
						val3._curSkin.Value = droppedItemRecord.SkinIndex;
						if (Object.op_Implicit((Object)(object)val3.Creature))
						{
							val3.Creature._isDrip.Value = droppedItemRecord.IsDripCreature;
						}
						if (Object.op_Implicit((Object)(object)val3.Rig))
						{
							val3.Rig.linearVelocity = new Vector3(droppedItemRecord.LinearVelocityX, droppedItemRecord.LinearVelocityY, droppedItemRecord.LinearVelocityZ);
							val3.Rig.angularVelocity = new Vector3(droppedItemRecord.AngularVelocityX, droppedItemRecord.AngularVelocityY, droppedItemRecord.AngularVelocityZ);
						}
						_trackedDroppedItems.Add(((Object)val3).GetInstanceID());
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Dropped item persistence restore failed: " + ex.Message));
			}
		}

		private bool HasLooseItemAt(byte itemId, Vector3 position)
		{
			//IL_0059: 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)
			Item[] array = ItemManager.Items.Values.ToArray();
			foreach (Item val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && val.ID == itemId && !((NetworkBehaviour)val).IsDeinitializing && !Object.op_Implicit((Object)(object)val.Holder) && !Object.op_Implicit((Object)(object)val.SyncedHolder) && !val.IsInInventory && Vector3.Distance(((Component)val).transform.position, position) < 0.75f)
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsFinite(Vector3 value)
		{
			//IL_0000: 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_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (!float.IsNaN(value.x) && !float.IsNaN(value.y) && !float.IsNaN(value.z) && !float.IsInfinity(value.x) && !float.IsInfinity(value.y))
			{
				return !float.IsInfinity(value.z);
			}
			return false;
		}

		private static bool IsFinite(Quaternion value)
		{
			//IL_0000: 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_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			if (!float.IsNaN(value.x) && !float.IsNaN(value.y) && !float.IsNaN(value.z) && !float.IsNaN(value.w) && !float.IsInfinity(value.x) && !float.IsInfinity(value.y) && !float.IsInfinity(value.z))
			{
				return !float.IsInfinity(value.w);
			}
			return false;
		}

		private void OnDestroy()
		{
			_quitting = true;
		}
	}
}