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(); } [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 _enabled; private ConfigEntry _maxItems; private readonly HashSet _baselineItems = new HashSet(); private readonly HashSet _trackedDroppedItems = new HashSet(); private readonly HashSet _seenHeldItems = new HashSet(); 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("General", "Enabled", true, "Enable dropped item persistence"); _maxItems = ((BaseUnityPlugin)this).Config.Bind("Persistence", "MaxDroppedItems", 256, new ConfigDescription("Maximum dropped items saved per server", (AcceptableValueBase)(object)new AcceptableValueRange(32, 1024), Array.Empty())); ((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 liveItems = new HashSet(); 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 list = new List(); 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(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(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; } } }