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 BossLootChests v1.0.10
Cjayride.BossLootChests.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyCompany("Cjayride.BossLootChests")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.10.0")] [assembly: AssemblyInformationalVersion("1.0.10+2243a4178b72b1fb8fceebcfc81564157a196b0e")] [assembly: AssemblyProduct("Cjayride.BossLootChests")] [assembly: AssemblyTitle("Cjayride.BossLootChests")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.10.0")] [module: UnverifiableCode] [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 Cjayride.BossLootChests { internal sealed class BossChestWatcher : MonoBehaviour { private Container _container; private Inventory _inventory; private void Awake() { _container = ((Component)this).GetComponent<Container>(); } private void OnEnable() { if (!((Object)(object)_container == (Object)null) && LootCapture.IsOurChest(_container.m_nview)) { ChestService.ApplyProtection(((Component)_container).gameObject); _inventory = _container.GetInventory(); if (_inventory != null) { Inventory inventory = _inventory; inventory.m_onChanged = (Action)Delegate.Remove(inventory.m_onChanged, new Action(OnInventoryChanged)); Inventory inventory2 = _inventory; inventory2.m_onChanged = (Action)Delegate.Combine(inventory2.m_onChanged, new Action(OnInventoryChanged)); } } } private void Start() { if ((Object)(object)_container != (Object)null && LootCapture.IsOurChest(_container.m_nview)) { ((MonoBehaviour)this).StartCoroutine(DeferredEmptyCheck()); } } private void OnDisable() { if (_inventory != null) { Inventory inventory = _inventory; inventory.m_onChanged = (Action)Delegate.Remove(inventory.m_onChanged, new Action(OnInventoryChanged)); } } private IEnumerator DeferredEmptyCheck() { yield return null; yield return null; OnInventoryChanged(); } private void OnInventoryChanged() { if ((Object)(object)_container == (Object)null || _inventory == null || !LootCapture.IsOurChest(_container.m_nview)) { return; } ZNetView nview = _container.m_nview; if (!((Object)(object)nview == (Object)null) && nview.IsValid() && _inventory.NrOfItems() <= 0) { if (!nview.IsOwner()) { nview.ClaimOwnership(); } if (nview.IsOwner()) { ChestService.DestroyChest(((Component)_container).gameObject, smoke: true); } } } } internal static class BountyTargets { private static Type _bountyTarget; internal static bool UseChestForBountyLoot() { if (ModConfig.BountyLootInChest != null) { return ModConfig.BountyLootInChest.Value; } return false; } internal static bool SkipChestCapture(Character character) { if (UseChestForBountyLoot() || (Object)(object)character == (Object)null) { return false; } return IsEpicLootBountyTarget(character); } internal static bool IsEpicLootBountyTarget(Character character) { Type type = BountyTargetType(); if (type == null) { return false; } return (Object)(object)((Component)character).gameObject.GetComponent(type) != (Object)null; } private static Type BountyTargetType() { if (_bountyTarget != null) { return _bountyTarget; } _bountyTarget = AccessTools.TypeByName("EpicLoot.Adventure.BountyTarget"); return _bountyTarget; } } internal static class ChestService { internal static List<Container> SpawnFilled(Vector3 origin, List<ItemData> items, int firstSlot = 0) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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) List<Container> list = new List<Container>(); if (items == null || items.Count == 0 || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { return list; } string text = ((ModConfig.ChestPrefab != null) ? ModConfig.ChestPrefab.Value : "piece_chest_blackmetal"); GameObject prefab = ZNetScene.instance.GetPrefab(text); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent<Container>())) { prefab = ZNetScene.instance.GetPrefab("piece_chest_blackmetal"); } if (!Object.op_Implicit((Object)(object)prefab)) { Plugin.Log.LogError((object)"BossLootChests: no chest prefab found."); return list; } Vector3 val = SnapGround(origin); int num = 0; int i = 0; while (i < items.Count) { Vector3 val2 = SnapGround(val + SideOffset(firstSlot + num)); GameObject val3 = Object.Instantiate<GameObject>(prefab, val2, Quaternion.identity); MarkChest(val3); Container component = val3.GetComponent<Container>(); Inventory inventory = component.GetInventory(); int num2 = 0; for (; i < items.Count; i++) { ItemData val4 = items[i]; if (!inventory.CanAddItem(val4, -1)) { break; } inventory.AddItem(val4); num2++; } if (num2 == 0) { DestroyChest(val3, smoke: false); Plugin.Log.LogWarning((object)"BossLootChests: an item would not fit the chest prefab; leftover loot was not placed."); break; } inventory.Changed(false, false); EnsureWatcher(val3); LootCapture.Remember(component); list.Add(component); num++; } Plugin.Log.LogInfo((object)("BossLootChests: stored " + items.Count + " stacks in " + num + " chest(s).")); return list; } internal static void Deposit(Container chest, List<ItemData> items) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)chest) || items == null || items.Count == 0) { return; } Inventory inventory = chest.GetInventory(); List<ItemData> list = new List<ItemData>(); foreach (ItemData item in items) { if (inventory.CanAddItem(item, -1)) { inventory.AddItem(item); } else { list.Add(item); } } inventory.Changed(false, false); if (list.Count > 0) { SpawnFilled(((Component)chest).transform.position, list, NearbyChests(((Component)chest).transform.position) + 1); } } internal static void DropOnGround(List<ItemData> items, Vector3 pos) { //IL_0016: 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) foreach (ItemData item in items) { ItemDrop.DropItem(item, item.m_stack, pos, Quaternion.identity); } } private static int NearbyChests(Vector3 pos) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) int num = 0; Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); foreach (Container val in array) { if (Object.op_Implicit((Object)(object)val) && LootCapture.IsOurChest(val.m_nview) && Vector3.Distance(pos, ((Component)val).transform.position) < 8f) { num++; } } return num; } internal static void EnsureWatching(Container container) { if (!((Object)(object)container == (Object)null) && LootCapture.IsOurChest(container.m_nview)) { ApplyProtection(((Component)container).gameObject); EnsureWatcher(((Component)container).gameObject); LootCapture.Remember(container); } } private static void MarkChest(GameObject go) { ZNetView component = go.GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.GetZDO() != null) { component.GetZDO().Set(186620331, 1, false); component.GetZDO().Set("cjayride.BossLootChests.Spawned", Object.op_Implicit((Object)(object)ZNet.instance) ? ZNet.instance.GetTime().Ticks : 0); } ApplyProtection(go); } internal static void ApplyProtection(GameObject go) { WearNTear component = go.GetComponent<WearNTear>(); if (Object.op_Implicit((Object)(object)component)) { component.m_noSupportWear = true; component.m_noRoofWear = false; component.m_health = 1E+09f; } Piece component2 = go.GetComponent<Piece>(); if (Object.op_Implicit((Object)(object)component2)) { component2.m_canBeRemoved = false; ((StaticTarget)component2).m_randomTarget = false; } } private static void EnsureWatcher(GameObject go) { if (!Object.op_Implicit((Object)(object)go.GetComponent<BossChestWatcher>())) { go.AddComponent<BossChestWatcher>(); } } internal static void DestroyChest(GameObject go, bool smoke) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)go)) { if (smoke) { RemoveFx.Broadcast(go.transform.position); } ZNetView component = go.GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid() && Object.op_Implicit((Object)(object)ZNetScene.instance)) { ZNetScene.instance.Destroy(go); } else { Object.Destroy((Object)(object)go); } } } private static Vector3 SnapGround(Vector3 origin) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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_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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0057: Unknown result type (might be due to invalid IL or missing references) RaycastHit val = default(RaycastHit); if (Physics.Raycast(origin + Vector3.up * 6f, Vector3.down, ref val, 40f, Object.op_Implicit((Object)(object)ZoneSystem.instance) ? ZoneSystem.instance.m_solidRayMask : (-1))) { return ((RaycastHit)(ref val)).point + Vector3.up * 0.05f; } return origin; } private static Vector3 SideOffset(int index) { //IL_002c: 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_0004: Unknown result type (might be due to invalid IL or missing references) if (index <= 0) { return Vector3.zero; } float num = (float)(index - 1) * 70f * ((float)Math.PI / 180f); return new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * (1.4f + (float)index * 0.15f); } } internal static class EpicLootHook { private static MethodInfo _getLootTable; private static MethodInfo _rollLootTable; internal static void TryPatch(Harmony harmony) { //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown Type type = AccessTools.TypeByName("EpicLoot.EpicLootDropsHelper"); Type type2 = AccessTools.TypeByName("EpicLoot.LootRoller"); if (type == null || type2 == null) { return; } MethodInfo methodInfo = AccessTools.Method(type, "OnCharacterDeath", new Type[3] { typeof(string), typeof(int), typeof(Vector3) }, (Type[])null); _getLootTable = AccessTools.Method(type2, "GetLootTable", new Type[1] { typeof(string) }, (Type[])null); foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type2)) { if (!(declaredMethod.Name != "RollLootTable") && declaredMethod.GetParameters().Length == 4) { ParameterInfo[] parameters = declaredMethod.GetParameters(); if (parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(string) && parameters[3].ParameterType == typeof(Vector3)) { _rollLootTable = declaredMethod; break; } } } if (methodInfo == null || _getLootTable == null || _rollLootTable == null) { Plugin.Log.LogWarning((object)"BossLootChests: EpicLoot found but could not hook loot rolls."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(EpicLootHook), "EpicDeathPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"BossLootChests: EpicLoot loot will go into boss chests."); } private static bool EpicDeathPrefix(string characterName, int level, Vector3 dropPoint) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!LootCapture.Active) { return true; } object obj = _getLootTable.Invoke(null, new object[1] { characterName }); if (obj == null) { return false; } LootCapture.IgnoreSpawns(on: true); object obj2; try { obj2 = _rollLootTable.Invoke(null, new object[4] { obj, level, characterName, dropPoint }); } finally { LootCapture.IgnoreSpawns(on: false); } if (obj2 is IEnumerable enumerable) { foreach (object item in enumerable) { ItemData val = (ItemData)((item is ItemData) ? item : null); if (val != null) { LootCapture.Add(val); } } } return false; } } internal static class LootCapture { private sealed class AddNote { internal ZDOID Boss; internal Character Character; internal long Deadline; internal long StampedUntil; } internal const int ZdoMarker = 186620331; internal const string ZdoSpawnTime = "cjayride.BossLootChests.Spawned"; internal const string ZdoAddUntil = "cjayride.BossLootChests.AddUntil"; internal const string ZdoAddKeep = "cjayride.BossLootChests.AddKeep"; internal const string RpcLoot = "cjayride.BossLootChests.Loot"; internal const int MarkBoss = 1; internal const int MarkAdd = 2; private static int _depth; private static int _ignoreSpawns; private static bool _add; private static Vector3 _origin; private static readonly List<ItemData> _items = new List<ItemData>(); private static readonly List<ItemDrop> _spawned = new List<ItemDrop>(); private static readonly List<ItemData> _held = new List<ItemData>(); private static readonly HashSet<Container> _chests = new HashSet<Container>(); private static readonly Dictionary<ZDOID, AddNote> _adds = new Dictionary<ZDOID, AddNote>(); private static readonly Dictionary<ZDOID, Character> _liveBosses = new Dictionary<ZDOID, Character>(); private static readonly List<ZDOID> _expired = new List<ZDOID>(); private static bool _rememberedCapture; private static float _nextScan; internal static bool Active { get { if (_depth > 0) { return On; } return false; } } private static bool On { get { if (ModConfig.Enabled != null) { return ModConfig.Enabled.Value; } return false; } } private static float Radius { get { if (ModConfig.AddRadius == null) { return 180f; } return ModConfig.AddRadius.Value; } } private static float Window { get { if (ModConfig.AddSeconds == null) { return 60f; } return ModConfig.AddSeconds.Value; } } private static long IdleTicks => (long)((double)((ModConfig.AddIdleSeconds != null) ? ModConfig.AddIdleSeconds.Value : 1200f) * 10000000.0); private static long Now { get { if (!((Object)(object)ZNet.instance != (Object)null)) { return 0L; } return ZNet.instance.GetTime().Ticks; } } internal static void BeginBoss(Vector3 origin) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Begin(origin, add: false); } internal static void Tick() { //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_030b: 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_014f: 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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: 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) if (!On || (Object)(object)ZNet.instance == (Object)null || Time.time < _nextScan) { return; } _nextScan = Time.time + 1f; long now = Now; _liveBosses.Clear(); List<Character> allCharacters = Character.GetAllCharacters(); for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if (Object.op_Implicit((Object)(object)val) && !val.IsDead() && val.IsBoss() && !BountyTargets.SkipChestCapture(val) && InCombat(val) && Object.op_Implicit((Object)(object)val.m_nview) && val.m_nview.IsValid()) { _liveBosses[val.m_nview.GetZDO().m_uid] = val; } } if (_liveBosses.Count > 0) { float num = Radius * Radius; for (int j = 0; j < allCharacters.Count; j++) { Character val2 = allCharacters[j]; if (!Object.op_Implicit((Object)(object)val2) || val2.IsDead() || val2.IsPlayer() || val2.IsBoss() || !Object.op_Implicit((Object)(object)val2.m_nview) || !val2.m_nview.IsValid()) { continue; } ZDOID uid = val2.m_nview.GetZDO().m_uid; foreach (KeyValuePair<ZDOID, Character> liveBoss in _liveBosses) { Vector3 val3 = ((Component)val2).transform.position - ((Component)liveBoss.Value).transform.position; if (!(((Vector3)(ref val3)).sqrMagnitude > num)) { if (!_adds.TryGetValue(uid, out var value)) { value = new AddNote(); _adds[uid] = value; } value.Character = val2; value.Boss = liveBoss.Key; value.Deadline = 0L; Stamp(value, now + 216000000000L); break; } } } } if (_adds.Count == 0) { return; } _expired.Clear(); foreach (KeyValuePair<ZDOID, AddNote> add in _adds) { AddNote value2 = add.Value; Character character = value2.Character; bool num2 = _liveBosses.ContainsKey(value2.Boss); bool flag = Object.op_Implicit((Object)(object)character) && IsFighting(character); if (num2) { value2.Deadline = 0L; } else if (flag || value2.Deadline == 0L) { value2.Deadline = now + IdleTicks; Stamp(value2, value2.Deadline); } else if (now > value2.Deadline) { _expired.Add(add.Key); } } for (int k = 0; k < _expired.Count; k++) { _adds.Remove(_expired[k]); } } internal static bool IsRemembered(Character character) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) if (!Object.op_Implicit((Object)(object)character) || !Object.op_Implicit((Object)(object)character.m_nview) || !character.m_nview.IsValid()) { return false; } ZDO zDO = character.m_nview.GetZDO(); ZDOID uid = zDO.m_uid; if (_adds.TryGetValue(uid, out var value)) { if (value.Deadline != 0L) { return Now <= value.Deadline; } return true; } return zDO.GetLong("cjayride.BossLootChests.AddUntil", 0L) > Now; } internal static void BeginAdd(Character character) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)character)) { BeginAdd(character.GetCenterPoint(), IsRemembered(character)); } } internal static void BeginAdd(Vector3 origin, bool remembered = false) { //IL_000a: 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) if (_depth != 0 || remembered || !((Object)(object)FindCollector(origin, remembered: false) == (Object)null)) { if (_depth == 0) { _rememberedCapture = remembered; } if (!(_depth > 0 && remembered)) { Begin(origin, add: true); } } } private static void Begin(Vector3 origin, bool add) { //IL_000f: 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) if (On) { if (_depth == 0) { _origin = origin; _add = add; _items.Clear(); _spawned.Clear(); } _depth++; } } internal static void End() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (_depth <= 0) { return; } _depth--; if (_depth <= 0) { Harvest(); List<ItemData> list = new List<ItemData>(_items); _items.Clear(); if (_add) { bool rememberedCapture = _rememberedCapture; _rememberedCapture = false; Route(list, _origin, rememberedCapture); } else if (list.Count != 0) { list.InsertRange(0, _held); _held.Clear(); ChestService.SpawnFilled(_origin, list); } } } internal static void Track(ItemDrop drop) { if (Active && _ignoreSpawns == 0 && Object.op_Implicit((Object)(object)drop) && !_spawned.Contains(drop)) { _spawned.Add(drop); } } internal static void IgnoreSpawns(bool on) { _ignoreSpawns = Mathf.Max(0, _ignoreSpawns + (on ? 1 : (-1))); } private static void Harvest() { foreach (ItemDrop item in _spawned) { if (Object.op_Implicit((Object)(object)item) && item.m_itemData != null) { ItemData val = item.m_itemData.Clone(); if (!Object.op_Implicit((Object)(object)val.m_dropPrefab) && Object.op_Implicit((Object)(object)ObjectDB.instance)) { val.m_dropPrefab = ObjectDB.instance.GetItemPrefab(PrefabName(((Component)item).gameObject)); } _items.Add(val); ZNetView component = ((Component)item).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid() && Object.op_Implicit((Object)(object)ZNetScene.instance)) { ZNetScene.instance.Destroy(((Component)item).gameObject); } else { Object.Destroy((Object)(object)((Component)item).gameObject); } } } _spawned.Clear(); } internal static void Add(ItemData item) { if (item != null) { _items.Add(item.Clone()); } } internal static void AddPrefab(GameObject prefab, int count) { if (!Object.op_Implicit((Object)(object)prefab) || count <= 0) { return; } ItemDrop component = prefab.GetComponent<ItemDrop>(); if (Object.op_Implicit((Object)(object)component)) { int num = count; int num2 = Mathf.Max(1, component.m_itemData.m_shared.m_maxStackSize); while (num > 0) { ItemData val = component.m_itemData.Clone(); val.m_dropPrefab = prefab; val.m_stack = Mathf.Min(num, num2); val.m_worldLevel = (byte)Game.m_worldLevel; num -= val.m_stack; _items.Add(val); } } } private static void Route(List<ItemData> items, Vector3 pos, bool remembered = false) { //IL_0009: 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) if (items.Count != 0) { ZNetView val = FindCollector(pos, remembered); if ((Object)(object)val == (Object)null) { ChestService.DropOnGround(items, pos); return; } if (val.IsOwner()) { Receive(val, items); return; } val.InvokeRPC("cjayride.BossLootChests.Loot", new object[1] { Pack(items) }); } } internal static void Register(ZNetView view) { if (!((Object)(object)view == (Object)null) && view.IsValid()) { view.Register<ZPackage>("cjayride.BossLootChests.Loot", (Action<long, ZPackage>)delegate(long sender, ZPackage pkg) { Receive(view, Unpack(pkg)); }); } } private static void Receive(ZNetView view, List<ItemData> items) { if (!((Object)(object)view == (Object)null) && view.IsValid() && items.Count != 0) { Container component = ((Component)view).GetComponent<Container>(); if (Object.op_Implicit((Object)(object)component) && IsOurChest(view)) { ChestService.Deposit(component, items); } else { _held.AddRange(items); } } } private static ZNetView FindCollector(Vector3 pos, bool remembered) { //IL_000c: 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) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_01c8: 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) if (!On) { return null; } if (remembered) { ZNetView val = NearestChest(pos); if ((Object)(object)val != (Object)null) { return val; } } float radius = Radius; foreach (Character allCharacter in Character.GetAllCharacters()) { if (Object.op_Implicit((Object)(object)allCharacter) && !allCharacter.IsDead() && allCharacter.IsBoss() && !BountyTargets.SkipChestCapture(allCharacter) && !(Vector3.Distance(pos, ((Component)allCharacter).transform.position) > radius) && InCombat(allCharacter) && Object.op_Implicit((Object)(object)allCharacter.m_nview) && allCharacter.m_nview.IsValid()) { return allCharacter.m_nview; } } Ragdoll[] array = Object.FindObjectsByType<Ragdoll>((FindObjectsSortMode)0); foreach (Ragdoll val2 in array) { ZNetView val3 = (Object.op_Implicit((Object)(object)val2) ? val2.m_nview : null); if (Object.op_Implicit((Object)(object)val3) && val3.IsValid() && val3.GetZDO().GetInt(186620331, 0) == 1 && Vector3.Distance(pos, ((Component)val2).transform.position) <= radius) { return val3; } } long num = (Object.op_Implicit((Object)(object)ZNet.instance) ? ZNet.instance.GetTime().Ticks : 0); long num2 = (long)((double)Window * 10000000.0); _chests.RemoveWhere((Container c) => !Object.op_Implicit((Object)(object)c)); foreach (Container chest in _chests) { ZNetView nview = chest.m_nview; if (Object.op_Implicit((Object)(object)nview) && nview.IsValid() && !(Vector3.Distance(pos, ((Component)chest).transform.position) > radius)) { long num3 = nview.GetZDO().GetLong("cjayride.BossLootChests.Spawned", 0L); if (num3 > 0 && num - num3 <= num2) { return nview; } } } return null; } private static ZNetView NearestChest(Vector3 pos) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) ZNetView result = null; float num = Radius * Radius; _chests.RemoveWhere((Container chest) => !Object.op_Implicit((Object)(object)chest)); foreach (Container chest in _chests) { if (IsOurChest(chest.m_nview)) { Vector3 val = pos - ((Component)chest).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude <= num) { result = chest.m_nview; num = sqrMagnitude; } } } return result; } private static void Stamp(AddNote note, long until) { if (until < note.StampedUntil + 600000000) { return; } Character character = note.Character; if (Object.op_Implicit((Object)(object)character) && Object.op_Implicit((Object)(object)character.m_nview) && character.m_nview.IsOwner()) { ZDO zDO = character.m_nview.GetZDO(); if (zDO != null) { zDO.Set("cjayride.BossLootChests.AddUntil", until); note.StampedUntil = until; } } } private static bool IsFighting(Character character) { BaseAI baseAI = character.GetBaseAI(); if (Object.op_Implicit((Object)(object)baseAI)) { if (!baseAI.IsAlerted()) { return baseAI.HaveTarget(); } return true; } return false; } private static bool InCombat(Character boss) { BaseAI baseAI = boss.GetBaseAI(); if (Object.op_Implicit((Object)(object)baseAI) && (baseAI.IsAlerted() || baseAI.HaveTarget())) { return true; } return boss.GetHealth() < boss.GetMaxHealth(); } private static ZPackage Pack(List<ItemData> items) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown Inventory val = new Inventory("BossLootChests", (Sprite)null, 8, Mathf.Max(1, items.Count)); foreach (ItemData item in items) { val.AddItem(item); } ZPackage val2 = new ZPackage(); val.Save(val2); return val2; } private static List<ItemData> Unpack(ZPackage pkg) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) Inventory val = new Inventory("BossLootChests", (Sprite)null, 8, 400); val.Load(pkg); List<ItemData> list = new List<ItemData>(); foreach (ItemData allItem in val.GetAllItems()) { list.Add(allItem.Clone()); } return list; } internal static string PrefabName(GameObject go) { string name = ((Object)go).name; int num = name.IndexOf('('); return ((num >= 0) ? name.Substring(0, num) : name).Trim(); } internal static void Remember(Container chest) { if (Object.op_Implicit((Object)(object)chest)) { _chests.Add(chest); } } internal static bool IsOurChest(WearNTear wear) { if (Object.op_Implicit((Object)(object)wear) && Object.op_Implicit((Object)(object)wear.m_nview) && wear.m_nview.IsValid()) { return wear.m_nview.GetZDO().GetInt(186620331, 0) == 1; } return false; } internal static bool IsOurChest(ZNetView view) { if (Object.op_Implicit((Object)(object)view) && view.IsValid() && Object.op_Implicit((Object)(object)((Component)view).GetComponent<Container>())) { return view.GetZDO().GetInt(186620331, 0) == 1; } return false; } } internal static class ModConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<string> ChestPrefab; internal static ConfigEntry<bool> RemoveSmoke; internal static ConfigEntry<float> AddRadius; internal static ConfigEntry<float> AddSeconds; internal static ConfigEntry<float> AddIdleSeconds; internal static ConfigEntry<bool> BountyLootInChest; internal static ConfigEntry<bool> PerPlayerAmounts; internal static ConfigEntry<float> PerPlayerRange; internal static void Bind(ConfigFile config) { Enabled = config.Bind<bool>("General", "Enabled", true, "Put boss loot into chests at the death spot instead of dropping it on the ground."); ChestPrefab = config.Bind<string>("General", "ChestPrefab", "piece_chest_blackmetal", "World chest prefab to spawn. Must be a Container (player-built chests are safest)."); RemoveSmoke = config.Bind<bool>("General", "RemoveSmoke", true, "Play a smoke puff when an emptied boss chest deletes itself."); AddRadius = config.Bind<float>("General", "AddRadius", 180f, "Creatures that die within this many meters of a boss in combat have their drops stored for the boss chest."); AddSeconds = config.Bind<float>("General", "AddSeconds", 60f, "After the boss chest appears, any creature that dies within AddRadius still goes into it for this many seconds."); AddIdleSeconds = config.Bind<float>("General", "AddIdleSeconds", 1200f, "Creatures that were near the boss while it was alive still go into the chest after it dies. This many seconds after the boss dies, an add that nobody is fighting is forgotten. Fighting it resets the timer."); PerPlayerAmounts = config.Bind<bool>("General", "PerPlayerAmounts", true, "Boss drops marked one-per-player count only players within PerPlayerRange of the boss when it dies. Drops with an amount range (such as Coins 200-300) give that amount for each of those players."); PerPlayerRange = config.Bind<float>("General", "PerPlayerRange", 400f, "Meters from the boss. Only players this close when it dies count for one-per-player boss drops."); BountyLootInChest = config.Bind<bool>("General", "BountyLootInChest", false, "When true, Epic Loot bounty targets (marked as boss for scaling) use boss chests like real bosses. When false, their meat and drops stay on the ground."); } } [HarmonyPatch] internal static class Patches { private static readonly List<Player> _nearby = new List<Player>(); [HarmonyPostfix] [HarmonyPatch(typeof(ZNet), "Awake")] private static void RegisterFxRpc() { RemoveFx.Register(); } [HarmonyPrefix] [HarmonyPatch(typeof(CharacterDrop), "OnDeath")] [HarmonyPriority(800)] private static void DeathBegin(CharacterDrop __instance) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) Character character = __instance.m_character; if (Object.op_Implicit((Object)(object)character) && !BountyTargets.SkipChestCapture(character)) { if (character.IsBoss()) { LootCapture.BeginBoss(character.GetCenterPoint()); } else { LootCapture.BeginAdd(character); } } } [HarmonyPostfix] [HarmonyPatch(typeof(CharacterDrop), "OnDeath")] [HarmonyPriority(0)] private static void DeathEnd() { if (LootCapture.Active) { LootCapture.End(); } } [HarmonyPostfix] [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] [HarmonyPriority(0)] private static void PerPlayer(CharacterDrop __instance, List<KeyValuePair<GameObject, int>> __result) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.Enabled == null || !ModConfig.Enabled.Value || ModConfig.PerPlayerAmounts == null || !ModConfig.PerPlayerAmounts.Value || __result == null || __result.Count == 0) { return; } Character character = __instance.m_character; if (!Object.op_Implicit((Object)(object)character) || !character.IsBoss() || BountyTargets.SkipChestCapture(character) || !Object.op_Implicit((Object)(object)ZNet.instance)) { return; } Dictionary<string, Queue<Drop>> dictionary = new Dictionary<string, Queue<Drop>>(); foreach (Drop drop in __instance.m_drops) { if (drop != null && Object.op_Implicit((Object)(object)drop.m_prefab) && drop.m_onePerPlayer) { string key = LootCapture.PrefabName(drop.m_prefab); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new Queue<Drop>()); } value.Enqueue(drop); } } if (dictionary.Count == 0) { return; } int num = NearbyPlayers(((Component)character).transform.position); for (int i = 0; i < __result.Count; i++) { GameObject key2 = __result[i].Key; if (Object.op_Implicit((Object)(object)key2) && dictionary.TryGetValue(LootCapture.PrefabName(key2), out var value2) && value2.Count != 0) { Drop val = value2.Dequeue(); int num2 = ((val.m_amountMax <= 1) ? 1 : Random.Range(Mathf.Max(1, val.m_amountMin), val.m_amountMax + 1)); __result[i] = new KeyValuePair<GameObject, int>(key2, num2 * num); } } } private static int NearbyPlayers(Vector3 pos) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) float num = ((ModConfig.PerPlayerRange != null) ? ModConfig.PerPlayerRange.Value : 400f); _nearby.Clear(); Player.GetPlayersInRange(pos, num, _nearby); int num2 = 0; foreach (Player item in _nearby) { if (Object.op_Implicit((Object)(object)item) && !((Character)item).IsDead()) { num2++; } } _nearby.Clear(); return Mathf.Max(1, num2); } [HarmonyPrefix] [HarmonyPatch(typeof(Ragdoll), "Setup")] private static void RagdollMark(Ragdoll __instance, CharacterDrop characterDrop) { if ((Object)(object)characterDrop == (Object)null || !Object.op_Implicit((Object)(object)characterDrop.m_character)) { return; } Character character = characterDrop.m_character; if (!character.IsPlayer() && !BountyTargets.SkipChestCapture(character) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.GetZDO() != null) { ZDO zDO = __instance.m_nview.GetZDO(); zDO.Set(186620331, character.IsBoss() ? 1 : 2, false); if (!character.IsBoss() && LootCapture.IsRemembered(character)) { zDO.Set("cjayride.BossLootChests.AddKeep", 1); } } } [HarmonyPrefix] [HarmonyPatch(typeof(Ragdoll), "SpawnLoot")] [HarmonyPriority(800)] private static void RagdollLootBegin(Ragdoll __instance, Vector3 center, out bool __state) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) __state = false; if (Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.IsValid()) { int num = __instance.m_nview.GetZDO().GetInt(186620331, 0); int num2 = __instance.m_nview.GetZDO().GetInt("cjayride.BossLootChests.AddKeep", 0); Vector3 origin = center + Vector3.up * 0.75f; if (num == 1) { LootCapture.BeginBoss(origin); } else if (num == 2 || num2 == 1) { LootCapture.BeginAdd(origin, num2 == 1); } __state = LootCapture.Active; } } [HarmonyPostfix] [HarmonyPatch(typeof(Ragdoll), "SpawnLoot")] [HarmonyPriority(0)] private static void RagdollLootEnd(bool __state) { if (__state) { LootCapture.End(); } } [HarmonyPrefix] [HarmonyPatch(typeof(CharacterDrop), "DropItems")] [HarmonyPriority(800)] private static void DropItems(List<KeyValuePair<GameObject, int>> drops) { if (!LootCapture.Active || drops == null) { return; } for (int i = 0; i < drops.Count; i++) { GameObject key = drops[i].Key; ItemDrop val = (Object.op_Implicit((Object)(object)key) ? key.GetComponent<ItemDrop>() : null); if (Object.op_Implicit((Object)(object)val) && val.m_itemData.m_shared.m_maxStackSize > 1 && drops[i].Value > 0) { LootCapture.AddPrefab(key, drops[i].Value); drops[i] = new KeyValuePair<GameObject, int>(key, 0); } } } [HarmonyPostfix] [HarmonyPatch(typeof(ItemDrop), "Awake")] private static void TrackSpawned(ItemDrop __instance) { LootCapture.Track(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(ItemDrop), "DropItem")] private static bool DropItem(ItemData item, int amount, ref ItemDrop __result) { if (!LootCapture.Active || item == null) { return true; } ItemData val = item.Clone(); if (amount > 0) { val.m_stack = amount; } LootCapture.Add(val); __result = null; return false; } [HarmonyPostfix] [HarmonyPatch(typeof(Character), "Awake")] private static void BossRpc(Character __instance) { if (Object.op_Implicit((Object)(object)__instance) && __instance.IsBoss()) { LootCapture.Register(__instance.m_nview); } } [HarmonyPostfix] [HarmonyPatch(typeof(Ragdoll), "Awake")] private static void RagdollRpc(Ragdoll __instance) { LootCapture.Register(__instance.m_nview); } [HarmonyPrefix] [HarmonyPatch(typeof(WearNTear), "ApplyDamage")] private static bool NoApplyDamage(WearNTear __instance) { return !LootCapture.IsOurChest(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(WearNTear), "Damage")] private static bool NoDamage(WearNTear __instance) { return !LootCapture.IsOurChest(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(WearNTear), "Remove")] private static bool NoRemove(WearNTear __instance) { return !LootCapture.IsOurChest(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(Container), "Awake")] private static void ContainerAwake(Container __instance) { LootCapture.Register(__instance.m_nview); ChestService.EnsureWatching(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(Container), "Load")] private static void ContainerLoad(Container __instance) { ChestService.EnsureWatching(__instance); } } [BepInPlugin("cjayride.bosslootchests", "BossLootChests", "1.0.9")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "cjayride.bosslootchests"; public const string PluginName = "BossLootChests"; public const string PluginVersion = "1.0.9"; internal static Plugin Instance; internal static Harmony Harmony; internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; private void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown Instance = this; ModConfig.Bind(((BaseUnityPlugin)this).Config); Harmony = new Harmony("cjayride.bosslootchests"); Harmony.PatchAll(Assembly.GetExecutingAssembly()); EpicLootHook.TryPatch(Harmony); } private void Update() { LootCapture.Tick(); } } internal static class RemoveFx { internal const string RpcName = "cjayride.BossLootChests.Puff"; private static EffectList _chestDestroyFx; private static readonly string[] Prefabs = new string[4] { "vfx_wood_black_stack_destroyed", "vfx_RockDestroyed", "vfx_wood_destroyed", "fx_creature_tamedremoved" }; internal static void Register() { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register<Vector3>("cjayride.BossLootChests.Puff", (Action<long, Vector3>)delegate(long _, Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) PlayLocal(pos); }); CacheChestDestroyFx(); } } internal static void Broadcast(Vector3 pos) { //IL_003c: 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 (ModConfig.RemoveSmoke == null || ModConfig.RemoveSmoke.Value) { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(0L, "cjayride.BossLootChests.Puff", new object[1] { pos }); } else { PlayLocal(pos); } } } private static void CacheChestDestroyFx() { if (_chestDestroyFx == null && !((Object)(object)ZNetScene.instance == (Object)null)) { string text = ((ModConfig.ChestPrefab != null) ? ModConfig.ChestPrefab.Value : "piece_chest_blackmetal"); GameObject prefab = ZNetScene.instance.GetPrefab(text); if (!Object.op_Implicit((Object)(object)prefab)) { prefab = ZNetScene.instance.GetPrefab("piece_chest_blackmetal"); } WearNTear val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<WearNTear>() : null); if ((Object)(object)val != (Object)null && val.m_destroyedEffect != null) { _chestDestroyFx = val.m_destroyedEffect; } } } private static void PlayLocal(Vector3 pos) { //IL_0011: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) CacheChestDestroyFx(); if (_chestDestroyFx != null) { _chestDestroyFx.Create(pos + Vector3.up * 0.05f, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } else { if ((Object)(object)ZNetScene.instance == (Object)null) { return; } Quaternion identity = Quaternion.identity; string[] prefabs = Prefabs; foreach (string text in prefabs) { GameObject prefab = ZNetScene.instance.GetPrefab(text); if (Object.op_Implicit((Object)(object)prefab)) { Object.Instantiate<GameObject>(prefab, pos + Vector3.up * 0.4f, identity); return; } } Plugin.Log.LogWarning((object)"BossLootChests: no remove VFX found (chest destroy effect or fallback prefabs)."); } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }