Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Lodged v0.1.0
plugins/Lodged.dll
Decompiled an hour agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.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 Lodged { internal sealed class Entry { internal string Bone; internal Vector3 Pos; internal Quaternion Rot; internal int Look; internal long Born; internal byte[] Item; } internal static class ItemBytes { private static int version = -1; private static int Current() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0016: 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) if (version < 0) { ZPackage val = new ZPackage(); new Inventory("", (Sprite)null, 1, 1).Save(val); version = new ZPackage(val.GetArray()).ReadInt(); } return version; } internal static byte[] Write(ItemData item) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(Current()); item.Save(val); return val.GetArray(); } internal static ItemData Read(byte[] data) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0013: Expected O, but got Unknown try { ZPackage val = new ZPackage(data); Item val2 = (Item)val.ReadInt(); ValueTuple<int, ItemData> valueTuple = ItemData.Load(val, val2); int item = valueTuple.Item1; ItemData item2 = valueTuple.Item2; GameObject val3 = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(item) : null); ItemDrop val4 = (Object.op_Implicit((Object)(object)val3) ? val3.GetComponent<ItemDrop>() : null); if ((Object)(object)val4 == (Object)null) { return null; } ItemData obj = val4.m_itemData.Clone(); obj.m_dropPrefab = val3; obj.m_stack = Mathf.Max(1, item2.m_stack); obj.m_durability = item2.m_durability; obj.m_quality = item2.m_quality; obj.m_variant = item2.m_variant; obj.m_crafterID = item2.m_crafterID; obj.m_crafterName = item2.m_crafterName; obj.m_customData = item2.m_customData; obj.m_worldLevel = item2.m_worldLevel; obj.m_pickedUp = item2.m_pickedUp; obj.m_cheated = item2.m_cheated; return obj; } catch (Exception ex) { Plugin.Log.LogWarning((object)("stuck item data: " + ex.Message)); return null; } } } internal static class Impaled { private sealed class Sent { internal ZDOID Id; internal int Nonce; internal byte[] Item; internal Vector3 Point; internal Quaternion Rotation; internal float Deadline; } private const string RpcAdd = "chistix.lodged.add"; private const string RpcLook = "chistix.lodged.look"; internal static readonly int KeyIn = StringExtensionMethods.GetStableHashCode("chistix.lodged.in"); internal static readonly int KeyRev = StringExtensionMethods.GetStableHashCode("chistix.lodged.inrev"); private const float AnswerSeconds = 10f; private static readonly List<Sent> sent = new List<Sent>(); private static int nonce; private static ZRoutedRpc registered; private static readonly List<ImpaledHost> hosts = new List<ImpaledHost>(); private static int cursor; private static readonly HashSet<Transform> seen = new HashSet<Transform>(); private static readonly List<Transform> walk = new List<Transform>(); private static readonly List<Transform> bones = new List<Transform>(); internal static void Tick() { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && instance != registered) { registered = instance; Impaled.sent.Clear(); instance.Register<ZDOID, ZPackage>("chistix.lodged.add", (Action<long, ZDOID, ZPackage>)OnAdd); instance.Register<ZDOID, long, int>("chistix.lodged.look", (Action<long, ZDOID, long, int>)OnLook); } float time = Time.time; for (int num = Impaled.sent.Count - 1; num >= 0; num--) { if (!(time < Impaled.sent[num].Deadline)) { Sent sent = Impaled.sent[num]; Impaled.sent.RemoveAt(num); try { Fall(sent.Item, sent.Point, sent.Rotation); } catch (Exception ex) { Plugin.Log.LogWarning((object)("unanswered stuck item: " + ex.Message)); } } } if (hosts.Count == 0) { return; } int i = 0; for (int num2 = Mathf.Min(hosts.Count, 4); i < num2; i++) { if (hosts.Count <= 0) { break; } if (cursor >= hosts.Count) { cursor = 0; } ImpaledHost impaledHost = hosts[cursor++]; if (!((Object)(object)impaledHost == (Object)null)) { try { impaledHost.Visit(time); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("stuck in creature: " + ex2.Message)); } } } } internal static void Register(ImpaledHost h) { if (!hosts.Contains(h)) { hosts.Add(h); } } internal static void Unregister(ImpaledHost h) { hosts.Remove(h); } internal static void Bones(Character ch, List<Transform> into) { into.Clear(); seen.Clear(); SkinnedMeshRenderer[] componentsInChildren = ((Component)ch).GetComponentsInChildren<SkinnedMeshRenderer>(false); for (int i = 0; i < componentsInChildren.Length; i++) { Transform[] array = componentsInChildren[i].bones; foreach (Transform val in array) { if (Object.op_Implicit((Object)(object)val) && ((Component)val).gameObject.activeInHierarchy && seen.Add(val)) { into.Add(val); } } } if (into.Count > 0) { return; } Animator val2 = (((Object)(object)ch.m_animator != (Object)null) ? ch.m_animator : ((Component)ch).GetComponentInChildren<Animator>()); if (!Object.op_Implicit((Object)(object)val2)) { return; } walk.Clear(); walk.Add(((Component)val2).transform); while (walk.Count > 0) { Transform val3 = walk[walk.Count - 1]; walk.RemoveAt(walk.Count - 1); if (!(((Object)val3).name == "lodged_look") && ((Component)val3).gameObject.activeInHierarchy) { into.Add(val3); for (int num = val3.childCount - 1; num >= 0; num--) { walk.Add(val3.GetChild(num)); } } } } internal static Transform Bone(Character ch, string name) { if (string.IsNullOrEmpty(name)) { return ((Component)ch).transform; } Bones(ch, bones); foreach (Transform bone in bones) { if (((Object)bone).name == name) { return bone; } } return ((Component)ch).transform; } private static Transform Closest(Character ch, Vector3 point) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) Bones(ch, bones); Transform result = null; float num = float.MaxValue; foreach (Transform bone in bones) { Vector3 val = bone.position - point; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = bone; } } return result; } internal static bool Add(Character ch, ItemData item, int look, Vector3 hitPoint, Quaternion rotation) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_010a: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) ItemData obj = item.Clone(); obj.m_stack = 1; obj.m_equipped = false; Transform val = Closest(ch, hitPoint); Transform val2 = (Object.op_Implicit((Object)(object)val) ? val : ((Component)ch).transform); Vector3 val3 = hitPoint + (Object.op_Implicit((Object)(object)val) ? ((val.position - hitPoint) * 0.25f) : Vector3.zero) + rotation * Vector3.forward * Visuals.Depth(Visuals.Get(look)); byte[] array = ItemBytes.Write(obj); ZDO zDO = ch.m_nview.GetZDO(); Sent sent = new Sent { Id = zDO.m_uid, Nonce = ++nonce, Item = array, Point = hitPoint - rotation * Vector3.forward * 0.3f, Rotation = rotation, Deadline = Time.time + 10f }; Impaled.sent.Add(sent); ZPackage val4 = new ZPackage(); val4.Write(Object.op_Implicit((Object)(object)val) ? ((Object)val).name : ""); val4.Write(val2.InverseTransformPoint(val3)); val4.Write(Quaternion.Inverse(val2.rotation) * rotation); val4.Write(look); val4.Write(ZNet.instance.GetTime().Ticks); val4.Write(array); val4.Write(sent.Point); val4.Write(rotation); val4.Write(sent.Nonce); long owner = zDO.GetOwner(); try { if (owner != 0L) { ZRoutedRpc.instance.InvokeRoutedRPC(owner, "chistix.lodged.add", new object[2] { zDO.m_uid, val4 }); } else { ZRoutedRpc.instance.InvokeRoutedRPC("chistix.lodged.add", new object[2] { zDO.m_uid, val4 }); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("stuck in creature, send: " + ex.Message)); } return true; } private static void OnAdd(long sender, ZDOID id, ZPackage pkg) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) Entry entry = new Entry { Bone = pkg.ReadString(), Pos = pkg.ReadVector3(), Rot = pkg.ReadQuaternion(), Look = pkg.ReadInt(), Born = pkg.ReadLong(), Item = pkg.ReadByteArray() }; Vector3 point = pkg.ReadVector3(); Quaternion rotation = pkg.ReadQuaternion(); int num = pkg.ReadInt(); ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(id) : null); GameObject val2 = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null); Character val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent<Character>() : null); bool flag = false; try { if (val == null || !val.IsOwner() || (Object)(object)val3 == (Object)null || val3.IsDead()) { Fall(entry.Item, point, rotation); flag = true; return; } List<Entry> list = Read(val); list.Add(entry); int value = Plugin.PerCreature.Value; List<Entry> list2 = new List<Entry>(); while (list.Count > value) { list2.Add(list[0]); list.RemoveAt(0); } Write(val, list); flag = true; foreach (Entry item in list2) { Fall(item.Item, WorldPoint(val3, item), Rotation(val3, item)); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("stuck in creature: " + ex.Message)); if (!flag) { try { Fall(entry.Item, point, rotation); return; } catch { return; } } } finally { ZRoutedRpc.instance.InvokeRoutedRPC(0L, "chistix.lodged.look", new object[3] { id, sender, num }); } } private static void OnLook(long from, ZDOID id, long shooter, int number) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (shooter == ZDOMan.GetSessionID()) { for (int i = 0; i < sent.Count; i++) { if (sent[i].Nonce == number && sent[i].Id == id) { sent.RemoveAt(i); break; } } } GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null); Character val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Character>() : null); if ((Object)(object)val2 != (Object)null) { Ensure(val2); } } internal static void Ensure(Character ch) { (((Component)ch).GetComponent<ImpaledHost>() ?? ((Component)ch).gameObject.AddComponent<ImpaledHost>()).Init(ch); } internal static Vector3 WorldPoint(Character ch, Entry e) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) return Bone(ch, e.Bone).TransformPoint(e.Pos); } internal static Quaternion Rotation(Character ch, Entry e) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) return Bone(ch, e.Bone).rotation * e.Rot; } internal static void Fall(byte[] data, Vector3 point, Quaternion rotation) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) ItemData val = ItemBytes.Read(data); if (val != null) { ItemDrop val2 = ItemDrop.DropItem(val, 1, point, rotation); Rigidbody val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<Rigidbody>() : null); if (Object.op_Implicit((Object)(object)val3) && !val3.isKinematic) { val3.linearVelocity = Random.insideUnitSphere * 0.5f; } } } internal static List<Entry> Read(ZDO zdo) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) List<Entry> list = new List<Entry>(); byte[] byteArray = zdo.GetByteArray(KeyIn, (byte[])null); if (byteArray == null || byteArray.Length < 2) { return list; } try { ZPackage val = new ZPackage(byteArray); if (val.ReadByte() != 1) { return list; } int num = val.ReadInt(); for (int i = 0; i < num; i++) { list.Add(new Entry { Bone = val.ReadString(), Pos = val.ReadVector3(), Rot = val.ReadQuaternion(), Look = val.ReadInt(), Born = val.ReadLong(), Item = val.ReadByteArray() }); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("stuck list: " + ex.Message)); } return list; } internal static void Write(ZDO zdo, List<Entry> list) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (list.Count == 0) { zdo.Set(KeyIn, new byte[0]); } else { ZPackage val = new ZPackage(); val.Write((byte)1); val.Write(list.Count); foreach (Entry item in list) { val.Write(item.Bone ?? ""); val.Write(item.Pos); val.Write(item.Rot); val.Write(item.Look); val.Write(item.Born); val.Write(item.Item); } zdo.Set(KeyIn, val.GetArray()); } zdo.Set(KeyRev, zdo.GetInt(KeyRev, 0) + 1, false); } internal static void Release(Character ch) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) ZNetView val = (Object.op_Implicit((Object)(object)ch) ? ch.m_nview : null); if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner()) { return; } ZDO zDO = val.GetZDO(); byte[] byteArray = zDO.GetByteArray(KeyIn, (byte[])null); if (byteArray == null || byteArray.Length < 2) { return; } foreach (Entry item in Read(zDO)) { Fall(item.Item, WorldPoint(ch, item), Rotation(ch, item)); } Write(zDO, new List<Entry>()); } } internal sealed class ImpaledHost : MonoBehaviour { private Character ch; private ZNetView view; private int seenRev = -1; private int shownCount; private float nextExpire; private float keepUntil; private readonly List<GameObject> shown = new List<GameObject>(); private readonly Dictionary<string, Transform> boneCache = new Dictionary<string, Transform>(); internal void Init(Character character) { ch = character; view = ch.m_nview; keepUntil = Time.time + 15f; Impaled.Register(this); Visit(Time.time); } internal void Visit(float now) { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)view == (Object)null || !view.IsValid()) { return; } ZDO zDO = view.GetZDO(); int num = zDO.GetInt(Impaled.KeyRev, 0); if (num != seenRev) { seenRev = num; Show(zDO); } if (zDO.IsOwner() && shownCount > 0 && now >= nextExpire) { nextExpire = now + 10f; List<Entry> list = Impaled.Read(zDO); DateTime time = ZNet.instance.GetTime(); float lifetimeSeconds = Plugin.LifetimeSeconds; List<Entry> list2 = new List<Entry>(); foreach (Entry item in list) { if ((time - new DateTime(item.Born)).TotalSeconds < (double)lifetimeSeconds) { list2.Add(item); continue; } ItemData val = ItemBytes.Read(item.Item); if (val != null && !Wear.Tracks(val)) { Impaled.Fall(item.Item, Impaled.WorldPoint(ch, item), Impaled.Rotation(ch, item)); } } if (list2.Count != list.Count) { Impaled.Write(zDO, list2); } } if (shownCount == 0 && now > keepUntil) { Object.Destroy((Object)(object)this); } } private Transform Bone(string name) { if (string.IsNullOrEmpty(name)) { return ((Component)ch).transform; } if (boneCache.TryGetValue(name, out var value) && Object.op_Implicit((Object)(object)value)) { return value; } Transform val = Impaled.Bone(ch, name); boneCache[name] = val; return val; } private void Show(ZDO zdo) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) foreach (GameObject item in shown) { if (Object.op_Implicit((Object)(object)item)) { Object.Destroy((Object)(object)item); } } shown.Clear(); List<Entry> list = Impaled.Read(zdo); shownCount = list.Count; foreach (Entry item2 in list) { Transform val = Bone(item2.Bone); GameObject val2 = Visuals.Place(Visuals.Get(item2.Look), val); if (!((Object)(object)val2 == (Object)null)) { val2.transform.localPosition = item2.Pos; val2.transform.localRotation = item2.Rot; Vector3 lossyScale = val.lossyScale; val2.transform.localScale = new Vector3((lossyScale.x != 0f) ? (1f / lossyScale.x) : 1f, (lossyScale.y != 0f) ? (1f / lossyScale.y) : 1f, (lossyScale.z != 0f) ? (1f / lossyScale.z) : 1f); shown.Add(val2); } } } private void OnDestroy() { Impaled.Unregister(this); } } [HarmonyPatch(typeof(Character), "Awake")] internal static class ImpaledOnLoad { private static void Postfix(Character __instance) { byte[] array = (((Object)(object)__instance.m_nview != (Object)null && __instance.m_nview.IsValid()) ? __instance.m_nview.GetZDO().GetByteArray(Impaled.KeyIn, (byte[])null) : null); if (array != null && array.Length > 1) { Impaled.Ensure(__instance); } } } [HarmonyPatch(typeof(Character), "OnDeath")] internal static class CreatureDeath { private static void Prefix(Character __instance) { try { Impaled.Release(__instance); } catch (Exception ex) { Plugin.Log.LogWarning((object)("death drop: " + ex.Message)); } } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class PlayerDeath { private static void Prefix(Player __instance) { try { Impaled.Release((Character)(object)__instance); } catch (Exception ex) { Plugin.Log.LogWarning((object)("death drop: " + ex.Message)); } } } [HarmonyPatch(typeof(ZNetScene), "Destroy")] internal static class CreatureGone { private static void Prefix(GameObject go) { if ((Object)(object)go == (Object)null || (Object)(object)go.GetComponent<ImpaledHost>() == (Object)null) { return; } try { Impaled.Release(go.GetComponent<Character>()); } catch (Exception ex) { Plugin.Log.LogWarning((object)("despawn drop: " + ex.Message)); } } } [HarmonyPatch(typeof(Game), "Shutdown")] internal static class LeavingWorld { private static void Prefix(Game __instance) { if (__instance.m_shuttingDown || (Object)(object)Player.m_localPlayer == (Object)null) { return; } try { Impaled.Release((Character)(object)Player.m_localPlayer); } catch (Exception ex) { Plugin.Log.LogWarning((object)("logout drop: " + ex.Message)); } } } [BepInPlugin("chistix.lodged", "Lodged", "0.1.0")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "chistix.lodged"; public const string Version = "0.1.0"; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> Hits; internal static ConfigEntry<int> Minutes; internal static ConfigEntry<int> PerArea; internal static ConfigEntry<int> PerCreature; internal static ManualLogSource Log; private Harmony harmony; internal static bool On { get { if (Enabled != null) { return Enabled.Value; } return false; } } internal static int Life { get { if (Hits != null) { return Hits.Value; } return 3; } } internal static float LifetimeSeconds { get { if (Minutes != null) { return (float)Minutes.Value * 60f; } return 1200f; } } private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Arrows, bolts and thrown spears stick where they hit and can be picked up. Off: they behave as in the game; what is already stuck stays and can be picked up. / Стрелы, болты и метательные копья втыкаются в место попадания, их можно подобрать. Выключено: как в игре; уже воткнутые остаются, их можно подобрать."); Hits = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ArrowHits", 3, new ConfigDescription("Hits an arrow or bolt lasts; it breaks on the last one and cannot be picked up. 1 = every arrow breaks on its first hit. Spears keep their own durability. / Сколько попаданий выдерживает стрела или болт; на последнем ломается и не подбирается. 1 = ломается с первого. У копий своя прочность.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); Minutes = ((BaseUnityPlugin)this).Config.Bind<int>("General", "StuckMinutes", 20, new ConfigDescription("Minutes a stuck arrow or spear stays unpicked while its area is loaded; also cleared after six times that on the world clock. / Сколько минут неподобранная стрела или копьё остаётся, пока участок загружен; по часам мира убирается после шестикратного срока.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 240), Array.Empty<object>())); PerArea = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "PerArea", 50, new ConfigDescription("Most stuck arrows and spears in one area of the world (64 x 64 m); over it the oldest go. / Больше всего воткнутых стрел и копий на одном участке мира (64 x 64 м); сверх — исчезают самые старые.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 500), Array.Empty<object>())); PerCreature = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "PerCreature", 8, new ConfigDescription("Most arrows and spears stuck in one creature or player; over it the oldest falls to the ground. / Больше всего стрел и копий в одном существе или игроке; лишняя, самая старая, падает на землю.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30), Array.Empty<object>())); harmony = new Harmony("chistix.lodged"); harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)("Lodged 0.1.0: arrows and spears stick, " + Life + " hits per arrow, " + Minutes.Value + " min unpicked, " + PerArea.Value + " per area.")); } private void Update() { Stuck.Tick(); Impaled.Tick(); Shots.Tick(); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } public struct ShotFacts { public bool FromAmmo; public bool ThrownItem; public float Pierce; public float Blunt; public float Slash; public float Area; public bool Tethered; public bool Bounces; } public enum ShotKind { None, Ammo, Thrown } public static class Rules { public static ShotKind Classify(ShotFacts f) { if (!f.FromAmmo && !f.ThrownItem) { return ShotKind.None; } if (f.Area > 0f || f.Tethered || f.Bounces) { return ShotKind.None; } if (!(f.Pierce > 0f) || f.Pierce < f.Blunt || f.Pierce < f.Slash) { return ShotKind.None; } if (!f.FromAmmo) { return ShotKind.Thrown; } return ShotKind.Ammo; } public static bool[] OverLimit(IList<long> born, int limit) { bool[] array = new bool[born.Count]; int num = born.Count - Math.Max(0, limit); if (num <= 0) { return array; } int[] array2 = new int[born.Count]; for (int i = 0; i < array2.Length; i++) { array2[i] = i; } Array.Sort(array2, delegate(int a, int b) { int num3 = born[a].CompareTo(born[b]); return (num3 == 0) ? a.CompareTo(b) : num3; }); for (int num2 = 0; num2 < num; num2++) { array[array2[num2]] = true; } return array; } public static int ZoneKey(int x, int y) { return (x << 16) ^ (y & 0xFFFF); } public static string Plural(int n, string one, string few, string many) { int num = Math.Abs(n) % 100; int num2 = num % 10; if (num2 == 1 && num != 11) { return one; } if (num2 >= 2 && num2 <= 4 && (num < 12 || num > 14)) { return few; } return many; } public static bool Expired(float loadedSeconds, double worldSeconds, float lifetimeSeconds) { if (lifetimeSeconds > 0f) { if (!(loadedSeconds >= lifetimeSeconds)) { return worldSeconds >= (double)lifetimeSeconds * 6.0; } return true; } return false; } } internal sealed class Shot { internal ItemData Item; internal int Wear; internal bool FromAmmo; } internal static class Shots { private sealed class Token { internal ItemData Item; internal int Wear; internal float Time; } private static readonly Dictionary<ItemData, Token> tokens = new Dictionary<ItemData, Token>(); private static readonly ConditionalWeakTable<Projectile, Shot> shots = new ConditionalWeakTable<Projectile, Shot>(); internal static bool inUseAmmo; internal static ItemData removed; internal static List<Run> removedQ; private static float nextSweep; internal static void Fired(ItemData stack, List<Run> queue) { int wear = Mathf.Max(0, WearMath.PopFront(queue)); Wear.Set(stack, queue); ItemData val = stack.Clone(); val.m_stack = 1; val.m_equipped = false; val.m_customData.Remove("chistix.lodged.wear"); tokens[stack] = new Token { Item = val, Wear = wear, Time = Time.time }; } internal static void FiredFresh(ItemData template, GameObject projectile, GameObject prefab) { if (template == null || (Object)(object)projectile == (Object)null) { return; } Projectile component = projectile.GetComponent<Projectile>(); if (!((Object)(object)component == (Object)null)) { ItemData val = template.Clone(); val.m_stack = 1; val.m_equipped = false; val.m_customData = new Dictionary<string, string>(); if ((Object)(object)val.m_dropPrefab == (Object)null) { val.m_dropPrefab = prefab; } if (!((Object)(object)val.m_dropPrefab == (Object)null)) { val.m_worldLevel = (byte)Game.m_worldLevel; shots.Remove(component); shots.Add(component, new Shot { Item = val, Wear = 0, FromAmmo = true }); } } } internal static void Bind(Projectile projectile, ItemData ammo) { if (!((Object)(object)projectile == (Object)null) && ammo != null && tokens.TryGetValue(ammo, out var value)) { tokens.Remove(ammo); if (!((Object)(object)value.Item.m_dropPrefab == (Object)null)) { shots.Remove(projectile); shots.Add(projectile, new Shot { Item = value.Item, Wear = value.Wear, FromAmmo = true }); } } } internal static Shot Take(Projectile projectile) { if ((Object)(object)projectile != (Object)null && shots.TryGetValue(projectile, out var value)) { return value; } return null; } internal static void Forget(Projectile projectile) { if ((Object)(object)projectile != (Object)null) { shots.Remove(projectile); } } internal static void Tick() { if (tokens.Count == 0 || Time.time < nextSweep) { return; } nextSweep = Time.time + 5f; List<ItemData> list = null; foreach (KeyValuePair<ItemData, Token> token in tokens) { if (Time.time - token.Value.Time > 5f) { (list ?? (list = new List<ItemData>())).Add(token.Key); } } if (list == null) { return; } foreach (ItemData item in list) { tokens.Remove(item); } } internal static ShotFacts Facts(Projectile p, Shot shot) { ShotFacts result = new ShotFacts { FromAmmo = (shot?.FromAmmo ?? false), ThrownItem = (p.m_respawnItemOnHit && p.m_spawnItem != null), Pierce = p.m_damage.m_pierce, Blunt = p.m_damage.m_blunt, Slash = p.m_damage.m_slash, Area = p.m_aoe, Bounces = p.m_bounce }; result.Tethered = (Object)(object)((Component)p).GetComponent<LineConnect>() != (Object)null || ((Object)(object)p.m_spawnOnHit != (Object)null && (Object)(object)p.m_spawnOnHit.GetComponent<GrapplingPoint>() != (Object)null); return result; } } [HarmonyPatch(typeof(Attack), "UseAmmo")] internal static class UseAmmoHook { private static void Prefix() { Shots.inUseAmmo = true; Shots.removed = null; } private static void Postfix(Attack __instance, bool __result) { Shots.inUseAmmo = false; ItemData removed = Shots.removed; Shots.removed = null; if (__result && Plugin.On && removed != null && removed == __instance.m_ammoItem) { Shots.Fired(removed, Shots.removedQ); } } private static void Finalizer() { Shots.inUseAmmo = false; } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(ItemData), typeof(int) })] internal static class AmmoTaken { private static void Prefix(ItemData item) { if (Shots.inUseAmmo && Wear.Tracks(item)) { Shots.removed = item; Shots.removedQ = Wear.Get(item); } } } [HarmonyPatch(typeof(Projectile), "Setup")] internal static class ProjectileSetup { private static void Postfix(Projectile __instance, ItemData ammo) { if (Plugin.On) { Shots.Bind(__instance, ammo); } } } [HarmonyPatch(typeof(Turret), "ShootProjectile")] internal static class TurretShot { private static void Postfix(Turret __instance) { if (Plugin.On && __instance.m_maxAmmo > 0 && !((Object)(object)__instance.m_lastProjectile == (Object)null) && __instance.m_lastAmmo != null) { GameObject prefab = null; try { ZNetScene instance = ZNetScene.instance; prefab = ((instance != null) ? instance.GetPrefab(__instance.GetAmmoType()) : null); } catch { } Shots.FiredFresh(__instance.m_lastAmmo, __instance.m_lastProjectile, prefab); } } } internal sealed class HitState { internal Shot Shot; internal ShotKind Kind; internal ItemData SpawnItem; internal Quaternion Rotation; } [HarmonyPatch(typeof(Projectile), "OnHit")] internal static class ProjectileHit { private static void Prefix(Projectile __instance, bool water, out HitState __state) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) __state = null; if (!Plugin.On || water || __instance.m_didHit) { return; } Shot shot = Shots.Take(__instance); if (shot == null && (!__instance.m_respawnItemOnHit || __instance.m_spawnItem == null)) { return; } ShotKind shotKind = Rules.Classify(Shots.Facts(__instance, shot)); if (shotKind != ShotKind.None) { __state = new HitState { Shot = shot, Kind = shotKind, SpawnItem = __instance.m_spawnItem, Rotation = ((Component)__instance).transform.rotation }; if (shotKind == ShotKind.Thrown) { __instance.m_spawnItem = null; } } } private static void Postfix(Projectile __instance, Collider collider, Vector3 hitPoint, HitState __state) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0114: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) if (__state == null) { return; } if (!__instance.m_didHit) { if (__state.Kind == ShotKind.Thrown) { __instance.m_spawnItem = __state.SpawnItem; } return; } Shots.Forget(__instance); ItemData val = null; bool flag = false; Quaternion rotation = __state.Rotation; try { if (__state.Kind == ShotKind.Ammo) { if (WearMath.Breaks(__state.Shot.Wear, Plugin.Life)) { return; } val = __state.Shot.Item.Clone(); val.m_stack = 1; Wear.SetSingle(val, __state.Shot.Wear + 1); } else { val = __state.SpawnItem; } if (val != null && !((Object)(object)val.m_dropPrefab == (Object)null)) { int stableHashCode = StringExtensionMethods.GetStableHashCode(Utils.GetPrefabName(((Component)__instance).gameObject)); Character val2 = (Object.op_Implicit((Object)(object)collider) ? ((Component)collider).GetComponentInParent<Character>() : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.m_nview != (Object)null && val2.m_nview.IsValid()) { flag = Impaled.Add(val2, val, stableHashCode, hitPoint, rotation); } else if ((Object)(object)collider == (Object)null || (Object)(object)collider.attachedRigidbody != (Object)null) { Stuck.Loose(val, hitPoint - rotation * Vector3.forward * 0.3f, rotation); flag = true; } else { flag = Stuck.Create(val, stableHashCode, hitPoint, rotation); } ZNetView nview = __instance.m_nview; if ((Object)(object)nview != (Object)null && nview.IsValid() && nview.IsOwner()) { ZNetScene.instance.Destroy(((Component)__instance).gameObject); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("hit of " + ((Object)__instance).name + ": " + ex.Message)); } finally { if (!flag && val != null && (Object)(object)val.m_dropPrefab != (Object)null) { try { Stuck.Loose(val, hitPoint - rotation * Vector3.forward * 0.3f, rotation); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("hit drop: " + ex2.Message)); } } } } } internal sealed class StackSnap { internal int N; internal List<Run> Q; internal bool Split; internal List<ItemData> Targets; internal List<int> Stacks; internal List<List<Run>> Queues; internal ItemData Cell; internal int CellStack; internal List<Run> CellQ; } internal static class StackHooks { internal sealed class Pending { internal ItemData Item; internal int N; internal List<Run> Q; } internal static Pending DropPending; internal static List<Run> Worn(ItemData item) { if (!Wear.Tracks(item) || !Wear.Has(item)) { return null; } List<Run> list = Wear.Get(item); if (!WearMath.AnyWorn(list)) { return null; } return list; } internal static StackSnap Snap(Inventory inventory, ItemData item) { if (inventory == null) { return null; } List<Run> list = Worn(item); if (list == null) { return null; } StackSnap stackSnap = new StackSnap { N = item.m_stack, Q = list, Targets = new List<ItemData>(), Stacks = new List<int>(), Queues = new List<List<Run>>() }; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem != item && allItem.m_shared != null && !(allItem.m_shared.m_name != item.m_shared.m_name)) { stackSnap.Targets.Add(allItem); stackSnap.Stacks.Add(allItem.m_stack); stackSnap.Queues.Add(Wear.Get(allItem)); } } return stackSnap; } internal static void Spread(ItemData item, StackSnap snap) { if (snap == null) { return; } int count = snap.Targets.Count; int[] array = new int[count]; for (int i = 0; i < count; i++) { array[i] = snap.Targets[i].m_stack - snap.Stacks[i]; } List<Run>[] array2 = WearMath.Spread(snap.Q, array); for (int j = 0; j < count; j++) { if (array[j] > 0) { List<Run> q = snap.Queues[j]; WearMath.Append(q, array2[j]); Wear.Set(snap.Targets[j], q); } } Wear.Set(item, snap.Q); } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] internal static class AddAnywhere { private static void Prefix(Inventory __instance, ItemData item, out StackSnap __state) { __state = StackHooks.Snap(__instance, item); } private static void Postfix(ItemData item, StackSnap __state) { StackHooks.Spread(item, __state); } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(Vector2i) })] internal static class AddAtCell { private static void Prefix(Inventory __instance, ItemData item, out StackSnap __state) { __state = StackHooks.Snap(__instance, item); } private static void Postfix(ItemData item, StackSnap __state) { StackHooks.Spread(item, __state); } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool) })] internal static class AddIntoCell { private static void Prefix(Inventory __instance, ItemData item, int amount, int x, int y, out StackSnap __state) { __state = null; List<Run> list = StackHooks.Worn(item); if (list != null) { ItemData itemAt = __instance.GetItemAt(x, y); __state = new StackSnap { N = item.m_stack, Q = list, Split = (amount < item.m_stack), Cell = itemAt, CellStack = (itemAt?.m_stack ?? 0), CellQ = ((itemAt == null) ? null : Wear.Get(itemAt)) }; } } private static void Postfix(Inventory __instance, ItemData item, int x, int y, StackSnap __state) { if (__state == null) { return; } ItemData val = __state.Cell; int num; List<Run> q; if (val != null) { if (val == item) { return; } num = val.m_stack - __state.CellStack; q = __state.CellQ; } else { val = __instance.GetItemAt(x, y); if (val == null || val == item) { return; } num = val.m_stack; q = new List<Run>(); } if (num > 0) { List<Run> tail = (__state.Split ? WearMath.TakeShare(__state.Q, num) : WearMath.TakeFront(__state.Q, num)); WearMath.Append(q, tail); Wear.Set(val, q); Wear.Set(item, __state.Q); } } } [HarmonyPatch(typeof(Humanoid), "DropItem", new Type[] { typeof(Inventory), typeof(ItemData), typeof(int) })] internal static class DropFromInventory { private static void Prefix(ItemData item, int amount) { StackHooks.DropPending = null; if (amount > 0) { List<Run> list = StackHooks.Worn(item); if (list != null) { StackHooks.DropPending = new StackHooks.Pending { Item = item, N = item.m_stack, Q = list }; } } } private static void Finalizer() { StackHooks.DropPending = null; } } [HarmonyPatch(typeof(ItemDrop), "DropItem")] internal static class DropAsItem { private static void Postfix(ItemData item, ItemDrop __result) { if (!((Object)(object)__result == (Object)null) && Wear.Has(item)) { ItemData itemData = __result.m_itemData; StackHooks.Pending dropPending = StackHooks.DropPending; if (dropPending != null && dropPending.Item == item) { List<Run> q = WearMath.TakeShare(dropPending.Q, itemData.m_stack); Wear.Set(itemData, q); Wear.Set(item, dropPending.Q); StackHooks.DropPending = null; } else { Wear.Set(itemData, Wear.Get(itemData)); } __result.Save(); } } } [HarmonyPatch(typeof(ItemDrop), "AutoStackItems")] internal static class AutoStack { internal sealed class State { internal List<Run> Before; internal int Stack; internal List<KeyValuePair<ItemDrop, List<Run>>> Worn; } private static readonly List<Collider> hidden = new List<Collider>(); private static int itemMask; private static bool Prefix(ItemDrop __instance, out State __state) { //IL_0013: 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) __state = null; if (Stuck.IsStuck(__instance)) { return false; } Stuck.HideNear(((Component)__instance).transform.position, 5f, hidden); if (!Wear.Tracks(__instance.m_itemData)) { return true; } if (itemMask == 0) { itemMask = LayerMask.GetMask(new string[1] { "item" }); } Collider[] array = Physics.OverlapSphere(((Component)__instance).transform.position, 4f, itemMask); foreach (Collider obj in array) { Rigidbody attachedRigidbody = obj.attachedRigidbody; if (!Object.op_Implicit((Object)(object)attachedRigidbody)) { continue; } ItemDrop other = ((Component)attachedRigidbody).GetComponent<ItemDrop>(); if ((Object)(object)other == (Object)null || (Object)(object)other == (Object)(object)__instance || other.m_itemData.m_shared.m_name != __instance.m_itemData.m_shared.m_name || (__state != null && __state.Worn.Exists((KeyValuePair<ItemDrop, List<Run>> p) => (Object)(object)p.Key == (Object)(object)other))) { continue; } List<Run> list = StackHooks.Worn(other.m_itemData); if (list != null) { if (__state == null) { __state = new State { Before = Wear.Get(__instance.m_itemData), Stack = __instance.m_itemData.m_stack, Worn = new List<KeyValuePair<ItemDrop, List<Run>>>() }; } __state.Worn.Add(new KeyValuePair<ItemDrop, List<Run>>(other, list)); } } return true; } private static void Postfix(ItemDrop __instance, State __state) { if (__state == null) { return; } List<Run> before = __state.Before; bool flag = false; foreach (KeyValuePair<ItemDrop, List<Run>> item in __state.Worn) { ZNetView val = (((Object)(object)item.Key == (Object)null) ? null : item.Key.m_nview); if ((Object)(object)val == (Object)null || !val.IsValid()) { WearMath.Append(before, item.Value); flag = true; } } if (flag) { int num = __instance.m_itemData.m_stack - WearMath.Count(before); if (num > 0) { WearMath.Append(before, WearMath.Fresh(num)); } Wear.Set(__instance.m_itemData, before); __instance.Save(); } } private static void Finalizer() { foreach (Collider item in hidden) { if (Object.op_Implicit((Object)(object)item)) { item.enabled = true; } } hidden.Clear(); } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] internal static class WearTooltip { private static void Postfix(ItemData item, ref string __result) { if (Wear.Tracks(item)) { string text = Wear.Text(item); if (text != null) { __result = __result + "\n\n" + text; } } } } [HarmonyPatch(typeof(ItemDrop), "GetHoverText")] internal static class WearHover { private static void Postfix(ItemDrop __instance, ref string __result) { if (Wear.Tracks(__instance.m_itemData)) { string text = Wear.Text(__instance.m_itemData); if (text != null) { __result = __result + "\n" + text; } } } } internal static class Stuck { internal static readonly int KeyLook = StringExtensionMethods.GetStableHashCode("chistix.lodged.look"); internal static readonly int KeyBorn = StringExtensionMethods.GetStableHashCode("chistix.lodged.born"); internal static readonly int KeyAge = StringExtensionMethods.GetStableHashCode("chistix.lodged.age"); private static readonly List<StuckItem> all = new List<StuckItem>(); private static readonly Dictionary<int, List<StuckItem>> zones = new Dictionary<int, List<StuckItem>>(); private static readonly List<long> born = new List<long>(); private static int cursor; private static int supportMask; private static int itemLayer = -1; private static float nextLimits; internal static int SupportMask { get { if (supportMask == 0) { return supportMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain" }); } return supportMask; } } internal static int ItemLayer { get { if (itemLayer < 0) { return itemLayer = LayerMask.NameToLayer("item"); } return itemLayer; } } internal static int Count => all.Count; internal static bool Create(ItemData item, int look, Vector3 point, Quaternion rotation) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) ItemDrop val = ItemDrop.DropItem(item, 1, point, rotation); if ((Object)(object)val == (Object)null) { return false; } try { ZNetView nview = val.m_nview; if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return true; } ZDO zDO = nview.GetZDO(); zDO.Set(KeyLook, (look == 0) ? 1 : look, false); zDO.Set(KeyBorn, ZNet.instance.GetTime().Ticks); zDO.Set(KeyAge, 0f); Attach(val); } catch (Exception ex) { Plugin.Log.LogWarning((object)("stuck item: " + ex.Message)); } return true; } internal static void Loose(ItemData item, Vector3 point, Quaternion rotation) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) ItemDrop.DropItem(item, 1, point, rotation); } internal static void Attach(ItemDrop drop) { (((Component)drop).GetComponent<StuckItem>() ?? ((Component)drop).gameObject.AddComponent<StuckItem>()).Init(); } internal static bool IsStuck(ItemDrop drop) { if ((Object)(object)drop != (Object)null) { return (Object)(object)((Component)drop).GetComponent<StuckItem>() != (Object)null; } return false; } internal static void Register(StuckItem s) { if (s.Slot < 0) { s.Slot = all.Count; all.Add(s); } } internal static void Unregister(StuckItem s) { int slot = s.Slot; if (slot >= 0 && slot < all.Count && !((Object)(object)all[slot] != (Object)(object)s)) { int index = all.Count - 1; all[slot] = all[index]; all[slot].Slot = slot; all.RemoveAt(index); s.Slot = -1; } } internal static void HideNear(Vector3 point, float radius, List<Collider> hidden) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) float num = radius * radius; foreach (StuckItem item in all) { Collider hover = item.Hover; if ((Object)(object)hover != (Object)null && hover.enabled) { Vector3 val = ((Component)item).transform.position - point; if (((Vector3)(ref val)).sqrMagnitude < num) { hover.enabled = false; hidden.Add(hover); } } } } internal static void Tick() { if (all.Count == 0) { return; } float time = Time.time; int num = Mathf.Min(all.Count, 6); for (int i = 0; i < num; i++) { if (all.Count <= 0) { break; } if (cursor >= all.Count) { cursor = 0; } StuckItem stuckItem = all[cursor++]; if (!((Object)(object)stuckItem == (Object)null)) { try { stuckItem.Visit(time); } catch (Exception ex) { Plugin.Log.LogWarning((object)("stuck item: " + ex.Message)); } } } if (time >= nextLimits) { nextLimits = time + 5f; Limits(); } } private static void Limits() { foreach (List<StuckItem> value3 in zones.Values) { value3.Clear(); } foreach (StuckItem item in all) { if (!((Object)(object)item == (Object)null) && item.Valid) { if (!zones.TryGetValue(item.Zone, out var value)) { value = (zones[item.Zone] = new List<StuckItem>()); } value.Add(item); } } int value2 = Plugin.PerArea.Value; foreach (List<StuckItem> value4 in zones.Values) { if (value4.Count <= value2) { continue; } born.Clear(); foreach (StuckItem item2 in value4) { born.Add(item2.Born); } bool[] array = Rules.OverLimit(born, value2); for (int i = 0; i < value4.Count; i++) { if (array[i] && value4[i].IsOwner) { value4[i].Remove(); } } } } } internal sealed class StuckItem : MonoBehaviour { internal int Slot = -1; internal int Zone; internal long Born; internal Collider Hover; private ItemDrop drop; private ZNetView view; private Rigidbody body; private ZSyncTransform sync; private Floating floating; private GameObject look; private Look shape; private bool floatingWas; private bool autoDestroyWas; private readonly List<Renderer> renderers = new List<Renderer>(); private readonly List<Collider> colliders = new List<Collider>(); private float age; private float lastVisit; private float nextWrite; private float nextSupport; private uint seen; private bool wasOwner; private bool frozen; internal bool Valid { get { if ((Object)(object)view != (Object)null) { return view.IsValid(); } return false; } } internal bool IsOwner { get { if (Valid) { return view.IsOwner(); } return false; } } private bool IsAmmo { get { if ((Object)(object)drop != (Object)null) { return Wear.Tracks(drop.m_itemData); } return false; } } internal void Init() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) drop = ((Component)this).GetComponent<ItemDrop>(); view = ((Component)this).GetComponent<ZNetView>(); body = ((Component)this).GetComponent<Rigidbody>(); sync = ((Component)this).GetComponent<ZSyncTransform>(); floating = ((Component)this).GetComponent<Floating>(); if (Valid) { ZDO zDO = view.GetZDO(); Born = zDO.GetLong(Stuck.KeyBorn, 0L); age = zDO.GetFloat(Stuck.KeyAge, 0f); seen = zDO.DataRevision; wasOwner = zDO.IsOwner(); Vector2s zone = ZoneSystem.GetZone(((Component)this).transform.position); Zone = Rules.ZoneKey(zone.x, zone.y); lastVisit = Time.time; nextWrite = lastVisit + 30f; nextSupport = lastVisit + 2f + Random.value * 2f; if (!frozen) { Freeze(zDO.GetInt(Stuck.KeyLook, 0)); } Stuck.Register(this); } } private void Freeze(int lookHash) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: 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_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) frozen = true; if (Object.op_Implicit((Object)(object)body)) { body.linearVelocity = Vector3.zero; body.angularVelocity = Vector3.zero; body.isKinematic = true; } if (Object.op_Implicit((Object)(object)sync)) { sync.m_isKinematicBody = true; } if (Object.op_Implicit((Object)(object)floating)) { floatingWas = ((Behaviour)floating).enabled; ((Behaviour)floating).enabled = false; } if (Object.op_Implicit((Object)(object)drop)) { drop.m_autoPickup = false; autoDestroyWas = drop.m_autoDestroy; drop.m_autoDestroy = false; } shape = Visuals.Get(lookHash); if (shape == null) { return; } Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (val.enabled) { val.enabled = false; renderers.Add(val); } } Collider[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Collider>(true); foreach (Collider val2 in componentsInChildren2) { if (val2.enabled) { val2.enabled = false; colliders.Add(val2); } } look = Visuals.Place(shape, ((Component)this).transform); Vector3 lossyScale = ((Component)this).transform.lossyScale; Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor((lossyScale.x != 0f) ? (1f / lossyScale.x) : 1f, (lossyScale.y != 0f) ? (1f / lossyScale.y) : 1f, (lossyScale.z != 0f) ? (1f / lossyScale.z) : 1f); float num = Visuals.Depth(shape); look.transform.localPosition = new Vector3(0f, 0f, num * val3.z); look.transform.localRotation = Quaternion.identity; look.transform.localScale = val3; GameObject val4 = new GameObject("lodged_hover") { layer = Stuck.ItemLayer }; val4.transform.SetParent(look.transform, false); CapsuleCollider val5 = val4.AddComponent<CapsuleCollider>(); float num2 = Mathf.Max(0.1f, shape.Back - num); val5.direction = 2; val5.center = new Vector3(0f, 0f, 0f - num - num2 * 0.5f); val5.height = num2 + 0.1f; val5.radius = Mathf.Clamp(shape.Width * 0.5f, 0.06f, 0.15f); Hover = (Collider)(object)val5; } private void Unfreeze() { frozen = false; if (Object.op_Implicit((Object)(object)look)) { Object.Destroy((Object)(object)look); } look = null; Hover = null; foreach (Renderer renderer in renderers) { if (Object.op_Implicit((Object)(object)renderer)) { renderer.enabled = true; } } renderers.Clear(); foreach (Collider collider in colliders) { if (Object.op_Implicit((Object)(object)collider)) { collider.enabled = true; } } colliders.Clear(); if (Object.op_Implicit((Object)(object)sync)) { sync.m_isKinematicBody = false; } if (Object.op_Implicit((Object)(object)body)) { body.isKinematic = false; } if (Object.op_Implicit((Object)(object)floating)) { ((Behaviour)floating).enabled = floatingWas; } if (Object.op_Implicit((Object)(object)drop)) { drop.m_autoPickup = true; drop.m_autoDestroy = autoDestroyWas; } Stuck.Unregister(this); Object.Destroy((Object)(object)this); } internal void Remove() { if (IsOwner) { if (IsAmmo) { view.Destroy(); } else { Release(); } } } private void Release() { if (IsOwner) { view.GetZDO().Set(Stuck.KeyLook, 0, false); Unfreeze(); } } private bool Supported() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)this).transform.position; Vector3 forward = ((Component)this).transform.forward; if (Physics.CheckSphere(position, 0.1f, Stuck.SupportMask, (QueryTriggerInteraction)1)) { return true; } float num = ((shape != null) ? Mathf.Max(0.3f, shape.Back) : 0.8f); return Physics.Raycast(position - forward * num, forward, num + 0.3f, Stuck.SupportMask, (QueryTriggerInteraction)1); } internal void Visit(float now) { if (!Valid) { return; } ZDO zDO = view.GetZDO(); if (!zDO.IsOwner()) { wasOwner = false; lastVisit = now; if (zDO.DataRevision != seen) { seen = zDO.DataRevision; if (zDO.GetInt(Stuck.KeyLook, 0) == 0) { Unfreeze(); } } return; } if (!wasOwner) { wasOwner = true; age = Mathf.Max(age, zDO.GetFloat(Stuck.KeyAge, 0f)); } age += Mathf.Min(now - lastVisit, 10f); lastVisit = now; if (now >= nextWrite) { nextWrite = now + 30f; zDO.Set(Stuck.KeyAge, age); } double worldSeconds = ((Born == 0L) ? 0.0 : (ZNet.instance.GetTime() - new DateTime(Born)).TotalSeconds); if (Rules.Expired(age, worldSeconds, Plugin.LifetimeSeconds)) { Remove(); return; } if (now >= nextSupport) { nextSupport = now + 2.5f + Random.value; if (!Supported()) { Release(); } } seen = zDO.DataRevision; } private void OnDestroy() { Stuck.Unregister(this); } } [HarmonyPatch(typeof(ItemDrop), "Awake")] internal static class StuckOnLoad { private static void Postfix(ItemDrop __instance) { ZNetView nview = __instance.m_nview; if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.GetZDO().GetInt(Stuck.KeyLook, 0) != 0) { Stuck.Attach(__instance); } } } internal sealed class Look { internal GameObject Template; internal float Back; internal float Front; internal float Width; } internal static class Visuals { private static readonly Dictionary<int, Look> looks = new Dictionary<int, Look>(); private static GameObject shelf; internal const string LookName = "lodged_look"; internal static Look Get(int prefabHash) { if (prefabHash == 0) { return null; } if (looks.TryGetValue(prefabHash, out var value)) { return value; } value = Build(prefabHash); looks[prefabHash] = value; return value; } private static bool ActiveIn(Transform t, Transform root) { while ((Object)(object)t != (Object)null) { if (!((Component)t).gameObject.activeSelf) { return false; } if ((Object)(object)t == (Object)(object)root) { break; } t = t.parent; } return true; } private static Look Build(int prefabHash) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0182: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(prefabHash) : null); if ((Object)(object)val == (Object)null) { return null; } Projectile component = val.GetComponent<Projectile>(); GameObject val2 = (Object.op_Implicit((Object)(object)component) ? component.m_hideOnHit : null); if ((Object)(object)shelf == (Object)null) { shelf = new GameObject("Lodged looks"); shelf.SetActive(false); Object.DontDestroyOnLoad((Object)(object)shelf); } GameObject val3 = new GameObject("lodged_" + ((Object)val).name); val3.transform.SetParent(shelf.transform, false); Matrix4x4 worldToLocalMatrix = val.transform.worldToLocalMatrix; bool flag = false; Bounds val4 = default(Bounds); MeshRenderer[] componentsInChildren = val.GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val5 in componentsInChildren) { if (!((Renderer)val5).enabled || !ActiveIn(((Component)val5).transform, val.transform) || ((Object)(object)val2 != (Object)null && ((Component)val5).transform.IsChildOf(val2.transform))) { continue; } MeshFilter component2 = ((Component)val5).GetComponent<MeshFilter>(); if ((Object)(object)component2 == (Object)null || (Object)(object)component2.sharedMesh == (Object)null) { continue; } Matrix4x4 val6 = worldToLocalMatrix * ((Component)val5).transform.localToWorldMatrix; GameObject val7 = new GameObject(((Object)val5).name); val7.transform.SetParent(val3.transform, false); val7.transform.localPosition = Vector4.op_Implicit(((Matrix4x4)(ref val6)).GetColumn(3)); val7.transform.localRotation = ((Matrix4x4)(ref val6)).rotation; val7.transform.localScale = ((Matrix4x4)(ref val6)).lossyScale; val7.AddComponent<MeshFilter>().sharedMesh = component2.sharedMesh; MeshRenderer obj = val7.AddComponent<MeshRenderer>(); ((Renderer)obj).sharedMaterials = ((Renderer)val5).sharedMaterials; ((Renderer)obj).shadowCastingMode = ((Renderer)val5).shadowCastingMode; ((Renderer)obj).receiveShadows = ((Renderer)val5).receiveShadows; Bounds bounds = component2.sharedMesh.bounds; for (int j = 0; j < 8; j++) { Vector3 val8 = ((Matrix4x4)(ref val6)).MultiplyPoint3x4(new Vector3(((j & 1) == 0) ? ((Bounds)(ref bounds)).min.x : ((Bounds)(ref bounds)).max.x, ((j & 2) == 0) ? ((Bounds)(ref bounds)).min.y : ((Bounds)(ref bounds)).max.y, ((j & 4) == 0) ? ((Bounds)(ref bounds)).min.z : ((Bounds)(ref bounds)).max.z)); if (!flag) { ((Bounds)(ref val4))..ctor(val8, Vector3.zero); flag = true; } else { ((Bounds)(ref val4)).Encapsulate(val8); } } } if (!flag) { Object.Destroy((Object)(object)val3); return null; } return new Look { Template = val3, Back = 0f - ((Bounds)(ref val4)).min.z, Front = ((Bounds)(ref val4)).max.z, Width = Mathf.Max(((Bounds)(ref val4)).size.x, ((Bounds)(ref val4)).size.y) }; } internal static float Depth(Look look) { if (look == null) { return 0f; } float num = Mathf.Max(0f, look.Front); float num2 = look.Back + num; return Mathf.Max(0f, Mathf.Clamp(num2 * 0.15f, 0.06f, 0.35f) - num); } internal static GameObject Place(Look look, Transform parent) { if (look == null) { return null; } GameObject obj = Object.Instantiate<GameObject>(look.Template, parent, false); ((Object)obj).name = "lodged_look"; obj.SetActive(true); return obj; } } internal static class Wear { internal const string Key = "chistix.lodged.wear"; internal static bool Tracks(ItemData item) { //IL_0016: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 if (item?.m_shared == null) { return false; } ItemType itemType = item.m_shared.m_itemType; if ((int)itemType == 9 || (int)itemType == 23) { return item.m_shared.m_maxStackSize > 1; } return false; } internal static bool Has(ItemData item) { if (item?.m_customData != null) { return item.m_customData.ContainsKey("chistix.lodged.wear"); } return false; } internal static List<Run> Get(ItemData item) { string value = null; if (item?.m_customData != null) { item.m_customData.TryGetValue("chistix.lodged.wear", out value); } return WearMath.Queue(value, item?.m_stack ?? 0, Plugin.Life); } internal static void Set(ItemData item, List<Run> q) { if (item?.m_customData != null) { if (q == null || !WearMath.AnyWorn(q)) { item.m_customData.Remove("chistix.lodged.wear"); } else { item.m_customData["chistix.lodged.wear"] = WearMath.Format(q); } } } internal static void SetSingle(ItemData item, int hits) { Set(item, new List<Run> { new Run(hits, 1) }); } private static bool Russian() { try { return Localization.instance != null && Localization.instance.GetSelectedLanguage() == "Russian"; } catch { return false; } } private static string Noun(ItemData item, int n, bool ru) { string text = (item.m_shared.m_ammoType ?? "").ToLowerInvariant(); if (text.Contains("bolt")) { if (!ru) { if (n != 1) { return "bolts"; } return "bolt"; } return Rules.Plural(n, "болт", "болта", "болтов"); } if (text.Contains("arrow")) { if (!ru) { if (n != 1) { return "arrows"; } return "arrow"; } return Rules.Plural(n, "стрела", "стрелы", "стрел"); } if (!ru) { return "pcs"; } return "шт."; } internal static string Text(ItemData item) { if (!Has(item)) { return null; } List<Run> q = Get(item); if (!WearMath.AnyWorn(q)) { return null; } int life = Plugin.Life; bool flag = Russian(); List<KeyValuePair<int, int>> list = WearMath.Rows(q, life); if (item.m_stack <= 1 && list.Count == 1) { return (flag ? "Прочность: " : "Durability: ") + list[0].Value + "/" + life; } StringBuilder stringBuilder = new StringBuilder(flag ? "Прочность в пачке:" : "Durability in stack:"); foreach (KeyValuePair<int, int> item2 in list) { stringBuilder.Append('\n').Append(item2.Key).Append(' ') .Append(Noun(item, item2.Key, flag)) .Append(' ') .Append(item2.Value) .Append('/') .Append(life); } int num = WearMath.Next(q); if (num >= 0) { stringBuilder.Append('\n').Append(flag ? "Следующий выстрел: " : "Next shot: ").Append(life - num) .Append('/') .Append(life); } return stringBuilder.ToString(); } } public struct Run { public int Wear; public int Count; public Run(int wear, int count) { Wear = wear; Count = count; } } public static class WearMath { public static List<Run> Fresh(int n) { List<Run> list = new List<Run>(); if (n > 0) { list.Add(new Run(0, n)); } return list; } public static int Count(List<Run> q) { int num = 0; foreach (Run item in q) { num += item.Count; } return num; } public static bool AnyWorn(List<Run> q) { foreach (Run item in q) { if (item.Wear > 0 && item.Count > 0) { return true; } } return false; } public static long HitsLeft(List<Run> q, int life) { long num = 0L; foreach (Run item in q) { num += (long)item.Count * (long)(life - item.Wear); } return num; } public static bool Breaks(int wear, int life) { return wear + 1 >= life; } public static List<Run> Tidy(List<Run> q) { List<Run> list = new List<Run>(q.Count); foreach (Run item in q) { if (item.Count > 0) { if (list.Count > 0 && list[list.Count - 1].Wear == item.Wear) { list[list.Count - 1] = new Run(item.Wear, list[list.Count - 1].Count + item.Count); } else { list.Add(item); } } } q.Clear(); q.AddRange(list); return q; } public static int Next(List<Run> q) { Tidy(q); if (q.Count != 0) { return q[0].Wear; } return -1; } public static int PopFront(List<Run> q) { Tidy(q); if (q.Count == 0) { return -1; } Run run = q[0]; if (run.Count == 1) { q.RemoveAt(0); } else { q[0] = new Run(run.Wear, run.Count - 1); } return run.Wear; } public static void Append(List<Run> q, List<Run> tail) { q.AddRange(tail); Tidy(q); } public static List<Run> TakeFront(List<Run> q, int k) { Tidy(q); List<Run> list = new List<Run>(); while (k > 0 && q.Count > 0) { Run run = q[0]; int num = Math.Min(k, run.Count); list.Add(new Run(run.Wear, num)); k -= num; if (num == run.Count) { q.RemoveAt(0); } else { q[0] = new Run(run.Wear, run.Count - num); } } return list; } public static List<Run> TakeShare(List<Run> q, int k) { Tidy(q); int num = Count(q); if (k <= 0 || num <= 0) { return new List<Run>(); } if (k >= num) { List<Run> result = new List<Run>(q); q.Clear(); return result; } int[] array = new int[q.Count]; long[] array2 = new long[q.Count]; int i = 0; for (int j = 0; j < q.Count; j++) { long num2 = (long)q[j].Count * (long)k; array[j] = (int)(num2 / num); array2[j] = num2 % num; i += array[j]; } for (; i < k; i++) { int num3 = -1; for (int l = 0; l < q.Count; l++) { if (array2[l] > 0 && (num3 < 0 || array2[l] > array2[num3])) { num3 = l; } } if (num3 < 0) { break; } array[num3]++; array2[num3] = 0L; } List<Run> list = new List<Run>(); for (int m = 0; m < q.Count; m++) { list.Add(new Run(q[m].Wear, array[m])); q[m] = new Run(q[m].Wear, q[m].Count - array[m]); } Tidy(q); return Tidy(list); } public static List<Run>[] Spread(List<Run> source, int[] grown) { List<Run>[] array = new List<Run>[grown.Length]; for (int i = 0; i < grown.Length; i++) { array[i] = ((grown[i] > 0) ? TakeFront(source, grown[i]) : new List<Run>()); } return array; } public static string Format(List<Run> q) { Tidy(q); StringBuilder stringBuilder = new StringBuilder(); foreach (Run item in q) { if (stringBuilder.Length > 0) { stringBuilder.Append(','); } stringBuilder.Append(item.Wear).Append(':').Append(item.Count); } return stringBuilder.Append('/').Append(Count(q)).ToString(); } public static List<Run> Queue(string text, int stack, int life) { List<Run> list = new List<Run>(); int result = -1; if (!string.IsNullOrEmpty(text)) { int num = text.LastIndexOf('/'); string obj = ((num >= 0) ? text.Substring(0, num) : text); if (num >= 0 && !int.TryParse(text.Substring(num + 1), out result)) { result = -1; } string[] array = obj.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { int num2 = text2.IndexOf(':'); if (num2 >= 0 && int.TryParse(text2.Substring(0, num2), out var result2) && int.TryParse(text2.Substring(num2 + 1), out var result3) && result2 >= 0 && result3 > 0) { list.Add(new Run(Math.Min(result2, Math.Max(0, life - 1)), result3)); } } } Tidy(list); int num3 = Count(list); if (stack <= 0) { return new List<Run>(); } if (stack < num3) { return TakeShare(list, stack); } if (stack > num3) { Append(list, Fresh(stack - num3)); } return list; } public static List<KeyValuePair<int, int>> Rows(List<Run> q, int life) { SortedDictionary<int, int> sortedDictionary = new SortedDictionary<int, int>(); foreach (Run item in q) { if (item.Count > 0) { int key = life - item.Wear; sortedDictionary.TryGetValue(key, out var value); sortedDictionary[key] = value + item.Count; } } List<KeyValuePair<int, int>> list = new List<KeyValuePair<int, int>>(); foreach (KeyValuePair<int, int> item2 in sortedDictionary) { list.Add(new KeyValuePair<int, int>(item2.Value, item2.Key)); } return list; } } }