Decompiled source of SlagCrusher v1.0.1

developerblue.SlagCrusher.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("developerblue.SlagCrusher")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("developerblue.SlagCrusher")]
[assembly: AssemblyTitle("developerblue.SlagCrusher")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SlagCrusher
{
	internal static class IronSlagItem
	{
		internal const string PrefabName = "IronSlag";

		private const string NameToken = "$slagcrusher_ironslag";

		private const string DescriptionToken = "$slagcrusher_ironslag_desc";

		private const float Weight = 10f;

		private const int MaxStack = 50;

		private const float Scale = 1.3f;

		private static GameObject _prefab;

		internal static Mesh OriginalMesh;

		private static bool _registered;

		internal static Sprite Icon { get; private set; }

		internal static void SetIcon(Sprite icon)
		{
			Icon = icon;
			_prefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { icon };
		}

		internal static bool Register()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			if (_registered)
			{
				return true;
			}
			GameObject orCreate = GetOrCreate();
			if ((Object)(object)orCreate == (Object)null)
			{
				return false;
			}
			if (!ItemManager.Instance.AddItem(new CustomItem(orCreate, false)))
			{
				Plugin.Instance.LogWarning("Iron Slag was not added.");
				return false;
			}
			_registered = true;
			return true;
		}

		private static GameObject GetOrCreate()
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_prefab != (Object)null)
			{
				return _prefab;
			}
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("IronSlag", "Stone");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			val.SetActive(true);
			ItemDrop component = val.GetComponent<ItemDrop>();
			component.m_itemData.m_dropPrefab = val;
			SharedData shared = component.m_itemData.m_shared;
			shared.m_name = "$slagcrusher_ironslag";
			shared.m_description = "$slagcrusher_ironslag_desc";
			shared.m_weight = 10f;
			shared.m_maxStackSize = 50;
			Mesh val2 = MeshFile.LoadMesh();
			OriginalMesh = new Mesh
			{
				name = ((Object)val2).name + "_original"
			};
			OriginalMesh.vertices = (Vector3[])(object)new Vector3[val2.vertices.Length];
			Array.Copy(val2.vertices, 0, OriginalMesh.vertices, 0, val2.vertices.Length);
			OriginalMesh.normals = (Vector3[])(object)new Vector3[val2.normals.Length];
			Array.Copy(val2.normals, 0, OriginalMesh.normals, 0, val2.normals.Length);
			OriginalMesh.uv = (Vector2[])(object)new Vector2[val2.uv.Length];
			Array.Copy(val2.uv, 0, OriginalMesh.uv, 0, val2.uv.Length);
			OriginalMesh.uv2 = (Vector2[])(object)new Vector2[val2.uv2.Length];
			Array.Copy(val2.uv2, 0, OriginalMesh.uv2, 0, val2.uv2.Length);
			OriginalMesh.triangles = new int[val2.triangles.Length];
			Array.Copy(val2.triangles, 0, OriginalMesh.triangles, 0, val2.triangles.Length);
			OriginalMesh.colors32 = (Color32[])(object)new Color32[val2.colors32.Length];
			Array.Copy(val2.colors32, 0, OriginalMesh.colors32, 0, val2.colors32.Length);
			Vector3[] vertices = val2.vertices;
			for (int i = 0; i < vertices.Length; i++)
			{
				vertices[i] *= 1.3f;
			}
			val2.vertices = vertices;
			val2.RecalculateBounds();
			val2.RecalculateTangents();
			Texture2D albedo = MeshFile.LoadTexture("iron-slag-albedo.png", linear: false);
			Texture2D normal = MeshFile.LoadTexture("iron-slag-normal.png", linear: true);
			Texture2D roughness = MeshFile.LoadTexture("iron-slag-roughness.png", linear: true);
			Texture2D val3 = MeshFile.LoadTexture("iron-slag-icon.png", linear: false);
			ApplyVisual(val, val2, albedo, normal, roughness);
			Icon = Sprite.Create(val3, new Rect(0f, 0f, (float)((Texture)val3).width, (float)((Texture)val3).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
			shared.m_icons = (Sprite[])(object)new Sprite[1] { Icon };
			_prefab = val;
			Plugin.Instance.LogVerbose("Registered item IronSlag (" + val2.vertexCount + " verts, " + val2.triangles.Length / 3 + " tris).");
			return _prefab;
		}

		private static void ApplyVisual(GameObject prefab, Mesh mesh, Texture2D albedo, Texture2D normal, Texture2D roughness)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			Dictionary<Material, Material> dictionary = new Dictionary<Material, Material>();
			MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val in componentsInChildren)
			{
				if ((Object)(object)((Component)val).GetComponent<ParticleSystem>() != (Object)null || (Object)(object)((Component)val).GetComponent<ParticleSystemRenderer>() != (Object)null)
				{
					continue;
				}
				Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if ((Object)(object)sharedMaterials[j] == (Object)null)
					{
						continue;
					}
					if (!dictionary.TryGetValue(sharedMaterials[j], out var value))
					{
						value = new Material(sharedMaterials[j])
						{
							name = "iron_slag"
						};
						value.mainTexture = (Texture)(object)albedo;
						SetTexture(value, new string[3] { "_BumpMap", "_NormalMap", "_Normal" }, normal);
						if (value.HasProperty("_BumpMap"))
						{
							value.EnableKeyword("_NORMALMAP");
						}
						if (value.HasProperty("_MetallicGlossMap"))
						{
							value.SetTexture("_MetallicGlossMap", (Texture)(object)MetallicGloss(roughness));
							value.EnableKeyword("_METALLICGLOSSMAP");
						}
						if (value.HasProperty("_Metallic"))
						{
							value.SetFloat("_Metallic", 1f);
						}
						if (value.HasProperty("_Glossiness"))
						{
							value.SetFloat("_Glossiness", 0.25f);
						}
						dictionary.Add(sharedMaterials[j], value);
					}
					sharedMaterials[j] = value;
				}
				((Renderer)val).sharedMaterials = sharedMaterials;
			}
			MeshFilter[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val2 in componentsInChildren2)
			{
				if (!((Object)(object)((Component)val2).GetComponent<MeshRenderer>() == (Object)null) && !((Object)(object)((Component)val2).GetComponent<ParticleSystem>() != (Object)null) && !((Object)(object)((Component)val2).GetComponent<ParticleSystemRenderer>() != (Object)null))
				{
					val2.sharedMesh = mesh;
				}
			}
			MeshCollider[] componentsInChildren3 = prefab.GetComponentsInChildren<MeshCollider>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				componentsInChildren3[i].sharedMesh = mesh;
			}
		}

		private static void SetTexture(Material material, string[] properties, Texture2D texture)
		{
			foreach (string text in properties)
			{
				if (material.HasProperty(text))
				{
					material.SetTexture(text, (Texture)(object)texture);
				}
			}
		}

		private static Texture2D MetallicGloss(Texture2D roughness)
		{
			//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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			Color[] pixels = roughness.GetPixels();
			Texture2D val = new Texture2D(((Texture)roughness).width, ((Texture)roughness).height, (TextureFormat)4, true, true)
			{
				name = "iron-slag-metallic",
				wrapMode = (TextureWrapMode)1
			};
			for (int i = 0; i < pixels.Length; i++)
			{
				float num = 1f - pixels[i].r;
				pixels[i] = new Color(1f, 1f, 1f, num);
			}
			val.SetPixels(pixels);
			val.Apply();
			return val;
		}
	}
	internal static class MeshFile
	{
		internal static Mesh LoadMesh()
		{
			return LoadMesh("iron-slag.mesh", "IronSlag");
		}

		internal static Mesh LoadMesh(string resourceName, string meshName)
		{
			//IL_008c: 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_009a: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			using BinaryReader binaryReader = new BinaryReader(Open(resourceName));
			string text = new string(binaryReader.ReadChars(4));
			if (text != "SLG1")
			{
				throw new InvalidDataException(resourceName + " header was " + text + ".");
			}
			int num = binaryReader.ReadInt32();
			int num2 = binaryReader.ReadInt32();
			float[] values = ReadVectors(binaryReader, num, 3);
			float[] values2 = ReadVectors(binaryReader, num, 3);
			float[] values3 = ReadVectors(binaryReader, num, 2);
			int[] array = new int[num2];
			for (int i = 0; i < num2; i++)
			{
				array[i] = binaryReader.ReadInt32();
			}
			Mesh val = new Mesh
			{
				name = meshName
			};
			val.vertices = Vectors3(values);
			val.normals = Vectors3(values2);
			val.uv = Vectors2(values3);
			val.uv2 = val.uv;
			val.triangles = array;
			Color32[] array2 = (Color32[])(object)new Color32[num];
			for (int j = 0; j < num; j++)
			{
				array2[j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
			}
			val.colors32 = array2;
			val.RecalculateBounds();
			val.RecalculateTangents();
			return val;
		}

		internal static Texture2D LoadTexture(string name, bool linear)
		{
			//IL_003f: 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)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0072: Expected O, but got Unknown
			byte[] array;
			using (Stream stream = Open(name))
			{
				array = new byte[stream.Length];
				for (int i = 0; i < array.Length; i += stream.Read(array, i, array.Length - i))
				{
				}
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
			{
				name = name,
				wrapMode = (TextureWrapMode)1
			};
			if (!ImageConversion.LoadImage(val, array))
			{
				throw new InvalidDataException("Could not load " + name + ".");
			}
			return val;
		}

		private static Stream Open(string name)
		{
			return Assembly.GetExecutingAssembly().GetManifestResourceStream(name) ?? throw new FileNotFoundException("Missing embedded slag resource " + name + ".");
		}

		private static float[] ReadVectors(BinaryReader reader, int count, int components)
		{
			float[] array = new float[count * components];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = reader.ReadSingle();
			}
			return array;
		}

		private static Vector3[] Vectors3(float[] values)
		{
			//IL_0024: 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)
			Vector3[] array = (Vector3[])(object)new Vector3[values.Length / 3];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new Vector3(values[i * 3], values[i * 3 + 1], values[i * 3 + 2]);
			}
			return array;
		}

		private static Vector2[] Vectors2(float[] values)
		{
			//IL_001d: 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)
			Vector2[] array = (Vector2[])(object)new Vector2[values.Length / 2];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new Vector2(values[i * 2], values[i * 2 + 1]);
			}
			return array;
		}
	}
	internal static class ModConfig
	{
		internal const int RatioMin = -20;

		internal const int RatioMax = 20;

		private const int DefaultRatio = 2;

		internal const int CrusherMin = -5;

		internal const int CrusherMax = 5;

		private const int DefaultCrusherOutput = -1;

		private const string DefaultRecipe = "Stone:20,SurtlingCore:7,Bronze:20,RoundLog:5";

		private const string DefaultBlastRecipe = "Stone:20,SurtlingCore:7,Iron:20,FineWood:20";

		private static readonly string DefaultStation = CraftingStations.Forge;

		private static readonly string DefaultBlastStation = CraftingStations.ArtisanTable;

		private static string _configError;

		private static ConfigurationManagerAttributes _blastOutputAttrs;

		private static ConfigurationManagerAttributes _blastCoalAttrs;

		private static ConfigurationManagerAttributes _blastTimeAttrs;

		private static readonly Dictionary<string, ConfigEntry<int>> _metals = new Dictionary<string, ConfigEntry<int>>();

		private static readonly Dictionary<string, ConfigEntry<bool>> _overrides = new Dictionary<string, ConfigEntry<bool>>();

		private static readonly Dictionary<string, ConfigurationManagerAttributes> _ratioAttributes = new Dictionary<string, ConfigurationManagerAttributes>();

		private static ConfigEntry<int> _globalRatio;

		private static ConfigEntry<bool> _smelterCompatibility;

		private static ConfigEntry<bool> _allowTeleport;

		private static ConfigEntry<string> _craftingRecipe;

		private static ConfigEntry<string> _blastCraftingRecipe;

		private static ConfigEntry<string> _requiredStation;

		private static ConfigEntry<string> _blastRequiredStation;

		private static ConfigEntry<int> _crusherOutput;

		private static ConfigEntry<int> _coalPerCycle;

		private static ConfigEntry<int> _smeltTime;

		private static ConfigEntry<bool> _blastCustomCycle;

		private static ConfigEntry<int> _blastCrusherOutput;

		private static ConfigEntry<int> _blastCoalPerCycle;

		private static ConfigEntry<int> _blastSmeltTime;

		private static ConfigEntry<bool> _verboseLogging;

		private static readonly float DebounceSeconds = 0.25f;

		private static ConfigEntryBase _debounceEntry;

		private static int _debounceValue;

		private static float _debounceDeadline;

		internal static int OutputSlagPerCycle
		{
			get
			{
				int num = Clamp(_crusherOutput.Value, -5, 5);
				if (num >= 0)
				{
					return 1;
				}
				return -num;
			}
		}

		internal static int OutputIngotsPerCycle
		{
			get
			{
				int num = Clamp(_crusherOutput.Value, -5, 5);
				if (num <= 0)
				{
					return 1;
				}
				return num;
			}
		}

		internal static int CoalPerCycle => Clamp(_coalPerCycle.Value, 0, 20);

		internal static int SmeltTime => Mathf.Clamp(_smeltTime.Value, 1, 300);

		internal static bool SmelterCompatibility => _smelterCompatibility.Value;

		internal static bool BlastCustomCycle => _blastCustomCycle.Value;

		internal static bool VerboseLogging
		{
			get
			{
				if (_verboseLogging != null)
				{
					return _verboseLogging.Value;
				}
				return false;
			}
		}

		internal static int BlastOutputSlagPerCycle
		{
			get
			{
				int num = Clamp(_blastCrusherOutput.Value, -5, 5);
				if (num >= 0)
				{
					return 1;
				}
				return -num;
			}
		}

		internal static int BlastOutputIngotsPerCycle
		{
			get
			{
				int num = Clamp(_blastCrusherOutput.Value, -5, 5);
				if (num <= 0)
				{
					return 1;
				}
				return num;
			}
		}

		internal static int BlastCoalPerCycle => Clamp(_blastCoalPerCycle.Value, 0, 20);

		internal static int BlastSmeltTime => Mathf.Clamp(_blastSmeltTime.Value, 1, 300);

		internal static int CrusherIngotsPerCycle(bool blast)
		{
			if (!blast || !BlastCustomCycle)
			{
				return OutputIngotsPerCycle;
			}
			return BlastOutputIngotsPerCycle;
		}

		internal static int CrusherSlagPerCycle(bool blast)
		{
			if (!blast || !BlastCustomCycle)
			{
				return OutputSlagPerCycle;
			}
			return BlastOutputSlagPerCycle;
		}

		internal static int SlagRatio(SlagMetal metal)
		{
			if (metal != null && _overrides.TryGetValue(metal.Id, out var value) && value.Value && _metals.TryGetValue(metal.Id, out var value2))
			{
				return Clamp(value2.Value, -20, 20);
			}
			if (_globalRatio == null)
			{
				return 0;
			}
			return Clamp(_globalRatio.Value, -20, 20);
		}

		internal static void Bind(ConfigFile config)
		{
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Expected O, but got Unknown
			_craftingRecipe = Add(config, "Slag Crusher", "Crafting recipe", "Stone:20,SurtlingCore:7,Bronze:20,RoundLog:5", 190, "Build cost of the Slag Crusher. Each entry is an item prefab name, a colon, and an amount. Separate entries with commas.");
			_requiredStation = Add(config, "Slag Crusher", "Required station", DefaultStation, 185, "Station prefab that must be nearby to build the Slag Crusher. Defaults to the Forge (forge), the same station as the Smelter. Leave empty for no station. Forge, Workbench, ArtisanTable, and the other Jotunn station names are also accepted.");
			_crusherOutput = Add(config, "Slag Crusher", "Crusher output", -1, 170, "Controls how much one crusher cycle consumes and yields, as a trade in slag and ingots. The slider label reads 5 Slag ➜ 1 Ingot at -5, 1 Slag ➜ 1 Ingot at -1, 0, and 1, and 1 Slag ➜ 5 Ingots at 5.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-5, 5), DrawCrusherOutput, "Slag to Ingot ratio");
			_coalPerCycle = Add(config, "Slag Crusher", "Coal burned", 2, 165, "Coal burned as fuel for each crusher cycle. 0 turns the fuel requirement off for the Slag Crusher and the Blast Crusher.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20));
			_smeltTime = Add(config, "Slag Crusher", "Smelt time", 30, 150, "Seconds one crusher cycle takes. This applies to the Slag Crusher and the Blast Crusher.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 300));
			_blastCraftingRecipe = Add(config, "Blast Crusher", "Crafting recipe", "Stone:20,SurtlingCore:7,Iron:20,FineWood:20", 190, "Build cost of the Blast Crusher. Each entry is an item prefab name, a colon, and an amount. Separate entries with commas.");
			_blastRequiredStation = Add(config, "Blast Crusher", "Required station", DefaultBlastStation, 185, "Station prefab that must be nearby to build the Blast Crusher. Defaults to the Artisan table (piece_artisanstation), the same station as the Blast Furnace. Leave empty for no station. Forge, Workbench, ArtisanTable, and the other Jotunn station names are also accepted.");
			_blastCustomCycle = Add(config, "Blast Crusher", "Custom Cycle Settings", defaultValue: false, 160, "When on, the Blast Crusher uses its own Crusher Output, Coal Burned, and Smelt Time instead of the shared Slag Crusher values.");
			_blastOutputAttrs = new ConfigurationManagerAttributes
			{
				Browsable = false
			};
			_blastCoalAttrs = new ConfigurationManagerAttributes
			{
				Browsable = false
			};
			_blastTimeAttrs = new ConfigurationManagerAttributes
			{
				Browsable = false
			};
			_blastCrusherOutput = Add(config, "Blast Crusher", "Blast Crusher output", -1, 155, "Controls how much one blast crusher cycle consumes and yields, the same trade as the Slag Crusher output. Only used when Custom Cycle Settings is on.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-5, 5), DrawCrusherOutput, "Blast Slag to Ingot ratio", _blastOutputAttrs);
			_blastCoalPerCycle = Add(config, "Blast Crusher", "Blast Coal burned", 2, 150, "Coal burned as fuel for each blast crusher cycle. Only used when Custom Cycle Settings is on.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), null, null, _blastCoalAttrs);
			_blastSmeltTime = Add(config, "Blast Crusher", "Blast Smelt time", 30, 145, "Seconds one blast crusher cycle takes. Only used when Custom Cycle Settings is on.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 300), null, null, _blastTimeAttrs);
			_blastCustomCycle.SettingChanged += delegate
			{
				ShowBlastOverrides();
				ApplyAll();
			};
			_globalRatio = Add(config, "Slag Output", "Slag ratio", 2, 1000, "How much slag smelting produces, for every metal that does not have an override on. The slider label reads as a trade, ingots to slag: 20 Ingots ➜ 1 Slag at the far left, No Slag in the middle, and 1 Ingot ➜ 20 Slag at the far right. One step either side of the middle is 1 Ingot ➜ 1 Slag. The default is 1 slag per 2 ingots.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-20, 20), DrawSlagRatio, "Slag Output Ratio");
			_globalRatio.SettingChanged += delegate
			{
				ResetGlobalRatio();
			};
			_allowTeleport = Add(config, "Slag Output", "Allow teleport", defaultValue: false, 990, "Allow slag to be carried through portals.");
			BindMetals(config);
			_smelterCompatibility = Add(config, "Blast Crusher", "Process Lower Slag Tiers", defaultValue: false, -1000, "When on, the Blast Crusher can also process lower-tier slag (copper, tin, bronze, iron, silver) into the matching ingot. When off, it only processes its own high-tier slag. Applies without a restart.");
			_verboseLogging = Add(config, "General", "Verbose logging", defaultValue: false, 0, "Log detailed startup and diagnostic messages to the BepInEx console. When off, the log is limited to warnings and errors. This is a per-client setting and is not synced from the server.", null, null, null, null, null, synced: false);
			Watch<string>(_craftingRecipe);
			Watch<string>(_requiredStation);
			Watch<string>(_blastCraftingRecipe);
			Watch<string>(_blastRequiredStation);
			Watch<int>(_crusherOutput);
			Watch<int>(_coalPerCycle);
			Watch<int>(_smeltTime);
			Watch<bool>(_blastCustomCycle);
			Watch<int>(_blastCrusherOutput);
			Watch<int>(_blastCoalPerCycle);
			Watch<int>(_blastSmeltTime);
			Watch<bool>(_allowTeleport);
			Watch<bool>(_smelterCompatibility);
			SynchronizationManager.OnConfigurationSynchronized += delegate
			{
				ApplyAll();
			};
		}

		internal static void AddRequirements(PieceConfig pieceConfig, bool blast)
		{
			string error;
			foreach (RequirementConfig item in Requirements(blast, out error))
			{
				pieceConfig.AddRequirement(item);
			}
		}

		internal static void ApplyTo(GameObject station)
		{
			if ((Object)(object)station == (Object)null)
			{
				return;
			}
			bool flag = ((Object)station).name.Replace("(Clone)", "") == "piece_blastcrusher";
			string label = (flag ? "Blast Crusher" : "Slag Crusher");
			Smelter component = station.GetComponent<Smelter>();
			if ((Object)(object)component != (Object)null)
			{
				bool flag2 = flag && BlastCustomCycle;
				component.m_secPerProduct = (flag2 ? BlastSmeltTime : SmeltTime);
				int num = (flag2 ? BlastCoalPerCycle : CoalPerCycle);
				if (num <= 0)
				{
					component.m_maxFuel = 0;
					component.m_fuelPerProduct = 0;
				}
				else
				{
					component.m_maxFuel = SlagCrusherStation.FuelCapacity;
					component.m_fuelPerProduct = num;
				}
			}
			Piece component2 = station.GetComponent<Piece>();
			if ((Object)(object)component2 == (Object)null)
			{
				return;
			}
			if (TryRequiredStation(flag, out var station2, out var error))
			{
				component2.m_craftingStation = station2;
			}
			else
			{
				Report(error);
			}
			string error2;
			List<RequirementConfig> list = Requirements(flag, out error2);
			if (list == null)
			{
				Report(error2);
				return;
			}
			Requirement[] array = Resolve(list, label, out error2);
			if (array == null)
			{
				Report(error2);
			}
			else
			{
				component2.m_resources = array;
			}
		}

		private static void BindMetals(ConfigFile config)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			int num = 100;
			string text = null;
			SlagMetal[] all = SlagMetals.All;
			foreach (SlagMetal slagMetal in all)
			{
				if (slagMetal.Section != text)
				{
					text = slagMetal.Section;
					num = 100;
				}
				config.Remove(new ConfigDefinition(slagMetal.Section, slagMetal.MetalName));
				string key = slagMetal.MetalName + " override";
				bool num2 = ConfigHas(config, slagMetal.Section, key);
				ConfigEntry<bool> val = Add(config, slagMetal.Section, key, defaultValue: false, num, "Use a separate slag ratio for " + slagMetal.MetalName.ToLowerInvariant() + ". The slider stays hidden until this is on.", null, null, slagMetal.MetalName + " Override");
				ConfigurationManagerAttributes val2 = new ConfigurationManagerAttributes();
				ConfigEntry<int> val3 = Add(config, slagMetal.Section, slagMetal.AmountKey, 2, num - 1, slagMetal.MetalName + " slag output, used only while " + slagMetal.MetalName + " Override is on. The slider label reads as a trade, ingots to slag: 20 Ingots ➜ 1 Slag at the far left, No Slag in the middle, and 1 Ingot ➜ 20 Slag at the far right. One step either side of the middle is 1 Ingot ➜ 1 Slag.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-20, 20), DrawSlagRatio, slagMetal.MetalName + " Slag Ratio", val2);
				if (!num2 && val3.Value != 2)
				{
					val.Value = true;
				}
				val2.Browsable = val.Value;
				_metals[slagMetal.Id] = val3;
				_overrides[slagMetal.Id] = val;
				_ratioAttributes[slagMetal.Id] = val2;
				SlagMetal tracked = slagMetal;
				val3.SettingChanged += delegate
				{
					SmelterSlagOutput.ResetRatioProgress(tracked);
				};
				val.SettingChanged += delegate
				{
					ShowOverride(tracked);
					SmelterSlagOutput.ResetRatioProgress(tracked);
				};
				num -= 10;
			}
		}

		internal static void ApplyItems()
		{
			if (_allowTeleport == null || PrefabManager.Instance == null)
			{
				return;
			}
			bool value = _allowTeleport.Value;
			SlagMetal[] all = SlagMetals.All;
			foreach (SlagMetal slagMetal in all)
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab(slagMetal.SlagPrefab);
				ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null);
				if (!((Object)(object)val == (Object)null))
				{
					val.m_itemData.m_shared.m_teleportable = value;
				}
			}
		}

		private static void ApplyAll()
		{
			SlagMetal[] all = SlagMetals.All;
			for (int i = 0; i < all.Length; i++)
			{
				ShowOverride(all[i]);
			}
			ApplyItems();
			ShowBlastOverrides();
			SlagCrusherStation.ApplyConfig();
		}

		private static void ShowBlastOverrides()
		{
			bool blastCustomCycle = BlastCustomCycle;
			if (_blastOutputAttrs != null)
			{
				_blastOutputAttrs.Browsable = blastCustomCycle;
			}
			if (_blastCoalAttrs != null)
			{
				_blastCoalAttrs.Browsable = blastCustomCycle;
			}
			if (_blastTimeAttrs != null)
			{
				_blastTimeAttrs.Browsable = blastCustomCycle;
			}
		}

		private static void ResetGlobalRatio()
		{
			SlagMetal[] all = SlagMetals.All;
			foreach (SlagMetal slagMetal in all)
			{
				if (!_overrides.TryGetValue(slagMetal.Id, out var value) || !value.Value)
				{
					SmelterSlagOutput.ResetRatioProgress(slagMetal);
				}
			}
		}

		private static void ShowOverride(SlagMetal metal)
		{
			if (_overrides.TryGetValue(metal.Id, out var value) && _ratioAttributes.TryGetValue(metal.Id, out var value2))
			{
				value2.Browsable = value.Value;
			}
		}

		private static bool ConfigHas(ConfigFile config, string section, string key)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (!(typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(config) is Dictionary<ConfigDefinition, string> dictionary))
			{
				return false;
			}
			return dictionary.ContainsKey(new ConfigDefinition(section, key));
		}

		private static ConfigEntry<T> Add<T>(ConfigFile config, string section, string key, T defaultValue, int order, string description, AcceptableValueBase range = null, Action<ConfigEntryBase> drawer = null, string displayName = null, ConfigurationManagerAttributes attributes = null, string displayCategory = null, bool synced = true)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			if (attributes == null)
			{
				attributes = new ConfigurationManagerAttributes();
			}
			attributes.IsAdminOnly = synced;
			attributes.Category = displayCategory ?? section;
			attributes.Order = order;
			attributes.CustomDrawer = drawer;
			attributes.DispName = displayName;
			return ConfigFileExtensions.BindConfig<T>(config, section, key, defaultValue, description, synced, (int?)order, range, drawer, attributes);
		}

		private static void DrawSlagRatio(ConfigEntryBase entry)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0053: 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_0061: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_009f: 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_00c2: Expected O, but got Unknown
			//IL_00c3: Expected O, but got Unknown
			ConfigEntry<int> val = (ConfigEntry<int>)(object)entry;
			int num = Clamp(val.Value, -20, 20);
			float num2 = GUI.skin.label.lineHeight;
			if (num2 < 1f)
			{
				num2 = 16f;
			}
			GUIStyle label = GUI.skin.label;
			GUIStyle val2 = new GUIStyle(label)
			{
				alignment = (TextAnchor)3,
				wordWrap = false,
				stretchHeight = false,
				stretchWidth = false,
				fixedHeight = num2,
				padding = new RectOffset(label.padding.left, label.padding.right, label.padding.top, label.padding.bottom),
				margin = new RectOffset(label.margin.left, label.margin.right, 0, 0)
			};
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			int num3 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)num, 20f, -20f, (GUILayoutOption[])(object)new GUILayoutOption[3]
			{
				GUILayout.Width(110f),
				GUILayout.ExpandWidth(false),
				GUILayout.Height(num2)
			}));
			GUILayout.Label(RatioText(num3), val2, (GUILayoutOption[])(object)new GUILayoutOption[4]
			{
				GUILayout.Width(150f),
				GUILayout.Height(num2),
				GUILayout.ExpandHeight(false),
				GUILayout.ExpandWidth(false)
			});
			GUILayout.EndHorizontal();
			if (num3 != val.Value)
			{
				Debounce(entry, num3);
			}
			TryFlushDebounce();
		}

		private static string RatioText(int value)
		{
			if (value == 0)
			{
				return "No Slag";
			}
			if (value < 0)
			{
				return "1 Ingot ➜ " + (-value).ToString(CultureInfo.InvariantCulture) + " Slag";
			}
			if (value == 1)
			{
				return "1 Ingot ➜ 1 Slag";
			}
			return value + " Ingots ➜ 1 Slag";
		}

		private static void DrawCrusherOutput(ConfigEntryBase entry)
		{
			//IL_003f: 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)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_009e: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_00c2: Expected O, but got Unknown
			ConfigEntry<int> val = (ConfigEntry<int>)(object)entry;
			int num = Clamp(val.Value, -5, 5);
			float num2 = GUI.skin.label.lineHeight;
			if (num2 < 1f)
			{
				num2 = 16f;
			}
			GUIStyle label = GUI.skin.label;
			GUIStyle val2 = new GUIStyle(label)
			{
				alignment = (TextAnchor)3,
				wordWrap = false,
				stretchHeight = false,
				stretchWidth = false,
				fixedHeight = num2,
				padding = new RectOffset(label.padding.left, label.padding.right, label.padding.top, label.padding.bottom),
				margin = new RectOffset(label.margin.left, label.margin.right, 0, 0)
			};
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			int num3 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)num, 5f, -5f, (GUILayoutOption[])(object)new GUILayoutOption[3]
			{
				GUILayout.Width(110f),
				GUILayout.ExpandWidth(false),
				GUILayout.Height(num2)
			}));
			GUILayout.Label(CrusherText(num3), val2, (GUILayoutOption[])(object)new GUILayoutOption[4]
			{
				GUILayout.Width(150f),
				GUILayout.Height(num2),
				GUILayout.ExpandHeight(false),
				GUILayout.ExpandWidth(false)
			});
			GUILayout.EndHorizontal();
			if (num3 != val.Value)
			{
				Debounce(entry, num3);
			}
			TryFlushDebounce();
		}

		private static string CrusherText(int value)
		{
			if (value < 0)
			{
				return -value + " Slag ➜ 1 Ingot";
			}
			if (value > 1)
			{
				return "1 Slag ➜ " + value + " Ingots";
			}
			return "1 Slag ➜ 1 Ingot";
		}

		private static void Watch<T>(ConfigEntry<T> entry)
		{
			entry.SettingChanged += delegate
			{
				ApplyAll();
			};
		}

		private static bool TryRequiredStation(bool blast, out CraftingStation station, out string error)
		{
			station = null;
			error = null;
			ConfigEntry<string> val = (blast ? _blastRequiredStation : _requiredStation);
			string name = (blast ? DefaultBlastStation : DefaultStation);
			string text = (blast ? "Blast Crusher" : "Slag Crusher");
			string text2 = ((val != null && val.Value != null) ? val.Value.Trim() : "");
			if (text2.Length == 0 || CraftingStations.GetInternalName(text2).Length == 0)
			{
				return true;
			}
			station = FindStation(text2);
			if ((Object)(object)station != (Object)null)
			{
				return true;
			}
			error = text + " required station \"" + text2 + "\" was not found.";
			CraftingStation val2 = FindStation(name);
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			Report(error + " Using the default station.");
			station = val2;
			error = null;
			return true;
		}

		private static CraftingStation FindStation(string name)
		{
			string internalName = CraftingStations.GetInternalName(name);
			if (string.IsNullOrEmpty(internalName) || PrefabManager.Instance == null)
			{
				return null;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab(internalName);
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			CraftingStation component = prefab.GetComponent<CraftingStation>();
			if (!((Object)(object)component != (Object)null))
			{
				return prefab.GetComponentInChildren<CraftingStation>(true);
			}
			return component;
		}

		private static List<RequirementConfig> Requirements(bool blast, out string error)
		{
			ConfigEntry<string> val = (blast ? _blastCraftingRecipe : _craftingRecipe);
			string text = (blast ? "Stone:20,SurtlingCore:7,Iron:20,FineWood:20" : "Stone:20,SurtlingCore:7,Bronze:20,RoundLog:5");
			string label = (blast ? "Blast Crusher" : "Slag Crusher");
			if (TryPairs(val.Value, label, out var pairs, out error))
			{
				return ToConfigs(pairs);
			}
			if (val.Value != text && TryPairs(text, label, out pairs, out var _))
			{
				Report(error + " Using the default recipe.");
				return ToConfigs(pairs);
			}
			return null;
		}

		private static Requirement[] Resolve(List<RequirementConfig> requirements, string label, out string error)
		{
			//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)
			//IL_006b: 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_0085: Expected O, but got Unknown
			Requirement[] array = (Requirement[])(object)new Requirement[requirements.Count];
			for (int i = 0; i < requirements.Count; i++)
			{
				string item = requirements[i].Item;
				GameObject prefab = PrefabManager.Instance.GetPrefab(item);
				ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val == (Object)null)
				{
					error = label + " crafting recipe item \"" + item + "\" was not found.";
					return null;
				}
				array[i] = new Requirement
				{
					m_resItem = val,
					m_amount = requirements[i].Amount,
					m_recover = true
				};
			}
			error = null;
			return array;
		}

		private static List<RequirementConfig> ToConfigs(List<KeyValuePair<string, int>> pairs)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			List<RequirementConfig> list = new List<RequirementConfig>(pairs.Count);
			foreach (KeyValuePair<string, int> pair in pairs)
			{
				list.Add(new RequirementConfig(pair.Key, pair.Value, 1, true));
			}
			return list;
		}

		private static bool TryPairs(string text, string label, out List<KeyValuePair<string, int>> pairs, out string error)
		{
			pairs = null;
			error = null;
			if (string.IsNullOrWhiteSpace(text))
			{
				error = label + " crafting recipe is empty.";
				return false;
			}
			List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>();
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			string[] array = text.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length != 0)
				{
					int num = text2.IndexOf(':');
					if (num <= 0 || num >= text2.Length - 1)
					{
						error = label + " crafting recipe entry \"" + text2 + "\" is invalid. Use PrefabName:amount.";
						return false;
					}
					string text3 = text2.Substring(0, num).Trim();
					if (!int.TryParse(text2.Substring(num + 1).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result < 1)
					{
						error = label + " crafting recipe amount for " + text3 + " must be a positive whole number.";
						return false;
					}
					if (dictionary.TryGetValue(text3, out var value))
					{
						KeyValuePair<string, int> keyValuePair = list[value];
						list[value] = new KeyValuePair<string, int>(text3, keyValuePair.Value + result);
					}
					else
					{
						dictionary.Add(text3, list.Count);
						list.Add(new KeyValuePair<string, int>(text3, result));
					}
				}
			}
			if (list.Count == 0)
			{
				error = label + " crafting recipe did not contain any items.";
				return false;
			}
			pairs = list;
			return true;
		}

		private static void Report(string message)
		{
			if (!string.IsNullOrEmpty(message) && !(_configError == message))
			{
				_configError = message;
				Plugin.Instance.LogWarning(message);
			}
		}

		private static int Clamp(int value, int min, int max)
		{
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}

		private static void Debounce(ConfigEntryBase entry, int value)
		{
			_debounceEntry = entry;
			_debounceValue = value;
			_debounceDeadline = Time.time + DebounceSeconds;
		}

		private static void TryFlushDebounce()
		{
			if (_debounceEntry != null && !(Time.time < _debounceDeadline))
			{
				((ConfigEntry<int>)(object)_debounceEntry).Value = _debounceValue;
				_debounceEntry = null;
			}
		}
	}
	[BepInPlugin("slagcrusher", "Slag Crusher", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "slagcrusher";

		public const string ModName = "Slag Crusher";

		public const string ModVersion = "1.0.1";

		internal static Plugin Instance { get; private set; }

		internal void LogVerbose(string message)
		{
			if (ModConfig.VerboseLogging)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)message);
			}
		}

		internal void LogWarning(string message)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)message);
		}

		private void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			AddLocalizations();
			new Harmony("slagcrusher").PatchAll(typeof(Plugin).Assembly);
			PrefabManager.OnVanillaPrefabsAvailable += RegisterContent;
			LogVerbose("Slag items, the Slag Crusher, and the Blast Crusher will register when vanilla prefabs load.");
		}

		private static void AddLocalizations()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			SlagMetal[] all = SlagMetals.All;
			string text;
			foreach (SlagMetal slagMetal in all)
			{
				text = "English";
				localization.AddTranslation(ref text, ref slagMetal.NameToken, slagMetal.DisplayName);
				text = "English";
				localization.AddTranslation(ref text, ref slagMetal.DescriptionToken, slagMetal.Description);
			}
			text = "English";
			string text2 = "$slagcrusher_station";
			localization.AddTranslation(ref text, ref text2, "Slag Crusher");
			text = "English";
			text2 = "$slagcrusher_blaststation";
			localization.AddTranslation(ref text, ref text2, "Blast Crusher");
		}

		private static void RegisterContent()
		{
			if (SlagItems.Register() && SlagCrusherStation.Register())
			{
				ModConfig.ApplyItems();
				PrefabManager.OnVanillaPrefabsAvailable -= RegisterContent;
			}
		}
	}
	internal sealed class CrusherDefinition
	{
		internal string PrefabName;

		internal string SourcePrefab;

		internal string NameToken;

		internal string Description;

		internal string DisplayName;

		internal string ModelPrefix;

		internal string MetalStation;

		internal bool Blast;

		internal GameObject Prefab;

		internal bool PieceAdded;

		internal bool ConversionsAdded;

		internal bool Registered;
	}
	internal static class SlagCrusherStation
	{
		internal const string PrefabName = "piece_slagcrusher";

		internal const string BlastPrefabName = "piece_blastcrusher";

		private static readonly CrusherDefinition[] All = new CrusherDefinition[2]
		{
			new CrusherDefinition
			{
				PrefabName = "piece_slagcrusher",
				SourcePrefab = "smelter",
				NameToken = "$slagcrusher_station",
				Description = "Crushes Smelter slag back into ingots.",
				DisplayName = "Slag Crusher",
				ModelPrefix = "slagcrusher",
				MetalStation = "smelter",
				Blast = false
			},
			new CrusherDefinition
			{
				PrefabName = "piece_blastcrusher",
				SourcePrefab = "blastfurnace",
				NameToken = "$slagcrusher_blaststation",
				Description = "Crushes Blast Furnace slag back into ingots.",
				DisplayName = "Blast Crusher",
				ModelPrefix = "blastcrusher",
				MetalStation = "blastfurnace",
				Blast = true
			}
		};

		private static bool _hooked;

		internal static int FuelCapacity { get; private set; } = 20;

		internal static bool Register()
		{
			bool flag = true;
			CrusherDefinition[] all = All;
			foreach (CrusherDefinition station in all)
			{
				flag &= RegisterOne(station);
			}
			if (flag)
			{
				Hook();
			}
			return flag;
		}

		private static bool RegisterOne(CrusherDefinition station)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Expected O, but got Unknown
			if (station.Registered)
			{
				return true;
			}
			GameObject orCreate = GetOrCreate(station);
			if ((Object)(object)orCreate == (Object)null)
			{
				return false;
			}
			if (!station.PieceAdded)
			{
				PieceConfig val = new PieceConfig
				{
					Name = station.NameToken,
					Description = station.Description,
					PieceTable = PieceTables.Hammer,
					Category = "Crafting"
				};
				ModConfig.AddRequirements(val, station.Blast);
				if (!PieceManager.Instance.AddPiece(new CustomPiece(orCreate, true, val)))
				{
					Plugin.Instance.LogWarning(station.DisplayName + " was not added to the hammer.");
					return false;
				}
				station.PieceAdded = true;
				Piece component = orCreate.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					component.m_groundOnly = false;
					component.m_groundPiece = false;
					component.m_clipGround = true;
					component.m_clipEverything = false;
					component.m_noClipping = true;
					component.m_notOnWood = true;
					component.m_noInWater = true;
				}
			}
			if (!station.ConversionsAdded)
			{
				SlagMetal[] all = SlagMetals.All;
				foreach (SlagMetal slagMetal in all)
				{
					if (!(slagMetal.Station != station.MetalStation) && !((Object)(object)PrefabManager.Instance.GetPrefab(slagMetal.SlagPrefab) == (Object)null))
					{
						SmelterConversionConfig val2 = new SmelterConversionConfig
						{
							Station = station.PrefabName,
							FromItem = slagMetal.SlagPrefab,
							ToItem = slagMetal.OutputItem
						};
						if (!ItemManager.Instance.AddItemConversion(new CustomItemConversion((ConversionConfig)(object)val2)))
						{
							Plugin.Instance.LogWarning(slagMetal.DisplayName + " conversion was not added to " + station.DisplayName + ".");
						}
					}
				}
				station.ConversionsAdded = true;
			}
			station.Registered = true;
			ApplyConfig();
			Plugin.Instance.LogVerbose("Registered station " + station.PrefabName + ".");
			return true;
		}

		private static void Hook()
		{
			if (!_hooked)
			{
				PieceManager.OnPiecesRegistered += ApplyConfig;
				_hooked = true;
			}
		}

		private static GameObject GetOrCreate(CrusherDefinition station)
		{
			if ((Object)(object)station.Prefab != (Object)null)
			{
				return station.Prefab;
			}
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(station.PrefabName, station.SourcePrefab);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Instance.LogWarning(station.DisplayName + " not registered. The " + station.SourcePrefab + " prefab was missing.");
				return null;
			}
			val.SetActive(true);
			Smelter component = val.GetComponent<Smelter>();
			component.m_name = station.NameToken;
			if (component.m_maxFuel > 0)
			{
				FuelCapacity = component.m_maxFuel;
			}
			component.m_conversion = new List<ItemConversion>();
			Piece component2 = val.GetComponent<Piece>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.m_icon = LoadPieceIcon(station.Blast ? "blast-crusher.png" : "slag-crusher.png");
			}
			StationModel.Attach(val, station.ModelPrefix);
			station.Prefab = val;
			CrusherSmelt.Bind(station.PrefabName);
			return station.Prefab;
		}

		private static Sprite LoadPieceIcon(string resourceName)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = MeshFile.LoadTexture(resourceName, linear: false);
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
			((Object)obj).name = resourceName;
			return obj;
		}

		internal static void ApplyConfig()
		{
			CrusherDefinition[] all = All;
			foreach (CrusherDefinition crusherDefinition in all)
			{
				if ((Object)(object)crusherDefinition.Prefab != (Object)null)
				{
					ModConfig.ApplyTo(crusherDefinition.Prefab);
				}
				SyncLowerTierConversions(((Object)(object)crusherDefinition.Prefab != (Object)null) ? crusherDefinition.Prefab.GetComponent<Smelter>() : null);
			}
			Smelter[] array = Object.FindObjectsByType<Smelter>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			foreach (Smelter val in array)
			{
				if (!((Object)(object)val == (Object)null) && !IsTemplate(((Component)val).gameObject) && CrusherSmelt.IsCrusher(val))
				{
					ModConfig.ApplyTo(((Component)val).gameObject);
					SyncLowerTierConversions(val);
				}
			}
		}

		private static void SyncLowerTierConversions(Smelter smelter)
		{
			//IL_00ad: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			if ((Object)(object)smelter == (Object)null || smelter.m_conversion == null || !CrusherSmelt.IsBlast(smelter))
			{
				return;
			}
			bool smelterCompatibility = ModConfig.SmelterCompatibility;
			SlagMetal[] all = SlagMetals.All;
			foreach (SlagMetal slagMetal in all)
			{
				if (slagMetal.Station != "smelter")
				{
					continue;
				}
				ItemDrop from = Drop(slagMetal.SlagPrefab);
				ItemDrop val = Drop(slagMetal.OutputItem);
				if ((Object)(object)from == (Object)null || (Object)(object)val == (Object)null)
				{
					continue;
				}
				int num = smelter.m_conversion.FindIndex((ItemConversion c) => c != null && (Object)(object)c.m_from == (Object)(object)from);
				if (smelterCompatibility)
				{
					if (num < 0)
					{
						smelter.m_conversion.Add(new ItemConversion
						{
							m_from = from,
							m_to = val
						});
					}
				}
				else if (num >= 0)
				{
					smelter.m_conversion.RemoveAt(num);
				}
			}
		}

		private static ItemDrop Drop(string prefabName)
		{
			GameObject val = ((PrefabManager.Instance != null) ? PrefabManager.Instance.GetPrefab(prefabName) : null);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<ItemDrop>();
		}

		private static bool IsTemplate(GameObject piece)
		{
			CrusherDefinition[] all = All;
			for (int i = 0; i < all.Length; i++)
			{
				if ((Object)(object)all[i].Prefab == (Object)(object)piece)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class CrusherSmelt
	{
		private static readonly HashSet<string> _names = new HashSet<string>();

		private static bool _patched;

		private static bool _removingExtra;

		private static MethodInfo _removeOneOre;

		private static FieldInfo _nview;

		private static Func<Smelter, int> _queueSize;

		private static bool _queueUnread;

		private static readonly HashSet<int> _inUpdate = new HashSet<int>();

		internal static void Bind(string prefabName)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Expected O, but got Unknown
			//IL_0145: Expected O, but got Unknown
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Expected O, but got Unknown
			_names.Add(prefabName);
			if (!_patched)
			{
				_patched = true;
				Harmony val = new Harmony("slagcrusher.smelt");
				MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Smelter), "GetQueuedOre", new Type[0], (Type[])null);
				if (methodInfo == null)
				{
					methodInfo = AccessTools.DeclaredMethod(typeof(Smelter), "GetQueuedOre", (Type[])null, (Type[])null);
				}
				MethodInfo methodInfo2 = (_removeOneOre = AccessTools.DeclaredMethod(typeof(Smelter), "RemoveOneOre", (Type[])null, (Type[])null));
				_nview = AccessTools.Field(typeof(Smelter), "m_nview");
				MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null);
				if (methodInfo3 != null)
				{
					_queueSize = AccessTools.MethodDelegate<Func<Smelter, int>>(methodInfo3, (object)null, true);
				}
				if (methodInfo != null)
				{
					val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(CrusherSmelt), "HideSingleSlagFromCook", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo4 = AccessTools.DeclaredMethod(typeof(Smelter), "UpdateSmelter", (Type[])null, (Type[])null);
				if (methodInfo4 != null)
				{
					val.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(CrusherSmelt), "BeginUpdate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(CrusherSmelt), "EndUpdate", (Type[])null), (HarmonyMethod)null);
				}
				else
				{
					Plugin.Instance.LogWarning("Smelter.UpdateSmelter was not found. Crusher queue logic will not run.");
				}
				if (methodInfo2 != null)
				{
					val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(CrusherSmelt), "ConsumeExtraSlag", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				else
				{
					Plugin.Instance.LogWarning("Smelter.RemoveOneOre was not found. The crusher will consume one slag.");
				}
			}
		}

		internal static bool IsCrusher(Smelter smelter)
		{
			if ((Object)(object)smelter == (Object)null)
			{
				return false;
			}
			return _names.Contains(((Object)((Component)smelter).gameObject).name.Replace("(Clone)", ""));
		}

		internal static bool IsBlast(Smelter smelter)
		{
			if ((Object)(object)smelter == (Object)null)
			{
				return false;
			}
			return ((Object)((Component)smelter).gameObject).name.Replace("(Clone)", "") == "piece_blastcrusher";
		}

		private static int QueueCount(Smelter smelter)
		{
			if (_queueSize == null)
			{
				return 0;
			}
			return _queueSize(smelter);
		}

		private static int CountLeading(Smelter smelter, string ore)
		{
			ZNetView val = (ZNetView)((_nview != null) ? /*isinst with value type is only supported in some contexts*/: null);
			ZDO val2 = (((Object)(object)val != (Object)null) ? val.GetZDO() : null);
			if (val2 == null)
			{
				return QueueCount(smelter);
			}
			int num = QueueCount(smelter);
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				string text = val2.GetString("item" + i, "");
				if (text.Length == 0)
				{
					WarnQueueUnread();
					return QueueCount(smelter);
				}
				if (text != ore)
				{
					break;
				}
				num2++;
			}
			return num2;
		}

		private static void WarnQueueUnread()
		{
			if (!_queueUnread)
			{
				_queueUnread = true;
				Plugin.Instance.LogWarning("Could not read the crusher ore queue. Mixed slag will share one cycle.");
			}
		}

		private static bool CalledFromSmelterUpdate(Smelter smelter)
		{
			return _inUpdate.Contains(((Object)smelter).GetInstanceID());
		}

		private static void BeginUpdate(Smelter __instance)
		{
			if (IsCrusher(__instance))
			{
				_inUpdate.Add(((Object)__instance).GetInstanceID());
			}
		}

		private static void EndUpdate(Smelter __instance)
		{
			_inUpdate.Remove(((Object)__instance).GetInstanceID());
		}

		private static void HideSingleSlagFromCook(Smelter __instance, ref string __result)
		{
			if (!_removingExtra && IsCrusher(__instance) && CalledFromSmelterUpdate(__instance) && !string.IsNullOrEmpty(__result))
			{
				int num = ModConfig.CrusherSlagPerCycle(IsBlast(__instance));
				if (CountLeading(__instance, __result) < num)
				{
					__result = "";
				}
			}
		}

		private static void ConsumeExtraSlag(Smelter __instance)
		{
			if (_removingExtra || _removeOneOre == null || !IsCrusher(__instance) || !CalledFromSmelterUpdate(__instance))
			{
				return;
			}
			int num = ModConfig.CrusherSlagPerCycle(IsBlast(__instance)) - 1;
			if (num <= 0)
			{
				return;
			}
			_removingExtra = true;
			try
			{
				for (int i = 0; i < num; i++)
				{
					if (QueueCount(__instance) < 1)
					{
						break;
					}
					_removeOneOre.Invoke(__instance, null);
				}
			}
			finally
			{
				_removingExtra = false;
			}
		}
	}
	[HarmonyPatch(typeof(Smelter), "Spawn", new Type[]
	{
		typeof(string),
		typeof(int)
	})]
	internal static class CrusherIngotOutput
	{
		private static void Prefix(Smelter __instance, string ore, ref int stack, out int __state)
		{
			__state = 0;
			if (CrusherSmelt.IsCrusher(__instance))
			{
				int num = ModConfig.CrusherIngotsPerCycle(CrusherSmelt.IsBlast(__instance));
				int num2 = OutputMaxStack(__instance, ore);
				__state = num - (stack = ((num < num2) ? num : num2));
			}
		}

		private static void Postfix(Smelter __instance, string ore, int __state)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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)
			if (!CrusherSmelt.IsCrusher(__instance) || __state <= 0 || (Object)(object)__instance.m_outputPoint == (Object)null)
			{
				return;
			}
			ItemDrop val = Output(__instance, ore);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			int num = val.m_itemData.m_shared.m_maxStackSize;
			if (num < 1)
			{
				num = 1;
			}
			int num2 = __state;
			while (num2 > 0)
			{
				int num3 = ((num2 > num) ? num : num2);
				GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, __instance.m_outputPoint.position, __instance.m_outputPoint.rotation);
				if (val2.scene != ((Component)__instance).gameObject.scene)
				{
					SceneManager.MoveGameObjectToScene(val2, ((Component)__instance).gameObject.scene);
				}
				ItemDrop component = val2.GetComponent<ItemDrop>();
				if ((Object)(object)component != (Object)null)
				{
					component.m_itemData.m_stack = num3;
					ItemDrop.OnCreateNew(component, false);
				}
				num2 -= num3;
			}
		}

		private static int OutputMaxStack(Smelter smelter, string ore)
		{
			ItemDrop val = Output(smelter, ore);
			if ((Object)(object)val == (Object)null || val.m_itemData.m_shared.m_maxStackSize < 1)
			{
				return 1;
			}
			return val.m_itemData.m_shared.m_maxStackSize;
		}

		private static ItemDrop Output(Smelter smelter, string ore)
		{
			if (smelter.m_conversion == null)
			{
				return null;
			}
			foreach (ItemConversion item in smelter.m_conversion)
			{
				if (item != null && !((Object)(object)item.m_from == (Object)null) && !((Object)(object)item.m_to == (Object)null) && ((Object)((Component)item.m_from).gameObject).name.Replace("(Clone)", "") == ore)
				{
					return item.m_to;
				}
			}
			return null;
		}
	}
	internal static class SlagItems
	{
		private static bool _registered;

		internal static bool Register()
		{
			if (_registered)
			{
				return true;
			}
			if (!IronSlagItem.Register())
			{
				return false;
			}
			Color[] pixels = IronSlagItem.Icon.texture.GetPixels();
			int width = ((Texture)IronSlagItem.Icon.texture).width;
			int height = ((Texture)IronSlagItem.Icon.texture).height;
			float pixelsPerUnit = IronSlagItem.Icon.pixelsPerUnit;
			float reference = ReferenceLevel(pixels);
			SlagMetal[] all = SlagMetals.All;
			foreach (SlagMetal slagMetal in all)
			{
				Sprite icon = Colorize(pixels, width, height, pixelsPerUnit, reference, slagMetal);
				if (slagMetal.UsesIronArt)
				{
					IronSlagItem.SetIcon(icon);
				}
				else
				{
					RegisterCopy(slagMetal, icon);
				}
			}
			_registered = true;
			return true;
		}

		private static void RegisterCopy(SlagMetal metal, Sprite icon)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(metal.SlagPrefab, "IronSlag");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Instance.LogWarning(metal.DisplayName + " was not created.");
				return;
			}
			val.SetActive(true);
			ItemDrop component = val.GetComponent<ItemDrop>();
			component.m_itemData.m_dropPrefab = val;
			SharedData shared = component.m_itemData.m_shared;
			shared.m_name = metal.NameToken;
			shared.m_description = metal.DescriptionToken;
			TintRenderers(val, metal);
			shared.m_icons = (Sprite[])(object)new Sprite[1] { icon };
			if (!ItemManager.Instance.AddItem(new CustomItem(val, false)))
			{
				Plugin.Instance.LogWarning(metal.DisplayName + " was not added.");
			}
		}

		private static void TintRenderers(GameObject prefab, SlagMetal metal)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] materials = ((Renderer)componentsInChildren[i]).materials;
				for (int j = 0; j < materials.Length; j++)
				{
					if (!((Object)(object)materials[j] == (Object)null) && materials[j].HasProperty("_Color"))
					{
						((Object)materials[j]).name = metal.SlagPrefab;
						materials[j].SetColor("_Color", metal.Tint);
					}
				}
			}
		}

		private static float ReferenceLevel(Color[] pixels)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			for (int i = 0; i < pixels.Length; i++)
			{
				if (pixels[i].a > 0.0627451f)
				{
					num++;
				}
			}
			float[] array = new float[num];
			int num2 = 0;
			for (int j = 0; j < pixels.Length; j++)
			{
				if (!(pixels[j].a <= 0.0627451f))
				{
					array[num2++] = Luma(pixels[j]);
				}
			}
			if (array.Length == 0)
			{
				return 1f;
			}
			Array.Sort(array);
			float num3 = array[array.Length / 2];
			if (!(num3 > 0.003921569f))
			{
				return 0.003921569f;
			}
			return num3;
		}

		private static Sprite Colorize(Color[] source, int width, int height, float pixelsPerUnit, float reference, SlagMetal metal)
		{
			//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_02f9: 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_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			Color[] array = (Color[])(object)new Color[source.Length];
			for (int i = 0; i < source.Length; i++)
			{
				Color val = source[i];
				if (val.a != 0f)
				{
					float num = Luma(val);
					float num2 = Mathf.Clamp(num / reference, 0f, 4f);
					float num3 = metal.Primary.r * num2;
					float num4 = metal.Primary.g * num2;
					float num5 = metal.Primary.b * num2;
					float num6 = metal.Accent.r;
					float num7 = metal.Accent.g;
					float num8 = metal.Accent.b;
					if (metal.Accent2.a > 0f)
					{
						float num9 = val.r / (val.r + val.b + 0.003921569f);
						num6 = metal.Accent.r * (1f - num9) + metal.Accent2.r * num9;
						num7 = metal.Accent.g * (1f - num9) + metal.Accent2.g * num9;
						num8 = metal.Accent.b * (1f - num9) + metal.Accent2.b * num9;
					}
					float num10 = Smooth(0.45f, 0.8f, num2) * (1f - Smooth(1.05f, 1.4f, num2)) * metal.AccentAmount;
					num3 = num3 * (1f - num10) + num6 * num2 * num10;
					num4 = num4 * (1f - num10) + num7 * num2 * num10;
					num5 = num5 * (1f - num10) + num8 * num2 * num10;
					float num11 = ((metal.SlagPrefab == "BlackMetalSlag") ? 1f : 0.8f);
					num3 *= num11;
					num4 *= num11;
					num5 *= num11;
					float start;
					float end;
					switch (metal.SlagPrefab)
					{
					case "BlackMetalSlag":
						start = 0.36f;
						end = 0.76f;
						break;
					case "IronSlag":
					case "FlametalSlag":
						start = 0.46f;
						end = 0.82f;
						break;
					default:
						start = 0.78f;
						end = 0.96f;
						break;
					}
					float num12 = Smooth(start, end, num) * metal.HighlightAmount;
					num3 = num3 * (1f - num12) + metal.Highlight.r * num12;
					num4 = num4 * (1f - num12) + metal.Highlight.g * num12;
					num5 = num5 * (1f - num12) + metal.Highlight.b * num12;
					array[i] = new Color(Clamp01(num3), Clamp01(num4), Clamp01(num5), val.a);
				}
			}
			Texture2D val2 = new Texture2D(width, height, (TextureFormat)4, false)
			{
				name = metal.SlagPrefab + "-icon",
				wrapMode = (TextureWrapMode)1
			};
			val2.SetPixels(array);
			val2.Apply();
			return Sprite.Create(val2, new Rect(0f, 0f, (float)width, (float)height), new Vector2(0.5f, 0.5f), pixelsPerUnit, 0u, (SpriteMeshType)0);
		}

		private static float Luma(Color color)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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)
			return 0.299f * color.r + 0.587f * color.g + 0.114f * color.b;
		}

		private static float Smooth(float start, float end, float value)
		{
			float num = (value - start) / (end - start);
			if (num < 0f)
			{
				num = 0f;
			}
			else if (num > 1f)
			{
				num = 1f;
			}
			return num * num * (3f - 2f * num);
		}

		private static float Clamp01(float value)
		{
			if (value < 0f)
			{
				return 0f;
			}
			if (value > 1f)
			{
				return 1f;
			}
			return value;
		}
	}
	internal sealed class SlagMetal
	{
		internal string Station;

		internal string Section;

		internal string OutputItem;

		internal string SlagPrefab;

		internal string MetalName;

		internal string NameToken;

		internal string DescriptionToken;

		internal string DisplayName;

		internal string Description;

		internal Color Tint = Color.white;

		internal Color Primary = Color.white;

		internal Color Accent = Color.black;

		internal Color Accent2 = Color.clear;

		internal float AccentAmount;

		internal Color Highlight = Color.white;

		internal float HighlightAmount = 0.75f;

		internal string AmountKey;

		internal string SourceItem;

		internal string Id => Station + "." + OutputItem;

		internal bool UsesIronArt => SlagPrefab == "IronSlag";
	}
	internal static class SlagMetals
	{
		internal const string Smelter = "smelter";

		internal const string BlastFurnace = "blastfurnace";

		internal static readonly SlagMetal[] All;

		static SlagMetals()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			All = new SlagMetal[8]
			{
				SmelterMetal("Copper", "CopperSlag", "$slagcrusher_copperslag", new Color(1f, 0.636f, 0.443f)),
				SmelterMetal("Tin", "TinSlag", "$slagcrusher_tinslag", new Color(0.988f, 0.988f, 1f)),
				SmelterMetal("Bronze", "BronzeSlag", "$slagcrusher_bronzeslag", new Color(1f, 0.786f, 0.398f)),
				SmelterMetal("Iron", "IronSlag", "$slagcrusher_ironslag", Color.white, "Slag per iron ingot"),
				SmelterMetal("Silver", "SilverSlag", "$slagcrusher_silverslag", new Color(0.949f, 0.969f, 1f)),
				BlastFurnaceMetal("Black Metal", "BlackMetal", "BlackMetalSlag", "$slagcrusher_blackmetalslag", new Color(0.25f, 0.55f, 0.28f)),
				BlastFurnaceMetal("Flametal", "Flametal", "FlametalSlag", "$slagcrusher_flametalslag", new Color(0.716f, 0.866f, 1f), "FlametalOreNew"),
				BlastFurnaceMetal("Bloodgold", "Gold", "BloodgoldSlag", "$slagcrusher_bloodgoldslag", new Color(1f, 0.805f, 0.331f))
			};
			SlagMetal[] all = All;
			for (int i = 0; i < all.Length; i++)
			{
				ApplyIcon(all[i]);
			}
		}

		private static Color Rgb(int r, int g, int b)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			return new Color((float)r / 255f, (float)g / 255f, (float)b / 255f, 1f);
		}

		private static void ApplyIcon(SlagMetal metal)
		{
			//IL_0130: 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_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			string slagPrefab = metal.SlagPrefab;
			if (slagPrefab == null)
			{
				return;
			}
			switch (slagPrefab.Length)
			{
			case 10:
				switch (slagPrefab[0])
				{
				case 'C':
					if (slagPrefab == "CopperSlag")
					{
						Icon(metal, Rgb(176, 112, 78), Rgb(214, 120, 58), Color.clear, 0.42f, Rgb(255, 214, 176), 0.72f);
					}
					break;
				case 'B':
					if (slagPrefab == "BronzeSlag")
					{
						Icon(metal, Rgb(200, 168, 108), Rgb(168, 112, 56), Color.clear, 0.28f, Rgb(255, 236, 196), 0.74f);
					}
					break;
				case 'S':
					if (slagPrefab == "SilverSlag")
					{
						Icon(metal, Rgb(186, 190, 196), Rgb(170, 178, 190), Color.clear, 0.16f, Rgb(255, 255, 255), 0.78f);
					}
					break;
				}
				break;
			case 7:
				if (slagPrefab == "TinSlag")
				{
					Icon(metal, Rgb(168, 168, 170), Rgb(146, 156, 170), Color.clear, 0.2f, Rgb(244, 244, 246), 0.7f);
				}
				break;
			case 8:
				if (slagPrefab == "IronSlag")
				{
					Icon(metal, Rgb(78, 96, 112), Rgb(58, 74, 98), Color.clear, 0.22f, Rgb(236, 244, 255), 1f);
				}
				break;
			case 14:
				if (slagPrefab == "BlackMetalSlag")
				{
					Icon(metal, Rgb(14, 16, 16), Rgb(22, 64, 26), Color.clear, 0.62f, Rgb(210, 255, 210), 1f);
				}
				break;
			case 12:
				if (slagPrefab == "FlametalSlag")
				{
					Icon(metal, Rgb(96, 116, 134), Rgb(214, 92, 40), Rgb(70, 170, 214), 0.5f, Rgb(255, 248, 255), 1f);
				}
				break;
			case 13:
				if (slagPrefab == "BloodgoldSlag")
				{
					Icon(metal, Rgb(228, 168, 58), Rgb(214, 52, 22), Color.clear, 0.58f, Rgb(255, 214, 160), 0.74f);
				}
				break;
			case 9:
			case 11:
				break;
			}
		}

		private static void Icon(SlagMetal metal, Color primary, Color accent, Color accent2, float accentAmount, Color highlight, float highlightAmount)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0010: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			metal.Primary = primary;
			metal.Accent = accent;
			metal.Accent2 = accent2;
			metal.AccentAmount = accentAmount;
			metal.Highlight = highlight;
			metal.HighlightAmount = highlightAmount;
		}

		internal static SlagMetal Find(Smelter smelter, string outputItem, string ore = null)
		{
			string text = StationOf(smelter);
			SlagMetal[] all;
			if (!string.IsNullOrEmpty(ore))
			{
				all = All;
				foreach (SlagMetal slagMetal in all)
				{
					if (slagMetal.Station == text && slagMetal.SourceItem == ore)
					{
						return slagMetal;
					}
				}
			}
			if (string.IsNullOrEmpty(outputItem))
			{
				return null;
			}
			all = All;
			foreach (SlagMetal slagMetal2 in all)
			{
				if (slagMetal2.Station == text && slagMetal2.OutputItem == outputItem)
				{
					return slagMetal2;
				}
			}
			if (text != "blastfurnace")
			{
				return null;
			}
			all = All;
			foreach (SlagMetal slagMetal3 in all)
			{
				if (slagMetal3.Station == "smelter" && slagMetal3.OutputItem == outputItem)
				{
					return slagMetal3;
				}
			}
			return null;
		}

		private static string StationOf(Smelter smelter)
		{
			if (!(((Object)((Component)smelter).gameObject).name.Replace("(Clone)", "") == "blastfurnace"))
			{
				return "smelter";
			}
			return "blastfurnace";
		}

		private static SlagMetal SmelterMetal(string metalName, string slagPrefab, string nameToken, Color tint, string amountKey = null)
		{
			//IL_0093: 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)
			string text = metalName.ToLowerInvariant();
			SlagMetal slagMetal = new SlagMetal();
			slagMetal.Station = "smelter";
			slagMetal.Section = "Slag Output - Smelter Overrides";
			slagMetal.OutputItem = metalName;
			slagMetal.SlagPrefab = slagPrefab;
			slagMetal.MetalName = metalName;
			slagMetal.NameToken = nameToken;
			slagMetal.DescriptionToken = nameToken + "_desc";
			slagMetal.DisplayName = metalName + " Slag";
			slagMetal.Description = "A lump of waste " + text + " that can be refined into " + text + " ingots using a Slag Crusher.";
			slagMetal.Tint = tint;
			slagMetal.AmountKey = amountKey ?? (metalName + " slag per ingot");
			return slagMetal;
		}

		private static SlagMetal BlastFurnaceMetal(string metalName, string outputItem, string slagPrefab, string nameToken, Color tint, string sourceItem = null, string amountKey = null)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			string text = metalName.ToLowerInvariant();
			SlagMetal slagMetal = new SlagMetal();
			slagMetal.Station = "blastfurnace";
			slagMetal.Section = "Slag Output - Blast Furnace Overrides";
			slagMetal.OutputItem = outputItem;
			slagMetal.SlagPrefab = slagPrefab;
			slagMetal.MetalName = metalName;
			slagMetal.NameToken = nameToken;
			slagMetal.DescriptionToken = nameToken + "_desc";
			slagMetal.DisplayName = metalName + " Slag";
			slagMetal.Description = "A lump of waste " + text + " that can be refined into " + text + " ingots using a Blast Crusher.";
			slagMetal.Tint = tint;
			slagMetal.AmountKey = amountKey ?? (metalName + " slag per ingot");
			slagMetal.SourceItem = sourceItem;
			return slagMetal;
		}
	}
	[HarmonyPatch(typeof(Smelter), "Spawn", new Type[]
	{
		typeof(string),
		typeof(int)
	})]
	internal static class SmelterSlagOutput
	{
		private static readonly ConditionalWeakTable<Smelter, Dictionary<int, int>> _progress = new ConditionalWeakTable<Smelter, Dictionary<int, int>>();

		private static FieldInfo _nview;

		private static bool _loggedMissingView;

		private static void Postfix(Smelter __instance, string ore, int stack)
		{
			if (stack > 0 && !CrusherSmelt.IsCrusher(__instance) && IsOwner(__instance))
			{
				SlagMetal slagMetal = SlagMetals.Find(__instance, OutputItem(__instance, ore), ore);
				if (slagMetal != null)
				{
					int num = ModConfig.SlagRatio(slagMetal);
					int amount = ((num < 0) ? (-num * stack) : ((num > 0) ? CountSlag(__instance, slagMetal, stack, num) : 0));
					DropSlag(__instance, slagMetal, amount);
				}
			}
		}

		internal static void ResetRatioProgress(SlagMetal metal)
		{
			if (metal == null)
			{
				return;
			}
			int every = ModConfig.SlagRatio(metal);
			Smelter[] array = Object.FindObjectsByType<Smelter>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			foreach (Smelter val in array)
			{
				if (!((Object)(object)val == (Object)null) && !CrusherSmelt.IsCrusher(val) && IsOwner(val))
				{
					SyncRatio(val, metal, ProgressKey(metal.Id), every);
				}
			}
		}

		private static string OutputItem(Smelter smelter, string ore)
		{
			if (smelter.m_conversion == null)
			{
				return null;
			}
			foreach (ItemConversion item in smelter.m_conversion)
			{
				if (item != null && !((Object)(object)item.m_from == (Object)null) && !((Object)(object)item.m_to == (Object)null) && !(((Object)((Component)item.m_from).gameObject).name.Replace("(Clone)", "") != ore))
				{
					return ((Object)((Component)item.m_to).gameObject).name.Replace("(Clone)", "");
				}
			}
			return null;
		}

		private static int CountSlag(Smelter smelter, SlagMetal metal, int stack, int every)
		{
			int key = ProgressKey(metal.Id);
			SyncRatio(smelter, metal, key, every);
			int num = ReadProgress(smelter, key) + stack;
			int result = num / every;
			WriteProgress(smelter, key, num % every);
			return result;
		}

		private static void SyncRatio(Smelter smelter, SlagMetal metal, int key, int every)
		{
			int key2 = RatioKey(metal.Id);
			if (ReadProgress(smelter, key2) != every)
			{
				WriteProgress(smelter, key, 0);
				WriteProgress(smelter, key2, every);
			}
		}

		private static void DropSlag(Smelter smelter, SlagMetal metal, int amount)
		{
			if (amount <= 0 || (Object)(object)smelter.m_outputPoint == (Object)null)
			{
				return;
			}
			ObjectDB instance = ObjectDB.instance;
			GameObject val = (((Object)(object)instance != (Object)null) ? instance.GetItemPrefab(metal.SlagPrefab) : null);
			if (!((Object)(object)val == (Object)null))
			{
				SharedData shared = val.GetComponent<ItemDrop>().m_itemData.m_shared;
				int num = ((shared.m_maxStackSize <= 0) ? 1 : shared.m_maxStackSize);
				while (amount > 0)
				{
					int num2 = ((amount > num) ? num : amount);
					SpawnSlag(smelter, val, num2);
					amount -= num2;
				}
			}
		}

		private static int ProgressKey(string metalId)
		{
			string text = "SlagCrusher." + metalId;
			int num = 5381;
			int num2 = num;
			for (int i = 0; i < text.Length; i += 2)
			{
				num = ((num << 5) + num) ^ text[i];
				if (i == text.Length - 1)
				{
					break;
				}
				num2 = ((num2 << 5) + num2) ^ text[i + 1];
			}
			return num + num2 * 1566083941;
		}

		private static int RatioKey(string metalId)
		{
			return ProgressKey(metalId + ".ratio");
		}

		private static int ReadProgress(Smelter smelter, int key)
		{
			ZDO val = Zdo(smelter);
			if (val != null)
			{
				return val.GetInt(key, 0);
			}
			if (!_progress.TryGetValue(smelter, out var value) || !value.TryGetValue(key, out var value2))
			{
				return 0;
			}
			return value2;
		}

		private static void WriteProgress(Smelter smelter, int key, int value)
		{
			ZDO val = Zdo(smelter);
			if (val != null)
			{
				val.Set(key, value, false);
				return;
			}
			_progress.GetValue(smelter, (Smelter _) => new Dictionary<int, int>())[key] = value;
		}

		private static bool IsOwner(Smelter smelter)
		{
			ZNetView val = View(smelter);
			if (!((Object)(object)val == (Object)null) && val.IsValid())
			{
				return val.IsOwner();
			}
			return true;
		}

		private static ZDO Zdo(Smelter smelter)
		{
			ZNetView val = View(smelter);
			if ((Object)(object)val != (Object)null && val.IsValid())
			{
				return val.GetZDO();
			}
			if (!_loggedMissingView)
			{
				_loggedMissingView = true;
				Plugin.Instance.LogVerbose("A smelter had no network view. Slag counted every few ingots will reset if that station is reloaded.");
			}
			return null;
		}

		private static ZNetView View(Smelter smelter)
		{
			if (_nview == null)
			{
				_nview = AccessTools.Field(typeof(Smelter), "m_nview");
			}
			if (!(_nview != null))
			{
				return null;
			}
			object? value = _nview.GetValue(smelter);
			return (ZNetView)((value is ZNetView) ? value : null);
		}

		private static void SpawnSlag(Smelter smelter, GameObject slag, int stack)
		{
			//IL_0009: 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_0022: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			Transform outputPoint = smelter.m_outputPoint;
			GameObject val = Object.Instantiate<GameObject>(slag, outputPoint.position, outputPoint.rotation);
			val.SetActive(true);
			if (val.scene != ((Component)smelter).gameObject.scene)
			{
				SceneManager.MoveGameObjectToScene(val, ((Component)smelter).gameObject.scene);
			}
			ItemDrop component = val.GetComponent<ItemDrop>();
			if (!((Object)(object)component == (Object)null))
			{
				component.m_itemData.m_dropPrefab = slag;
				component.m_itemData.m_stack = stack;
				ItemDrop.OnCreateNew(component, false);
			}
		}
	}
	internal static class StationModel
	{
		[Serializable]
		private class StationLayout
		{
			public float[] add_ore;

			public float[] add_ore_rotation;

			public float[] add_wood;

			public float[] add_wood_rotation;

			public float[] output;

			public float[] output_rotation;

			public float[] smoke;

			public float[] smoke_rotation;

			public float[] enabled;

			public float[] enabled_rotation;

			public RollerLayout[] rollers;

			public string wheel_mesh;

			public float[] wheel_position;

			public float[] wheel_axis;

			public float wheel_speed;

			public string pump_mesh;

			public float[] pump_amplitude;

			public float pump_speed;
		}

		[Serializable]
		private class RollerLayout
		{
			public string mesh;

			public float[] position;

			public float[] rotation;

			public float[] axis;

			public float degreesPerSecond;
		}

		private static GameObject _burstHolder;

		private static Texture2D _metalMask;

		internal static void Attach(GameObject prefab, string prefix)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0422: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0487: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0519: Unknown result type (might be due to invalid IL or missing references)
			//IL_055d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0576: Unknown result type (might be due to invalid IL or missing references)
			string text = ((prefix == "blastcrusher") ? "Blast Crusher" : "Slag Crusher");
			StationLayout stationLayout = LoadLayout(prefix);
			Smelter component = prefab.GetComponent<Smelter>();
			Material val = VanillaMaterial(prefab, component);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Instance.LogWarning(text + " model was not loaded. The piece material was missing.");
				return;
			}
			HideVanillaBody(prefab);
			DisableOldColliders(prefab);
			Material material = new Material(val)
			{
				name = prefix + "_baked"
			};
			UseBake(material, Resource(prefix, "station-albedo.png"), Resource(prefix, "station-normal.png"));
			Roughen(material);
			bool flag = prefix == "blastcrusher";
			Color metalColor = (flag ? new Color(12f, 12f, 12f, 1f) : new Color(8f, 6f, 3.6f, 1f));
			if (flag)
			{
				ApplyFurnaceMask(material, metalColor);
			}
			Material material2 = new Material(val)
			{
				name = prefix + "_grate"
			};
			UseMetalGrate(material2, metalColor, flag);
			Material val2 = new Material(val)
			{
				name = prefix + "_rollers"
			};
			UseBake(val2, Resource(prefix, "roller-albedo.png"), Resource(prefix, "roller-normal.png"));
			if (flag)
			{
				Texture mainTexture = val2.mainTexture;
				Gray((Texture2D)(object)((mainTexture is Texture2D) ? mainTexture : null));
			}
			PolishMetal(val2, metalColor);
			Transform transform = new GameObject(prefix + "_model").transform;
			((Component)transform).gameObject.layer = prefab.layer;
			transform.SetParent(prefab.transform, false);
			Mesh val3 = MeshFile.LoadMesh(Resource(prefix, "body-smelter.mesh"), prefix + "_body");
			Mesh val4 = MeshFile.LoadMesh(Resource(prefix, "body-metal.mesh"), prefix + "_grate");
			int num = val4.triangles.Length / 3;
			Transform part = CreatePart(transform, "body", val3, material, Vector3.zero);
			Transform part2 = CreatePart(transform, "grate", val4, material2, Vector3.zero);
			AddSolid(part, val3, convex: false);
			AddSolid(part2, val4, convex: false);
			RollerLayout[] array = stationLayout.rollers ?? new RollerLayout[0];
			CrusherRollers crusherRollers = prefab.AddComponent<CrusherRollers>();
			crusherRollers.Rollers = (Transform[])(object)new Transform[array.Length];
			crusherRollers.Axes = (Vector3[])(object)new Vector3[array.Length];
			crusherRollers.Speeds = new float[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				RollerLayout rollerLayout = array[i];
				Mesh mesh = MeshFile.LoadMesh(Resource(prefix, rollerLayout.mesh), rollerLayout.mesh);
				Transform val5 = CreatePart(transform, rollerLayout.mesh, mesh, val2, Vector(rollerLayout.position));
				if (rollerLayout.rotation != null && rollerLayout.rotation.Length == 4)
				{
					val5.localRotation = new Quaternion(rollerLayout.rotation[0], rollerLayout.rotation[1], rollerLayout.rotation[2], rollerLayout.rotation[3]);
				}
				AddSolid(val5, mesh, convex: true);
				crusherRollers.Rollers[i] = val5;
				crusherRollers.Axes[i] = Vector(rollerLayout.axis);
				crusherRollers.Speeds[i] = rollerLayout.degreesPerSecond;
			}
			if (!string.IsNullOrEmpty(stationLayout.wheel_mesh))
			{
				Mesh mesh2 = MeshFile.LoadMesh(Resource(prefix, stationLayout.wheel_mesh), prefix + "_wheel");
				Mesh mesh3 = MeshFile.LoadMesh(Resource(prefix, stationLayout.pump_mesh), prefix + "_pump");
				Transform val6 = CreatePart(transform, "wheel", mesh2, material, Vector(stationLayout.wheel_position));
				Transform val7 = CreatePart(transform, "pump", mesh3, material, Vector3.zero);
				AddSolid(val6, mesh2, convex: true);
				AddSolid(val7, mesh3, convex: true);
				BlastPump blastPump = prefab.AddComponent<BlastPump>();
				blastPump.Wheel = val6;
				blastPump.Axis = Vector(stationLayout.wheel_axis);
				blastPump.DegreesPerSecond = stationLayout.wheel_speed;
				blastPump.Rod = val7;
				blastPump.Amplitude = Vector(stationLayout.pump_amplitude);
			}
			Place(prefab.transform, ((Object)(object)component.m_addOreSwitch != (Object)null) ? ((Component)component.m_addOreSwitch).transform : null, Vector(stationLayout.add_ore), stationLayout.add_ore_rotation);
			Place(prefab.transform, ((Object)(object)component.m_addWoodSwitch != (Object)null) ? ((Component)component.m_addWoodSwitch).transform : null, Vector(stationLayout.add_wood), stationLayout.add_wood_rotation);
			Place(prefab.transform, component.m_outputPoint, Vector(stationLayout.output), stationLayout.output_rotation);
			Place(prefab.transform, ((Object)(object)component.m_enabledObject != (Object)null) ? component.m_enabledObject.transform : null, Vector(stationLayout.enabled), stationLayout.enabled_rotation);
			Place(prefab.transform, ((Object)(object)component.m_smokeSpawner != (Object)null) ? ((Component)component.m_smokeSpawner).transform : null, Vector(stationLayout.smoke), stationLayout.smoke_rotation);
			FitFire(component, flag);
			AimBursts(component, flag);
			NeutralizeDemolishVisuals(prefab, prefix);
			BoxCollider obj = prefab.AddComponent<BoxCollider>();
			((Collider)obj).isTrigger = false;
			obj.center = new Vector3(0f, 0.5f, 0f);
			obj.size = new Vector3(2.4f, 1f, 2.2f);
			Plugin.Instance.LogVerbose("Attached the " + text + " model (" + val3.vertexCount + " body verts, " + num + " grate tris, " + array.Length + " rollers).");
		}

		private static void NeutralizeDemolishVisuals(GameObject prefab, string prefix)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			WearNTear component = prefab.GetComponent<WearNTear>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			component.m_autoCreateFragments = false;
			component.m_fragmentRoots = null;
			GameObject val = component.m_new;
			GameObject worn = component.m_worn;
			GameObject broken = component.m_broken;
			if ((Object)(object)val != (Object)null)
			{
				val.SetActive(false);
			}
			if ((Object)(object)worn != (Object)null && (Object)(object)worn != (Object)(object)val)
			{
				worn.SetActive(false);
			}
			if ((Object)(object)broken != (Object)null && (Object)(object)broken != (Object)(object)val && (Object)(object)broken != (Object)(object)worn)
			{
				broken.SetActive(false);
			}
			GameObject val2 = new GameObject(prefix + "_wear");
			val2.layer = prefab.layer;
			val2.transform.SetParent(prefab.transform, false);
			component.m_new = val2;
			component.m_worn = val2;
			component.m_broken = val2;
			Transform[] componentsInChildren = prefab.GetComponentsInChildren<Transform>(true);
			foreach (Transform val3 in componentsInChildren)
			{
				if (((Object)val3).name.IndexOf("_Destruction", StringComparison.Ordinal) >= 0)
				{
					((Component)val3).gameObject.SetActive(false);
				}
			}
			if (component.m_destroyedEffect != null)
			{
				GameObject prefab2 = PrefabManager.Instance.GetPrefab("vfx_RockDestroyed");
				if ((Object)(object)prefab2 != (Object)null)
				{
					EffectData val4 = new EffectData();
					val4.m_prefab = prefab2;
					val4.m_enabled = true;
					component.m_destroyedEffect.m_effectPrefabs = (EffectData[])(object)new EffectData[1] { val4 };
				}
				else
				{
					component.m_destroyedEffect.m_effectPrefabs = (EffectData[])(object)new EffectData[0];
				}
			}
			if (component.m_hitEffect != null)
			{
				component.m_hitEffect.m_effectPrefabs = (EffectData[])(object)new EffectData[0];
			}
			if (component.m_switchEffect != null)
			{
				component.m_switchEffect.m_effectPrefabs = (EffectData[])(object)new EffectData[0];
			}
		}

		private static void FitFire(Smelter smelter, bool blast)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)smelter.m_enabledObject == (Object)null)
			{
				return;
			}
			Transform transform = smelter.m_enabledObject.transform;
			Transform val = (((Object)(object)smelter.m_addOreSwitch != (Object)null) ? ((Component)smelter.m_addOreSwitch).transform : null);
			Transform val2 = (((Object)(object)smelter.m_addWoodSwitch != (Object)null) ? ((Component)smelter.m_addWoodSwitch).transform : null);
			if (blast)
			{
				FitBlastFire(smelter, transform, val, val2);
				return;
			}
			Transform val3 = transform.Find("smoke (1)");
			if ((Object)(object)val3 != (Object)null)
			{
				val3.localPosition = new Vector3(0f, 1f, 0f);
			}
			PlaceFlame(transform, "flames", val, 0.32f, 0.2f);
			PlaceFlame(transform, "flames (1)", val2, 0.32f, 0.2f);
			PlaceFlame(transform, "flames (2)", smelter.m_outputPoint, 1.1f, 0f);
		}

		private static void FitBlastFire(Smelter smelter, Transform fire, Transform ore, Transform wood)
		{
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: 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)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (