using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BoarderArmorStandStats")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Azumatt")]
[assembly: AssemblyProduct("BoarderArmorStandStats")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyFileVersion("1.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 BoarderArmorStandStats
{
public interface ITransientContainer
{
bool SuppressPersistence { get; }
void OnContainerDropRequested();
}
public class ArmourStandBridge : Container, ITransientContainer
{
internal ArmorStand? ArmourStand;
private SlotTypeMap? _acceptedTypes;
private int _syncedItemCount;
private static readonly string[] ContainerRpcEndpoints = new string[6] { "RequestOpen", "OpenRespons", "RPC_RequestStack", "RPC_StackResponse", "RequestTakeAll", "TakeAllRespons" };
public bool ViewingInventory
{
get
{
if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.instance.m_currentContainer == this)
{
return InventoryGui.IsVisible();
}
return false;
}
}
public bool SuppressPersistence => true;
public void OnContainerDropRequested()
{
Inventory inventory = ((Container)this).GetInventory();
if (inventory != null)
{
inventory.RemoveAll();
}
}
private void Awake()
{
if (ArmourStand == null)
{
ArmourStand = ((Component)this).GetComponent<ArmorStand>();
}
if ((Object)(object)ArmourStand == (Object)null)
{
throw new InvalidOperationException("No ArmorStand attached to " + ((Object)this).name);
}
base.m_name = ArmourStand.m_name;
base.m_width = ArmourStand.m_slots.Count;
base.m_height = 1;
Switch componentInChildren = ((Component)this).GetComponentInChildren<Switch>();
if ((Object)(object)componentInChildren != (Object)null)
{
componentInChildren.m_name = ArmourStand.m_name;
}
((Container)this).Awake();
if (ZNetView.m_forceDisableInit)
{
Object.Destroy((Object)(object)this);
return;
}
Inventory inventory = ((Container)this).GetInventory();
inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(SyncToFigure));
_acceptedTypes = SlotTypeMap.BuildFrom(ArmourStand);
}
private void OnDestroy()
{
DetachRpcHandlers();
BridgeRegistry.Deregister(this);
}
private void DetachRpcHandlers()
{
if (!((Object)(object)base.m_nview == (Object)null))
{
string[] containerRpcEndpoints = ContainerRpcEndpoints;
foreach (string text in containerRpcEndpoints)
{
base.m_nview.Unregister(text);
}
}
}
internal static string SlotItemKey(int slotIndex)
{
return $"{slotIndex}_item";
}
private void SyncToFigure()
{
if (ViewingInventory)
{
PushToAmourStand();
}
}
public void PullFromArmourStandIfChanged()
{
if ((Object)(object)ArmourStand == (Object)null)
{
return;
}
int nrOfAttachedItems = ArmourStand.GetNrOfAttachedItems();
int num = base.m_inventory.NrOfItems();
if (nrOfAttachedItems == num && _syncedItemCount == nrOfAttachedItems)
{
return;
}
base.m_loading = true;
base.m_inventory.RemoveAll();
ZDO zDO = base.m_nview.GetZDO();
for (int i = 0; i < ArmourStand.m_slots.Count; i++)
{
string @string = zDO.GetString(SlotItemKey(i), "");
if (!string.IsNullOrEmpty(@string))
{
ItemData val = HydrateFromZdo(@string, i);
if (val != null)
{
base.m_inventory.AddItem(val);
}
}
}
_syncedItemCount = base.m_inventory.NrOfItems();
base.m_loading = false;
}
private void PushToAmourStand()
{
if ((Object)(object)ArmourStand == (Object)null)
{
return;
}
int nrOfAttachedItems = ArmourStand.GetNrOfAttachedItems();
int num = base.m_inventory.NrOfItems();
if (nrOfAttachedItems == num && _syncedItemCount == num)
{
return;
}
WipeAllSlots();
foreach (ItemData allItem in base.m_inventory.GetAllItems())
{
int x = allItem.m_gridPos.x;
WriteSlot(allItem, x);
}
ArmourStand.UpdateVisual();
ArmourStand.UpdateSupports();
_syncedItemCount = num;
}
private void WipeAllSlots()
{
if ((Object)(object)ArmourStand == (Object)null)
{
return;
}
ZDO zDO = base.m_nview.GetZDO();
bool flag = base.m_nview.IsOwner();
for (int i = 0; i < ArmourStand.m_slots.Count; i++)
{
if (flag)
{
zDO.Set(SlotItemKey(i), "");
}
ArmourStand.SetVisualItem(i, "", 0);
}
}
private void WriteSlot(ItemData piece, int slot)
{
if (!((Object)(object)ArmourStand == (Object)null) && piece != null && slot >= 0 && slot < ArmourStand.m_slots.Count && base.m_nview.IsOwner())
{
ArmorStandSlot val = ArmourStand.m_slots[slot];
if (ArmourStand.CanAttach(val, piece))
{
ZDO zDO = base.m_nview.GetZDO();
zDO.Set(SlotItemKey(slot), ((Object)piece.m_dropPrefab).name);
ItemDrop.SaveToZDO(slot, piece, zDO);
}
}
}
internal ItemData? HydrateFromZdo(string prefabId, int zdoIndex = -1)
{
if (string.IsNullOrEmpty(prefabId))
{
return null;
}
GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabId);
if ((Object)(object)itemPrefab == (Object)null)
{
return null;
}
ItemDrop val = default(ItemDrop);
if (!itemPrefab.TryGetComponent<ItemDrop>(ref val))
{
return null;
}
ItemData val2 = val.m_itemData.Clone();
if (zdoIndex >= 0)
{
ItemDrop.LoadFromZDO(zdoIndex, val2, base.m_nview.GetZDO());
}
return val2;
}
public void RelocateToSlot(ItemData? piece)
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: 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_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: 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)
//IL_007c: 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_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)ArmourStand == (Object)null || piece == null)
{
return;
}
int num = LocateCompatibleSlot(piece, allowOccupied: true);
if (num < 0)
{
BoarderArmorStandStatsPlugin.BoarderArmorStandStatsPluginLogger.LogWarning((object)("No compatible slot for " + piece.m_shared.m_name));
return;
}
Vector2i val = default(Vector2i);
((Vector2i)(ref val))..ctor(num, 0);
if (!(piece.m_gridPos == val))
{
ItemData itemAt = base.m_inventory.GetItemAt(val.x, val.y);
if (itemAt != null && itemAt != piece)
{
Vector2i gridPos = piece.m_gridPos;
piece.m_gridPos = val;
itemAt.m_gridPos = gridPos;
}
else
{
piece.m_gridPos = val;
}
base.m_inventory.Changed();
}
}
public AttachmentCheck ValidateAttachment(ItemData piece, int targetSlot, bool isInternal)
{
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)ArmourStand == (Object)null || piece == null)
{
return AttachmentCheck.Deny("Invalid context");
}
if (!isInternal)
{
foreach (ItemData allItem in base.m_inventory.GetAllItems())
{
if (allItem.m_shared.m_itemType == piece.m_shared.m_itemType)
{
return AttachmentCheck.Deny($"Duplicate {piece.m_shared.m_itemType} type");
}
}
}
if (targetSlot >= 0 && targetSlot < ArmourStand.m_slots.Count)
{
ArmorStandSlot val = ArmourStand.m_slots[targetSlot];
if (!isInternal && ArmourStand.HaveAttachment(targetSlot))
{
return AttachmentCheck.Deny("Position taken");
}
if (!ArmourStand.CanAttach(val, piece))
{
return AttachmentCheck.Deny($"{piece.m_shared.m_itemType} cannot attach here");
}
return AttachmentCheck.Permit();
}
if (LocateCompatibleSlot(piece, isInternal) < 0)
{
return AttachmentCheck.Deny($"No attach point for {piece.m_shared.m_itemType}");
}
return AttachmentCheck.Permit();
}
private int LocateCompatibleSlot(ItemData? piece, bool allowOccupied)
{
if ((Object)(object)ArmourStand == (Object)null || piece == null)
{
return -1;
}
SlotTypeMap? acceptedTypes = _acceptedTypes;
if (acceptedTypes != null && acceptedTypes.HasEntries)
{
foreach (KeyValuePair<int, ItemType> entry in _acceptedTypes.Entries)
{
int key = entry.Key;
if ((allowOccupied || !ArmourStand.HaveAttachment(key)) && ArmourStand.CanAttach(ArmourStand.m_slots[key], piece))
{
return key;
}
}
}
for (int i = 0; i < ArmourStand.m_slots.Count; i++)
{
if ((allowOccupied || !ArmourStand.HaveAttachment(i)) && ArmourStand.CanAttach(ArmourStand.m_slots[i], piece))
{
return i;
}
}
return -1;
}
public void NotifyUser(string text = "")
{
if (!((Object)(object)Player.m_localPlayer == (Object)null))
{
((Character)Player.m_localPlayer).Message((MessageType)2, string.IsNullOrEmpty(text) ? "$piece_armorstand_cantattach" : text, 0, (Sprite)null);
}
}
}
internal class SlotTypeMap
{
public Dictionary<int, ItemType> Entries { get; } = new Dictionary<int, ItemType>();
public bool HasEntries => Entries.Count > 0;
public static SlotTypeMap BuildFrom(ArmorStand figure)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
SlotTypeMap slotTypeMap = new SlotTypeMap();
if ((Object)(object)figure == (Object)null)
{
return slotTypeMap;
}
for (int i = 0; i < figure.m_slots.Count; i++)
{
ArmorStandSlot val = figure.m_slots[i];
List<ItemType> supportedTypes = val.m_supportedTypes;
if (supportedTypes != null && supportedTypes.Count > 0)
{
slotTypeMap.Entries[i] = val.m_supportedTypes[0];
}
}
return slotTypeMap;
}
}
public readonly struct AttachmentCheck
{
public bool Allowed { get; }
public string Message { get; }
private AttachmentCheck(bool allowed, string message)
{
Allowed = allowed;
Message = message;
}
public static AttachmentCheck Permit()
{
return new AttachmentCheck(allowed: true, "");
}
public static AttachmentCheck Deny(string message)
{
return new AttachmentCheck(allowed: false, message);
}
}
public class EquipmentMetrics
{
public float TotalArmor;
public float TotalWeight;
public float MovementPenalty;
public readonly Dictionary<DamageType, float> Resistances = new Dictionary<DamageType, float>();
public readonly List<string> ArmorBreakdown = new List<string>();
public readonly Dictionary<string, int> SetCounts = new Dictionary<string, int>();
}
internal static class BridgeRegistry
{
private static ArmourStandBridge?[] _table = new ArmourStandBridge[64];
private static bool[] _isTombstone = new bool[64];
private static int _population;
private static int ComputeSlot(Inventory inv)
{
return (((object)inv).GetHashCode() & 0x7FFFFFFF) % _table.Length;
}
public static void Register(ArmourStandBridge bridge)
{
Inventory inventory = ((Container)bridge).GetInventory();
if (inventory == null)
{
return;
}
int num = ComputeSlot(inventory);
int num2 = -1;
for (int i = 0; i < _table.Length; i++)
{
int num3 = (num + i) % _table.Length;
if (_isTombstone[num3] && num2 < 0)
{
num2 = num3;
continue;
}
if ((Object)(object)_table[num3] == (Object)null && !_isTombstone[num3])
{
int num4 = ((num2 >= 0) ? num2 : num3);
_table[num4] = bridge;
_isTombstone[num4] = false;
_population++;
if ((float)_population > (float)_table.Length * 0.7f)
{
Expand();
}
return;
}
if (!_isTombstone[num3])
{
ArmourStandBridge? obj = _table[num3];
if (((obj != null) ? ((Container)obj).GetInventory() : null) == inventory)
{
_table[num3] = bridge;
return;
}
}
}
if (num2 >= 0)
{
_table[num2] = bridge;
_isTombstone[num2] = false;
_population++;
if ((float)_population > (float)_table.Length * 0.7f)
{
Expand();
}
}
}
public static void Deregister(ArmourStandBridge bridge)
{
Inventory inventory = ((Container)bridge).GetInventory();
if (inventory == null)
{
for (int i = 0; i < _table.Length; i++)
{
if (_table[i] == bridge)
{
_table[i] = null;
_isTombstone[i] = true;
_population = Math.Max(0, _population - 1);
break;
}
}
return;
}
int num = ComputeSlot(inventory);
for (int j = 0; j < _table.Length; j++)
{
int num2 = (num + j) % _table.Length;
if ((Object)(object)_table[num2] == (Object)null && !_isTombstone[num2])
{
break;
}
if (!_isTombstone[num2] && _table[num2] == bridge)
{
_table[num2] = null;
_isTombstone[num2] = true;
_population = Math.Max(0, _population - 1);
break;
}
}
}
public static bool Resolve(Inventory? inv, out ArmourStandBridge bridge)
{
bridge = null;
if (inv == null)
{
return false;
}
int num = ComputeSlot(inv);
for (int i = 0; i < _table.Length; i++)
{
int num2 = (num + i) % _table.Length;
if ((Object)(object)_table[num2] == (Object)null && !_isTombstone[num2])
{
return false;
}
if (!_isTombstone[num2])
{
ArmourStandBridge armourStandBridge = _table[num2];
if (!((Object)(object)armourStandBridge == (Object)null) && ((Container)armourStandBridge).GetInventory() == inv)
{
bridge = armourStandBridge;
return true;
}
}
}
return false;
}
public static void Reset()
{
Array.Clear(_table, 0, _table.Length);
Array.Clear(_isTombstone, 0, _isTombstone.Length);
_population = 0;
}
private static void Expand()
{
ArmourStandBridge[] table = _table;
bool[] isTombstone = _isTombstone;
_table = new ArmourStandBridge[table.Length * 2];
_isTombstone = new bool[table.Length * 2];
_population = 0;
for (int i = 0; i < table.Length; i++)
{
if ((Object)(object)table[i] != (Object)null && !isTombstone[i])
{
Register(table[i]);
}
}
}
}
[HarmonyPatch(typeof(ZNetScene), "Awake")]
internal static class AddMannequinBridgeComponentToArmorStand
{
private static void Postfix(ZNetScene __instance)
{
GameObject prefab = __instance.GetPrefab("ArmorStand");
if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent<ArmourStandBridge>() != (Object)null))
{
prefab.AddComponent<ArmourStandBridge>();
}
}
}
[HarmonyPatch(typeof(Container))]
internal static class BridgeLifecycleHooks
{
[HarmonyPostfix]
[HarmonyPatch("Awake")]
private static void AfterAwake(Container __instance)
{
if (__instance is ArmourStandBridge bridge)
{
BridgeRegistry.Register(bridge);
}
}
}
[HarmonyPatch(typeof(Container))]
internal static class TransientContainerInterceptor
{
[HarmonyPrefix]
[HarmonyPatch("Save")]
private static bool InterceptSave(Container __instance)
{
return !(__instance is ITransientContainer transientContainer) || !transientContainer.SuppressPersistence;
}
[HarmonyPrefix]
[HarmonyPatch("DropAllItems", new Type[] { })]
private static bool InterceptDrop(Container __instance)
{
if (!(__instance is ITransientContainer transientContainer))
{
return true;
}
transientContainer.OnContainerDropRequested();
return false;
}
}
[HarmonyPatch(typeof(Game), "Start")]
internal static class SessionBoundaryHandler
{
private static void Prefix()
{
BridgeRegistry.Reset();
GridCellRenderer.InvalidateCache();
}
}
[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
internal static class ItemInsertionValidator
{
[HarmonyPriority(800)]
private static bool Prefix(Inventory __instance, ItemData item, ref bool __result)
{
if (!BridgeRegistry.Resolve(__instance, out ArmourStandBridge bridge))
{
return true;
}
if (item.m_stack != 1)
{
bridge.NotifyUser("Armor stands only accept single items");
__result = false;
return false;
}
AttachmentCheck attachmentCheck = bridge.ValidateAttachment(item, -1, isInternal: false);
if (attachmentCheck.Allowed || !bridge.ViewingInventory)
{
return true;
}
BoarderArmorStandStatsPlugin.BoarderArmorStandStatsPluginLogger.LogDebug((object)("Rejected " + item.m_shared.m_name + ": " + attachmentCheck.Message));
bridge.NotifyUser(attachmentCheck.Message);
__result = false;
return false;
}
[HarmonyPriority(800)]
private static void Postfix(Inventory __instance, ItemData item, bool __result)
{
if (__result && BridgeRegistry.Resolve(__instance, out ArmourStandBridge bridge))
{
bridge.RelocateToSlot(item);
}
}
}
[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
internal static class DragDropInterceptor
{
[HarmonyPriority(800)]
private static bool Prefix(InventoryGui __instance, InventoryGrid grid, Modifier mod, Vector2i pos)
{
//IL_002a: 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)
if (!(__instance.m_currentContainer is ArmourStandBridge armourStandBridge))
{
return true;
}
Player localPlayer = Player.m_localPlayer;
if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting())
{
return true;
}
if ((int)mod != 0)
{
return true;
}
ItemData dragItem = __instance.m_dragItem;
if (dragItem == null)
{
return true;
}
Inventory inventory = grid.GetInventory();
Inventory inventory2 = ((Container)armourStandBridge).GetInventory();
if (inventory != inventory2)
{
return true;
}
__instance.m_dragAmount = 1;
bool isInternal = __instance.m_dragInventory == inventory2;
AttachmentCheck attachmentCheck = armourStandBridge.ValidateAttachment(dragItem, pos.x, isInternal);
if (attachmentCheck.Allowed)
{
return true;
}
armourStandBridge.NotifyUser(attachmentCheck.Message);
__instance.m_dragAmount = dragItem.m_stack;
return false;
}
}
[HarmonyPatch(typeof(InventoryGui), "Show")]
internal static class ContainerOpenHook
{
private static void Postfix(Container container)
{
if (container is ArmourStandBridge armourStandBridge)
{
armourStandBridge.PullFromArmourStandIfChanged();
}
}
}
[HarmonyPatch(typeof(Switch), "Interact")]
internal static class InteractionRouter
{
private static bool Prefix(Switch __instance, Humanoid character, bool hold, bool alt, ref bool __result)
{
if (!BoarderArmorStandStatsPlugin.EnableContainerFeature.Value)
{
return true;
}
Player localPlayer = Player.m_localPlayer;
if ((Object)(object)localPlayer == (Object)null)
{
return true;
}
Player val = (Player)(object)((character is Player) ? character : null);
if (val != null && (Object)(object)val != (Object)(object)localPlayer)
{
return true;
}
GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
if ((Object)(object)hoverObject == (Object)null)
{
return true;
}
ArmorStand componentInParent = hoverObject.GetComponentInParent<ArmorStand>();
if ((Object)(object)componentInParent == (Object)null)
{
return true;
}
ArmourStandBridge armourStandBridge = default(ArmourStandBridge);
if (!((Component)componentInParent).TryGetComponent<ArmourStandBridge>(ref armourStandBridge))
{
return true;
}
if (!((Container)armourStandBridge).m_nview.IsOwner())
{
((Container)armourStandBridge).m_nview.ClaimOwnership();
}
if (alt && !hold)
{
__result = true;
return true;
}
armourStandBridge.PullFromArmourStandIfChanged();
InventoryGui.instance.Show((Container)(object)armourStandBridge, 1);
__result = true;
return false;
}
}
[HarmonyPatch(typeof(ArmorStand), "UseItem")]
internal static class HotbarInteractionBlock
{
private static bool Prefix(ArmorStand __instance, ref bool __result)
{
ArmourStandBridge armourStandBridge = default(ArmourStandBridge);
if (!((Component)__instance).TryGetComponent<ArmourStandBridge>(ref armourStandBridge))
{
return true;
}
if (((Container)armourStandBridge).IsInUse())
{
__result = false;
return false;
}
if (!BoarderArmorStandStatsPlugin.EnableContainerFeature.Value)
{
return true;
}
bool button;
if (ZInput.IsNonClassicFunctionality() && ZInput.IsGamepadActive())
{
button = ZInput.GetButton("JoyAltKeys");
}
else
{
if (ZInput.GetButton("AltPlace"))
{
goto IL_005c;
}
button = ZInput.GetButton("JoyAltPlace");
}
if (!button)
{
__result = false;
return false;
}
goto IL_005c;
IL_005c:
return true;
}
}
[HarmonyPatch(typeof(ArmorStand), "UpdateVisual")]
internal static class VisualSyncHook
{
private static void Postfix(ArmorStand __instance)
{
ArmourStandBridge armourStandBridge = default(ArmourStandBridge);
if (((Component)__instance).TryGetComponent<ArmourStandBridge>(ref armourStandBridge) && !armourStandBridge.ViewingInventory)
{
armourStandBridge.PullFromArmourStandIfChanged();
}
}
}
[HarmonyPatch(typeof(Switch), "GetHoverText")]
internal static class HoverTextEnhancer
{
private static void Postfix(Switch __instance, ref string __result)
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
ArmorStand componentInParent = ((Component)__instance).GetComponentInParent<ArmorStand>();
if ((Object)(object)componentInParent == (Object)null || (Object)(object)__instance == (Object)(object)componentInParent.m_changePoseSwitch || !BoarderArmorStandStatsPlugin.EnableContainerFeature.Value)
{
return;
}
__result = "";
if (PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, false, false))
{
string text = __instance.m_name + "\n[<color=yellow><b>$KEY_Use</b></color>] $piece_container_open";
if (componentInParent.GetNrOfAttachedItems() > 0)
{
text += "\n[<color=yellow><b>L.Shift + $KEY_Use</b></color>] $piece_itemstand_take";
}
__result = Localization.instance.Localize(text);
string text2 = HoverInfoGenerator.Generate(componentInParent);
if (!string.IsNullOrEmpty(text2))
{
__result += Localization.instance.Localize(text2);
}
}
else
{
__result = Localization.instance.Localize(__instance.m_name + "\n$piece_noaccess");
}
}
}
[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
internal static class GridVisualEnhancer
{
private static void Postfix(InventoryGrid __instance)
{
if (__instance.m_inventory == null || !BridgeRegistry.Resolve(__instance.m_inventory, out ArmourStandBridge bridge))
{
return;
}
for (int i = 0; i < __instance.m_elements.Count; i++)
{
Element val = __instance.m_elements[i];
if (!((Object)(object)val?.m_go == (Object)null))
{
GridCellRenderer.Render(val, i, bridge);
}
}
}
}
[BepInPlugin("Azumatt.BoarderArmorStandStats", "BoarderArmorStandStats", "1.1.0")]
public class BoarderArmorStandStatsPlugin : BaseUnityPlugin
{
internal const string ModName = "BoarderArmorStandStats";
internal const string ModVersion = "1.1.0";
internal const string Author = "Azumatt";
private const string ModGUID = "Azumatt.BoarderArmorStandStats";
private static string ConfigFileName = "Azumatt.BoarderArmorStandStats.cfg";
private static string ConfigFileFullPath;
internal static string ConnectionError;
private readonly Harmony _harmony = new Harmony("Azumatt.BoarderArmorStandStats");
public static readonly ManualLogSource BoarderArmorStandStatsPluginLogger;
private static ConfigEntry<bool> _serverConfigLocked;
public static ConfigEntry<bool> EnableContainerFeature;
public void Awake()
{
_serverConfigLocked = config("1 - General", "Lock Configuration", value: true, "If on, the configuration is locked and can be changed by server admins only.");
EnableContainerFeature = config("2 - Container", "Enable Container Feature", value: true, "Enable opening armor stands as containers (E opens container, Shift+E for normal interaction)");
Assembly executingAssembly = Assembly.GetExecutingAssembly();
_harmony.PatchAll(executingAssembly);
SetupWatcher();
}
private void OnDestroy()
{
((BaseUnityPlugin)this).Config.Save();
}
private void SetupWatcher()
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
fileSystemWatcher.Changed += ReadConfigValues;
fileSystemWatcher.Created += ReadConfigValues;
fileSystemWatcher.Renamed += ReadConfigValues;
fileSystemWatcher.IncludeSubdirectories = true;
fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
fileSystemWatcher.EnableRaisingEvents = true;
}
private void ReadConfigValues(object sender, FileSystemEventArgs e)
{
if (!File.Exists(ConfigFileFullPath))
{
return;
}
try
{
BoarderArmorStandStatsPluginLogger.LogDebug((object)"ReadConfigValues called");
((BaseUnityPlugin)this).Config.Reload();
}
catch
{
BoarderArmorStandStatsPluginLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
BoarderArmorStandStatsPluginLogger.LogError((object)"Please check your config entries for spelling and format!");
}
}
private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
return ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
}
private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Expected O, but got Unknown
return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
}
static BoarderArmorStandStatsPlugin()
{
string configPath = Paths.ConfigPath;
char directorySeparatorChar = Path.DirectorySeparatorChar;
ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
ConnectionError = "";
BoarderArmorStandStatsPluginLogger = Logger.CreateLogSource("BoarderArmorStandStats");
_serverConfigLocked = null;
EnableContainerFeature = null;
}
}
internal static class GridCellRenderer
{
private const string PlaceholderTag = "EquipHint";
private static Sprite[]? _iconCache;
public static void Render(Element cell, int position, ArmourStandBridge bridge)
{
if ((Object)(object)cell?.m_go == (Object)null || (Object)(object)bridge?.ArmourStand == (Object)null)
{
return;
}
CellStateTracker component = cell.m_go.GetComponent<CellStateTracker>();
if (((Behaviour)cell.m_icon).enabled)
{
RemoveHint(cell.m_go);
string @string = ((Container)bridge).m_nview.GetZDO().GetString(ArmourStandBridge.SlotItemKey(position), "");
if (!string.IsNullOrEmpty(@string))
{
ItemData equipment = bridge.HydrateFromZdo(@string, position);
ApplyWearIndicator(cell.m_go, component, equipment);
}
else
{
ClearWearIndicator(cell.m_go, component);
}
}
else
{
ClearWearIndicator(cell.m_go, component);
ShowHint(cell.m_go, position, bridge);
}
}
private static void ApplyWearIndicator(GameObject host, CellStateTracker? tracker, ItemData? equipment)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: 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_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: 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_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: 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)
Button val = default(Button);
if (host.TryGetComponent<Button>(ref val))
{
if (tracker == null)
{
tracker = host.AddComponent<CellStateTracker>();
}
if (!tracker.capturedOriginal)
{
tracker.baseColors = ((Selectable)val).colors;
tracker.capturedOriginal = true;
}
if (equipment == null || !equipment.m_shared.m_useDurability)
{
((Selectable)val).colors = tracker.baseColors;
return;
}
Color val2 = DeriveConditionColor(equipment.GetDurabilityPercentage());
ColorBlock baseColors = tracker.baseColors;
((ColorBlock)(ref baseColors)).normalColor = ((ColorBlock)(ref baseColors)).normalColor + val2;
((ColorBlock)(ref baseColors)).highlightedColor = ((ColorBlock)(ref baseColors)).highlightedColor + val2;
((Selectable)val).colors = baseColors;
}
}
private static void ClearWearIndicator(GameObject host, CellStateTracker? tracker)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
Button val = default(Button);
if (host.TryGetComponent<Button>(ref val) && (Object)(object)tracker != (Object)null && tracker.capturedOriginal)
{
((Selectable)val).colors = tracker.baseColors;
}
}
private static Color DeriveConditionColor(float ratio)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: 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_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_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)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
if (!(ratio >= 0.75f))
{
if (!(ratio >= 0.5f))
{
if (ratio >= 0.25f)
{
return new Color(0.6f, 0.3f, 0f, 0.4f);
}
return new Color(0.6f, 0f, 0f, 0.5f);
}
return new Color(0.5f, 0.5f, 0f, 0.35f);
}
return new Color(0f, 0.5f, 0f, 0.3f);
}
private static void ShowHint(GameObject host, int position, ArmourStandBridge bridge)
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: 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_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: 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_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)host.transform.Find("EquipHint") != (Object)null))
{
Sprite val = ResolveIconForPosition(position, bridge);
if (!((Object)(object)val == (Object)null))
{
GameObject val2 = new GameObject("EquipHint");
val2.transform.SetParent(host.transform, false);
val2.transform.SetAsFirstSibling();
RectTransform obj = val2.AddComponent<RectTransform>();
obj.anchorMin = Vector2.zero;
obj.anchorMax = Vector2.one;
obj.offsetMin = Vector2.zero;
obj.offsetMax = Vector2.zero;
Image obj2 = val2.AddComponent<Image>();
obj2.sprite = val;
((Graphic)obj2).color = new Color(1f, 1f, 1f, 0.5f);
((Graphic)obj2).raycastTarget = false;
}
}
}
private static void RemoveHint(GameObject host)
{
Transform val = host.transform.Find("EquipHint");
if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)((Component)val).gameObject);
}
}
private static Sprite? ResolveIconForPosition(int position, ArmourStandBridge bridge)
{
if ((Object)(object)bridge.ArmourStand == (Object)null)
{
return null;
}
if (position >= bridge.ArmourStand.m_slots.Count)
{
return null;
}
if (_iconCache == null)
{
_iconCache = (Sprite[]?)(object)new Sprite[8];
}
if (position < _iconCache.Length && (Object)(object)_iconCache[position] != (Object)null)
{
return _iconCache[position];
}
ArmorStandSlot val = bridge.ArmourStand.m_slots[position];
if ((Object)(object)ObjectDB.instance == (Object)null)
{
return null;
}
ItemDrop val2 = default(ItemDrop);
foreach (GameObject item in ObjectDB.instance.m_items)
{
if ((Object)(object)item == (Object)null || !item.TryGetComponent<ItemDrop>(ref val2) || val2.m_itemData == null || !bridge.ArmourStand.CanAttach(val, val2.m_itemData))
{
continue;
}
try
{
Sprite[] array = val2.m_itemData.m_shared?.m_icons;
if (array == null || array.Length <= 0)
{
continue;
}
Sprite val3 = array[0];
if (position < _iconCache.Length)
{
_iconCache[position] = val3;
}
return val3;
}
catch (Exception ex)
{
BoarderArmorStandStatsPlugin.BoarderArmorStandStatsPluginLogger.LogWarning((object)("Icon extraction failed for " + ((Object)item).name + ": " + ex.Message));
}
}
return null;
}
public static void InvalidateCache()
{
_iconCache = null;
}
}
internal class CellStateTracker : MonoBehaviour
{
public ColorBlock baseColors;
public bool capturedOriginal;
public CellStateTracker(ColorBlock baseColors, bool capturedOriginal)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
this.baseColors = baseColors;
this.capturedOriginal = capturedOriginal;
((MonoBehaviour)this)..ctor();
}
}
public static class HoverInfoGenerator
{
public static string Generate(ArmorStand figure)
{
if ((Object)(object)figure?.m_nview == (Object)null)
{
return "";
}
List<ItemData> list = GatherEquipment(figure);
if (list.Count == 0)
{
return "";
}
EquipmentMetrics figure2 = ComputeMetrics(list);
EquipmentMetrics player = ComputePlayerMetrics();
return FormatOutput(figure2, player);
}
private static List<ItemData> GatherEquipment(ArmorStand figure)
{
List<ItemData> list = new List<ItemData>();
ZDO zDO = figure.m_nview.GetZDO();
ItemDrop val2 = default(ItemDrop);
for (int i = 0; i < figure.m_slots.Count; i++)
{
string text = ((zDO != null) ? zDO.GetString(ArmourStandBridge.SlotItemKey(i), "") : null);
if (!string.IsNullOrEmpty(text))
{
ObjectDB instance = ObjectDB.instance;
GameObject val = ((instance != null) ? instance.GetItemPrefab(text) : null);
if (!((Object)(object)val == (Object)null) && val.TryGetComponent<ItemDrop>(ref val2))
{
ItemData val3 = val2.m_itemData.Clone();
ItemDrop.LoadFromZDO(i, val3, zDO);
list.Add(val3);
}
}
}
return list;
}
private static EquipmentMetrics ComputeMetrics(List<ItemData> equipment)
{
//IL_00b3: 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_00ba: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: 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)
EquipmentMetrics equipmentMetrics = new EquipmentMetrics();
foreach (ItemData item in equipment)
{
if (item.m_shared.m_armor > 0f)
{
float armor = item.GetArmor();
equipmentMetrics.TotalArmor += armor;
equipmentMetrics.ArmorBreakdown.Add(Localization.instance.Localize($" {item.m_shared.m_name}: {armor:F0}"));
}
equipmentMetrics.TotalWeight += item.GetWeight(-1);
equipmentMetrics.MovementPenalty += item.m_shared.m_movementModifier;
foreach (DamageModPair damageModifier in item.m_shared.m_damageModifiers)
{
float num = ConvertModifier(damageModifier.m_modifier);
if (!equipmentMetrics.Resistances.ContainsKey(damageModifier.m_type))
{
equipmentMetrics.Resistances[damageModifier.m_type] = 0f;
}
equipmentMetrics.Resistances[damageModifier.m_type] += num;
}
if (!string.IsNullOrEmpty(item.m_shared.m_setName))
{
if (!equipmentMetrics.SetCounts.ContainsKey(item.m_shared.m_setName))
{
equipmentMetrics.SetCounts[item.m_shared.m_setName] = 0;
}
equipmentMetrics.SetCounts[item.m_shared.m_setName]++;
}
}
return equipmentMetrics;
}
private static EquipmentMetrics? ComputePlayerMetrics()
{
Player localPlayer = Player.m_localPlayer;
if ((Object)(object)localPlayer == (Object)null)
{
return null;
}
List<ItemData> list = new List<ItemData>();
foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
{
if (allItem.m_equipped && allItem.IsEquipable())
{
list.Add(allItem);
}
}
if (list.Count <= 0)
{
return null;
}
return ComputeMetrics(list);
}
private static float ConvertModifier(DamageModifier mod)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected I4, but got Unknown
return (mod - 1) switch
{
0 => 50f,
4 => 75f,
2 => 100f,
1 => -50f,
5 => -100f,
_ => 0f,
};
}
private static string FormatOutput(EquipmentMetrics figure, EquipmentMetrics? player)
{
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Unknown result type (might be due to invalid IL or missing references)
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("\n\n");
stringBuilder.Append($"\n<color=white>$item_armor: {figure.TotalArmor:F0}</color>");
WriteDelta(stringBuilder, figure.TotalArmor, player?.TotalArmor ?? 0f, higherIsBetter: true);
stringBuilder.Append($"\n<color=white>$item_weight: {figure.TotalWeight:F1}</color>");
WriteDelta(stringBuilder, figure.TotalWeight, player?.TotalWeight ?? 0f, higherIsBetter: false);
if (figure.MovementPenalty != 0f || (player?.MovementPenalty ?? 0f) != 0f)
{
float num = figure.MovementPenalty * 100f;
stringBuilder.Append($"\n<color=white>$item_movement_modifier: {num:+0;-0}%</color>");
if (player != null)
{
WriteDelta(stringBuilder, num, player.MovementPenalty * 100f, higherIsBetter: true, "%");
}
}
if (figure.Resistances.Count > 0)
{
stringBuilder.Append("\n<color=#FFA500>Resistances:</color>");
foreach (KeyValuePair<DamageType, float> resistance in figure.Resistances)
{
string arg = ((resistance.Value >= 0f) ? "white" : "#FF4444");
stringBuilder.Append($" {resistance.Key}:<color={arg}>{resistance.Value:+0;-0}%</color>");
if (player != null && player.Resistances.TryGetValue(resistance.Key, out var value))
{
float num2 = resistance.Value - value;
if (num2 != 0f)
{
string arg2 = ((num2 > 0f) ? "#00FF00" : "#FF4444");
stringBuilder.Append($"<color={arg2}>({num2:+0;-0})</color>");
}
}
}
}
if (figure.SetCounts.Count <= 0)
{
return stringBuilder.ToString();
}
stringBuilder.Append("\n<color=#BB88FF>Set:</color>");
foreach (KeyValuePair<string, int> setCount in figure.SetCounts)
{
stringBuilder.Append($" {Localization.instance.Localize(setCount.Key)} x{setCount.Value}");
}
return stringBuilder.ToString();
}
private static void WriteDelta(StringBuilder output, float figureVal, float playerVal, bool higherIsBetter, string suffix = "")
{
if (playerVal != 0f)
{
float num = figureVal - playerVal;
if (num != 0f)
{
string text = ((higherIsBetter ? (num > 0f) : (num < 0f)) ? "#00FF00" : "#FF4444");
string format = ((suffix == "%") ? "{0:+0;-0}%" : ((suffix == "" && figureVal < 10f) ? "{0:+0.0;-0.0}" : "{0:+0;-0}"));
output.Append(" <color=" + text + ">(" + string.Format(format, num) + ")</color>");
}
}
}
}
}