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 DynamicStorage Ammunition Piles v1.0.1
plugins/DynamicStorageAmmunitionPiles.dll
Decompiled 4 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("DynamicStorageAmmunitionPiles")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DynamicStorageAmmunitionPiles")] [assembly: AssemblyTitle("DynamicStorageAmmunitionPiles")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DynamicStorageAmmunitionPiles { public sealed class AmmunitionBarrelAppearance : MonoBehaviour { private const string ZdoScaleKey = "DSAP.Appearance.Scale"; private const string ZdoHeightOffsetKey = "DSAP.Appearance.HeightOffset"; private const string ZdoLooksFullAtKey = "DSAP.Appearance.LooksFullAt"; private const string ZdoAmmoModelScaleKey = "DSAP.Appearance.AmmoModelScale"; private const string ZdoFillBasisKey = "DSAP.Appearance.FillBasis"; internal const string DefaultLooksFullAt = "50%"; internal const string DefaultFillBasis = "Occupied Slots"; internal const float DefaultAmmoModelScale = 0.8f; internal static readonly string[] LooksFullAtOptions = new string[5] { "25%", "50%", "75%", "100%", "Always Full" }; internal static readonly string[] FillBasisOptions = new string[2] { "Occupied Slots", "Storage Capacity" }; [SerializeField] private Vector3 baseScale = Vector3.one; private ZNetView nview; private AmmunitionBarrelFamily family; private bool applied; private float nextCheck; private float currentScaleMultiplier = 1f; private float currentHeightOffset; private float currentAmmoModelScale = 0.8f; private string currentFillBasis = "Occupied Slots"; private string currentLooksFullAt = "50%"; private bool pendingPlacementSnapshot; private float pendingScale; private float pendingHeightOffset; private float pendingAmmoModelScale; private string pendingFillBasis; private string pendingLooksFullAt; private float pendingDeadline; private float startedAt; internal float CurrentScaleMultiplier => currentScaleMultiplier; internal float CurrentHeightOffset => currentHeightOffset; internal float CurrentAmmoModelScale => currentAmmoModelScale; internal string CurrentFillBasis => NormalizeFillBasis(currentFillBasis); internal string CurrentLooksFullAt => NormalizeLooksFullAt(currentLooksFullAt); internal AmmunitionKind FamilyKind { get { if (!Object.op_Implicit((Object)(object)family)) { return AmmunitionKind.Arrow; } return family.Kind; } } internal void Setup(Vector3 originalBaseScale) { //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) baseScale = originalBaseScale; } private void Start() { startedAt = Time.time; nview = ((Component)this).GetComponent<ZNetView>(); family = ((Component)this).GetComponent<AmmunitionBarrelFamily>(); ApplyOrSave(); } private void Update() { if (!applied && !(Time.unscaledTime < nextCheck)) { nextCheck = Time.unscaledTime + 0.25f; ApplyOrSave(); } } private BarrelAppearanceTemplate CurrentTemplate() { if (!Object.op_Implicit((Object)(object)family)) { family = ((Component)this).GetComponent<AmmunitionBarrelFamily>(); } DynamicStorageAmmunitionPilesPlugin current = DynamicStorageAmmunitionPilesPlugin.Current; if ((Object)(object)current != (Object)null) { return current.GetAppearanceTemplate(Object.op_Implicit((Object)(object)family) ? family.Kind : AmmunitionKind.Arrow); } return new BarrelAppearanceTemplate(1f, 0f, 0.8f, "Occupied Slots", "50%"); } private void ApplyOrSave() { if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!Object.op_Implicit((Object)(object)family)) { family = ((Component)this).GetComponent<AmmunitionBarrelFamily>(); } if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid() || nview.GetZDO() == null) { return; } if (pendingPlacementSnapshot) { TryCommitPendingPlacementSnapshot(); } BarrelAppearanceTemplate barrelAppearanceTemplate = CurrentTemplate(); ZDO zDO = nview.GetZDO(); float num = zDO.GetFloat("DSAP.Appearance.Scale", -1f); bool flag = num > 0f; float num2 = zDO.GetFloat("DSAP.Appearance.HeightOffset", float.NaN); bool flag2 = !float.IsNaN(num2); float num3 = zDO.GetFloat("DSAP.Appearance.AmmoModelScale", -1f); bool flag3 = num3 > 0f; string text = zDO.GetString("DSAP.Appearance.FillBasis", ""); bool flag4 = !string.IsNullOrEmpty(text); string text2 = zDO.GetString("DSAP.Appearance.LooksFullAt", ""); bool flag5 = !string.IsNullOrEmpty(text2); if ((!flag || !flag2 || !flag3 || !flag4 || !flag5) && nview.IsOwner()) { if (!flag) { num = barrelAppearanceTemplate.BarrelScale; zDO.Set("DSAP.Appearance.Scale", num); } if (!flag2) { num2 = barrelAppearanceTemplate.HeightOffset; zDO.Set("DSAP.Appearance.HeightOffset", num2); } if (!flag3) { num3 = barrelAppearanceTemplate.AmmoModelScale; zDO.Set("DSAP.Appearance.AmmoModelScale", num3); } if (!flag4) { text = NormalizeFillBasis(barrelAppearanceTemplate.FillBasis); zDO.Set("DSAP.Appearance.FillBasis", text); } if (!flag5) { if (Time.time - startedAt < 1f && !pendingPlacementSnapshot) { return; } text2 = NormalizeLooksFullAt(barrelAppearanceTemplate.LooksFullAt); zDO.Set("DSAP.Appearance.LooksFullAt", text2); } } if (num <= 0f) { num = barrelAppearanceTemplate.BarrelScale; } if (float.IsNaN(num2)) { num2 = barrelAppearanceTemplate.HeightOffset; } if (num3 <= 0f) { num3 = barrelAppearanceTemplate.AmmoModelScale; } text = NormalizeFillBasis(string.IsNullOrEmpty(text) ? barrelAppearanceTemplate.FillBasis : text); text2 = NormalizeLooksFullAt(string.IsNullOrEmpty(text2) ? barrelAppearanceTemplate.LooksFullAt : text2); ApplyAppearance(num, num2, num3, text, text2); applied = true; } internal void SavePlacementDefaults() { BarrelAppearanceTemplate barrelAppearanceTemplate = CurrentTemplate(); pendingScale = barrelAppearanceTemplate.BarrelScale; pendingHeightOffset = barrelAppearanceTemplate.HeightOffset; pendingAmmoModelScale = barrelAppearanceTemplate.AmmoModelScale; pendingFillBasis = barrelAppearanceTemplate.FillBasis; pendingLooksFullAt = barrelAppearanceTemplate.LooksFullAt; pendingPlacementSnapshot = true; pendingDeadline = Time.time + 15f; applied = false; TryCommitPendingPlacementSnapshot(); } private bool TryCommitPendingPlacementSnapshot() { if (!pendingPlacementSnapshot) { return false; } if (Time.time > pendingDeadline) { Logger.LogWarning((object)(((Object)((Component)this).gameObject).name + ": Ammunition Barrel placement appearance snapshot timed out before ZDO ownership became ready.")); pendingPlacementSnapshot = false; return false; } if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid() || nview.GetZDO() == null || !nview.IsOwner()) { return false; } ZDO zDO = nview.GetZDO(); zDO.Set("DSAP.Appearance.Scale", Mathf.Clamp(pendingScale, 0.5f, 3f)); zDO.Set("DSAP.Appearance.HeightOffset", Mathf.Clamp(pendingHeightOffset, -2f, 2f)); zDO.Set("DSAP.Appearance.AmmoModelScale", Mathf.Clamp(pendingAmmoModelScale, 0.35f, 2.5f)); zDO.Set("DSAP.Appearance.FillBasis", NormalizeFillBasis(pendingFillBasis)); zDO.Set("DSAP.Appearance.LooksFullAt", NormalizeLooksFullAt(pendingLooksFullAt)); pendingPlacementSnapshot = false; Logger.LogInfo((object)(((Object)((Component)this).gameObject).name + ": saved per-barrel scale/height/ammo-model/fill-basis/looks-full-at placement snapshot.")); return true; } internal void ApplyPlacementPreview(float scaleMultiplier) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) scaleMultiplier = Mathf.Clamp(scaleMultiplier, 0.5f, 3f); currentScaleMultiplier = scaleMultiplier; ((Component)this).transform.localScale = new Vector3(baseScale.x * scaleMultiplier, baseScale.y * scaleMultiplier, baseScale.z * scaleMultiplier); } internal bool ApplyCurrentTemplateFromConfig(out string result) { //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: 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_0169: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!Object.op_Implicit((Object)(object)family)) { family = ((Component)this).GetComponent<AmmunitionBarrelFamily>(); } if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid() || nview.GetZDO() == null) { result = "Placed barrel has no writable ZDO."; return false; } if (!nview.IsOwner()) { result = "Cannot apply: this client is not the ZDO owner."; return false; } BarrelAppearanceTemplate barrelAppearanceTemplate = CurrentTemplate(); float num = Mathf.Clamp(barrelAppearanceTemplate.BarrelScale, 0.5f, 3f); float num2 = Mathf.Clamp(barrelAppearanceTemplate.HeightOffset, -2f, 2f); float num3 = Mathf.Clamp(barrelAppearanceTemplate.AmmoModelScale, 0.35f, 2.5f); string text = NormalizeFillBasis(barrelAppearanceTemplate.FillBasis); string text2 = NormalizeLooksFullAt(barrelAppearanceTemplate.LooksFullAt); float num4 = num2 - currentHeightOffset; ZDO zDO = nview.GetZDO(); zDO.Set("DSAP.Appearance.Scale", num); zDO.Set("DSAP.Appearance.HeightOffset", num2); zDO.Set("DSAP.Appearance.AmmoModelScale", num3); zDO.Set("DSAP.Appearance.FillBasis", text); zDO.Set("DSAP.Appearance.LooksFullAt", text2); if (Mathf.Abs(num4) > 0.0001f) { Transform transform = ((Component)this).transform; transform.position += Vector3.up * num4; try { zDO.SetPosition(((Component)this).transform.position); } catch (Exception ex) { Logger.LogWarning((object)(((Object)((Component)this).gameObject).name + ": applied height offset locally but could not write ZDO position: " + ex.Message)); } } ApplyAppearance(num, num2, num3, text, text2); applied = true; string text3 = AmmunitionCatalog.FamilyDisplayName(FamilyKind); result = "Applied current " + text3 + " barrel appearance configuration."; Logger.LogInfo((object)(((Object)((Component)this).gameObject).name + ": " + result)); return true; } private void ApplyAppearance(float scaleMultiplier, float heightOffset, float ammoModelScale, string fillBasis, string looksFullAt) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) scaleMultiplier = Mathf.Clamp(scaleMultiplier, 0.5f, 3f); currentScaleMultiplier = scaleMultiplier; currentHeightOffset = Mathf.Clamp(heightOffset, -2f, 2f); currentAmmoModelScale = Mathf.Clamp(ammoModelScale, 0.35f, 2.5f); currentFillBasis = NormalizeFillBasis(fillBasis); currentLooksFullAt = NormalizeLooksFullAt(looksFullAt); ((Component)this).transform.localScale = new Vector3(baseScale.x * scaleMultiplier, baseScale.y * scaleMultiplier, baseScale.z * scaleMultiplier); AmmunitionBarrelVisual component = ((Component)this).GetComponent<AmmunitionBarrelVisual>(); AmmunitionBarrelStorage component2 = ((Component)this).GetComponent<AmmunitionBarrelStorage>(); if (Object.op_Implicit((Object)(object)component)) { component.Refresh(Object.op_Implicit((Object)(object)component2) ? component2.AssignedPrefabName : null, Object.op_Implicit((Object)(object)component2) ? component2.StoredCount : 0); } } internal static string NormalizeFillBasis(string value) { if (string.Equals(value, "Occupied Slots", StringComparison.OrdinalIgnoreCase)) { return "Occupied Slots"; } if (string.Equals(value, "Stored Ammo Count", StringComparison.OrdinalIgnoreCase)) { return "Occupied Slots"; } if (string.Equals(value, "Stored Ammunition Count", StringComparison.OrdinalIgnoreCase)) { return "Occupied Slots"; } if (string.Equals(value, "Stored Item Count", StringComparison.OrdinalIgnoreCase)) { return "Occupied Slots"; } string.Equals(value, "Occupied Slots", StringComparison.OrdinalIgnoreCase); return "Occupied Slots"; } internal static string NormalizeLooksFullAt(string value) { if (string.Equals(value, "25%", StringComparison.OrdinalIgnoreCase)) { return "25%"; } if (string.Equals(value, "75%", StringComparison.OrdinalIgnoreCase)) { return "75%"; } if (string.Equals(value, "100%", StringComparison.OrdinalIgnoreCase)) { return "100%"; } if (string.Equals(value, "Always Full", StringComparison.OrdinalIgnoreCase)) { return "Always Full"; } return "50%"; } internal static float LooksFullFraction(string value) { value = NormalizeLooksFullAt(value); return value switch { "25%" => 0.25f, "75%" => 0.75f, "100%" => 1f, "Always Full" => 0f, _ => 0.5f, }; } } internal static class AmmunitionBarrelAppearanceEditorPatches { private static int lastApplyFrame = -1; internal static bool Install(Harmony harmony) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown if (harmony == null) { return false; } MethodInfo methodInfo = AccessTools.Method(typeof(Container), "GetHoverText", Type.EmptyTypes, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(AmmunitionBarrelAppearanceEditorPatches), "GetHoverTextPostfix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Logger.LogWarning((object)"Container.GetHoverText() not found; Ammunition Barrel appearance editor is unavailable."); return false; } try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } catch (Exception ex) { Logger.LogWarning((object)("Could not install Ammunition Barrel appearance editor hover: " + ex.Message)); return false; } } private static void GetHoverTextPostfix(Container __instance, ref string __result) { try { DynamicStorageAmmunitionPilesPlugin current = DynamicStorageAmmunitionPilesPlugin.Current; if ((Object)(object)current == (Object)null || !current.AppearanceEditorEnabled || !Object.op_Implicit((Object)(object)__instance)) { return; } AmmunitionBarrelAppearance component = ((Component)__instance).GetComponent<AmmunitionBarrelAppearance>(); if (!Object.op_Implicit((Object)(object)component)) { return; } if (Input.GetKeyDown((KeyCode)114) && Time.frameCount != lastApplyFrame) { lastApplyFrame = Time.frameCount; string result; bool num = component.ApplyCurrentTemplateFromConfig(out result); Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { ((Character)localPlayer).Message((MessageType)2, result, 0, (Sprite)null, false); } if (!num) { Logger.LogWarning((object)(((Object)((Component)__instance).gameObject).name + ": appearance editor apply rejected: " + result)); } } __result += BuildEditorHoverText(component); } catch (Exception ex) { Logger.LogWarning((object)("Ammunition Barrel appearance editor hover failed: " + ex.Message)); } } private static string BuildEditorHoverText(AmmunitionBarrelAppearance appearance) { if (!Object.op_Implicit((Object)(object)appearance)) { return string.Empty; } string text = FamilyTitle(appearance.FamilyKind); DynamicStorageAmmunitionPilesPlugin current = DynamicStorageAmmunitionPilesPlugin.Current; int num = (((Object)(object)current != (Object)null) ? current.BarrelStorageCapacity : 20); return "\n<color=#5EC8FF><b>BARREL APPEARANCE EDITOR</b></color>\n<color=#AAB4BC>" + text.ToUpperInvariant() + "</color>\n<color=#8AD7FF>Barrel scale:</color> <color=#FFFFFF>" + appearance.CurrentScaleMultiplier.ToString("0.##") + "</color>\n<color=#8AD7FF>Ammo model:</color> <color=#FFFFFF>" + appearance.CurrentAmmoModelScale.ToString("0.##") + "</color>\n<color=#8AD7FF>Height offset:</color> <color=#FFFFFF>" + FormatSigned(appearance.CurrentHeightOffset) + "</color>\n<color=#8AD7FF>Visual fill:</color> <color=#FFFFFF>" + appearance.CurrentFillBasis + " · " + appearance.CurrentLooksFullAt + "</color>\n<color=#8AD7FF>Server capacity:</color> <color=#FFFFFF>" + num + " slots</color>\n<color=#FFD166><b>[R]</b></color> <color=#AAB4BC>Apply current " + text + " config</color>"; } private static string FamilyTitle(AmmunitionKind kind) { return kind switch { AmmunitionKind.CrossbowBolt => "Bolt Barrel", AmmunitionKind.BallistaMissile => "Missile Barrel", _ => "Arrow Barrel", }; } private static string FormatSigned(float value) { if (Mathf.Abs(value) < 0.0005f) { return "0"; } if (!(value > 0f)) { return value.ToString("0.###"); } return "+" + value.ToString("0.###"); } } public sealed class AmmunitionBarrelCapacity : MonoBehaviour { private static readonly HashSet<AmmunitionBarrelCapacity> Active = new HashSet<AmmunitionBarrelCapacity>(); private static readonly FieldInfo InventoryWidth = AccessTools.Field(typeof(Inventory), "m_width"); private static readonly FieldInfo InventoryHeight = AccessTools.Field(typeof(Inventory), "m_height"); private Container container; private Inventory inventory; private float nextRefresh; private int lastAppliedCapacity = -1; private int lastBlockedCapacity = -1; private void OnEnable() { Active.Add(this); nextRefresh = 0f; } private void OnDisable() { Active.Remove(this); } private void OnDestroy() { Active.Remove(this); } private void Start() { ApplyConfiguredCapacity(force: true); } private void Update() { if (!(Time.unscaledTime < nextRefresh)) { nextRefresh = Time.unscaledTime + 0.5f; ApplyConfiguredCapacity(force: false); } } internal static void RefreshAll() { AmmunitionBarrelCapacity[] array = new AmmunitionBarrelCapacity[Active.Count]; Active.CopyTo(array); AmmunitionBarrelCapacity[] array2 = array; foreach (AmmunitionBarrelCapacity ammunitionBarrelCapacity in array2) { if (Object.op_Implicit((Object)(object)ammunitionBarrelCapacity)) { ammunitionBarrelCapacity.ApplyConfiguredCapacity(force: true); ammunitionBarrelCapacity.RefreshVisualFill(); } } } internal void ApplyConfiguredCapacity(bool force) { DynamicStorageAmmunitionPilesPlugin current = DynamicStorageAmmunitionPilesPlugin.Current; if ((Object)(object)current == (Object)null) { return; } int barrelStorageCapacity = current.BarrelStorageCapacity; if (!force && barrelStorageCapacity == lastAppliedCapacity) { return; } if (!Object.op_Implicit((Object)(object)container)) { container = ((Component)this).GetComponent<Container>(); } if (!Object.op_Implicit((Object)(object)container)) { return; } Inventory val = container.GetInventory(); if (val != null) { inventory = val; } DynamicStorageAmmunitionPilesPlugin.GetStorageGrid(barrelStorageCapacity, out var width, out var height); if (inventory == null) { container.m_width = width; container.m_height = height; return; } int num = ReadDimension(InventoryWidth, inventory, container.m_width); int num2 = ReadDimension(InventoryHeight, inventory, container.m_height); if (width * height < num * num2 && !ItemsFit(width, height)) { container.m_width = num; container.m_height = num2; if (lastBlockedCapacity != barrelStorageCapacity) { lastBlockedCapacity = barrelStorageCapacity; Logger.LogWarning((object)$"{((Object)((Component)this).gameObject).name}: Ammunition Barrel capacity reduction to {barrelStorageCapacity} slots deferred because existing items do not fit."); } return; } lastBlockedCapacity = -1; bool num3 = num != width || num2 != height || container.m_width != width || container.m_height != height; container.m_width = width; container.m_height = height; WriteDimension(InventoryWidth, inventory, width); WriteDimension(InventoryHeight, inventory, height); lastAppliedCapacity = barrelStorageCapacity; if (!num3) { return; } List<ItemData> allItems = inventory.GetAllItems(); int num4 = allItems?.Count ?? 0; int num5 = 0; if (allItems != null) { foreach (ItemData item in allItems) { if (item != null) { num5 += item.m_stack; } } } Logger.LogInfo((object)($"{((Object)((Component)this).gameObject).name}: Ammunition Barrel grid resized {num}x{num2} -> " + $"{width}x{height} without Inventory.Changed notification; " + $"contents={num4} stack(s), {num5} item(s).")); } private void RefreshVisualFill() { AmmunitionBarrelStorage component = ((Component)this).GetComponent<AmmunitionBarrelStorage>(); AmmunitionBarrelVisual component2 = ((Component)this).GetComponent<AmmunitionBarrelVisual>(); if (Object.op_Implicit((Object)(object)component2)) { component2.Refresh(Object.op_Implicit((Object)(object)component) ? component.AssignedPrefabName : null, Object.op_Implicit((Object)(object)component) ? component.StoredCount : 0); } } private bool ItemsFit(int width, int height) { if (inventory == null) { return true; } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null) { return true; } foreach (ItemData item in allItems) { if (item != null && (item.m_gridPos.x < 0 || item.m_gridPos.y < 0 || item.m_gridPos.x >= width || item.m_gridPos.y >= height)) { return false; } } return true; } private static int ReadDimension(FieldInfo field, Inventory target, int fallback) { if (field == null || target == null) { return fallback; } try { return (int)field.GetValue(target); } catch { return fallback; } } private static void WriteDimension(FieldInfo field, Inventory target, int value) { if (field == null || target == null) { return; } try { field.SetValue(target, value); } catch (Exception ex) { Logger.LogWarning((object)("Ammunition Barrel inventory dimension update failed: " + ex.Message)); } } } internal static class AmmunitionBarrelCapacityPatches { private static bool installed; internal static bool Install(Harmony harmony) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown if (installed) { return true; } MethodInfo methodInfo = AccessTools.Method(typeof(Container), "Awake", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(AmmunitionBarrelCapacityPatches), "ContainerAwakePrefix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { return false; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); installed = true; return true; } private static void ContainerAwakePrefix(Container __instance) { if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<AmmunitionBarrelCapacity>())) { DynamicStorageAmmunitionPilesPlugin.GetStorageGrid(60, out var width, out var height); __instance.m_width = width; __instance.m_height = height; } } } public sealed class AmmunitionBarrelFamily : MonoBehaviour { [SerializeField] private AmmunitionKind kind; internal AmmunitionKind Kind => kind; internal void Setup(AmmunitionKind value) { kind = value; } } internal struct BarrelAppearanceTemplate { internal float BarrelScale; internal float HeightOffset; internal float AmmoModelScale; internal string FillBasis; internal string LooksFullAt; internal BarrelAppearanceTemplate(float barrelScale, float heightOffset, float ammoModelScale, string fillBasis, string looksFullAt) { BarrelScale = barrelScale; HeightOffset = heightOffset; AmmoModelScale = ammoModelScale; FillBasis = fillBasis; LooksFullAt = looksFullAt; } } public sealed class AmmunitionBarrelStorage : MonoBehaviour { private const string ZdoAssignedKey = "DSAP.AssignedAmmo"; private static readonly Dictionary<Inventory, AmmunitionBarrelStorage> Registry = new Dictionary<Inventory, AmmunitionBarrelStorage>(); private Container container; private Inventory inventory; private ZNetView nview; private AmmunitionBarrelFamily family; private string assignedPrefab; private int storedCount; private int occupiedSlotCount; private float nextRefresh; private bool mixedWarningShown; private float lastRejectMessageTime = -10f; internal string AssignedPrefabName => assignedPrefab; internal int StoredCount => storedCount; internal int OccupiedSlotCount => occupiedSlotCount; internal AmmunitionKind AllowedKind { get { if (!Object.op_Implicit((Object)(object)family)) { return AmmunitionKind.Arrow; } return family.Kind; } } internal Container Container { get { if (!Object.op_Implicit((Object)(object)container)) { return container = ((Component)this).GetComponent<Container>(); } return container; } } private void OnEnable() { nextRefresh = 0f; } private void Start() { container = ((Component)this).GetComponent<Container>(); nview = ((Component)this).GetComponent<ZNetView>(); family = ((Component)this).GetComponent<AmmunitionBarrelFamily>(); RefreshState(forceVisual: true); } private void Update() { if (!(Time.unscaledTime < nextRefresh)) { nextRefresh = Time.unscaledTime + 0.2f; RefreshState(forceVisual: false); } } private void OnDisable() { UnregisterInventory(); } private void OnDestroy() { UnregisterInventory(); } private void RefreshState(bool forceVisual) { if (!Object.op_Implicit((Object)(object)container)) { container = ((Component)this).GetComponent<Container>(); } if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!Object.op_Implicit((Object)(object)family)) { family = ((Component)this).GetComponent<AmmunitionBarrelFamily>(); } if (!Object.op_Implicit((Object)(object)container)) { return; } Inventory val = container.GetInventory(); if (inventory != val) { UnregisterInventory(); inventory = val; if (inventory != null) { Registry[inventory] = this; } } bool mixed; int count; int usedSlots; string text = ResolveAssignmentFromInventory(out mixed, out count, out usedSlots); string text2 = ReadAssignedFromZdo(); string b = ((!string.IsNullOrEmpty(text)) ? text : text2); if (inventory != null && inventory.GetAllItems().Count == 0) { b = null; count = 0; usedSlots = 0; } if (mixed && !mixedWarningShown) { mixedWarningShown = true; Logger.LogWarning((object)(((Object)((Component)this).gameObject).name + ": multiple ammunition types were already present. New inserts will be restricted to the first detected type until the barrel is emptied.")); } if (!mixed) { mixedWarningShown = false; } bool num = !string.Equals(assignedPrefab, b, StringComparison.Ordinal); bool flag = storedCount != count; bool flag2 = occupiedSlotCount != usedSlots; assignedPrefab = b; storedCount = count; occupiedSlotCount = usedSlots; if (Object.op_Implicit((Object)(object)nview) && nview.IsValid() && nview.IsOwner() && nview.GetZDO() != null) { string a = nview.GetZDO().GetString("DSAP.AssignedAmmo", ""); string text3 = assignedPrefab ?? ""; if (!string.Equals(a, text3, StringComparison.Ordinal)) { nview.GetZDO().Set("DSAP.AssignedAmmo", text3); } } if (num || flag || flag2 || forceVisual) { AmmunitionBarrelVisual component = ((Component)this).GetComponent<AmmunitionBarrelVisual>(); if (Object.op_Implicit((Object)(object)component)) { component.Refresh(assignedPrefab, storedCount); } } } private string ReadAssignedFromZdo() { if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid() || nview.GetZDO() == null) { return null; } string text = nview.GetZDO().GetString("DSAP.AssignedAmmo", ""); if (!AmmunitionCatalog.IsSupported(text)) { return null; } return text; } private string ResolveAssignmentFromInventory(out bool mixed, out int count, out int usedSlots) { mixed = false; count = 0; usedSlots = 0; if (inventory == null) { return null; } string text = null; foreach (ItemData allItem in inventory.GetAllItems()) { string text2 = AmmunitionCatalog.PrefabName(allItem); if (!string.IsNullOrEmpty(text2)) { if (text == null) { text = text2; } else if (!string.Equals(text, text2, StringComparison.Ordinal)) { mixed = true; } if (string.Equals(text, text2, StringComparison.Ordinal)) { count += Mathf.Max(0, allItem.m_stack); usedSlots++; } } } return text; } internal bool Allows(ItemData item) { if (item == null) { return true; } return AllowsPrefab(AmmunitionCatalog.PrefabName(item)); } internal bool AllowsPrefab(GameObject prefab) { if (Object.op_Implicit((Object)(object)prefab)) { return AllowsPrefab(((Object)prefab).name); } return false; } internal bool AllowsPrefab(string prefabName) { prefabName = AmmunitionCatalog.NormalizePrefabName(prefabName); if (!AmmunitionCatalog.IsSupported(prefabName)) { return false; } if (!AmmunitionCatalog.TryGetKind(prefabName, out var kind) || kind != AllowedKind) { return false; } bool mixed; int count; int usedSlots; string text = ResolveAssignmentFromInventory(out mixed, out count, out usedSlots); if (string.IsNullOrEmpty(text)) { text = assignedPrefab; } if (!string.IsNullOrEmpty(text)) { return string.Equals(text, prefabName, StringComparison.Ordinal); } return true; } internal void NotifyRejected(string attemptedPrefab) { if (Time.unscaledTime - lastRejectMessageTime < 0.6f) { return; } lastRejectMessageTime = Time.unscaledTime; string text = AmmunitionCatalog.FamilyDisplayName(AllowedKind); string text2; if (!AmmunitionCatalog.IsSupported(attemptedPrefab) || !AmmunitionCatalog.TryGetKind(attemptedPrefab, out var kind) || kind != AllowedKind) { text2 = "This barrel only accepts " + text + "."; } else { bool mixed; int count; int usedSlots; string text3 = ResolveAssignmentFromInventory(out mixed, out count, out usedSlots); if (string.IsNullOrEmpty(text3)) { text3 = assignedPrefab; } string text4 = AmmunitionCatalog.DisplayName(text3); text2 = (string.IsNullOrEmpty(text4) ? "This barrel already contains a different ammunition type." : ("This barrel can only hold " + text4 + ".")); } Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { ((Character)localPlayer).Message((MessageType)2, text2, 0, (Sprite)null, false); } } private void UnregisterInventory() { if (inventory != null) { if (Registry.TryGetValue(inventory, out var value) && (Object)(object)value == (Object)(object)this) { Registry.Remove(inventory); } inventory = null; } } internal static AmmunitionBarrelStorage ForInventory(Inventory target) { if (target == null) { return null; } if (!Registry.TryGetValue(target, out var value)) { return null; } return value; } } internal static class AmmunitionBarrelInventoryPatches { internal static bool Install(Harmony harmony) { if (harmony == null) { return false; } return (byte)(1u & (PatchPrefix(harmony, AccessTools.Method(typeof(Inventory), "CanAddItem", new Type[2] { typeof(ItemData), typeof(int) }, (Type[])null), "CanAddItemData") ? 1u : 0u) & (PatchPrefix(harmony, AccessTools.Method(typeof(Inventory), "CanAddItem", new Type[2] { typeof(GameObject), typeof(int) }, (Type[])null), "CanAddPrefab") ? 1u : 0u) & (PatchPrefix(harmony, AccessTools.Method(typeof(Inventory), "AddItem", new Type[1] { typeof(ItemData) }, (Type[])null), "AddItemData") ? 1u : 0u) & (PatchPrefix(harmony, AccessTools.Method(typeof(Inventory), "AddItem", new Type[5] { typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool) }, (Type[])null), "AddItemAt") ? 1u : 0u) & (PatchPrefix(harmony, AccessTools.Method(typeof(Inventory), "MoveItemToThis", new Type[2] { typeof(Inventory), typeof(ItemData) }, (Type[])null), "MoveItemToThisSimple") ? 1u : 0u) & (PatchPrefix(harmony, AccessTools.Method(typeof(Inventory), "MoveItemToThis", new Type[5] { typeof(Inventory), typeof(ItemData), typeof(int), typeof(int), typeof(int) }, (Type[])null), "MoveItemToThisAt") ? 1u : 0u)) != 0; } private static bool PatchPrefix(Harmony harmony, MethodBase target, string prefixName) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if (target == null) { Logger.LogWarning((object)"An Ammunition Barrel inventory restriction hook was not found in this Valheim build."); return false; } MethodInfo methodInfo = AccessTools.Method(typeof(AmmunitionBarrelInventoryPatches), prefixName, (Type[])null, (Type[])null); try { harmony.Patch(target, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } catch (Exception ex) { Logger.LogWarning((object)("Ammunition Barrel restriction hook failed: " + ex.Message)); return false; } } private static bool CanAddItemData(Inventory __instance, ItemData item, ref bool __result) { AmmunitionBarrelStorage ammunitionBarrelStorage = AmmunitionBarrelStorage.ForInventory(__instance); if (!Object.op_Implicit((Object)(object)ammunitionBarrelStorage) || ammunitionBarrelStorage.Allows(item)) { return true; } __result = false; return false; } private static bool CanAddPrefab(Inventory __instance, GameObject prefab, ref bool __result) { AmmunitionBarrelStorage ammunitionBarrelStorage = AmmunitionBarrelStorage.ForInventory(__instance); if (!Object.op_Implicit((Object)(object)ammunitionBarrelStorage) || ammunitionBarrelStorage.AllowsPrefab(prefab)) { return true; } __result = false; return false; } private static bool AddItemData(Inventory __instance, ItemData item, ref bool __result) { AmmunitionBarrelStorage ammunitionBarrelStorage = AmmunitionBarrelStorage.ForInventory(__instance); if (!Object.op_Implicit((Object)(object)ammunitionBarrelStorage) || ammunitionBarrelStorage.Allows(item)) { return true; } ammunitionBarrelStorage.NotifyRejected(AmmunitionCatalog.PrefabName(item)); __result = false; return false; } private static bool AddItemAt(Inventory __instance, ItemData item, ref bool __result) { AmmunitionBarrelStorage ammunitionBarrelStorage = AmmunitionBarrelStorage.ForInventory(__instance); if (!Object.op_Implicit((Object)(object)ammunitionBarrelStorage) || ammunitionBarrelStorage.Allows(item)) { return true; } ammunitionBarrelStorage.NotifyRejected(AmmunitionCatalog.PrefabName(item)); __result = false; return false; } private static bool MoveItemToThisSimple(Inventory __instance, Inventory fromInventory, ItemData item) { AmmunitionBarrelStorage ammunitionBarrelStorage = AmmunitionBarrelStorage.ForInventory(__instance); if ((Object)(object)ammunitionBarrelStorage == (Object)null || fromInventory == __instance || ammunitionBarrelStorage.Allows(item)) { return true; } RejectMoveAndRestore(ammunitionBarrelStorage, fromInventory, item); return false; } private static bool MoveItemToThisAt(Inventory __instance, Inventory fromInventory, ItemData item) { AmmunitionBarrelStorage ammunitionBarrelStorage = AmmunitionBarrelStorage.ForInventory(__instance); if ((Object)(object)ammunitionBarrelStorage == (Object)null || fromInventory == __instance || ammunitionBarrelStorage.Allows(item)) { return true; } RejectMoveAndRestore(ammunitionBarrelStorage, fromInventory, item); return false; } private static void RejectMoveAndRestore(AmmunitionBarrelStorage storage, Inventory fromInventory, ItemData item) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)storage)) { storage.NotifyRejected(AmmunitionCatalog.PrefabName(item)); } if (fromInventory == null || item == null || ContainsReference(fromInventory, item)) { return; } try { Vector2i gridPos = item.m_gridPos; if (fromInventory.AddItem(item)) { Logger.LogInfo((object)("Rejected incompatible Ammunition Barrel swap and restored '" + AmmunitionCatalog.PrefabName(item) + "' " + $"to the source inventory (previous grid {gridPos.x},{gridPos.y}).")); } else { Logger.LogError((object)("Rejected incompatible Ammunition Barrel swap but could not restore '" + AmmunitionCatalog.PrefabName(item) + "' to the source inventory. Leave the inventories open and report this log before moving more items.")); } } catch (Exception ex) { Logger.LogError((object)("Rejected incompatible Ammunition Barrel swap restoration failed: " + ex)); } } private static bool ContainsReference(Inventory inventory, ItemData item) { if (inventory == null || item == null) { return false; } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null) { return false; } foreach (ItemData item2 in allItems) { if (item2 == item) { return true; } } return false; } } internal static class AmmunitionBarrelUnlocks { private static readonly Dictionary<AmmunitionKind, Piece> FamilyPieces = new Dictionary<AmmunitionKind, Piece>(); private static readonly FieldInfo AvailableByCategoryField = AccessTools.Field(typeof(PieceTable), "m_availablePiecesByCategory"); private static readonly MethodInfo UpdateAvailablePiecesMethod = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", Type.EmptyTypes, (Type[])null); internal static void Install(Harmony harmony) { //IL_004e: 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_0076: Expected O, but got Unknown //IL_0076: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown if (harmony != null) { MethodInfo methodInfo = AccessTools.Method(typeof(Player), "AddKnownItem", new Type[1] { typeof(ItemData) }, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(AmmunitionBarrelUnlocks), "AddKnownItemPrefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.Method(typeof(AmmunitionBarrelUnlocks), "AddKnownItemPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Logger.LogWarning((object)"Could not install Ammunition Barrel discovery hook: Player.AddKnownItem(ItemData) was not found."); } MethodInfo methodInfo2 = AccessTools.Method(typeof(PieceTable), "UpdateAvailable", new Type[4] { typeof(HashSet<string>), typeof(Player), typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(AmmunitionBarrelUnlocks), "PieceTableUpdateAvailablePostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Logger.LogWarning((object)"Could not install Ammunition Barrel build-menu discovery hook: PieceTable.UpdateAvailable was not found."); } } } internal static void RegisterPiece(AmmunitionKind kind, Piece piece) { if (Object.op_Implicit((Object)(object)piece)) { FamilyPieces[kind] = piece; } } private static void AddKnownItemPrefix(Player __instance, ItemData item, ref bool __state) { __state = false; if (Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && item != null && AmmunitionCatalog.TryGetKind(item, out var kind)) { __state = AmmunitionCatalog.IsFamilyKnown(__instance, kind); } } private static void AddKnownItemPostfix(Player __instance, ItemData item, bool __state) { if (Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && item != null && AmmunitionCatalog.TryGetKind(item, out var kind) && !__state && AmmunitionCatalog.IsFamilyKnown(__instance, kind)) { RefreshBuildPieces(__instance); if (FamilyPieces.TryGetValue(kind, out var value) && Object.op_Implicit((Object)(object)value)) { ((Character)__instance).Message((MessageType)2, "New build piece: " + value.m_name, 0, (Sprite)null, false); } } } private static void PieceTableUpdateAvailablePostfix(PieceTable __instance, Player __1) { //IL_0129: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)__instance) || !Object.op_Implicit((Object)(object)__1) || (Object)(object)__1 != (Object)(object)Player.m_localPlayer) { return; } List<List<Piece>> list = null; if (AvailableByCategoryField != null) { try { list = AvailableByCategoryField.GetValue(__instance) as List<List<Piece>>; } catch { } } foreach (KeyValuePair<AmmunitionKind, Piece> familyPiece in FamilyPieces) { Piece value = familyPiece.Value; if (!Object.op_Implicit((Object)(object)value) || !Object.op_Implicit((Object)(object)((Component)value).gameObject) || !__instance.m_pieces.Contains(((Component)value).gameObject)) { continue; } __instance.m_availablePieces.Remove(value); __instance.m_enabledPieces.Remove(value); if (list != null) { foreach (List<Piece> item in list) { item?.Remove(value); } } if (!AmmunitionCatalog.IsFamilyKnown(__1, familyPiece.Key)) { continue; } __instance.m_availablePieces.Add(value); __instance.m_enabledPieces.Add(value); if (list == null) { continue; } int num = __instance.m_categories.IndexOf(value.m_category); if (num >= 0 && num < list.Count) { List<Piece> list2 = list[num]; if (list2 != null && !list2.Contains(value)) { list2.Add(value); } } } } private static void RefreshBuildPieces(Player player) { if (!Object.op_Implicit((Object)(object)player) || UpdateAvailablePiecesMethod == null) { return; } try { UpdateAvailablePiecesMethod.Invoke(player, null); } catch (Exception ex) { Logger.LogWarning((object)("Could not refresh Ammunition Barrel discovery list: " + ex.GetBaseException().Message)); } } } public sealed class AmmunitionBarrelVisual : MonoBehaviour { internal const string BarrelVisualName = "DSAP_OpenBarrelVisual"; private const string VisualRootName = "DSAP_AmmunitionVisuals"; private const int MaxVisibleProjectiles = 20; private Transform barrelVisual; private Transform visualRoot; private readonly List<GameObject> visualInstances = new List<GameObject>(); private string builtPrefabName; private float builtModelScale = -1f; private int pendingStoredCount; private string pendingPrefabName; private bool started; private void Start() { barrelVisual = FindDescendant(((Component)this).transform, "DSAP_OpenBarrelVisual"); EnsureVisualRoot(); started = true; Refresh(pendingPrefabName, pendingStoredCount); } internal void Refresh(string prefabName, int storedCount) { pendingPrefabName = AmmunitionCatalog.NormalizePrefabName(prefabName); pendingStoredCount = Mathf.Max(0, storedCount); if (!started) { return; } if (!Object.op_Implicit((Object)(object)barrelVisual)) { barrelVisual = FindDescendant(((Component)this).transform, "DSAP_OpenBarrelVisual"); } EnsureVisualRoot(); if (!Object.op_Implicit((Object)(object)visualRoot)) { SetVisibleCount(0); return; } if (string.IsNullOrEmpty(pendingPrefabName) || pendingStoredCount <= 0) { SetVisibleCount(0); builtPrefabName = pendingPrefabName; return; } AmmunitionBarrelAppearance component = ((Component)this).GetComponent<AmmunitionBarrelAppearance>(); float num = (Object.op_Implicit((Object)(object)component) ? component.CurrentAmmoModelScale : 0.8f); if (!string.Equals(builtPrefabName, pendingPrefabName, StringComparison.Ordinal) || visualInstances.Count == 0 || Mathf.Abs(builtModelScale - num) > 0.0001f) { RebuildVisuals(pendingPrefabName); } SetVisibleCount(CalculateVisibleCount(pendingPrefabName, pendingStoredCount)); } private void EnsureVisualRoot() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)visualRoot)) { return; } if (!Object.op_Implicit((Object)(object)barrelVisual)) { barrelVisual = FindDescendant(((Component)this).transform, "DSAP_OpenBarrelVisual"); } if (Object.op_Implicit((Object)(object)barrelVisual)) { Transform val = barrelVisual.Find("DSAP_AmmunitionVisuals"); if (Object.op_Implicit((Object)(object)val)) { visualRoot = val; return; } GameObject val2 = new GameObject("DSAP_AmmunitionVisuals"); val2.transform.SetParent(barrelVisual, false); val2.layer = ((Component)barrelVisual).gameObject.layer; visualRoot = val2.transform; } } private int CalculateVisibleCount(string prefabName, int storedCount) { if (storedCount <= 0) { return 0; } AmmunitionBarrelAppearance component = ((Component)this).GetComponent<AmmunitionBarrelAppearance>(); string text = (Object.op_Implicit((Object)(object)component) ? component.CurrentLooksFullAt : "50%"); if (text == "Always Full") { return 20; } DynamicStorageAmmunitionPilesPlugin current = DynamicStorageAmmunitionPilesPlugin.Current; int num = (((Object)(object)current != (Object)null) ? current.BarrelStorageCapacity : 20); float num2 = AmmunitionBarrelAppearance.LooksFullFraction(text); float num3; float num4; if ((Object.op_Implicit((Object)(object)component) ? component.CurrentFillBasis : "Occupied Slots") == "Occupied Slots") { AmmunitionBarrelStorage component2 = ((Component)this).GetComponent<AmmunitionBarrelStorage>(); num3 = (Object.op_Implicit((Object)(object)component2) ? ((float)component2.OccupiedSlotCount) : 1f); num4 = Mathf.Max(1f, (float)num * num2); } else { int maxStackSize = AmmunitionCatalog.GetMaxStackSize(prefabName); num3 = storedCount; num4 = Mathf.Max(1f, (float)(num * maxStackSize) * num2); } return Mathf.Clamp(Mathf.CeilToInt(Mathf.Clamp01(num3 / num4) * 20f), 1, 20); } private void RebuildVisuals(string prefabName) { //IL_00db: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Expected O, but got Unknown //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_0485: Unknown result type (might be due to invalid IL or missing references) //IL_04f4: Unknown result type (might be due to invalid IL or missing references) ClearVisuals(); builtPrefabName = prefabName; GameObject prefab = AmmunitionCatalog.GetPrefab(prefabName); if (!Object.op_Implicit((Object)(object)prefab)) { Logger.LogWarning((object)("Could not build Ammunition Barrel visuals because prefab was not found: " + prefabName)); return; } if (!Object.op_Implicit((Object)(object)barrelVisual)) { barrelVisual = FindDescendant(((Component)this).transform, "DSAP_OpenBarrelVisual"); } if (!Object.op_Implicit((Object)(object)barrelVisual) || !Object.op_Implicit((Object)(object)visualRoot)) { Logger.LogWarning((object)(((Object)((Component)this).gameObject).name + ": open barrel visual anchor was not available for ammunition rendering.")); return; } MeshFilter component = ((Component)barrelVisual).GetComponent<MeshFilter>(); Mesh val = (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null); Bounds val2 = (Bounds)(Object.op_Implicit((Object)(object)val) ? val.bounds : new Bounds(new Vector3(0f, 0.5f, 0f), new Vector3(0.88f, 1f, 0.89f))); AmmunitionBarrelAppearance component2 = ((Component)this).GetComponent<AmmunitionBarrelAppearance>(); float num = (Object.op_Implicit((Object)(object)component2) ? component2.CurrentAmmoModelScale : 0.8f); num = (builtModelScale = Mathf.Clamp(num, 0.35f, 2.5f)); GameObject val3 = new GameObject("DSAP_AmmoVisualTemplate"); val3.transform.SetParent(visualRoot, false); val3.layer = ((Component)barrelVisual).gameObject.layer; val3.SetActive(false); GameObject val4 = new GameObject("Geometry"); val4.transform.SetParent(val3.transform, false); val4.layer = val3.layer; int meshRendererCount = 0; int skinnedRendererCount = 0; CloneVisualHierarchy(prefab.transform, val4.transform, val3.layer, isPrefabRoot: true, ref meshRendererCount, ref skinnedRendererCount); if (meshRendererCount + skinnedRendererCount <= 0) { Object.Destroy((Object)(object)val3); Logger.LogWarning((object)("Could not find a renderable ammunition hierarchy for: " + prefabName)); return; } if (!TryCalculateCombinedBounds(val4.transform, out var bounds)) { Object.Destroy((Object)(object)val3); Logger.LogWarning((object)("Could not calculate complete visual bounds for: " + prefabName)); return; } Vector3 size = ((Bounds)(ref bounds)).size; Vector3 val5; float num2; if (size.x >= size.y && size.x >= size.z) { val5 = Vector3.right; num2 = size.x; } else if (size.z >= size.x && size.z >= size.y) { val5 = Vector3.forward; num2 = size.z; } else { val5 = Vector3.up; num2 = size.y; } Quaternion val6 = Quaternion.FromToRotation(val5, Vector3.up); val3.transform.localRotation = val6; val3.transform.localScale = Vector3.one * num; val4.transform.localPosition = -((Bounds)(ref bounds)).center; float num3 = Mathf.Max(0.1f, ((Bounds)(ref val2)).size.y); float num4 = Mathf.Max(0.01f, num2 * num); float num5 = Mathf.Min(((Bounds)(ref val2)).extents.x, ((Bounds)(ref val2)).extents.z) * 0.56f; for (int i = 0; i < 20; i++) { GameObject val7 = Object.Instantiate<GameObject>(val3, visualRoot, false); ((Object)val7).name = "AmmoVisual_" + i.ToString("00"); val7.layer = ((Component)barrelVisual).gameObject.layer; float num6 = (float)i * 137.50777f * ((float)Math.PI / 180f); float num7 = Mathf.Sqrt(((float)i + 0.5f) / 20f); float num8 = num5 * num7; float num9 = Mathf.Cos(num6) * num8; float num10 = Mathf.Sin(num6) * num8; float num11 = num3 * 0.08f; float num12 = ((Bounds)(ref val2)).min.y + num11 + num4 * 0.5f; num12 += ((float)(i * 7 % 9) - 4f) * num3 * 0.018f; val7.transform.localPosition = new Vector3(((Bounds)(ref val2)).center.x + num9, num12, ((Bounds)(ref val2)).center.z + num10); Quaternion val8 = val6; float num13 = Mathf.Repeat((float)i * 137.50777f + 19f, 360f); float num14 = Mathf.Sin((float)(i + 1) * 2.173f) * 10.5f; float num15 = Mathf.Cos((float)(i + 1) * 1.619f) * 9f; val7.transform.localRotation = Quaternion.Euler(num14, num13, num15) * val8; val7.transform.localScale = Vector3.one * num; val7.SetActive(false); visualInstances.Add(val7); } Object.Destroy((Object)(object)val3); Logger.LogInfo((object)($"Built {visualInstances.Count} exact-size dynamic ammunition visuals for {prefabName} " + $"(20-at-full layout; complete hierarchy: MeshRenderers={meshRendererCount}, SkinnedMeshRenderers={skinnedRendererCount}, " + $"vanillaBounds={((Bounds)(ref bounds)).size}, majorLength={num2:0.###}, modelScale={num:0.###}; 1.0 = vanilla gameplay size).")); } private static void CloneVisualHierarchy(Transform source, Transform destinationParent, int layer, bool isPrefabRoot, ref int meshRendererCount, ref int skinnedRendererCount) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_002e: 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_0046: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)source) && Object.op_Implicit((Object)(object)destinationParent)) { GameObject val = new GameObject(((Object)source).name); Transform transform = val.transform; transform.SetParent(destinationParent, false); transform.localPosition = source.localPosition; transform.localRotation = source.localRotation; transform.localScale = source.localScale; val.layer = layer; val.SetActive(isPrefabRoot || ((Component)source).gameObject.activeSelf); MeshFilter component = ((Component)source).GetComponent<MeshFilter>(); MeshRenderer component2 = ((Component)source).GetComponent<MeshRenderer>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sharedMesh) && Object.op_Implicit((Object)(object)component2)) { val.AddComponent<MeshFilter>().sharedMesh = component.sharedMesh; MeshRenderer destination = val.AddComponent<MeshRenderer>(); CopyRendererSettings(component2, destination); meshRendererCount++; } SkinnedMeshRenderer component3 = ((Component)source).GetComponent<SkinnedMeshRenderer>(); if (Object.op_Implicit((Object)(object)component3) && Object.op_Implicit((Object)(object)component3.sharedMesh)) { SkinnedMeshRenderer obj = val.AddComponent<SkinnedMeshRenderer>(); obj.sharedMesh = component3.sharedMesh; ((Renderer)obj).localBounds = ((Renderer)component3).localBounds; ((Renderer)obj).sharedMaterials = ((Renderer)component3).sharedMaterials; ((Renderer)obj).enabled = ((Renderer)component3).enabled; ((Renderer)obj).shadowCastingMode = ((Renderer)component3).shadowCastingMode; ((Renderer)obj).receiveShadows = ((Renderer)component3).receiveShadows; ((Renderer)obj).lightProbeUsage = ((Renderer)component3).lightProbeUsage; ((Renderer)obj).reflectionProbeUsage = ((Renderer)component3).reflectionProbeUsage; ((Renderer)obj).renderingLayerMask = ((Renderer)component3).renderingLayerMask; skinnedRendererCount++; } for (int i = 0; i < source.childCount; i++) { CloneVisualHierarchy(source.GetChild(i), transform, layer, isPrefabRoot: false, ref meshRendererCount, ref skinnedRendererCount); } } } private static void CopyRendererSettings(MeshRenderer source, MeshRenderer destination) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) ((Renderer)destination).sharedMaterials = ((Renderer)source).sharedMaterials; ((Renderer)destination).enabled = ((Renderer)source).enabled; ((Renderer)destination).shadowCastingMode = ((Renderer)source).shadowCastingMode; ((Renderer)destination).receiveShadows = ((Renderer)source).receiveShadows; ((Renderer)destination).lightProbeUsage = ((Renderer)source).lightProbeUsage; ((Renderer)destination).reflectionProbeUsage = ((Renderer)source).reflectionProbeUsage; ((Renderer)destination).renderingLayerMask = ((Renderer)source).renderingLayerMask; } private static bool TryCalculateCombinedBounds(Transform root, out Bounds bounds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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) //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) //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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) bounds = new Bounds(Vector3.zero, Vector3.zero); if (!Object.op_Implicit((Object)(object)root)) { return false; } bool initialized = false; Matrix4x4 worldToLocalMatrix = root.worldToLocalMatrix; MeshFilter[] componentsInChildren = ((Component)root).GetComponentsInChildren<MeshFilter>(true); foreach (MeshFilter val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.sharedMesh)) { MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>(); if (Object.op_Implicit((Object)(object)component) && ((Renderer)component).enabled && IsActiveSelfChain(((Component)val).transform, root)) { EncapsulateTransformedBounds(val.sharedMesh.bounds, worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix, ref bounds, ref initialized); } } } SkinnedMeshRenderer[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren2) { if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.sharedMesh) && ((Renderer)val2).enabled && IsActiveSelfChain(((Component)val2).transform, root)) { EncapsulateTransformedBounds(((Renderer)val2).localBounds, worldToLocalMatrix * ((Component)val2).transform.localToWorldMatrix, ref bounds, ref initialized); } } return initialized; } private static bool IsActiveSelfChain(Transform transform, Transform root) { if (!Object.op_Implicit((Object)(object)transform) || !Object.op_Implicit((Object)(object)root)) { return false; } Transform val = transform; while (Object.op_Implicit((Object)(object)val)) { if (!((Component)val).gameObject.activeSelf) { return false; } if ((Object)(object)val == (Object)(object)root) { return true; } val = val.parent; } return false; } private static void EncapsulateTransformedBounds(Bounds sourceBounds, Matrix4x4 matrix, ref Bounds combined, ref bool initialized) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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) //IL_0025: 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_0036: 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_0048: 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_005f: 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_0082: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) Vector3 min = ((Bounds)(ref sourceBounds)).min; Vector3 max = ((Bounds)(ref sourceBounds)).max; Vector3 val = default(Vector3); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { for (int k = 0; k < 2; k++) { ((Vector3)(ref val))..ctor((i == 0) ? min.x : max.x, (j == 0) ? min.y : max.y, (k == 0) ? min.z : max.z); Vector3 val2 = ((Matrix4x4)(ref matrix)).MultiplyPoint3x4(val); if (!initialized) { combined = new Bounds(val2, Vector3.zero); initialized = true; } else { ((Bounds)(ref combined)).Encapsulate(val2); } } } } } private void SetVisibleCount(int count) { count = Mathf.Clamp(count, 0, visualInstances.Count); for (int i = 0; i < visualInstances.Count; i++) { GameObject val = visualInstances[i]; if (Object.op_Implicit((Object)(object)val) && val.activeSelf != i < count) { val.SetActive(i < count); } } } private void ClearVisuals() { foreach (GameObject visualInstance in visualInstances) { if (Object.op_Implicit((Object)(object)visualInstance)) { Object.Destroy((Object)(object)visualInstance); } } visualInstances.Clear(); if (!Object.op_Implicit((Object)(object)visualRoot)) { return; } for (int num = visualRoot.childCount - 1; num >= 0; num--) { Transform child = visualRoot.GetChild(num); if (Object.op_Implicit((Object)(object)child)) { Object.Destroy((Object)(object)((Component)child).gameObject); } } } private static Transform FindDescendant(Transform root, string name) { if (!Object.op_Implicit((Object)(object)root)) { return null; } Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && string.Equals(((Object)val).name, name, StringComparison.Ordinal)) { return val; } } return null; } } internal enum AmmunitionKind { Arrow, CrossbowBolt, BallistaMissile } internal sealed class AmmunitionDefinition { internal readonly string PrefabName; internal readonly string DisplayName; internal readonly AmmunitionKind Kind; internal AmmunitionDefinition(string prefabName, string displayName, AmmunitionKind kind) { PrefabName = prefabName; DisplayName = displayName; Kind = kind; } } internal static class AmmunitionCatalog { private static readonly AmmunitionDefinition[] Candidates = new AmmunitionDefinition[24] { new AmmunitionDefinition("ArrowWood", "Wood arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowFlint", "Flinthead arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowBronze", "Bronzehead arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowFire", "Fire arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowIron", "Ironhead arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowPoison", "Poison arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowObsidian", "Obsidian arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowFrost", "Frost arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowSilver", "Silver arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowNeedle", "Needle arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowCarapace", "Carapace arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowCharred", "Charred arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("ArrowBloodGold", "Bloodgold arrow", AmmunitionKind.Arrow), new AmmunitionDefinition("BoltBone", "Bone bolt", AmmunitionKind.CrossbowBolt), new AmmunitionDefinition("BoltIron", "Iron bolt", AmmunitionKind.CrossbowBolt), new AmmunitionDefinition("BoltBlackmetal", "Black metal bolt", AmmunitionKind.CrossbowBolt), new AmmunitionDefinition("BoltCarapace", "Carapace bolt", AmmunitionKind.CrossbowBolt), new AmmunitionDefinition("BoltCharred", "Charred bolt", AmmunitionKind.CrossbowBolt), new AmmunitionDefinition("BoltBloodGold", "Bloodgold bolt", AmmunitionKind.CrossbowBolt), new AmmunitionDefinition("TurretBoltWood", "Wooden missile", AmmunitionKind.BallistaMissile), new AmmunitionDefinition("TurretBolt", "Black metal missile", AmmunitionKind.BallistaMissile), new AmmunitionDefinition("TurretBoltFlametal", "Flametal missile", AmmunitionKind.BallistaMissile), new AmmunitionDefinition("TurretBoltBloodgold", "Bloodgold missile", AmmunitionKind.BallistaMissile), new AmmunitionDefinition("TurretBoltBone", "Bone missile", AmmunitionKind.BallistaMissile) }; private static readonly Dictionary<string, AmmunitionDefinition> Supported = new Dictionary<string, AmmunitionDefinition>(StringComparer.Ordinal); internal static int SupportedCount => Supported.Count; internal static void Initialize() { Supported.Clear(); AmmunitionDefinition[] candidates = Candidates; foreach (AmmunitionDefinition ammunitionDefinition in candidates) { GameObject prefab = PrefabManager.Instance.GetPrefab(ammunitionDefinition.PrefabName); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent<ItemDrop>())) { Logger.LogWarning((object)("Ammunition prefab not found or not an ItemDrop: " + ammunitionDefinition.PrefabName)); } else { Supported[ammunitionDefinition.PrefabName] = ammunitionDefinition; } } Logger.LogInfo((object)$"Ammunition catalog initialized: {Supported.Count}/{Candidates.Length} supported vanilla ammunition prefabs found."); } internal static bool IsSupported(string prefabName) { prefabName = NormalizePrefabName(prefabName); if (!string.IsNullOrEmpty(prefabName)) { return Supported.ContainsKey(prefabName); } return false; } internal static bool TryGetKind(string prefabName, out AmmunitionKind kind) { prefabName = NormalizePrefabName(prefabName); if (!string.IsNullOrEmpty(prefabName) && Supported.TryGetValue(prefabName, out var value)) { kind = value.Kind; return true; } kind = AmmunitionKind.Arrow; return false; } internal static bool TryGetKind(ItemData item, out AmmunitionKind kind) { return TryGetKind(PrefabName(item), out kind); } internal static bool IsKind(string prefabName, AmmunitionKind kind) { if (TryGetKind(prefabName, out var kind2)) { return kind2 == kind; } return false; } internal static bool IsFamilyKnown(Player player, AmmunitionKind kind) { if (!Object.op_Implicit((Object)(object)player)) { return false; } foreach (AmmunitionDefinition value in Supported.Values) { if (value.Kind == kind) { GameObject prefab = PrefabManager.Instance.GetPrefab(value.PrefabName); ItemDrop val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<ItemDrop>() : null); string text = (((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null) ? val.m_itemData.m_shared.m_name : null); if (!string.IsNullOrEmpty(text) && player.IsMaterialKnown(text)) { return true; } } } return false; } internal static string FamilyDisplayName(AmmunitionKind kind) { return kind switch { AmmunitionKind.CrossbowBolt => "crossbow bolts", AmmunitionKind.BallistaMissile => "Ballista missiles", _ => "arrows", }; } internal static string DisplayName(string prefabName) { prefabName = NormalizePrefabName(prefabName); if (string.IsNullOrEmpty(prefabName) || !Supported.TryGetValue(prefabName, out var value)) { return prefabName; } return value.DisplayName; } internal static GameObject GetPrefab(string prefabName) { prefabName = NormalizePrefabName(prefabName); if (!IsSupported(prefabName)) { return null; } return PrefabManager.Instance.GetPrefab(prefabName); } internal static int GetMaxStackSize(string prefabName) { GameObject prefab = GetPrefab(prefabName); ItemDrop val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null) { return 100; } return Mathf.Max(1, val.m_itemData.m_shared.m_maxStackSize); } internal static string PrefabName(ItemData item) { if (item == null) { return null; } if (Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return NormalizePrefabName(((Object)item.m_dropPrefab).name); } return null; } internal static string NormalizePrefabName(string value) { if (string.IsNullOrEmpty(value)) { return null; } if (value.EndsWith("(Clone)", StringComparison.Ordinal)) { value = value.Substring(0, value.Length - "(Clone)".Length); } return value.Trim(); } } internal sealed class ConfigurationManagerAttributes { public int? Order; public bool? IsAdminOnly; public bool? ReadOnly; public bool? Browsable; public bool? IsAdvanced; } [BepInPlugin("com.muji.DynamicStorageAmmunitionPiles", "DynamicStorage Ammunition Piles", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal sealed class DynamicStorageAmmunitionPilesPlugin : BaseUnityPlugin { private sealed class BarrelDefinition { internal readonly string PrefabName; internal readonly string DisplayName; internal readonly string Description; internal readonly AmmunitionKind Kind; internal BarrelDefinition(string prefabName, string displayName, string description, AmmunitionKind kind) { PrefabName = prefabName; DisplayName = displayName; Description = description; Kind = kind; } } public const string PluginGuid = "com.muji.DynamicStorageAmmunitionPiles"; public const string PluginName = "DynamicStorage Ammunition Piles"; public const string PluginVersion = "1.0.1"; private const string VanillaBaseName = "piece_chest_barrel"; private static readonly BarrelDefinition[] BarrelDefinitions = new BarrelDefinition[3] { new BarrelDefinition("DSAP_ArrowBarrel", "Arrow Barrel", "Stores one arrow type at a time. Revealed after discovering any arrow.", AmmunitionKind.Arrow), new BarrelDefinition("DSAP_BoltBarrel", "Bolt Barrel", "Stores one crossbow bolt type at a time. Revealed after discovering any crossbow bolt.", AmmunitionKind.CrossbowBolt), new BarrelDefinition("DSAP_MissileBarrel", "Missile Barrel", "Stores one Ballista missile type at a time. Revealed after discovering any Ballista missile.", AmmunitionKind.BallistaMissile) }; private ConfigEntry<int> barrelSlots; private ConfigEntry<bool> barrelAppearanceEditor; private ConfigEntry<float> arrowBarrelScale; private ConfigEntry<float> arrowBarrelHeightOffset; private ConfigEntry<float> arrowAmmoModelScale; private ConfigEntry<string> arrowFillBasis; private ConfigEntry<string> arrowLooksFullAt; private ConfigEntry<float> boltBarrelScale; private ConfigEntry<float> boltBarrelHeightOffset; private ConfigEntry<float> boltAmmoModelScale; private ConfigEntry<string> boltFillBasis; private ConfigEntry<string> boltLooksFullAt; private ConfigEntry<float> missileBarrelScale; private ConfigEntry<float> missileBarrelHeightOffset; private ConfigEntry<float> missileAmmoModelScale; private ConfigEntry<string> missileFillBasis; private ConfigEntry<string> missileLooksFullAt; private Harmony harmony; private readonly Dictionary<AmmunitionKind, GameObject> registeredPrefabs = new Dictionary<AmmunitionKind, GameObject>(); private readonly Dictionary<AmmunitionKind, Vector3> registeredBaseScales = new Dictionary<AmmunitionKind, Vector3>(); internal static DynamicStorageAmmunitionPilesPlugin Current { get; private set; } internal int BarrelStorageCapacity => NormalizeStorageCapacity((barrelSlots != null) ? barrelSlots.Value : 20); internal bool AppearanceEditorEnabled { get { if (barrelAppearanceEditor != null) { return barrelAppearanceEditor.Value; } return false; } } private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Current = this; BindConfig(); harmony = new Harmony("com.muji.DynamicStorageAmmunitionPiles"); AmmunitionBarrelInventoryPatches.Install(harmony); AmmunitionBarrelCapacityPatches.Install(harmony); AmmunitionBarrelPlacementPatches.Install(harmony); AmmunitionBarrelAppearanceEditorPatches.Install(harmony); AmmunitionBarrelUnlocks.Install(harmony); PrefabManager.OnPrefabsRegistered += OnPrefabsRegistered; ((BaseUnityPlugin)this).Logger.LogInfo((object)"DynamicStorage Ammunition Piles 1.0.1 loaded."); } private void OnDestroy() { PrefabManager.OnPrefabsRegistered -= OnPrefabsRegistered; if (harmony != null) { try { harmony.UnpatchSelf(); } catch { } } if ((Object)(object)Current == (Object)(object)this) { Current = null; } } private void BindConfig() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown AcceptableValueList<int> val = new AcceptableValueList<int>(new int[4] { 10, 20, 40, 60 }); barrelSlots = ConfigFileExtensions.BindConfig<int>(((BaseUnityPlugin)this).Config, "Server Settings", "Ammunition Barrel Slots", 20, "Server-controlled inventory slot count shared by Arrow, Bolt, and Missile Barrels. Options: 10, 20, 40, or 60.", true, (int?)100, (AcceptableValueBase)(object)val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); barrelAppearanceEditor = ((BaseUnityPlugin)this).Config.Bind<bool>("Appearance Editor", "Barrel Appearance Editor", false, new ConfigDescription("Shows a colour-coded appearance summary while looking at DynamicStorage Ammunition Piles barrels and enables R to apply the current configuration for that exact barrel family to the placed piece. Appearance changes are saved on the placed piece and replicated through its ZDO.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 100 } })); BindAppearanceProfile("Arrow Barrel Appearance", 1f, 0f, 0.8f, "Occupied Slots", "50%", out arrowBarrelScale, out arrowBarrelHeightOffset, out arrowAmmoModelScale, out arrowFillBasis, out arrowLooksFullAt); BindAppearanceProfile("Bolt Barrel Appearance", 0.6f, 0f, 1.8f, "Occupied Slots", "50%", out boltBarrelScale, out boltBarrelHeightOffset, out boltAmmoModelScale, out boltFillBasis, out boltLooksFullAt); BindAppearanceProfile("Missile Barrel Appearance", 1.5f, 0f, 0.6f, "Occupied Slots", "50%", out missileBarrelScale, out missileBarrelHeightOffset, out missileAmmoModelScale, out missileFillBasis, out missileLooksFullAt); barrelSlots.SettingChanged += delegate { AmmunitionBarrelCapacity.RefreshAll(); }; arrowBarrelScale.SettingChanged += delegate { RefreshPlacementTemplateScale(AmmunitionKind.Arrow); }; boltBarrelScale.SettingChanged += delegate { RefreshPlacementTemplateScale(AmmunitionKind.CrossbowBolt); }; missileBarrelScale.SettingChanged += delegate { RefreshPlacementTemplateScale(AmmunitionKind.BallistaMissile); }; } private void BindAppearanceProfile(string section, float defaultBarrelScale, float defaultHeightOffset, float defaultAmmoModelScale, string defaultFillBasis, string defaultLooksFullAt, out ConfigEntry<float> scale, out ConfigEntry<float> heightOffset, out ConfigEntry<float> ammoScale, out ConfigEntry<string> fillBasis, out ConfigEntry<string> looksFullAt) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown scale = ((BaseUnityPlugin)this).Config.Bind<float>(section, "Barrel Scale", defaultBarrelScale, new ConfigDescription("Template barrel scale for newly placed barrels of this family. Each placed barrel saves its own value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 100 } })); heightOffset = ((BaseUnityPlugin)this).Config.Bind<float>(section, "Barrel Height Offset", defaultHeightOffset, new ConfigDescription("Vertical placement offset for newly placed barrels of this family. Each placed barrel saves its own value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 2f), new object[1] { new ConfigurationManagerAttributes { Order = 95 } })); ammoScale = ((BaseUnityPlugin)this).Config.Bind<float>(section, "Ammunition Model Scale", defaultAmmoModelScale, new ConfigDescription("Scale multiplier for complete visible ammunition models. 1.00 is the exact vanilla gameplay-prefab size before the barrel's own scale is applied.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.35f, 2.5f), new object[1] { new ConfigurationManagerAttributes { Order = 90 } })); fillBasis = ((BaseUnityPlugin)this).Config.Bind<string>(section, "Fill Based On", defaultFillBasis, new ConfigDescription("How this barrel's visual growth is measured. Occupied Slots counts used inventory slots. Storage Capacity uses the actual number of projectiles stored against the server-selected slot capacity multiplied by that ammunition's stack size. Saved into each placed barrel.", (AcceptableValueBase)(object)new AcceptableValueList<string>(AmmunitionBarrelAppearance.FillBasisOptions), new object[1] { new ConfigurationManagerAttributes { Order = 85 } })); looksFullAt = ((BaseUnityPlugin)this).Config.Bind<string>(section, "Looks Full At", defaultLooksFullAt, new ConfigDescription("How quickly this barrel reaches its 20-projectile full visual. 50% means full at half of the selected fill basis; the threshold scales with the server-selected 10 / 20 / 40 / 60 slot capacity. Always Full disables dynamic visual fill. Saved into each placed barrel.", (AcceptableValueBase)(object)new AcceptableValueList<string>(AmmunitionBarrelAppearance.LooksFullAtOptions), new object[1] { new ConfigurationManagerAttributes { Order = 80 } })); } internal BarrelAppearanceTemplate GetAppearanceTemplate(AmmunitionKind kind) { return kind switch { AmmunitionKind.CrossbowBolt => new BarrelAppearanceTemplate(Mathf.Clamp((boltBarrelScale != null) ? boltBarrelScale.Value : 0.6f, 0.5f, 3f), Mathf.Clamp((boltBarrelHeightOffset != null) ? boltBarrelHeightOffset.Value : 0f, -2f, 2f), Mathf.Clamp((boltAmmoModelScale != null) ? boltAmmoModelScale.Value : 1.8f, 0.35f, 2.5f), AmmunitionBarrelAppearance.NormalizeFillBasis((boltFillBasis != null) ? boltFillBasis.Value : "Occupied Slots"), AmmunitionBarrelAppearance.NormalizeLooksFullAt((boltLooksFullAt != null) ? boltLooksFullAt.Value : "50%")), AmmunitionKind.BallistaMissile => new BarrelAppearanceTemplate(Mathf.Clamp((missileBarrelScale != null) ? missileBarrelScale.Value : 1.5f, 0.5f, 3f), Mathf.Clamp((missileBarrelHeightOffset != null) ? missileBarrelHeightOffset.Value : 0f, -2f, 2f), Mathf.Clamp((missileAmmoModelScale != null) ? missileAmmoModelScale.Value : 0.6f, 0.35f, 2.5f), AmmunitionBarrelAppearance.NormalizeFillBasis((missileFillBasis != null) ? missileFillBasis.Value : "Occupied Slots"), AmmunitionBarrelAppearance.NormalizeLooksFullAt((missileLooksFullAt != null) ? missileLooksFullAt.Value : "50%")), _ => new BarrelAppearanceTemplate(Mathf.Clamp((arrowBarrelScale != null) ? arrowBarrelScale.Value : 1f, 0.5f, 3f), Mathf.Clamp((arrowBarrelHeightOffset != null) ? arrowBarrelHeightOffset.Value : 0f, -2f, 2f), Mathf.Clamp((arrowAmmoModelScale != null) ? arrowAmmoModelScale.Value : 0.8f, 0.35f, 2.5f), AmmunitionBarrelAppearance.NormalizeFillBasis((arrowFillBasis != null) ? arrowFillBasis.Value : "Occupied Slots"), AmmunitionBarrelAppearance.NormalizeLooksFullAt((arrowLooksFullAt != null) ? arrowLooksFullAt.Value : "50%")), }; } private void OnPrefabsRegistered() { PrefabManager.OnPrefabsRegistered -= OnPrefabsRegistered; AmmunitionCatalog.Initialize(); RegisterBarrels(); } private void RegisterBarrels() { GameObject val = null; if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { val = ZNetScene.instance.GetPrefab("piece_chest_barrel"); } if (!Object.op_Implicit((Object)(object)val)) { val = PrefabManager.Instance.GetPrefab("piece_chest_barrel"); } if (!Object.op_Implicit((Object)(object)val)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not create ammunition barrels: live vanilla source 'piece_chest_barrel' was not found."); return; } Piece component = val.GetComponent<Piece>(); ZNetView component2 = val.GetComponent<ZNetView>(); WearNTear component3 = val.GetComponent<WearNTear>(); Container component4 = val.GetComponent<Container>(); Collider[] componentsInChildren = val.GetComponentsInChildren<Collider>(true); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2) || !Object.op_Implicit((Object)(object)component3) || !Object.op_Implicit((Object)(object)component4) || componentsInChildren.Length == 0) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not create ammunition barrels: 'piece_chest_barrel' was not the expected complete build piece (Piece=" + Bool((Object)(object)component) + ", ZNetView=" + Bool((Object)(object)component2) + ", WearNTear=" + Bool((Object)(object)component3) + ", " + $"Container={Bool((Object)(object)component4)}, Colliders={componentsInChildren.Length}).")); return; } Mesh prefab = Cache.GetPrefab<Mesh>("barrel"); Material prefab2 = Cache.GetPrefab<Material>("barrelplayer_mat"); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab2)) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not create ammunition barrels: open barrel assets were unavailable (mesh=" + Bool((Object)(object)prefab) + ", material=" + Bool((Object)(object)prefab2) + ").")); return; } int num = 0; BarrelDefinition[] barrelDefinitions = BarrelDefinitions; foreach (BarrelDefinition definition in barrelDefinitions) { if (RegisterBarrel(definition, val, component, componentsInChildren.Length, prefab, prefab2)) { num++; } } ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Registered {num}/{BarrelDefinitions.Length} family-specific ammunition barrels; " + $"capacity={BarrelStorageCapacity}, supportedAmmo={AmmunitionCatalog.SupportedCount}. " + "Arrow/Bolt/Missile patterns are revealed independently when the player discovers that ammunition family.")); } private bool RegisterBarrel(BarrelDefinition definition, GameObject source, Piece sourcePiece, int sourceColliderCount, Mesh openBarrelMesh, Material openBarrelMaterial) { //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Expected O, but got Unknown //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Expected O, but got Unknown //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Expected O, but got Unknown //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Expected O, but got Unknown GameObject val = PrefabManager.Instance.CreateClonedPrefab(definition.PrefabName, source); if (!Object.op_Implicit((Object)(object)val)) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not clone live vanilla source 'piece_chest_barrel' for " + definition.DisplayName + ".")); return false; } Transform bodyAnchor = FindVanillaBodyAnchor(val); Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true); int num = 0; Renderer[] array = componentsInChildren; foreach (Renderer val2 in array) { if (Object.op_Implicit((Object)(object)val2)) { val2.enabled = false; num++; } } if (!Object.op_Implicit((Object)(object)CreateOpenBarrelVisual(val, bodyAnchor, openBarrelMesh, openBarrelMaterial))) { Object.DestroyImmediate((Object)(object)val); return false; } AmmunitionBarrelFamily ammunitionBarrelFamily = val.GetComponent<AmmunitionBarrelFamily>(); if (!Object.op_Implicit((Object)(object)ammunitionBarrelFamily)) { ammunitionBarrelFamily = val.AddComponent<AmmunitionBarrelFamily>(); } ammunitionBarrelFamily.Setup(definition.Kind); Piece component = val.GetComponent<Piece>(); component.m_name = definition.DisplayName; component.m_description = definition.Description; if (Object.op_Implicit((Object)(object)sourcePiece.m_icon)) { component.m_icon = sourcePiece.m_icon; } Container component2 = val.GetComponent<Container>(); component2.m_name = definition.DisplayName; GetStorageGrid(BarrelStorageCapacity, out var width, out var height); component2.m_width = width; component2.m_height = height; if (!Object.op_Implicit((Object)(object)val.GetComponent<AmmunitionBarrelCapacity>())) { val.AddComponent<AmmunitionBarrelCapacity>(); } if (!Object.op_Implicit((Object)(object)val.GetComponent<AmmunitionBarrelStorage>())) { val.AddComponent<AmmunitionBarrelStorage>(); } if (!Object.op_Implicit((Object)(object)val.GetComponent<AmmunitionBarrelVisual>())) { val.AddComponent<AmmunitionBarrelVisual>(); } Vector3 localScale = val.transform.localScale; registeredBaseScales[definition.Kind] = localScale; AmmunitionBarrelAppearance ammunitionBarrelAppearance = val.GetComponent<AmmunitionBarrelAppearance>(); if (!Object.op_Implicit((Object)(object)ammunitionBarrelAppearance)) { ammunitionBarrelAppearance = val.AddComponent<AmmunitionBarrelAppearance>(); } ammunitionBarrelAppearance.Setup(localScale); BarrelAppearanceTemplate appearanceTemplate = GetAppearanceTemplate(definition.Kind); val.transform.localScale = Multiply(localScale, appearanceTemplate.BarrelScale); WearNTear component3 = val.GetComponent<WearNTear>(); if (Object.op_Implicit((Object)(object)component3)) { component3.m_autoCreateFragments = false; } PieceConfig val3 = new PieceConfig { PieceTable = PieceTables.Hammer, Category = PieceCategories.Misc }; val3.AddRequirement(new RequirementConfig("FineWood", 10, 0, true)); val3.AddRequirement(new RequirementConfig("Bronze", 2, 0, true)); CustomPiece val4 = new CustomPiece(val, true, val3); if (!PieceManager.Instance.AddPiece(val4)) { ((BaseUnityPlugin)this).Logger.LogError((object)("Jotunn PieceManager rejected '" + definition.DisplayName + "'.")); return false; } registeredPrefabs[definition.Kind] = val; AmmunitionBarrelUnlocks.RegisterPiece(definition.Kind, component); ((BaseUnityPlugin)this).Logger.LogInfo((object)(string.Format("Registered '{0}' ({1}) from live '{2}': ", definition.DisplayName, definition.Kind, "piece_chest_barrel") + $"preserved {sourceColliderCount} vanilla collider(s), disabled {num} inherited renderer(s), " + $"barrelScale={appearanceTemplate.BarrelScale:0.##}, ammoScale={appearanceTemplate.AmmoModelScale:0.##}, fillBasis={appearanceTemplate.FillBasis}, looksFullAt={appearanceTemplate.LooksFullAt}.")); return true; } private GameObject CreateOpenBarrelVisual(GameObject prefab, Transform bodyAnchor, Mesh mesh, Material material) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_006d: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Object.op_Implicit((Object)(object)bodyAnchor) && Object.op_Implicit((Object)(object)bodyAnchor.parent)) ? bodyAnchor.parent : prefab.transform); GameObject val2 = new GameObject("DSAP_OpenBarrelVisual"); val2.transform.SetParent(val, false); if (Object.op_Implicit((Object)(object)bodyAnchor)) { val2.transform.localPosition = bodyAnchor.localPosition; val2.transform.localRotation = bodyAnchor.localRotation; val2.transform.localScale = bodyAnchor.localScale; val2.layer = ((Component)bodyAnchor).gameObject.layer; } else { val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = Vector3.one; val2.layer = prefab.layer; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Vanilla barrel body anchor was not found; open visual is using the Piece root as a fallback."); } val2.AddComponent<MeshFilter>().sharedMesh = mesh; MeshRenderer obj = val2.AddComponent<MeshRenderer>(); ((Renderer)obj).sharedMaterial = material; ((Renderer)obj).enabled = true; return val2; } private static Transform FindVanillaBodyAnchor(GameObject prefab) { if (!Object.op_Implicit((Object)(object)prefab)) { return null; } Transform val = prefab.transform.Find("New/blackmetalchest"); if (Object.op_Implicit((Object)(object)val)) { return val; } MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val2 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val2) && string.Equals(((Object)((Component)val2).gameObject).name, "blackmetalchest", StringComparison.OrdinalIgnoreCase)) { return ((Component)val2).transform; } } componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val3 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)((Renderer)val3).sharedMaterial) && string.Equals(((Object)((Renderer)val3).sharedMaterial).name, "barrelplayer_mat", StringComparison.OrdinalIgnoreCase) && ((Object)((Component)val3).gameObject).name.IndexOf("top", StringComparison.OrdinalIgnoreCase) < 0 && ((Object)((Component)val3).gameObject).name.IndexOf("LOD", StringComparison.OrdinalIgnoreCase) < 0) { return ((Component)val3).transform; } } return null; } private void RefreshPlacementTemplateScale(AmmunitionKind kind) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //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) if (registeredPrefabs.TryGetValue(kind, out var value) && Object.op_Implicit((Object)(object)value)) { if (!registeredBaseScales.TryGetValue(kind, out var value2)) { value2 = Vector3.one; } value.transform.localScale = Multiply(value2, GetAppearanceTemplate(kind).BarrelScale); } } internal static int NormalizeStorageCapacity(int value) { return value switch { 10 => 10, 40 => 40, 60 => 60, _ => 20, }; } internal static void GetStorageGrid(int capacity, out int width, out int height) { switch (NormalizeStorageCapacity(capacity)) { case 10: width = 5; height = 2; break; case 40: width = 8; height = 5; break; case 60: width = 10; height = 6; break; default: width = 5; height = 4; break; } } private static Vector3 Multiply(Vector3 value, float multiplier) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_0018: Unknown result type (might be due to invalid IL or missing references) return new Vector3(value.x * multiplier, value.y * multiplier, value.z * multiplier); } private static string Bool(Object value)