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 SmelterUpgrades v1.1.5
SmelterUpgrades.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.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.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("SmelterUpgrades")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.5.0")] [assembly: AssemblyInformationalVersion("1.1.5")] [assembly: AssemblyProduct("SmelterUpgrades")] [assembly: AssemblyTitle("SmelterUpgrades")] [assembly: AssemblyVersion("1.1.5.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 SmelterUpgrades { internal class HotkeyWatcher : MonoBehaviour { public const string ButtonName = "smx_cycle_lock"; private static ButtonConfig s_button; public static void RegisterButton() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown s_button = new ButtonConfig { Name = "smx_cycle_lock", Config = ModConfig.LockKey, HintToken = "$smx_hint_lock", ActiveInGUI = false, ActiveInCustomGUI = false }; InputManager.Instance.AddButton("zl.smelterupgrades", s_button); if (s_button.Name == "smx_cycle_lock") { Logger.LogWarning((object)"Lock key was not registered with Jotunn; the ore-lock hotkey will not respond."); s_button = null; } } private void Update() { if (s_button == null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ZInput.instance == null || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) || InventoryGui.IsVisible() || Menu.IsVisible() || Minimap.IsOpen() || !ZInput.GetButtonDown(s_button.Name)) { return; } GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); if (!((Object)(object)hoverObject == (Object)null)) { SmelterStation componentInParent = hoverObject.GetComponentInParent<SmelterStation>(); if (!((Object)(object)componentInParent == (Object)null)) { componentInParent.CycleLock(); } } } } internal class LockIcon : MonoBehaviour { private const float PollInterval = 0.4f; private const float RectSize = 64f; private const float ProbeDistance = 3f; private const float SurfaceClearance = 0.18f; private SmelterStation m_station; private Transform m_intake; private Canvas m_canvas; private Image m_image; private string m_shownOre; private int m_mask; public static void Attach(SmelterStation station, Transform intake) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)station == (Object)null) && ModConfig.ShowLockIcon != null && ModConfig.ShowLockIcon.Value) { GameObject val = new GameObject("smx_lock_icon", new Type[2] { typeof(RectTransform), typeof(Canvas) }) { layer = ((Component)station).gameObject.layer }; val.transform.SetParent(((Component)station).transform, false); LockIcon lockIcon = val.AddComponent<LockIcon>(); lockIcon.m_station = station; lockIcon.m_intake = intake; } } private void Awake() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) m_canvas = ((Component)this).GetComponent<Canvas>(); m_canvas.renderMode = (RenderMode)2; ((Behaviour)m_canvas).enabled = false; RectTransform val = (RectTransform)((Component)this).transform; val.sizeDelta = new Vector2(64f, 64f); float num = Mathf.Max(0.05f, ModConfig.LockIconSize.Value); ((Transform)val).localScale = Vector3.one * (num / 64f); GameObject val2 = new GameObject("icon", new Type[2] { typeof(RectTransform), typeof(Image) }); val2.layer = ((Component)this).gameObject.layer; val2.transform.SetParent(((Component)this).transform, false); RectTransform component = val2.GetComponent<RectTransform>(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; m_image = val2.GetComponent<Image>(); m_image.preserveAspect = true; ((Graphic)m_image).raycastTarget = false; m_mask = (1 << ((Component)this).gameObject.layer) | LayerMask.GetMask(new string[3] { "piece", "static_solid", "Default" }); } private void Start() { ((MonoBehaviour)this).InvokeRepeating("Refresh", 0.25f, 0.4f); } private void Refresh() { if ((Object)(object)m_station == (Object)null || ModConfig.ShowLockIcon == null || !ModConfig.ShowLockIcon.Value) { Show(on: false); return; } string lockedOre = m_station.LockedOre; if (string.IsNullOrEmpty(lockedOre) || !WithinRange()) { Show(on: false); return; } if (lockedOre != m_shownOre) { m_shownOre = lockedOre; m_image.sprite = QueueIconPanel.IconFor(lockedOre); } Show((Object)(object)m_image.sprite != (Object)null); } private bool WithinRange() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } float value = ModConfig.LockIconRange.Value; if (value <= 0f) { return false; } return Vector3.SqrMagnitude(((Component)localPlayer).transform.position - m_station.StationPosition) <= value * value; } private void Show(bool on) { if ((Object)(object)m_canvas != (Object)null && ((Behaviour)m_canvas).enabled != on) { ((Behaviour)m_canvas).enabled = on; } } private void LateUpdate() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)m_canvas == (Object)null) && ((Behaviour)m_canvas).enabled) { Camera mainCamera = Utils.GetMainCamera(); if (!((Object)(object)mainCamera == (Object)null)) { ((Component)this).transform.position = IconPoint(); ((Component)this).transform.rotation = Quaternion.LookRotation(((Component)this).transform.position - ((Component)mainCamera).transform.position, Vector3.up); } } } private Vector3 IconPoint() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: 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_00f1: 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) Vector3 stationPosition = m_station.StationPosition; Vector3 val = (((Object)(object)m_intake != (Object)null) ? m_intake.position : (stationPosition + Vector3.up * 1.2f)); Vector3 val2 = val - stationPosition; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f) { val2 = ((Component)m_station).transform.forward; } ((Vector3)(ref val2)).Normalize(); Vector3 val3 = val + Vector3.up * ModConfig.LockIconHeight.Value; RaycastHit val4 = default(RaycastHit); if (Physics.Raycast(val3 + val2 * 3f, -val2, ref val4, 3f, m_mask, (QueryTriggerInteraction)1) && (Object)(object)((RaycastHit)(ref val4)).collider != (Object)null && (Object)(object)((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent<SmelterStation>() == (Object)(object)m_station) { return ((RaycastHit)(ref val4)).point + val2 * 0.18f; } return val3 + val2 * 0.18f; } } internal class UpgradeDef { public string Key; public string PrefabName; public string CloneFrom; public string DisplayName; public string Description; public string TargetPrefab; public string CraftedAt; public string DefModelPrefab; public (string item, int amount)[] Requirements; public float DefSpeed; public int DefOreCap; public int DefFuelCap; public float DefFuelEff; public ConfigEntry<float> Speed; public ConfigEntry<int> OreCap; public ConfigEntry<int> FuelCap; public ConfigEntry<float> FuelEff; public ConfigEntry<float> Range; public ConfigEntry<string> ModelPrefab; } internal static class ModConfig { public static ConfigEntry<string> UpgradeStations; public static ConfigEntry<string> CoreFuelStations; public static ConfigEntry<bool> CoresEnabled; public static ConfigEntry<string> CoreItem; public static ConfigEntry<float> CoreFuelValue; public static ConfigEntry<float> CoreSpeedMultiplier; public static ConfigEntry<bool> FeederEnabled; public static ConfigEntry<float> FeederRange; public static ConfigEntry<float> FeederInterval; public static ConfigEntry<bool> FeederFeedsFuel; public static ConfigEntry<bool> FeederFeedsOre; public static ConfigEntry<string> FeederStations; public static ConfigEntry<bool> DebugBaseStats; public static ConfigEntry<int> ConfigVersion; private const int CurrentConfigVersion = 4; public static ConfigEntry<bool> UseVanillaShader; public static ConfigEntry<string> FeederModelPrefab; public static ConfigEntry<KeyCode> LockKey; public static ConfigEntry<bool> ShowLockIcon; public static ConfigEntry<float> LockIconSize; public static ConfigEntry<float> LockIconRange; public static ConfigEntry<float> LockIconHeight; private static readonly Dictionary<string, UpgradeDef> ByKey = new Dictionary<string, UpgradeDef>(); private static readonly UpgradeDef[] Defs = new UpgradeDef[6] { new UpgradeDef { Key = "kiln_vents", PrefabName = "smx_kiln_vents", CloneFrom = "forge_ext2", DisplayName = "Kiln Vents", Description = "Feeds air to a charcoal kiln, burning it down faster.", TargetPrefab = "charcoal_kiln", CraftedAt = "piece_workbench", Requirements = new(string, int)[2] { ("Bronze", 5), ("Copper", 10) }, DefModelPrefab = "forge_ext1", DefSpeed = 0.25f, DefOreCap = 15 }, new UpgradeDef { Key = "wood_rack", PrefabName = "smx_wood_rack", CloneFrom = "piece_workbench_ext1", DisplayName = "Wood Rack", Description = "Stacked wood within arm's reach of the kiln, so it can hold more.", TargetPrefab = "charcoal_kiln", CraftedAt = "piece_workbench", Requirements = new(string, int)[2] { ("FineWood", 15), ("Iron", 5) }, DefModelPrefab = "wood_stack", DefOreCap = 15 }, new UpgradeDef { Key = "bellows", PrefabName = "smx_bellows", CloneFrom = "forge_ext2", DisplayName = "Smelter Bellows", Description = "A hotter, cleaner burn: the smelter works faster on less coal.", TargetPrefab = "smelter", CraftedAt = "forge", Requirements = new(string, int)[3] { ("Iron", 10), ("TrollHide", 5), ("Chain", 2) }, DefModelPrefab = "forge_ext2", DefSpeed = 0.25f, DefFuelEff = 0.25f, DefOreCap = 6 }, new UpgradeDef { Key = "ore_hopper", PrefabName = "smx_ore_hopper", CloneFrom = "forge_ext1", DisplayName = "Ore Hopper", Description = "Holds a deeper stack of ore and a bigger bed of coal.", TargetPrefab = "smelter", CraftedAt = "forge", Requirements = new(string, int)[2] { ("Silver", 10), ("Obsidian", 10) }, DefModelPrefab = "piece_chest_barrel", DefOreCap = 10, DefFuelCap = 20 }, new UpgradeDef { Key = "tuyeres", PrefabName = "smx_tuyeres", CloneFrom = "forge_ext2", DisplayName = "Furnace Tuyeres", Description = "A stoked firebox blowing three tuyeres into the furnace: it runs hotter, and burns one coal a bar instead of two.", TargetPrefab = "blastfurnace", CraftedAt = "blackforge", Requirements = new(string, int)[3] { ("BlackMetal", 10), ("Iron", 10), ("Chain", 2) }, DefModelPrefab = "forge_ext2", DefSpeed = 0.25f, DefFuelEff = 0.3f, DefOreCap = 6 }, new UpgradeDef { Key = "charging_ramp", PrefabName = "smx_charging_ramp", CloneFrom = "piece_workbench_ext1", DisplayName = "Charging Ramp", Description = "A barrow ramp up to a tipping bin, so the furnace can be charged deeper before it needs you again.", TargetPrefab = "blastfurnace", CraftedAt = "blackforge", Requirements = new(string, int)[3] { ("FineWood", 20), ("Iron", 8), ("BlackMetal", 5) }, DefModelPrefab = "wood_stack", DefOreCap = 10, DefFuelCap = 20 } }; public static IEnumerable<UpgradeDef> All => ByKey.Values; public static void Init(ConfigFile cfg) { UpgradeStations = cfg.Bind<string>("General", "UpgradeStations", "charcoal_kiln,smelter,blastfurnace", "Prefab names of the stations that accept upgrade pieces. Comma separated."); CoreFuelStations = cfg.Bind<string>("SurtlingCores", "Stations", "smelter,blastfurnace", "Prefab names of the stations that accept Surtling Cores as fuel. Comma separated. Stations with no fuel at all, such as the charcoal kiln, ignore this."); CoresEnabled = cfg.Bind<bool>("SurtlingCores", "Enabled", true, "Allow Surtling Cores to be burned as a high-grade fuel."); CoreItem = cfg.Bind<string>("SurtlingCores", "ItemPrefab", "SurtlingCore", "Prefab name of the item used as super-fuel."); CoreFuelValue = cfg.Bind<float>("SurtlingCores", "FuelValue", 4f, "How many units of ordinary fuel one core is worth."); CoreSpeedMultiplier = cfg.Bind<float>("SurtlingCores", "SpeedMultiplier", 2f, "Speed multiplier while core fuel remains in the tank. Stacks on top of upgrade pieces. NOTE: fuel is a single pool, so once cores and coal are mixed the boost runs until the core fuel is spent rather than tracking individual cores."); FeederEnabled = cfg.Bind<bool>("FeederChest", "Enabled", true, "Let the Stoker's Chest top up nearby stations on its own."); FeederRange = cfg.Bind<float>("FeederChest", "Range", 8f, "How far the chest reaches to find stations to feed."); FeederInterval = cfg.Bind<float>("FeederChest", "IntervalSeconds", 3f, "Seconds between feeding passes. One fuel and one ore per station per pass."); FeederFeedsFuel = cfg.Bind<bool>("FeederChest", "FeedFuel", true, "Top up station fuel from the chest."); FeederFeedsOre = cfg.Bind<bool>("FeederChest", "FeedOre", true, "Top up the station input queue from the chest. Respects a locked ore type."); LockKey = cfg.Bind<KeyCode>("General", "LockOreKey", (KeyCode)110, "Held on a smelter, steps its ore lock: unlocked -> each ore in turn -> unlocked. Also rebindable from the game's own controls menu."); FeederStations = cfg.Bind<string>("FeederChest", "Stations", "charcoal_kiln,smelter,blastfurnace", "Prefab names of the stations this chest will feed, comma separated. Smelter is the class behind more than these three, so the list keeps the chest from quietly topping up anything else in range that happens to smelt. Leave it empty to feed every one of them, modded stations included."); FeederModelPrefab = cfg.Bind<string>("FeederChest", "ModelPrefab", "piece_chest_blackmetal", "Vanilla prefab whose geometry the feeder chest wears."); ShowLockIcon = cfg.Bind<bool>("General", "ShowLockIcon", true, "When a station is locked to one ore, float that ore's icon at the spot you feed it, so you can read what a smelter is set to without walking up and hovering it."); LockIconSize = cfg.Bind<float>("General", "LockIconSize", 0.45f, "How big that icon is drawn, in metres. Takes effect on the next world load."); LockIconRange = cfg.Bind<float>("General", "LockIconRange", 14f, "How far away the icon stays readable, in metres. 0 turns it off."); LockIconHeight = cfg.Bind<float>("General", "LockIconHeight", 0.35f, "How far above the intake the icon floats, in metres."); UseVanillaShader = cfg.Bind<bool>("General", "UseVanillaShader", true, "Draw the mod's models with Valheim's own shader so they weather, wet and catch snow like the rest of the world. Turn off to use the plain shader shipped in the model bundle."); DebugBaseStats = cfg.Bind<bool>("General", "DebugLogBaseStats", false, "Log each station's untouched vanilla stats on spawn. Use this to tune the values below against the real numbers instead of guessing them."); UpgradeDef[] defs = Defs; foreach (UpgradeDef upgradeDef in defs) { upgradeDef.Speed = cfg.Bind<float>(upgradeDef.Key, "SpeedBonus", upgradeDef.DefSpeed, "Added as a fraction of base speed. 0.25 = 25% faster. 0 disables."); upgradeDef.OreCap = cfg.Bind<int>(upgradeDef.Key, "OreCapacityBonus", upgradeDef.DefOreCap, "Extra slots on the input queue."); upgradeDef.FuelCap = cfg.Bind<int>(upgradeDef.Key, "FuelCapacityBonus", upgradeDef.DefFuelCap, "Extra fuel capacity. Ignored on stations with no fuel, such as the kiln."); upgradeDef.FuelEff = cfg.Bind<float>(upgradeDef.Key, "FuelEfficiencyBonus", upgradeDef.DefFuelEff, "Fraction of fuel saved per product. NOTE: the game stores fuel-per-product as a whole number, so this rounds -- small values may have no effect at all. It can never drop below 1 fuel per product."); upgradeDef.Range = cfg.Bind<float>(upgradeDef.Key, "Range", 5f, "How close to the station this piece must be built."); upgradeDef.ModelPrefab = cfg.Bind<string>(upgradeDef.Key, "ModelPrefab", upgradeDef.DefModelPrefab, "Vanilla prefab whose geometry this piece wears. Using real game art is what makes these match the world. Any buildable prefab name works -- try wood_stack, coal_pile, piece_chest_barrel, forge_ext1..6, blackforge_ext1..4. Leave empty to keep the piece's own model."); ByKey[upgradeDef.Key] = upgradeDef; } Migrate(cfg); } private static void MigrateDefault<T>(ConfigEntry<T> entry, T previousDefault) { if (entry != null && object.Equals(entry.Value, previousDefault)) { entry.Value = (T)((ConfigEntryBase)entry).DefaultValue; } } private static void Migrate(ConfigFile cfg) { ConfigVersion = cfg.Bind<int>("General", "ConfigVersion", 1, "Internal bookkeeping so balance updates reach existing configs. Do not edit."); if (ConfigVersion.Value < 4) { if (ConfigVersion.Value < 2) { MigrateDefault(Get("kiln_vents")?.OreCap, 0); MigrateDefault(Get("wood_rack")?.OreCap, 10); MigrateDefault(Get("bellows")?.OreCap, 0); MigrateDefault(Get("ore_hopper")?.OreCap, 5); MigrateDefault(Get("ore_hopper")?.FuelCap, 10); } if (ConfigVersion.Value < 3) { MigrateDefault(UpgradeStations, "charcoal_kiln,smelter"); } if (ConfigVersion.Value < 4) { MigrateDefault<KeyCode>(LockKey, (KeyCode)103); } Logger.LogInfo((object)($"Config migrated from version {ConfigVersion.Value} to {4}; " + "values you had customised were kept.")); ConfigVersion.Value = 4; } } public static UpgradeDef Get(string key) { if (key == null) { return null; } ByKey.TryGetValue(key, out var value); return value; } private static bool InList(ConfigEntry<string> list, string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return false; } return (from s in list.Value.Split(new char[1] { ',' }) select s.Trim()).Any((string s) => s.Length > 0 && s == prefabName); } public static bool IsUpgradeStation(string prefabName) { return InList(UpgradeStations, prefabName); } public static bool IsCoreFuelStation(string prefabName) { if (CoresEnabled.Value) { return InList(CoreFuelStations, prefabName); } return false; } public static bool IsFeederStation(string prefabName) { if (FeederStations == null || string.IsNullOrEmpty(FeederStations.Value.Trim())) { return true; } return InList(FeederStations, prefabName); } public static bool IsManagedStation(string prefabName) { if (!IsUpgradeStation(prefabName)) { return IsCoreFuelStation(prefabName); } return true; } } internal static class ModelDump { private sealed class ObjWriter { private readonly StringBuilder _obj = new StringBuilder(); private int _vertices; private int _normals; private int _uvs; public readonly Dictionary<string, Material> Materials = new Dictionary<string, Material>(); public int Meshes; public int Triangles; public void Add(Mesh mesh, Matrix4x4 local, Material[] materials, string group) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) Vector3[] vertices = mesh.vertices; if (vertices.Length == 0) { return; } Vector3[] normals = mesh.normals; Vector2[] uv = mesh.uv; _obj.AppendLine("g " + Sanitise(group)); Vector3[] array = vertices; foreach (Vector3 val in array) { Vector3 val2 = ((Matrix4x4)(ref local)).MultiplyPoint3x4(val); _obj.AppendLine(string.Format(CultureInfo.InvariantCulture, "v {0:0.#####} {1:0.#####} {2:0.#####}", 0f - val2.x, val2.y, val2.z)); } array = normals; foreach (Vector3 val3 in array) { Vector3 val4 = ((Matrix4x4)(ref local)).MultiplyVector(val3); Vector3 normalized = ((Vector3)(ref val4)).normalized; _obj.AppendLine(string.Format(CultureInfo.InvariantCulture, "vn {0:0.####} {1:0.####} {2:0.####}", 0f - normalized.x, normalized.y, normalized.z)); } Vector2[] array2 = uv; foreach (Vector2 val5 in array2) { _obj.AppendLine(string.Format(CultureInfo.InvariantCulture, "vt {0:0.#####} {1:0.#####}", val5.x, val5.y)); } bool hasNormals = normals.Length == vertices.Length; bool hasUvs = uv.Length == vertices.Length; for (int j = 0; j < mesh.subMeshCount; j++) { Material val6 = ((materials != null && j < materials.Length) ? materials[j] : null); string text = (((Object)(object)val6 != (Object)null) ? Sanitise(((Object)val6).name) : "default"); if ((Object)(object)val6 != (Object)null && !Materials.ContainsKey(text)) { Materials[text] = val6; } _obj.AppendLine("usemtl " + text); int[] triangles = mesh.GetTriangles(j); for (int k = 0; k + 2 < triangles.Length; k += 3) { _obj.Append("f "); Corner(triangles[k + 2], hasNormals, hasUvs); _obj.Append(' '); Corner(triangles[k + 1], hasNormals, hasUvs); _obj.Append(' '); Corner(triangles[k], hasNormals, hasUvs); _obj.AppendLine(); Triangles++; } } _vertices += vertices.Length; _normals += normals.Length; _uvs += uv.Length; Meshes++; } private void Corner(int index, bool hasNormals, bool hasUvs) { _obj.Append(_vertices + index + 1); if (hasUvs) { _obj.Append('/').Append(_uvs + index + 1); } else if (hasNormals) { _obj.Append('/'); } if (hasNormals) { _obj.Append('/').Append(_normals + index + 1); } } public string Finish(string name) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# " + name + " - read out of Valheim by Smelter Upgrades"); stringBuilder.AppendLine("# Metres, in the prefab's own space: the origin is where the piece meets the ground."); stringBuilder.AppendLine("# X is negated and winding reversed, the usual Unity .obj convention."); stringBuilder.AppendLine("mtllib " + name + ".mtl"); return stringBuilder.Append((object?)_obj).ToString(); } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__4_0; internal void <Register>b__4_0(ConsoleEventArgs args) { string list = s_prefabs.Value; if (args.Length > 1) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 1; i < args.Length; i++) { if (stringBuilder.Length > 0) { stringBuilder.Append(','); } stringBuilder.Append(args[i]); } list = stringBuilder.ToString(); } Run(list); } } private static ConfigEntry<bool> s_enabled; private static ConfigEntry<string> s_prefabs; private static ConfigEntry<bool> s_textures; private static readonly Dictionary<string, string> s_savedTextures = new Dictionary<string, string>(); public static void Register(ConfigFile cfg) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown s_enabled = cfg.Bind<bool>("Dump", "DumpStationModels", false, "Developer tool. On the next world load, write the prefabs listed below to BepInEx/config/SmelterUpgrades/models: .obj geometry, .png textures and a .txt report of sizes, colliders, snap points and attachment points. Turn it back off afterwards; it costs a moment of the world load."); s_prefabs = cfg.Bind<string>("Dump", "Prefabs", "blastfurnace,charcoal_kiln,smelter,forge_ext1,forge_ext2,piece_workbench_ext1", "Which prefabs to write out, by prefab name, comma separated. The forge and workbench extensions are in the list as a reference for how vanilla sizes and places a piece that stands beside a station."); s_textures = cfg.Bind<bool>("Dump", "Textures", true, "Also write each material's main texture as a .png. Turn off for geometry only."); PrefabManager.OnVanillaPrefabsAvailable += OnPrefabsAvailable; object obj = <>c.<>9__4_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { string list = s_prefabs.Value; if (args.Length > 1) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 1; i < args.Length; i++) { if (stringBuilder.Length > 0) { stringBuilder.Append(','); } stringBuilder.Append(args[i]); } list = stringBuilder.ToString(); } Run(list); }; <>c.<>9__4_0 = val; obj = (object)val; } new ConsoleCommand("smx.dumpmodels", "Write station models to BepInEx/config/SmelterUpgrades/models. Optional: prefab names.", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static void OnPrefabsAvailable() { PrefabManager.OnVanillaPrefabsAvailable -= OnPrefabsAvailable; if (s_enabled != null && s_enabled.Value) { Run(s_prefabs.Value); } } private static void Run(string list) { string text = Path.Combine(Paths.ConfigPath, "SmelterUpgrades", "models"); string text2 = Path.Combine(text, "textures"); try { Directory.CreateDirectory(text2); } catch (Exception ex) { Logger.LogError((object)("[dump] cannot write to " + text + ": " + ex.Message)); return; } int num = 0; string[] array = list.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text3 = array[i].Trim(); if (text3.Length == 0) { continue; } GameObject prefab = PrefabManager.Instance.GetPrefab(text3); if ((Object)(object)prefab == (Object)null) { Logger.LogWarning((object)("[dump] no prefab named '" + text3 + "'")); continue; } try { DumpOne(prefab, text3, Path.Combine(text, text3), text2); num++; } catch (Exception ex2) { Logger.LogError((object)("[dump] " + text3 + " failed: " + ex2)); } } string text4 = "wrote " + num + " model(s) to " + text; Logger.LogInfo((object)("[dump] " + text4)); if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "Smelter Upgrades: " + text4, 0, (Sprite)null, false, true); } } private static void DumpOne(GameObject prefab, string name, string dir, string textureDir) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) Directory.CreateDirectory(dir); ObjWriter objWriter = new ObjWriter(); StringBuilder stringBuilder = new StringBuilder(); int num = 0; stringBuilder.AppendLine(name); stringBuilder.AppendLine(new string('=', Math.Max(4, name.Length))); stringBuilder.AppendLine("Every position and size below is in metres, relative to the prefab's"); stringBuilder.AppendLine("own origin - which is where the piece sits on the ground."); stringBuilder.AppendLine(); HashSet<Renderer> hashSet = LowDetailRenderers(prefab); Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix; Bounds bounds = default(Bounds); bool have = false; stringBuilder.AppendLine("MESHES"); MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren<MeshFilter>(true); foreach (MeshFilter val in componentsInChildren) { Mesh sharedMesh = val.sharedMesh; Renderer component = ((Component)val).GetComponent<Renderer>(); if (!((Object)(object)sharedMesh == (Object)null) && (!((Object)(object)component != (Object)null) || !hashSet.Contains(component))) { Matrix4x4 local = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix; Encapsulate(ref bounds, ref have, local, sharedMesh.bounds); Material[] materials = (((Object)(object)component != (Object)null) ? component.sharedMaterials : null); ReportMesh(stringBuilder, PathOf(((Component)val).transform, prefab.transform), sharedMesh, local, materials); if (sharedMesh.isReadable) { objWriter.Add(sharedMesh, local, materials, PathOf(((Component)val).transform, prefab.transform)); } else { num++; } } } SkinnedMeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren2) { Mesh sharedMesh2 = val2.sharedMesh; if (!((Object)(object)sharedMesh2 == (Object)null) && !hashSet.Contains((Renderer)(object)val2)) { Matrix4x4 local2 = worldToLocalMatrix * ((Component)val2).transform.localToWorldMatrix; Encapsulate(ref bounds, ref have, local2, sharedMesh2.bounds); ReportMesh(stringBuilder, PathOf(((Component)val2).transform, prefab.transform), sharedMesh2, local2, ((Renderer)val2).sharedMaterials); if (sharedMesh2.isReadable) { objWriter.Add(sharedMesh2, local2, ((Renderer)val2).sharedMaterials, PathOf(((Component)val2).transform, prefab.transform)); } else { num++; } } } stringBuilder.AppendLine(); stringBuilder.AppendLine("OVERALL SIZE"); if (have) { stringBuilder.AppendLine(" width x height x depth " + Fmt(((Bounds)(ref bounds)).size)); stringBuilder.AppendLine(" lowest / highest point y " + N(((Bounds)(ref bounds)).min.y) + " / " + N(((Bounds)(ref bounds)).max.y)); stringBuilder.AppendLine(" centre " + Fmt(((Bounds)(ref bounds)).center)); stringBuilder.AppendLine(" footprint corners " + Fmt(new Vector3(((Bounds)(ref bounds)).min.x, 0f, ((Bounds)(ref bounds)).min.z)) + " to " + Fmt(new Vector3(((Bounds)(ref bounds)).max.x, 0f, ((Bounds)(ref bounds)).max.z))); } else { stringBuilder.AppendLine(" (no meshes found)"); } AppendColliders(stringBuilder, prefab); AppendSnapPoints(stringBuilder, prefab); AppendStationFacts(stringBuilder, prefab); stringBuilder.AppendLine(); stringBuilder.AppendLine("HIERARCHY"); AppendHierarchy(stringBuilder, prefab.transform, prefab.transform, 1); File.WriteAllText(Path.Combine(dir, name + ".txt"), stringBuilder.ToString()); if (objWriter.Triangles > 0) { File.WriteAllText(Path.Combine(dir, name + ".obj"), objWriter.Finish(name)); File.WriteAllText(Path.Combine(dir, name + ".mtl"), WriteMaterials(objWriter.Materials, textureDir)); } Logger.LogInfo((object)("[dump] " + name + ": " + objWriter.Meshes + " mesh(es), " + objWriter.Triangles + " triangles" + ((num > 0) ? (", " + num + " not readable") : ""))); } private static void ReportMesh(StringBuilder report, string path, Mesh mesh, Matrix4x4 local, Material[] materials) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_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) report.AppendLine(" " + path); report.AppendLine(" mesh " + ((Object)mesh).name + " verts " + mesh.vertexCount + " submeshes " + mesh.subMeshCount + (mesh.isReadable ? "" : " NOT READABLE - geometry not exported")); Bounds bounds = mesh.bounds; string text = Fmt(Abs(((Matrix4x4)(ref local)).MultiplyVector(((Bounds)(ref bounds)).size))); bounds = mesh.bounds; report.AppendLine(" size " + text + " centre " + Fmt(((Matrix4x4)(ref local)).MultiplyPoint3x4(((Bounds)(ref bounds)).center))); if (materials == null) { return; } foreach (Material val in materials) { if (!((Object)(object)val == (Object)null)) { Texture val2 = MainTexture(val); report.AppendLine(" material " + ((Object)val).name + " shader " + (((Object)(object)val.shader != (Object)null) ? ((Object)val.shader).name : "?") + (((Object)(object)val2 != (Object)null) ? (" texture " + ((Object)val2).name + " " + val2.width + "x" + val2.height) : "")); } } } private static void AppendColliders(StringBuilder report, GameObject prefab) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) report.AppendLine(); report.AppendLine("COLLIDERS (what a new piece must not stand inside)"); bool flag = false; Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { flag = true; string text = PathOf(((Component)val).transform, prefab.transform); Vector3 v = prefab.transform.InverseTransformPoint(((Component)val).transform.position); BoxCollider val2 = (BoxCollider)(object)((val is BoxCollider) ? val : null); SphereCollider val3 = (SphereCollider)(object)((val is SphereCollider) ? val : null); CapsuleCollider val4 = (CapsuleCollider)(object)((val is CapsuleCollider) ? val : null); string text2 = (((Object)(object)val2 != (Object)null) ? ("box size " + Fmt(Vector3.Scale(val2.size, ((Component)val).transform.lossyScale)) + " centre " + Fmt(val2.center)) : (((Object)(object)val3 != (Object)null) ? ("sphere radius " + N(val3.radius * ((Component)val).transform.lossyScale.x)) : (((Object)(object)val4 != (Object)null) ? ("capsule radius " + N(val4.radius) + " height " + N(val4.height)) : ((object)val).GetType().Name))); report.AppendLine(" " + text + " at " + Fmt(v) + " " + text2 + (val.isTrigger ? " (trigger)" : "")); } if (!flag) { report.AppendLine(" (none)"); } } private static void AppendSnapPoints(StringBuilder report, GameObject prefab) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) report.AppendLine(); report.AppendLine("SNAP POINTS (where the game lets other pieces attach)"); bool flag = false; Transform[] componentsInChildren = prefab.GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if (IsSnapPoint(val)) { flag = true; report.AppendLine(" " + Fmt(prefab.transform.InverseTransformPoint(val.position)) + " " + ((Object)val).name); } } if (!flag) { report.AppendLine(" (none)"); } } private static bool IsSnapPoint(Transform t) { if (((Object)t).name.IndexOf("snappoint", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } try { return ((Component)t).CompareTag("snappoint"); } catch (Exception) { return false; } } private static void AppendStationFacts(StringBuilder report, GameObject prefab) { //IL_025d: Unknown result type (might be due to invalid IL or missing references) Transform transform = prefab.transform; Smelter component = prefab.GetComponent<Smelter>(); if ((Object)(object)component != (Object)null) { report.AppendLine(); report.AppendLine("SMELTER COMPONENT"); report.AppendLine(" name " + component.m_name + " max ore " + component.m_maxOre + " max fuel " + component.m_maxFuel + " fuel per product " + component.m_fuelPerProduct + " sec per product " + N(component.m_secPerProduct)); report.AppendLine(" requires roof " + component.m_requiresRoof); AppendPoint(report, transform, "add wood switch ", ((Object)(object)component.m_addWoodSwitch != (Object)null) ? ((Component)component.m_addWoodSwitch).transform : null); AppendPoint(report, transform, "add ore switch ", ((Object)(object)component.m_addOreSwitch != (Object)null) ? ((Component)component.m_addOreSwitch).transform : null); AppendPoint(report, transform, "empty ore switch", ((Object)(object)component.m_emptyOreSwitch != (Object)null) ? ((Component)component.m_emptyOreSwitch).transform : null); AppendPoint(report, transform, "output point ", component.m_outputPoint); AppendPoint(report, transform, "roof check point", component.m_roofCheckPoint); if (component.m_conversion != null) { foreach (ItemConversion item in component.m_conversion) { if (item != null) { report.AppendLine(" converts " + (((Object)(object)item.m_from != (Object)null) ? ((Object)item.m_from).name : "?") + " -> " + (((Object)(object)item.m_to != (Object)null) ? ((Object)item.m_to).name : "?")); } } } } StationExtension component2 = prefab.GetComponent<StationExtension>(); if ((Object)(object)component2 != (Object)null) { report.AppendLine(); report.AppendLine("STATION EXTENSION COMPONENT (this piece stands beside a station)"); report.AppendLine(" max station distance " + N(component2.m_maxStationDistance) + " stacks " + component2.m_stack + " connection offset " + Fmt(component2.m_connectionOffset)); } CraftingStation component3 = prefab.GetComponent<CraftingStation>(); if ((Object)(object)component3 != (Object)null) { report.AppendLine(); report.AppendLine("CRAFTING STATION COMPONENT"); report.AppendLine(" name " + component3.m_name + " build range " + N(component3.m_rangeBuild) + " use distance " + N(component3.m_useDistance)); AppendPoint(report, transform, "connection point", component3.m_connectionPoint); } Piece component4 = prefab.GetComponent<Piece>(); if ((Object)(object)component4 != (Object)null) { report.AppendLine(); report.AppendLine("PIECE COMPONENT"); report.AppendLine(" name " + component4.m_name + " category " + ((object)Unsafe.As<PieceCategory, PieceCategory>(ref component4.m_category)/*cast due to .constrained prefix*/).ToString() + " space requirement " + N(component4.m_spaceRequirement) + " comfort " + component4.m_comfort); } } private static void AppendPoint(StringBuilder report, Transform root, string label, Transform point) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)point == (Object)null)) { report.AppendLine(" " + label + " " + Fmt(root.InverseTransformPoint(point.position))); } } private static void AppendHierarchy(StringBuilder report, Transform t, Transform root, int depth) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0041: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) foreach (Transform item in t) { Transform val = item; report.AppendLine(new string(' ', depth * 2) + ((Object)val).name + " at " + Fmt(root.InverseTransformPoint(val.position)) + ((val.localScale != Vector3.one) ? (" scale " + Fmt(val.localScale)) : "") + (((Component)val).gameObject.activeSelf ? "" : " (inactive)")); AppendHierarchy(report, val, root, depth + 1); } } private static string WriteMaterials(Dictionary<string, Material> materials, string textureDir) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<string, Material> material in materials) { stringBuilder.AppendLine("newmtl " + material.Key); Material value = material.Value; Color val = (((Object)(object)value != (Object)null && value.HasProperty("_Color")) ? value.GetColor("_Color") : Color.white); stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "Kd {0:0.####} {1:0.####} {2:0.####}", val.r, val.g, val.b)); stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "d {0:0.###}", val.a)); if (s_textures != null && s_textures.Value) { string text = SaveTexture(MainTexture(value), textureDir); if (text != null) { stringBuilder.AppendLine("map_Kd ../textures/" + text); } } stringBuilder.AppendLine(); } return stringBuilder.ToString(); } private static Texture MainTexture(Material material) { if ((Object)(object)material == (Object)null) { return null; } string[] array = new string[4] { "_MainTex", "_MainTexture", "_BaseMap", "_BaseColorMap" }; foreach (string text in array) { if (material.HasProperty(text)) { Texture texture = material.GetTexture(text); if ((Object)(object)texture != (Object)null) { return texture; } } } return null; } private static string SaveTexture(Texture texture, string textureDir) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)texture == (Object)null) { return null; } if (s_savedTextures.TryGetValue(((Object)texture).name, out var value)) { return value; } string text = Sanitise(((Object)texture).name) + ".png"; string path = Path.Combine(textureDir, text); RenderTexture val = null; RenderTexture active = RenderTexture.active; Texture2D val2 = null; try { val = RenderTexture.GetTemporary(texture.width, texture.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); Graphics.Blit(texture, val); RenderTexture.active = val; val2 = new Texture2D(texture.width, texture.height, (TextureFormat)4, false); val2.ReadPixels(new Rect(0f, 0f, (float)texture.width, (float)texture.height), 0, 0); val2.Apply(); File.WriteAllBytes(path, ImageConversion.EncodeToPNG(val2)); } catch (Exception ex) { Logger.LogWarning((object)("[dump] texture " + ((Object)texture).name + " failed: " + ex.Message)); text = null; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { RenderTexture.ReleaseTemporary(val); } if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } } s_savedTextures[((Object)texture).name] = text; return text; } private static HashSet<Renderer> LowDetailRenderers(GameObject prefab) { HashSet<Renderer> hashSet = new HashSet<Renderer>(); LODGroup[] componentsInChildren = prefab.GetComponentsInChildren<LODGroup>(true); for (int i = 0; i < componentsInChildren.Length; i++) { LOD[] lODs = componentsInChildren[i].GetLODs(); for (int j = 1; j < lODs.Length; j++) { Renderer[] renderers = lODs[j].renderers; foreach (Renderer val in renderers) { if ((Object)(object)val != (Object)null) { hashSet.Add(val); } } } } return hashSet; } private static void Encapsulate(ref Bounds bounds, ref bool have, Matrix4x4 local, Bounds meshBounds) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) Vector3 center = ((Bounds)(ref meshBounds)).center; Vector3 extents = ((Bounds)(ref meshBounds)).extents; for (int i = 0; i < 8; i++) { Vector3 val = ((Matrix4x4)(ref local)).MultiplyPoint3x4(new Vector3(center.x + (((i & 1) == 0) ? (0f - extents.x) : extents.x), center.y + (((i & 2) == 0) ? (0f - extents.y) : extents.y), center.z + (((i & 4) == 0) ? (0f - extents.z) : extents.z))); if (!have) { bounds = new Bounds(val, Vector3.zero); have = true; } else { ((Bounds)(ref bounds)).Encapsulate(val); } } } private static string PathOf(Transform t, Transform root) { List<string> list = new List<string>(); while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)root) { list.Insert(0, ((Object)t).name); t = t.parent; } if (list.Count != 0) { return string.Join("/", list.ToArray()); } return "(root)"; } private static Vector3 Abs(Vector3 v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) return new Vector3(Mathf.Abs(v.x), Mathf.Abs(v.y), Mathf.Abs(v.z)); } private static string N(float value) { return value.ToString("0.###", CultureInfo.InvariantCulture); } private static string Fmt(Vector3 v) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) return "(" + N(v.x) + ", " + N(v.y) + ", " + N(v.z) + ")"; } private static string Sanitise(string name) { if (string.IsNullOrEmpty(name)) { return "unnamed"; } StringBuilder stringBuilder = new StringBuilder(name.Length); foreach (char c in name) { stringBuilder.Append((char.IsLetterOrDigit(c) || c == '_' || c == '-' || c == '.') ? c : '_'); } return stringBuilder.ToString(); } } internal static class ModLocalization { public static void Register() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "smx_level"; localization.AddTranslation(ref text, "Level"); text = "smx_speed"; localization.AddTranslation(ref text, "speed"); text = "smx_capacity"; localization.AddTranslation(ref text, "capacity"); text = "smx_fuel"; localization.AddTranslation(ref text, "fuel"); text = "smx_fuel_per_item"; localization.AddTranslation(ref text, "fuel per item"); text = "smx_core_boost"; localization.AddTranslation(ref text, "Core fire"); text = "smx_locked_to"; localization.AddTranslation(ref text, "Locked to"); text = "smx_unlocked"; localization.AddTranslation(ref text, "Unlocked - accepts any ore"); text = "smx_hint_lock"; localization.AddTranslation(ref text, "Lock ore type"); text = "smx_feeder_name"; localization.AddTranslation(ref text, "Stoker's Chest"); text = "smx_feeder_desc"; localization.AddTranslation(ref text, "Feeds fuel and ore to nearby smelters and kilns on its own."); text = "smx_feeder_range"; localization.AddTranslation(ref text, "Feeding"); text = "smx_feeder_idle"; localization.AddTranslation(ref text, "Idle"); } } [HarmonyPatch(typeof(Smelter), "Awake")] internal static class Smelter_Awake_Patch { private static void Postfix(Smelter __instance) { ZNetView val = ((Component)__instance).GetComponent<ZNetView>() ?? ((Component)__instance).GetComponentInParent<ZNetView>(); if (!((Object)(object)val == (Object)null) && val.GetZDO() != null && ModConfig.IsManagedStation(Utils.GetPrefabName(((Component)val).gameObject)) && !((Object)(object)((Component)__instance).GetComponent<SmelterStation>() != (Object)null)) { ((Component)__instance).gameObject.AddComponent<SmelterStation>(); } } } [HarmonyPatch(typeof(Smelter), "OnHoverAddOre")] internal static class Smelter_OnHoverAddOre_Patch { private static void Postfix(Smelter __instance, ref string __result) { SmelterStation component = ((Component)__instance).GetComponent<SmelterStation>(); if (!((Object)(object)component == (Object)null)) { component.PokeConnections(); __result += Localization.instance.Localize(component.GetUpgradeHoverText()); } } } [HarmonyPatch(typeof(Smelter), "OnAddOre")] internal static class Smelter_OnAddOre_Patch { private static bool Prefix(Smelter __instance, Humanoid user, ref ItemData item, ref bool __result) { SmelterStation component = ((Component)__instance).GetComponent<SmelterStation>(); if ((Object)(object)component == (Object)null || !component.IsLocked) { return true; } string lockedOre = component.LockedOre; ItemConversion val = component.FindConversion(lockedOre); if (val == null) { return true; } string name = val.m_from.m_itemData.m_shared.m_name; if (item != null) { if ((Object)(object)item.m_dropPrefab != (Object)null && ((Object)item.m_dropPrefab).name == lockedOre) { return true; } ((Character)user).Message((MessageType)2, Localization.instance.Localize("$smx_locked_to " + name), 0, (Sprite)null, false); __result = false; return false; } ItemData item2 = user.GetInventory().GetItem(name, -1, false); if (item2 == null) { ((Character)user).Message((MessageType)2, Localization.instance.Localize("$msg_donthaveany " + name), 0, (Sprite)null, false); __result = false; return false; } item = item2; return true; } } [HarmonyPatch(typeof(Smelter), "TryGetItems")] internal static class Smelter_TryGetItems_Patch { private static void Postfix(Smelter __instance, Switch switchRef, ref List<string> items) { SmelterStation component = ((Component)__instance).GetComponent<SmelterStation>(); if ((Object)(object)component == (Object)null || !component.IsLocked || (Object)(object)switchRef != (Object)(object)__instance.m_addOreSwitch || items == null) { return; } string lockedShared = component.LockedSharedName; if (!string.IsNullOrEmpty(lockedShared)) { items.RemoveAll((string n) => n != lockedShared); } } } [HarmonyPatch(typeof(Smelter), "OnAddFuel")] internal static class Smelter_OnAddFuel_Patch { private static bool Prefix(Smelter __instance, Humanoid user, ItemData item, ref bool __result) { SmelterStation component = ((Component)__instance).GetComponent<SmelterStation>(); if ((Object)(object)component == (Object)null || !component.AllowsCores) { return true; } if (item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return true; } if (((Object)item.m_dropPrefab).name != ModConfig.CoreItem.Value) { return true; } float value = ModConfig.CoreFuelValue.Value; if (value <= 0f) { return true; } if (component.CurrentFuel + value > (float)__instance.m_maxFuel + 0.001f) { ((Character)user).Message((MessageType)2, "$msg_itsfull", 0, (Sprite)null, false); __result = false; return false; } user.GetInventory().RemoveItem(item, 1); ((Character)user).Message((MessageType)2, Localization.instance.Localize("$msg_added " + item.m_shared.m_name), 0, (Sprite)null, false); component.AddCoreFuel(value); __result = true; return false; } } [HarmonyPatch(typeof(Smelter), "OnHoverAddFuel")] internal static class Smelter_OnHoverAddFuel_Patch { private static void Postfix(Smelter __instance, ref string __result) { SmelterStation component = ((Component)__instance).GetComponent<SmelterStation>(); if (!((Object)(object)component == (Object)null) && component.AllowsCores && component.BoostFuel > 0f) { __result += Localization.instance.Localize($"\n<color=#ff8040>$smx_core_boost x{ModConfig.CoreSpeedMultiplier.Value:0.##} " + $"({Mathf.Ceil(component.BoostFuel)} $smx_fuel)</color>"); } } } [HarmonyPatch(typeof(Smelter), "CanUseItems")] internal static class Smelter_CanUseItems_Patch { private static void Postfix(Smelter __instance, Player player, Switch switchRef, bool sendErrorMessage, ref bool __result) { SmelterStation component = ((Component)__instance).GetComponent<SmelterStation>(); if (!__result && (Object)(object)component != (Object)null && component.AllowsCores && (Object)(object)__instance.m_addWoodSwitch != (Object)null && (Object)(object)switchRef == (Object)(object)__instance.m_addWoodSwitch) { float value = ModConfig.CoreFuelValue.Value; if (component.CurrentFuel + value <= (float)__instance.m_maxFuel + 0.001f && HasCore(player)) { __result = true; return; } } if (!__result) { return; } SmelterStation component2 = ((Component)__instance).GetComponent<SmelterStation>(); if ((Object)(object)component2 == (Object)null || !component2.IsLocked || (Object)(object)switchRef != (Object)(object)__instance.m_addOreSwitch) { return; } string lockedSharedName = component2.LockedSharedName; if (!string.IsNullOrEmpty(lockedSharedName) && !((Humanoid)player).GetInventory().HaveItem(lockedSharedName, true)) { if (sendErrorMessage) { ((Character)player).Message((MessageType)2, Localization.instance.Localize("$msg_donthaveany " + lockedSharedName), 0, (Sprite)null, false); } __result = false; } } internal static bool HasCore(Player player) { string text = CoreItemSharedName(); if (!string.IsNullOrEmpty(text)) { return ((Humanoid)player).GetInventory().HaveItem(text, true); } return false; } internal static string CoreItemSharedName() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return null; } GameObject itemPrefab = instance.GetItemPrefab(ModConfig.CoreItem.Value); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.m_itemData.m_shared.m_name; } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] internal static class Player_UpdatePlacementGhost_Patch { private static void Postfix(GameObject ___m_placementGhost) { if (!((Object)(object)___m_placementGhost == (Object)null)) { SmelterExtension component = ___m_placementGhost.GetComponent<SmelterExtension>(); if (!((Object)(object)component == (Object)null)) { component.PokeConnection(); } } } } internal static class Pieces { private const string BundleName = "smelterupgrades"; private static AssetBundle s_bundle; private static bool s_bundleChecked; private static Transform s_visualHolder; private static readonly Dictionary<string, Material> s_retargeted = new Dictionary<string, Material>(); private static Shader s_pieceShader; public static void Register() { PrefabManager.OnVanillaPrefabsAvailable += AddPieces; } private static AssetBundle Bundle() { if (s_bundleChecked) { return s_bundle; } s_bundleChecked = true; if (!HasEmbeddedBundle()) { Logger.LogInfo((object)"No model bundle embedded; using vanilla models."); return null; } try { s_bundle = AssetUtils.LoadAssetBundleFromResources("smelterupgrades"); } catch (Exception ex) { Logger.LogError((object)("Model bundle failed to load: " + ex.Message)); s_bundle = null; } if ((Object)(object)s_bundle != (Object)null) { Logger.LogInfo((object)"Loaded custom model bundle."); } return s_bundle; } private static bool HasEmbeddedBundle() { int num = 0; string[] manifestResourceNames = typeof(Pieces).Assembly.GetManifestResourceNames(); for (int i = 0; i < manifestResourceNames.Length; i++) { if (manifestResourceNames[i].EndsWith("smelterupgrades")) { num++; } } if (num > 1) { Logger.LogError((object)(string.Format("{0} embedded resources end with '{1}'; the bundle lookup is ", num, "smelterupgrades") + "ambiguous and will fail. Only one may match.")); return false; } return num == 1; } private static GameObject MakePrefab(string prefabName, string cloneFrom, string modelPrefab, out bool fixReference) { AssetBundle val = Bundle(); if ((Object)(object)val != (Object)null && val.Contains(prefabName)) { GameObject val2 = val.LoadAsset<GameObject>(prefabName); if ((Object)(object)val2 != (Object)null) { fixReference = true; return PrefabManager.Instance.CreateClonedPrefab(prefabName, val2); } } fixReference = false; GameObject val3 = PrefabManager.Instance.CreateClonedPrefab(prefabName, cloneFrom); if ((Object)(object)val3 == (Object)null) { return null; } if ((Object)(object)val != (Object)null) { string text = prefabName + "_model"; if (val.Contains(text)) { GraftModel(val3, val.LoadAsset<GameObject>(text), retargetShader: true, alreadyInstantiated: false); return val3; } } if (!string.IsNullOrEmpty(modelPrefab) && modelPrefab != cloneFrom) { GameObject val4 = BorrowVisual(modelPrefab); if ((Object)(object)val4 != (Object)null) { GraftModel(val3, val4, retargetShader: false, alreadyInstantiated: true); return val3; } } return val3; } private static Transform VisualHolder() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_002a: Expected O, but got Unknown if ((Object)(object)s_visualHolder != (Object)null) { return s_visualHolder; } GameObject val = new GameObject("smx_visual_holder"); val.SetActive(false); Object.DontDestroyOnLoad((Object)val); s_visualHolder = val.transform; return s_visualHolder; } private static GameObject BorrowVisual(string modelPrefab) { GameObject prefab = PrefabManager.Instance.GetPrefab(modelPrefab); if ((Object)(object)prefab == (Object)null) { Logger.LogWarning((object)("Model prefab '" + modelPrefab + "' not found; keeping the donor's model.")); return null; } GameObject val = Object.Instantiate<GameObject>(prefab, VisualHolder()); LODGroup[] componentsInChildren = val.GetComponentsInChildren<LODGroup>(true); foreach (LODGroup val2 in componentsInChildren) { LOD[] lODs = val2.GetLODs(); for (int j = 1; j < lODs.Length; j++) { Renderer[] renderers = lODs[j].renderers; foreach (Renderer val3 in renderers) { if ((Object)(object)val3 != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val3).gameObject); } } } Object.DestroyImmediate((Object)(object)val2); } MonoBehaviour[] componentsInChildren2 = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val4 in componentsInChildren2) { if ((Object)(object)val4 != (Object)null) { Object.DestroyImmediate((Object)(object)val4); } } Collider[] componentsInChildren3 = val.GetComponentsInChildren<Collider>(true); foreach (Collider val5 in componentsInChildren3) { if ((Object)(object)val5 != (Object)null) { Object.DestroyImmediate((Object)(object)val5); } } Rigidbody[] componentsInChildren4 = val.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody val6 in componentsInChildren4) { if ((Object)(object)val6 != (Object)null) { Object.DestroyImmediate((Object)(object)val6); } } return val; } private static Shader PieceShader(GameObject donor) { if ((Object)(object)s_pieceShader != (Object)null) { return s_pieceShader; } s_pieceShader = Shader.Find("Custom/Piece"); if ((Object)(object)s_pieceShader != (Object)null) { return s_pieceShader; } Renderer[] componentsInChildren = donor.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!(val is MeshRenderer) && !(val is SkinnedMeshRenderer)) { continue; } Material sharedMaterial = val.sharedMaterial; if (!((Object)(object)sharedMaterial == (Object)null) && !((Object)(object)sharedMaterial.shader == (Object)null)) { string name = ((Object)sharedMaterial.shader).name; if (!name.Contains("Creature") && !name.Contains("Character") && !(name == "Standard")) { s_pieceShader = sharedMaterial.shader; return s_pieceShader; } } } Logger.LogWarning((object)"Could not resolve Valheim's piece shader; models keep the bundled one."); return null; } private static void GraftModel(GameObject prefab, GameObject model, bool retargetShader, bool alreadyInstantiated) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)model == (Object)null) { return; } Shader vanillaShader = PieceShader(prefab); LODGroup[] componentsInChildren = prefab.GetComponentsInChildren<LODGroup>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } Renderer[] componentsInChildren2 = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren2) { if (val is MeshRenderer || val is SkinnedMeshRenderer) { val.enabled = false; } } GameObject val2 = (alreadyInstantiated ? model : Object.Instantiate<GameObject>(model)); val2.transform.SetParent(prefab.transform, false); ((Object)val2).name = "smx_model"; val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; PrefabExtension.FixReferences(val2); if (retargetShader) { WarnOnUnresolvedMaterials(val2, ((Object)prefab).name); } if (retargetShader && ModConfig.UseVanillaShader.Value) { RetargetShader(val2, vanillaShader, ((Object)prefab).name); } } private static void RetargetShader(GameObject visual, Shader vanillaShader, string pieceName) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)vanillaShader == (Object)null) { Logger.LogWarning((object)("'" + pieceName + "': no vanilla shader to borrow; keeping the bundled one.")); return; } Renderer[] componentsInChildren = visual.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { Material[] sharedMaterials = val.sharedMaterials; Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if ((Object)(object)val2 == (Object)null) { array[j] = null; continue; } if ((Object)(object)val2.shader == (Object)(object)vanillaShader) { array[j] = val2; continue; } string key = ((Object)val2).name + "|" + ((Object)vanillaShader).name; if (!s_retargeted.TryGetValue(key, out var value)) { if ((Object)(object)val2.mainTexture != (Object)null && !CanCarryTexture(vanillaShader)) { Logger.LogWarning((object)("'" + pieceName + "': vanilla shader '" + ((Object)vanillaShader).name + "' has no _MainTex; keeping the bundled shader so the texture is not lost.")); s_retargeted[key] = val2; array[j] = val2; continue; } value = new Material(vanillaShader) { name = ((Object)val2).name + "_vanilla" }; if (value.HasProperty("_MainTex")) { value.mainTexture = val2.mainTexture; } if (value.HasProperty("_Color")) { value.color = val2.color; } s_retargeted[key] = value; Logger.LogInfo((object)("Retargeted '" + ((Object)val2).name + "' onto vanilla shader '" + ((Object)vanillaShader).name + "'.")); } array[j] = value; } val.sharedMaterials = array; } } private static bool CanCarryTexture(Shader shader) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown Material val = new Material(shader); bool result = val.HasProperty("_MainTex"); Object.DestroyImmediate((Object)val); return result; } private static void RenderIcon(GameObject prefab) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Piece component = prefab.GetComponent<Piece>(); if (!((Object)(object)component == (Object)null)) { RenderRequest val = new RenderRequest(prefab) { Rotation = RenderManager.IsometricRotation, UseCache = false, Width = 128, Height = 128 }; Sprite val2 = RenderManager.Instance.Render(val); if ((Object)(object)val2 != (Object)null) { component.m_icon = val2; } else { Logger.LogWarning((object)("Icon render returned nothing for '" + ((Object)prefab).name + "'.")); } } } private static void WarnOnUnresolvedMaterials(GameObject visual, string pieceName) { Renderer[] componentsInChildren = visual.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = componentsInChildren[i].sharedMaterials; foreach (Material val in sharedMaterials) { if ((Object)(object)val == (Object)null) { Logger.LogWarning((object)("'" + pieceName + "': a renderer has no material.")); return; } if (((Object)val).name.StartsWith("JVLmock_")) { Logger.LogWarning((object)("'" + pieceName + "': mock material '" + ((Object)val).name + "' did not resolve. The vanilla material it names is probably not loaded; ship your own texture instead of mocking.")); return; } } } } private static void AddPieces() { PrefabManager.OnVanillaPrefabsAvailable -= AddPieces; foreach (UpgradeDef item in ModConfig.All) { try { AddPiece(item); } catch (Exception ex) { Logger.LogError((object)("Failed to register upgrade piece '" + item.Key + "': " + ex.Message)); } } try { AddFeederChest(); } catch (Exception ex2) { Logger.LogError((object)("Failed to register the feeder chest: " + ex2.Message)); } } private static void AddFeederChest() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown bool fixReference; GameObject val = MakePrefab("smx_feeder_chest", "piece_chest_wood", ModConfig.FeederModelPrefab.Value, out fixReference); if ((Object)(object)val == (Object)null) { Logger.LogError((object)"Could not build a prefab for the feeder chest."); return; } Container component = val.GetComponent<Container>(); if ((Object)(object)component != (Object)null) { component.m_name = "$smx_feeder_name"; } val.AddComponent<SmelterFeeder>(); PieceConfig val2 = new PieceConfig { Name = "$smx_feeder_name", Description = "$smx_feeder_desc", PieceTable = "Hammer", Category = "Crafting", CraftingStation = "forge" }; val2.AddRequirement(new RequirementConfig("BlackMetal", 10, 0, true)); val2.AddRequirement(new RequirementConfig("LinenThread", 10, 0, true)); val2.AddRequirement(new RequirementConfig("Iron", 5, 0, true)); PieceManager.Instance.AddPiece(new CustomPiece(val, fixReference, val2)); RenderIcon(val); } private static void AddPiece(UpgradeDef def) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown bool fixReference; GameObject val = MakePrefab(def.PrefabName, def.CloneFrom, def.ModelPrefab.Value, out fixReference); if ((Object)(object)val == (Object)null) { Logger.LogError((object)("Could not build a prefab for '" + def.Key + "'.")); return; } StationExtension component = val.GetComponent<StationExtension>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } val.AddComponent<SmelterExtension>().UpgradeKey = def.Key; PieceConfig val2 = new PieceConfig { Name = def.DisplayName, Description = def.Description, PieceTable = "Hammer", Category = "Crafting", CraftingStation = def.CraftedAt }; (string, int)[] requirements = def.Requirements; for (int i = 0; i < requirements.Length; i++) { var (text, num) = requirements[i]; val2.AddRequirement(new RequirementConfig(text, num, 0, true)); } PieceManager.Instance.AddPiece(new CustomPiece(val, fixReference, val2)); RenderIcon(val); } } [BepInPlugin("zl.smelterupgrades", "Smelter Upgrades", "1.1.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "zl.smelterupgrades"; public const string PluginName = "Smelter Upgrades"; public const string PluginVersion = "1.1.5"; internal static Plugin Instance; private Harmony _harmony; private void Awake() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown Instance = this; ModConfig.Init(((BaseUnityPlugin)this).Config); ModelDump.Register(((BaseUnityPlugin)this).Config); ModLocalization.Register(); Pieces.Register(); HotkeyWatcher.RegisterButton(); QueueIconPanel.Register(); ((Component)this).gameObject.AddComponent<HotkeyWatcher>(); _harmony = new Harmony("zl.smelterupgrades"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Smelter Upgrades 1.1.5 loaded"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal class QueueIconPanel : MonoBehaviour { private class Slot { public GameObject Go; public RectTransform Rect; public Image Icon; public Text Count; } private const int MaxGroups = 12; private const float IconSize = 34f; private const float IconGap = 4f; private const float VerticalOffset = -120f; private static QueueIconPanel s_instance; private RectTransform m_content; private readonly List<Slot> m_slots = new List<Slot>(); private readonly List<KeyValuePair<string, int>> m_queue = new List<KeyValuePair<string, int>>(); private static readonly Dictionary<string, Sprite> s_iconCache = new Dictionary<string, Sprite>(); public static void Register() { GUIManager.OnCustomGUIAvailable += Create; } private static void Create() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)s_instance)) { GameObject val = new GameObject("smx_queue_panel", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(GUIManager.CustomGUIFront.transform, false); s_instance = val.AddComponent<QueueIconPanel>(); s_instance.Build(); } } private void Build() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) RectTransform component = ((Component)this).GetComponent<RectTransform>(); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 0.5f); component.anchorMax = val; component.anchorMin = val; component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = new Vector2(0f, -120f); component.sizeDelta = new Vector2(456f, 34f); GameObject val2 = new GameObject("content", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent((Transform)(object)component, false); m_content = val2.GetComponent<RectTransform>(); m_content.anchorMin = Vector2.zero; m_content.anchorMax = Vector2.one; m_content.offsetMin = Vector2.zero; m_content.offsetMax = Vector2.zero; ((Component)m_content).gameObject.SetActive(false); } private Slot GetSlot(int index) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) Vector2 val2 = default(Vector2); while (m_slots.Count <= index) { GameObject val = new GameObject($"slot{m_slots.Count}", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent((Transform)(object)m_content, false); RectTransform component = val.GetComponent<RectTransform>(); ((Vector2)(ref val2))..ctor(0.5f, 0.5f); component.anchorMax = val2; component.anchorMin = val2; component.pivot = new Vector2(0.5f, 0.5f); component.sizeDelta = new Vector2(34f, 34f); Image component2 = val.GetComponent<Image>(); component2.preserveAspect = true; ((Graphic)component2).raycastTarget = false; GameObject val3 = new GameObject("count", new Type[2] { typeof(RectTransform), typeof(Text) }); val3.transform.SetParent(val.transform, false); RectTransform component3 = val3.GetComponent<RectTransform>(); component3.anchorMin = Vector2.zero; component3.anchorMax = Vector2.one; component3.offsetMin = Vector2.zero; component3.offsetMax = Vector2.zero; Text component4 = val3.GetComponent<Text>(); component4.alignment = (TextAnchor)8; ((Graphic)component4).raycastTarget = false; GUIManager.Instance.ApplyTextStyle(component4, Color.white, 14, true); m_slots.Add(new Slot { Go = val, Rect = component, Icon = component2, Count = component4 }); } return m_slots[index]; } internal static Sprite IconFor(string prefabName) { if (s_iconCache.TryGetValue(prefabName, out var value)) { return value; } Sprite val = null; ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return null; } GameObject itemPrefab = instance.GetItemPrefab(prefabName); ItemDrop val2 = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 != (Object)null && val2.m_itemData.m_shared.m_icons.Length != 0) { val = val2.m_itemData.m_shared.m_icons[0]; } s_iconCache[prefabName] = val; return val; } private void Update() { SmelterStation smelterStation = HoveredStation(); if ((Object)(object)smelterStation == (Object)null) { Hide(); return; } smelterStation.GetGroupedQueue(m_queue); if (m_queue.Count == 0) { Hide(); return; } ((Component)m_content).gameObject.SetActive(true); Layout(); } private void Hide() { if ((Object)(object)m_content != (Object)null && ((Component)m_content).gameObject.activeSelf) { ((Component)m_content).gameObject.SetActive(false); } } private void Layout() { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Min(m_queue.Count, 12); float num2 = (0f - ((float)num * 34f + (float)Mathf.Max(0, num - 1) * 4f)) * 0.5f + 17f; for (int i = 0; i < num; i++) { Slot slot = GetSlot(i); KeyValuePair<string, int> keyValuePair = m_queue[i]; Sprite val = IconFor(keyValuePair.Key); slot.Icon.sprite = val; ((Behaviour)slot.Icon).enabled = (Object)(object)val != (Object)null; slot.Count.text = ((keyValuePair.Value > 1) ? ("x" + keyValuePair.Value) : string.Empty); slot.Rect.anchoredPosition = new Vector2(num2, 0f); num2 += 38f; slot.Go.SetActive(true); } if (m_queue.Count > 12 && num > 0) { GetSlot(num - 1).Count.text = "+" + (m_queue.Count - 12 + 1); } for (int j = num; j < m_slots.Count; j++) { m_slots[j].Go.SetActive(false); } } private static SmelterStation HoveredStation() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } if (InventoryGui.IsVisible() || Menu.IsVisible()) { return null; } GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); if (!((Object)(object)hoverObject != (Object)null)) { return null; } return hoverObject.GetComponentInParent<SmelterStation>(); } } public class SmelterExtension : MonoBehaviour, Hoverable { public string UpgradeKey; private static readonly List<SmelterExtension> s_all = new List<SmelterExtension>(); private static GameObject s_connectionPrefab; private static bool s_connectionPrefabSearched; private Piece m_piece; private GameObject m_connection; private string PieceName { get { if (!((Object)(object)m_piece != (Object)null)) { return ((Object)this).name; } return m_piece.m_name; } } private void Awake() { m_piece = ((Component)this).GetComponent<Piece>(); ZNetView component = ((Component)this).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.GetZDO() != null) { s_all.Add(this); } } private void OnDestroy() { StopConnectionEffect(); s_all.Remove(this); } public string GetHoverName() { return Localization.instance.Localize(PieceName); } public string GetHoverText() { PokeConnection(); return Localization.instance.Localize(PieceName); } public float GetHoverOffset() { return 0f; } public void PokeConnection(float timeout = 1f) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) UpgradeDef upgradeDef = ModConfig.Get(UpgradeKey); if (upgradeDef != null) { SmelterStation smelterStation = SmelterStation.FindClosest(upgradeDef.TargetPrefab, ((Component)this).transform.position, upgradeDef.Range.Value); if ((Object)(object)smelterStation != (Object)null) { StartConnectionEffect(smelterStation.StationPosition, timeout); } else { StopConnectionEffect(); } } } public static void FindFor(string targetPrefab, Vector3 stationPos, List<SmelterExtension> into) { //IL_0041: 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) foreach (SmelterExtension item in s_all) { if (!((Object)(object)item == (Object)null)) { UpgradeDef upgradeDef = ModConfig.Get(item.UpgradeKey); if (upgradeDef != null && !(upgradeDef.TargetPrefab != targetPrefab) && !(Vector3.Distance(((Component)item).transform.position, stationPos) >= upgradeDef.Range.Value) && !AlreadyHasType(into, item)) { into.Add(item); } } } } private static bool AlreadyHasType(List<SmelterExtension> chosen, SmelterExtension candidate) { foreach (SmelterExtension item in chosen) { if (item.PieceName == candidate.PieceName) { return true; } } return false; } private static GameObject ConnectionPrefab() { if (s_connectionPrefabSearched) { return s_connectionPrefab; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { return null; } s_connectionPrefabSearched = true; GameObject prefab = instance.GetPrefab("forge_ext1"); StationExtension val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<StationExtension>() : null); if ((Object)(object)val != (Object)null) { s_connectionPrefab = val.m_connectionPrefab; } if ((Object)(object)s_connectionPrefab == (Object)null) { Logger.LogWarning((object)"Could not borrow the station connection VFX; upgrade beams disabled."); } return s_connectionPrefab; } public void StartConnectionEffect(Vector3 targetPos, float timeout = 1f) { //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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_0044: Unknown result type (might be due to invalid IL or missing references) GameObject val = ConnectionPrefab(); if ((Object)(object)val == (Object)null) { return; } Vector3 position = ((Component)this).transform.position; Vector3 val2 = targetPos - position; if (!(((Vector3)(ref val2)).sqrMagnitude < 0.0001f)) { if ((Object)(object)m_connection == (Object)null) { m_connection = Object.Instantiate<GameObject>(val, position, Quaternion.identity); } m_connection.transform.position = position; m_connection.transform.rotation = Quaternion.LookRotation(((Vector3)(ref val2)).normalized); m_connection.transform.localScale = new Vector3(1f, 1f, ((Vector3)(ref val2)).magnitude); ((MonoBehaviour)this).CancelInvoke("StopConnectionEffect"); ((MonoBehaviour)this).Invoke("StopConnectionEffect", timeout); } } public void StopConnectionEffect() { if (!((Object)(object)m_connection == (Object)null)) { Object.Destroy((Object)(object)m_connection); m_connection = null; } } } public class SmelterFeeder : MonoBehaviour { private Container m_container; private ZNetView m_nview; private static readonly List<Piece> s_pieceBuffer = new List<Piece>(); private static readonly HashSet<Smelter> s_seen = new HashSet<Smelter>(); private static bool s_warned; private readonly List<Smelter> m_targets = new List<Smelter>(); private void Awake() { m_container = ((Component)this).GetComponent<Container>(); m_nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)m_container == (Object)null || (Object)(object)m_nview == (Object)null || m_nview.GetZDO() == null) { ((Behaviour)this).enabled = false; } else { ((MonoBehaviour)this).InvokeRepeating("Tick", Random.Range(1f, 2f), ModConfig.FeederInterval.Value); } } private void Tick() { if (!ModConfig.FeederEnabled.Value || !m_nview.IsOwner()) { return; } Inventory inventory = m_container.GetInventory(); if (inventory == null || inventory.NrOfItems() == 0) { return; } CollectNearbySmelters(m_targets); foreach (Smelter target in m_targets) { try { FeedFuel(target, inventory); FeedOre(target, inventory); } catch (Exception ex) { WarnOnce("could not feed '" + PrefabNameOf(target) + "': " + ex.Message); } } } private void CollectNearbySmelters(List<Smelter> into) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) into.Clear(); s_pieceBuffer.Clear(); s_seen.Clear(); Piece.GetAllPiecesInRadius(((Component)this).transform.position, ModConfig.FeederRange.Value, s_pieceBuffer); foreach (Piece item in s_pieceBuffer) { if (!((Object)(object)item == (Object)null)) { Smelter componentInChildren = ((Component)item).GetComponentInChildren<Smelter>(); if (!((Object)(object)componentInChildren == (Object)null) && s_seen.Add(componentInChildren) && ModConfig.IsFeederStation(PrefabNameOf(componentInChildren))) { into.Add(componentInChildren); } } } } private static ZNetView ViewOf(Smelter smelter) { return ((Component)smelter).GetComponent<ZNetView>() ?? ((Component)smelter).GetComponentInParent<ZNetView>(); } private static string PrefabNameOf(Smelter smelter) { ZNetView val = ViewOf(smelter); if (!