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 DynamicStorageForge v1.0.0
plugins/DynamicStorageForge.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; 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("DynamicStorageForge")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DynamicStorageForge")] [assembly: AssemblyTitle("DynamicStorageForge")] [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 DynamicStorageForge { internal sealed class AppearanceSettings { internal const string FlintExperimentalLayout = "Flint - Experimental"; internal const string ObsidianExperimentalLayout = "Obsidian - Experimental"; internal const string ModelDefaultMaterial = "Model Default"; internal static readonly Dictionary<string, string> MaterialSources = new Dictionary<string, string>(StringComparer.Ordinal) { { "Copper Ore", "CopperOre" }, { "Copper Scrap", "CopperScrap" }, { "Tin Ore", "TinOre" }, { "Scrap Bronze", "BronzeScrap" }, { "Scrap Iron", "IronScrap" }, { "Iron Ore", "IronOre" }, { "Silver Ore", "SilverOre" }, { "Black Metal Scrap", "BlackMetalScrap" }, { "Petrified Tissue", "GoldOre" }, { "Flametal Ore", "FlametalOreNew" }, { "Glowing Metal Ore", "FlametalOre" }, { "Flint", "Flint" }, { "Coal", "Coal" }, { "Stone", "Stone" }, { "Black Marble", "BlackMarble" }, { "Obsidian", "Obsidian" }, { "Copper Bars", "Copper" }, { "Tin Bars", "Tin" }, { "Bronze Bars", "Bronze" }, { "Iron Bars", "Iron" }, { "Silver Bars", "Silver" }, { "Black Metal Bars", "BlackMetal" }, { "Bloodgold Bars", "Gold" }, { "Flametal Bars", "FlametalNew" }, { "Ancient Metal Bars", "Flametal" } }; internal static readonly Dictionary<string, string> ModelSources = new Dictionary<string, string>(StringComparer.Ordinal) { { "Copper Ore", "CopperOre" }, { "Copper Scrap", "CopperScrap" }, { "Tin Ore", "TinOre" }, { "Scrap Bronze", "BronzeScrap" }, { "Scrap Iron", "IronScrap" }, { "Iron Ore", "IronOre" }, { "Silver Ore", "SilverOre" }, { "Black Metal Scrap", "BlackMetalScrap" }, { "Petrified Tissue", "GoldOre" }, { "Flametal Ore", "FlametalOreNew" }, { "Glowing Metal Ore", "FlametalOre" }, { "Flint", "Flint" }, { "Coal", "Coal" }, { "Stone", "Stone" }, { "Black Marble", "BlackMarble" }, { "Obsidian", "Obsidian" } }; private readonly bool isBar; private readonly ConfigEntry<string> preset; private readonly ConfigEntry<string> shape; private readonly ConfigEntry<string> model; private readonly ConfigEntry<string> material; private readonly ConfigEntry<float> layoutScale; private readonly ConfigEntry<float> layoutHeight; private readonly ConfigEntry<float> modelScale; private readonly ConfigEntry<float> visualVerticalOffset; private readonly ConfigEntry<string> finish; private readonly ConfigEntry<string> barArrangement; private readonly ConfigEntry<int> barAcross; private readonly ConfigEntry<int> barDeep; private readonly ConfigEntry<int> barLayers; private readonly ConfigEntry<string> fillBasis; private readonly ConfigEntry<string> looksFullAt; private readonly List<PileAppearancePreset> pilePresets = new List<PileAppearancePreset>(); private bool updatingPreset; private string observedPresetValue; private string observedAppearanceSignature; private bool updatingBarDimensions; internal string SectionName { get; } internal static string DisplayLayoutName(string layout) { if (string.Equals(layout, "Flint", StringComparison.Ordinal)) { return "Flint - Experimental"; } if (string.Equals(layout, "Obsidian", StringComparison.Ordinal)) { return "Obsidian - Experimental"; } return layout; } internal static string ModelNameForPrefab(string prefabName) { foreach (KeyValuePair<string, string> modelSource in ModelSources) { if (string.Equals(modelSource.Value, prefabName, StringComparison.Ordinal)) { return modelSource.Key; } } return null; } internal AppearanceSettings(ConfigFile config, string section, bool isBar, string nativeShape, string defaultShape, string defaultModelPrefab, float defaultSize, float defaultHeight, string legacySection = null) { //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Expected O, but got Unknown //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Expected O, but got Unknown //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown //IL_04e8: Unknown result type (might be due to invalid IL or missing references) //IL_04f2: Expected O, but got Unknown //IL_06e9: Unknown result type (might be due to invalid IL or missing references) //IL_06f3: Expected O, but got Unknown //IL_05af: Unknown result type (might be due to invalid IL or missing references) //IL_05b9: Expected O, but got Unknown //IL_0632: Unknown result type (might be due to invalid IL or missing references) //IL_063c: Expected O, but got Unknown //IL_078a: Unknown result type (might be due to invalid IL or missing references) //IL_0794: Expected O, but got Unknown //IL_0aa0: Unknown result type (might be due to invalid IL or missing references) //IL_0aaa: Expected O, but got Unknown //IL_0b73: Unknown result type (might be due to invalid IL or missing references) //IL_0b7d: Expected O, but got Unknown //IL_08b5: Unknown result type (might be due to invalid IL or missing references) //IL_08bf: Expected O, but got Unknown //IL_0907: Unknown result type (might be due to invalid IL or missing references) //IL_0911: Expected O, but got Unknown //IL_0959: Unknown result type (might be due to invalid IL or missing references) //IL_0963: Expected O, but got Unknown //IL_09f2: Unknown result type (might be due to invalid IL or missing references) //IL_09fc: Expected O, but got Unknown this.isBar = isBar; SectionName = section; Func<string, string> func = delegate(string key) { object obj = ReadSavedValue(config, section, key); if (obj == null) { if (!string.IsNullOrEmpty(legacySection)) { return ReadSavedValue(config, legacySection, key); } obj = null; } return (string)obj; }; Func<string, float?> func2 = delegate(string key) { float? num8 = ReadSavedFloat(config, section, key); return (num8.HasValue || string.IsNullOrEmpty(legacySection)) ? num8 : ReadSavedFloat(config, legacySection, key); }; string defaultModel = ModelNameForPrefab(defaultModelPrefab) ?? ModelSources.Keys.First(); PileAppearancePreset pileAppearancePreset = null; if (!isBar) { pileAppearancePreset = CreateDefaultPreset(section, string.IsNullOrEmpty(defaultShape) ? nativeShape : defaultShape, defaultModel, defaultSize, defaultHeight); pilePresets.Add(pileAppearancePreset); AddAdditionalPresets(section, pilePresets); } if (!isBar) { string text = DisplayLayoutName(nativeShape); List<string> list = new List<string> { text }; string[] array = new string[6] { "Coal", "Stone", "Black Marble", "Grausten", "Flint - Experimental", "Obsidian - Experimental" }; foreach (string text2 in array) { if (text2 != text) { list.Add(text2); } } string text3 = DisplayLayoutName(func("Layout") ?? func("Mesh Shape")); string text4 = (list.Contains(text3) ? text3 : pileAppearancePreset.Layout); shape = config.Bind<string>(section, "Layout", text4, new ConfigDescription("Pile placement / fill framework for the next pile. This changes where models sit, not which model is used.", (AcceptableValueBase)(object)new AcceptableValueList<string>(list.ToArray()), new object[1] { new ConfigurationManagerAttributes { Order = 90 } })); } else { string text5 = func("Bar Arrangement"); barArrangement = config.Bind<string>(section, "Bar Arrangement", "Vanilla Cross-Stacked", new ConfigDescription("Visual arrangement saved into each newly placed bar stack. Cross-stacked styles alternate each layer by 90 degrees; Parallel Rows keeps every bar facing the same direction. Brick Stacked alternates full layers with centered N-1 layers so bars bridge the joins below instead of hanging over empty space. The Sideways brick variants use the same bond on the other horizontal axis. Misaligned variants keep the same structure but add small deterministic hand-stacked variation.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[8] { "Vanilla Cross-Stacked", "Misaligned Cross-Stacked", "Parallel Rows", "Misaligned Parallel Rows", "Brick Stacked", "Misaligned Brick Stacked", "Brick Stacked Sideways", "Misaligned Brick Stacked Sideways" }), new object[1] { new ConfigurationManagerAttributes { Order = 100 } })); barArrangement.Value = NormalizeBarArrangement(string.IsNullOrEmpty(text5) ? barArrangement.Value : text5); string value = func("Bars Across"); string value2 = func("Bars Deep"); string value3 = func("Layers High"); barAcross = config.Bind<int>(section, "Bars Across", 2, new ConfigDescription("Horizontal footprint from left to right. Cross-stacked arrangements use 2x2 woven modules, so odd values are rounded down to the nearest even value (minimum 2). The server-wide visual bar cap is set in General Settings.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 12), new object[1] { new ConfigurationManagerAttributes { Order = 90 } })); barDeep = config.Bind<int>(section, "Bars Deep", 2, new ConfigDescription("Horizontal footprint from front to back. Cross-stacked and Brick Stacked arrangements require an even depth, so odd values are rounded down to the nearest even value (minimum 2). Other arrangements can use any value from 1 to 12. The server-wide visual bar cap is set in General Settings.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 12), new object[1] { new ConfigurationManagerAttributes { Order = 80 } })); barLayers = config.Bind<int>(section, "Layers High", 5, new ConfigDescription("Number of vertical layers when the visual is full. The server-wide visual bar cap is set in General Settings.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[1] { new ConfigurationManagerAttributes { Order = 70 } })); if (string.IsNullOrEmpty(value) && int.TryParse(func("Columns"), out var result)) { barAcross.Value = Mathf.Clamp(result, 1, 12); } if (string.IsNullOrEmpty(value3) && int.TryParse(func("Rows"), out var result2)) { barLayers.Value = Mathf.Clamp(result2, 1, 20); } if (string.IsNullOrEmpty(value2)) { barDeep.Value = 2; } barArrangement.Value = NormalizeBarArrangement(barArrangement.Value); SanitizeBarDimensions(); barArrangement.SettingChanged += OnBarLayoutValueChanged; barAcross.SettingChanged += OnBarLayoutValueChanged; barDeep.SettingChanged += OnBarLayoutValueChanged; barLayers.SettingChanged += OnBarLayoutValueChanged; } if (!isBar) { model = config.Bind<string>(section, "Model", pileAppearancePreset.Model, new ConfigDescription("Actual item model repeated through the selected pile layout for the next placement.", (AcceptableValueBase)(object)new AcceptableValueList<string>(ModelSources.Keys.ToArray()), new object[1] { new ConfigurationManagerAttributes { Order = 60, IsAdvanced = true } })); } if (isBar) { string value4 = func("Fill Based On") ?? ReadSavedValue(config, "Storage Capacity", "Ingot Stack Fill Based On") ?? "Occupied Slots"; string value5 = func("Looks Full At") ?? ReadSavedValue(config, "Storage Capacity", "Ingot Stack Looks Full At") ?? "100%"; fillBasis = config.Bind<string>(section, "Fill Based On", DynamicStorageForgePlugin.NormalizeBarFillBasis(value4), new ConfigDescription("How this stack's visual growth is measured. Occupied Slots counts used inventory slots; Stored Bar Count uses the actual number of ingots stored. Saved into each placed stack.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Occupied Slots", "Stored Bar Count" }), new object[1] { new ConfigurationManagerAttributes { Order = 50 } })); looksFullAt = config.Bind<string>(section, "Looks Full At", DynamicStorageForgePlugin.NormalizeBarLooksFullAt(value5), new ConfigDescription("How quickly this stack reaches its fully configured visual. 50% means the visual is full at half of the selected fill basis; Always Full disables dynamic visual fill. Saved into each placed stack.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[6] { "10%", "25%", "50%", "75%", "100%", "Always Full" }), new object[1] { new ConfigurationManagerAttributes { Order = 45 } })); } else { string value6 = func("Looks Full At") ?? ReadSavedValue(config, "Storage Capacity", "Ore Pile Looks Full At") ?? "Match Storage Capacity"; looksFullAt = config.Bind<string>(section, "Looks Full At", DynamicStorageForgePlugin.NormalizePileLooksFullAt(value6), new ConfigDescription("How quickly this pile reaches its full visual. Match Storage Capacity follows the real slot capacity; 10/20/40/60 slots reaches full at that many occupied slots; Always Full disables dynamic visual fill. Saved into each placed pile.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[6] { "Match Storage Capacity", "10 slots", "20 slots", "40 slots", "60 slots", "Always Full" }), new object[1] { new ConfigurationManagerAttributes { Order = 10 } })); } List<string> list2 = new List<string> { isBar ? "Default" : "Model Default" }; list2.AddRange(MaterialSources.Keys); material = config.Bind<string>(section, "Material", isBar ? "Default" : pileAppearancePreset.Material, new ConfigDescription(isBar ? "Vanilla material for the next placement. Default keeps the stack's native material." : "Material override for the next placement. Model Default uses the native material of whichever Model is selected.", (AcceptableValueBase)(object)new AcceptableValueList<string>(list2.ToArray()), new object[1] { new ConfigurationManagerAttributes { Order = 40, IsAdvanced = true } })); if (!isBar && string.Equals(func("Material"), "Default", StringComparison.Ordinal)) { material.Value = "Model Default"; } if (!isBar) { float num2 = func2("Size") ?? pileAppearancePreset.LayoutScale; float num3 = func2("Height") ?? pileAppearancePreset.LayoutHeight; float num4 = func2("Layout Scale") ?? num2; float num5 = func2("Layout Height") ?? num3; float num6 = func2("Model Scale") ?? pileAppearancePreset.ModelScale; layoutScale = config.Bind<float>(section, "Layout Scale", num4, new ConfigDescription("Scales the spacing / footprint of the pile layout without enlarging the individual models.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 80 } })); layoutHeight = config.Bind<float>(section, "Layout Height", num5, new ConfigDescription("Scales only the vertical spacing of the pile layout. The individual item models are not stretched.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 1.5f), new object[1] { new ConfigurationManagerAttributes { Order = 70 } })); modelScale = config.Bind<float>(section, "Model Scale", num6, new ConfigDescription("Uniformly scales each repeated item model without changing the pile layout spacing. 1.0 matches that item's native dropped-world size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 50 } })); float num7 = func2("Visual Vertical Offset") ?? func2("Visual Y Offset") ?? pileAppearancePreset.VisualVerticalOffset; visualVerticalOffset = config.Bind<float>(section, "Visual Vertical Offset", num7, new ConfigDescription("Moves only the pile visuals vertically after layout/model scaling. Negative values sink floating models; the piece root and container stay in place.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 0.5f), new object[1] { new ConfigurationManagerAttributes { Order = 20 } })); } string text6 = func("Finish"); finish = config.Bind<string>(section, "Finish", isBar ? "As Material" : pileAppearancePreset.Finish, new ConfigDescription("Advanced material finish for the visible models. Matte/Satin/Glossy adjust smoothness; Metallic and Polished Metal also force a metallic response. Debug Emissive is an intentionally extreme bright test used to verify that finish changes are reaching the rendered model.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[7] { "As Material", "Matte", "Satin", "Glossy", "Metallic", "Polished Metal", "Debug Emissive" }), new object[1] { new ConfigurationManagerAttributes { Order = 30, IsAdvanced = true } })); if (text6 == "Original") { finish.Value = "As Material"; } if (text6 == "Shiny") { finish.Value = "Glossy"; } if (!isBar) { List<string> list3 = pilePresets.Select((PileAppearancePreset entry) => entry.Name).ToList(); list3.Add("Custom"); preset = config.Bind<string>(section, "Preset", pileAppearancePreset.Name, new ConfigDescription("Curated appearance recipe. Selecting a preset populates the settings below; changing any individual value automatically changes this to Custom.", (AcceptableValueBase)(object)new AcceptableValueList<string>(list3.ToArray()), new object[1] { new ConfigurationManagerAttributes { Order = 100 } })); RefreshPresetFromValues(); preset.SettingChanged += OnPresetChanged; shape.SettingChanged += OnAppearanceValueChanged; model.SettingChanged += OnAppearanceValueChanged; material.SettingChanged += OnAppearanceValueChanged; layoutScale.SettingChanged += OnAppearanceValueChanged; layoutHeight.SettingChanged += OnAppearanceValueChanged; modelScale.SettingChanged += OnAppearanceValueChanged; visualVerticalOffset.SettingChanged += OnAppearanceValueChanged; finish.SettingChanged += OnAppearanceValueChanged; RememberObservedPresetState(); } } private static bool TryGetScrapPresetProfile(string section, out string nativeModel, out string oreModel, out string material) { nativeModel = null; oreModel = null; material = null; if (string.Equals(section, "Copper Scrap Pile (Storage)", StringComparison.Ordinal)) { nativeModel = "Copper Scrap"; oreModel = "Copper Ore"; material = "Copper Scrap"; return true; } if (string.Equals(section, "Bronze Scrap Pile (Storage)", StringComparison.Ordinal)) { nativeModel = "Scrap Bronze"; oreModel = "Copper Ore"; material = "Scrap Bronze"; return true; } if (string.Equals(section, "Iron Scrap Pile (Storage)", StringComparison.Ordinal)) { nativeModel = "Scrap Iron"; oreModel = "Iron Ore"; material = "Scrap Iron"; return true; } if (string.Equals(section, "Black Metal Scrap Pile (Storage)", StringComparison.Ordinal)) { nativeModel = "Black Metal Scrap"; oreModel = "Copper Ore"; material = "Black Metal Scrap"; return true; } return false; } private static PileAppearancePreset CreateDefaultPreset(string section, string fallbackLayout, string defaultModel, float defaultLayoutScale, float defaultLayoutHeight) { if (string.Equals(section, "Copper Ore Pile (Storage)", StringComparison.Ordinal)) { return new PileAppearancePreset("Default (Coal)", "Coal", "Copper Ore", "Model Default", "As Material", 1.4f, 0.8f, 1f, 0.05f); } if (string.Equals(section, "Black Metal Scrap Pile (Storage)", StringComparison.Ordinal)) { return new PileAppearancePreset("Default (Obsidian)", "Obsidian - Experimental", "Black Metal Scrap", "Model Default", "As Material", 1f, 0.9f, 1.1f, 0f); } if (TryGetScrapPresetProfile(section, out var nativeModel, out var _, out var _)) { return new PileAppearancePreset("Default (Black Marble)", "Black Marble", nativeModel, "Model Default", "As Material", 0.8f, 0.5f, 1f, 0f); } if (string.Equals(section, "Tin Ore Pile (Storage)", StringComparison.Ordinal)) { return new PileAppearancePreset("Default (Grausten)", "Grausten", "Tin Ore", "Model Default", "As Material", 0.8f, 0.75f, 1f, 0.03f); } if (string.Equals(section, "Iron Ore Pile (Storage)", StringComparison.Ordinal)) { return new PileAppearancePreset("Default (Stone)", "Stone", "Iron Ore", "Model Default", "As Material", 1.2f, 0.75f, 1f, 0.07f); } if (string.Equals(section, "Silver Ore Pile (Storage)", StringComparison.Ordinal)) { return new PileAppearancePreset("Default (Black Marble)", "Black Marble", "Silver Ore", "Model Default", "As Material", 1.211f, 0.92f, 1f, 0.05f); } if (string.Equals(section, "Flametal Ore Pile (Storage)", StringComparison.Ordinal)) { return new PileAppearancePreset("Default (Coal)", "Coal", "Flametal Ore", "Model Default", "As Material", 2f, 1f, 1f, 0.15f); } if (string.Equals(section, "Petrified Tissue Pile (Storage)", StringComparison.Ordinal)) { return new PileAppearancePreset("Default (Stone)", "Stone", "Petrified Tissue", "Model Default", "As Material", 1.2f, 1.05f, 1f, 0.03f); } string text2 = DisplayLayoutName(string.IsNullOrEmpty(fallbackLayout) ? "Coal" : fallbackLayout); return new PileAppearancePreset("Default (" + text2 + ")", text2, defaultModel, "Model Default", "As Material", defaultLayoutScale, defaultLayoutHeight, 1f, 0f); } private static void AddAdditionalPresets(string section, List<PileAppearancePreset> presets) { if (presets == null) { return; } string nativeModel; string oreModel; string text; if (string.Equals(section, "Copper Ore Pile (Storage)", StringComparison.Ordinal)) { presets.Add(new PileAppearancePreset("Stone", "Stone", "Copper Ore", "Model Default", "As Material", 1.3f, 0.8f, 1f, 0.03f)); } else if (TryGetScrapPresetProfile(section, out nativeModel, out oreModel, out text)) { if (string.Equals(section, "Black Metal Scrap Pile (Storage)", StringComparison.Ordinal)) { presets.Add(new PileAppearancePreset("Black Marble", "Black Marble", nativeModel, "Model Default", "As Material", 0.8f, 0.5f, 1f, 0f)); } presets.Add(new PileAppearancePreset("Stone (Ore Model)", "Stone", oreModel, text, "As Material", 1.08216f, 0.75821f, 0.85915f, 0.02582f)); if (!string.Equals(section, "Black Metal Scrap Pile (Storage)", StringComparison.Ordinal)) { presets.Add(new PileAppearancePreset("Obsidian", "Obsidian - Experimental", nativeModel, "Model Default", "As Material", 1f, 0.9f, 1.1f, 0f)); } presets.Add(new PileAppearancePreset("Flint", "Flint - Experimental", nativeModel, "Model Default", "As Material", 1f, 1f, 1f, -0.1f)); } else if (string.Equals(section, "Tin Ore Pile (Storage)", StringComparison.Ordinal)) { presets.Add(new PileAppearancePreset("Stone", "Stone", "Tin Ore", "Model Default", "As Material", 1.05f, 0.9f, 1f, 0.03f)); presets.Add(new PileAppearancePreset("Coal", "Coal", "Tin Ore", "Model Default", "As Material", 1f, 1f, 1f, 0.13f)); } else if (string.Equals(section, "Silver Ore Pile (Storage)", StringComparison.Ordinal)) { presets.Add(new PileAppearancePreset("Coal", "Coal", "Silver Ore", "Model Default", "Satin", 1f, 1f, 1f, 0f)); } else if (string.Equals(section, "Flametal Ore Pile (Storage)", StringComparison.Ordinal)) { presets.Add(new PileAppearancePreset("Grausten", "Grausten", "Flametal Ore", "Model Default", "As Material", 1.4f, 1.1f, 1f, 0f)); presets.Add(new PileAppearancePreset("Flint - Experimental", "Flint - Experimental", "Flametal Ore", "Model Default", "As Material", 1.81f, 1.3f, 1f, -0.1f)); presets.Add(new PileAppearancePreset("Stone (Glowing Model)", "Stone", "Glowing Metal Ore", "Model Default", "As Material", 1.75f, 1f, 1f, 0.05f)); } else if (string.Equals(section, "Petrified Tissue Pile (Storage)", StringComparison.Ordinal)) { presets.Add(new PileAppearancePreset("Coal", "Coal", "Petrified Tissue", "Model Default", "As Material", 1.48f, 0.95f, 1f, 0.06f)); } } private void OnPresetChanged(object sender, EventArgs args) { if (!updatingPreset && !isBar && preset != null) { ApplySelectedPresetOrRefresh(); RememberObservedPresetState(); } } private void OnAppearanceValueChanged(object sender, EventArgs args) { if (!updatingPreset) { RefreshPresetFromValues(); RememberObservedPresetState(); } } internal void SynchronizePresetSelection() { if (updatingPreset || isBar || preset == null) { return; } string value = preset.Value; string a = BuildAppearanceSignature(); bool flag = !string.Equals(value, observedPresetValue, StringComparison.Ordinal); bool flag2 = !string.Equals(a, observedAppearanceSignature, StringComparison.Ordinal); if (flag || flag2) { if (flag) { ApplySelectedPresetOrRefresh(); } else { RefreshPresetFromValues(); } RememberObservedPresetState(); } } private void ApplySelectedPresetOrRefresh() { if (string.Equals(preset.Value, "Custom", StringComparison.Ordinal)) { RefreshPresetFromValues(); return; } PileAppearancePreset pileAppearancePreset = pilePresets.FirstOrDefault((PileAppearancePreset entry) => string.Equals(entry.Name, preset.Value, StringComparison.Ordinal)); if (pileAppearancePreset == null) { RefreshPresetFromValues(); } else { ApplyPreset(pileAppearancePreset); } } private void ApplyPreset(PileAppearancePreset selected) { if (selected == null) { return; } updatingPreset = true; try { shape.Value = selected.Layout; model.Value = selected.Model; material.Value = selected.Material; layoutScale.Value = selected.LayoutScale; layoutHeight.Value = selected.LayoutHeight; modelScale.Value = selected.ModelScale; visualVerticalOffset.Value = selected.VisualVerticalOffset; finish.Value = selected.Finish; preset.Value = selected.Name; } finally { updatingPreset = false; } } private void RefreshPresetFromValues() { if (isBar || preset == null) { return; } PileAppearancePreset pileAppearancePreset = pilePresets.FirstOrDefault(MatchesPreset); string text = ((pileAppearancePreset != null) ? pileAppearancePreset.Name : "Custom"); if (string.Equals(preset.Value, text, StringComparison.Ordinal)) { return; } updatingPreset = true; try { preset.Value = text; } finally { updatingPreset = false; } } private void RememberObservedPresetState() { if (!isBar && preset != null) { observedPresetValue = preset.Value; observedAppearanceSignature = BuildAppearanceSignature(); } } private string BuildAppearanceSignature() { if (isBar) { return string.Empty; } return string.Join("|", shape.Value ?? string.Empty, model.Value ?? string.Empty, material.Value ?? string.Empty, finish.Value ?? string.Empty, layoutScale.Value.ToString("R", CultureInfo.InvariantCulture), layoutHeight.Value.ToString("R", CultureInfo.InvariantCulture), modelScale.Value.ToString("R", CultureInfo.InvariantCulture), visualVerticalOffset.Value.ToString("R", CultureInfo.InvariantCulture)); } private bool MatchesPreset(PileAppearancePreset candidate) { if (candidate == null) { return false; } if (string.Equals(shape.Value, candidate.Layout, StringComparison.Ordinal) && string.Equals(model.Value, candidate.Model, StringComparison.Ordinal) && string.Equals(material.Value, candidate.Material, StringComparison.Ordinal) && string.Equals(finish.Value, candidate.Finish, StringComparison.Ordinal) && Mathf.Abs(layoutScale.Value - candidate.LayoutScale) <= 0.0005f && Mathf.Abs(layoutHeight.Value - candidate.LayoutHeight) <= 0.0005f && Mathf.Abs(modelScale.Value - candidate.ModelScale) <= 0.0005f) { return Mathf.Abs(visualVerticalOffset.Value - candidate.VisualVerticalOffset) <= 0.0005f; } return false; } internal static string NormalizeBarArrangement(string value) { if (string.IsNullOrEmpty(value)) { return "Vanilla Cross-Stacked"; } if (string.Equals(value, "Vanilla", StringComparison.Ordinal)) { return "Vanilla Cross-Stacked"; } if (string.Equals(value, "Irregular", StringComparison.Ordinal) || string.Equals(value, "Misaligned", StringComparison.Ordinal)) { return "Misaligned Parallel Rows"; } if (string.Equals(value, "Aligned", StringComparison.Ordinal) || string.Equals(value, "Side by Side", StringComparison.Ordinal) || string.Equals(value, "Long Side by Side", StringComparison.Ordinal)) { return "Parallel Rows"; } switch (value) { case "Misaligned Brick Stacked": case "Misaligned Cross-Stacked": case "Misaligned Parallel Rows": case "Brick Stacked": case "Parallel Rows": case "Vanilla Cross-Stacked": case "Brick Stacked Sideways": case "Misaligned Brick Stacked Sideways": return value; default: return "Vanilla Cross-Stacked"; } } internal static bool IsCrossStackedArrangement(string arrangement) { arrangement = NormalizeBarArrangement(arrangement); if (!(arrangement == "Vanilla Cross-Stacked")) { return arrangement == "Misaligned Cross-Stacked"; } return true; } internal static bool IsBrickStackedArrangement(string arrangement) { arrangement = NormalizeBarArrangement(arrangement); switch (arrangement) { default: return arrangement == "Misaligned Brick Stacked Sideways"; case "Brick Stacked": case "Misaligned Brick Stacked": case "Brick Stacked Sideways": return true; } } internal static bool IsBrickStackedSidewaysArrangement(string arrangement) { arrangement = NormalizeBarArrangement(arrangement); if (!(arrangement == "Brick Stacked Sideways")) { return arrangement == "Misaligned Brick Stacked Sideways"; } return true; } internal static bool IsMisalignedArrangement(string arrangement) { arrangement = NormalizeBarArrangement(arrangement); switch (arrangement) { default: return arrangement == "Misaligned Brick Stacked Sideways"; case "Misaligned Cross-Stacked": case "Misaligned Parallel Rows": case "Misaligned Brick Stacked": return true; } } internal static int NormalizeCrossStackDimension(int value) { value = Mathf.Clamp(value, 2, 12); if ((value & 1) != 0) { value--; } return Mathf.Max(2, value); } internal static int NormalizeBrickDeepDimension(int value) { value = Mathf.Clamp(value, 2, 12); if ((value & 1) != 0) { value--; } return Mathf.Max(2, value); } internal static int CalculateBarVisualCount(string arrangement, int across, int deep, int layers) { across = Mathf.Clamp(across, 1, 12); deep = Mathf.Clamp(deep, 1, 12); layers = Mathf.Clamp(layers, 1, 20); arrangement = NormalizeBarArrangement(arrangement); if (IsCrossStackedArrangement(arrangement)) { across = NormalizeCrossStackDimension(across); deep = NormalizeCrossStackDimension(deep); return across * deep / 2 * layers; } if (IsBrickStackedArrangement(arrangement)) { deep = NormalizeBrickDeepDimension(deep); bool num = IsBrickStackedSidewaysArrangement(arrangement); int num2 = (layers + 1) / 2; int num3 = layers / 2; int num4 = across * deep; int num5 = 0; int num6; if (num) { num6 = ((across > 1) ? (across - 1) : across) * deep; if (across > 1) { num5 = deep; } } else { num6 = across * ((deep > 1) ? (deep - 1) : deep); if (deep > 1) { num5 = (across + 1) / 2 * 2; } } return num2 * num4 + num3 * (num6 + num5); } return across * deep * layers; } internal static void SanitizeBarDimensionsToLimit(string arrangement, ref int across, ref int deep, ref int layers, int maxVisualBars) { arrangement = NormalizeBarArrangement(arrangement); bool flag = IsCrossStackedArrangement(arrangement); bool flag2 = IsBrickStackedArrangement(arrangement); across = Mathf.Clamp(across, 1, 12); deep = Mathf.Clamp(deep, 1, 12); layers = Mathf.Clamp(layers, 1, 20); if (flag) { across = NormalizeCrossStackDimension(across); deep = NormalizeCrossStackDimension(deep); } else if (flag2) { deep = NormalizeBrickDeepDimension(deep); } maxVisualBars = Mathf.Clamp(maxVisualBars, 10, 400); while (layers > 1 && CalculateBarVisualCount(arrangement, across, deep, layers) > maxVisualBars) { layers--; } int num = ((!(flag || flag2)) ? 1 : 2); int num2 = ((!(flag || flag2)) ? 1 : 2); int num3 = ((!flag) ? 1 : 2); int num4 = ((!flag) ? 1 : 2); while (deep > num && CalculateBarVisualCount(arrangement, across, deep, layers) > maxVisualBars) { deep -= num2; } while (across > num3 && CalculateBarVisualCount(arrangement, across, deep, layers) > maxVisualBars) { across -= num4; } while (layers > 1 && CalculateBarVisualCount(arrangement, across, deep, layers) > maxVisualBars) { layers--; } } private void OnBarLayoutValueChanged(object sender, EventArgs args) { if (!updatingBarDimensions) { SanitizeBarDimensions(); } } private void SanitizeBarDimensions() { if (!isBar || barAcross == null || barDeep == null || barLayers == null || barArrangement == null) { return; } updatingBarDimensions = true; try { barArrangement.Value = NormalizeBarArrangement(barArrangement.Value); int across = barAcross.Value; int deep = barDeep.Value; int layers = barLayers.Value; SanitizeBarDimensionsToLimit(barArrangement.Value, ref across, ref deep, ref layers, DynamicStorageForgePlugin.CurrentMaxVisualBarsPerStack); barAcross.Value = across; barDeep.Value = deep; barLayers.Value = layers; } finally { updatingBarDimensions = false; } } private static string ReadSavedValue(ConfigFile config, string section, string key) { try { if (!File.Exists(config.ConfigFilePath)) { return null; } bool flag = false; string text = key + " = "; foreach (string item in File.ReadLines(config.ConfigFilePath)) { string text2 = item.Trim(); if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { flag = text2.Substring(1, text2.Length - 2) == section; } else if (flag && text2.StartsWith(text, StringComparison.Ordinal)) { return text2.Substring(text.Length).Trim(); } } } catch (IOException) { } catch (UnauthorizedAccessException) { } return null; } private static float? ReadSavedFloat(ConfigFile config, string section, string key) { string text = ReadSavedValue(config, section, key); if (string.IsNullOrEmpty(text)) { return null; } if (float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } if (float.TryParse(text, out var result2)) { return result2; } return null; } internal AppearanceSnapshot Capture() { AppearanceSnapshot appearanceSnapshot = new AppearanceSnapshot { Preset = ((preset == null) ? "Custom" : preset.Value), Shape = ((shape == null) ? "Default" : shape.Value), Model = ((model == null) ? "Default" : model.Value), Material = material.Value, Tint = "#FFFFFF", Finish = finish.Value, BarArrangement = ((barArrangement == null) ? "Vanilla Cross-Stacked" : NormalizeBarArrangement(barArrangement.Value)), BarAcross = ((barAcross == null) ? 2 : Mathf.Clamp(barAcross.Value, 1, 12)), BarDeep = ((barDeep == null) ? 2 : Mathf.Clamp(barDeep.Value, 1, 12)), BarLayers = ((barLayers == null) ? 5 : Mathf.Clamp(barLayers.Value, 1, 20)), FillBasis = ((isBar && fillBasis != null) ? DynamicStorageForgePlugin.NormalizeBarFillBasis(fillBasis.Value) : "Occupied Slots"), LooksFullAt = (isBar ? DynamicStorageForgePlugin.NormalizeBarLooksFullAt((looksFullAt != null) ? looksFullAt.Value : "100%") : DynamicStorageForgePlugin.NormalizePileLooksFullAt((looksFullAt != null) ? looksFullAt.Value : "Match Storage Capacity")) }; if (isBar) { appearanceSnapshot.Scale = 1f; int across = appearanceSnapshot.BarAcross; int deep = appearanceSnapshot.BarDeep; int layers = appearanceSnapshot.BarLayers; SanitizeBarDimensionsToLimit(appearanceSnapshot.BarArrangement, ref across, ref deep, ref layers, DynamicStorageForgePlugin.CurrentMaxVisualBarsPerStack); appearanceSnapshot.BarAcross = across; appearanceSnapshot.BarDeep = deep; appearanceSnapshot.BarLayers = layers; } else { appearanceSnapshot.LayoutScale = Mathf.Clamp(layoutScale.Value, 0.5f, 3f); appearanceSnapshot.LayoutHeight = Mathf.Clamp(layoutHeight.Value, 0.5f, 1.5f); appearanceSnapshot.ModelScale = Mathf.Clamp(modelScale.Value, 0.5f, 3f); appearanceSnapshot.VisualVerticalOffset = Mathf.Clamp(visualVerticalOffset.Value, -0.5f, 0.5f); } return appearanceSnapshot; } } internal sealed class PileAppearancePreset { internal string Name { get; } internal string Layout { get; } internal string Model { get; } internal string Material { get; } internal string Finish { get; } internal float LayoutScale { get; } internal float LayoutHeight { get; } internal float ModelScale { get; } internal float VisualVerticalOffset { get; } internal PileAppearancePreset(string name, string layout, string model, string material, string finish, float layoutScale, float layoutHeight, float modelScale, float visualVerticalOffset) { Name = name; Layout = layout; Model = model; Material = material; Finish = finish; LayoutScale = layoutScale; LayoutHeight = layoutHeight; ModelScale = modelScale; VisualVerticalOffset = visualVerticalOffset; } } internal sealed class AppearanceSnapshot { internal string Preset = "Custom"; internal string Shape = "Default"; internal string Model = "Default"; internal string Material = "Default"; internal float Scale = 1f; internal float LayoutScale = 1f; internal float LayoutHeight = 1f; internal float ModelScale = 1f; internal float VisualVerticalOffset; internal string Tint = "#FFFFFF"; internal string Finish = "As Material"; internal string BarArrangement = "Vanilla Cross-Stacked"; internal int BarAcross = 2; internal int BarDeep = 2; internal int BarLayers = 5; internal string FillBasis = "Occupied Slots"; internal string LooksFullAt = "Match Storage Capacity"; internal string Identity => Shape + "|" + Model + "|" + Material + "|" + Scale.ToString("R", CultureInfo.InvariantCulture) + "|" + LayoutScale.ToString("R", CultureInfo.InvariantCulture) + "|" + LayoutHeight.ToString("R", CultureInfo.InvariantCulture) + "|" + ModelScale.ToString("R", CultureInfo.InvariantCulture) + "|" + VisualVerticalOffset.ToString("R", CultureInfo.InvariantCulture) + "|" + Tint + "|" + Finish + "|" + BarArrangement + "|" + BarAcross.ToString(CultureInfo.InvariantCulture) + "|" + BarDeep.ToString(CultureInfo.InvariantCulture) + "|" + BarLayers.ToString(CultureInfo.InvariantCulture) + "|" + FillBasis + "|" + LooksFullAt; internal static string NormalizeTint(string value) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) string text = (value ?? "").Trim(); if (!text.StartsWith("#", StringComparison.Ordinal)) { text = "#" + text; } Color val = default(Color); if (!ColorUtility.TryParseHtmlString(text, ref val)) { return "#FFFFFF"; } return "#" + ColorUtility.ToHtmlStringRGB(val); } } internal sealed class ConfigurationManagerAttributes { public int? Order; public bool? IsAdminOnly; public bool? ReadOnly; public bool? Browsable; public bool? IsAdvanced; } [BepInPlugin("com.modularvalheim.DynamicStorageForge", "Dynamic Storage Forge Piles", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal sealed class DynamicStorageForgePlugin : BaseUnityPlugin { private sealed class BarDefinition { public string BasePiecePrefab { get; } public string DestroyedVfxPrefab { get; } public string ResourceItemPrefab { get; } public string NewPrefabName { get; } public string DisplayName { get; } public int BuildCost { get; } public BarDefinition(string basePiecePrefab, string destroyedVfxPrefab, string resourceItemPrefab, string newPrefabName, string displayName, int buildCost) { BasePiecePrefab = basePiecePrefab; DestroyedVfxPrefab = destroyedVfxPrefab; ResourceItemPrefab = resourceItemPrefab; NewPrefabName = newPrefabName; DisplayName = displayName; BuildCost = buildCost; } } private sealed class TemplateDefinition { public string BasePilePrefab { get; } public string MaterialSourcePrefab { get; } public string ResourceItemPrefab { get; } public string NewPrefabName { get; } public string DisplayName { get; } public int BuildCost { get; } public float LocalScaleMultiplier { get; } public string DefaultShape { get; } public float DefaultSize { get; } public float DefaultHeight { get; } public string ConfigSectionName { get; } public string LegacyConfigSectionName { get; } public TemplateDefinition(string basePilePrefab, string materialSourcePrefab, string resourceItemPrefab, string newPrefabName, string displayName, int buildCost, float localScaleMultiplier = 1f, string defaultShape = null, float defaultSize = 1f, float defaultHeight = 1f, string configSectionName = null, string legacyConfigSectionName = null) { BasePilePrefab = basePilePrefab; MaterialSourcePrefab = materialSourcePrefab; ResourceItemPrefab = resourceItemPrefab; NewPrefabName = newPrefabName; DisplayName = displayName; BuildCost = buildCost; LocalScaleMultiplier = localScaleMultiplier; DefaultShape = defaultShape; DefaultSize = defaultSize; DefaultHeight = defaultHeight; ConfigSectionName = (string.IsNullOrEmpty(configSectionName) ? displayName : configSectionName); LegacyConfigSectionName = legacyConfigSectionName; } } public const string PluginGuid = "com.modularvalheim.DynamicStorageForge"; public const string PluginName = "Dynamic Storage Forge Piles"; public const string PluginVersion = "1.0.0"; private Harmony placementHarmony; private Harmony restrictionHarmony; private readonly List<CustomPiece> piecesNeedingIcons = new List<CustomPiece>(); private readonly List<GameObject> forgeBuildPiecePrefabs = new List<GameObject>(); private bool pieceIconsQueued; private ConfigEntry<bool> showMeshDebugHover; private ConfigEntry<bool> showTechnicalDebugHover; private ConfigEntry<bool> showDroppedModelDebugHover; private ConfigEntry<bool> enableApplyConfigDebug; private ConfigEntry<int> orePileStorageCapacity; private ConfigEntry<int> ingotStackStorageCapacity; private ConfigEntry<int> maxVisualBarsPerStack; private ConfigEntry<bool> showForgeBuildPieces; private PlacedAppearance configApplyHoverTarget; private float configApplyHoverTargetUntil; private PlacedAppearance debugHoverTarget; private float debugHoverTargetUntil; private PlacedAppearance debugOverrideTarget; private static bool hoverErrorLogged; private float nextPresetConfigSync; internal const float ObsidianVisualGroundOffset = -0.0508f; internal const int AbsoluteMaxVisualBarsPerStack = 400; private readonly List<BarDefinition> barDefinitions = new List<BarDefinition> { new BarDefinition("bar_copper_stack", "vfx_bar_copper_stack_destroyed", "Copper", "DSF_CopperStack", "Copper Stack (Storage)", 3), new BarDefinition("bar_bronze_stack", "vfx_bar_bronze_stack_destroyed", "Bronze", "DSF_BronzeStack", "Bronze Stack (Storage)", 3), new BarDefinition("bar_iron_stack", "vfx_bar_iron_stack_destroyed", "Iron", "DSF_IronStack", "Iron Stack (Storage)", 3), new BarDefinition("bar_silver_stack", "vfx_bar_silver_stack_destroyed", "Silver", "DSF_SilverStack", "Silver Stack (Storage)", 3), new BarDefinition("bar_blackmetal_stack", "vfx_bar_blackmetal_stack_destroyed", "BlackMetal", "DSF_BlackMetalStack", "Black Metal Stack (Storage)", 3), new BarDefinition("bar_flametal_stack", "vfx_bar_flametal_stack_destroyed", "FlametalNew", "DSF_FlametalStack", "Flametal Stack (Storage)", 3), new BarDefinition("bar_ancientmetal_stack", "vfx_bar_ancientmetal_stack_destroyed", "Flametal", "DSF_AncientMetalStack", "Ancient Metal Stack (Storage)", 3), new BarDefinition("bar_gold_stack", "vfx_bar_gold_stack_destroyed", "Gold", "DSF_BloodgoldStack", "Bloodgold Stack (Storage)", 3), new BarDefinition("bar_tin_stack", "vfx_bar_tin_stack_destroyed", "Tin", "DSF_TinStack", "Tin Stack (Storage)", 3) }; private readonly List<TemplateDefinition> templateDefinitions = new List<TemplateDefinition> { new TemplateDefinition("coal_pile", "CopperOre", "CopperOre", "DSF_CopperOrePile", "Copper Ore Pile (Storage)", 10), new TemplateDefinition("coal_pile", "CopperScrap", "CopperScrap", "DSF_CopperScrapPile", "Copper Scrap Pile (Storage)", 10), new TemplateDefinition("coal_pile", "TinOre", "TinOre", "DSF_TinOrePile", "Tin Ore Pile (Storage)", 10), new TemplateDefinition("blackmarble_pile", "BronzeScrap", "BronzeScrap", "DSF_BronzeScrapPile", "Bronze Scrap Pile (Storage)", 10, 0.6f, null, 1f, 1f, "Bronze Scrap Pile (Storage)", "Scrap Bronze Pile (Storage)"), new TemplateDefinition("blackmarble_pile", "IronOre", "IronOre", "DSF_IronOrePile", "Iron Ore Pile (Storage)", 10, 0.6f), new TemplateDefinition("blackmarble_pile", "IronScrap", "IronScrap", "DSF_IronScrapPile", "Iron Scrap Pile (Storage)", 10, 0.6f, null, 1f, 1f, "Iron Scrap Pile (Storage)", "Scrap Iron Pile (Storage)"), new TemplateDefinition("coal_pile", "SilverOre", "SilverOre", "DSF_SilverOrePile", "Silver Ore Pile (Storage)", 10), new TemplateDefinition("blackmarble_pile", "BlackMetalScrap", "BlackMetalScrap", "DSF_BlackMetalScrapPile", "Black Metal Scrap Pile (Storage)", 10, 0.6f), new TemplateDefinition("stone_pile", "FlametalOreNew", "FlametalOreNew", "DSF_FlametalOrePile", "Flametal Ore Pile (Storage)", 10, 1f, "Coal", 2f, 0.8f), new TemplateDefinition("stone_pile", "GoldOre", "GoldOre", "DSF_PetrifiedTissuePile", "Petrified Tissue Pile (Storage)", 10) }; internal static DynamicStorageForgePlugin Current { get; private set; } internal bool ShowAppearanceDebugHover => EnableApplyConfigDebug; internal bool ShowMeshDebugHover { get { if (showMeshDebugHover != null) { return showMeshDebugHover.Value; } return false; } } internal bool ShowTechnicalDebugHover { get { if (showTechnicalDebugHover != null) { return showTechnicalDebugHover.Value; } return false; } } internal bool ShowDroppedModelDebugHover { get { if (showDroppedModelDebugHover != null) { return showDroppedModelDebugHover.Value; } return false; } } internal bool EnableApplyConfigDebug { get { if (enableApplyConfigDebug != null) { return enableApplyConfigDebug.Value; } return false; } } internal int OrePileStorageCapacity => NormalizeStorageCapacity((orePileStorageCapacity != null) ? orePileStorageCapacity.Value : 20); internal int IngotStackStorageCapacity => NormalizeStorageCapacity((ingotStackStorageCapacity != null) ? ingotStackStorageCapacity.Value : 20); internal int MaxVisualBarsPerStack => Mathf.Clamp((maxVisualBarsPerStack != null) ? maxVisualBarsPerStack.Value : 120, 10, 400); internal static int CurrentMaxVisualBarsPerStack { get { if (!((Object)(object)Current != (Object)null)) { return 120; } return Current.MaxVisualBarsPerStack; } } internal bool ShowAnyDebugHover { get { if (!EnableApplyConfigDebug && !ShowMeshDebugHover) { return ShowTechnicalDebugHover; } return true; } } private void Awake() { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Expected O, but got Unknown Current = this; AcceptableValueList<int> val = new AcceptableValueList<int>(new int[4] { 10, 20, 40, 60 }); int value = ReadSavedInt("Storage Capacity", "Ore Pile Slots", 20); int value2 = ReadSavedInt("Storage Capacity", "Ingot Stack Slots", 20); bool flag = ReadSavedBool("Build Menu", "Show Forge Build Pieces", fallback: true); orePileStorageCapacity = ConfigFileExtensions.BindConfig<int>(((BaseUnityPlugin)this).Config, "General Settings", "Ore Pile Slots", NormalizeStorageCapacity(value), "Server-controlled slot count for ore/scrap/resource piles. Options: 10, 20, 40, or 60.", true, (int?)100, (AcceptableValueBase)(object)val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ingotStackStorageCapacity = ConfigFileExtensions.BindConfig<int>(((BaseUnityPlugin)this).Config, "General Settings", "Ingot Stack Slots", NormalizeStorageCapacity(value2), "Server-controlled slot count for metal ingot/bar stacks. Options: 10, 20, 40, or 60.", true, (int?)90, (AcceptableValueBase)(object)val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); maxVisualBarsPerStack = ConfigFileExtensions.BindConfig<int>(((BaseUnityPlugin)this).Config, "General Settings", "Maximum Visual Bars Per Stack", 120, "Server-controlled visual safety cap for generated ingot/bar meshes on a single placed stack. Default: 120. This does not change storage capacity.", true, (int?)80, (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 400), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); showForgeBuildPieces = ((BaseUnityPlugin)this).Config.Bind<bool>("General Settings", "Show Forge Build Pieces", flag, new ConfigDescription("Client-local only. Turn this off to hide Dynamic Storage Forge Piles blueprints from the Hammer build menu. Existing placed storage remains registered and fully usable.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 70 } })); orePileStorageCapacity.SettingChanged += OnStorageCapacityChanged; ingotStackStorageCapacity.SettingChanged += OnStorageCapacityChanged; maxVisualBarsPerStack.SettingChanged += OnMaximumVisualBarsChanged; showForgeBuildPieces.SettingChanged += OnShowForgeBuildPiecesChanged; BindAppearanceEditorSettings(); InstallPlacementHook(); InstallHoverHook(); restrictionHarmony = new Harmony("com.modularvalheim.DynamicStorageForge.restrictions"); if (!ForgeInventoryRestrictionPatches.Install(restrictionHarmony)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"One or more Forge item restriction hooks could not be installed."); } if (!ForgeStorageCapacityPatches.Install(restrictionHarmony)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Forge storage-capacity safety hook could not be installed."); } PrefabManager.OnPrefabsRegistered += OnPrefabsRegistered; PieceManager.OnPiecesRegistered += OnPiecesRegistered; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Dynamic Storage Forge Piles 1.0.0 loaded; waiting for prefabs."); } private void BindAppearanceEditorSettings() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown enableApplyConfigDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Appearance Editor", "Pile Appearance Editor", false, new ConfigDescription("Shows a colour-coded appearance summary while looking at Forge storage and enables R to apply the current configuration for that exact pile/stack 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 } })); } private void BindDebugSettings() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown showMeshDebugHover = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Show Mesh Debug On Hover", false, new ConfigDescription("Show the generic mesh inspector for Forge visual stacks. Use Left/Right to select a mesh stage, Up/Down to show or hide it, and Right Ctrl to lock/unlock the selected layer.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdvanced = true } })); showTechnicalDebugHover = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Show Technical Debug On Hover", false, new ConfigDescription("Show snapshot and ZDO ownership troubleshooting information.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdvanced = true } })); showDroppedModelDebugHover = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Show Dropped Model Debug On Hover", false, new ConfigDescription("Append DSF model-size diagnostics to supported loose/dropped items so Model Scale 1.0 can be verified against the actual world item.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdvanced = true } })); } private void OnStorageCapacityChanged(object sender, EventArgs args) { ForgeStorageCapacity.RefreshAll(); ForgeVisualStack.RefreshAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Storage capacity updated: ore piles={OrePileStorageCapacity}, " + $"ingot stacks={IngotStackStorageCapacity}.")); } private void OnMaximumVisualBarsChanged(object sender, EventArgs args) { PlacedAppearance[] array = Object.FindObjectsOfType<PlacedAppearance>(); foreach (PlacedAppearance placedAppearance in array) { if (Object.op_Implicit((Object)(object)placedAppearance)) { placedAppearance.ForceAppearanceRefresh(); } } } private void OnShowForgeBuildPiecesChanged(object sender, EventArgs args) { ApplyForgeBuildPieceVisibility(); } private void ApplyForgeBuildPieceVisibility() { if (showForgeBuildPieces == null || PieceManager.Instance == null) { return; } PieceTable pieceTable = PieceManager.Instance.GetPieceTable(PieceTables.Hammer); if (!Object.op_Implicit((Object)(object)pieceTable) || pieceTable.m_pieces == null) { return; } bool value = showForgeBuildPieces.Value; int num = 0; foreach (GameObject forgeBuildPiecePrefab in forgeBuildPiecePrefabs) { if (Object.op_Implicit((Object)(object)forgeBuildPiecePrefab)) { bool flag = pieceTable.m_pieces.Contains(forgeBuildPiecePrefab); if (value && !flag) { pieceTable.m_pieces.Add(forgeBuildPiecePrefab); num++; } else if (!value && flag) { pieceTable.m_pieces.Remove(forgeBuildPiecePrefab); num++; } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Forge Hammer blueprints " + (value ? "shown" : "hidden") + ((num > 0) ? $" ({num} menu entries updated)." : "."))); } private string ReadSavedValue(string section, string key) { try { if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { return null; } bool flag = false; string text = key + " = "; foreach (string item in File.ReadLines(((BaseUnityPlugin)this).Config.ConfigFilePath)) { string text2 = item.Trim(); if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { flag = text2.Substring(1, text2.Length - 2) == section; } else if (flag && text2.StartsWith(text, StringComparison.Ordinal)) { return text2.Substring(text.Length).Trim(); } } } catch (IOException) { } catch (UnauthorizedAccessException) { } return null; } private int ReadSavedInt(string section, string key, int fallback) { if (!int.TryParse(ReadSavedValue(section, key), out var result)) { return fallback; } return result; } private bool ReadSavedBool(string section, string key, bool fallback) { if (!bool.TryParse(ReadSavedValue(section, key), out var result)) { return fallback; } return result; } internal static string NormalizeBarFillBasis(string value) { if (!string.Equals(value, "Stored Bar Count", StringComparison.Ordinal)) { return "Occupied Slots"; } return "Stored Bar Count"; } internal static string NormalizeBarLooksFullAt(string value) { if (string.Equals(value, "Always Full", StringComparison.Ordinal)) { return "Always Full"; } switch (value) { case "10%": case "25%": case "50%": case "75%": case "100%": return value; default: return "100%"; } } internal static int ParseBarLooksFullPercent(string value) { return NormalizeBarLooksFullAt(value) switch { "Always Full" => -1, "10%" => 10, "25%" => 25, "50%" => 50, "75%" => 75, _ => 100, }; } internal static string NormalizePileLooksFullAt(string value) { if (string.IsNullOrEmpty(value) || string.Equals(value, "Match Storage Capacity", StringComparison.Ordinal)) { return "Match Storage Capacity"; } if (string.Equals(value, "Always Full", StringComparison.Ordinal)) { return "Always Full"; } if (value.StartsWith("10", StringComparison.Ordinal)) { return "10 slots"; } if (value.StartsWith("20", StringComparison.Ordinal)) { return "20 slots"; } if (value.StartsWith("40", StringComparison.Ordinal)) { return "40 slots"; } if (value.StartsWith("60", StringComparison.Ordinal)) { return "60 slots"; } return "Match Storage Capacity"; } internal static int ParsePileLooksFullSlots(string value) { return NormalizePileLooksFullAt(value) switch { "Always Full" => -1, "10 slots" => 10, "20 slots" => 20, "40 slots" => 40, "60 slots" => 60, _ => 0, }; } 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 void LateUpdate() { if (Time.unscaledTime >= nextPresetConfigSync) { nextPresetConfigSync = Time.unscaledTime + 0.1f; PlacedAppearance.SynchronizeConfigPresets(); } bool flag = EnableApplyConfigDebug && Object.op_Implicit((Object)(object)configApplyHoverTarget) && Time.unscaledTime <= configApplyHoverTargetUntil; if (!EnableApplyConfigDebug) { configApplyHoverTarget = null; } else if (flag && Input.GetKeyDown((KeyCode)114)) { configApplyHoverTarget.ApplyCurrentConfigToPlacedPiece(); } if (!ShowMeshDebugHover) { if (Object.op_Implicit((Object)(object)debugOverrideTarget)) { debugOverrideTarget.ClearDebugMeshOverride(); } debugOverrideTarget = null; debugHoverTarget = null; return; } if (Object.op_Implicit((Object)(object)debugOverrideTarget) && !debugOverrideTarget.RefreshDebugMeshOverride()) { debugOverrideTarget = null; } if (!Object.op_Implicit((Object)(object)debugHoverTarget) || !(Time.unscaledTime <= debugHoverTargetUntil)) { return; } int num = (Input.GetKeyDown((KeyCode)275) ? 1 : (Input.GetKeyDown((KeyCode)276) ? (-1) : 0)); bool keyDown = Input.GetKeyDown((KeyCode)273); bool keyDown2 = Input.GetKeyDown((KeyCode)274); bool keyDown3 = Input.GetKeyDown((KeyCode)305); if (num == 0 && !keyDown && !keyDown2 && !keyDown3) { return; } if (Object.op_Implicit((Object)(object)debugOverrideTarget) && (Object)(object)debugOverrideTarget != (Object)(object)debugHoverTarget) { debugOverrideTarget.ClearDebugMeshOverride(); debugOverrideTarget = null; } if (num != 0) { debugHoverTarget.DebugSelectMesh(num); } if (keyDown3) { if (debugHoverTarget.DebugToggleLockedLayer()) { debugOverrideTarget = debugHoverTarget; } else if ((Object)(object)debugOverrideTarget == (Object)(object)debugHoverTarget) { debugOverrideTarget = null; } } if (keyDown && debugHoverTarget.DebugSetSelectedMeshVisible(visible: true)) { debugOverrideTarget = debugHoverTarget; } else if (keyDown2 && debugHoverTarget.DebugSetSelectedMeshVisible(visible: false)) { debugOverrideTarget = debugHoverTarget; } } private void OnDestroy() { PrefabManager.OnPrefabsRegistered -= OnPrefabsRegistered; PieceManager.OnPiecesRegistered -= OnPiecesRegistered; Harmony obj = placementHarmony; if (obj != null) { obj.UnpatchSelf(); } Harmony obj2 = restrictionHarmony; if (obj2 != null) { obj2.UnpatchSelf(); } if ((Object)(object)Current == (Object)(object)this) { Current = null; } } private void InstallPlacementHook() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown MethodInfo[] array = (from methodInfo2 in typeof(Piece).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where methodInfo2.Name == "SetCreator" && methodInfo2.GetParameters().Length != 0 && methodInfo2.GetParameters()[0].ParameterType == typeof(long) select methodInfo2).ToArray(); if (array.Length == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"No Piece.SetCreator overload with a long creator ID was found; appearance snapshots cannot be saved."); return; } if (placementHarmony == null) { placementHarmony = new Harmony("com.modularvalheim.DynamicStorageForge.appearance"); } MethodInfo method = typeof(DynamicStorageForgePlugin).GetMethod("CaptureNewPiece", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array2 = array; foreach (MethodInfo methodInfo in array2) { try { placementHarmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Appearance placement hook installed on Piece.{methodInfo}."); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Could not install appearance hook on Piece.{methodInfo}: {arg}"); } } } private void InstallHoverHook() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown MethodInfo method = typeof(Container).GetMethod("GetHoverText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method == null || method.ReturnType != typeof(string)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Container.GetHoverText() not found; appearance hover debug is unavailable."); return; } try { if (placementHarmony == null) { placementHarmony = new Harmony("com.modularvalheim.DynamicStorageForge.appearance"); } MethodInfo method2 = typeof(DynamicStorageForgePlugin).GetMethod("AddAppearanceDebugHover", BindingFlags.Static | BindingFlags.NonPublic); placementHarmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo method3 = typeof(ItemDrop).GetMethod("GetHoverText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method3 != null && method3.ReturnType == typeof(string)) { MethodInfo method4 = typeof(DynamicStorageForgePlugin).GetMethod("AddDroppedModelDebugHover", BindingFlags.Static | BindingFlags.NonPublic); placementHarmony.Patch((MethodBase)method3, (HarmonyMethod)null, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Could not install appearance editor hover: {arg}"); } } private static void AddAppearanceDebugHover(Container __instance, ref string __result) { if ((Object)(object)Current == (Object)null || !Current.ShowAnyDebugHover || !Object.op_Implicit((Object)(object)__instance)) { return; } try { PlacedAppearance component = ((Component)__instance).GetComponent<PlacedAppearance>(); if (Object.op_Implicit((Object)(object)component)) { if (Current.ShowMeshDebugHover) { Current.debugHoverTarget = component; Current.debugHoverTargetUntil = Time.unscaledTime + 0.35f; } if (Current.EnableApplyConfigDebug) { Current.configApplyHoverTarget = component; Current.configApplyHoverTargetUntil = Time.unscaledTime + 0.35f; } __result = (__result ?? string.Empty) + component.GetDebugHoverText(Current.ShowAppearanceDebugHover, Current.ShowMeshDebugHover, Current.ShowTechnicalDebugHover, Current.EnableApplyConfigDebug); } } catch (Exception arg) { if (!hoverErrorLogged) { ((BaseUnityPlugin)Current).Logger.LogWarning((object)$"Forge appearance/editor hover failed: {arg}"); hoverErrorLogged = true; } } } private static void AddDroppedModelDebugHover(ItemDrop __instance, ref string __result) { //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Current == (Object)null || !Current.ShowDroppedModelDebugHover || !Object.op_Implicit((Object)(object)__instance)) { return; } try { string text = null; if (__instance.m_itemData != null && Object.op_Implicit((Object)(object)__instance.m_itemData.m_dropPrefab)) { text = ((Object)__instance.m_itemData.m_dropPrefab).name; } if (string.IsNullOrEmpty(text)) { text = ((Object)((Component)__instance).gameObject).name ?? string.Empty; int num = text.IndexOfAny(new char[2] { '(', ' ' }); if (num > 0) { text = text.Substring(0, num); } } string value = AppearanceSettings.ModelNameForPrefab(text); if (string.IsNullOrEmpty(value)) { return; } Vector3 size; bool flag = ForgePileStageDefinitions.TryMeasureModelInstanceWorldSize(((Component)__instance).gameObject, out size); Vector3 size2; bool flag2 = ForgePileStageDefinitions.TryGetNativeModelWorldSize(text, out size2); if (flag || flag2) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("\n<color=#8AD7FF>DSF DROPPED MODEL DEBUG — ").Append(value).Append("</color>"); if (flag) { stringBuilder.Append("\nDropped rendered size: ").Append(FormatDebugSize(size)).Append(" m"); } if (flag2) { stringBuilder.Append("\nForge Model Scale 1.0: ").Append(FormatDebugSize(size2)).Append(" m"); } __result = (__result ?? string.Empty) + stringBuilder.ToString(); } } catch (Exception ex) { if (!hoverErrorLogged) { ((BaseUnityPlugin)Current).Logger.LogWarning((object)("DSF dropped-model hover debug failed: " + ex)); hoverErrorLogged = true; } } } private static string FormatDebugSize(Vector3 size) { return size.x.ToString("0.###", CultureInfo.InvariantCulture) + " × " + size.y.ToString("0.###", CultureInfo.InvariantCulture) + " × " + size.z.ToString("0.###", CultureInfo.InvariantCulture); } private static void CaptureNewPiece(Piece __instance) { try { if (Object.op_Implicit((Object)(object)__instance)) { PlacedAppearance component = ((Component)__instance).GetComponent<PlacedAppearance>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { component.SavePlacementDefaults(); } } } catch (Exception arg) { DynamicStorageForgePlugin current = Current; if (current != null) { ((BaseUnityPlugin)current).Logger.LogError((object)$"Appearance could not be saved on new piece: {arg}"); } } } private void OnPiecesRegistered() { if (!pieceIconsQueued) { foreach (CustomPiece piecesNeedingIcon in piecesNeedingIcons) { if (piecesNeedingIcon != null && Object.op_Implicit((Object)(object)piecesNeedingIcon.PiecePrefab) && (Object)(object)piecesNeedingIcon.Piece != (Object)null) { ((MonoBehaviour)this).StartCoroutine(RenderPieceIcon(piecesNeedingIcon)); } } pieceIconsQueued = true; } ApplyForgeBuildPieceVisibility(); } private IEnumerator RenderPieceIcon(CustomPiece piece) { yield return null; ForgeVisualStack[] componentsInChildren = ((Component)piece.Piece).GetComponentsInChildren<ForgeVisualStack>(true); ForgeVisualStack[] array = componentsInChildren; foreach (ForgeVisualStack forgeVisualStack in array) { if (Object.op_Implicit((Object)(object)forgeVisualStack)) { forgeVisualStack.SetVisualsActive(55f); } } piece.Piece.m_icon = RenderManager.Instance.Render(new RenderRequest(piece.PiecePrefab) { Width = 64, Height = 64, Rotation = RenderManager.IsometricRotation * Quaternion.Euler(0f, -90f, 0f), UseCache = true, TargetPlugin = ((BaseUnityPlugin)this).Info.Metadata }); array = componentsInChildren; foreach (ForgeVisualStack forgeVisualStack2 in array) { if (Object.op_Implicit((Object)(object)forgeVisualStack2)) { forgeVisualStack2.SetVisualsActive(100f); } } } private void OnPrefabsRegistered() { PrefabManager.OnPrefabsRegistered -= OnPrefabsRegistered; int num = 0; PlacedAppearance.CacheSources(); foreach (TemplateDefinition templateDefinition in templateDefinitions) { try { if (TryRegisterTemplatePile(templateDefinition)) { num++; } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"{templateDefinition.NewPrefabName}: {arg}"); } } foreach (BarDefinition barDefinition in barDefinitions) { try { if (TryRegisterBarStack(barDefinition)) { num++; } } catch (Exception arg2) { ((BaseUnityPlugin)this).Logger.LogError((object)$"{barDefinition.NewPrefabName}: {arg2}"); } } BindDebugSettings(); ((BaseUnityPlugin)this).Logger.LogInfo((object)(string.Format("{0}: registered {1} of ", "Dynamic Storage Forge Piles", num) + $"{barDefinitions.Count + templateDefinitions.Count} storage pieces.")); } private bool TryRegisterBarStack(BarDefinition definition) { //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0211: 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) GameObject prefab = PrefabManager.Instance.GetPrefab(definition.BasePiecePrefab); if (!Object.op_Implicit((Object)(object)prefab)) { return Fail(definition.NewPrefabName, "base piece '" + definition.BasePiecePrefab + "' not found"); } GameObject val = FindDestroyedVfx(prefab, definition.DestroyedVfxPrefab); if (!Object.op_Implicit((Object)(object)val)) { val = PrefabManager.Instance.GetPrefab(definition.DestroyedVfxPrefab); } if (!Object.op_Implicit((Object)(object)val)) { return Fail(definition.NewPrefabName, "destroyed VFX '" + definition.DestroyedVfxPrefab + "' not found"); } GameObject prefab2 = PrefabManager.Instance.GetPrefab(definition.ResourceItemPrefab); if (!Object.op_Implicit((Object)(object)prefab2)) { return Fail(definition.NewPrefabName, "resource item '" + definition.ResourceItemPrefab + "' not found"); } MeshRenderer componentInChildren = prefab2.GetComponentInChildren<MeshRenderer>(true); if (!Object.op_Implicit((Object)(object)componentInChildren) || !Object.op_Implicit((Object)(object)((Renderer)componentInChildren).sharedMaterial)) { return Fail(definition.NewPrefabName, "resource item '" + definition.ResourceItemPrefab + "' has no bar material"); } GameObject val2 = PrefabManager.Instance.CreateClonedPrefab(definition.NewPrefabName, prefab); if (!Object.op_Implicit((Object)(object)val2)) { return Fail(definition.NewPrefabName, "CreateClonedPrefab returned null"); } MeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<MeshRenderer>(true); Component[] componentsInChildren2 = val2.GetComponentsInChildren<Component>(true); foreach (Component val3 in componentsInChildren2) { if (Object.op_Implicit((Object)(object)val3) && ((object)val3).GetType().Name == "SimpleMeshCombine") { Object.DestroyImmediate((Object)(object)val3); } } int layer = ((componentsInChildren.Length != 0) ? ((Component)componentsInChildren[0]).gameObject.layer : val2.layer); MeshRenderer[] array = componentsInChildren; for (int i = 0; i < array.Length; i++) { ((Renderer)array[i]).enabled = false; } Transform transform = new GameObject("dynamic_bar_visuals").transform; ((Component)transform).gameObject.layer = layer; transform.SetParent(val2.transform, false); transform.localPosition = val.transform.localPosition; transform.localRotation = val.transform.localRotation; transform.localScale = val.transform.localScale; int num = CopyBarMeshes(val, transform, ((Renderer)componentInChildren).sharedMaterial); if (num < 2) { return Fail(definition.NewPrefabName, $"destroyed VFX provided only {num} usable meshes"); } if (!PrepareAsDynamicStorage(val2, prefab, definition.DisplayName, requireMultipleMeshes: true, transform, stripDestroyedVfx: false, isBarStack: true)) { return Fail(definition.NewPrefabName, "failed to prepare dynamic storage prefab"); } AttachAppearance(val2, definition.NewPrefabName, definition.ResourceItemPrefab, definition.DisplayName, isBar: true); if (!RegisterStandalonePiece(val2, definition.ResourceItemPrefab, definition.BuildCost)) { return false; } ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Registered {definition.DisplayName} with {num} active " + "meshes from " + definition.DestroyedVfxPrefab + ".")); return true; } private static int CopyBarMeshes(GameObject vfx, Transform targetRoot, Material barMaterial) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) int num = 0; MeshRenderer[] componentsInChildren = vfx.GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val in componentsInChildren) { MeshFilter component = ((Component)val).GetComponent<MeshFilter>(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.sharedMesh)) { continue; } List<Transform> list = new List<Transform>(); Transform val2 = ((Component)val).transform; while (Object.op_Implicit((Object)(object)val2) && (Object)(object)val2 != (Object)(object)vfx.transform) { list.Add(val2); val2 = val2.parent; } if (list.Count != 0) { Transform val3 = targetRoot; for (int num2 = list.Count - 1; num2 >= 0; num2--) { Transform val4 = list[num2]; GameObject val5 = new GameObject($"bar_{num:D2}_{((Object)val4).name}") { layer = ((Component)targetRoot).gameObject.layer }; Transform val6 = val3; val3 = val5.transform; val3.SetParent(val6, false); val3.localPosition = val4.localPosition; val3.localRotation = val4.localRotation; val3.localScale = val4.localScale; } ((Component)val3).gameObject.AddComponent<MeshFilter>().sharedMesh = component.sharedMesh; MeshRenderer obj = ((Component)val3).gameObject.AddComponent<MeshRenderer>(); int count = Math.Max(1, ((Renderer)val).sharedMaterials.Length); ((Renderer)obj).sharedMaterials = Enumerable.Repeat<Material>(barMaterial, count).ToArray(); ((Renderer)obj).shadowCastingMode = ((Renderer)val).shadowCastingMode; ((Renderer)obj).receiveShadows = ((Renderer)val).receiveShadows; ((Renderer)obj).enabled = true; num++; } } return num; } private bool TryRegisterTemplatePile(TemplateDefinition definition) { //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = PrefabManager.Instance.GetPrefab(definition.BasePilePrefab); if (!Object.op_Implicit((Object)(object)prefab)) { return Fail(definition.NewPrefabName, "base pile '" + definition.BasePilePrefab + "' not found"); } GameObject prefab2 = PrefabManager.Instance.GetPrefab(definition.MaterialSourcePrefab); if (!Object.op_Implicit((Object)(object)prefab2)) { return Fail(definition.NewPrefabName, "material source '" + definition.MaterialSourcePrefab + "' not found"); } if (!Object.op_Implicit((Object)(object)PrefabManager.Instance.GetPrefab(definition.ResourceItemPrefab))) { return Fail(definition.NewPrefabName, "resource item '" + definition.ResourceItemPrefab + "' not found"); } MeshRenderer componentInChildren = prefab2.GetComponentInChildren<MeshRenderer>(true); if (!Object.op_Implicit((Object)(object)componentInChildren) || !Object.op_Implicit((Object)(object)((Renderer)componentInChildren).sharedMaterial)) { return Fail(definition.NewPrefabName, "'" + definition.MaterialSourcePrefab + "' has no usable material"); } GameObject val = PrefabManager.Instance.CreateClonedPrefab(definition.NewPrefabName, prefab); if (!Object.op_Implicit((Object)(object)val)) { return Fail(definition.NewPrefabName, "CreateClonedPrefab returned null"); } if (definition.LocalScaleMultiplier != 1f) { Transform transform = val.transform; transform.localScale *= definition.LocalScaleMultiplier; } if (!PrepareAsDynamicStorage(val, prefab, definition.DisplayName, requireMultipleMeshes: false)) { return Fail(definition.NewPrefabName, "failed to prepare dynamic storage prefab"); } if (!InstallNativePileVisuals(val, definition.BasePilePrefab, definition.ResourceItemPrefab)) { return Fail(definition.NewPrefabName, "could not prepare native '" + definition.BasePilePrefab + "' fill stages"); } AttachAppearance(val, definition.NewPrefabName, definition.MaterialSourcePrefab, definition.ConfigSectionName, isBar: false, definition.BasePilePrefab, definition.DefaultShape, definition.DefaultSize, definition.DefaultHeight); if (!RegisterStandalonePiece(val, definition.ResourceItemPrefab, definition.BuildCost)) { return false; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Registered " + definition.DisplayName + " from vanilla base pile " + definition.BasePilePrefab + ".")); return true; } private bool InstallNativePileVisuals(GameObject prefab, string visualPrefabName, string resourceItemPrefab) { //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_0480: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04b7: Unknown result type (might be due to invalid IL or missing references) //IL_04c3: Unknown result type (might be due to invalid IL or missing references) GameObject prefab2 = PrefabManager.Instance.GetPrefab(visualPrefabName); GameObject prefab3 = PrefabManager.Instance.GetPrefab(resourceItemPrefab); MeshRenderer val = (Object.op_Implicit((Object)(object)prefab3) ? ((IEnumerable<MeshRenderer>)prefab3.GetComponentsInChildren<MeshRenderer>(true)).FirstOrDefault((Func<MeshRenderer, bool>)((MeshRenderer r) => Object.op_Implicit((Object)(object)((Component)r).GetComponent<MeshFilter>()) && Object.op_Implicit((Object)(object)((Component)r).GetComponent<MeshFilter>().sharedMesh))) : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } ForgeVisualStack component = prefab.GetComponent<ForgeVisualStack>(); if (!Object.op_Implicit((Object)(object)component)) { return false; } List<Transform> stackMeshes = component.stackMeshes; if (stackMeshes == null || stackMeshes.Count == 0) { return false; } Component[] componentsInChildren = prefab.GetComponentsInChildren<Component>(true); foreach (Component val2 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val2) && ((object)val2).GetType().Name == "SimpleMeshCombine") { Object.DestroyImmediate((Object)(object)val2); } } MeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshRenderer>(true); for (int num = 0; num < componentsInChildren2.Length; num++) { ((Renderer)componentsInChildren2[num]).enabled = false; } foreach (Transform item in stackMeshes) { if (Object.op_Implicit((Object)(object)item)) { Collider[] componentsInChildren3 = ((Component)item).GetComponentsInChildren<Collider>(true); for (int num = 0; num < componentsInChildren3.Length; num++) { componentsInChildren3[num].enabled = false; } } } Transform transform = new GameObject("dynamic_native_pile_visuals").transform; transform.SetParent(prefab.transform, false); ((Component)transform).gameObject.layer = (Object.op_Implicit((Object)(object)stackMeshes[0]) ? ((Component)stackMeshes[0]).gameObject.layer : prefab.layer); if (string.Equals(visualPrefabName, "obsidian_pile", StringComparison.OrdinalIgnoreCase)) { transform.localPosition += Vector3.up * -0.0508f; } List<Transform> stages; string text; if (ForgePileStageDefinitions.HasAuthoredRendererOrder(visualPrefabName)) { if (ForgePileStageDefinitions.TryBuildAuthoredModelStages(prefab3, visualPrefabName, transform, null, ((Component)transform).gameObject.layer, "authored_fill_", out stages, out var diagnostic)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(((Object)prefab).name + ": " + diagnostic)); text = visualPrefabName + " authored layout with " + resourceItemPrefab + " model"; } else { ((BaseUnityPlugin)this).Logger.LogError((object)(((Object)prefab).name + ": " + diagnostic + ". Falling back to generated item stages so the storage piece remains registered.")); stages = BuildGeneratedItemStages(transform, val, null, 16, ((Component)transform).gameObject.layer); text = resourceItemPrefab + " emergency item fallback"; } } else { List<MeshRenderer> nativePileCandidates = GetNativePileCandidates(prefab2); bool num2 = nativePileCandidates.Count >= 2; if (num2) { stages = BuildNativeRendererStages(transform, prefab2, nativePileCandidates, null, ((Component)transform).gameObject.layer); text = visualPrefabName; } else { stages = BuildGeneratedItemStages(transform, val, null, 16, ((Component)transform).gameObject.layer); text = resourceItemPrefab + " item fallback"; } if (num2) { for (int num3 = 0; num3 < nativePileCandidates.Count; num3++) { MeshRenderer val3 = nativePileCandidates[num3]; MeshFilter component2 = ((Component)val3).GetComponent<MeshFilter>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"{((Object)prefab).name}: native candidate {num3 + 1:00}/" + $"{nativePileCandidates.Count:00} lod={GetRendererLodLabel(prefab2, (Renderer)(object)val3)} " + "mesh=" + ((Object)component2.sharedMesh).name + " path=" + RelativePath(((Component)val3).transform, prefab2.transform) + " " + $"minY={LocalMeshBoundsMinY(val3, prefab2.transform):0.###}")); } } } if (stages == null || stages.Count == 0) { Object.DestroyImmediate((Object)(object)((Component)transform).gameObject); return false; } component.stackMeshes = stages; int num4 = (Object.op_Implicit((Object)(object)prefab2) ? prefab2.GetComponentsInChildren<MeshRenderer>(true).Count((MeshRenderer r) => Object.op_Implicit((Object)(object)r) && Object.op_Implicit((Object)(object)((Component)r).GetComponent<MeshFilter>()) && Object.op_Implicit((Object)(object)((Component)r).GetComponent<MeshFilter>().sharedMesh)) : 0); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"{((Object)prefab).name}: {stages.Count} pile stages from " + text + $"; renderers(raw)={num4}; " + "native root scale=" + (Object.op_Implicit((Object)(object)prefab2) ? FormatVector(prefab2.transform.localScale) : "missing") + "; storage root scale=" + FormatVector(prefab.transform.localScale) + "; " + $"visual scale={FormatVector(transform.localScale)}; visual Y offset={transform.localPosition.y:0.###}")); return true; } private static List<Transform> BuildGeneratedItemStages(Transform holder, MeshRenderer itemRenderer, Material itemMaterial, int count, int layer) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) List<Transform> list = new List<Transform>(); if (!Object.op_Implicit((Object)(object)holder) || !Object.op_Implicit((Object)(object)itemRenderer)) { return list; } MeshFilter component = ((Component)itemRenderer).GetComponent<MeshFilter>(); Mesh val = (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null); if (!Object.op_Implicit((Object)(object)val)) { return list; } for (int i = 0; i < count; i++) { Transform transform = new GameObject("generated_fill_" + i) { layer = layer }.transform; transform.SetParent(holder, false); int num = i / 6; int num2 = i % 6; transform.localPosition = new Vector3((float)(num2 % 3 - 1) * 0.36f + (float)(num % 2) * 0.08f, (float)num * 0.17f, ((float)(num2 / 3) - 0.5f) * 0.38f); transform.localRotation = Quaternion.Euler(0f, (float)(i * 53 % 360), (float)(i % 3 - 1) * 12f); Bounds bounds = ((Renderer)itemRenderer).bounds; float x = ((Bounds)(ref bounds)).size.x; bounds = ((Renderer)itemRenderer).bounds; float num3 = Mathf.Max(x, ((Bounds)(ref bounds)).size.z); transform.localScale = Vector3.one * Mathf.Clamp(0.43f / Mathf.Max(num3, 0.01f), 0.35f, 1.8f); ((Component)transform).gameObject.AddComponent<MeshFilter>().sharedMesh = val; MeshRenderer val2 = ((Component)transform).gameObject.AddComponent<MeshRenderer>(); if (Object.op_Implicit((Object)(object)itemMaterial)) { ((Renderer)val2).sharedMaterials = Enumerable.Repeat<Material>(itemMaterial, Math.Max(1, ((Renderer)itemRenderer).sharedMaterials.Length)).ToArray(); } else { ((Renderer)val2).sharedMaterials = ((Renderer)itemRenderer).sharedMaterials; } ((Renderer)val2).shadowCastingMode = ((Renderer)itemRenderer).shadowCastingMode; ((Renderer)val2).receiveShadows = ((Renderer)itemRenderer).receiveShadows; list.Add(transform); } return list; } private static List<Transform> BuildNativeRendererStages(Transform holder, GameObject native, List<MeshRenderer> nativePieces, Material itemMaterial, int layer) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) List<Transform> list = new List<Transform>(); if (!Object.op_Implicit((Object)(object)holder) || !Object.op_Implicit((Object)(object)native) || nativePieces == null) { return list; } for (int i = 0; i < nativePieces.Count; i++) { MeshRenderer val = nativePieces[i]; MeshFilter val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<MeshFilter>() : null); Mesh val3 = (Object.op_Implicit((Object)(object)val2) ? val2.sharedMesh : null); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val3)) { GameObject val4 = new GameObject("native_fill_" + i); val4.layer = layer; Transform transform = val4.transform; transform.SetParent(holder, false); List<Transform> list2 = new List<Transform>(); Transform val5 = ((Component)val).transform; while (Object.op_Implicit((Object)(object)val5) && (Object)(object)val5 != (Object)(object)native.transform) { list2.Add(val5); val5 = val5.parent; } Transform val6 = transform; for (int num = list2.Count - 1; num >= 0; num--) { Transform val7 = list2[num]; Transform transform2 = new GameObject(((Object)val7).name) { layer = val4.layer }.transform; transform2.SetParent(val6, false); transform2.localPosition = val7.localPosition; transform2.localRotation = val7.localRotation; transform2.localScale = val7.localScale; val6 = transform2; } if ((Object)(object)val6 == (Object)(object)transform) { val6 = new GameObject("native_pile_mesh").transform; val6.SetParent(transform, false); ((Component)val6).gameObject.layer = val4.layer; } ((Component)val6).gameObject.AddComponent<MeshFilter>().sharedMesh = val3; MeshRenderer val8 = ((Component)val6).gameObject.AddComponent<MeshRenderer>(); if (Object.op_Implicit((Object)(object)itemMaterial)) { ((Renderer)val8).sharedMaterials = Enumerable.Repeat<Material>(itemMaterial, Math.Max(1, ((Renderer)val).sharedMaterials.Length)).ToArray(); } else { ((Renderer)val8).sharedMaterials = ((Renderer)val).sharedMaterials; } ((Renderer)val8).shadowCastingMode = ((Renderer)val).shadowCastingMode; ((Renderer)val8).receiveShadows = ((Renderer)val).receiveShadows; val4.AddComponent<MeshDebugMetadata>().Setup(RelativePath(((Component)val).transform, native.transform), GetRendererLodLabel(native, (Renderer)(object)val), ((Object)val3).name, val3.vertexCount); list.Add(transform); } } return list; } internal static List<MeshRenderer> GetNativePileCandidates(GameObject native) { if (!Object.op_Implicit((Object)(object)native)) { return new List<MeshRenderer>(); } List<MeshRenderer> source = (from r in native.GetComponentsInChildren<MeshRenderer>(true) where Object.op_Implicit((Object)(object)r) && Object.op_Implicit((Object)(object)((Component)r).GetComponent<MeshFilter>()) && Object.op_Implicit((Object)(object)((Component)r).GetComponent<MeshFilter>().sharedMesh) select r).ToList(); HashSet<Renderer> lodControlled = new HashSet<Renderer>(); HashSet<Renderer> lodZero = new HashSet<Renderer>(); LODGroup[] componentsInChildren = native.GetComponentsInChildren<LODGroup>(true); for (int num = 0; num < componentsInChildren.Length; num++) { LOD[] lODs = componentsInChildren[num].GetLODs(); for (int num2 = 0; num2 < lODs.Length; num2++) { Renderer[] renderers = lODs[num2].renderers; foreach (Renderer val in renderers) { if (Object.op_Implicit((Object)(object)val)) { lodControlled.Add(val); if (num2 == 0) { lodZero.Add(val); } } } } } return (from g in source.Where((MeshRenderer r) => !lodControlled.Contains((Renderer)(object)r) || lodZero.Contains((Renderer)(object)r)).GroupBy(delegate(MeshRenderer r) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_006c: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = native.transform.InverseTransformPoint(((Component)r).transform.position); return Mathf.RoundToInt(val2.x * 100f) + ":" + Mathf.RoundToInt(val2.y * 100f) + ":" + Mathf.RoundToInt(val2.z * 100f); }) select g.OrderByDescending((MeshRenderer r) => ((Component)r).GetComponent<MeshFilter>().sharedMesh.vertexCount).First() into r orderby LocalMeshBoundsMinY(r, native.transform) select r).ToList(); } internal static string GetRendererLodLabel(GameObject root, Renderer target) { if (!Object.op_Implicit((Object)(object)root) || !Object.op_Implicit((Object)(object)target)) { return "none"; } LODGroup[] componentsInChildren = root.GetComponentsInChildren<LODGroup>(true); for (int i = 0; i < componentsInChildren.Length; i++) { LOD[] lODs = componentsInChildren[i].GetLODs(); for (int j = 0; j < lODs.Length; j++) { if (lODs[j].renderers.Any((Renderer renderer) => (Object)(object)renderer == (Object)(object)target)) { return "LOD" + j; } } } return "none"; } private static string FormatVector(Vector3 value) { //IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references) return $"({value.x:0.###},{value.y:0.###},{value.z:0.###})"; } internal static string RelativePath(Transform child, Transform root) { if (!Object.op_Implicit((Object)(object)child)) { return "missing"; } List<string> list = new List<string>(); Transform val = child; while (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)root) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list.ToArray()); } internal static float LocalMeshBoundsMinY(MeshRenderer renderer, Transform relativeTo) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)renderer) || !Object.op_Implicit((Object)(object)relativeTo)) { return float.NaN; } MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>(); Mesh val = (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null); if (!Object.op_Implicit((Object)(object)val)) { return float.NaN; } Bounds bounds = val.bounds; Vector3 center = ((Bounds)(ref bounds)).center; Vector3 extents = ((Bounds)(ref bounds)).extents; float num = float.PositiveInfinity; for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { Vector3 val2 = center + Vector3.Scale(extents, new Ve