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 Quads Quiver v0.2.3
plugins/Quiver.dll
Decompiled 15 hours agousing System; using System.Collections; 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.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DHack.Shared; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI (Claude Code).")] [assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [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 Quiver { [BepInPlugin("com.quad.quiver", "Quiver", "0.2.3")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.quad.quiver"; public const string OldGuid = "com.dhack.quiver"; public const string Name = "Quiver"; public const string Version = "0.2.3"; internal static ManualLogSource Log; internal static ServerSettings Synced; internal static ConfigEntry<bool> Recover; internal static ConfigEntry<bool> Bolts; internal static ConfigEntry<bool> FireBurns; internal static ConfigEntry<bool> ShowQuiver; internal static ConfigEntry<bool> Debug; internal static ConfigEntry<float> GroundChance; internal static ConfigEntry<float> CreatureChance; internal static ConfigEntry<float> Back; internal static ConfigEntry<float> Side; internal static ConfigEntry<float> Height; internal static ConfigEntry<float> TiltSide; internal static ConfigEntry<float> TiltBack; private Harmony _harmony; private void Awake() { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Expected O, but got Unknown //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Expected O, but got Unknown //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Expected O, but got Unknown //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Expected O, but got Unknown //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Expected O, but got Unknown Migration.FromOldGuid((BaseUnityPlugin)(object)this, "com.dhack.quiver"); Log = ((BaseUnityPlugin)this).Logger; Synced = new ServerSettings("com.quad.quiver", ((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); Recover = Synced.Add<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Arrows", "PickUpArrows", true, "Arrows you shoot that hit something land on the ground as arrows you can pick up again. In multiplayer the server's value applies.")); GroundChance = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("Arrows", "ChanceOnGround", 1f, new ConfigDescription("The chance an arrow that hit the ground, a tree, a wall or the like is kept. 1 keeps every one. In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()))); CreatureChance = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("Arrows", "ChanceOnCreature", 0.75f, new ConfigDescription("The chance an arrow that hit a creature is kept: it drops with that creature's loot when it dies. 0.75 keeps three in four. In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()))); Bolts = Synced.Add<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Arrows", "IncludeBolts", true, "Crossbow bolts can be picked up too. In multiplayer the server's value applies.")); FireBurns = Synced.Add<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Arrows", "FireArrowsBurnUp", true, "Fire arrows are always used up. In multiplayer the server's value applies.")); Debug = ((BaseUnityPlugin)this).Config.Bind<bool>("Arrows", "LogHits", false, "Write what each arrow hit did (kept, broke, why not) to the BepInEx log. For finding out why an arrow did not come back."); ShowQuiver = ((BaseUnityPlugin)this).Config.Bind<bool>("Quiver", "Show", true, "A quiver on your back while you have arrows (or bolts) equipped."); Back = ((BaseUnityPlugin)this).Config.Bind<float>("Quiver", "Back", 0.2f, new ConfigDescription("How far behind your spine the quiver hangs (metres).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 0.4f), Array.Empty<object>())); Side = ((BaseUnityPlugin)this).Config.Bind<float>("Quiver", "Side", 0.1f, new ConfigDescription("How far to your right it hangs (negative: left).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.3f, 0.3f), Array.Empty<object>())); Height = ((BaseUnityPlugin)this).Config.Bind<float>("Quiver", "Height", -0.03f, new ConfigDescription("How far up it hangs (negative: lower).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.4f, 0.4f), Array.Empty<object>())); TiltSide = ((BaseUnityPlugin)this).Config.Bind<float>("Quiver", "TiltSide", 22f, new ConfigDescription("How far the top leans to your right (degrees).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-45f, 45f), Array.Empty<object>())); TiltBack = ((BaseUnityPlugin)this).Config.Bind<float>("Quiver", "TiltBack", 8f, new ConfigDescription("How far the top leans backwards (degrees).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-45f, 45f), Array.Empty<object>())); _harmony = new Harmony("com.quad.quiver"); _harmony.PatchAll(typeof(Plugin).Assembly); } private void Update() { Synced?.Update(); Stuck.Tick(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && !BetterArchery.QuiverOn && (Object)(object)((Component)localPlayer).GetComponent<QuiverView>() == (Object)null) { ((Component)localPlayer).gameObject.AddComponent<QuiverView>(); } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } Stuck.Clear(); QuiverView[] array = Object.FindObjectsOfType<QuiverView>(); foreach (QuiverView quiverView in array) { quiverView.Clear(); Object.Destroy((Object)(object)quiverView); } Synced?.Dispose(); } } internal static class BetterArchery { private static bool _checked; private static bool _arrows; private static bool _quiver; public static bool ArrowsOn { get { Check(); return _arrows; } } public static bool QuiverOn { get { Check(); return _quiver; } } private static void Check() { if (_checked || (Object)(object)Player.m_localPlayer == (Object)null) { return; } _checked = true; if (Chainloader.PluginInfos.TryGetValue("ishid4.mods.betterarchery", out var value)) { _arrows = Setting(value, "Retrievable Arrows", "Enable Retrievable Arrows"); _quiver = Setting(value, "Quiver", "Enable Quiver"); if (_arrows) { Plugin.Log.LogInfo((object)"BetterArchery's retrievable arrows are on: arrows are picked up its way, and this mod's arrow recovery is off"); } if (_quiver) { Plugin.Log.LogInfo((object)"BetterArchery's quiver is on: this mod's quiver is not drawn"); } } } private static bool Setting(PluginInfo info, string section, string key) { ConfigEntry<bool> val = null; if (!((Object)(object)info.Instance == (Object)null) && info.Instance.Config.TryGetEntry<bool>(section, key, ref val)) { return val.Value; } return true; } } internal class QuiverView : MonoBehaviour { private static readonly FieldRef<Humanoid, ItemData> AmmoRef = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_ammoItem"); private Humanoid _body; private GameObject _root; private string _shown = ""; private float _next; private static Material _leather; private static Material _dark; private const float TubeHalf = 0.25f; private const float TubeRadius = 0.06f; private const float Sticks = 0.17f; private const float MaxArrow = 0.6f; private void Awake() { _body = ((Component)this).GetComponent<Humanoid>(); } private void Update() { if (!(Time.time < _next)) { _next = Time.time + 0.3f; Refresh(); } } public void Clear() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } _root = null; _shown = ""; } private void Refresh() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Invalid comparison between Unknown and I4 ItemData val = ((Plugin.ShowQuiver.Value && (Object)(object)_body != (Object)null && !((Character)_body).IsDead()) ? AmmoRef.Invoke(_body) : null); if (val == null || (int)val.m_shared.m_itemType != 9 || (Object)(object)val.m_dropPrefab == (Object)null) { Clear(); return; } int num = _body.GetInventory().CountItems(val.m_shared.m_name, -1, true); int num2 = Mathf.Clamp(1 + num / 15, 1, 7); string text = $"{((Object)val.m_dropPrefab).name}|{num2}|{Plugin.Back.Value}|{Plugin.Side.Value}|{Plugin.Height.Value}|{Plugin.TiltSide.Value}|{Plugin.TiltBack.Value}"; if (!(text == _shown) || !((Object)(object)_root != (Object)null)) { Clear(); _shown = text; Build(val, num2); } } private void Build(ItemData ammo, int arrows) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_005e: 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_006a: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //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_00b8: 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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: 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_0148: Unknown result type (might be due to invalid IL or missing references) //IL_015d: 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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: 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_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) Transform val = FindBone(((Component)this).transform, "Spine2") ?? FindBone(((Component)this).transform, "Spine1") ?? FindBone(((Component)this).transform, "Spine"); if (!((Object)(object)val == (Object)null)) { MakeMaterials(); _root = new GameObject("Quiver"); Vector3 up = ((Component)this).transform.up; Vector3 right = ((Component)this).transform.right; Vector3 val2 = -((Component)this).transform.forward; Vector3 val3 = up + right * Mathf.Tan(Plugin.TiltSide.Value * ((float)Math.PI / 180f)) + val2 * Mathf.Tan(Plugin.TiltBack.Value * ((float)Math.PI / 180f)); Vector3 normalized = ((Vector3)(ref val3)).normalized; _root.transform.position = val.position + val2 * Plugin.Back.Value + right * Plugin.Side.Value + up * Plugin.Height.Value; _root.transform.rotation = Quaternion.FromToRotation(Vector3.up, normalized) * Quaternion.LookRotation(Vector3.forward, Vector3.up); _root.transform.localScale = Vector3.one; Part((PrimitiveType)2, "Tube", new Vector3(0.12f, 0.25f, 0.12f), Vector3.zero, _leather); Part((PrimitiveType)2, "Rim", new Vector3(0.13499999f, 0.012f, 0.13499999f), Vector3.up * 0.25f, _dark); Part((PrimitiveType)2, "Base", new Vector3(0.102f, 0.02f, 0.102f), Vector3.down * 0.25f, _dark); Part((PrimitiveType)2, "Band", new Vector3(0.12900001f, 0.014f, 0.12900001f), Vector3.up * 0.1125f, _dark); Random random = new Random(((Object)ammo.m_dropPrefab).name.GetHashCode()); Vector3 at = default(Vector3); for (int i = 0; i < arrows; i++) { float num = ((i == 0) ? 0f : 0.032f); float num2 = (float)i * 137.5f * ((float)Math.PI / 180f); ((Vector3)(ref at))..ctor(Mathf.Cos(num2) * num, 0f, Mathf.Sin(num2) * num); Quaternion lean = Quaternion.Euler((float)(random.NextDouble() * 10.0 - 5.0), 0f, (float)(random.NextDouble() * 10.0 - 5.0)); Arrow(ammo.m_dropPrefab, at, lean); } _root.transform.SetParent(val, true); Collider[] componentsInChildren = _root.GetComponentsInChildren<Collider>(); foreach (Collider val4 in componentsInChildren) { Object.Destroy((Object)(object)val4); } } } private void Part(PrimitiveType shape, string name, Vector3 scale, Vector3 at, Material material) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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) GameObject val = GameObject.CreatePrimitive(shape); ((Object)val).name = name; val.transform.SetParent(_root.transform, false); val.transform.localPosition = at; val.transform.localScale = scale; val.GetComponent<Renderer>().sharedMaterial = material; } private void Arrow(GameObject prefab, Vector3 at, Quaternion lean) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_029e: 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) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: 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_00c8: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: 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_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Arrow"); val.transform.SetParent(_root.transform, false); float num = float.MaxValue; float num2 = float.MinValue; LODGroup componentInChildren = prefab.GetComponentInChildren<LODGroup>(); Renderer[] array = ((componentInChildren != null && componentInChildren.GetLODs().Length != 0) ? componentInChildren.GetLODs()[0].renderers : prefab.GetComponentsInChildren<Renderer>()); Renderer[] array2 = array; foreach (Renderer val2 in array2) { MeshFilter val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<MeshFilter>() : null); if ((Object)(object)val3 == (Object)null || (Object)(object)val3.sharedMesh == (Object)null) { continue; } MeshRenderer val4 = (MeshRenderer)(object)((val2 is MeshRenderer) ? val2 : null); if (val4 == null) { continue; } Matrix4x4 val5 = prefab.transform.worldToLocalMatrix * ((Component)val3).transform.localToWorldMatrix; GameObject val6 = new GameObject(((Object)val3).name); val6.transform.SetParent(val.transform, false); val6.transform.localPosition = Vector4.op_Implicit(((Matrix4x4)(ref val5)).GetColumn(3)); val6.transform.localRotation = ((Matrix4x4)(ref val5)).rotation; val6.transform.localScale = ((Matrix4x4)(ref val5)).lossyScale; val6.AddComponent<MeshFilter>().sharedMesh = val3.sharedMesh; ((Renderer)val6.AddComponent<MeshRenderer>()).sharedMaterials = ((Renderer)val4).sharedMaterials; Bounds bounds = val3.sharedMesh.bounds; float[] array3 = new float[2] { ((Bounds)(ref bounds)).min.x, ((Bounds)(ref bounds)).max.x }; foreach (float num3 in array3) { float[] array4 = new float[2] { ((Bounds)(ref bounds)).min.y, ((Bounds)(ref bounds)).max.y }; foreach (float num4 in array4) { float[] array5 = new float[2] { ((Bounds)(ref bounds)).min.z, ((Bounds)(ref bounds)).max.z }; foreach (float num5 in array5) { float z = ((Matrix4x4)(ref val5)).MultiplyPoint3x4(new Vector3(num3, num4, num5)).z; num = Mathf.Min(num, z); num2 = Mathf.Max(num2, z); } } } } if (num == float.MaxValue || num2 - num < 0.01f) { Object.Destroy((Object)(object)val); return; } float num6 = Mathf.Min(1f, 0.6f / (num2 - num)); val.transform.localScale = Vector3.one * num6; val.transform.localRotation = lean * Quaternion.Euler(90f, 0f, 0f); val.transform.localPosition = at + Vector3.up * (0.42000002f + num * num6); } private static Transform FindBone(Transform root, string name) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown if (((Object)root).name == name) { return root; } foreach (Transform item in root) { Transform root2 = item; Transform val = FindBone(root2, name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static void MakeMaterials() { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_leather != (Object)null && (Object)(object)_dark != (Object)null) { return; } Material val = null; GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("Wood") : null); if ((Object)(object)val2 != (Object)null) { Renderer[] componentsInChildren = val2.GetComponentsInChildren<Renderer>(true); foreach (Renderer val3 in componentsInChildren) { val = val ?? ((IEnumerable<Material>)val3.sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => (Object)(object)m != (Object)null && ((Object)m).name == "wood_item")); } } val = (Material)(((object)val) ?? ((object)new Material(Shader.Find("Standard") ?? Shader.Find("Sprites/Default")))); _leather = Plain(val, new Color(0.4f, 0.24f, 0.12f)); _dark = Plain(val, new Color(0.17f, 0.1f, 0.06f)); } private static Material Plain(Material basis, Color color) { //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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown Material val = new Material(basis) { color = color }; if (val.HasProperty("_MainTex")) { val.mainTexture = null; } if (val.HasProperty("_Glossiness")) { val.SetFloat("_Glossiness", 0.1f); } if (val.HasProperty("_Metallic")) { val.SetFloat("_Metallic", 0f); } return val; } } [HarmonyPatch(typeof(Projectile), "OnHit")] internal static class Projectile_OnHit_Recover { private static readonly FieldRef<Projectile, ItemData> Ammo = AccessTools.FieldRefAccess<Projectile, ItemData>("m_ammo"); private static readonly FieldRef<Projectile, Character> Owner = AccessTools.FieldRefAccess<Projectile, Character>("m_owner"); private static readonly FieldRef<Projectile, ZNetView> View = AccessTools.FieldRefAccess<Projectile, ZNetView>("m_nview"); private static readonly FieldRef<Projectile, ItemData> SpawnItem = AccessTools.FieldRefAccess<Projectile, ItemData>("m_spawnItem"); private static readonly FieldRef<Projectile, ItemData> Weapon = AccessTools.FieldRefAccess<Projectile, ItemData>("m_weapon"); private static readonly HashSet<int> Done = new HashSet<int>(); private static void Postfix(Projectile __instance, Collider collider, Vector3 hitPoint, bool water, Vector3 normal) { //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_043a: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Debug.Value) { ZNetView val = View.Invoke(__instance); ManualLogSource log = Plugin.Log; object[] obj = new object[6] { ((Object)__instance).name, null, null, null, null, null }; Character obj2 = Owner.Invoke(__instance); obj[1] = ((obj2 != null) ? ((Object)obj2).name : null) ?? "none"; obj[2] = ((object)Owner.Invoke(__instance))?.GetType().Name; obj[3] = (((Object)(object)val == (Object)null) ? "none" : ((!val.IsValid()) ? "invalid" : (val.IsOwner() ? "owned here" : "owned elsewhere"))); obj[4] = water; obj[5] = ((collider != null) ? ((Object)collider).name : null) ?? "nothing"; log.LogInfo((object)string.Format("OnHit {0}: owner {1} ({2}), view {3}, water {4}, on {5}", obj)); } if (!Plugin.Recover.Value || water) { return; } Character obj3 = Owner.Invoke(__instance); Player val2 = (Player)(object)((obj3 is Player) ? obj3 : null); if (val2 == null || (Object)(object)val2 != (Object)(object)Player.m_localPlayer || BetterArchery.ArrowsOn) { return; } ItemData val3 = Ammo.Invoke(__instance) ?? SpawnItem.Invoke(__instance); if (Plugin.Debug.Value) { ManualLogSource log2 = Plugin.Log; string[] obj4 = new string[13] { "Hit by ", ((Object)__instance).name, ": ammo ", Ammo.Invoke(__instance)?.m_shared.m_name ?? "none", ", spawnItem ", SpawnItem.Invoke(__instance)?.m_shared.m_name ?? "none", ", weapon ", Weapon.Invoke(__instance)?.m_shared.m_name ?? "none", ", on ", ((collider != null) ? ((Object)collider).name : null) ?? "nothing", " (", null, null }; object obj5; if (collider == null) { obj5 = null; } else { Character componentInParent = ((Component)collider).GetComponentInParent<Character>(); obj5 = ((componentInParent != null) ? ((Object)componentInParent).name : null); } if (obj5 == null) { obj5 = "no creature"; } obj4[11] = (string)obj5; obj4[12] = ")"; log2.LogInfo((object)string.Concat(obj4)); } if (val3 == null || (Object)(object)val3.m_dropPrefab == (Object)null || !Recoverable(val3)) { if (Plugin.Debug.Value) { Plugin.Log.LogInfo((object)(" not kept: " + ((val3 == null) ? "no ammo item on the projectile" : (((Object)(object)val3.m_dropPrefab == (Object)null) ? "ammo has no drop prefab" : "not an arrow or bolt it keeps")))); } } else { if (!Done.Add(((Object)__instance).GetInstanceID())) { return; } if (Done.Count > 300) { Done.Clear(); } Character val4 = (((Object)(object)collider != (Object)null) ? ((Component)collider).GetComponentInParent<Character>() : null); if ((Object)(object)val4 != (Object)null && !val4.IsPlayer() && !val4.IsTamed() && !val4.IsDead()) { bool flag = Random.value <= Plugin.CreatureChance.Value; if (Plugin.Debug.Value) { Plugin.Log.LogInfo((object)(" creature " + ((Object)val4).name + ": arrow " + ((Object)val3.m_dropPrefab).name + " " + (flag ? "kept for when it dies" : "broke"))); } if (flag) { Stuck.Add(val4, val3); } return; } if (!(Random.value > Plugin.GroundChance.Value)) { if (Plugin.Debug.Value) { Plugin.Log.LogInfo((object)(" " + ((Object)val3.m_dropPrefab).name + " dropped where it hit")); } ItemData val5 = val3.Clone(); val5.m_stack = 1; val5.m_equipped = false; ItemDrop.DropItem(val5, 1, hitPoint + normal * 0.08f + Vector3.up * 0.05f, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); try { __instance.SetStayTTL(0.05f); return; } catch (Exception) { return; } } if (Plugin.Debug.Value) { Plugin.Log.LogInfo((object)" broke on what it hit"); } } } private static bool Recoverable(ItemData ammo) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)ammo.m_shared.m_itemType != 9) { return false; } string text = (ammo.m_shared.m_ammoType ?? "").ToLowerInvariant(); if (text.Contains("bolt") && !Plugin.Bolts.Value) { return false; } if (!text.Contains("arrow") && !text.Contains("bolt")) { return false; } if (Plugin.FireBurns.Value) { return !((Object)ammo.m_dropPrefab).name.ToLowerInvariant().Contains("fire"); } return true; } } internal static class Stuck { private class Entry { public Character Target; public string Name; public Vector3 Last; public float LastHit; public float Seen; public bool Died; public HashSet<string> Ragdolls; public readonly Dictionary<string, KeyValuePair<ItemData, int>> Arrows = new Dictionary<string, KeyValuePair<ItemData, int>>(); } private struct Body { public string Name; public Vector3 At; public float Time; } private const float Patience = 300f; private const int MaxKept = 200; private const float Wait = 3f; private const float BodyRange = 8f; private static readonly Dictionary<int, Entry> Hit = new Dictionary<int, Entry>(); private static readonly List<Body> Bodies = new List<Body>(); private static float _next; public static void Add(Character target, ItemData arrow) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)target).GetInstanceID(); if (!Hit.TryGetValue(instanceID, out var value)) { if (Hit.Count >= 200) { Hit.Remove(Hit.OrderBy((KeyValuePair<int, Entry> kv) => kv.Value.LastHit).First().Key); } value = (Hit[instanceID] = new Entry { Target = target, Name = ((Object)target).name, Seen = Time.time, Ragdolls = RagdollNames(target) }); } value.LastHit = Time.time; string name = ((Object)arrow.m_dropPrefab).name; value.Arrows[name] = new KeyValuePair<ItemData, int>(value.Arrows.TryGetValue(name, out var value2) ? value2.Key : arrow, (value.Arrows.TryGetValue(name, out var value3) ? value3.Value : 0) + 1); value.Last = ((Component)target).transform.position; if (Plugin.Debug.Value) { Plugin.Log.LogInfo((object)(" " + ((Object)target).name + " has " + string.Join(", ", value.Arrows.Select((KeyValuePair<string, KeyValuePair<ItemData, int>> kv) => kv.Value.Value + " " + kv.Key)) + " stuck in it")); } } public static void OnDeath(Character target) { //IL_0038: 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) if (Hit.Count != 0 && !((Object)(object)target == (Object)null) && Hit.TryGetValue(((Object)target).GetInstanceID(), out var value)) { value.Died = true; value.Last = ((Component)target).transform.position; } } public static void OnRagdoll(Ragdoll ragdoll) { //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) if (Hit.Count != 0 && !((Object)(object)ragdoll == (Object)null)) { Bodies.Add(new Body { Name = Utils.GetPrefabName(((Component)ragdoll).gameObject), At = ((Component)ragdoll).transform.position, Time = Time.time }); } } public static void Tick() { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if (Hit.Count == 0) { Bodies.Clear(); } else { if (Time.time < _next) { return; } _next = Time.time + 0.25f; Bodies.RemoveAll((Body b) => Time.time - b.Time > 5f); foreach (int item in Hit.Keys.ToList()) { Entry entry = Hit[item]; bool flag = (Object)(object)entry.Target == (Object)null; if (!flag) { entry.Last = ((Component)entry.Target).transform.position; entry.Seen = Time.time; if (entry.Target.IsDead() || entry.Target.GetHealth() <= 0f) { entry.Died = true; } } if (!entry.Died && flag && FoundBody(entry)) { entry.Died = true; } if (entry.Died) { Drop(entry); Hit.Remove(item); } else if (flag && Time.time - entry.Seen > 3f) { if (Plugin.Debug.Value) { Plugin.Log.LogInfo((object)(" " + entry.Name + " with arrows in it went away without dying: they stay with it")); } Hit.Remove(item); } else if (!flag && Time.time - entry.LastHit > 300f) { Hit.Remove(item); } } } } private static bool FoundBody(Entry e) { //IL_0054: 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) if (e.Ragdolls == null || e.Ragdolls.Count == 0) { return false; } foreach (Body body in Bodies) { if (body.Time >= e.Seen - 1f && e.Ragdolls.Contains(body.Name) && Vector3.Distance(body.At, e.Last) < 8f) { return true; } } return false; } private static HashSet<string> RagdollNames(Character target) { HashSet<string> hashSet = new HashSet<string>(); if (target.m_deathEffects?.m_effectPrefabs == null) { return hashSet; } EffectData[] effectPrefabs = target.m_deathEffects.m_effectPrefabs; foreach (EffectData val in effectPrefabs) { if (val != null && val.m_enabled && (Object)(object)val.m_prefab != (Object)null && (Object)(object)val.m_prefab.GetComponent<Ragdoll>() != (Object)null) { hashSet.Add(((Object)val.m_prefab).name); } } return hashSet; } private static void Drop(Entry e) { //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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_0062: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) Vector3 val = e.Last + Vector3.up * 0.4f; foreach (KeyValuePair<ItemData, int> value in e.Arrows.Values) { ItemData val2 = value.Key.Clone(); val2.m_stack = value.Value; val2.m_equipped = false; ItemDrop.DropItem(val2, value.Value, val + Random.insideUnitSphere * 0.3f, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); if (Plugin.Debug.Value) { Plugin.Log.LogInfo((object)$" {e.Name} died: {value.Value} {((Object)value.Key.m_dropPrefab).name} dropped with its loot"); } } } public static void Clear() { Hit.Clear(); Bodies.Clear(); } } [HarmonyPatch(typeof(Character), "OnDeath")] internal static class Character_OnDeath_Stuck { private static void Prefix(Character __instance) { Stuck.OnDeath(__instance); } } [HarmonyPatch(typeof(Ragdoll), "Awake")] internal static class Ragdoll_Awake_Stuck { private static void Postfix(Ragdoll __instance) { Stuck.OnRagdoll(__instance); } } } namespace DHack.Shared { internal static class Migration { private sealed class Notice : MonoBehaviour { public string Text; private float _next; private void Update() { if (!(Time.unscaledTime < _next) && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)MessageHud.instance == (Object)null)) { ((Character)Player.m_localPlayer).Message((MessageType)2, Text, 0, (Sprite)null, false); _next = Time.unscaledTime + 60f; } } } public static void FromOldGuid(BaseUnityPlugin plugin, string oldGuid) { BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin); string text = ((metadata != null) ? metadata.GUID : null); if (string.IsNullOrEmpty(oldGuid) || string.IsNullOrEmpty(text) || oldGuid == text) { return; } ManualLogSource val = Logger.CreateLogSource(text); try { bool flag = false; if (Directory.Exists(Paths.ConfigPath)) { string[] files = Directory.GetFiles(Paths.ConfigPath, oldGuid + ".*"); foreach (string text2 in files) { string fileName = Path.GetFileName(text2); if (!fileName.EndsWith(".cfg") && !fileName.EndsWith(".json") && !fileName.EndsWith(".txt")) { continue; } string text3 = Path.Combine(Paths.ConfigPath, text + fileName.Substring(oldGuid.Length)); if (!File.Exists(text3)) { File.Copy(text2, text3); val.LogInfo((object)("Settings moved over from " + fileName + " (the mod's id is now " + text + "; the old file is kept as a backup)")); if (fileName == oldGuid + ".cfg") { flag = true; } } } } if (flag) { plugin.Config.Reload(); } } catch (Exception ex) { val.LogWarning((object)("Couldn't move the settings over from " + oldGuid + ".cfg: " + ex.Message)); } finally { Logger.Sources.Remove((ILogSource)(object)val); } ((MonoBehaviour)plugin).StartCoroutine(StandDownIfTwin(plugin, oldGuid)); } private static IEnumerator StandDownIfTwin(BaseUnityPlugin plugin, string oldGuid) { yield return null; yield return null; if (!((Object)(object)plugin == (Object)null) && Chainloader.PluginInfos.TryGetValue(oldGuid, out var value) && !((Object)(object)value.Instance == (Object)null) && !((Object)(object)value.Instance == (Object)(object)plugin)) { BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin); string text = ((metadata != null) ? metadata.Name : null) ?? oldGuid; string text2 = (string.IsNullOrEmpty(value.Location) ? "an older copy" : value.Location); string text3 = text + ": two copies are installed, an old one (" + text2 + ") and this one. Both would run and do everything twice, so this one stands down. Delete the old copy, then restart the game."; Debug.LogError((object)("[" + text + "] " + text3)); Object.Destroy((Object)(object)plugin); GameObject val = new GameObject("Migration_TwoCopies_" + text); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<Notice>().Text = text3; } } } internal sealed class ServerSettings : IDisposable { private readonly string _send; private readonly string _ask; private readonly ConfigFile _config; private readonly ManualLogSource _log; private readonly List<ConfigEntryBase> _entries = new List<ConfigEntryBase>(); private readonly Dictionary<ConfigEntryBase, object> _own = new Dictionary<ConfigEntryBase, object>(); private readonly Dictionary<ConfigEntryBase, object> _server = new Dictionary<ConfigEntryBase, object>(); private ZRoutedRpc _registeredOn; private bool _applying; private bool _changePending; private float _nextChangeSend; private const float ChangeSendGap = 0.5f; public bool FromServer => _server.Count > 0; private static bool IsServer { get { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } } public ServerSettings(string guid, ConfigFile config, ManualLogSource log) { _send = guid + ".settings"; _ask = guid + ".settings.ask"; _config = config; _log = log; } public ConfigEntry<T> Add<T>(ConfigEntry<T> entry) { if (entry == null || _entries.Contains((ConfigEntryBase)(object)entry)) { return entry; } _entries.Add((ConfigEntryBase)(object)entry); entry.SettingChanged += OnChanged; return entry; } public void Update() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != _registeredOn) { Unregister(); Restore(); _changePending = false; if (instance != null) { Register(instance); } } if (_changePending && Time.unscaledTime >= _nextChangeSend) { SendChange(); } } public void Dispose() { Unregister(); Restore(); foreach (ConfigEntryBase entry in _entries) { Unsubscribe(entry); } _entries.Clear(); } private void Register(ZRoutedRpc rpc) { Forget(rpc, _send); Forget(rpc, _ask); rpc.Register<ZPackage>(_send, (Action<long, ZPackage>)OnValues); rpc.Register(_ask, (Action<long>)OnAsk); rpc.m_onNewPeer = (Action<long>)Delegate.Combine(rpc.m_onNewPeer, new Action<long>(OnNewPeer)); _registeredOn = rpc; } private void Unregister() { if (_registeredOn != null) { ZRoutedRpc registeredOn = _registeredOn; registeredOn.m_onNewPeer = (Action<long>)Delegate.Remove(registeredOn.m_onNewPeer, new Action<long>(OnNewPeer)); Forget(_registeredOn, _send); Forget(_registeredOn, _ask); _registeredOn = null; } } private static void Forget(ZRoutedRpc rpc, string name) { if (AccessTools.Field(typeof(ZRoutedRpc), "m_functions")?.GetValue(rpc) is IDictionary dictionary) { dictionary.Remove(StringExtensionMethods.GetStableHashCode(name)); } } private void OnNewPeer(long peer) { if (IsServer) { Send(peer); } else if ((Object)(object)ZNet.instance != (Object)null) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null && serverPeer.m_uid == peer) { Ask(); } } } private void OnAsk(long sender) { if (IsServer) { Send(sender); } } private void Ask() { try { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(ZNet.instance.GetServerPeer().m_uid, _ask, Array.Empty<object>()); } } catch (Exception) { } } private void Send(long target) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown if (ZRoutedRpc.instance == null || _entries.Count == 0) { return; } ZPackage val = new ZPackage(); val.Write(_entries.Count); foreach (ConfigEntryBase entry in _entries) { val.Write(entry.Definition.Section); val.Write(entry.Definition.Key); val.Write(TomlTypeConverter.ConvertToString(entry.BoxedValue, entry.SettingType)); } ZRoutedRpc.instance.InvokeRoutedRPC(target, _send, new object[1] { val }); } private void OnValues(long sender, ZPackage pkg) { if (IsServer) { return; } ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null); if (val == null || val.m_uid != sender) { return; } try { int num = pkg.ReadInt(); List<string> list = new List<string>(); for (int i = 0; i < num; i++) { string section = pkg.ReadString(); string key = pkg.ReadString(); string text = pkg.ReadString(); ConfigEntryBase val2 = ((IEnumerable<ConfigEntryBase>)_entries).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase x) => x.Definition.Section == section && x.Definition.Key == key)); if (val2 != null) { object obj; try { obj = TomlTypeConverter.ConvertToValue(text, val2.SettingType); } catch (Exception) { continue; } if (!_own.ContainsKey(val2)) { _own[val2] = val2.BoxedValue; } _server[val2] = obj; if (!object.Equals(val2.BoxedValue, obj)) { Apply(val2, obj); list.Add(section + "/" + key + " = " + text); } } } ManualLogSource log = _log; if (log != null) { log.LogInfo((object)($"Settings from the server apply while you play here ({_server.Count})" + ((list.Count > 0) ? (": " + string.Join(", ", list.ToArray())) : ""))); } } catch (Exception ex2) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("Could not read the server's settings: " + ex2.Message)); } } } private void Apply(ConfigEntryBase e, object value) { bool saveOnConfigSet = _config.SaveOnConfigSet; _applying = true; try { _config.SaveOnConfigSet = false; e.BoxedValue = value; } finally { _config.SaveOnConfigSet = saveOnConfigSet; _applying = false; } } private void Restore() { if (_server.Count == 0) { return; } foreach (KeyValuePair<ConfigEntryBase, object> item in _own) { Apply(item.Key, item.Value); } _own.Clear(); _server.Clear(); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)"Your own settings apply again"); } } private void OnChanged(object sender, EventArgs args) { if (_applying) { return; } ConfigEntryBase val = (ConfigEntryBase)((sender is ConfigEntryBase) ? sender : null); if (val == null) { return; } if (_server.TryGetValue(val, out var value)) { _own[val] = val.BoxedValue; Apply(val, value); } else if (IsServer) { _changePending = true; if (Time.unscaledTime >= _nextChangeSend) { SendChange(); } } } private void SendChange() { _changePending = false; _nextChangeSend = Time.unscaledTime + 0.5f; if (IsServer && ZNet.instance.GetPeers().Count > 0) { Send(0L); } } private void Unsubscribe(ConfigEntryBase e) { ((object)e).GetType().GetEvent("SettingChanged")?.RemoveEventHandler(e, new EventHandler(OnChanged)); } } }