using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using HarmonyLib; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("DeathChest")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DeathChest")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("b8ff20b6-2efb-4726-91c3-fb3b0fc22a3e")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] [BepInPlugin("com.robertomontanas.muck.deathchest", "Death Chest", "1.9.1")] public class DeathChestPlugin : BaseUnityPlugin { private class DroppedItem { public int ItemId; public int Amount; public int ObjectId; public DroppedItem(int itemId, int amount, int objectId) { ItemId = itemId; Amount = amount; ObjectId = objectId; } } private class DropBatch { public int ClientId; public float FirstDropTime; public float LastDropTime; public bool MultipleDrops; public readonly List Items = new List(); public DropBatch(int clientId, float time) { ClientId = clientId; FirstDropTime = time; LastDropTime = time; MultipleDrops = false; } } private class ProtectedChest { public int ObjectId; public BuildDestruction BuildDestruction; public ProtectedChest(int objectId, BuildDestruction buildDestruction) { ObjectId = objectId; BuildDestruction = buildDestruction; } } private const string PluginGuid = "com.robertomontanas.muck.deathchest"; private const string PluginName = "Death Chest"; private const string PluginVersion = "1.9.1"; private const float DeathTimeout = 2f; private const float DropBatchWindow = 0.05f; private const float FirstChestHeight = 1f; private const float SecondChestHeight = 2.75f; private const float DropRemovalDelay = 0.5f; private const int DropRemovalRetries = 2; private const float DropRemovalRetryDelay = 0.1f; private const int ProtectedDeathChestCount = 16; private const int DeathChestExtraHP = 10000; private const int ChestSize = 21; private static DeathChestPlugin Instance; private Harmony harmony; private readonly Dictionary pendingDrops = new Dictionary(); private readonly Queue protectedDeathChests = new Queue(); private void Awake() { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown Instance = this; ((BaseUnityPlugin)this).Logger.LogInfo((object)"========================================"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Death Chest v1.9.1"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Death Chest iniciado."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Modo actual: captura + preview + creación de cofres."); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Protección de estabilidad: últimos " + 16 + " cofres.")); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Protección contra mobs: activa."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Protección de daño de Death Chests: activa."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Destrucción de Chest mediante OnKill: no interceptada."); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Death Chest HP extra: +" + 10000)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Eliminación de drops mediante ItemManager.PickupItem."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"========================================"); try { harmony = new Harmony("com.robertomontanas.muck.deathchest"); InstallPatches(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hooks instalados correctamente."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Esperando drops y muertes..."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"ERROR instalando Death Chest:"); ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } private void InstallPatches() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Expected O, but got Unknown //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Expected O, but got Unknown //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(ItemManager), "DropItem", new Type[4] { typeof(int), typeof(int), typeof(int), typeof(int) }, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"NO SE ENCONTRÓ ItemManager.DropItem(int, int, int, int)."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DeathChestPlugin), "ItemManagerDropItemPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hook instalado: ItemManager.DropItem(...)"); MethodInfo methodInfo2 = AccessTools.Method(typeof(ServerHandle), "PlayerDied", new Type[2] { typeof(int), typeof(Packet) }, (Type[])null); if (methodInfo2 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"NO SE ENCONTRÓ ServerHandle.PlayerDied(int, Packet)."); return; } harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(DeathChestPlugin), "ServerPlayerDiedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hook instalado: ServerHandle.PlayerDied(...)"); MethodInfo methodInfo3 = AccessTools.Method(typeof(Hitable), "Damage", new Type[4] { typeof(int), typeof(int), typeof(int), typeof(Vector3) }, (Type[])null); if (methodInfo3 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"NO SE ENCONTRÓ Hitable.Damage(int, int, int, Vector3)."); } else { harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(DeathChestPlugin), "HitableDamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hook instalado: Hitable.Damage(...)"); } MethodInfo methodInfo4 = AccessTools.Method(typeof(ChestManager), "UpdateChest", new Type[4] { typeof(int), typeof(int), typeof(int), typeof(int) }, (Type[])null); if (methodInfo4 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"NO SE ENCONTRÓ ChestManager.UpdateChest(int, int, int, int)."); } else { harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(DeathChestPlugin), "ChestManagerUpdateChestPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hook instalado: ChestManager.UpdateChest(...)"); } MethodInfo methodInfo5 = AccessTools.Method(typeof(MobServerEnemy), "FindNextPosition", Type.EmptyTypes, (Type[])null); if (methodInfo5 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"NO SE ENCONTRÓ MobServerEnemy.FindNextPosition()."); } else { harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(DeathChestPlugin), "MobServerEnemyFindNextPositionPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hook instalado: MobServerEnemy.FindNextPosition(...)"); } MethodInfo methodInfo6 = AccessTools.Method(typeof(MobServerEnemy), "TryAttack", Type.EmptyTypes, (Type[])null); if (methodInfo6 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"NO SE ENCONTRÓ MobServerEnemy.TryAttack()."); return; } harmony.Patch((MethodBase)methodInfo6, new HarmonyMethod(typeof(DeathChestPlugin), "MobServerEnemyTryAttackPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hook instalado: MobServerEnemy.TryAttack(...)"); } private static bool HitableDamagePrefix(Hitable __instance, int newHp, int fromClient, int hitEffect, Vector3 pos) { if ((Object)(object)Instance == (Object)null) { return true; } if ((Object)(object)__instance == (Object)null) { return true; } try { HitableChest val = (HitableChest)(object)((__instance is HitableChest) ? __instance : null); if ((Object)(object)val == (Object)null) { return true; } int num = -1; try { num = ((Hitable)val).GetId(); } catch (Exception) { num = -1; } if (!Instance.IsProtectedDeathChest(num)) { return true; } ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[CHEST DAMAGE PROTECTION] Daño bloqueado. ChestID=" + num + " CurrentHP=" + __instance.hp + " RequestedHP=" + newHp)); return false; } catch (Exception ex2) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogError((object)"[CHEST DAMAGE PROTECTION] Error interceptando Hitable.Damage:"); ((BaseUnityPlugin)Instance).Logger.LogError((object)ex2); } return true; } } private static void ChestManagerUpdateChestPostfix(int chestId, int cellId, int itemId, int amount) { if ((Object)(object)Instance == (Object)null) { return; } try { Instance.CheckProtectedChestAfterUpdate(chestId); } catch (Exception ex) { ((BaseUnityPlugin)Instance).Logger.LogError((object)"[CHEST CONTENT] Error comprobando Death Chest vacío:"); ((BaseUnityPlugin)Instance).Logger.LogError((object)ex); } } private void CheckProtectedChestAfterUpdate(int chestId) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (!IsProtectedDeathChest(chestId)) { return; } ChestManager chestManager = GetChestManager(); if ((Object)(object)chestManager == (Object)null || chestManager.chests == null) { return; } if (!chestManager.chests.TryGetValue(chestId, out var value)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[CHEST CONTENT] Death Chest protegido ya no existe en ChestManager. ChestID=" + chestId)); RemoveProtectedDeathChest(chestId); } else { if (ChestHasContents(value)) { return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[CHEST CONTENT] Death Chest quedó vacío. ChestID=" + chestId + ". Eliminando protección.")); RemoveProtectedDeathChest(chestId); HitableChest val = GetChestFromTransform(((Component)value).transform); if ((Object)(object)val == (Object)null) { val = ((Component)value).GetComponentInParent(); } if ((Object)(object)val == (Object)null) { val = ((Component)value).GetComponentInChildren(true); } if (!((Object)(object)val == (Object)null)) { try { ((Hitable)val).KillObject(Vector3.zero); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[CHEST CONTENT] ChestID=" + chestId + " destruido porque quedó vacío.")); return; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[CHEST CONTENT] Error destruyendo ChestID=" + chestId + ":")); ((BaseUnityPlugin)this).Logger.LogError((object)ex); return; } } ((BaseUnityPlugin)this).Logger.LogWarning((object)("[CHEST CONTENT] No se encontró HitableChest para ChestID=" + chestId)); } } private void RemoveProtectedDeathChest(int objectId) { if (protectedDeathChests.Count == 0) { return; } Queue queue = new Queue(); bool flag = false; while (protectedDeathChests.Count > 0) { ProtectedChest protectedChest = protectedDeathChests.Dequeue(); if (protectedChest != null) { if (protectedChest.ObjectId == objectId) { flag = true; } else { queue.Enqueue(protectedChest); } } } while (queue.Count > 0) { protectedDeathChests.Enqueue(queue.Dequeue()); } if (flag) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[STABILITY] Death Chest eliminado de la protección. ObjectID=" + objectId + " ProtectedCount=" + protectedDeathChests.Count)); } } private static void MobServerEnemyFindNextPositionPostfix(MobServerEnemy __instance, ref Vector3 __result) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Instance == (Object)null || (Object)(object)__instance == (Object)null) { return; } try { Mob component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)component.target == (Object)null || !Instance.IsChestTarget(component.target)) { return; } HitableChest chestFromTransform = Instance.GetChestFromTransform(component.target); int num = -1; if ((Object)(object)chestFromTransform != (Object)null) { try { num = ((Hitable)chestFromTransform).GetId(); } catch (Exception) { num = -1; } } ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[MOB PROTECTION] Mob intentó seleccionar un Chest. Objetivo cancelado. ChestID=" + num)); component.target = null; component.targetPlayerId = -1; __result = Vector3.zero; } catch (Exception ex2) { ((BaseUnityPlugin)Instance).Logger.LogError((object)"[MOB PROTECTION] Error en FindNextPosition:"); ((BaseUnityPlugin)Instance).Logger.LogError((object)ex2); } } private static bool MobServerEnemyTryAttackPrefix(MobServerEnemy __instance) { if ((Object)(object)Instance == (Object)null) { return true; } if ((Object)(object)__instance == (Object)null) { return true; } try { Mob component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } if ((Object)(object)component.target == (Object)null) { return true; } if (!Instance.IsChestTarget(component.target)) { return true; } HitableChest chestFromTransform = Instance.GetChestFromTransform(component.target); int num = -1; if ((Object)(object)chestFromTransform != (Object)null) { try { num = ((Hitable)chestFromTransform).GetId(); } catch (Exception) { num = -1; } } ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[MOB PROTECTION] Ataque contra Chest bloqueado. ChestID=" + num)); component.target = null; component.targetPlayerId = -1; return false; } catch (Exception ex2) { ((BaseUnityPlugin)Instance).Logger.LogError((object)"[MOB PROTECTION] Error en TryAttack:"); ((BaseUnityPlugin)Instance).Logger.LogError((object)ex2); return true; } } private bool IsChestTarget(Transform target) { if ((Object)(object)target == (Object)null) { return false; } if ((Object)(object)((Component)target).GetComponent() != (Object)null) { return true; } if ((Object)(object)((Component)target).GetComponentInChildren(true) != (Object)null) { return true; } if ((Object)(object)((Component)target).GetComponentInParent() != (Object)null) { return true; } return false; } private HitableChest GetChestFromTransform(Transform target) { if ((Object)(object)target == (Object)null) { return null; } HitableChest component = ((Component)target).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } component = ((Component)target).GetComponentInChildren(true); if ((Object)(object)component != (Object)null) { return component; } return ((Component)target).GetComponentInParent(); } private bool IsProtectedDeathChest(int objectId) { foreach (ProtectedChest protectedDeathChest in protectedDeathChests) { if (protectedDeathChest != null && protectedDeathChest.ObjectId == objectId) { return true; } } return false; } private bool ChestHasContents(Chest chest) { if ((Object)(object)chest == (Object)null) { return false; } if (chest.cells == null) { return false; } InventoryItem[] cells = chest.cells; foreach (InventoryItem val in cells) { if ((Object)(object)val != (Object)null && val.amount > 0) { return true; } } return false; } private static void ItemManagerDropItemPrefix(int fromClient, int itemId, int amount, int objectID) { if ((Object)(object)Instance == (Object)null) { return; } try { Instance.RegisterDrop(fromClient, itemId, amount, objectID); } catch (Exception ex) { ((BaseUnityPlugin)Instance).Logger.LogError((object)"ERROR capturando ItemManager.DropItem:"); ((BaseUnityPlugin)Instance).Logger.LogError((object)ex); } } private void RegisterDrop(int clientId, int itemId, int amount, int objectId) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (pendingDrops.TryGetValue(clientId, out var value)) { float num = realtimeSinceStartup - value.LastDropTime; if (num > 0.05f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP BATCH RESET] ClientID=" + clientId + " Gap=" + (num * 1000f).ToString("0.000") + "ms")); pendingDrops.Remove(clientId); value = null; } else { value.MultipleDrops = true; value.LastDropTime = realtimeSinceStartup; } } if (!pendingDrops.TryGetValue(clientId, out var value2)) { value2 = new DropBatch(clientId, realtimeSinceStartup); pendingDrops.Add(clientId, value2); } DroppedItem item = new DroppedItem(itemId, amount, objectId); value2.Items.Add(item); value2.LastDropTime = realtimeSinceStartup; string itemName = GetItemName(itemId); float num2 = realtimeSinceStartup - value2.FirstDropTime; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP] ClientID=" + clientId + " ItemID=" + itemId + " ItemName=\"" + itemName + "\" Amount=" + amount + " ObjectID=" + objectId + " BatchDrops=" + value2.Items.Count + " SinceFirstDrop=" + (num2 * 1000f).ToString("0.000") + "ms")); } private static void ServerPlayerDiedPostfix(int fromClient, Packet packet) { if ((Object)(object)Instance == (Object)null) { return; } try { Instance.ProcessDeath(fromClient); } catch (Exception ex) { ((BaseUnityPlugin)Instance).Logger.LogError((object)("ERROR procesando muerte de ClientID=" + fromClient + ":")); ((BaseUnityPlugin)Instance).Logger.LogError((object)ex); } } private void ProcessDeath(int clientId) { //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_0094: 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) float realtimeSinceStartup = Time.realtimeSinceStartup; ((BaseUnityPlugin)this).Logger.LogInfo((object)"========================================"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DEATH] ClientID=" + clientId)); Vector3 gravePosition; try { GameManager gameManager = GetGameManager(); if ((Object)(object)gameManager == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[DEATH] No se pudo obtener GameManager."); return; } gravePosition = gameManager.GetGravePosition(clientId); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"No se pudo obtener la posición de la tumba."); ((BaseUnityPlugin)this).Logger.LogError((object)ex); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DEATH] GravePosition=" + FormatVector3(gravePosition))); if (!pendingDrops.TryGetValue(clientId, out var value)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEATH] No existen drops pendientes para este jugador."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"========================================"); return; } float num = realtimeSinceStartup - value.FirstDropTime; float num2 = realtimeSinceStartup - value.LastDropTime; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DEATH] FirstDropAgo=" + (num * 1000f).ToString("0.000") + "ms")); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DEATH] LastDropAgo=" + (num2 * 1000f).ToString("0.000") + "ms")); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DEATH] Drops capturados=" + value.Items.Count)); if (!value.MultipleDrops) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEATH] Solo había un drop."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEATH] La tanda NO se considera Death Chest."); pendingDrops.Remove(clientId); ((BaseUnityPlugin)this).Logger.LogInfo((object)"========================================"); } else if (num > 2f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEATH] La tanda de drops es demasiado antigua."); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DEATH] Límite=" + 2f.ToString("0.00") + "s")); pendingDrops.Remove(clientId); ((BaseUnityPlugin)this).Logger.LogInfo((object)"========================================"); } else { PrintDeathChestPreview(clientId, value); CreateDeathChests(clientId, gravePosition, value, realtimeSinceStartup); pendingDrops.Remove(clientId); ((BaseUnityPlugin)this).Logger.LogInfo((object)"========================================"); } } private void PrintDeathChestPreview(int clientId, DropBatch batch) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"----------------------------------------"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("DEATH CHEST PREVIEW — ClientID=" + clientId)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Cantidad de items=" + batch.Items.Count)); for (int i = 0; i < batch.Items.Count; i++) { DroppedItem droppedItem = batch.Items[i]; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[" + i + "] ItemID=" + droppedItem.ItemId + " Name=\"" + GetItemName(droppedItem.ItemId) + "\" Amount=" + droppedItem.Amount + " ObjectID=" + droppedItem.ObjectId)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"----------------------------------------"); } private void CreateDeathChests(int clientId, Vector3 gravePosition, DropBatch batch, float deathTime) { //IL_00e3: 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_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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: 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_0142: 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_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: 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) //IL_0193: 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_01b3: Unknown result type (might be due to invalid IL or missing references) int num = FindChestItemId(); if (num < 0) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST] No se encontró un InventoryItem de tipo Storage con Chest."); return; } ItemManager itemManager = GetItemManager(); if ((Object)(object)itemManager == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST] No se pudo recuperar ItemManager."); return; } if (itemManager.allItems == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST] ItemManager.allItems es null."); return; } if (!itemManager.allItems.TryGetValue(num, out var value)) { ((BaseUnityPlugin)this).Logger.LogError((object)("[CHEST] ItemID=" + num + " no existe en ItemManager.allItems.")); return; } if ((Object)(object)value == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST] El InventoryItem Chest es null."); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[CHEST] Storage encontrado: ItemID=" + num + " Name=\"" + value.name + "\"")); Vector3 val = gravePosition + Vector3.up * 1f; int num2 = CreateChest(clientId, num, val); if (num2 < 0) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST] Falló la creación del Chest #1."); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[CHEST] Chest #1 creado. ObjectID=" + num2 + " Position=" + FormatVector3(val))); Vector3 val2 = val + Vector3.up * 2.75f; int num3 = CreateChest(clientId, num, val2); if (num3 < 0) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST] Falló la creación del Chest #2."); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[CHEST] Chest #2 creado. ObjectID=" + num3 + " Position=" + FormatVector3(val2))); try { ServerSend.SendBuild(clientId, num, num2, val, 0); ServerSend.SendBuild(clientId, num, num3, val2, 0); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[CHEST] SendBuild enviado para ambos cofres."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST] Error enviando SendBuild:"); ((BaseUnityPlugin)this).Logger.LogError((object)ex); return; } ((MonoBehaviour)this).StartCoroutine(FillChestsNextFrame(clientId, num2, num3, batch, deathTime)); } private int CreateChest(int clientId, int chestItemId, Vector3 position) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) try { ResourceManager resourceManager = GetResourceManager(); if ((Object)(object)resourceManager == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST] No se pudo recuperar ResourceManager."); return -1; } BuildManager buildManager = GetBuildManager(); if ((Object)(object)buildManager == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST] No se pudo recuperar BuildManager."); return -1; } int nextId = resourceManager.GetNextId(); GameObject val = buildManager.BuildItem(clientId, chestItemId, nextId, position, 0); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)("[CHEST] BuildItem devolvió null. ObjectID=" + nextId)); return -1; } Hitable val2 = val.GetComponent(); if ((Object)(object)val2 == (Object)null) { val2 = val.GetComponentInChildren(true); } if ((Object)(object)val2 != (Object)null) { int hp = val2.hp; int maxHp = val2.maxHp; Hitable obj = val2; obj.hp += 10000; Hitable obj2 = val2; obj2.maxHp += 10000; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[CHEST HP] ObjectID=" + nextId + " HP=" + hp + " -> " + val2.hp + " MaxHP=" + maxHp + " -> " + val2.maxHp)); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[CHEST HP] No se encontró Hitable para ObjectID=" + nextId)); } ProtectDeathChest(nextId, val); return nextId; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[CHEST] Error creando Chest: " + ex)); return -1; } } private void ProtectDeathChest(int objectId, GameObject chestObject) { if ((Object)(object)chestObject == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[STABILITY] ObjectID=" + objectId + " no tiene GameObject.")); return; } BuildDestruction val = chestObject.GetComponent(); if ((Object)(object)val == (Object)null) { val = chestObject.GetComponentInChildren(true); } if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[STABILITY] ObjectID=" + objectId + " no tiene BuildDestruction.")); protectedDeathChests.Enqueue(new ProtectedChest(objectId, null)); while (protectedDeathChests.Count > 16) { ProtectedChest protectedChest = protectedDeathChests.Dequeue(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[STABILITY] ObjectID=" + protectedChest.ObjectId + " dejó de estar dentro de los últimos " + 16 + " Death Chests protegidos.")); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[STABILITY] ObjectID=" + objectId + " protegido mediante ObjectID aunque no tenga BuildDestruction.")); return; } val.connectedToGround = true; val.directlyGrounded = true; protectedDeathChests.Enqueue(new ProtectedChest(objectId, val)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[STABILITY] Death Chest protegido. ObjectID=" + objectId + " ConnectedToGround=true DirectlyGrounded=true ProtectedCount=" + protectedDeathChests.Count)); while (protectedDeathChests.Count > 16) { ProtectedChest protectedChest2 = protectedDeathChests.Dequeue(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[STABILITY] ObjectID=" + protectedChest2.ObjectId + " dejó de estar dentro de los últimos " + 16 + " Death Chests protegidos.")); } } private void MaintainProtectedDeathChests() { if (protectedDeathChests.Count == 0) { return; } foreach (ProtectedChest protectedDeathChest in protectedDeathChests) { if (protectedDeathChest == null) { continue; } BuildDestruction buildDestruction = protectedDeathChest.BuildDestruction; if (!((Object)(object)buildDestruction == (Object)null)) { try { buildDestruction.connectedToGround = true; buildDestruction.directlyGrounded = true; } catch (Exception) { } } } } private IEnumerator FillChestsNextFrame(int clientId, int chestId1, int chestId2, DropBatch batch, float deathTime) { yield return null; ChestManager chestManager = GetChestManager(); if ((Object)(object)chestManager == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST CONTENT] No se pudo recuperar ChestManager."); yield break; } if (chestManager.chests == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST CONTENT] ChestManager.chests es null."); yield break; } if (!chestManager.chests.ContainsKey(chestId1)) { ((BaseUnityPlugin)this).Logger.LogError((object)("[CHEST CONTENT] Chest " + chestId1 + " no existe en ChestManager.")); yield break; } if (!chestManager.chests.ContainsKey(chestId2)) { ((BaseUnityPlugin)this).Logger.LogError((object)("[CHEST CONTENT] Chest " + chestId2 + " no existe en ChestManager.")); yield break; } List storedObjectIds = new List(); int num = 0; foreach (DroppedItem item in batch.Items) { int num2; int num3; if (num < 21) { num2 = chestId1; num3 = num; } else { int num4 = num - 21; if (num4 >= 21) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[CHEST CONTENT] No hay espacio para ItemID=" + item.ItemId + " Amount=" + item.Amount + " ObjectID=" + item.ObjectId + ". El item permanece como drop original.")); num++; continue; } num2 = chestId2; num3 = num4; } bool flag = false; try { chestManager.UpdateChest(num2, num3, item.ItemId, item.Amount); ServerSend.UpdateChest(clientId, num2, num3, item.ItemId, item.Amount); flag = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[CHEST CONTENT] ChestID=" + num2 + " Cell=" + num3 + " ItemID=" + item.ItemId + " Name=\"" + GetItemName(item.ItemId) + "\" Amount=" + item.Amount + " ObjectID=" + item.ObjectId)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[CHEST CONTENT] Error guardando ItemID=" + item.ItemId + " ObjectID=" + item.ObjectId + ":")); ((BaseUnityPlugin)this).Logger.LogError((object)ex); } if (flag) { storedObjectIds.Add(item.ObjectId); } num++; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[CHEST CONTENT] Finalizado. Items procesados=" + Math.Min(batch.Items.Count, 42) + " Items almacenados=" + storedObjectIds.Count)); float num5 = Time.realtimeSinceStartup - deathTime; float num6 = 0.5f - num5; if (num6 > 0f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP REMOVE] Esperando " + (num6 * 1000f).ToString("0.000") + "ms antes de eliminar los drops originales.")); yield return (object)new WaitForSeconds(num6); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP REMOVE] Iniciando eliminación. Tiempo desde muerte=" + ((Time.realtimeSinceStartup - deathTime) * 1000f).ToString("0.000") + "ms")); yield return ((MonoBehaviour)this).StartCoroutine(RemoveOriginalDropsWithRetries(clientId, storedObjectIds)); } private IEnumerator RemoveOriginalDropsWithRetries(int clientId, List objectIds) { if (objectIds == null || objectIds.Count == 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[DROP REMOVE] No hay drops para eliminar."); yield break; } HashSet uniqueObjectIds = new HashSet(objectIds); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP REMOVE] Objetos a eliminar=" + uniqueObjectIds.Count)); int removed = 0; int alreadyMissing = 0; int failed = 0; foreach (int objectId in uniqueObjectIds) { bool removedSuccessfully = false; bool neverFound = true; int totalAttempts = 3; for (int attempt = 0; attempt < totalAttempts; attempt++) { ItemManager itemManager = GetItemManager(); if ((Object)(object)itemManager == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[DROP REMOVE] Attempt=" + (attempt + 1) + "/" + totalAttempts + " ObjectID=" + objectId + " ItemManager no disponible.")); if (attempt < 2) { yield return (object)new WaitForSeconds(0.1f); } continue; } if (itemManager.list == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[DROP REMOVE] Attempt=" + (attempt + 1) + "/" + totalAttempts + " ObjectID=" + objectId + " ItemManager.list es null.")); if (attempt < 2) { yield return (object)new WaitForSeconds(0.1f); } continue; } if (!itemManager.list.ContainsKey(objectId)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[DROP REMOVE] Attempt=" + (attempt + 1) + "/" + totalAttempts + " ObjectID=" + objectId + " no existe.")); if (attempt < 2) { yield return (object)new WaitForSeconds(0.1f); } continue; } neverFound = false; try { if (itemManager.PickupItem(objectId)) { ServerSend.PickupItem(clientId, objectId); removedSuccessfully = true; removed++; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP REMOVE] ObjectID=" + objectId + " eliminado mediante ItemManager.PickupItem(). Attempt=" + (attempt + 1) + "/" + totalAttempts)); break; } ((BaseUnityPlugin)this).Logger.LogWarning((object)("[DROP REMOVE] Attempt=" + (attempt + 1) + "/" + totalAttempts + " ObjectID=" + objectId + " PickupItem devolvió false.")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[DROP REMOVE] Attempt=" + (attempt + 1) + "/" + totalAttempts + " ObjectID=" + objectId + " falló: " + ex.Message)); } if (attempt < 2) { yield return (object)new WaitForSeconds(0.1f); } } if (!removedSuccessfully) { if (neverFound) { alreadyMissing++; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[DROP REMOVE] ObjectID=" + objectId + " no apareció después de " + totalAttempts + " intentos.")); } else { failed++; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[DROP REMOVE] ObjectID=" + objectId + " no pudo eliminarse después de " + totalAttempts + " intentos.")); } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)"----------------------------------------"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP REMOVE] Resultado para ClientID=" + clientId)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP REMOVE] Objetos únicos=" + uniqueObjectIds.Count)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP REMOVE] Eliminados=" + removed)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP REMOVE] No encontrados=" + alreadyMissing)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP REMOVE] Fallidos=" + failed)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"----------------------------------------"); } private int FindChestItemId() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Invalid comparison between Unknown and I4 ItemManager itemManager = GetItemManager(); if ((Object)(object)itemManager == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST SEARCH] No se pudo recuperar ItemManager."); return -1; } if (itemManager.allItems == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[CHEST SEARCH] ItemManager.allItems es null."); return -1; } foreach (KeyValuePair allItem in itemManager.allItems) { InventoryItem value = allItem.Value; if (!((Object)(object)value == (Object)null) && (int)value.type == 6 && !((Object)(object)value.prefab == (Object)null) && (Object)(object)value.prefab.GetComponentInChildren(true) != (Object)null) { return allItem.Key; } } return -1; } private string GetItemName(int itemId) { try { ItemManager itemManager = GetItemManager(); if ((Object)(object)itemManager == (Object)null) { return ""; } if (itemManager.allItems == null) { return ""; } if (!itemManager.allItems.TryGetValue(itemId, out var value)) { return ""; } if ((Object)(object)value == (Object)null) { return ""; } return value.name; } catch (Exception) { return ""; } } private ItemManager GetItemManager() { //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_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) Scene scene; try { if ((Object)(object)ItemManager.Instance != (Object)null && (Object)(object)((Component)ItemManager.Instance).gameObject != (Object)null) { scene = ((Component)ItemManager.Instance).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return ItemManager.Instance; } } } catch (Exception) { } try { ItemManager[] array = Resources.FindObjectsOfTypeAll(); foreach (ItemManager val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return val; } } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[MANAGER] Error buscando ItemManager: " + ex2.Message)); } return null; } private ResourceManager GetResourceManager() { //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_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) Scene scene; try { if ((Object)(object)ResourceManager.Instance != (Object)null && (Object)(object)((Component)ResourceManager.Instance).gameObject != (Object)null) { scene = ((Component)ResourceManager.Instance).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return ResourceManager.Instance; } } } catch (Exception) { } try { ResourceManager[] array = Resources.FindObjectsOfTypeAll(); foreach (ResourceManager val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return val; } } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[MANAGER] Error buscando ResourceManager: " + ex2.Message)); } return null; } private BuildManager GetBuildManager() { //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_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) Scene scene; try { if ((Object)(object)BuildManager.Instance != (Object)null && (Object)(object)((Component)BuildManager.Instance).gameObject != (Object)null) { scene = ((Component)BuildManager.Instance).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return BuildManager.Instance; } } } catch (Exception) { } try { BuildManager[] array = Resources.FindObjectsOfTypeAll(); foreach (BuildManager val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return val; } } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[MANAGER] Error buscando BuildManager: " + ex2.Message)); } return null; } private ChestManager GetChestManager() { //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_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) Scene scene; try { if ((Object)(object)ChestManager.Instance != (Object)null && (Object)(object)((Component)ChestManager.Instance).gameObject != (Object)null) { scene = ((Component)ChestManager.Instance).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return ChestManager.Instance; } } } catch (Exception) { } try { ChestManager[] array = Resources.FindObjectsOfTypeAll(); foreach (ChestManager val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return val; } } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[MANAGER] Error buscando ChestManager: " + ex2.Message)); } return null; } private GameManager GetGameManager() { //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_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) Scene scene; try { if ((Object)(object)GameManager.instance != (Object)null && (Object)(object)((Component)GameManager.instance).gameObject != (Object)null) { scene = ((Component)GameManager.instance).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return GameManager.instance; } } } catch (Exception) { } try { GameManager[] array = Resources.FindObjectsOfTypeAll(); foreach (GameManager val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return val; } } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[MANAGER] Error buscando GameManager: " + ex2.Message)); } return null; } private void Update() { MaintainProtectedDeathChests(); if (pendingDrops.Count == 0) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; List list = new List(); foreach (KeyValuePair pendingDrop in pendingDrops) { DropBatch value = pendingDrop.Value; if (realtimeSinceStartup - value.FirstDropTime > 2f) { list.Add(pendingDrop.Key); } } foreach (int item in list) { if (pendingDrops.TryGetValue(item, out var value2)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[DROP CLEANUP] ClientID=" + item + " Drops=" + value2.Items.Count + " No apareció una muerte dentro de " + 2f.ToString("0.00") + "s.")); } pendingDrops.Remove(item); } } private string FormatVector3(Vector3 position) { return "(" + position.x.ToString("0.00") + ", " + position.y.ToString("0.00") + ", " + position.z.ToString("0.00") + ")"; } private void OnDestroy() { try { if (harmony != null) { harmony.UnpatchSelf(); } pendingDrops.Clear(); protectedDeathChests.Clear(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error durante cleanup: " + ex)); } } }