Decompiled source of DSPTrashBuilding v1.2.3

BepInEx/plugins/DSPTrashBuilding/DSPTrashBuilding.dll

Decompiled 3 days ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using xiaoye97;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace DSPTrashBuilding;

internal static class Patches
{
	private sealed class CacheEntry
	{
		internal int EntityId;

		internal bool IsTrash;
	}

	[HarmonyPatch(typeof(Resources), "Load", new Type[]
	{
		typeof(string),
		typeof(Type)
	})]
	internal static class ResourcesLoadPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref string path, ref Object __result)
		{
			return TrashCanPrefab.HandleResourcesLoad(path, ref __result);
		}
	}

	[HarmonyPatch]
	internal static class AddItemPatch
	{
		[HarmonyTargetMethod]
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(StorageComponent), "AddItem", new Type[5]
			{
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(int).MakeByRefType(),
				typeof(bool)
			}, (Type[])null);
		}

		[HarmonyPrefix]
		private static bool Prefix(StorageComponent __instance, int itemId, int count, int inc, out int remainInc, bool useBan, ref int __result)
		{
			if (!TryHandleTrashInput(__instance, itemId, count, out var accepted))
			{
				remainInc = 0;
				return true;
			}
			remainInc = ((accepted == 0) ? inc : 0);
			__result = accepted;
			return false;
		}
	}

	[HarmonyPatch(typeof(StorageComponent), "AddItemFiltered")]
	internal static class AddItemFilteredPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(StorageComponent __instance, int itemId, int count, int inc, out int remainInc, bool useBan, ref int __result)
		{
			if (!TryHandleTrashInput(__instance, itemId, count, out var accepted))
			{
				remainInc = 0;
				return true;
			}
			remainInc = ((accepted == 0) ? inc : 0);
			__result = accepted;
			return false;
		}
	}

	[HarmonyPatch(typeof(StorageComponent), "AddItemFilteredBanOnly")]
	internal static class AddItemFilteredBanOnlyPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(StorageComponent __instance, int itemId, int count, int inc, out int remainInc, ref int __result)
		{
			if (!TryHandleTrashInput(__instance, itemId, count, out var accepted))
			{
				remainInc = 0;
				return true;
			}
			remainInc = ((accepted == 0) ? inc : 0);
			__result = accepted;
			return false;
		}
	}

	[HarmonyPatch(typeof(StorageComponent), "AddCargo")]
	internal static class AddCargoPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(StorageComponent __instance, ref Cargo cargo, bool useBan, ref bool __result)
		{
			if (!TryHandleTrashInput(__instance, cargo.item, cargo.stack, out var accepted))
			{
				return true;
			}
			if (accepted > 0)
			{
				((Cargo)(ref cargo)).SetEmpty();
			}
			__result = accepted > 0;
			return false;
		}
	}

	[HarmonyPatch(typeof(UIStorageWindow), "_OnOpen")]
	internal static class StorageWindowOpenPatch
	{
		[HarmonyPostfix]
		private static void Postfix(UIStorageWindow __instance)
		{
			RefreshTrashWindow(__instance);
		}
	}

	[HarmonyPatch(typeof(UIStorageWindow), "OnStorageIdChange")]
	internal static class StorageWindowChangePatch
	{
		[HarmonyPostfix]
		private static void Postfix(UIStorageWindow __instance)
		{
			RefreshTrashWindow(__instance);
		}
	}

	[HarmonyPatch(typeof(UIStorageWindow), "_OnUpdate")]
	internal static class StorageWindowUpdatePatch
	{
		[HarmonyPostfix]
		private static void Postfix(UIStorageWindow __instance)
		{
			StorageComponent windowStorage = GetWindowStorage(__instance);
			if (windowStorage != null && IsTrashStorage(windowStorage))
			{
				ApplyTrashModeRow(__instance, windowStorage);
			}
			else if (modeRowPatched)
			{
				RestoreModeRow();
				modeRowPatched = false;
			}
		}
	}

	[HarmonyPatch(typeof(UIStorageWindow), "OnBansSliderValueChange")]
	internal static class BansSliderPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(UIStorageWindow __instance, float value)
		{
			if (eventLockField != null && (bool)eventLockField.GetValue(__instance))
			{
				return true;
			}
			StorageComponent windowStorage = GetWindowStorage(__instance);
			if (windowStorage == null || !IsTrashStorage(windowStorage))
			{
				return true;
			}
			int num = ((value >= 0.5f) ? 1 : 0);
			if (windowStorage.bans != num)
			{
				windowStorage.SetBans(num);
				windowStorage.changed = true;
			}
			ApplyTrashModeRow(__instance, windowStorage);
			return false;
		}
	}

	[HarmonyPatch(typeof(UIStorageGrid), "SetStorageBansDisplay")]
	internal static class StorageGridBansDisplayPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(UIStorageGrid __instance)
		{
			StorageComponent val = (StorageComponent)((gridStorageField != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if (val != null && IsTrashStorage(val))
			{
				if (gridBgMaterialField != null)
				{
					object? value = gridBgMaterialField.GetValue(__instance);
					Material val2 = (Material)((value is Material) ? value : null);
					if ((Object)(object)val2 != (Object)null)
					{
						val2.SetFloat("_Bans", 0f);
					}
				}
				return false;
			}
			return true;
		}
	}

	private static readonly ConcurrentDictionary<StorageComponent, CacheEntry> cache = new ConcurrentDictionary<StorageComponent, CacheEntry>();

	private const int TrashSlotCount = 20;

	private static readonly FieldInfo eventLockField = AccessTools.Field(typeof(UIStorageWindow), "eventLock");

	private static readonly FieldInfo gridStorageField = AccessTools.Field(typeof(UIStorageGrid), "storage");

	private static readonly FieldInfo gridBgMaterialField = AccessTools.Field(typeof(UIStorageGrid), "bgImageMat");

	private static readonly UnityAction toggleModeAction = new UnityAction(ToggleTrashMode);

	private static bool windowDefaultsSaved;

	private static bool savedEditableFilter;

	private static bool savedAllowFilterIcon;

	private static bool bansButtonBound;

	private static UIStorageWindow boundWindow;

	private static Transform modeRow;

	private static Text[] modeRowLabels;

	private static string[] modeRowLabelOriginals;

	private static bool modeRowPatched;

	private static bool TryHandleTrashInput(StorageComponent storage, int itemId, int count, out int accepted)
	{
		accepted = 0;
		if (storage == null || itemId <= 0 || count <= 0 || !IsTrashStorage(storage))
		{
			return false;
		}
		if (IsItemAllowed(storage, itemId))
		{
			accepted = count;
		}
		return true;
	}

	internal static bool IsItemAllowed(StorageComponent storage, int itemId)
	{
		bool flag = storage.bans != 0;
		GRID[] grids = storage.grids;
		int size = storage.size;
		bool flag2 = false;
		if (grids != null)
		{
			int num = Math.Min(size, grids.Length);
			for (int i = 0; i < num; i++)
			{
				if (grids[i].filter == itemId)
				{
					flag2 = true;
					break;
				}
			}
		}
		if (!flag)
		{
			return !flag2;
		}
		return flag2;
	}

	internal static StorageComponent GetWindowStorage(UIStorageWindow window)
	{
		if ((Object)(object)window == (Object)null)
		{
			return null;
		}
		int storageId = window.storageId;
		if (storageId <= 0)
		{
			return null;
		}
		PlanetFactory factory = window.factory;
		if (factory == null)
		{
			PlanetData localPlanet = GameMain.localPlanet;
			if (localPlanet != null)
			{
				factory = localPlanet.factory;
			}
		}
		if (factory == null || factory.factoryStorage == null)
		{
			return null;
		}
		StorageComponent[] storagePool = factory.factoryStorage.storagePool;
		if (storageId >= storagePool.Length)
		{
			return null;
		}
		StorageComponent val = storagePool[storageId];
		if (val == null || val.id != storageId)
		{
			return null;
		}
		return val;
	}

	private static void RefreshTrashWindow(UIStorageWindow window)
	{
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Invalid comparison between Unknown and I4
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)window == (Object)null)
		{
			return;
		}
		StorageComponent windowStorage = GetWindowStorage(window);
		bool flag = windowStorage != null && IsTrashStorage(windowStorage);
		if (flag && windowStorage.size < 20)
		{
			int size = windowStorage.size;
			windowStorage.SetSize(20);
			windowStorage.changed = true;
			Log("Upgraded trash storage " + windowStorage.id + " from " + size + " to " + 20 + " slots for the vanilla UI grid.");
		}
		if (flag && (int)windowStorage.type != 9)
		{
			windowStorage.type = (EStorageType)9;
			windowStorage.changed = true;
		}
		UIStorageGrid storageUI = window.storageUI;
		if ((Object)(object)storageUI != (Object)null)
		{
			if (!windowDefaultsSaved)
			{
				savedEditableFilter = storageUI.editableFilter;
				savedAllowFilterIcon = storageUI.allowFilterIcon;
				windowDefaultsSaved = true;
			}
			if (flag)
			{
				storageUI.editableFilter = true;
				storageUI.allowFilterIcon = true;
			}
			else
			{
				storageUI.editableFilter = savedEditableFilter;
				storageUI.allowFilterIcon = savedAllowFilterIcon;
			}
		}
		if (flag)
		{
			EnsureBansButtonBinding(window);
			ApplyTrashModeRow(window, windowStorage);
		}
		else if (modeRowPatched)
		{
			RestoreModeRow();
			modeRowPatched = false;
		}
	}

	private static void EnsureBansButtonBinding(UIStorageWindow window)
	{
		if (bansButtonBound && (Object)(object)boundWindow != (Object)null && boundWindow == window)
		{
			return;
		}
		try
		{
			if ((Object)(object)window.bansButton != (Object)null && (Object)(object)window.bansButton.button != (Object)null)
			{
				((UnityEvent)window.bansButton.button.onClick).RemoveListener(toggleModeAction);
				((UnityEvent)window.bansButton.button.onClick).AddListener(toggleModeAction);
			}
		}
		catch (Exception ex)
		{
			Log("Could not bind the trash mode button: " + ex.Message);
		}
		bansButtonBound = true;
		boundWindow = window;
	}

	private static void ToggleTrashMode()
	{
		UIStorageWindow window = boundWindow;
		StorageComponent windowStorage = GetWindowStorage(window);
		if (windowStorage != null && IsTrashStorage(windowStorage))
		{
			windowStorage.SetBans((windowStorage.bans == 0) ? 1 : 0);
			windowStorage.changed = true;
			ApplyTrashModeRow(window, windowStorage);
		}
	}

	private static void ApplyTrashModeRow(UIStorageWindow window, StorageComponent storage)
	{
		if ((Object)(object)window == (Object)null || storage == null)
		{
			return;
		}
		CacheModeRow(window);
		modeRowPatched = true;
		Slider bansSlider = window.bansSlider;
		if ((Object)(object)bansSlider != (Object)null)
		{
			bool flag = eventLockField != null && (bool)eventLockField.GetValue(window);
			try
			{
				if (eventLockField != null)
				{
					eventLockField.SetValue(window, true);
				}
				float num = ((storage.bans != 0) ? 1f : 0f);
				bansSlider.minValue = 0f;
				bansSlider.maxValue = 1f;
				bansSlider.wholeNumbers = true;
				if (!Mathf.Approximately(bansSlider.value, num))
				{
					bansSlider.value = num;
				}
			}
			finally
			{
				if (eventLockField != null)
				{
					eventLockField.SetValue(window, flag);
				}
			}
		}
		if ((Object)(object)window.bansValueText != (Object)null)
		{
			window.bansValueText.text = ((storage.bans != 0) ? "白名单" : "黑名单");
		}
		SetModeRowLabels("黑白名单");
	}

	private static void CacheModeRow(UIStorageWindow window)
	{
		if ((Object)(object)modeRow != (Object)null)
		{
			return;
		}
		Transform obj = (((Object)(object)window.bansSlider != (Object)null) ? ((Component)window.bansSlider).transform : null);
		Transform child = (((Object)(object)window.bansButton != (Object)null) ? ((Component)window.bansButton).transform : null);
		Transform child2 = (((Object)(object)window.bansValueText != (Object)null) ? ((Component)window.bansValueText).transform : null);
		Transform val = (Transform)(((Object)(object)window.windowTrans != (Object)null) ? ((object)window.windowTrans) : ((object)((Component)window).transform));
		Transform val2 = obj;
		while ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)val)
		{
			if (IsInside(child, val2) && IsInside(child2, val2))
			{
				modeRow = val2;
				break;
			}
			val2 = val2.parent;
		}
		if ((Object)(object)modeRow == (Object)null)
		{
			return;
		}
		HashSet<Text> hashSet = new HashSet<Text>();
		List<Text> list = new List<Text>();
		Text[] componentsInChildren = ((Component)modeRow).GetComponentsInChildren<Text>(true);
		foreach (Text val3 in componentsInChildren)
		{
			if ((Object)(object)val3 != (Object)null && (Object)(object)val3 != (Object)(object)window.bansValueText && hashSet.Add(val3))
			{
				list.Add(val3);
			}
		}
		if ((Object)(object)window.windowTrans != (Object)null)
		{
			Text[] componentsInChildren2 = ((Component)window.windowTrans).GetComponentsInChildren<Text>(true);
			foreach (Text val4 in componentsInChildren2)
			{
				if ((Object)(object)val4 != (Object)null && (Object)(object)val4 != (Object)(object)window.bansValueText && !hashSet.Contains(val4) && IsCapacityLimitLabel(val4.text))
				{
					hashSet.Add(val4);
					list.Add(val4);
				}
			}
		}
		modeRowLabels = list.ToArray();
		modeRowLabelOriginals = new string[modeRowLabels.Length];
		for (int k = 0; k < modeRowLabels.Length; k++)
		{
			modeRowLabelOriginals[k] = modeRowLabels[k].text;
		}
	}

	private static bool IsInside(Transform child, Transform parent)
	{
		if ((Object)(object)child != (Object)null && (Object)(object)parent != (Object)null)
		{
			return child.IsChildOf(parent);
		}
		return false;
	}

	private static void SetModeRowLabels(string text)
	{
		if (modeRowLabels == null)
		{
			return;
		}
		for (int i = 0; i < modeRowLabels.Length; i++)
		{
			if ((Object)(object)modeRowLabels[i] != (Object)null)
			{
				modeRowLabels[i].text = text;
			}
		}
	}

	private static bool IsCapacityLimitLabel(string value)
	{
		if (string.IsNullOrEmpty(value))
		{
			return false;
		}
		if (value.IndexOf("容量限制", StringComparison.Ordinal) < 0 && value.IndexOf("自动化输入限制", StringComparison.Ordinal) < 0 && value.IndexOf("Capacity Limit", StringComparison.OrdinalIgnoreCase) < 0)
		{
			return value.IndexOf("Automation Capacity", StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return true;
	}

	private static void RestoreModeRow()
	{
		if (modeRowLabels == null || modeRowLabelOriginals == null)
		{
			return;
		}
		for (int i = 0; i < modeRowLabels.Length; i++)
		{
			if ((Object)(object)modeRowLabels[i] != (Object)null && i < modeRowLabelOriginals.Length)
			{
				modeRowLabels[i].text = modeRowLabelOriginals[i];
			}
		}
	}

	internal static bool IsTrashStorage(StorageComponent storage)
	{
		if (storage == null || Plugin.ItemId <= 0 || storage.isPlayerInventory)
		{
			return false;
		}
		int entityId = storage.entityId;
		if (entityId <= 0)
		{
			return false;
		}
		if (cache.TryGetValue(storage, out var value) && value.EntityId == entityId)
		{
			return value.IsTrash;
		}
		bool flag = false;
		try
		{
			GameData data = GameMain.data;
			if (data != null && data.factories != null)
			{
				int num = data.factoryCount;
				if (num > data.factories.Length)
				{
					num = data.factories.Length;
				}
				for (int i = 0; i < num; i++)
				{
					PlanetFactory val = data.factories[i];
					if (val == null || val.factoryStorage == null)
					{
						continue;
					}
					StorageComponent[] storagePool = val.factoryStorage.storagePool;
					int id = storage.id;
					if (id > 0 && id < storagePool.Length && storagePool[id] == storage)
					{
						EntityData[] entityPool = val.entityPool;
						if (entityId < entityPool.Length)
						{
							flag = entityPool[entityId].protoId == Plugin.ItemId;
						}
						break;
					}
				}
			}
		}
		catch (Exception ex)
		{
			Log("IsTrashStorage failed: " + ex.Message);
		}
		CacheEntry cacheEntry = new CacheEntry();
		cacheEntry.EntityId = entityId;
		cacheEntry.IsTrash = flag;
		cache[storage] = cacheEntry;
		return flag;
	}

	internal static bool IsTrashStorage(PlanetFactory factory, int storageId)
	{
		if (factory == null || factory.factoryStorage == null || storageId <= 0)
		{
			return false;
		}
		StorageComponent[] storagePool = factory.factoryStorage.storagePool;
		if (storageId >= storagePool.Length)
		{
			return false;
		}
		StorageComponent val = storagePool[storageId];
		if (val == null || val.id != storageId)
		{
			return false;
		}
		int entityId = val.entityId;
		if (entityId <= 0 || entityId >= factory.entityPool.Length)
		{
			return false;
		}
		return factory.entityPool[entityId].protoId == Plugin.ItemId;
	}

	private static void ClearStorage(StorageComponent storage)
	{
		for (int i = 0; i < storage.size; i++)
		{
			if (storage.grids[i].itemId != 0 || storage.grids[i].count != 0)
			{
				storage.grids[i].itemId = 0;
				storage.grids[i].count = 0;
				storage.changed = true;
			}
		}
	}

	private static void Log(string message)
	{
		if (Plugin.Log != null)
		{
			Plugin.Log.LogWarning((object)message);
		}
	}
}
[BepInPlugin("com.dsptrashcan.building", "DSP Trash Building", "1.2.3")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInProcess("DSPGAME.exe")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string Guid = "com.dsptrashcan.building";

	public const string Name = "DSP Trash Building";

	public const string Version = "1.2.3";

	public const string LdbToolGuid = "me.xiaoye97.plugin.Dyson.LDBTool";

	internal static Plugin Instance;

	internal static ManualLogSource Log;

	internal static int ItemId;

	internal static int ModelId;

	internal static int RecipeId;

	internal const int LegacyModelId = 714;

	internal static ItemProto TrashItem;

	internal static ModelProto TrashModel;

	internal static RecipeProto TrashRecipe;

	internal static TechProto AutomationTech;

	internal static int AutomationTechId;

	private static bool registered;

	private GameHistoryData unlockedHistory;

	private void Awake()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		try
		{
			new Harmony("com.dsptrashcan.building").PatchAll(Assembly.GetExecutingAssembly());
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Harmony patching failed: " + ex));
		}
		RegisterProtos();
		LDBTool.PreAddDataAction = (Action)Delegate.Combine(LDBTool.PreAddDataAction, new Action(OnPreAddData));
		LDBTool.PostAddDataAction = (Action)Delegate.Combine(LDBTool.PostAddDataAction, new Action(OnPostAddData));
		((BaseUnityPlugin)this).Logger.LogInfo((object)"DSP Trash Building 1.2.3 loaded.");
	}

	private void Update()
	{
		if (RecipeId <= 0 || AutomationTechId <= 0)
		{
			return;
		}
		try
		{
			GameHistoryData history = GameMain.history;
			if (history != null && history.TechUnlocked(AutomationTechId) && history != unlockedHistory)
			{
				history.UnlockRecipe(RecipeId);
				unlockedHistory = history;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Unlocked the trash building recipe through tech " + AutomationTechId + "."));
			}
		}
		catch (Exception)
		{
		}
	}

	private void RegisterProtos()
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Expected O, but got Unknown
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		if (!registered)
		{
			registered = true;
			TrashModel = new ModelProto();
			((Proto)TrashModel).ID = 0;
			((Proto)TrashModel).Name = "DSPTrashCanModel";
			TrashModel.PrefabPath = "assets/dsptrashcan/building/trashcan";
			TrashModel.RendererType = 0;
			TrashModel.HpMax = 200;
			LDBTool.PreAddProto((Proto)(object)TrashModel);
			ModelId = ((Proto)TrashModel).ID;
			TrashItem = new ItemProto();
			((Proto)TrashItem).ID = 11999;
			((Proto)TrashItem).Name = "垃圾桶";
			TrashItem.Description = "销毁由分拣器送入的物品。\n点击建筑可配置黑白名单。\nDestroys items inserted by sorters; click the building to configure a block/allow list.";
			TrashItem.Type = (EItemType)6;
			TrashItem.StackSize = 50;
			TrashItem.IconPath = "assets/dsptrashcan/building/icon";
			TrashItem.IconTag = "";
			TrashItem.GridIndex = 2814;
			TrashItem.DescFields = new int[4] { 22, 11, 12, 1 };
			TrashItem.ModelIndex = ((Proto)TrashModel).ID;
			TrashItem.ModelCount = 1;
			TrashItem.BuildMode = 1;
			TrashItem.IsEntity = true;
			TrashItem.CanBuild = true;
			TrashItem.UnlockKey = -1;
			TrashItem.HpMax = 200;
			TrashItem.SubID = 0;
			LDBTool.PreAddProto((Proto)(object)TrashItem);
			ItemId = ((Proto)TrashItem).ID;
			TrashRecipe = new RecipeProto();
			((Proto)TrashRecipe).ID = 11998;
			((Proto)TrashRecipe).Name = "垃圾桶";
			TrashRecipe.Description = "销毁由分拣器送入的物品。";
			TrashRecipe.Type = (ERecipeType)4;
			TrashRecipe.Handcraft = true;
			TrashRecipe.Explicit = true;
			TrashRecipe.TimeSpend = 60;
			TrashRecipe.Items = new int[1] { 1101 };
			TrashRecipe.ItemCounts = new int[1] { 4 };
			TrashRecipe.Results = new int[1] { ((Proto)TrashItem).ID };
			TrashRecipe.ResultCounts = new int[1] { 1 };
			TrashRecipe.GridIndex = 2814;
			TrashRecipe.IconPath = "assets/dsptrashcan/building/icon";
			TrashRecipe.IconTag = "";
			LDBTool.PreAddProto((Proto)(object)TrashRecipe);
			RecipeId = ((Proto)TrashRecipe).ID;
		}
	}

	private static void OnPreAddData()
	{
		try
		{
			ChooseModelId();
			ChooseGridIndex();
			ChoosePreTech();
			Log.LogInfo((object)("Trash building registered: item=" + ((Proto)TrashItem).ID + " model=" + ((Proto)TrashModel).ID + " recipe=" + ((Proto)TrashRecipe).ID + " grid=" + TrashItem.GridIndex));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("OnPreAddData failed: " + ex));
		}
	}

	private static void ChooseModelId()
	{
		if ((Object)(object)LDB.models == (Object)null || ((ProtoSet<ModelProto>)(object)LDB.models).dataArray == null)
		{
			return;
		}
		ModelProto[] dataArray = ((ProtoSet<ModelProto>)(object)LDB.models).dataArray;
		int val = dataArray.Length;
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < dataArray.Length; i++)
		{
			if (dataArray[i] != null)
			{
				hashSet.Add(((Proto)dataArray[i]).ID);
			}
		}
		int num = 0;
		int num2 = Math.Max(1, val);
		for (int j = num2; j <= num2 + 63; j++)
		{
			if (!hashSet.Contains(j))
			{
				num = j;
				break;
			}
		}
		if (num <= 0)
		{
			Log.LogError((object)"Could not find a free model ID.");
			return;
		}
		((Proto)TrashModel).ID = num;
		TrashItem.ModelIndex = num;
		ModelId = num;
		PersistModelId(num);
		Log.LogInfo((object)("Using model ID " + num + " (vanilla model count " + val + ")."));
	}

	private static void PersistModelId(int id)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		try
		{
			ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "LDBTool", "LDBTool.CustomID.cfg"), true);
			ConfigEntry<int> val2 = val.Bind<int>("Model", "DSPTrashCanModel", id, "Model ID used by DSP Trash Building");
			if (val2.Value != id)
			{
				val2.Value = id;
				val.Save();
			}
		}
		catch (Exception ex)
		{
			if (Log != null)
			{
				Log.LogWarning((object)("Could not persist model ID: " + ex.Message));
			}
		}
	}

	private static void ChooseGridIndex()
	{
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < ((ProtoSet<ItemProto>)(object)LDB.items).dataArray.Length; i++)
		{
			ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray[i];
			if (val != null && val.GridIndex > 0)
			{
				hashSet.Add(val.GridIndex);
			}
		}
		for (int j = 0; j < ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray.Length; j++)
		{
			RecipeProto val2 = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray[j];
			if (val2 != null && val2.GridIndex > 0)
			{
				hashSet.Add(val2.GridIndex);
			}
		}
		int num = 0;
		int num2 = 8;
		while (num2 >= 1 && num == 0)
		{
			for (int num3 = 14; num3 >= 1; num3--)
			{
				int num4 = 2000 + num2 * 100 + num3;
				if (!hashSet.Contains(num4))
				{
					num = num4;
					break;
				}
			}
			num2--;
		}
		if (num == 0)
		{
			num = 2801;
		}
		TrashItem.GridIndex = num;
		TrashRecipe.GridIndex = num;
		Log.LogInfo((object)("Using replicator grid index " + num + "."));
	}

	private static void ChoosePreTech()
	{
		TechProto val = FindAutomationMetallurgyTech();
		if (val == null)
		{
			Log.LogError((object)"Could not find the 自动化冶金 / Automatic Metallurgy tech; the recipe will remain locked.");
			return;
		}
		if (val.UnlockRecipes == null)
		{
			val.UnlockRecipes = new int[0];
		}
		if (val.unlockRecipeArray == null)
		{
			val.unlockRecipeArray = (RecipeProto[])(object)new RecipeProto[0];
		}
		TrashRecipe.preTech = val;
		AutomationTech = val;
		AutomationTechId = ((Proto)val).ID;
		Log.LogInfo((object)("Linked recipe " + RecipeId + " to tech " + ((Proto)val).ID + " (" + ((Proto)val).name + ")."));
	}

	private static TechProto FindAutomationMetallurgyTech()
	{
		TechProto[] array = (((Object)(object)LDB.techs != (Object)null) ? ((ProtoSet<TechProto>)(object)LDB.techs).dataArray : null);
		if (array == null)
		{
			return null;
		}
		for (int i = 0; i < 2; i++)
		{
			foreach (TechProto val in array)
			{
				if (val == null || ((Proto)val).ID <= 0)
				{
					continue;
				}
				string value = ((Proto)val).Name ?? "";
				string value2 = ((Proto)val).name ?? "";
				bool num;
				if (i != 0)
				{
					if (!IsLooseMetallurgyTechName(value))
					{
						num = IsLooseMetallurgyTechName(value2);
						goto IL_0085;
					}
				}
				else if (!IsExactMetallurgyTechName(value))
				{
					num = IsExactMetallurgyTechName(value2);
					goto IL_0085;
				}
				goto IL_0087;
				IL_0087:
				return val;
				IL_0085:
				if (!num)
				{
					continue;
				}
				goto IL_0087;
			}
		}
		return null;
	}

	private static bool IsExactMetallurgyTechName(string value)
	{
		if (!(value == "自动化冶金") && !(value == "T自动化冶金"))
		{
			return value.Equals("Automatic Metallurgy", StringComparison.OrdinalIgnoreCase);
		}
		return true;
	}

	private static bool IsLooseMetallurgyTechName(string value)
	{
		if (value.IndexOf("冶金", StringComparison.Ordinal) < 0)
		{
			return value.IndexOf("Metallurgy", StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return true;
	}

	private unsafe static void OnPostAddData()
	{
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			TrashModel.Preload();
			TrashCanPrefab.ReshapeModel(TrashModel.prefabDesc);
			AssignModelEntries();
			FixPrefabDescCache();
			PrefabDesc prefabDesc = TrashModel.prefabDesc;
			if (prefabDesc == null || prefabDesc == PrefabDesc.none)
			{
				Log.LogError((object)"Trash building prefab failed to load; placing it will not work.");
			}
			else
			{
				ManualLogSource log = Log;
				string[] obj = new string[12]
				{
					"Prefab ready: storage=",
					prefabDesc.isStorage.ToString(),
					" storageSize=",
					prefabDesc.storageCol.ToString(),
					"x",
					prefabDesc.storageRow.ToString(),
					" beltPorts=",
					((prefabDesc.portPoses != null) ? prefabDesc.portPoses.Length : 0).ToString(),
					" sorterSlots=",
					((prefabDesc.slotPoses != null) ? prefabDesc.slotPoses.Length : 0).ToString(),
					" buildCollider=",
					null
				};
				Vector3 pos = prefabDesc.buildCollider.pos;
				obj[11] = ((object)(*(Vector3*)(&pos))/*cast due to .constrained prefix*/).ToString();
				log.LogInfo((object)string.Concat(obj));
			}
			RegisterAssets(prefabDesc);
			int num = Array.IndexOf(((ProtoSet<ItemProto>)(object)LDB.items).dataArray, TrashItem);
			if (num < 0)
			{
				num = TrashItem.index;
			}
			TrashItem.Preload(num);
			int num2 = Array.IndexOf(((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray, TrashRecipe);
			if (num2 < 0)
			{
				num2 = TrashRecipe.index;
			}
			TrashRecipe.Preload(num2);
			if (AutomationTech != null && TrashRecipe.preTech == null)
			{
				TrashRecipe.preTech = AutomationTech;
			}
			if ((Object)(object)TrashItem.iconSprite == (Object)null)
			{
				Log.LogWarning((object)"Trash building icon was not loaded.");
			}
			SyncStorageTables();
			PlaceBuildBar();
			Log.LogInfo((object)"Post-add setup finished.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("OnPostAddData failed: " + ex));
		}
	}

	private static void AssignModelEntries()
	{
		if ((Object)(object)LDB.models == (Object)null)
		{
			return;
		}
		ModelProto[] array = LDB.models.modelArray;
		if (array == null)
		{
			array = (ModelProto[])(object)new ModelProto[Math.Max(ModelId + 1, 728)];
			LDB.models.modelArray = array;
		}
		else if (ModelId >= array.Length)
		{
			Array.Resize(ref array, ModelId + 64);
			LDB.models.modelArray = array;
		}
		array[ModelId] = TrashModel;
		if (714 != ModelId && 714 < array.Length)
		{
			ModelProto val = array[714];
			if (val == null || (((Proto)val).ID == 714 && string.IsNullOrEmpty(val.PrefabPath)))
			{
				array[714] = TrashModel;
				Log.LogInfo((object)("Registered legacy model alias " + 714 + " for saves from older versions."));
			}
		}
	}

	private static bool IsLegacyModelAliasActive()
	{
		ModelProto[] array = (((Object)(object)LDB.models != (Object)null) ? LDB.models.modelArray : null);
		if (array != null && 714 < array.Length)
		{
			return array[714] == TrashModel;
		}
		return false;
	}

	private static void FixPrefabDescCache()
	{
		try
		{
			PrefabDesc[] array = PlanetFactory.PrefabDescByModelIndex;
			if (array == null)
			{
				PlanetFactory.InitPrefabDescArray();
				array = PlanetFactory.PrefabDescByModelIndex;
			}
			if (array == null)
			{
				Log.LogWarning((object)"PrefabDesc cache is unavailable.");
				return;
			}
			int modelId = ModelId;
			if (modelId >= 0)
			{
				bool flag = IsLegacyModelAliasActive();
				int num = ((flag && 714 > modelId) ? 714 : modelId);
				if (num >= array.Length)
				{
					Array.Resize(ref array, num + 64);
					PlanetFactory.PrefabDescByModelIndex = array;
				}
				array[modelId] = TrashModel.prefabDesc;
				if (flag)
				{
					array[714] = TrashModel.prefabDesc;
				}
				Log.LogInfo((object)("PrefabDesc cache entries are ready: " + modelId + (flag ? (" and " + 714) : "")));
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not update the PrefabDesc cache: " + ex.Message));
		}
	}

	private static void SyncStorageTables()
	{
		int iD = ((Proto)TrashItem).ID;
		if (iD >= 0 && iD < 12000)
		{
			if (StorageComponent.itemStackCount != null && iD < StorageComponent.itemStackCount.Length)
			{
				StorageComponent.itemStackCount[iD] = TrashItem.StackSize;
			}
			if (StorageComponent.itemIsFuel != null && iD < StorageComponent.itemIsFuel.Length)
			{
				StorageComponent.itemIsFuel[iD] = TrashItem.HeatValue > 0;
			}
			if (StorageComponent.itemIsAmmo != null && iD < StorageComponent.itemIsAmmo.Length)
			{
				StorageComponent.itemIsAmmo[iD] = false;
			}
			if (StorageComponent.itemIsBomb != null && iD < StorageComponent.itemIsBomb.Length)
			{
				StorageComponent.itemIsBomb[iD] = false;
			}
			if (StorageComponent.itemIsFighter != null && iD < StorageComponent.itemIsFighter.Length)
			{
				StorageComponent.itemIsFighter[iD] = false;
			}
		}
	}

	private static void PlaceBuildBar()
	{
		int num = TrashCanPrefab.PreferredBuildCategory();
		if (num <= 0 || num > 12)
		{
			num = 1;
		}
		int num2 = FindFreeSlot(num);
		if (num2 == 0)
		{
			for (int i = 1; i <= 12; i++)
			{
				if (i != num)
				{
					num2 = FindFreeSlot(i);
					if (num2 != 0)
					{
						num = i;
						break;
					}
				}
			}
		}
		if (num2 == 0)
		{
			Log.LogError((object)"No free build-menu slot was found.");
			return;
		}
		TrashItem.BuildIndex = num * 100 + num2;
		LDBTool.SetBuildBar(num, num2, ((Proto)TrashItem).ID);
		Log.LogInfo((object)("Build bar placement: category " + num + ", slot " + num2 + " (BuildIndex " + TrashItem.BuildIndex + ")."));
	}

	private static int FindFreeSlot(int category)
	{
		bool[] array = new bool[10];
		for (int i = 0; i < ((ProtoSet<ItemProto>)(object)LDB.items).dataArray.Length; i++)
		{
			ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray[i];
			if (val == null || ((Proto)val).ID == ItemId)
			{
				continue;
			}
			int buildIndex = val.BuildIndex;
			if (buildIndex / 100 == category)
			{
				int num = buildIndex % 100;
				if (num >= 1 && num <= 9)
				{
					array[num] = true;
				}
			}
		}
		for (int j = 1; j <= 9; j++)
		{
			if (!array[j])
			{
				return j;
			}
		}
		return 0;
	}

	private static void RegisterAssets(PrefabDesc pd)
	{
		if (pd == null)
		{
			return;
		}
		SaveAsset("SaveGameObjectResources", pd.prefab);
		SaveAsset("SaveGameObjectResources", pd.colliderPrefab);
		SaveAsset("SaveObject", pd.mesh);
		SaveAsset("SaveMeshes", pd.meshes);
		SaveAsset("SaveObject", pd.meshCollider);
		SaveAsset("SaveMaterials", pd.materials);
		SaveAsset("SaveMeshes", pd.lodMeshes);
		if (pd.lodMaterials != null)
		{
			for (int i = 0; i < pd.lodMaterials.Length; i++)
			{
				SaveAsset("SaveMaterials", pd.lodMaterials[i]);
			}
		}
	}

	private static void SaveAsset(string methodName, object arg)
	{
		if (arg == null)
		{
			return;
		}
		try
		{
			MethodInfo[] methods = typeof(VFPreload).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != methodName)
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 1)
				{
					Type parameterType = parameters[0].ParameterType;
					if (parameterType.IsInstanceOfType(arg) || parameterType.IsAssignableFrom(arg.GetType()))
					{
						methodInfo.Invoke(null, new object[1] { arg });
						break;
					}
				}
			}
		}
		catch (Exception)
		{
		}
	}
}
internal static class TrashCanPrefab
{
	internal const string FakePrefabPath = "assets/dsptrashcan/building/trashcan";

	internal const string FakeIconPath = "assets/dsptrashcan/building/icon";

	private const string IconResourceName = "DSPTrashBuilding.icon.png";

	private const float FallbackY = -100000f;

	private static GameObject cachedPrefab;

	private static Sprite cachedIcon;

	private static Sprite cachedVanillaIcon;

	private static Mesh previewMesh;

	private static Material[] previewMaterials;

	private static int donorItemId;

	private static bool failed;

	private static Material trashBodyMaterial;

	private static Texture2D trashBodyTexture;

	internal static bool HandleResourcesLoad(string path, ref Object result)
	{
		switch (path)
		{
		case "assets/dsptrashcan/building/trashcan":
			result = (Object)(object)GetOrCreatePrefab();
			return false;
		case "assets/dsptrashcan/building/trashcan-cl":
			result = null;
			return false;
		case "assets/dsptrashcan/building/icon":
			result = (Object)(object)GetIcon();
			return false;
		default:
			return true;
		}
	}

	internal static Sprite GetIcon()
	{
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Expected O, but got Unknown
		//IL_0101: 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)
		if ((Object)(object)cachedIcon != (Object)null)
		{
			return cachedIcon;
		}
		Sprite val = TryRenderIcon();
		if ((Object)(object)val != (Object)null)
		{
			cachedIcon = val;
			return cachedIcon;
		}
		Sprite vanillaIcon = GetVanillaIcon();
		if ((Object)(object)vanillaIcon != (Object)null)
		{
			cachedIcon = vanillaIcon;
			return cachedIcon;
		}
		try
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			Stream manifestResourceStream = executingAssembly.GetManifestResourceStream("DSPTrashBuilding.icon.png");
			if (manifestResourceStream == null)
			{
				string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
				for (int i = 0; i < manifestResourceNames.Length; i++)
				{
					if (manifestResourceNames[i].EndsWith(".icon.png", StringComparison.OrdinalIgnoreCase))
					{
						manifestResourceStream = executingAssembly.GetManifestResourceStream(manifestResourceNames[i]);
						break;
					}
				}
			}
			if (manifestResourceStream != null)
			{
				using (manifestResourceStream)
				{
					using MemoryStream memoryStream = new MemoryStream();
					manifestResourceStream.CopyTo(memoryStream);
					Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, false);
					ImageConversion.LoadImage(val2, memoryStream.ToArray());
					((Texture)val2).wrapMode = (TextureWrapMode)1;
					((Texture)val2).filterMode = (FilterMode)1;
					((Object)val2).hideFlags = (HideFlags)61;
					cachedIcon = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f), 100f);
					((Object)cachedIcon).hideFlags = (HideFlags)61;
				}
			}
		}
		catch (Exception ex)
		{
			LogWarning("Icon load failed: " + ex.Message);
		}
		if ((Object)(object)cachedIcon == (Object)null)
		{
			cachedIcon = CreateFallbackIcon();
		}
		return cachedIcon;
	}

	private static Sprite TryRenderIcon()
	{
		//IL_0525: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Unknown result type (might be due to invalid IL or missing references)
		//IL_053d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0549: Unknown result type (might be due to invalid IL or missing references)
		//IL_0555: Unknown result type (might be due to invalid IL or missing references)
		//IL_0561: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: 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_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Expected O, but got Unknown
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: 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_01a4: Expected O, but got Unknown
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0231: Unknown result type (might be due to invalid IL or missing references)
		//IL_0241: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Expected O, but got Unknown
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_0283: Unknown result type (might be due to invalid IL or missing references)
		//IL_0285: Unknown result type (might be due to invalid IL or missing references)
		//IL_028a: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0307: Unknown result type (might be due to invalid IL or missing references)
		//IL_0325: Unknown result type (might be due to invalid IL or missing references)
		//IL_0343: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03af: Expected O, but got Unknown
		//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_046e: Unknown result type (might be due to invalid IL or missing references)
		//IL_047d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)previewMesh == (Object)null || previewMaterials == null || previewMaterials.Length == 0)
		{
			return null;
		}
		GameObject val = null;
		GameObject val2 = null;
		GameObject val3 = null;
		RenderTexture val4 = null;
		Texture2D val5 = null;
		Texture2D val6 = null;
		Color globalColor = Shader.GetGlobalColor("_Global_AmbientColor0");
		Color globalColor2 = Shader.GetGlobalColor("_Global_AmbientColor1");
		Color globalColor3 = Shader.GetGlobalColor("_Global_AmbientColor2");
		Color globalColor4 = Shader.GetGlobalColor("_Global_Biomo_Color0");
		Color globalColor5 = Shader.GetGlobalColor("_Global_Biomo_Color1");
		Color globalColor6 = Shader.GetGlobalColor("_Global_Biomo_Color2");
		float globalFloat = Shader.GetGlobalFloat("_Global_Planet_Radius");
		float globalFloat2 = Shader.GetGlobalFloat("_Global_Cut_Underground");
		Texture globalTexture = Shader.GetGlobalTexture("_Global_UGI");
		try
		{
			val = new GameObject("DSPTrashCan_IconPreview");
			((Object)val).hideFlags = (HideFlags)61;
			val.transform.position = new Vector3(50000f, 0f, 50000f);
			val.transform.rotation = Quaternion.identity;
			val.AddComponent<MeshFilter>().sharedMesh = previewMesh;
			((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterials = previewMaterials;
			if (!TryGetBounds(val, out var bounds))
			{
				return null;
			}
			Vector3 center = ((Bounds)(ref bounds)).center;
			float num = Mathf.Max(0.1f, Mathf.Max(((Bounds)(ref bounds)).extents.x, Mathf.Max(((Bounds)(ref bounds)).extents.y, ((Bounds)(ref bounds)).extents.z)));
			Vector3 val7 = new Vector3(0.9f, 0.68f, 1.15f);
			Vector3 normalized = ((Vector3)(ref val7)).normalized;
			Quaternion val8 = Quaternion.LookRotation(-normalized, Vector3.up);
			float orthographicSize = ComputeProjectedHalfSize(previewMesh, val.transform, center, val8, num);
			val2 = new GameObject("DSPTrashCan_IconCamera");
			((Object)val2).hideFlags = (HideFlags)61;
			Camera obj = val2.AddComponent<Camera>();
			((Behaviour)obj).enabled = false;
			obj.orthographic = true;
			obj.orthographicSize = orthographicSize;
			obj.clearFlags = (CameraClearFlags)2;
			obj.backgroundColor = new Color(0f, 0f, 0f, 0f);
			obj.cullingMask = -1;
			obj.nearClipPlane = 0.05f;
			obj.farClipPlane = num * 8f + 4f;
			((Component)obj).transform.position = center + normalized * (num * 4f + 3f);
			((Component)obj).transform.rotation = val8;
			val3 = new GameObject("DSPTrashCan_IconLight");
			((Object)val3).hideFlags = (HideFlags)61;
			Light obj2 = val3.AddComponent<Light>();
			obj2.type = (LightType)1;
			obj2.color = Color.white;
			obj2.intensity = 1f;
			((Component)obj2).transform.rotation = Quaternion.LookRotation(-normalized, Vector3.up);
			Shader.SetGlobalColor("_Global_AmbientColor0", new Color(0.62f, 0.66f, 0.7f));
			Shader.SetGlobalColor("_Global_AmbientColor1", new Color(0.45f, 0.5f, 0.55f));
			Shader.SetGlobalColor("_Global_AmbientColor2", new Color(0.3f, 0.34f, 0.38f));
			Shader.SetGlobalColor("_Global_Biomo_Color0", new Color(0.55f, 0.58f, 0.6f));
			Shader.SetGlobalColor("_Global_Biomo_Color1", new Color(0.42f, 0.46f, 0.48f));
			Shader.SetGlobalColor("_Global_Biomo_Color2", new Color(0.3f, 0.34f, 0.36f));
			Shader.SetGlobalFloat("_Global_Planet_Radius", 200f);
			Shader.SetGlobalFloat("_Global_Cut_Underground", 1f);
			Shader.SetGlobalTexture("_Global_UGI", (Texture)null);
			val4 = (obj.targetTexture = RenderTexture.GetTemporary(256, 256, 24, (RenderTextureFormat)0));
			obj.Render();
			RenderTexture.active = val4;
			val5 = new Texture2D(256, 256, (TextureFormat)4, false);
			val5.ReadPixels(new Rect(0f, 0f, 256f, 256f), 0, 0);
			val5.Apply();
			RenderTexture.active = null;
			obj.targetTexture = null;
			Color32[] pixels = val5.GetPixels32();
			int num2 = 0;
			for (int i = 0; i < pixels.Length; i++)
			{
				if (pixels[i].a > 32)
				{
					num2++;
				}
			}
			if (num2 < 256)
			{
				LogWarning("Rendered icon was empty (" + num2 + " pixels); using the fallback icon.");
				return null;
			}
			val6 = DownscaleIcon(val5, 80);
			Sprite val9 = Sprite.Create(val6, new Rect(0f, 0f, (float)((Texture)val6).width, (float)((Texture)val6).height), new Vector2(0.5f, 0.5f), 100f);
			((Object)val9).hideFlags = (HideFlags)61;
			LogInfo("Rendered the trash building icon (" + num2 + " visible pixels, " + ((Texture)val6).width + "x" + ((Texture)val6).height + ").");
			return val9;
		}
		catch (Exception ex)
		{
			LogWarning("Icon render failed: " + ex.Message);
			return null;
		}
		finally
		{
			Shader.SetGlobalColor("_Global_AmbientColor0", globalColor);
			Shader.SetGlobalColor("_Global_AmbientColor1", globalColor2);
			Shader.SetGlobalColor("_Global_AmbientColor2", globalColor3);
			Shader.SetGlobalColor("_Global_Biomo_Color0", globalColor4);
			Shader.SetGlobalColor("_Global_Biomo_Color1", globalColor5);
			Shader.SetGlobalColor("_Global_Biomo_Color2", globalColor6);
			Shader.SetGlobalFloat("_Global_Planet_Radius", globalFloat);
			Shader.SetGlobalFloat("_Global_Cut_Underground", globalFloat2);
			Shader.SetGlobalTexture("_Global_UGI", globalTexture);
			RenderTexture.active = null;
			if ((Object)(object)val4 != (Object)null)
			{
				RenderTexture.ReleaseTemporary(val4);
			}
			if ((Object)(object)val5 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)val5);
			}
			if ((Object)(object)val2 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)val2);
			}
			if ((Object)(object)val3 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)val3);
			}
			if ((Object)(object)val != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)val);
			}
		}
	}

	private static float ComputeProjectedHalfSize(Mesh mesh, Transform transform, Vector3 center, Quaternion viewRotation, float fallbackRadius)
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: 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_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		float result = Mathf.Max(0.1f, fallbackRadius * 1.3f);
		if ((Object)(object)mesh == (Object)null || (Object)(object)transform == (Object)null)
		{
			return result;
		}
		Vector3[] vertices;
		try
		{
			vertices = mesh.vertices;
		}
		catch (Exception)
		{
			return result;
		}
		if (vertices == null || vertices.Length == 0)
		{
			return result;
		}
		Quaternion val = Quaternion.Inverse(viewRotation);
		float num = 0.01f;
		float num2 = 0.01f;
		for (int i = 0; i < vertices.Length; i++)
		{
			Vector3 val2 = transform.TransformPoint(vertices[i]);
			Vector3 val3 = val * (val2 - center);
			float num3 = Mathf.Abs(val3.x);
			float num4 = Mathf.Abs(val3.y);
			if (num3 > num)
			{
				num = num3;
			}
			if (num4 > num2)
			{
				num2 = num4;
			}
		}
		float num5 = Mathf.Max(num, num2) * 1.12f;
		return Mathf.Max(0.1f, num5);
	}

	private static Texture2D DownscaleIcon(Texture2D source, int size)
	{
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: 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_0142: 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_0150: Expected O, but got Unknown
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		int width = ((Texture)source).width;
		Color32[] pixels = source.GetPixels32();
		Color32[] array = (Color32[])(object)new Color32[size * size];
		for (int i = 0; i < size; i++)
		{
			int num = i * width / size;
			int num2 = Mathf.Max(num + 1, (i + 1) * width / size);
			for (int j = 0; j < size; j++)
			{
				int num3 = j * width / size;
				int num4 = Mathf.Max(num3 + 1, (j + 1) * width / size);
				int num5 = 0;
				int num6 = 0;
				int num7 = 0;
				int num8 = 0;
				int num9 = 0;
				for (int k = num; k < num2; k++)
				{
					int num10 = k * width;
					for (int l = num3; l < num4; l++)
					{
						Color32 val = pixels[num10 + l];
						num5 += val.r;
						num6 += val.g;
						num7 += val.b;
						num8 += val.a;
						num9++;
					}
				}
				array[i * size + j] = new Color32((byte)(num5 / num9), (byte)(num6 / num9), (byte)(num7 / num9), (byte)(num8 / num9));
			}
		}
		Texture2D val2 = new Texture2D(size, size, (TextureFormat)4, false)
		{
			name = "DSPTrashCan_Icon",
			wrapMode = (TextureWrapMode)1,
			filterMode = (FilterMode)1,
			hideFlags = (HideFlags)61
		};
		val2.SetPixels32(array);
		val2.Apply();
		return val2;
	}

	private static bool TryGetBounds(GameObject root, out Bounds bounds)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: 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_0068: 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_003b: 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)
		Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
		bool flag = false;
		bounds = new Bounds(root.transform.position, Vector3.zero);
		foreach (Renderer val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null))
			{
				if (!flag)
				{
					bounds = val.bounds;
					flag = true;
				}
				else
				{
					((Bounds)(ref bounds)).Encapsulate(val.bounds);
				}
			}
		}
		if (flag)
		{
			Vector3 size = ((Bounds)(ref bounds)).size;
			return ((Vector3)(ref size)).sqrMagnitude > 0.0001f;
		}
		return false;
	}

	private static Sprite GetVanillaIcon()
	{
		if ((Object)(object)cachedVanillaIcon != (Object)null)
		{
			return cachedVanillaIcon;
		}
		try
		{
			int num = ((donorItemId > 0) ? donorItemId : 2206);
			ItemProto val = (((Object)(object)LDB.items != (Object)null) ? ((ProtoSet<ItemProto>)(object)LDB.items).Select(num) : null);
			if (val == null)
			{
				return null;
			}
			if ((Object)(object)val.iconSprite != (Object)null)
			{
				cachedVanillaIcon = val.iconSprite;
			}
			else if (!string.IsNullOrEmpty(val.IconPath))
			{
				cachedVanillaIcon = Resources.Load<Sprite>(val.IconPath);
			}
			if ((Object)(object)cachedVanillaIcon != (Object)null)
			{
				LogInfo("Using the donor item icon (" + ((Proto)val).ID + ").");
			}
			else
			{
				LogWarning("The donor item icon was not loaded; using the bundled icon.");
			}
		}
		catch (Exception ex)
		{
			LogWarning("Donor icon load failed: " + ex.Message);
		}
		return cachedVanillaIcon;
	}

	private static Sprite CreateFallbackIcon()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color val2 = default(Color);
		((Color)(ref val2))..ctor(0.07f, 0.15f, 0.21f, 1f);
		Color val3 = default(Color);
		((Color)(ref val3))..ctor(0.16f, 0.36f, 0.25f, 1f);
		Color val4 = default(Color);
		((Color)(ref val4))..ctor(0.72f, 0.78f, 0.8f, 1f);
		Color[] array = (Color[])(object)new Color[4096];
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = val2;
		}
		for (int j = 18; j < 46; j++)
		{
			for (int k = 18; k < 46; k++)
			{
				array[j * 64 + k] = val3;
			}
		}
		for (int l = 46; l < 52; l++)
		{
			for (int m = 14; m < 50; m++)
			{
				array[l * 64 + m] = val4;
			}
		}
		for (int n = 52; n < 57; n++)
		{
			for (int num = 26; num < 38; num++)
			{
				array[n * 64 + num] = val4;
			}
		}
		for (int num2 = 24; num2 < 42; num2++)
		{
			for (int num3 = 24; num3 < 27; num3++)
			{
				array[num2 * 64 + num3] = val2;
			}
			for (int num4 = 31; num4 < 34; num4++)
			{
				array[num2 * 64 + num4] = val2;
			}
			for (int num5 = 38; num5 < 41; num5++)
			{
				array[num2 * 64 + num5] = val2;
			}
		}
		val.SetPixels(array);
		val.Apply();
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)1;
		((Object)val).hideFlags = (HideFlags)61;
		Sprite obj = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f);
		((Object)obj).hideFlags = (HideFlags)61;
		return obj;
	}

	internal static GameObject GetOrCreatePrefab()
	{
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)cachedPrefab != (Object)null)
		{
			return cachedPrefab;
		}
		if (failed)
		{
			return null;
		}
		try
		{
			cachedPrefab = BuildPrefab();
			if ((Object)(object)cachedPrefab == (Object)null)
			{
				failed = true;
				LogError("Trash building prefab construction failed.");
			}
			else
			{
				((Object)cachedPrefab).name = "DSPTrashCan_Prefab";
				((Object)cachedPrefab).hideFlags = (HideFlags)61;
				cachedPrefab.transform.position = Vector3.zero;
				cachedPrefab.SetActive(true);
			}
		}
		catch (Exception ex)
		{
			failed = true;
			LogError("Trash building prefab construction crashed: " + ex);
		}
		return cachedPrefab;
	}

	private unsafe static GameObject BuildPrefab()
	{
		//IL_028c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: 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_01ef: Unknown result type (might be due to invalid IL or missing references)
		ItemProto val = FindStorageSource();
		if (val == null || val.prefabDesc == null || (Object)(object)val.prefabDesc.prefab == (Object)null)
		{
			LogError("No vanilla storage prefab is available.");
			return null;
		}
		GameObject val2 = Object.Instantiate<GameObject>(val.prefabDesc.prefab);
		((Object)val2).hideFlags = (HideFlags)61;
		val2.SetActive(false);
		LogInfo("Using storage source item " + ((Proto)val).ID + " (sorterSlots=" + ((val.prefabDesc.slotPoses != null) ? val.prefabDesc.slotPoses.Length : 0) + ").");
		ItemProto val3 = FindDonor();
		if (val3 != null && val3.prefabDesc != null && (Object)(object)val3.prefabDesc.prefab != (Object)null)
		{
			GameObject val4 = Object.Instantiate<GameObject>(val3.prefabDesc.prefab);
			((Object)val4).hideFlags = (HideFlags)61;
			val4.SetActive(false);
			donorItemId = ((Proto)val3).ID;
			string[] obj = new string[5]
			{
				"Using visual donor item ",
				((Proto)val3).ID.ToString(),
				" (size=",
				null,
				null
			};
			Vector3 selectSize = val3.prefabDesc.selectSize;
			obj[3] = ((object)(*(Vector3*)(&selectSize))/*cast due to .constrained prefix*/).ToString();
			obj[4] = ").";
			LogInfo(string.Concat(obj));
			RemoveFunctionalDescriptors(val4);
			CopySlotConfig(val2, null, val4);
			SetStorageSize(val4, 10, 2);
			CopyBuildCondition(val2, val4);
			TintPrefab(val4);
			SlotConfig componentInChildren = val4.GetComponentInChildren<SlotConfig>(true);
			bool flag = (Object)(object)componentInChildren != (Object)null && componentInChildren.insertPoses != null && componentInChildren.insertPoses.Length != 0;
			bool flag2 = (Object)(object)val4.GetComponentInChildren<Renderer>(true) != (Object)null || (Object)(object)val4.GetComponentInChildren<LODModelDesc>(true) != (Object)null;
			if (flag && flag2)
			{
				((Object)val4).name = "DSPTrashCan_Prefab";
				val4.transform.position = Vector3.zero;
				val4.SetActive(true);
				Object.DestroyImmediate((Object)(object)val2);
				LogInfo("Built trash building from donor item " + ((Proto)val3).ID + ".");
				return val4;
			}
			LogWarning("Donor prefab validation failed (sorterSlots=" + flag + ", visual=" + flag2 + "); using the storage model instead.");
			Object.DestroyImmediate((Object)(object)val4);
		}
		SetStorageSize(val2, 10, 2);
		TintPrefab(val2);
		((Object)val2).name = "DSPTrashCan_Prefab";
		val2.transform.position = Vector3.zero;
		val2.SetActive(true);
		LogInfo("Built trash building from the vanilla storage model.");
		return val2;
	}

	internal static int PreferredBuildCategory()
	{
		ItemProto val = FindStorageSource();
		if (val != null && val.BuildIndex > 0)
		{
			return val.BuildIndex / 100;
		}
		return 1;
	}

	internal static void ReshapeModel(PrefabDesc desc)
	{
		if (desc == null)
		{
			return;
		}
		Dictionary<Mesh, Mesh> copies = new Dictionary<Mesh, Mesh>();
		if ((Object)(object)desc.mesh != (Object)null)
		{
			desc.mesh = GetReshapedMesh(desc.mesh, copies);
		}
		if (desc.meshes != null)
		{
			for (int i = 0; i < desc.meshes.Length; i++)
			{
				desc.meshes[i] = GetReshapedMesh(desc.meshes[i], copies);
			}
		}
		if (desc.lodMeshes != null)
		{
			for (int j = 0; j < desc.lodMeshes.Length; j++)
			{
				desc.lodMeshes[j] = GetReshapedMesh(desc.lodMeshes[j], copies);
			}
		}
		if (desc.lodCount > 0 && desc.lodMeshes != null && desc.lodMeshes.Length != 0 && (Object)(object)desc.lodMeshes[0] != (Object)null && desc.lodMaterials != null && desc.lodMaterials.Length != 0 && desc.lodMaterials[0] != null)
		{
			previewMesh = desc.lodMeshes[0];
			previewMaterials = desc.lodMaterials[0];
		}
		else
		{
			previewMesh = desc.mesh;
			previewMaterials = desc.materials;
		}
		LogInfo("Reshaped runtime model: lodCount=" + desc.lodCount + " lodMeshes=" + ((desc.lodMeshes != null) ? desc.lodMeshes.Length : 0) + " lodVertas=" + (desc.lodVertas != null) + " materials=" + ((previewMaterials != null) ? previewMaterials.Length : 0));
	}

	private static Mesh GetReshapedMesh(Mesh source, Dictionary<Mesh, Mesh> copies)
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: 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_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_019a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)source == (Object)null)
		{
			return null;
		}
		if (copies.TryGetValue(source, out var value))
		{
			return value;
		}
		Mesh val = Object.Instantiate<Mesh>(source);
		((Object)val).name = ((Object)source).name + "_Trash";
		((Object)val).hideFlags = (HideFlags)61;
		Vector3[] vertices = val.vertices;
		Bounds bounds = source.bounds;
		float y = ((Bounds)(ref bounds)).min.y;
		float num = Mathf.Max(0.01f, ((Bounds)(ref bounds)).size.y);
		for (int i = 0; i < vertices.Length; i++)
		{
			float num2 = Mathf.Clamp01((vertices[i].y - y) / num);
			float num3 = Mathf.Lerp(1.12f, 0.78f, num2);
			vertices[i].x *= num3;
			vertices[i].z *= num3;
			vertices[i].y = y + (vertices[i].y - y) * 0.9f;
		}
		val.vertices = vertices;
		Color[] colors = val.colors;
		if (colors != null && colors.Length == vertices.Length)
		{
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(1f, 0.97f, 0.95f, 1f);
			for (int j = 0; j < colors.Length; j++)
			{
				colors[j] = new Color(colors[j].r * val2.r, colors[j].g * val2.g, colors[j].b * val2.b, colors[j].a);
			}
			val.colors = colors;
		}
		val.RecalculateBounds();
		copies[source] = val;
		return val;
	}

	private static Material FindBaseMaterial(GameObject root)
	{
		Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Material[] sharedMaterials = componentsInChildren[i].sharedMaterials;
			if (sharedMaterials == null)
			{
				continue;
			}
			for (int j = 0; j < sharedMaterials.Length; j++)
			{
				if ((Object)(object)sharedMaterials[j] != (Object)null)
				{
					return sharedMaterials[j];
				}
			}
		}
		return null;
	}

	private static bool BuildCustomVisuals(GameObject root, Material baseMaterial)
	{
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: 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_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: 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_0158: 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)
		//IL_017e: 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_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f1: 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_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_024b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0265: Unknown result type (might be due to invalid IL or missing references)
		//IL_0279: Unknown result type (might be due to invalid IL or missing references)
		//IL_0285: Unknown result type (might be due to invalid IL or missing references)
		//IL_029f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0313: 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_0333: Unknown result type (might be due to invalid IL or missing references)
		//IL_034d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0361: Unknown result type (might be due to invalid IL or missing references)
		//IL_036d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0387: Unknown result type (might be due to invalid IL or missing references)
		//IL_039b: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0405: Unknown result type (might be due to invalid IL or missing references)
		//IL_040a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0420: Unknown result type (might be due to invalid IL or missing references)
		//IL_0425: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)baseMaterial == (Object)null)
		{
			return false;
		}
		MeshRenderer[] componentsInChildren = root.GetComponentsInChildren<MeshRenderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
		}
		MeshFilter[] componentsInChildren2 = root.GetComponentsInChildren<MeshFilter>(true);
		for (int j = 0; j < componentsInChildren2.Length; j++)
		{
			Object.DestroyImmediate((Object)(object)componentsInChildren2[j]);
		}
		LODModelDesc[] componentsInChildren3 = root.GetComponentsInChildren<LODModelDesc>(true);
		for (int k = 0; k < componentsInChildren3.Length; k++)
		{
			Object.DestroyImmediate((Object)(object)componentsInChildren3[k]);
		}
		Material material = CreateTintedMaterial(baseMaterial, "TrashBody", new Color(0.11f, 0.24f, 0.17f), 0.3f);
		Material material2 = CreateTintedMaterial(baseMaterial, "TrashMetal", new Color(0.44f, 0.49f, 0.51f), 0.75f);
		Material material3 = CreateTintedMaterial(baseMaterial, "TrashDark", new Color(0.05f, 0.06f, 0.07f), 0.2f);
		Material material4 = CreateGlowMaterial(baseMaterial, "TrashGlow", new Color(0.22f, 0.95f, 0.42f));
		GameObject val = new GameObject("TrashCanVisual")
		{
			hideFlags = (HideFlags)61
		};
		val.transform.SetParent(root.transform, false);
		AddCylinder(val.transform, "Base", new Vector3(0f, 0.1f, 0f), new Vector3(2f, 0.1f, 2f), material3);
		AddCylinder(val.transform, "Body", new Vector3(0f, 1.14f, 0f), new Vector3(1.84f, 0.95f, 1.84f), material);
		AddCylinder(val.transform, "Rim", new Vector3(0f, 2.12f, 0f), new Vector3(2f, 0.06f, 2f), material2);
		AddCylinder(val.transform, "Lid", new Vector3(0f, 2.24f, 0f), new Vector3(2.04f, 0.05f, 2.04f), material2);
		AddCube(val.transform, "Handle", new Vector3(0f, 2.33f, 0f), new Vector3(0.52f, 0.1f, 0.18f), material2);
		AddCylinder(val.transform, "GlowRing", new Vector3(0f, 2.03f, 0f), new Vector3(1.92f, 0.018f, 1.92f), material4);
		AddCube(val.transform, "Inlet", new Vector3(0f, 1.26f, 0.925f), new Vector3(0.62f, 0.5f, 0.05f), material3);
		AddCube(val.transform, "Indicator", new Vector3(0f, 1.57f, 0.952f), new Vector3(0.2f, 0.06f, 0.02f), material4);
		AddCube(val.transform, "Foot1", new Vector3(0.72f, 0.06f, 0.72f), new Vector3(0.2f, 0.12f, 0.2f), material3);
		AddCube(val.transform, "Foot2", new Vector3(-0.72f, 0.06f, 0.72f), new Vector3(0.2f, 0.12f, 0.2f), material3);
		AddCube(val.transform, "Foot3", new Vector3(0.72f, 0.06f, -0.72f), new Vector3(0.2f, 0.12f, 0.2f), material3);
		AddCube(val.transform, "Foot4", new Vector3(-0.72f, 0.06f, -0.72f), new Vector3(0.2f, 0.12f, 0.2f), material3);
		SlotConfig componentInChildren = root.GetComponentInChildren<SlotConfig>(true);
		if ((Object)(object)componentInChildren != (Object)null)
		{
			componentInChildren.selectCenter = new Vector3(0f, 1.2f, 0f);
			componentInChildren.selectSize = new Vector3(2.3f, 2.6f, 2.3f);
			componentInChildren.selectAlpha = 0.5f;
		}
		previewMesh = BuildCombinedMesh(val.transform, out previewMaterials);
		return true;
	}

	internal static void ApplyPreviewMesh(PrefabDesc desc)
	{
		if (desc == null || (Object)(object)previewMesh == (Object)null || previewMaterials == null || previewMaterials.Length == 0)
		{
			return;
		}
		desc.mesh = previewMesh;
		desc.meshes = (Mesh[])(object)new Mesh[1] { previewMesh };
		desc.materials = previewMaterials;
		desc.lodCount = 1;
		desc.lodMeshes = (Mesh[])(object)new Mesh[1] { previewMesh };
		desc.lodMaterials = new Material[1][] { previewMaterials };
		desc.lodBlueprintMaterials = new Material[1][] { previewMaterials };
		desc.lodDistances = new float[1] { 100000f };
		desc.lodSubmeshIgnores = new bool[1][] { new bool[previewMaterials.Length] };
		try
		{
			PrefabDesc[] prefabDescByModelIndex = PlanetFactory.PrefabDescByModelIndex;
			int modelIndex = desc.modelIndex;
			if (prefabDescByModelIndex != null && modelIndex >= 0 && modelIndex < prefabDescByModelIndex.Length)
			{
				prefabDescByModelIndex[modelIndex] = desc;
			}
		}
		catch (Exception)
		{
		}
		if (Plugin.Log != null)
		{
			Plugin.Log.LogInfo((object)("Runtime model published: lodCount=" + desc.lodCount + " lodMeshes=" + desc.lodMeshes.Length + " subMeshes=" + previewMesh.subMeshCount + " materials=" + previewMaterials.Length));
		}
	}

	private static Mesh BuildCombinedMesh(Transform visual, out Material[] materials)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e5: Expected O, but got Unknown
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: 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)
		List<Vector3> list = new List<Vector3>();
		List<Vector3> list2 = new List<Vector3>();
		List<Vector2> list3 = new List<Vector2>();
		List<Material> list4 = new List<Material>();
		List<List<int>> list5 = new List<List<int>>();
		Matrix4x4 worldToLocalMatrix = visual.worldToLocalMatrix;
		MeshFilter[] componentsInChildren = ((Component)visual).GetComponentsInChildren<MeshFilter>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Mesh sharedMesh = componentsInChildren[i].sharedMesh;
			if ((Object)(object)sharedMesh == (Object)null)
			{
				continue;
			}
			Renderer component = ((Component)componentsInChildren[i]).GetComponent<Renderer>();
			Material item = (((Object)(object)component != (Object)null) ? component.sharedMaterial : null);
			int num = list4.IndexOf(item);
			if (num < 0)
			{
				num = list4.Count;
				list4.Add(item);
				list5.Add(new List<int>());
			}
			Matrix4x4 val = worldToLocalMatrix * ((Component)componentsInChildren[i]).transform.localToWorldMatrix;
			int count = list.Count;
			Vector3[] vertices = sharedMesh.vertices;
			for (int j = 0; j < vertices.Length; j++)
			{
				list.Add(((Matrix4x4)(ref val)).MultiplyPoint3x4(vertices[j]));
			}
			Vector3[] normals = sharedMesh.normals;
			if (normals != null && normals.Length == vertices.Length)
			{
				for (int k = 0; k < normals.Length; k++)
				{
					Vector3 val2 = ((Matrix4x4)(ref val)).MultiplyVector(normals[k]);
					list2.Add(((Vector3)(ref val2)).normalized);
				}
			}
			else
			{
				for (int l = 0; l < vertices.Length; l++)
				{
					list2.Add(Vector3.up);
				}
			}
			Vector2[] uv = sharedMesh.uv;
			for (int m = 0; m < vertices.Length; m++)
			{
				list3.Add((uv != null && m < uv.Length) ? uv[m] : Vector2.zero);
			}
			List<int> list6 = list5[num];
			int[] triangles = sharedMesh.triangles;
			for (int n = 0; n < triangles.Length; n++)
			{
				list6.Add(triangles[n] + count);
			}
		}
		Mesh val3 = new Mesh();
		((Object)val3).name = "DSPTrashCan_Model";
		((Object)val3).hideFlags = (HideFlags)61;
		val3.SetVertices(list);
		val3.SetNormals(list2);
		val3.SetUVs(0, list3);
		val3.subMeshCount = list5.Count;
		for (int num2 = 0; num2 < list5.Count; num2++)
		{
			val3.SetTriangles(list5[num2], num2);
		}
		val3.RecalculateBounds();
		materials = list4.ToArray();
		return val3;
	}

	private static void AddCylinder(Transform parent, string name, Vector3 position, Vector3 scale, Material material)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		GameObject obj = GameObject.CreatePrimitive((PrimitiveType)2);
		((Object)obj).name = name;
		((Object)obj).hideFlags = (HideFlags)61;
		obj.transform.SetParent(parent, false);
		obj.transform.localPosition = position;
		obj.transform.localScale = scale;
		Collider component = obj.GetComponent<Collider>();
		if ((Object)(object)component != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component);
		}
		Renderer component2 = obj.GetComponent<Renderer>();
		if ((Object)(object)component2 != (Object)null)
		{
			component2.sharedMaterial = material;
		}
	}

	private static void AddCube(Transform parent, string name, Vector3 position, Vector3 scale, Material material)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
		((Object)obj).name = name;
		((Object)obj).hideFlags = (HideFlags)61;
		obj.transform.SetParent(parent, false);
		obj.transform.localPosition = position;
		obj.transform.localScale = scale;
		Collider component = obj.GetComponent<Collider>();
		if ((Object)(object)component != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component);
		}
		Renderer component2 = obj.GetComponent<Renderer>();
		if ((Object)(object)component2 != (Object)null)
		{
			component2.sharedMaterial = material;
		}
	}

	private static Material CreateTintedMaterial(Material source, string name, Color color, float metallic)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		Material val = new Material(source);
		((Object)val).name = name;
		((Object)val).hideFlags = (HideFlags)61;
		if (val.HasProperty("_Color"))
		{
			val.color = color;
		}
		if (val.HasProperty("_BaseColor"))
		{
			val.SetColor("_BaseColor", color);
		}
		if (val.HasProperty("_TintColor"))
		{
			val.SetColor("_TintColor", color);
		}
		if (val.HasProperty("_Metallic"))
		{
			val.SetFloat("_Metallic", metallic);
		}
		if (val.HasProperty("_Glossiness"))
		{
			val.SetFloat("_Glossiness", 0.5f);
		}
		if (val.HasProperty("_GlossyReflections"))
		{
			val.SetFloat("_GlossyReflections", 0.5f);
		}
		return val;
	}

	private static Material CreateGlowMaterial(Material source, string name, Color color)
	{
		//IL_0002: 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_0032: Unknown result type (might be due to invalid IL or missing references)
		Material val = CreateTintedMaterial(source, name, color, 0f);
		if (val.HasProperty("_EmissionColor"))
		{
			val.EnableKeyword("_EMISSION");
			val.SetColor("_EmissionColor", color * 1.6f);
		}
		if (val.HasProperty("_Emission"))
		{
			val.SetFloat("_Emission", 1f);
		}
		return val;
	}

	private static ItemProto FindStorageSource()
	{
		ItemProto val = null;
		for (int i = 0; i < ((ProtoSet<ItemProto>)(object)LDB.items).dataArray.Length; i++)
		{
			ItemProto val2 = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray[i];
			if (val2 != null && ((Proto)val2).ID != Plugin.ItemId)
			{
				PrefabDesc prefabDesc = val2.prefabDesc;
				if (prefabDesc != null && !((Object)(object)prefabDesc.prefab == (Object)null) && prefabDesc.isStorage && !prefabDesc.isTank && !prefabDesc.isStation && !prefabDesc.isDispenser && !prefabDesc.isBattleBase && prefabDesc.storageCol > 0 && prefabDesc.storageRow > 0 && (val == null || prefabDesc.storageCol * prefabDesc.storageRow < val.prefabDesc.storageCol * val.prefabDesc.storageRow))
				{
					val = val2;
				}
			}
		}
		return val;
	}

	private unsafe static ItemProto FindDonor()
	{
		//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)
		ItemProto val = null;
		float num = float.MaxValue;
		for (int i = 0; i < ((ProtoSet<ItemProto>)(object)LDB.items).dataArray.Length; i++)
		{
			ItemProto val2 = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray[i];
			if (val2 == null || ((Proto)val2).ID == Plugin.ItemId)
			{
				continue;
			}
			PrefabDesc prefabDesc = val2.prefabDesc;
			if (prefabDesc == null || (Object)(object)prefabDesc.prefab == (Object)null || prefabDesc.isStorage || prefabDesc.isTank || prefabDesc.isStation || prefabDesc.isBattleBase || prefabDesc.isAssembler || prefabDesc.isLab || (!prefabDesc.isAccumulator && !prefabDesc.isSpraycoster && !prefabDesc.isPiler))
			{
				continue;
			}
			string[] obj = new string[12]
			{
				"Donor candidate: id=",
				((Proto)val2).ID.ToString(),
				" acc=",
				prefabDesc.isAccumulator.ToString(),
				" spray=",
				prefabDesc.isSpraycoster.ToString(),
				" piler=",
				prefabDesc.isPiler.ToString(),
				" size=",
				null,
				null,
				null
			};
			Vector3 selectSize = prefabDesc.selectSize;
			obj[9] = ((object)(*(Vector3*)(&selectSize))/*cast due to .constrained prefix*/).ToString();
			obj[10] = " beltPorts=";
			obj[11] = ((prefabDesc.portPoses != null) ? prefabDesc.portPoses.Length : 0).ToString();
			LogInfo(string.Concat(obj));
			if (!(prefabDesc.selectSize.x > 2.5f) && !(prefabDesc.selectSize.z > 2.5f))
			{
				float num2 = Mathf.Max(0.1f, prefabDesc.selectSize.x) * Mathf.Max(0.1f, prefabDesc.selectSize.z);
				if (prefabDesc.isAccumulator)
				{
					num2 -= 100f;
				}
				else if (prefabDesc.isSpraycoster)
				{
					num2 -= 50f;
				}
				if (num2 < num)
				{
					num = num2;
					val = val2;
				}
			}
		}
		if (val == null)
		{
			val = TryItemDonor(2206);
			if (val == null)
			{
				val = TryItemDonor(2040);
			}
		}
		if (val != null)
		{
			LogInfo("Selected visual donor item " + ((Proto)val).ID + ".");
		}
		else
		{
			LogWarning("No visual donor item was found.");
		}
		return val;
	}

	private static ItemProto TryItemDonor(int itemId)
	{
		ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(itemId);
		if (val == null || val.prefabDesc == null || (Object)(object)val.prefabDesc.prefab == (Object)null)
		{
			return null;
		}
		if (val.prefabDesc.isStorage || val.prefabDesc.isTank || val.prefabDesc.isStation)
		{
			return null;
		}
		return val;
	}

	private static ItemProto FindPortSource()
	{
		ItemProto val = TryPortSource(2020);
		if (val != null)
		{
			LogInfo("Using vanilla splitter as belt-port source.");
			return val;
		}
		ItemProto val2 = TryPortSource(2040);
		if (val2 != null)
		{
			LogInfo("Using vanilla piler as belt-port source.");
			return val2;
		}
		ItemProto val3 = null;
		for (int i = 0; i < ((ProtoSet<ItemProto>)(object)LDB.items).dataArray.Length; i++)
		{
			ItemProto val4 = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray[i];
			if (val4 != null && ((Proto)val4).ID != Plugin.ItemId && IsPortSource(val4))
			{
				if (val3 == null)
				{
					val3 = val4;
				}
				if (val4.prefabDesc.isSplitter || val4.prefabDesc.isPiler || val4.prefabDesc.isSpraycoster)
				{
					val3 = val4;
					break;
				}
			}
		}
		if (val3 != null)
		{
			LogInfo("Using fallback belt-port source item " + ((Proto)val3).ID + " (" + ((Proto)val3).Name + ").");
		}
		return val3;
	}

	private static ItemProto TryPortSource(int itemId)
	{
		ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(itemId);
		if (!IsPortSource(val))
		{
			return null;
		}
		return val;
	}

	private static bool IsPortSource(ItemProto item)
	{
		if (item == null || !item.CanBuild || !item.IsEntity)
		{
			return false;
		}
		PrefabDesc prefabDesc = item.prefabDesc;
		if (prefabDesc == null || (Object)(object)prefabDesc.prefab == (Object)null)
		{
			return false;
		}
		if (prefabDesc.portPoses == null || prefabDesc.portPoses.Length == 0)
		{
			return false;
		}
		if (prefabDesc.isStorage || prefabDesc.isTank || prefabDesc.isStation || prefabDesc.isBattleBase || prefabDesc.isAssembler || prefabDesc.isLab)
		{
			return false;
		}
		if (prefabDesc.selectSize.x > 3.5f || prefabDesc.selectSize.z > 3.5f)
		{
			return false;
		}
		return true;
	}

	private static bool HasConnectionPoses(SlotConfig slot)
	{
		if ((Object)(object)slot == (Object)null)
		{
			return false;
		}
		bool num = slot.slotPoses != null && slot.slotPoses.Length != 0;
		bool flag = slot.insertPoses != null && slot.insertPoses.Length != 0;
		return num || flag;
	}

	private static void ApplyBeltPorts(GameObject target, GameObject portSource)
	{
		SlotConfig componentInChildren = target.GetComponentInChildren<SlotConfig>(true);
		SlotConfig componentInChildren2 = portSource.GetComponentInChildren<SlotConfig>(true);
		if (!((Object)(object)componentInChildren == (Object)null) && !((Object)(object)componentInChildren2 == (Object)null))
		{
			componentInChildren.slotPoses = ClonePoses(componentInChildren2.slotPoses, portSource.transform, target.transform);
		}
	}

	private static void RemoveFunctionalDescriptors(GameObject root)
	{
		MonoBehaviour[] componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val in componentsInChildren)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			string name = ((object)val).GetType().Name;
			if (name.EndsWith("Desc", StringComparison.Ordinal))
			{
				switch (name)
				{
				case "LODModelDesc":
				case "StorageDesc":
				case "AudioDesc":
				case "AnimDesc":
					continue;
				}
				Object.DestroyImmediate((Object)(object)val);
			}
		}
	}

	private unsafe static void CopySlotConfig(GameObject storageSource, GameObject portSource, GameObject target)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: 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_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: 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_021e: 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_0225: Unknown result type (might be due to invalid IL or missing references)
		//IL_0227: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0293: Unknown result type (might be due to invalid IL or missing references)
		//IL_0298: Unknown result type (might be due to invalid IL or missing references)
		SlotConfig componentInChildren = storageSource.GetComponentInChildren<SlotConfig>(true);
		SlotConfig val = target.GetComponentInChildren<SlotConfig>(true);
		if ((Object)(object)val == (Object)null)
		{
			val = target.AddComponent<SlotConfig>();
		}
		Transform[] array = null;
		Vector3 selectCenter = (((Object)(object)val != (Object)null) ? val.selectCenter : Vector3.zero);
		Vector3 val2 = (((Object)(object)val != (Object)null) ? val.selectSize : Vector3.one);
		float selectAlpha = (((Object)(object)val != (Object)null) ? val.selectAlpha : 0.5f);
		if ((Object)(object)portSource == (Object)null && (Object)(object)val != (Object)null && val.slotPoses != null && val.slotPoses.Length != 0)
		{
			array = val.slotPoses;
		}
		if ((Object)(object)componentInChildren != (Object)null)
		{
			CopyFields(componentInChildren, val);
		}
		else
		{
			LogWarning("The vanilla storage prefab has no SlotConfig.");
		}
		if ((Object)(object)portSource != (Object)null)
		{
			SlotConfig componentInChildren2 = portSource.GetComponentInChildren<SlotConfig>(true);
			Transform[] source = (((Object)(object)componentInChildren2 != (Object)null) ? componentInChildren2.slotPoses : null);
			Transform sourceRoot = (((Object)(object)componentInChildren2 != (Object)null) ? portSource.transform : target.transform);
			val.slotPoses = ClonePoses(source, sourceRoot, target.transform);
			if ((Object)(object)componentInChildren == (Object)null && (Object)(object)componentInChildren2 != (Object)null)
			{
				val.insertPoses = ClonePoses(componentInChildren2.insertPoses, portSource.transform, target.transform);
			}
		}
		else if (array != null)
		{
			val.slotPoses = array;
		}
		else if ((Object)(object)componentInChildren != (Object)null)
		{
			val.slotPoses = ClonePoses(componentInChildren.slotPoses, storageSource.transform, target.transform);
		}
		if ((Object)(object)componentInChildren != (Object)null)
		{
			val.insertPoses = ClonePoses(componentInChildren.insertPoses, storageSource.transform, target.transform);
			val.addonAreaCol = ClonePoses(componentInChildren.addonAreaCol, storageSource.transform, target.transform);
			val.addonAreaCenter = componentInChildren.addonAreaCenter;
		}
		else if ((Object)(object)portSource != (Object)null && val.insertPoses == null)
		{
			SlotConfig componentInChildren3 = portSource.GetComponentInChildren<SlotConfig>(true);
			if ((Object)(object)componentInChildren3 != (Object)null)
			{
				val.insertPoses = ClonePoses(componentInChildren3.insertPoses, portSource.transform, target.transform);
			}
		}
		if (val2.x > 0.1f || val2.z > 0.1f)
		{
			val.selectCenter = selectCenter;
			val.selectSize = val2;
			val.selectAlpha = selectAlpha;
		}
		string[] obj = new string[7]
		{
			"Slot config: beltPorts=",
			((val.slotPoses != null) ? val.slotPoses.Length : 0).ToString(),
			", sorterSlots=",
			((val.insertPoses != null) ? val.insertPoses.Length : 0).ToString(),
			", selectSize=",
			null,
			null
		};
		Vector3 selectSize = val.selectSize;
		obj[5] = ((object)(*(Vector3*)(&selectSize))/*cast due to .constrained prefix*/).ToString();
		obj[6] = ".";
		LogInfo(string.Concat(obj));
	}

	private static Transform[] ClonePoses(Transform[] source, Transform sourceRoot, Transform targetRoot)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		if (source == null)
		{
			return null;
		}
		Transform[] array = (Transform[])(object)new Transform[source.Length];
		for (int i = 0; i < source.Length; i++)
		{
			Transform val = source[i];
			if (!((Object)(object)val == (Object)null))
			{
				Transform transform = new GameObject("TrashPort_" + i)
				{
					hideFlags = (HideFlags)61
				}.transform;
				transform.SetParent(targetRoot, false);
				transform.localPosition = sourceRoot.InverseTransformPoint(val.position);
				transform.localRotation = Quaternion.Inverse(sourceRoot.rotation) * val.rotation;
				transform.localScale = Vector3.one;
				array[i] = transform;
			}
		}
		return array;
	}

	private static void SetStorageSize(GameObject root, int columns, int rows)
	{
		StorageDesc val = root.GetComponentInChildren<StorageDesc>(true);
		if ((Object)(object)val == (Object)null)
		{
			val = root.AddComponent<StorageDesc>();
		}
		val.colCount = columns;
		val.rowCount = rows;
	}

	private static void CopyBuildCondition(GameObject source, GameObject target)
	{
		BuildConditionConfig componentInChildren = source.GetComponentInChildren<BuildConditionConfig>(true);
		if (!((Object)(object)componentInChildren == (Object)null))
		{
			BuildConditionConfig val = target.GetComponentInChildren<BuildConditionConfig>(true);
			if ((Object)(object)val == (Object)null)
			{
				val = target.AddComponent<BuildConditionConfig>();
			}
			CopyFields(componentInChildren, val);
		}
	}

	private static void CopyFields(object source, object target)
	{
		if (source == null || target == null)
		{
			return;
		}
		FieldInfo[] fields = source.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly)
			{
				try
				{
					fieldInfo.SetValue(target, fieldInfo.GetValue(source));
				}
				catch (Exception)
				{
				}
			}
		}
	}

	private static void TintPrefab(GameObject root)
	{
		Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
		Material val = null;
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			if (!((Object)(object)val == (Object)null))
			{
				break;
			}
			Material[] sharedMaterials = componentsInChildren[i].sharedMaterials;
			if (sharedMaterials == null)
			{
				continue;
			}
			for (int j = 0; j < sharedMaterials.Length; j++)
			{
				if ((Object)(object)sharedMaterials[j] != (Object)null && !IsGlass(sharedMaterials[j]) && !IsEffect(sharedMaterials[j]))
				{
					val = sharedMaterials[j];
					break;
				}
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			LogWarning("No opaque accumulator material was found for the trash body.");
			return;
		}
		trashBodyMaterial = CreateBodyMaterial(val);
		for (int k = 0; k < componentsInChildren.Length; k++)
		{
			Material[] sharedMaterials2 = componentsInChildren[k].sharedMaterials;
			if (sharedMaterials2 != null)
			{
				componentsInChildren[k].sharedMaterials = MapMaterials(sharedMaterials2);
			}
		}
		LODModelDesc[] componentsInChildren2 = root.GetComponentsInChildren<LODModelDesc>(true);
		foreach (LODModelDesc val2 in componentsInChildren2)
		{
			if (val2.lodMeshDatas == null)
			{
				continue;
			}
			for (int m = 0; m < val2.lodMeshDatas.Length; m++)
			{
				MeshDataAsset val3 = val2.lodMeshDatas[m];
				if (!((Object)(object)val3 == (Object)null))
				{
					MeshDataAsset val4 = ScriptableObject.CreateInstance<MeshDataAsset>();
					((Object)val4).name = ((Object)val3).name + "_Trash";
					val4.bytes = val3.bytes;
					val4.materials = MapMaterials(val3.materials);
					val4.blueprintMaterials = MapMaterials(val3.blueprintMaterials);
					val4.blueprintSubmeshIgnores = val3.blueprintSubmeshIgnores;
					((Object)val4).hideFlags = (HideFlags)61;
					val2.lodMeshDatas[m] = val4;
				}
			}
		}
	}

	private static Material[] MapMaterials(Material[] source)
	{
		if (source == null)
		{
			return null;
		}
		Material[] array = (Material[])(object)new Material[source.Length];
		for (int i = 0; i < source.Length; i++)
		{
			Material val = source[i];
			if (!((Object)(object)val == (Object)null))
			{
				if (IsGlass(val))
				{
					array[i] = trashBodyMaterial;
				}
				else if (IsEffect(val))
				{
					array[i] = CloneMaterial(val, "trash-effect");
				}
				else if (i == 0)
				{
					array[i] = trashBodyMaterial;
				}
				else
				{
					array[i] = TintMaterial(val, i);
				}
			}
		}
		return array;
	}

	private static bool IsGlass(Material material)
	{
		if ((Object)(object)material == (Object)null)
		{
			return false;
		}
		string obj = ((((Object)material).name != null) ? ((Object)material).name.ToLowerInvariant() : "");
		string text = (((Object)(object)material.shader != (Object)null) ? ((Object)material.shader).name.ToLowerInvariant() : "");
		if (!obj.Contains("glass"))
		{
			return text.Contains("glass");
		}
		return true;
	}

	private static bool IsEffect(Material material)
	{
		if ((Object)(object)material == (Object)null)
		{
			return false;
		}
		string obj = ((((Object)material).name != null) ? ((Object)material).name.ToLowerInvariant() : "");
		string text = (((Object)(object)material.shader != (Object)null) ? ((Object)material.shader).name.ToLowerInvariant() : "");
		if (!obj.Contains("effect") && !text.Contains("unlit"))
		{
			return text.Contains("additive");
		}
		return true;
	}

	private static Material CreateBodyMaterial(Material source)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		Material val = new Material(source);
		((Object)val).name = "trash-body";
		((Object)val).hideFlags = (HideFlags)61;
		if (val.HasProperty("_MainTex"))
		{
			val.SetTexture("_MainTex", (Texture)(object)GetBodyTexture());
		}
		if (val.HasProperty("_Color"))
		{
			val.color = Color.white;
		}
		if (val.HasProperty("_BaseColor"))
		{
			val.SetColor("_BaseColor", Color.white);
		}
		if (val.HasProperty("_TintColor"))
		{
			val.SetColor("_TintColor", Color.white);
		}
		if (val.HasProperty("_EmissionColor"))
		{
			val.SetColor("_EmissionColor", Color.black);
			val.DisableKeyword("_EMISSION");
		}
		return val;
	}

	private static Texture2D GetBodyTexture()
	{
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0203: Expected O, but got Unknown
		//IL_0204: Expected O, but got Unknown
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: 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_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid