Decompiled source of Dustbin v1.3.3

patchers/DustbinPreloader.dll

Decompiled 9 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Mono.Cecil;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("DustbinPreloader")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("DSP MOD - Prealoder for Dustbin")]
[assembly: AssemblyFileVersion("1.3.1.0")]
[assembly: AssemblyInformationalVersion("1.3.1+534d602953c168fb34342ff46b566978eabc0e39")]
[assembly: AssemblyProduct("DustbinPreloader")]
[assembly: AssemblyTitle("DustbinPreloader")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DustbinPreloader
{
	public static class Preloader
	{
		private static readonly ManualLogSource Logger = Logger.CreateLogSource("Dustbin Preloader");

		public static IEnumerable<string> TargetDLLs { get; } = new string[1] { "Assembly-CSharp.dll" };


		public static void Patch(AssemblyDefinition assembly)
		{
			ModuleDefinition mainModule = assembly.MainModule;
			try
			{
				mainModule.GetType("StorageComponent").AddFied("IsDustbin", mainModule.TypeSystem.Boolean);
			}
			catch (Exception ex)
			{
				Logger.LogError((object)"Failed to add `bool StorageComponent.IsDustbin`!");
				Logger.LogError((object)ex);
			}
			try
			{
				mainModule.GetType("TankComponent").AddFied("IsDustbin", mainModule.TypeSystem.Boolean);
			}
			catch (Exception ex2)
			{
				Logger.LogError((object)"Failed to add `bool TankComponent.IsDustbin`!");
				Logger.LogError((object)ex2);
			}
		}

		private static void AddFied(this TypeDefinition typeDefinition, string fieldName, TypeReference fieldType)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Expected O, but got Unknown
			FieldDefinition val = new FieldDefinition(fieldName, (FieldAttributes)6, fieldType);
			typeDefinition.Fields.Add(val);
			Logger.LogDebug((object)("Add " + (object)val));
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "DustbinPreloader";

		public const string PLUGIN_NAME = "DustbinPreloader";

		public const string PLUGIN_VERSION = "1.3.1";
	}
}

plugins/Dustbin.dll

Decompiled 9 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using Dustbin.NebulaSupport.Packet;
using Dustbin.UI;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NebulaAPI;
using NebulaAPI.Interfaces;
using NebulaAPI.Networking;
using NebulaAPI.Packets;
using UnityEngine;
using UnityEngine.UI;
using crecheng.DSPModSave;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Dustbin")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("DSP MOD - Dustbin")]
[assembly: AssemblyFileVersion("1.3.3.0")]
[assembly: AssemblyInformationalVersion("1.3.3+e2d83ee3cba46207f73d983cb0fd76c6dd66618b")]
[assembly: AssemblyProduct("Dustbin")]
[assembly: AssemblyTitle("Dustbin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.3.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Dustbin
{
	public static class BeltSignal
	{
		private static HashSet<int>[] _signalBelts;

		private static int _signalBeltsCapacity;

		private static bool _initialized;

		private static AssetBundle _bundle;

		private static Harmony _patch;

		public static void Enable(bool on)
		{
			if (on)
			{
				if (_patch == null)
				{
					_patch = Harmony.CreateAndPatchAll(typeof(BeltSignal), (string)null);
				}
				InitSignalBelts();
				return;
			}
			Harmony patch = _patch;
			if (patch != null)
			{
				patch.UnpatchSelf();
			}
			_patch = null;
			_signalBelts = null;
			_signalBeltsCapacity = 0;
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(VFPreload), "InvokeOnLoadWorkEnded")]
		private static void VFPreload_InvokeOnLoadWorkEnded_Postfix()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			if (!_initialized)
			{
				_bundle = AssetBundle.LoadFromFile(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/dustbin.assetbundle");
				SignalProtoSet signals = LDB._signals;
				int value = ((ProtoSet<SignalProto>)(object)signals).dataArray.Length;
				SignalProto val = new SignalProto
				{
					ID = 410,
					Name = "DUSTBIN",
					GridIndex = 3110,
					IconPath = "Assets/signal-410.png",
					_iconSprite = _bundle.LoadAsset<Sprite>("Assets/signal-410.png"),
					SID = ""
				};
				((Proto)val).name = Localization.Translate(((Proto)val).Name);
				((ProtoSet<SignalProto>)(object)signals).dataArray = CollectionExtensions.AddItem<SignalProto>((IEnumerable<SignalProto>)((ProtoSet<SignalProto>)(object)signals).dataArray, val).ToArray();
				((ProtoSet<SignalProto>)(object)signals).dataIndices[((Proto)val).ID] = value;
				_initialized = true;
			}
		}

		private static void InitSignalBelts()
		{
			if (!GameMain.isRunning)
			{
				return;
			}
			_signalBelts = new HashSet<int>[64];
			_signalBeltsCapacity = 64;
			PlanetFactory[] array = GameMain.data?.factories;
			if (array == null)
			{
				return;
			}
			PlanetFactory[] array2 = array;
			foreach (PlanetFactory val in array2)
			{
				SignData[] array3 = val?.entitySignPool;
				if (array3 == null)
				{
					continue;
				}
				CargoTraffic cargoTraffic = val.cargoTraffic;
				BeltComponent[] beltPool = cargoTraffic.beltPool;
				for (int num = cargoTraffic.beltCursor - 1; num > 0; num--)
				{
					if (beltPool[num].id == num && array3[beltPool[num].entityId].iconId0 == 410)
					{
						SetSignalBelt(val.index, num);
					}
				}
			}
		}

		private static void SetSignalBelt(int factory, int beltId)
		{
			GetOrCreateSignalBelts(factory).Add(beltId);
		}

		private static HashSet<int> GetOrCreateSignalBelts(int index)
		{
			if (index < 0)
			{
				return null;
			}
			HashSet<int> hashSet;
			if (index >= _signalBeltsCapacity)
			{
				int num = _signalBeltsCapacity * 2;
				HashSet<int>[] array = new HashSet<int>[num];
				Array.Copy(_signalBelts, array, _signalBeltsCapacity);
				_signalBelts = array;
				_signalBeltsCapacity = num;
			}
			else
			{
				hashSet = _signalBelts[index];
				if (hashSet != null)
				{
					return hashSet;
				}
			}
			hashSet = new HashSet<int>();
			_signalBelts[index] = hashSet;
			return hashSet;
		}

		private static HashSet<int> GetSignalBelts(int index)
		{
			if (index < 0 || index >= _signalBeltsCapacity)
			{
				return null;
			}
			return _signalBelts[index];
		}

		private static void RemoveSignalBelt(int factory, int beltId)
		{
			GetSignalBelts(factory)?.Remove(beltId);
		}

		private static void RemovePlanetSignalBelts(int factory)
		{
			GetSignalBelts(factory)?.Clear();
		}

		[HarmonyPostfix]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		private static void DigitalSystem_Constructor_Postfix(PlanetData _planet)
		{
			if (GameMain.mainPlayer != null)
			{
				PlanetFactory val = _planet?.factory;
				if (val != null)
				{
					RemovePlanetSignalBelts(val.index);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameMain), "Begin")]
		private static void GameMain_Begin_Postfix()
		{
			InitSignalBelts();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(CargoTraffic), "RemoveBeltComponent")]
		public static void CargoTraffic_RemoveBeltComponent_Prefix(int id)
		{
			PlanetData localPlanet = GameMain.localPlanet;
			if (localPlanet != null)
			{
				RemoveSignalBelt(localPlanet.factoryIndex, id);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CargoTraffic), "SetBeltSignalIcon")]
		public static void CargoTraffic_SetBeltSignalIcon_Postfix(CargoTraffic __instance, int signalId, int entityId)
		{
			PlanetData localPlanet = GameMain.localPlanet;
			if (localPlanet != null)
			{
				PlanetFactory factory = __instance.factory;
				int factoryIndex = localPlanet.factoryIndex;
				int beltId = factory.entityPool[entityId].beltId;
				if (signalId == 410)
				{
					SetSignalBelt(factoryIndex, beltId);
				}
				else
				{
					RemoveSignalBelt(factoryIndex, beltId);
				}
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(GameData), "GameTick")]
		public static IEnumerable<CodeInstruction> GameData_GameTick_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, generator);
			val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(PerformanceMonitor), "EndSample", (Type[])null, (Type[])null), (string)null)
			}).Advance(1).Insert((CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(BeltSignal), "ProcessBeltSignals", (Type[])null, (Type[])null))
			});
			return val.InstructionEnumeration();
		}

		public static void ProcessBeltSignals()
		{
			PlanetFactory[] array = GameMain.data?.factories;
			if (array == null)
			{
				return;
			}
			PlanetFactory[] array2 = array;
			byte b = default(byte);
			byte b2 = default(byte);
			foreach (PlanetFactory val in array2)
			{
				if (val == null)
				{
					continue;
				}
				int index = val.index;
				HashSet<int> signalBelts = GetSignalBelts(index);
				if (signalBelts == null || signalBelts.Count == 0)
				{
					continue;
				}
				int[] consumeRegister = GameMain.statistics.production.factoryStatPool[index].consumeRegister;
				CargoTraffic cargoTraffic = val.cargoTraffic;
				foreach (int item in signalBelts)
				{
					ref BeltComponent reference = ref cargoTraffic.beltPool[item];
					CargoPath cargoPath = cargoTraffic.GetCargoPath(reference.segPathId);
					int num;
					if (cargoPath != null && (num = cargoPath.TryPickItem(reference.segIndex + reference.segPivotOffset - 5, 12, ref b, ref b2)) > 0)
					{
						consumeRegister[num] += b;
						Dustbin.CalcGetSands(num, b);
					}
				}
			}
		}
	}
	[BepInPlugin("org.soardev.dustbin", "Dustbin", "1.3.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Dustbin : BaseUnityPlugin, IModCanSave, IMultiplayerMod
	{
		public static readonly ManualLogSource Logger = Logger.CreateLogSource("Dustbin");

		private static readonly int[] SandsFactors = new int[12001];

		private const ushort ModSaveVersion = 1;

		public string Version => "1.3.3";

		public bool CheckVersion(string hostVersion, string clientVersion)
		{
			return hostVersion.Equals(clientVersion);
		}

		private void Awake()
		{
			bool value = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "StorageDustbin", true, "Can turn storages into dustbins").Value;
			bool value2 = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "TankDustbin", true, "Can turn tanks into dustbins").Value;
			bool value3 = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BeltSignalDustbin", true, "Add belt signal as dustbin").Value;
			string[] array = ((BaseUnityPlugin)this).Config.Bind<string>("General", "SandsFactors", "", "Sands get from different items\nFormat: id1:value1|id2:value2|...").Value.Split(new char[1] { '|' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ':' });
				if (array2.Length >= 2 && int.TryParse(array2[0], out var result) && result <= 12000 && int.TryParse(array2[1], out var result2))
				{
					SandsFactors[result] = result2;
				}
			}
			if (value)
			{
				StoragePatch.Enable(on: true);
			}
			if (value2)
			{
				TankPatch.Enable(on: true);
			}
			if (value3)
			{
				BeltSignal.Enable(on: true);
			}
			if (Chainloader.PluginInfos.ContainsKey("dsp.nebula-multiplayer") && (value || value2))
			{
				NebulaModAPI.RegisterPackets(Assembly.GetExecutingAssembly());
				NebulaModAPI.OnPlanetLoadFinished = (Action<int>)Delegate.Combine(NebulaModAPI.OnPlanetLoadFinished, new Action<int>(RequestPlanetDustbinData));
			}
		}

		private void OnDestroy()
		{
			TankPatch.Enable(on: false);
			StoragePatch.Enable(on: false);
			BeltSignal.Enable(on: false);
			NebulaModAPI.OnPlanetLoadFinished = (Action<int>)Delegate.Remove(NebulaModAPI.OnPlanetLoadFinished, new Action<int>(RequestPlanetDustbinData));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int CalcGetSands(int itemId, int count)
		{
			int num = ((itemId <= 12000) ? SandsFactors[itemId] : 0);
			if (num <= 0)
			{
				return count;
			}
			Player mainPlayer = GameMain.mainPlayer;
			int num2 = count * num;
			mainPlayer.sandCount += num2;
			return count;
		}

		public void Export(BinaryWriter w)
		{
			w.Write((ushort)1);
			StoragePatch.Export(w);
			TankPatch.Export(w);
		}

		public void Import(BinaryReader r)
		{
			if (r.ReadUInt16() > 0)
			{
				StoragePatch.Import(r);
				TankPatch.Import(r);
			}
		}

		public void IntoOtherSave()
		{
		}

		public static byte[] ExportData(PlanetFactory factory)
		{
			int planetId = factory.planetId;
			List<int> list = new List<int>();
			List<int> list2 = new List<int>();
			FactoryStorage factoryStorage = factory.factoryStorage;
			StorageComponent[] storagePool = factoryStorage.storagePool;
			for (int i = 1; i < factoryStorage.storageCursor; i++)
			{
				StorageComponent val = storagePool[i];
				if (val != null && val.id == i && val.IsDustbin)
				{
					list.Add(i);
				}
			}
			TankComponent[] tankPool = factoryStorage.tankPool;
			for (int j = 1; j < factoryStorage.tankCursor; j++)
			{
				ref TankComponent reference = ref tankPool[j];
				if (reference.id == j && reference.IsDustbin)
				{
					list2.Add(j);
				}
			}
			IWriterProvider binaryWriter = NebulaModAPI.GetBinaryWriter();
			try
			{
				using BinaryWriter binaryWriter2 = binaryWriter.BinaryWriter;
				binaryWriter2.Write(planetId);
				binaryWriter2.Write(list.Count);
				foreach (int item in list)
				{
					binaryWriter2.Write(item);
				}
				binaryWriter2.Write(list2.Count);
				foreach (int item2 in list2)
				{
					binaryWriter2.Write(item2);
				}
				return binaryWriter.CloseAndGetBytes();
			}
			finally
			{
				((IDisposable)binaryWriter)?.Dispose();
			}
		}

		public static void ImportData(byte[] bytes)
		{
			IReaderProvider binaryReader = NebulaModAPI.GetBinaryReader(bytes);
			try
			{
				using BinaryReader binaryReader2 = binaryReader.BinaryReader;
				int num = binaryReader2.ReadInt32();
				PlanetFactory val = GameMain.galaxy.PlanetById(num)?.factory;
				if (val == null)
				{
					return;
				}
				FactoryStorage factoryStorage = val.factoryStorage;
				int num2 = binaryReader2.ReadInt32();
				StorageComponent[] storagePool = factoryStorage.storagePool;
				int storageCursor = factoryStorage.storageCursor;
				for (int i = 1; i < storageCursor; i++)
				{
					StorageComponent val2 = storagePool[i];
					if (val2 != null && val2.id == i)
					{
						val2.IsDustbin = false;
					}
				}
				for (int j = 0; j < num2; j++)
				{
					int num3 = binaryReader2.ReadInt32();
					storagePool[num3].IsDustbin = true;
				}
				num2 = binaryReader2.ReadInt32();
				TankComponent[] tankPool = factoryStorage.tankPool;
				storageCursor = factoryStorage.tankCursor;
				for (int k = 1; k < storageCursor; k++)
				{
					ref TankComponent reference = ref tankPool[k];
					if (reference.id == k)
					{
						reference.IsDustbin = false;
					}
				}
				for (int l = 0; l < num2; l++)
				{
					int num4 = binaryReader2.ReadInt32();
					if (num4 < storageCursor)
					{
						ref TankComponent reference2 = ref tankPool[num4];
						if (reference2.id == num4)
						{
							reference2.IsDustbin = true;
						}
					}
				}
			}
			finally
			{
				((IDisposable)binaryReader)?.Dispose();
			}
		}

		public void RequestPlanetDustbinData(int planetId)
		{
			if (NebulaModAPI.IsMultiplayerActive && NebulaModAPI.MultiplayerSession.IsClient)
			{
				NebulaModAPI.MultiplayerSession.Network.SendPacket<ToggleEvent>(new ToggleEvent(planetId, 0, enable: false));
			}
		}
	}
	[HarmonyPatch]
	public static class StoragePatch
	{
		private static MyCheckBox _storageDustbinCheckBox;

		private static int _lastStorageId;

		private static Harmony _patch;

		public static void Enable(bool on)
		{
			if (on)
			{
				if (_patch == null)
				{
					_patch = Harmony.CreateAndPatchAll(typeof(StoragePatch), (string)null);
				}
				return;
			}
			Harmony patch = _patch;
			if (patch != null)
			{
				patch.UnpatchSelf();
			}
			_patch = null;
		}

		public static void Reset()
		{
			_lastStorageId = 0;
		}

		public static void Export(BinaryWriter w)
		{
			MemoryStream memoryStream = new MemoryStream();
			BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			PlanetFactory[] factories = GameMain.data.factories;
			int factoryCount = GameMain.data.factoryCount;
			for (int i = 0; i < factoryCount; i++)
			{
				PlanetFactory val = factories[i];
				FactoryStorage val2 = val?.factoryStorage;
				StorageComponent[] array = val2?.storagePool;
				if (array == null)
				{
					continue;
				}
				int storageCursor = val2.storageCursor;
				int num = 0;
				for (int j = 1; j < storageCursor; j++)
				{
					if (array[j] != null && array[j].id == j && array[j].IsDustbin)
					{
						binaryWriter.Write(j);
						num++;
					}
				}
				if (num != 0)
				{
					binaryWriter.Flush();
					memoryStream.Position = 0L;
					w.Write((byte)1);
					w.Write(val.planetId);
					w.Write(num);
					memoryStream.CopyTo(w.BaseStream);
					memoryStream.SetLength(0L);
				}
			}
			binaryWriter.Dispose();
			memoryStream.Dispose();
		}

		public static void Import(BinaryReader r)
		{
			while (r.PeekChar() == 1)
			{
				r.ReadByte();
				int num = r.ReadInt32();
				StorageComponent[] array = GameMain.data.galaxy.PlanetById(num)?.factory?.factoryStorage?.storagePool;
				if (array == null)
				{
					for (int num2 = r.ReadInt32(); num2 > 0; num2--)
					{
						r.ReadInt32();
					}
					continue;
				}
				for (int num3 = r.ReadInt32(); num3 > 0; num3--)
				{
					int num4 = r.ReadInt32();
					if (num4 > 0 && num4 < array.Length && array[num4] != null && array[num4].id == num4)
					{
						array[num4].IsDustbin = true;
					}
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameMain), "Start")]
		private static void GameMain_Start_Prefix()
		{
			Reset();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIStorageWindow), "_OnCreate")]
		private static void UIStorageWindow__OnCreate_Postfix(UIStorageWindow __instance)
		{
			_storageDustbinCheckBox = MyCheckBox.CreateCheckBox(check: false, ((Component)__instance).transform, 50f, 50f, (Localization.CurrentLanguageLCID == 2052) ? "垃圾桶" : "Dustbin");
			UIStorageWindow window = __instance;
			_storageDustbinCheckBox.OnChecked += delegate
			{
				int storageId = window.storageId;
				if (storageId > 0)
				{
					StorageComponent[] storagePool = window.factoryStorage.storagePool;
					if (storagePool[storageId].id == storageId)
					{
						bool @checked = _storageDustbinCheckBox.Checked;
						storagePool[storageId].IsDustbin = @checked;
						if (NebulaModAPI.IsMultiplayerActive)
						{
							int planetId = window.factory.planetId;
							NebulaModAPI.MultiplayerSession.Network.SendPacketToLocalStar<ToggleEvent>(new ToggleEvent(planetId, storageId, @checked));
						}
					}
				}
			};
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIStorageWindow), "_OnUpdate")]
		private static void UIStorageWindow__OnUpdate_Postfix(UIStorageWindow __instance)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			int storageId = __instance.storageId;
			if (_lastStorageId == storageId)
			{
				return;
			}
			_lastStorageId = storageId;
			if (storageId <= 0)
			{
				return;
			}
			StorageComponent[] storagePool = __instance.factoryStorage.storagePool;
			if (storagePool[storageId].id == storageId)
			{
				_storageDustbinCheckBox.Checked = storagePool[storageId].IsDustbin;
				Transform transform = ((Component)__instance).transform;
				RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				if (val != null)
				{
					_storageDustbinCheckBox.rectTrans.anchoredPosition3D = new Vector3(190f, 57f - val.sizeDelta.y, 0f);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIStorageGrid), "OnStorageSizeChanged")]
		private static void UIStorageGrid_OnStorageSizeChanged_Postfix()
		{
			_lastStorageId = 0;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		private static IEnumerable<CodeInstruction> StorageComponent_AddItem_HarmonyTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, generator);
			Label label = generator.DefineLabel();
			val.Start().MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Stind_I4, (object)null, (string)null)
			}).Advance(1)
				.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[7]
				{
					new CodeInstruction(OpCodes.Ldarg_0, (object)null),
					new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(StorageComponent), "IsDustbin")),
					new CodeInstruction(OpCodes.Brfalse, (object)label),
					new CodeInstruction(OpCodes.Ldarg_1, (object)null),
					new CodeInstruction(OpCodes.Ldarg_2, (object)null),
					new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Dustbin), "CalcGetSands", (Type[])null, (Type[])null)),
					new CodeInstruction(OpCodes.Ret, (object)null)
				});
			val.Labels.Add(label);
			return val.InstructionEnumeration();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StorageComponent), "Import")]
		private static void StorageComponent_Import_Postfix(StorageComponent __instance)
		{
			if (__instance.bans < 0)
			{
				__instance.bans = -__instance.bans - 1;
				__instance.IsDustbin = true;
			}
		}
	}
	[HarmonyPatch]
	public static class TankPatch
	{
		private static MyCheckBox _tankDustbinCheckBox;

		private static int _lastTankId;

		private static Harmony _patch;

		public static void Enable(bool on)
		{
			if (on)
			{
				if (_patch == null)
				{
					_patch = Harmony.CreateAndPatchAll(typeof(TankPatch), (string)null);
				}
				return;
			}
			Harmony patch = _patch;
			if (patch != null)
			{
				patch.UnpatchSelf();
			}
			_patch = null;
		}

		public static void Reset()
		{
			_lastTankId = 0;
		}

		public static void Export(BinaryWriter w)
		{
			MemoryStream memoryStream = new MemoryStream();
			BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			PlanetFactory[] factories = GameMain.data.factories;
			int factoryCount = GameMain.data.factoryCount;
			for (int i = 0; i < factoryCount; i++)
			{
				PlanetFactory val = factories[i];
				if (val == null)
				{
					continue;
				}
				FactoryStorage factoryStorage = val.factoryStorage;
				TankComponent[] tankPool = factoryStorage.tankPool;
				int tankCursor = factoryStorage.tankCursor;
				int num = 0;
				for (int j = 1; j < tankCursor; j++)
				{
					if (tankPool[j].id == j && tankPool[j].IsDustbin)
					{
						binaryWriter.Write(j);
						num++;
					}
				}
				if (num != 0)
				{
					binaryWriter.Flush();
					memoryStream.Position = 0L;
					w.Write((byte)2);
					w.Write(val.planetId);
					w.Write(num);
					memoryStream.CopyTo(w.BaseStream);
					memoryStream.SetLength(0L);
				}
			}
			binaryWriter.Dispose();
			memoryStream.Dispose();
		}

		public static void Import(BinaryReader r)
		{
			while (r.PeekChar() == 2)
			{
				r.ReadByte();
				int num = r.ReadInt32();
				TankComponent[] array = GameMain.data.galaxy.PlanetById(num)?.factory.factoryStorage.tankPool;
				if (array == null)
				{
					for (int num2 = r.ReadInt32(); num2 > 0; num2--)
					{
						r.ReadInt32();
					}
					continue;
				}
				for (int num3 = r.ReadInt32(); num3 > 0; num3--)
				{
					int num4 = r.ReadInt32();
					if (num4 > 0 && num4 < array.Length && array[num4].id == num4)
					{
						array[num4].IsDustbin = true;
					}
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameMain), "Start")]
		private static void GameMain_Start_Prefix()
		{
			Reset();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UITankWindow), "_OnCreate")]
		private static void UITankWindow__OnCreate_Postfix(UITankWindow __instance)
		{
			_tankDustbinCheckBox = MyCheckBox.CreateCheckBox(check: false, ((Component)__instance).transform, 120f, 20f, (Localization.CurrentLanguageLCID == 2052) ? "垃圾桶" : "Dustbin");
			UITankWindow window = __instance;
			_tankDustbinCheckBox.OnChecked += delegate
			{
				int tankId = window.tankId;
				if (tankId > 0)
				{
					TankComponent[] tankPool = window.storage.tankPool;
					if (tankPool[tankId].id == tankId)
					{
						bool @checked = _tankDustbinCheckBox.Checked;
						tankPool[tankId].IsDustbin = @checked;
						if (NebulaModAPI.IsMultiplayerActive)
						{
							int planetId = window.factory.planetId;
							NebulaModAPI.MultiplayerSession.Network.SendPacketToLocalStar<ToggleEvent>(new ToggleEvent(planetId, -tankId, @checked));
						}
					}
				}
			};
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UITankWindow), "_OnUpdate")]
		private static void UITankWindow__OnUpdate_Postfix(UITankWindow __instance)
		{
			int tankId = __instance.tankId;
			if (_lastTankId == tankId)
			{
				return;
			}
			_lastTankId = tankId;
			if (tankId > 0)
			{
				ref TankComponent reference = ref __instance.storage.tankPool[tankId];
				if (reference.id == tankId)
				{
					_tankDustbinCheckBox.Checked = reference.IsDustbin;
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TankComponent), "GameTick")]
		private static bool TankComponent_GameTick_Prefix(ref TankComponent __instance, PlanetFactory factory)
		{
			if (__instance.fluidInc < 0)
			{
				__instance.fluidInc = 0;
			}
			if (!__instance.isBottom)
			{
				return false;
			}
			CargoTraffic cargoTraffic = factory.cargoTraffic;
			TankComponent[] tankPool = factory.factoryStorage.tankPool;
			int belt = __instance.belt0;
			if (belt > 0)
			{
				TankComponentUpdateBelt(ref __instance, belt, __instance.isOutput0, ref cargoTraffic, ref tankPool);
			}
			belt = __instance.belt1;
			if (belt > 0)
			{
				TankComponentUpdateBelt(ref __instance, belt, __instance.isOutput1, ref cargoTraffic, ref tankPool);
			}
			belt = __instance.belt2;
			if (belt > 0)
			{
				TankComponentUpdateBelt(ref __instance, belt, __instance.isOutput2, ref cargoTraffic, ref tankPool);
			}
			belt = __instance.belt3;
			if (belt > 0)
			{
				TankComponentUpdateBelt(ref __instance, belt, __instance.isOutput3, ref cargoTraffic, ref tankPool);
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static void TankComponentUpdateBelt(ref TankComponent thisTank, int belt, bool isOutput, ref CargoTraffic cargoTraffic, ref TankComponent[] tankPool)
		{
			if (isOutput)
			{
				if (thisTank.outputSwitch && thisTank.fluidId > 0 && thisTank.fluidCount > 0)
				{
					int num = ((thisTank.fluidInc != 0) ? (thisTank.fluidInc / thisTank.fluidCount) : 0);
					if (cargoTraffic.TryInsertItemAtHead(belt, thisTank.fluidId, (byte)1, (byte)num))
					{
						thisTank.fluidCount--;
						thisTank.fluidInc -= num;
					}
				}
			}
			else
			{
				if (!thisTank.inputSwitch)
				{
					return;
				}
				int fluidId = thisTank.fluidId;
				byte b = default(byte);
				byte b2 = default(byte);
				if (fluidId <= 0)
				{
					if (fluidId == 0)
					{
						int num2 = cargoTraffic.TryPickItemAtRear(belt, 0, ItemProto.fluids, ref b, ref b2);
						if (num2 > 0 && !thisTank.IsDustbin)
						{
							thisTank.fluidId = num2;
							thisTank.fluidCount += b;
							thisTank.fluidInc += b2;
						}
						return;
					}
				}
				else if (thisTank.fluidCount < thisTank.fluidCapacity && cargoTraffic.TryPickItemAtRear(belt, thisTank.fluidId, (int[])null, ref b, ref b2) > 0 && !thisTank.IsDustbin)
				{
					thisTank.fluidCount += b;
					thisTank.fluidInc += b2;
					return;
				}
				if (thisTank.fluidCount < thisTank.fluidCapacity || cargoTraffic.GetItemIdAtRear(belt) != thisTank.fluidId || thisTank.nextTankId <= 0)
				{
					return;
				}
				ref TankComponent reference = ref tankPool[thisTank.nextTankId];
				while (reference.fluidCount >= reference.fluidCapacity)
				{
					ref TankComponent reference2 = ref tankPool[reference.lastTankId];
					if (reference.fluidId != reference2.fluidId)
					{
						if (reference2.id == thisTank.id || reference.fluidCount >= reference.fluidCapacity)
						{
							return;
						}
						reference = ref reference2;
						break;
					}
					if (!reference.inputSwitch)
					{
						if (reference2.id == thisTank.id || reference.fluidCount >= reference.fluidCapacity)
						{
							return;
						}
						reference = ref reference2;
						break;
					}
					if (reference.nextTankId <= 0)
					{
						break;
					}
					reference = ref tankPool[reference.nextTankId];
				}
				ref TankComponent reference3 = ref tankPool[reference.lastTankId];
				if (!reference.inputSwitch)
				{
					reference = ref reference3;
				}
				else
				{
					int fluidId2 = reference.fluidId;
					if (fluidId2 != 0 && fluidId2 != reference3.fluidId)
					{
						if (reference3.id == thisTank.id || reference.fluidCount >= reference.fluidCapacity)
						{
							return;
						}
						reference = ref reference3;
					}
					else if (!reference3.outputSwitch)
					{
						return;
					}
				}
				if (cargoTraffic.TryPickItemAtRear(belt, thisTank.fluidId, (int[])null, ref b, ref b2) > 0 && !reference.IsDustbin)
				{
					if (reference.fluidCount == 0)
					{
						reference.fluidId = thisTank.fluidId;
					}
					reference.fluidCount += b;
					reference.fluidInc += b2;
				}
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "org.soardev.dustbin";

		public const string PLUGIN_NAME = "Dustbin";

		public const string PLUGIN_VERSION = "1.3.3";
	}
}
namespace Dustbin.UI
{
	public class MyCheckBox : MonoBehaviour
	{
		public UIButton uiButton;

		public Image checkImage;

		public RectTransform rectTrans;

		public Text labelText;

		private bool _checked;

		public bool Checked
		{
			get
			{
				return _checked;
			}
			set
			{
				_checked = value;
				((Behaviour)checkImage).enabled = value;
			}
		}

		public event Action OnChecked;

		public static MyCheckBox CreateCheckBox(bool check, Transform parent = null, float x = 0f, float y = 0f, string label = "", int fontSize = 15)
		{
			//IL_006a: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(((Component)UIRoot.instance.uiGame.buildMenu.uxFacilityCheck).gameObject);
			Transform transform = val.transform;
			RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			((Object)val).name = "my-checkbox";
			MyCheckBox myCheckBox = val.AddComponent<MyCheckBox>();
			myCheckBox._checked = check;
			if ((Object)(object)parent != (Object)null)
			{
				((Transform)val2).SetParent(parent);
			}
			val2.anchorMax = new Vector2(0f, 1f);
			val2.anchorMin = new Vector2(0f, 1f);
			val2.pivot = new Vector2(0f, 1f);
			val2.anchoredPosition3D = new Vector3(x, 0f - y, 0f);
			myCheckBox.rectTrans = val2;
			myCheckBox.uiButton = val.GetComponent<UIButton>();
			Transform obj = val.transform.Find("checked");
			myCheckBox.checkImage = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null);
			Transform val3 = val.transform.Find("text");
			if ((Object)(object)val3 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)((Component)val3).GetComponent<Localizer>());
				myCheckBox.labelText = ((Component)val3).GetComponent<Text>();
				myCheckBox.labelText.fontSize = fontSize;
				myCheckBox.SetLabelText(label);
			}
			myCheckBox.uiButton.onClick += myCheckBox.OnClick;
			if ((Object)(object)myCheckBox.checkImage != (Object)null)
			{
				((Behaviour)myCheckBox.checkImage).enabled = check;
			}
			return myCheckBox;
		}

		public void SetLabelText(string val)
		{
			if ((Object)(object)labelText != (Object)null)
			{
				labelText.text = val;
			}
		}

		public void OnClick(int obj)
		{
			_checked = !_checked;
			((Behaviour)checkImage).enabled = _checked;
			this.OnChecked?.Invoke();
		}
	}
}
namespace Dustbin.NebulaSupport.Packet
{
	public class SyncPlanetData
	{
		public byte[] Data { get; set; }

		public SyncPlanetData()
		{
		}

		public SyncPlanetData(byte[] data)
		{
			Data = data;
		}
	}
	public class ToggleEvent
	{
		public int PlanetId { get; set; }

		public int StorageId { get; set; }

		public bool Enable { get; set; }

		public ToggleEvent()
		{
		}

		public ToggleEvent(int planetId, int storageId, bool enable)
		{
			PlanetId = planetId;
			StorageId = storageId;
			Enable = enable;
		}
	}
	[RegisterPacketProcessor]
	internal class SyncPlanetDataProcessor : BasePacketProcessor<SyncPlanetData>
	{
		public override void ProcessPacket(SyncPlanetData packet, INebulaConnection conn)
		{
			Dustbin.ImportData(packet.Data);
		}
	}
	[RegisterPacketProcessor]
	internal class ToggleEventProcessor : BasePacketProcessor<ToggleEvent>
	{
		public override void ProcessPacket(ToggleEvent packet, INebulaConnection conn)
		{
			PlanetFactory val = GameMain.galaxy.PlanetById(packet.PlanetId)?.factory;
			if (val == null)
			{
				return;
			}
			int storageId = packet.StorageId;
			if (storageId >= 0)
			{
				if (storageId == 0)
				{
					NebulaModAPI.MultiplayerSession.Network.SendPacket<SyncPlanetData>(new SyncPlanetData(Dustbin.ExportData(val)));
					return;
				}
				val.factoryStorage.storagePool[storageId].IsDustbin = packet.Enable;
				StoragePatch.Reset();
			}
			else
			{
				val.factoryStorage.tankPool[-storageId].IsDustbin = packet.Enable;
				TankPatch.Reset();
			}
		}
	}
}