Decompiled source of ConstructionOps v1.1.0

BepInEx/plugins/ConstructionOps/ConstructionOps.dll

Decompiled a month ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Mirage;
using Mirage.Serialization;
using NOHenDev.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NuclearOption.MissionEditorScripts;
using NuclearOption.Networking;
using NuclearOption.NodeGraph;
using NuclearOption.SavedMission;
using NuclearOption.SavedMission.Objectives;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[CompilerGenerated]
[EditorBrowsable(EditorBrowsableState.Never)]
[GeneratedCode("Unity.MonoScriptGenerator.MonoScriptInfoGenerator", null)]
internal class UnitySourceGeneratedAssemblyMonoScriptTypes_v1
{
	private struct MonoScriptData
	{
		public byte[] FilePathsData;

		public byte[] TypesData;

		public int TotalTypes;

		public int TotalFiles;

		public bool IsEditorOnly;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	private static MonoScriptData Get()
	{
		return new MonoScriptData
		{
			FilePathsData = new byte[1146]
			{
				0, 0, 0, 1, 0, 0, 0, 53, 92, 65,
				115, 115, 101, 116, 115, 92, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 79, 112,
				115, 92, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 66, 117, 105, 108, 100, 105, 110, 103, 79,
				98, 106, 101, 99, 116, 105, 118, 101, 46, 99,
				115, 0, 0, 0, 1, 0, 0, 0, 58, 92,
				65, 115, 115, 101, 116, 115, 92, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 105, 111, 110, 79,
				112, 115, 92, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 66, 117, 105, 108, 100, 105, 110, 103,
				83, 97, 118, 101, 100, 79, 98, 106, 101, 99,
				116, 105, 118, 101, 46, 99, 115, 0, 0, 0,
				1, 0, 0, 0, 45, 92, 65, 115, 115, 101,
				116, 115, 92, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 92, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 65, 115, 115, 101, 116, 115, 46, 99, 115,
				0, 0, 0, 3, 0, 0, 0, 48, 92, 65,
				115, 115, 101, 116, 115, 92, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 79, 112,
				115, 92, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 67, 97, 116, 97, 108, 111,
				103, 117, 101, 46, 99, 115, 0, 0, 0, 4,
				0, 0, 0, 45, 92, 65, 115, 115, 101, 116,
				115, 92, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 92, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 105, 111, 110,
				67, 111, 110, 102, 105, 103, 46, 99, 115, 0,
				0, 0, 2, 0, 0, 0, 49, 92, 65, 115,
				115, 101, 116, 115, 92, 67, 111, 110, 115, 116,
				114, 117, 99, 116, 105, 111, 110, 79, 112, 115,
				92, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 67, 114, 97, 116, 101, 80, 97,
				110, 101, 108, 46, 99, 115, 0, 0, 0, 2,
				0, 0, 0, 53, 92, 65, 115, 115, 101, 116,
				115, 92, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 92, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 105, 111, 110,
				67, 114, 97, 116, 101, 80, 108, 97, 99, 101,
				109, 101, 110, 116, 46, 99, 115, 0, 0, 0,
				3, 0, 0, 0, 48, 92, 65, 115, 115, 101,
				116, 115, 92, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 92, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 76, 111, 103, 105, 115, 116, 105, 99, 115,
				46, 99, 115, 0, 0, 0, 2, 0, 0, 0,
				46, 92, 65, 115, 115, 101, 116, 115, 92, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 79, 112, 115, 92, 67, 111, 110, 115, 116,
				114, 117, 99, 116, 105, 111, 110, 77, 97, 110,
				97, 103, 101, 114, 46, 99, 115, 0, 0, 0,
				4, 0, 0, 0, 42, 92, 65, 115, 115, 101,
				116, 115, 92, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 92, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 78, 101, 116, 46, 99, 115, 0, 0, 0,
				2, 0, 0, 0, 49, 92, 65, 115, 115, 101,
				116, 115, 92, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 92, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 79, 98, 106, 101, 99, 116, 105, 118, 101,
				115, 46, 99, 115, 0, 0, 0, 1, 0, 0,
				0, 46, 92, 65, 115, 115, 101, 116, 115, 92,
				67, 111, 110, 115, 116, 114, 117, 99, 116, 105,
				111, 110, 79, 112, 115, 92, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 79, 112,
				115, 72, 111, 115, 116, 46, 99, 115, 0, 0,
				0, 1, 0, 0, 0, 44, 92, 65, 115, 115,
				101, 116, 115, 92, 67, 111, 110, 115, 116, 114,
				117, 99, 116, 105, 111, 110, 79, 112, 115, 92,
				67, 111, 110, 115, 116, 114, 117, 99, 116, 105,
				111, 110, 80, 97, 110, 101, 108, 46, 99, 115,
				0, 0, 0, 1, 0, 0, 0, 47, 92, 65,
				115, 115, 101, 116, 115, 92, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 79, 112,
				115, 92, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 82, 101, 103, 105, 115, 116,
				114, 121, 46, 99, 115, 0, 0, 0, 1, 0,
				0, 0, 43, 92, 65, 115, 115, 101, 116, 115,
				92, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 79, 112, 115, 92, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 105, 111, 110, 83,
				105, 116, 101, 46, 99, 115, 0, 0, 0, 1,
				0, 0, 0, 53, 92, 65, 115, 115, 101, 116,
				115, 92, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 92, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 105, 111, 110,
				84, 114, 97, 110, 115, 112, 111, 114, 116, 83,
				116, 97, 116, 101, 46, 99, 115, 0, 0, 0,
				2, 0, 0, 0, 41, 92, 65, 115, 115, 101,
				116, 115, 92, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 92, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 85, 105, 46, 99, 115, 0, 0, 0, 1,
				0, 0, 0, 51, 92, 65, 115, 115, 101, 116,
				115, 92, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 92, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 79, 98, 106,
				101, 99, 116, 105, 118, 101, 69, 100, 105, 116,
				111, 114, 46, 99, 115, 0, 0, 0, 1, 0,
				0, 0, 52, 92, 65, 115, 115, 101, 116, 115,
				92, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 79, 112, 115, 92, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 79, 98, 106, 101,
				99, 116, 105, 118, 101, 80, 97, 116, 99, 104,
				101, 115, 46, 99, 115, 0, 0, 0, 1, 0,
				0, 0, 33, 92, 65, 115, 115, 101, 116, 115,
				92, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 79, 112, 115, 92, 80, 108, 117,
				103, 105, 110, 46, 99, 115, 0, 0, 0, 1,
				0, 0, 0, 32, 92, 65, 115, 115, 101, 116,
				115, 92, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 92, 80, 114,
				111, 98, 101, 46, 99, 115
			},
			TypesData = new byte[1625]
			{
				0, 0, 0, 0, 42, 67, 111, 110, 115, 116,
				114, 117, 99, 116, 105, 111, 110, 79, 112, 115,
				124, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				66, 117, 105, 108, 100, 105, 110, 103, 79, 98,
				106, 101, 99, 116, 105, 118, 101, 0, 0, 0,
				0, 47, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 124, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 66, 117, 105,
				108, 100, 105, 110, 103, 83, 97, 118, 101, 100,
				79, 98, 106, 101, 99, 116, 105, 118, 101, 0,
				0, 0, 0, 34, 67, 111, 110, 115, 116, 114,
				117, 99, 116, 105, 111, 110, 79, 112, 115, 124,
				67, 111, 110, 115, 116, 114, 117, 99, 116, 105,
				111, 110, 65, 115, 115, 101, 116, 115, 0, 0,
				0, 0, 37, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 124, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 67, 97, 116, 97, 108, 111, 103, 117, 101,
				0, 0, 0, 0, 50, 67, 111, 110, 115, 116,
				114, 117, 99, 116, 105, 111, 110, 79, 112, 115,
				46, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 67, 97, 116, 97, 108, 111, 103,
				117, 101, 124, 77, 97, 116, 101, 114, 105, 97,
				108, 76, 111, 97, 100, 0, 0, 0, 0, 49,
				67, 111, 110, 115, 116, 114, 117, 99, 116, 105,
				111, 110, 79, 112, 115, 46, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 67, 97,
				116, 97, 108, 111, 103, 117, 101, 124, 66, 117,
				105, 108, 100, 79, 112, 116, 105, 111, 110, 0,
				0, 0, 0, 34, 67, 111, 110, 115, 116, 114,
				117, 99, 116, 105, 111, 110, 79, 112, 115, 124,
				67, 111, 110, 115, 116, 114, 117, 99, 116, 105,
				111, 110, 67, 111, 110, 102, 105, 103, 0, 0,
				0, 0, 48, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 46, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 67, 111, 110, 102, 105, 103, 124, 77, 97,
				116, 101, 114, 105, 97, 108, 69, 110, 116, 114,
				121, 0, 0, 0, 0, 45, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 79, 112,
				115, 46, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 67, 111, 110, 102, 105, 103,
				124, 66, 117, 105, 108, 100, 69, 110, 116, 114,
				121, 0, 0, 0, 0, 58, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 79, 112,
				115, 46, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 67, 111, 110, 102, 105, 103,
				124, 65, 105, 114, 99, 114, 97, 102, 116, 80,
				114, 111, 100, 117, 99, 116, 105, 111, 110, 69,
				110, 116, 114, 121, 0, 0, 0, 0, 38, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 79, 112, 115, 124, 67, 111, 110, 115, 116,
				114, 117, 99, 116, 105, 111, 110, 67, 114, 97,
				116, 101, 80, 97, 110, 101, 108, 0, 0, 0,
				0, 44, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 46, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 105, 111, 110,
				67, 114, 97, 116, 101, 80, 97, 110, 101, 108,
				124, 66, 108, 111, 99, 107, 0, 0, 0, 0,
				41, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 79, 112, 115, 124, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 105, 111, 110, 67,
				114, 97, 116, 101, 83, 101, 116, 116, 105, 110,
				103, 115, 0, 0, 0, 0, 43, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 105, 111, 110, 79,
				112, 115, 124, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 67, 114, 97, 116, 101,
				80, 108, 97, 99, 101, 109, 101, 110, 116, 115,
				0, 0, 0, 0, 37, 67, 111, 110, 115, 116,
				114, 117, 99, 116, 105, 111, 110, 79, 112, 115,
				124, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 76, 111, 103, 105, 115, 116, 105,
				99, 115, 0, 0, 0, 0, 44, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 105, 111, 110, 79,
				112, 115, 46, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 76, 111, 103, 105, 115,
				116, 105, 99, 115, 124, 83, 111, 114, 116, 105,
				101, 0, 0, 0, 0, 51, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 79, 112,
				115, 46, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 76, 111, 103, 105, 115, 116,
				105, 99, 115, 124, 67, 114, 97, 116, 101, 65,
				116, 116, 101, 109, 112, 116, 115, 0, 0, 0,
				0, 35, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 124, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 105, 111, 110,
				77, 97, 110, 97, 103, 101, 114, 0, 0, 0,
				0, 50, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 46, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 105, 111, 110,
				77, 97, 110, 97, 103, 101, 114, 124, 67, 111,
				109, 112, 108, 101, 116, 101, 100, 66, 117, 105,
				108, 100, 0, 0, 0, 0, 31, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 105, 111, 110, 79,
				112, 115, 124, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 78, 101, 116, 0, 0,
				0, 0, 46, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 46, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 78, 101, 116, 124, 67, 111, 109, 109, 97,
				110, 100, 77, 101, 115, 115, 97, 103, 101, 0,
				0, 0, 0, 41, 67, 111, 110, 115, 116, 114,
				117, 99, 116, 105, 111, 110, 79, 112, 115, 46,
				67, 111, 110, 115, 116, 114, 117, 99, 116, 105,
				111, 110, 78, 101, 116, 124, 83, 105, 116, 101,
				83, 116, 97, 116, 101, 0, 0, 0, 0, 44,
				67, 111, 110, 115, 116, 114, 117, 99, 116, 105,
				111, 110, 79, 112, 115, 46, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 78, 101,
				116, 124, 83, 116, 97, 116, 101, 77, 101, 115,
				115, 97, 103, 101, 0, 0, 0, 0, 38, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 79, 112, 115, 124, 67, 111, 110, 115, 116,
				114, 117, 99, 116, 105, 111, 110, 79, 98, 106,
				101, 99, 116, 105, 118, 101, 115, 0, 0, 0,
				0, 48, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 105, 111, 110, 79, 112, 115, 46, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 105, 111, 110,
				79, 98, 106, 101, 99, 116, 105, 118, 101, 115,
				124, 68, 105, 114, 101, 99, 116, 105, 118, 101,
				0, 0, 0, 0, 35, 67, 111, 110, 115, 116,
				114, 117, 99, 116, 105, 111, 110, 79, 112, 115,
				124, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 79, 112, 115, 72, 111, 115, 116,
				0, 0, 0, 0, 33, 67, 111, 110, 115, 116,
				114, 117, 99, 116, 105, 111, 110, 79, 112, 115,
				124, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 80, 97, 110, 101, 108, 0, 0,
				0, 0, 36, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 124, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 82, 101, 103, 105, 115, 116, 114, 121, 0,
				0, 0, 0, 32, 67, 111, 110, 115, 116, 114,
				117, 99, 116, 105, 111, 110, 79, 112, 115, 124,
				67, 111, 110, 115, 116, 114, 117, 99, 116, 105,
				111, 110, 83, 105, 116, 101, 0, 0, 0, 0,
				42, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 79, 112, 115, 124, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 105, 111, 110, 84,
				114, 97, 110, 115, 112, 111, 114, 116, 83, 116,
				97, 116, 101, 0, 0, 0, 0, 30, 67, 111,
				110, 115, 116, 114, 117, 99, 116, 105, 111, 110,
				79, 112, 115, 124, 67, 111, 110, 115, 116, 114,
				117, 99, 116, 105, 111, 110, 85, 105, 0, 0,
				0, 0, 38, 67, 111, 110, 115, 116, 114, 117,
				99, 116, 105, 111, 110, 79, 112, 115, 46, 67,
				111, 110, 115, 116, 114, 117, 99, 116, 105, 111,
				110, 85, 105, 124, 72, 111, 116, 90, 111, 110,
				101, 0, 0, 0, 0, 40, 67, 111, 110, 115,
				116, 114, 117, 99, 116, 105, 111, 110, 79, 112,
				115, 124, 67, 111, 110, 115, 116, 114, 117, 99,
				116, 79, 98, 106, 101, 99, 116, 105, 118, 101,
				69, 100, 105, 116, 111, 114, 0, 0, 0, 0,
				41, 67, 111, 110, 115, 116, 114, 117, 99, 116,
				105, 111, 110, 79, 112, 115, 124, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 79, 98, 106, 101,
				99, 116, 105, 118, 101, 80, 97, 116, 99, 104,
				101, 115, 0, 0, 0, 0, 22, 67, 111, 110,
				115, 116, 114, 117, 99, 116, 105, 111, 110, 79,
				112, 115, 124, 80, 108, 117, 103, 105, 110, 0,
				0, 0, 0, 21, 67, 111, 110, 115, 116, 114,
				117, 99, 116, 105, 111, 110, 79, 112, 115, 124,
				80, 114, 111, 98, 101
			},
			TotalFiles = 21,
			TotalTypes = 36,
			IsEditorOnly = false
		};
	}
}
namespace ConstructionOps;

public class ConstructBuildingObjective : Objective, IObjectiveWithPosition
{
	public const string AnyBuild = "any";

	private const string ProductionLabel = "Produces";

	public readonly Waypoint Spot = new Waypoint();

	private readonly ValueWrapperInt count = new ValueWrapperInt(1);

	private readonly ValueWrapperBool aiBuild = new ValueWrapperBool(false);

	private string buildId = "any";

	private string production = "";

	private readonly ObjectivePosition[] positions = (ObjectivePosition[])(object)new ObjectivePosition[1];

	public ConstructBuildingSavedObjective Saved => (ConstructBuildingSavedObjective)(object)base.SavedObjective;

	public bool AiBuild => ((ValueWrapper<bool>)(object)aiBuild).Value;

	public string RequestedProduction => production ?? "";

	public GlobalPosition TargetPosition => ((ValueWrapper<GlobalPosition>)(object)Spot.GlobalPosition).Value;

	public float TargetRange => Mathf.Max(1f, ((ValueWrapper<float>)(object)Spot.Range).Value);

	public override bool NeedsFaction => false;

	public override float CompletePercent
	{
		get
		{
			int num = Mathf.Max(1, ((ValueWrapper<int>)(object)count).Value);
			return Mathf.Clamp01((float)CountMatching() / (float)num);
		}
	}

	public IReadOnlyList<ObjectivePosition> Positions
	{
		get
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			positions[0] = Spot.ToObjectivePosition();
			return positions;
		}
	}

	public string BuildIdForDiagnostics => buildId;

	public int RequiredCountForDiagnostics => Mathf.Max(1, ((ValueWrapper<int>)(object)count).Value);

	public ConstructBuildingObjective(ConstructBuildingSavedObjective savedObjective)
		: base((SavedObjective)(object)savedObjective)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		ApplySaved();
	}

	private void ApplySaved()
	{
		//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)
		((ValueWrapper<GlobalPosition>)(object)Spot.GlobalPosition).SetValue(new GlobalPosition(Saved.Position), (object)this, true);
		((ValueWrapper<float>)(object)Spot.Range).SetValue(Mathf.Max(1f, Saved.Range), (object)this, true);
		((ValueWrapper<int>)(object)count).SetValue(Mathf.Max(1, Saved.Count), (object)this, true);
		((ValueWrapper<bool>)(object)aiBuild).SetValue(Saved.AiBuild, (object)this, true);
		buildId = (string.IsNullOrEmpty(Saved.BuildId) ? "any" : Saved.BuildId);
		production = Saved.Production ?? "";
	}

	public override void Load(MissionLookups lookups)
	{
		((Objective)this).Load(lookups);
		ApplySaved();
	}

	public override void Save()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		((Objective)this).Save();
		ConstructBuildingSavedObjective saved = Saved;
		GlobalPosition value = ((ValueWrapper<GlobalPosition>)(object)Spot.GlobalPosition).Value;
		saved.Position = ((GlobalPosition)(ref value)).AsVector3();
		Saved.Range = ((ValueWrapper<float>)(object)Spot.Range).Value;
		Saved.Count = ((ValueWrapper<int>)(object)count).Value;
		Saved.AiBuild = ((ValueWrapper<bool>)(object)aiBuild).Value;
		Saved.BuildId = buildId;
		Saved.Production = production ?? "";
	}

	public override void CopyFrom(Objective original)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		((Objective)this).CopyFrom(original);
		if (original is ConstructBuildingObjective constructBuildingObjective)
		{
			((ValueWrapper<GlobalPosition>)(object)Spot.GlobalPosition).SetValue(((ValueWrapper<GlobalPosition>)(object)constructBuildingObjective.Spot.GlobalPosition).Value, (object)this, true);
			((ValueWrapper<float>)(object)Spot.Range).SetValue(((ValueWrapper<float>)(object)constructBuildingObjective.Spot.Range).Value, (object)this, true);
			((ValueWrapper<int>)(object)count).SetValue(((ValueWrapper<int>)(object)constructBuildingObjective.count).Value, (object)this, true);
			((ValueWrapper<bool>)(object)aiBuild).SetValue(((ValueWrapper<bool>)(object)constructBuildingObjective.aiBuild).Value, (object)this, true);
			buildId = constructBuildingObjective.buildId;
			production = constructBuildingObjective.production;
		}
	}

	public override void OnStart()
	{
	}

	public override void ClientOnlyUpdate()
	{
	}

	protected override void DataReferenceDestroyed(ISaveableReference reference)
	{
	}

	public override bool UpdateAndCheck()
	{
		return CountMatching() >= Mathf.Max(1, ((ValueWrapper<int>)(object)count).Value);
	}

	public int CountMatching()
	{
		//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_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		IList<ConstructionManager.CompletedBuild> completedBuilds = ConstructionManager.CompletedBuilds;
		if (completedBuilds.Count == 0)
		{
			return 0;
		}
		GlobalPosition value = ((ValueWrapper<GlobalPosition>)(object)Spot.GlobalPosition).Value;
		float num = Mathf.Max(1f, ((ValueWrapper<float>)(object)Spot.Range).Value);
		float num2 = num * num;
		FactionHQ factionHQ = ((Objective)this).FactionHQ;
		int num3 = 0;
		for (int i = 0; i < completedBuilds.Count; i++)
		{
			ConstructionManager.CompletedBuild completedBuild = completedBuilds[i];
			if ((!((Object)(object)factionHQ != (Object)null) || !((Object)(object)completedBuild.HQ != (Object)(object)factionHQ)) && MatchesBuild(completedBuild) && !(FastMath.SquareDistance(completedBuild.Position, value) > num2))
			{
				num3++;
			}
		}
		return num3;
	}

	private bool MatchesBuild(ConstructionManager.CompletedBuild build)
	{
		if (string.IsNullOrEmpty(buildId) || buildId == "any")
		{
			return true;
		}
		if (!string.Equals(buildId, build.BuildId, StringComparison.OrdinalIgnoreCase))
		{
			return string.Equals(buildId, build.BuildingJsonKey, StringComparison.OrdinalIgnoreCase);
		}
		return true;
	}

	public override void DrawData(DataDrawer drawer)
	{
		if (drawer != null)
		{
			ConstructionCratePanel.OfferPrefabs(drawer.Prefabs);
		}
		BuildChoices(out var ids, out var labels);
		int num = ids.IndexOf(buildId);
		if (num < 0)
		{
			num = 0;
		}
		DropdownDataField productionField = null;
		drawer.DrawDropdown("Build", labels, num, (Action<int>)delegate(int index)
		{
			if (index >= 0 && index < ids.Count)
			{
				buildId = ids[index];
				production = "";
				RefreshProductionField(productionField);
			}
		});
		productionField = drawer.DrawDropdown("Produces", new List<string>(), 0, (Action<int>)delegate
		{
		});
		RefreshProductionField(productionField);
		drawer.InstantiateWithParent<Vector3DataField>(drawer.Prefabs.VectorFieldPrefab).Setup("Target Spot", (IValueWrapper<Vector3>)(object)Spot.GlobalPosition);
		drawer.InstantiateWithParent<FloatDataField>(drawer.Prefabs.FloatFieldPrefab).Setup("Range", (IValueWrapper<float>)(object)Spot.Range, (FloatSettings?)null);
		drawer.InstantiateWithParent<FloatDataField>(drawer.Prefabs.FloatFieldPrefab).Setup("Count", count, (IntSettings?)null);
		drawer.Space(8);
		drawer.InstantiateWithParent<BoolDataField>(drawer.Prefabs.BoolFieldPrefab).Setup("AI will construct this", (IValueWrapper<bool>)(object)aiBuild);
		drawer.Space(8);
		drawer.DrawLabel("Drag the marker in the world to move the target spot.");
	}

	public override void AddPins(GraphNodeData data)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Expected O, but got Unknown
		((Objective)this).AddPins(data);
		data.InputElements.Add((GraphElementData)new GraphReadOnlyFieldData
		{
			PinId = new PinId("Build"),
			DisplayName = "Build",
			GetText = () => LabelFor(buildId) + " x" + ((ValueWrapper<int>)(object)count).Value + (string.IsNullOrEmpty(production) ? "" : (" making " + ConstructionCatalogue.ProductionName(production))) + (((ValueWrapper<bool>)(object)aiBuild).Value ? " (AI builds)" : "")
		});
	}

	public override IObjectiveEditorUpdate CreateEditorUpdate(Canvas canvas, UIPrefabs prefabs)
	{
		return (IObjectiveEditorUpdate)(object)new ConstructObjectiveEditor(canvas, prefabs, this);
	}

	private static void BuildChoices(out List<string> ids, out List<string> labels)
	{
		ids = new List<string> { "any" };
		labels = new List<string> { "Any construction" };
		foreach (string item in ConstructionCatalogue.AuthoredIds())
		{
			ids.Add(item);
			labels.Add(LabelFor(item));
		}
	}

	private void RefreshProductionField(DropdownDataField field)
	{
		if ((Object)(object)field == (Object)null)
		{
			return;
		}
		ProductionChoices(buildId, production, out var keys, out var labels);
		int num = keys.IndexOf(production ?? "");
		if (num < 0)
		{
			num = 0;
		}
		field.Setup("Produces", labels, num, (Action<int>)delegate(int index)
		{
			if (index >= 0 && index < keys.Count)
			{
				production = keys[index];
			}
		});
		((DataField)field).Interactable = keys.Count > 1;
	}

	private static void ProductionChoices(string buildId, string stored, out List<string> keys, out List<string> labels)
	{
		keys = new List<string> { "" };
		labels = new List<string> { "Cheapest (automatic)" };
		ConstructionCatalogue.BuildOption buildOption = ((string.IsNullOrEmpty(buildId) || buildId == "any") ? null : ConstructionCatalogue.ById(buildId));
		if (buildOption != null && buildOption.ProductionOptions != null)
		{
			string[] productionOptions = buildOption.ProductionOptions;
			foreach (string text in productionOptions)
			{
				if (!string.IsNullOrEmpty(text) && !keys.Contains(text))
				{
					keys.Add(text);
					labels.Add(ConstructionCatalogue.ProductionName(text));
				}
			}
		}
		if (!string.IsNullOrEmpty(stored) && !keys.Contains(stored))
		{
			keys.Add(stored);
			labels.Add(ConstructionCatalogue.ProductionName(stored) + " (not in this install)");
		}
	}

	private static string LabelFor(string id)
	{
		if (string.IsNullOrEmpty(id) || id == "any")
		{
			return "Any construction";
		}
		ConstructionCatalogue.BuildOption buildOption = ConstructionCatalogue.ById(id);
		if (buildOption != null && !string.IsNullOrEmpty(buildOption.DisplayName))
		{
			return buildOption.DisplayName;
		}
		string text = ConstructionCatalogue.AuthoredDisplayName(id);
		if (!string.IsNullOrEmpty(text))
		{
			return text;
		}
		return id;
	}
}
[Serializable]
public class ConstructBuildingSavedObjective : SavedObjective
{
	public const int TypeValue = 5;

	public Vector3 Position;

	public float Range = 500f;

	public string BuildId = "any";

	public int Count = 1;

	public bool AiBuild;

	public string Production = "";

	public override ObjectiveType ObjectiveTypeEnum => (ObjectiveType)5;

	public ConstructBuildingSavedObjective()
	{
	}

	public ConstructBuildingSavedObjective(string name)
		: base(name)
	{
		//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)
		Position = LookedAtPosition();
	}

	private static Vector3 LookedAtPosition()
	{
		//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_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0074: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return Vector3.zero;
			}
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(main.ScreenPointToRay(new Vector3((float)Screen.width / 2f, (float)Screen.height / 2f)), ref val, 100000f, LayerMask.op_Implicit(PhysicsLayers.StaticsMask)))
			{
				GlobalPosition val2 = GlobalPositionExtensions.ToGlobalPosition(((RaycastHit)(ref val)).point);
				return ((GlobalPosition)(ref val2)).AsVector3();
			}
		}
		catch
		{
		}
		return Vector3.zero;
	}
}
public static class ConstructionAssets
{
	private const string BundleName = "constructionops";

	private const string CratePrefabName = "ConstructionCrate";

	private const string CrateDefinitionName = "ConstructionCrateDefinition";

	private const string MountName = "ConstructionMount";

	private const string InfoName = "ConstructionInfo";

	private const string ConfigName = "ConstructionCatalogue";

	private static AssetBundle _bundle;

	public static bool Loaded => (Object)(object)_bundle != (Object)null;

	public static GameObject CratePrefab { get; private set; }

	public static UnitDefinition CrateDefinition { get; private set; }

	public static WeaponMount Mount { get; private set; }

	public static WeaponInfo Info { get; private set; }

	public static ConstructionConfig Config { get; private set; }

	public static bool Load(ManualLogSource log)
	{
		if ((Object)(object)_bundle != (Object)null)
		{
			return true;
		}
		string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		if (string.IsNullOrEmpty(directoryName))
		{
			log.LogError((object)"[assets] could not resolve the plugin directory");
			return false;
		}
		string text = Path.Combine(directoryName, "constructionops");
		if (!File.Exists(text))
		{
			log.LogError((object)("[assets] bundle missing at " + text + " — run the ThunderKit Deploy pipeline"));
			return false;
		}
		_bundle = AssetBundle.LoadFromFile(text);
		if ((Object)(object)_bundle == (Object)null)
		{
			log.LogError((object)("[assets] AssetBundle.LoadFromFile returned null for " + text));
			return false;
		}
		CratePrefab = _bundle.LoadAsset<GameObject>("ConstructionCrate");
		CrateDefinition = _bundle.LoadAsset<UnitDefinition>("ConstructionCrateDefinition");
		Mount = _bundle.LoadAsset<WeaponMount>("ConstructionMount");
		Info = _bundle.LoadAsset<WeaponInfo>("ConstructionInfo");
		Config = _bundle.LoadAsset<ConstructionConfig>("ConstructionCatalogue");
		if ((Object)(object)Config == (Object)null)
		{
			log.LogWarning((object)"[assets] no 'ConstructionCatalogue' in the bundle — using the built-in catalogue.");
		}
		if ((Object)(object)CratePrefab == (Object)null || (Object)(object)CrateDefinition == (Object)null || (Object)(object)Mount == (Object)null)
		{
			log.LogError((object)($"[assets] missing asset(s) — crate={(Object)(object)CratePrefab != (Object)null} " + $"definition={(Object)(object)CrateDefinition != (Object)null} mount={(Object)(object)Mount != (Object)null}. " + "Bundle contains: " + string.Join(", ", _bundle.GetAllAssetNames())));
			return false;
		}
		log.LogInfo((object)$"[assets] bundle loaded, {_bundle.GetAllAssetNames().Length} assets");
		return true;
	}
}
public static class ConstructionCatalogue
{
	public sealed class MaterialLoad
	{
		public readonly string Family;

		public readonly float Tonnes;

		public string DisplayName => FamilyName(Family);

		public MaterialLoad(string family, float tonnes)
		{
			Family = family;
			Tonnes = Mathf.Max(0f, tonnes);
		}
	}

	public sealed class BuildOption
	{
		public string Id;

		public string BuildingJsonKey;

		public string DisplayName;

		public string Summary;

		public MaterialLoad[] BaseManifest;

		public bool RequiresFriendlyAirbase;

		public bool RequiresWarheadStorage;

		public string[] ProductionOptions = new string[0];

		public float ProductionInterval = 900f;

		public BuildingDefinition Definition
		{
			get
			{
				if (Encyclopedia.Lookup != null && Encyclopedia.Lookup.TryGetValue(BuildingJsonKey, out var value))
				{
					return (BuildingDefinition)(object)((value is BuildingDefinition) ? value : null);
				}
				return null;
			}
		}
	}

	private const string Munitions = "MunitionsContainer1";

	private const string NavalSupply = "NavalSupplyContainer1";

	private const string RadarCrate = "RadarContainer1";

	private const string Fuel = "FuelContainer3";

	private static List<BuildOption> _resolved;

	private static ConstructionConfig _source;

	private static readonly List<BuildOption> Empty = new List<BuildOption>();

	private static readonly Dictionary<string, string> FamilyByContainer = new Dictionary<string, string>
	{
		{ "NavalSupplyContainer1", "naval" },
		{ "NavalPallet1", "naval" },
		{ "MunitionsContainer1", "munitions" },
		{ "MunitionsPallet1", "munitions" },
		{ "MunitionsPallet2", "munitions" },
		{ "FuelContainer1", "fuel" },
		{ "FuelContainer2", "fuel" },
		{ "FuelContainer3", "fuel" },
		{ "RadarContainer1", "radar" }
	};

	public const string FamilyNaval = "naval";

	public const string FamilyMunitions = "munitions";

	public const string FamilyFuel = "fuel";

	public const string FamilyRadar = "radar";

	private static int MaxPerLine
	{
		get
		{
			if (_resolved == null)
			{
				Resolve();
			}
			if (!((Object)(object)_source != (Object)null))
			{
				return 20;
			}
			return Mathf.Max(1, _source.maxLoadsPerLine);
		}
	}

	public static IList<BuildOption> Options
	{
		get
		{
			if (_resolved == null)
			{
				Resolve();
			}
			return _resolved ?? Empty;
		}
	}

	public static ConstructionConfig BuiltIn()
	{
		ConstructionConfig constructionConfig = ScriptableObject.CreateInstance<ConstructionConfig>();
		constructionConfig.builds = new ConstructionConfig.BuildEntry[6]
		{
			Entry("radar", "radarStation1", "Radar Station", "Faction-wide detection from this position.", Mat(ConstructionConfig.MaterialFamily.RadarEquipment, 20f)),
			Entry("bunker", "ammunitionBunker", "Munitions Bunker", "Forward rearming point. Adds warhead storage when built at an airbase.", Mat(ConstructionConfig.MaterialFamily.Munitions, 20f), Mat(ConstructionConfig.MaterialFamily.NavalSupply, 10f)),
			Airbased(Entry("shelter", "shelter1", "Hardened Aircraft Shelter", "Aircraft capacity and warhead storage. Must be built at a friendly airbase.", Mat(ConstructionConfig.MaterialFamily.NavalSupply, 20f), Mat(ConstructionConfig.MaterialFamily.Munitions, 10f))),
			Entry("depot", "VehicleDepot1", "Vehicle Depot", "Produces ground vehicles here, rather than into faction-wide supply.", Mat(ConstructionConfig.MaterialFamily.NavalSupply, 20f), Mat(ConstructionConfig.MaterialFamily.Munitions, 10f), Mat(ConstructionConfig.MaterialFamily.Fuel, 8.5f)),
			Factory(Entry("factory", "factory_large", "Aircraft Factory", "Adds airframes to faction supply, usable from any friendly airbase. Each airframe has its own material cost.", Mat(ConstructionConfig.MaterialFamily.NavalSupply, 30f), Mat(ConstructionConfig.MaterialFamily.Munitions, 20f), Mat(ConstructionConfig.MaterialFamily.Fuel, 8.5f))),
			Warheads(Entry("warheads", "enrichmentPlant1", "Nuclear Warhead Plant", "Produces warheads. Useless unless the faction owns an airbase with storage.", Mat(ConstructionConfig.MaterialFamily.NavalSupply, 40f), Mat(ConstructionConfig.MaterialFamily.Munitions, 40f), Mat(ConstructionConfig.MaterialFamily.Fuel, 17f)))
		};
		return constructionConfig;
	}

	private static ConstructionConfig.MaterialEntry Mat(ConstructionConfig.MaterialFamily family, float tonnes)
	{
		return new ConstructionConfig.MaterialEntry
		{
			family = family,
			tonnes = tonnes
		};
	}

	private static ConstructionConfig.BuildEntry Entry(string id, string building, string name, string summary, params ConstructionConfig.MaterialEntry[] manifest)
	{
		return new ConstructionConfig.BuildEntry
		{
			id = id,
			buildingJsonKey = building,
			displayName = name,
			summary = summary,
			manifest = manifest
		};
	}

	private static ConstructionConfig.BuildEntry Airbased(ConstructionConfig.BuildEntry e)
	{
		e.requiresFriendlyAirbase = true;
		return e;
	}

	private static ConstructionConfig.BuildEntry Factory(ConstructionConfig.BuildEntry e)
	{
		e.productionSource = ConstructionConfig.ProductionSource.AllAircraft;
		e.productionInterval = 900f;
		return e;
	}

	private static ConstructionConfig.BuildEntry Warheads(ConstructionConfig.BuildEntry e)
	{
		e.requiresWarheadStorage = true;
		e.productionSource = ConstructionConfig.ProductionSource.ExplicitList;
		e.productionOptions = new string[1] { "Nuclear Warhead" };
		e.productionInterval = 1200f;
		return e;
	}

	public static BuildOption ById(string id)
	{
		if (string.IsNullOrEmpty(id))
		{
			return null;
		}
		IList<BuildOption> options = Options;
		for (int i = 0; i < options.Count; i++)
		{
			if (options[i].Id == id)
			{
				return options[i];
			}
		}
		return null;
	}

	public static string FamilyId(ConstructionConfig.MaterialFamily family)
	{
		return family switch
		{
			ConstructionConfig.MaterialFamily.Munitions => "munitions", 
			ConstructionConfig.MaterialFamily.Fuel => "fuel", 
			ConstructionConfig.MaterialFamily.RadarEquipment => "radar", 
			_ => "naval", 
		};
	}

	public static string FamilyOf(string containerJsonKey)
	{
		if (string.IsNullOrEmpty(containerJsonKey))
		{
			return null;
		}
		if (!FamilyByContainer.TryGetValue(containerJsonKey, out var value))
		{
			return null;
		}
		return value;
	}

	public static string FamilyName(string family)
	{
		return family switch
		{
			"naval" => "Naval supply", 
			"munitions" => "Munitions", 
			"fuel" => "Fuel", 
			"radar" => "Radar equipment", 
			_ => family, 
		};
	}

	public static List<string> ContainersFor(string family)
	{
		List<string> list = new List<string>();
		foreach (KeyValuePair<string, string> item in FamilyByContainer)
		{
			if (item.Value == family)
			{
				list.Add(item.Key);
			}
		}
		return list;
	}

	public static float TonnesOf(UnitDefinition definition)
	{
		if (!((Object)(object)definition != (Object)null))
		{
			return 0f;
		}
		return Mathf.Max(0f, definition.mass) * 0.001f;
	}

	public static float TonnesOf(string containerJsonKey)
	{
		if (string.IsNullOrEmpty(containerJsonKey) || Encyclopedia.Lookup == null)
		{
			return 0f;
		}
		if (!Encyclopedia.Lookup.TryGetValue(containerJsonKey, out var value))
		{
			return 0f;
		}
		return TonnesOf(value);
	}

	public static bool IsMaterial(string jsonKey)
	{
		string text = FamilyOf(jsonKey);
		if (text == null)
		{
			return false;
		}
		IList<BuildOption> options = Options;
		for (int i = 0; i < options.Count; i++)
		{
			for (int j = 0; j < options[i].BaseManifest.Length; j++)
			{
				if (options[i].BaseManifest[j].Family == text)
				{
					return true;
				}
			}
		}
		return false;
	}

	public static int ProductionRank(string productionKey)
	{
		if (string.IsNullOrEmpty(productionKey) || Encyclopedia.Lookup == null)
		{
			return 0;
		}
		if (!Encyclopedia.Lookup.TryGetValue(productionKey, out var value))
		{
			return 0;
		}
		AircraftDefinition val = (AircraftDefinition)(object)((value is AircraftDefinition) ? value : null);
		if ((Object)(object)val == (Object)null || (Object)(object)val.aircraftParameters == (Object)null)
		{
			return 0;
		}
		return Mathf.Max(0, val.aircraftParameters.rankRequired);
	}

	public static List<MaterialLoad> ResolveManifest(BuildOption option, string productionKey)
	{
		List<MaterialLoad> list = new List<MaterialLoad>();
		if (option == null)
		{
			return list;
		}
		int maxPerLine = MaxPerLine;
		ConstructionConfig.AircraftProductionEntry aircraftProductionEntry = AircraftOverride(productionKey);
		if (aircraftProductionEntry != null && aircraftProductionEntry.manifestOverride != null && aircraftProductionEntry.manifestOverride.Length != 0)
		{
			ConstructionConfig.MaterialEntry[] manifestOverride = aircraftProductionEntry.manifestOverride;
			foreach (ConstructionConfig.MaterialEntry materialEntry in manifestOverride)
			{
				if (materialEntry != null)
				{
					list.Add(new MaterialLoad(FamilyId(materialEntry.family), Mathf.Clamp(materialEntry.tonnes, 1f, (float)maxPerLine)));
				}
			}
			if (list.Count > 0)
			{
				return list;
			}
			Plugin.Log.LogWarning((object)("[catalogue] the manifest override for '" + productionKey + "' has no usable lines — using the build's own manifest."));
		}
		float num = ((aircraftProductionEntry != null && aircraftProductionEntry.loadsMultiplier > 0f) ? aircraftProductionEntry.loadsMultiplier : 1f);
		MaterialLoad[] baseManifest = option.BaseManifest;
		foreach (MaterialLoad materialLoad in baseManifest)
		{
			float num2 = materialLoad.Tonnes * num;
			list.Add(new MaterialLoad(materialLoad.Family, Mathf.Clamp(num2, 1f, (float)maxPerLine)));
		}
		return list;
	}

	public static ConstructionConfig.AircraftProductionEntry AircraftOverride(string productionKey)
	{
		if (_resolved == null)
		{
			Resolve();
		}
		if (!((Object)(object)_source != (Object)null))
		{
			return null;
		}
		return _source.FindAircraft(productionKey);
	}

	public static float ProductionInterval(BuildOption option, string productionKey)
	{
		ConstructionConfig.AircraftProductionEntry aircraftProductionEntry = AircraftOverride(productionKey);
		if (aircraftProductionEntry != null && aircraftProductionEntry.productionInterval > 0f)
		{
			return aircraftProductionEntry.productionInterval;
		}
		return option?.ProductionInterval ?? 900f;
	}

	public static float TotalLoads(IList<MaterialLoad> manifest)
	{
		float num = 0f;
		if (manifest == null)
		{
			return num;
		}
		for (int i = 0; i < manifest.Count; i++)
		{
			num += manifest[i].Tonnes;
		}
		return num;
	}

	private static void Resolve()
	{
		if (Encyclopedia.Lookup == null)
		{
			return;
		}
		_source = ConstructionAssets.Config;
		if ((Object)(object)_source == (Object)null || _source.builds == null || _source.builds.Length == 0)
		{
			if ((Object)(object)_source != (Object)null)
			{
				Plugin.Log.LogWarning((object)"[catalogue] the bundled catalogue asset has no builds — falling back to the built-in table.");
			}
			_source = BuiltIn();
		}
		_resolved = new List<BuildOption>();
		List<string> list = new List<string>();
		ConstructionConfig.BuildEntry[] builds = _source.builds;
		foreach (ConstructionConfig.BuildEntry buildEntry in builds)
		{
			if (buildEntry != null && !string.IsNullOrEmpty(buildEntry.buildingJsonKey))
			{
				BuildOption buildOption = Convert(buildEntry);
				if (buildOption == null)
				{
					list.Add(buildEntry.buildingJsonKey);
				}
				else
				{
					_resolved.Add(buildOption);
				}
			}
		}
		if (_resolved.Count == 0)
		{
			Plugin.Log.LogError((object)"[catalogue] no buildable types resolved — the panel will be empty.");
		}
		else if (list.Count > 0)
		{
			Plugin.Log.LogWarning((object)("[catalogue] dropped, not present in this install: " + string.Join(", ", list.ToArray())));
		}
		Plugin.Log.LogInfo((object)($"[catalogue] {_resolved.Count} build type(s) from " + (((Object)(object)ConstructionAssets.Config != (Object)null) ? "the bundled asset" : "the built-in table") + $"; {((_source.aircraftProduction != null) ? _source.aircraftProduction.Length : 0)} " + "per-airframe entr(ies)."));
	}

	private static BuildOption Convert(ConstructionConfig.BuildEntry entry)
	{
		if (!Encyclopedia.Lookup.TryGetValue(entry.buildingJsonKey, out var value))
		{
			return null;
		}
		BuildingDefinition val = (BuildingDefinition)(object)((value is BuildingDefinition) ? value : null);
		if ((Object)(object)val == (Object)null || (Object)(object)((UnitDefinition)val).unitPrefab == (Object)null)
		{
			return null;
		}
		List<MaterialLoad> list = new List<MaterialLoad>();
		if (entry.manifest != null)
		{
			ConstructionConfig.MaterialEntry[] manifest = entry.manifest;
			foreach (ConstructionConfig.MaterialEntry materialEntry in manifest)
			{
				if (materialEntry != null)
				{
					list.Add(new MaterialLoad(FamilyId(materialEntry.family), Mathf.Max(1f, materialEntry.tonnes)));
				}
			}
		}
		if (list.Count == 0)
		{
			Plugin.Log.LogWarning((object)("[catalogue] '" + entry.id + "' has an empty manifest and was skipped — a build with no materials would complete immediately."));
			return null;
		}
		return new BuildOption
		{
			Id = (string.IsNullOrEmpty(entry.id) ? entry.buildingJsonKey : entry.id),
			BuildingJsonKey = entry.buildingJsonKey,
			DisplayName = (string.IsNullOrEmpty(entry.displayName) ? ((UnitDefinition)val).unitName : entry.displayName),
			Summary = (entry.summary ?? ""),
			BaseManifest = list.ToArray(),
			RequiresFriendlyAirbase = entry.requiresFriendlyAirbase,
			RequiresWarheadStorage = entry.requiresWarheadStorage,
			ProductionOptions = ResolveProduction(entry),
			ProductionInterval = Mathf.Max(1f, entry.productionInterval)
		};
	}

	private static string[] ResolveProduction(ConstructionConfig.BuildEntry entry)
	{
		switch (entry.productionSource)
		{
		case ConstructionConfig.ProductionSource.ExplicitList:
			return entry.productionOptions ?? new string[0];
		case ConstructionConfig.ProductionSource.AllAircraft:
		{
			List<string> list = new List<string>();
			if ((Object)(object)Encyclopedia.i != (Object)null && Encyclopedia.i.aircraft != null)
			{
				foreach (AircraftDefinition item in Encyclopedia.i.aircraft)
				{
					if (!((Object)(object)item == (Object)null) && !string.IsNullOrEmpty(((UnitDefinition)item).jsonKey))
					{
						ConstructionConfig.AircraftProductionEntry aircraftProductionEntry = (((Object)(object)_source != (Object)null) ? _source.FindAircraft(((UnitDefinition)item).jsonKey) : null);
						if (aircraftProductionEntry == null || aircraftProductionEntry.canProduce)
						{
							list.Add(((UnitDefinition)item).jsonKey);
						}
					}
				}
			}
			list.Sort((string a, string b) => ProductionRank(a).CompareTo(ProductionRank(b)));
			return list.ToArray();
		}
		default:
			return new string[0];
		}
	}

	public static List<string> AuthoredIds()
	{
		List<string> list = new List<string>();
		foreach (ConstructionConfig.BuildEntry item in AuthoredEntries())
		{
			if (!string.IsNullOrEmpty(item.id))
			{
				list.Add(item.id);
			}
		}
		return list;
	}

	public static string AuthoredDisplayName(string id)
	{
		foreach (ConstructionConfig.BuildEntry item in AuthoredEntries())
		{
			if (item.id == id)
			{
				return string.IsNullOrEmpty(item.displayName) ? item.buildingJsonKey : item.displayName;
			}
		}
		return null;
	}

	private static IEnumerable<ConstructionConfig.BuildEntry> AuthoredEntries()
	{
		ConstructionConfig constructionConfig = ConstructionAssets.Config;
		if ((Object)(object)constructionConfig == (Object)null || constructionConfig.builds == null || constructionConfig.builds.Length == 0)
		{
			constructionConfig = BuiltIn();
		}
		ConstructionConfig.BuildEntry[] builds = constructionConfig.builds;
		foreach (ConstructionConfig.BuildEntry buildEntry in builds)
		{
			if (buildEntry != null)
			{
				yield return buildEntry;
			}
		}
	}

	public static string ProductionName(string key)
	{
		if (string.IsNullOrEmpty(key))
		{
			return "nothing";
		}
		if (Encyclopedia.Lookup != null && Encyclopedia.Lookup.TryGetValue(key, out var value) && (Object)(object)value != (Object)null && !string.IsNullOrEmpty(value.unitName))
		{
			return value.unitName;
		}
		return key;
	}

	public static void Reset()
	{
		_resolved = null;
		_source = null;
	}
}
[CreateAssetMenu(fileName = "ConstructionCatalogue", menuName = "ConstructionOps/Construction Catalogue", order = 0)]
public class ConstructionConfig : ScriptableObject
{
	public enum ProductionSource
	{
		None,
		ExplicitList,
		AllAircraft
	}

	[Serializable]
	public enum MaterialFamily
	{
		NavalSupply,
		Munitions,
		Fuel,
		RadarEquipment
	}

	[Serializable]
	public class MaterialEntry
	{
		public MaterialFamily family;

		[Min(0f)]
		public float tonnes = 10f;
	}

	[Serializable]
	public class BuildEntry
	{
		[Tooltip("Stable id, written to the site state file. Changing it orphans sites that are already part-built in a running mission.")]
		public string id = "";

		[Tooltip("Encyclopedia jsonKey of the STOCK BuildingDefinition to spawn.")]
		public string buildingJsonKey = "";

		[Tooltip("Shown in the panel. Leave blank to use the building's own unitName.")]
		public string displayName = "";

		[Tooltip("One line explaining what the finished building does.")]
		[TextArea(2, 4)]
		public string summary = "";

		[Tooltip("The material that must be flown in, in panel order. For the Aircraft Factory this is only the fallback — a per-airframe entry below normally decides the cost.")]
		public MaterialEntry[] manifest = new MaterialEntry[0];

		[Tooltip("Refuse this build unless a friendly airbase is within AirbaseAttachRadius. Needed by anything carrying Hangar or WarheadStorage, which are inert unless the building is a member of an airbase.")]
		public bool requiresFriendlyAirbase;

		[Tooltip("Refuse this build unless the faction already owns an airbase with warhead storage. Without one FactionHQ.AddWarheadStockpile discards the output and the plant produces nothing, forever.")]
		public bool requiresWarheadStorage;

		public ProductionSource productionSource;

		[Tooltip("Used when productionSource is ExplicitList. Either an Encyclopedia jsonKey, or the literal string \"Nuclear Warhead\", which Factory.SetFactory treats as a special case rather than looking it up.")]
		public string[] productionOptions = new string[0];

		[Tooltip("Seconds between production ticks. The game's own default is 900. For the Aircraft Factory a per-airframe entry below can override this.")]
		[Min(1f)]
		public float productionInterval = 900f;
	}

	[Serializable]
	public class AircraftProductionEntry
	{
		[Tooltip("Encyclopedia jsonKey of the aircraft, e.g. Fighter1 (FS-12 Revoker), QuadVTOL1 (VL-49 Tarantula), FastBomber1 (Alkyon AB-4). The full list for THIS install is in the AIRCRAFT ROSTER section of BepInEx/ConstructionOps.probe.txt.")]
		public string aircraftJsonKey = "";

		[Tooltip("Human note for whoever edits this asset. Not used by the mod.")]
		public string aircraftName = "";

		[Tooltip("Untick to remove this airframe from the factory's production dropdown.")]
		public bool canProduce = true;

		[Tooltip("Exact manifest for a factory producing this airframe. This is the normal way to tune an aircraft. Leave EMPTY to fall back to loadsMultiplier, and then to the Aircraft Factory's own base manifest.")]
		public MaterialEntry[] manifestOverride = new MaterialEntry[0];

		[Tooltip("Shortcut: multiply the factory's base manifest instead of writing one out. 0 = unused. Ignored when manifestOverride has entries.")]
		[Min(0f)]
		public float loadsMultiplier;

		[Tooltip("Seconds between this airframe rolling off the line. 0 = use the Aircraft Factory's own productionInterval.")]
		[Min(0f)]
		public float productionInterval;
	}

	[Tooltip("The catalogue, in the order the panel offers it.")]
	public BuildEntry[] builds = new BuildEntry[0];

	[Tooltip("Per-airframe cost and rate for the Aircraft Factory. An airframe with no entry costs the factory's own base manifest.")]
	public AircraftProductionEntry[] aircraftProduction = new AircraftProductionEntry[0];

	[Tooltip("Safety clamp on any single manifest line, so a typo cannot demand 500 containers.")]
	[Min(1f)]
	public int maxLoadsPerLine = 20;

	public AircraftProductionEntry FindAircraft(string jsonKey)
	{
		if (string.IsNullOrEmpty(jsonKey) || aircraftProduction == null)
		{
			return null;
		}
		for (int i = 0; i < aircraftProduction.Length; i++)
		{
			AircraftProductionEntry aircraftProductionEntry = aircraftProduction[i];
			if (aircraftProductionEntry != null && string.Equals(aircraftProductionEntry.aircraftJsonKey, jsonKey, StringComparison.OrdinalIgnoreCase))
			{
				return aircraftProductionEntry;
			}
		}
		return null;
	}
}
internal static class ConstructionCratePanel
{
	private class Block
	{
		public GameObject Root;

		public BoolDataField AiBuild;

		public DropdownDataField Build;

		public DropdownDataField Production;
	}

	private const string BlockName = "ConstructionCrateSettings";

	private const string PatchId = "hendev.constructionops.unitpanel";

	private static bool _patched;

	private static bool _loggedFailure;

	private static FieldInfo _targetsField;

	private static UIPrefabs _prefabs;

	private static readonly ConditionalWeakTable<UnitPanel, Block> _blocks = new ConditionalWeakTable<UnitPanel, Block>();

	public static void OfferPrefabs(UIPrefabs prefabs)
	{
		if ((Object)(object)prefabs != (Object)null && (Object)(object)_prefabs == (Object)null)
		{
			_prefabs = prefabs;
		}
	}

	public static void Apply(Harmony harmony)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Expected O, but got Unknown
		if (_patched)
		{
			return;
		}
		_patched = true;
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(UnitPanel), "OnTargetsChanged", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogWarning((object)"[panel] UnitPanel.OnTargetsChanged not found — a placed crate cannot be configured in the editor. Crates still work; only authoring them does not.");
				return;
			}
			_targetsField = AccessTools.Field(typeof(UnitPanel), "targets");
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(ConstructionCratePanel), "OnTargetsChangedPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Plugin.Log.LogInfo((object)"[panel] Mission Editor unit panel patched — a selected construction crate can be set to build something.");
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("[panel] could not patch UnitPanel (" + ex.GetType().Name + ": " + ex.Message + ") — continuing without the crate settings."));
		}
	}

	private static void OnTargetsChangedPostfix(UnitPanel __instance)
	{
		try
		{
			Refresh(__instance);
		}
		catch (Exception ex)
		{
			if (!_loggedFailure)
			{
				_loggedFailure = true;
				Plugin.Log.LogError((object)("[panel] crate settings failed and are now inert (" + ex.GetType().Name + ": " + ex.Message + "). The editor itself is unaffected."));
			}
		}
	}

	private static void Refresh(UnitPanel panel)
	{
		if ((Object)(object)panel == (Object)null || _targetsField == null)
		{
			return;
		}
		bool anythingElse;
		List<SavedUnit> list = CollectCrates(panel, out anythingElse);
		if (list.Count == 0 || anythingElse)
		{
			if (_blocks.TryGetValue(panel, out var value) && value != null && (Object)(object)value.Root != (Object)null)
			{
				value.Root.SetActive(false);
			}
			return;
		}
		Block orCreateBlock = GetOrCreateBlock(panel);
		if (orCreateBlock != null && !((Object)(object)orCreateBlock.Root == (Object)null))
		{
			orCreateBlock.Root.SetActive(true);
			Bind(orCreateBlock, list, panel);
			FixLayout.RebuildRoot(((Component)panel).gameObject);
		}
	}

	private static void Bind(Block block, List<SavedUnit> selected, UnitPanel panel)
	{
		ConstructionCrateSettings constructionCrateSettings = ConstructionCratePlacements.Get(selected[0]);
		if ((Object)(object)block.AiBuild != (Object)null)
		{
			ValueWrapperBool val = ValueWrapper.FromCallback<ValueWrapperBool, bool>((object)panel, constructionCrateSettings.AiBuild, (Action<bool>)delegate(bool v)
			{
				foreach (SavedUnit item in selected)
				{
					ConstructionCratePlacements.Get(item).AiBuild = v;
				}
			});
			block.AiBuild.Setup("AI will build this", (IValueWrapper<bool>)(object)val);
		}
		List<string> buildIds = new List<string> { "" };
		List<string> list = new List<string> { "Player chooses" };
		foreach (ConstructionCatalogue.BuildOption option in ConstructionCatalogue.Options)
		{
			if (option != null)
			{
				buildIds.Add(option.Id);
				list.Add(option.DisplayName);
			}
		}
		if ((Object)(object)block.Build != (Object)null)
		{
			int num = buildIds.IndexOf(constructionCrateSettings.BuildId ?? "");
			if (num < 0)
			{
				num = 0;
			}
			block.Build.Setup("Build", list, num, (Action<int>)delegate(int index)
			{
				if (index >= 0 && index < buildIds.Count)
				{
					foreach (SavedUnit item2 in selected)
					{
						ConstructionCrateSettings constructionCrateSettings2 = ConstructionCratePlacements.Get(item2);
						constructionCrateSettings2.BuildId = buildIds[index];
						constructionCrateSettings2.Production = "";
					}
					BindProduction(block, selected);
				}
			});
		}
		BindProduction(block, selected);
	}

	private static void BindProduction(Block block, List<SavedUnit> targets)
	{
		if (block == null || (Object)(object)block.Production == (Object)null || targets.Count == 0)
		{
			return;
		}
		ConstructionCrateSettings constructionCrateSettings = ConstructionCratePlacements.Get(targets[0]);
		ConstructionCatalogue.BuildOption buildOption = (string.IsNullOrEmpty(constructionCrateSettings.BuildId) ? null : ConstructionCatalogue.ById(constructionCrateSettings.BuildId));
		List<string> keys = new List<string> { "" };
		List<string> list = new List<string> { "Cheapest (automatic)" };
		if (buildOption != null && buildOption.ProductionOptions != null)
		{
			string[] productionOptions = buildOption.ProductionOptions;
			foreach (string text in productionOptions)
			{
				if (!string.IsNullOrEmpty(text))
				{
					keys.Add(text);
					list.Add(ConstructionCatalogue.ProductionName(text));
				}
			}
		}
		int num = keys.IndexOf(constructionCrateSettings.Production ?? "");
		if (num < 0)
		{
			num = 0;
		}
		block.Production.Setup("Produces", list, num, (Action<int>)delegate(int index)
		{
			if (index < 0 || index >= keys.Count)
			{
				return;
			}
			foreach (SavedUnit target in targets)
			{
				ConstructionCratePlacements.Get(target).Production = keys[index];
			}
		});
		((DataField)block.Production).Interactable = keys.Count > 1;
	}

	private static List<SavedUnit> CollectCrates(UnitPanel panel, out bool anythingElse)
	{
		anythingElse = false;
		List<SavedUnit> list = new List<SavedUnit>();
		object value = _targetsField.GetValue(panel);
		if (value == null)
		{
			return list;
		}
		PropertyInfo property = value.GetType().GetProperty("Targets");
		IEnumerable enumerable = ((property != null) ? (property.GetValue(value) as IEnumerable) : null);
		if (enumerable == null)
		{
			return list;
		}
		foreach (object item in enumerable)
		{
			SavedUnit val = (SavedUnit)((item is SavedUnit) ? item : null);
			if (val != null)
			{
				if (ConstructionCratePlacements.IsCrate(val))
				{
					list.Add(val);
				}
				else
				{
					anythingElse = true;
				}
			}
		}
		return list;
	}

	private static Block GetOrCreateBlock(UnitPanel panel)
	{
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Expected O, but got Unknown
		if (_blocks.TryGetValue(panel, out var value) && value != null && (Object)(object)value.Root != (Object)null)
		{
			return value;
		}
		_blocks.Remove(panel);
		UIPrefabs val = ResolvePrefabs();
		if ((Object)(object)val == (Object)null || (Object)(object)val.BoolFieldPrefab == (Object)null || (Object)(object)val.Dropdown == (Object)null)
		{
			if (!_loggedFailure)
			{
				_loggedFailure = true;
				Plugin.Log.LogWarning((object)"[panel] the editor's field prefabs could not be found — a placed crate cannot be configured. Open any objective's panel once and reselect the crate; that hands us the prefabs.");
			}
			return null;
		}
		GameObject val2 = new GameObject("ConstructionCrateSettings", new Type[1] { typeof(RectTransform) });
		val2.transform.SetParent(((Component)panel).transform, false);
		VerticalLayoutGroup obj = val2.AddComponent<VerticalLayoutGroup>();
		((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
		((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
		((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
		((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
		ContentSizeFitter obj2 = val2.AddComponent<ContentSizeFitter>();
		obj2.verticalFit = (FitMode)2;
		obj2.horizontalFit = (FitMode)0;
		Block block = new Block
		{
			Root = val2
		};
		block.AiBuild = Object.Instantiate<BoolDataField>(val.BoolFieldPrefab, val2.transform);
		((Object)((Component)block.AiBuild).gameObject).name = "ConstructionCrateSettings.AiBuild";
		((Component)block.AiBuild).gameObject.SetActive(true);
		block.Build = Object.Instantiate<DropdownDataField>(val.Dropdown, val2.transform);
		((Object)((Component)block.Build).gameObject).name = "ConstructionCrateSettings.Build";
		((Component)block.Build).gameObject.SetActive(true);
		block.Build.LabelWidth(160);
		block.Production = Object.Instantiate<DropdownDataField>(val.Dropdown, val2.transform);
		((Object)((Component)block.Production).gameObject).name = "ConstructionCrateSettings.Production";
		((Component)block.Production).gameObject.SetActive(true);
		block.Production.LabelWidth(160);
		_blocks.Add(panel, block);
		return block;
	}

	private static UIPrefabs ResolvePrefabs()
	{
		if ((Object)(object)_prefabs != (Object)null)
		{
			return _prefabs;
		}
		UIPrefabs[] array = Resources.FindObjectsOfTypeAll<UIPrefabs>();
		if (array != null && array.Length != 0)
		{
			return _prefabs = array[0];
		}
		_prefabs = ReflectFrom<ObjectiveEditorV2>("prefabs") ?? ReflectFrom<EditObjectivePanel>("prefabs") ?? ReflectFrom<EditOutcomePanel>("prefabs") ?? ReflectFrom<AirbasePanel>("uiPrefabs");
		return _prefabs;
	}

	private static UIPrefabs ReflectFrom<T>(string fieldName) where T : Component
	{
		FieldInfo fieldInfo = AccessTools.Field(typeof(T), fieldName);
		if (fieldInfo == null)
		{
			return null;
		}
		T[] array = Resources.FindObjectsOfTypeAll<T>();
		foreach (T val in array)
		{
			object? value = fieldInfo.GetValue(val);
			UIPrefabs val2 = (UIPrefabs)((value is UIPrefabs) ? value : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
		}
		return null;
	}
}
public class ConstructionCrateSettings
{
	public bool AiBuild;

	public string BuildId = "";

	public string Production = "";

	public bool IsDefault
	{
		get
		{
			if (!AiBuild && string.IsNullOrEmpty(BuildId))
			{
				return string.IsNullOrEmpty(Production);
			}
			return false;
		}
	}
}
public static class ConstructionCratePlacements
{
	private const string PropertyName = "constructionCrate";

	private static readonly ConditionalWeakTable<SavedUnit, ConstructionCrateSettings> _byPlacement = new ConditionalWeakTable<SavedUnit, ConstructionCrateSettings>();

	private static bool _installed;

	public static bool IsCrate(SavedUnit saved)
	{
		if (saved != null)
		{
			return saved.type == "hendev_construction_crate";
		}
		return false;
	}

	public static ConstructionCrateSettings Get(SavedUnit saved)
	{
		return _byPlacement.GetValue(saved, (SavedUnit _) => new ConstructionCrateSettings());
	}

	public static bool TryGet(SavedUnit saved, out ConstructionCrateSettings settings)
	{
		settings = null;
		if (saved != null)
		{
			return _byPlacement.TryGetValue(saved, out settings);
		}
		return false;
	}

	public static void Set(SavedUnit saved, ConstructionCrateSettings settings)
	{
		if (saved != null && settings != null)
		{
			_byPlacement.Remove(saved);
			_byPlacement.Add(saved, settings);
		}
	}

	public static void Install()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Expected O, but got Unknown
		//IL_004a: Expected O, but got Unknown
		if (_installed)
		{
			return;
		}
		try
		{
			MissionContainerExtras.Register("constructionCrate", new WriteExtra(Write), new ReadExtra(Read), (Action<string>)delegate(string message)
			{
				Plugin.Log.LogWarning((object)("[mission] " + message));
			});
			_installed = true;
			Plugin.Log.LogInfo((object)"[mission] placed construction crates will keep their build settings in mission.json.");
		}
		catch (Exception ex)
		{
			_installed = true;
			Plugin.Log.LogError((object)("[mission] could not install the mission converter (" + ex.GetType().Name + ": " + ex.Message + ") — crates stay editable but their settings will not survive a save."));
		}
	}

	private static JToken Write(SavedContainer container, JsonSerializer serializer)
	{
		if (!IsCrate((SavedUnit)(object)container))
		{
			return null;
		}
		if (!TryGet((SavedUnit)(object)container, out var settings) || settings == null || settings.IsDefault)
		{
			return null;
		}
		return (JToken)(object)JObject.FromObject((object)settings, serializer);
	}

	private static void Read(SavedContainer container, JToken stored, JsonSerializer serializer)
	{
		ConstructionCrateSettings constructionCrateSettings = stored.ToObject<ConstructionCrateSettings>(serializer);
		if (constructionCrateSettings != null)
		{
			Set((SavedUnit)(object)container, constructionCrateSettings);
		}
	}
}
public static class ConstructionLogistics
{
	private sealed class Sortie
	{
		public Loadout Loadout;

		public AircraftDefinition Definition;

		public FactionHQ HQ;

		public int SiteId = -1;

		public string Objective;

		public string MaterialKey;

		public string Family;

		public float TonnesEach;

		public GlobalPosition Target;

		public float LaunchedAt;

		public bool DelayedSpawn;

		public Aircraft Aircraft;

		public ConstructionTransportState State;

		public int Containers = 1;

		public int Dropped;

		public float LastDropAt;

		public bool Borrowed;

		public int Slot;

		public bool Released;

		public float ReleasedAt;

		public bool IsCrate => string.IsNullOrEmpty(MaterialKey);
	}

	private sealed class CrateAttempts
	{
		public int Failures;

		public float LastFailureAt;

		public string LastReason;

		public readonly HashSet<string> Tried = new HashSet<string>();
	}

	private static readonly List<Sortie> _sorties = new List<Sortie>();

	private static readonly Dictionary<string, WeaponMount> _mountForMaterial = new Dictionary<string, WeaponMount>();

	private static bool _mountsMapped;

	private static readonly HashSet<string> _warned = new HashSet<string>();

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

	private static readonly HashSet<string> _verdictSeen = new HashSet<string>();

	private static readonly Dictionary<string, CrateAttempts> _crateAttempts = new Dictionary<string, CrateAttempts>();

	private const float CrateRetryCooldown = 12f;

	private static float _lastDispatch;

	private static float _pacing;

	private const float SettleClaimSeconds = 45f;

	private static FieldInfo _activeAiField;

	public static int ActiveSorties => _sorties.Count;

	public static void Reset()
	{
		_sorties.Clear();
		_mountForMaterial.Clear();
		_mountsMapped = false;
		_warned.Clear();
		_verdict.Clear();
		_verdictSeen.Clear();
		_crateAttempts.Clear();
		_lastDispatch = 0f;
		_pacing = 0f;
	}

	public static void Tick()
	{
		if (Plugin.AiEnabled.Value && ConstructionManager.CanBuild)
		{
			PruneSorties();
			AdoptSpawnedHaulers();
			BorrowIdleCarriers();
			TaskAirborneHaulers();
			Plan();
		}
	}

	private static void PruneSorties()
	{
		for (int num = _sorties.Count - 1; num >= 0; num--)
		{
			Sortie sortie = _sorties[num];
			float num2 = Time.timeSinceLevelLoad - sortie.LaunchedAt;
			if ((Object)(object)sortie.Aircraft == (Object)null)
			{
				float num3 = (sortie.DelayedSpawn ? 240f : 90f);
				if (num2 > num3)
				{
					Plugin.Log.LogInfo((object)("[ai] sortie for " + Describe(sortie) + " never appeared after " + $"{num3:F0}s — giving up on it."));
					if (sortie.IsCrate)
					{
						RecordCrateFailure(sortie, "the airframe never left the hangar");
					}
					_sorties.RemoveAt(num);
				}
			}
			else
			{
				bool flag = (Object)(object)sortie.Aircraft == (Object)null || ((Unit)sortie.Aircraft).disabled;
				bool flag2 = sortie.State != null && sortie.State.Finished;
				if ((!sortie.Released || !(Time.timeSinceLevelLoad - sortie.ReleasedAt < 60f)) && (flag || flag2 || num2 > Plugin.AiSortieTimeout.Value + 120f))
				{
					if (flag && !sortie.Released)
					{
						Plugin.Log.LogInfo((object)("[ai] hauler for " + Describe(sortie) + " was lost before delivering."));
					}
					if (sortie.IsCrate && sortie.Dropped == 0)
					{
						RecordCrateFailure(sortie, flag ? "the hauler was lost on the way" : (flag2 ? "the hauler gave up and went home" : "the errand ran out of time"));
					}
					_sorties.RemoveAt(num);
				}
			}
		}
	}

	private static void AdoptSpawnedHaulers()
	{
		List<Aircraft> allAircraft = UnitRegistry.allAircraft;
		for (int i = 0; i < allAircraft.Count; i++)
		{
			Aircraft val = allAircraft[i];
			if ((Object)(object)val == (Object)null || ((Unit)val).disabled || (Object)(object)val.Player != (Object)null)
			{
				continue;
			}
			for (int j = 0; j < _sorties.Count; j++)
			{
				Sortie sortie = _sorties[j];
				if (!((Object)(object)sortie.Aircraft != (Object)null) && val.loadout == sortie.Loadout)
				{
					sortie.Aircraft = val;
					Plugin.Log.LogInfo((object)("[ai] hauler " + ((UnitDefinition)val.definition).jsonKey + " airborne for " + Describe(sortie) + " carrying " + DescribeCargo(val) + "."));
					break;
				}
			}
		}
	}

	private static void TaskAirborneHaulers()
	{
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < _sorties.Count; i++)
		{
			Sortie sortie = _sorties[i];
			if ((Object)(object)sortie.Aircraft == (Object)null || ((Unit)sortie.Aircraft).disabled || sortie.State != null)
			{
				continue;
			}
			Pilot val = FirstPilot(sortie.Aircraft);
			if ((Object)(object)val == (Object)null || val.dead || val.ejected || val.playerControlled)
			{
				continue;
			}
			PilotBaseState currentState = val.currentState;
			if (currentState is AIPilotCombatModes || currentState is AIHeloCombatState || currentState is AIHeloTransportState)
			{
				Sortie captured = sortie;
				sortie.State = new ConstructionTransportState(sortie.Aircraft, sortie.Target, () => StillWanted(captured), delegate
				{
					OnReleased(captured);
				}, captured.Containers);
				val.SwitchState((PilotBaseState)(object)sortie.State);
				Plugin.Log.LogInfo((object)("[ai] hauler " + ((UnitDefinition)sortie.Aircraft.definition).jsonKey + " tasked: " + Describe(sortie) + "."));
			}
		}
	}

	private static string DescribeCargo(Aircraft ac)
	{
		if (((Unit)ac).weaponStations == null || ((Unit)ac).weaponStations.Count == 0)
		{
			return "nothing (no stations)";
		}
		List<string> list = new List<string>();
		foreach (WeaponStation weaponStation in ((Unit)ac).weaponStations)
		{
			if (weaponStation != null && !((Object)(object)weaponStation.WeaponInfo == (Object)null) && (weaponStation.WeaponInfo.cargo || weaponStation.WeaponInfo.troops))
			{
				list.Add($"'{weaponStation.WeaponInfo.weaponName}' x{weaponStation.Ammo}" + (weaponStation.SafetyIsOn(ac) ? " [SAFETY ON]" : ""));
			}
		}
		if (list.Count != 0)
		{
			return string.Join(", ", list);
		}
		return "nothing (no cargo station loaded)";
	}

	private static void BorrowIdleCarriers()
	{
		//IL_0170: 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_0181: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.AiBorrowIdleCarriers.Value)
		{
			return;
		}
		List<Aircraft> allAircraft = UnitRegistry.allAircraft;
		for (int i = 0; i < allAircraft.Count; i++)
		{
			Aircraft val = allAircraft[i];
			if ((Object)(object)val == (Object)null || ((Unit)val).disabled || (Object)(object)val.Player != (Object)null || (Object)(object)((Unit)val).NetworkHQ == (Object)null || SortieFor(val) != null)
			{
				continue;
			}
			Pilot val2 = FirstPilot(val);
			if (!((Object)(object)val2 == (Object)null) && !val2.dead && !val2.ejected && !val2.playerControlled && val2.currentState != null && !(val2.currentState.stateDisplayName != "Awaiting Cargo Mission") && ReadCargo(val, out var materialKey, out var containers))
			{
				ConstructionSite constructionSite = NearestSiteNeeding(val, materialKey);
				if (constructionSite != null)
				{
					Sortie sortie = new Sortie
					{
						Loadout = val.loadout,
						Definition = val.definition,
						HQ = ((Unit)val).NetworkHQ,
						SiteId = constructionSite.Id,
						MaterialKey = materialKey,
						LaunchedAt = Time.timeSinceLevelLoad,
						Aircraft = val,
						Containers = containers,
						Family = ConstructionCatalogue.FamilyOf(materialKey),
						TonnesEach = ContainerMass(materialKey),
						Borrowed = true,
						Slot = FreeSlot(constructionSite.Id)
					};
					sortie.Target = SlotPosition(constructionSite.Position, sortie.Slot);
					_sorties.Add(sortie);
					Plugin.Log.LogInfo((object)("[ai] borrowed idle " + ((UnitDefinition)val.definition).jsonKey + " carrying " + $"{containers}x '{materialKey}' — sending it to site {constructionSite.Id} " + "(costs the faction nothing; it was already flying)."));
				}
			}
		}
	}

	private static Sortie SortieFor(Aircraft ac)
	{
		for (int i = 0; i < _sorties.Count; i++)
		{
			if (_sorties[i].Aircraft == ac)
			{
				return _sorties[i];
			}
		}
		return null;
	}

	private static bool ReadCargo(Aircraft ac, out string materialKey, out int containers)
	{
		materialKey = null;
		containers = 0;
		if (((Unit)ac).weaponStations == null)
		{
			return false;
		}
		foreach (WeaponStation weaponStation in ((Unit)ac).weaponStations)
		{
			if (weaponStation == null || (Object)(object)weaponStation.WeaponInfo == (Object)null || !weaponStation.WeaponInfo.cargo || weaponStation.Ammo <= 0 || weaponStation.Weapons == null)
			{
				continue;
			}
			foreach (Weapon weapon in weaponStation.Weapons)
			{
				MountedCargo val = (MountedCargo)(object)((weapon is MountedCargo) ? weapon : null);
				if ((Object)(object)val == (Object)null || ((Weapon)val).ammo <= 0 || (Object)(object)val.cargo == (Object)null)
				{
					continue;
				}
				string jsonKey = val.cargo.jsonKey;
				if (!string.IsNullOrEmpty(jsonKey) && ConstructionCatalogue.IsMaterial(jsonKey))
				{
					if (materialKey == null)
					{
						materialKey = jsonKey;
					}
					else if (materialKey != jsonKey)
					{
						return false;
					}
					containers++;
				}
			}
		}
		if (materialKey != null)
		{
			return containers > 0;
		}
		return false;
	}

	private static ConstructionSite NearestSiteNeeding(Aircraft ac, string materialKey)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		GlobalPosition val = GlobalPositionExtensions.GlobalPosition((Unit)(object)ac);
		ConstructionSite result = null;
		float num = float.MaxValue;
		IList<ConstructionSite> sites = ConstructionManager.Sites;
		for (int i = 0; i < sites.Count; i++)
		{
			ConstructionSite constructionSite = sites[i];
			if (constructionSite.AiSupplied && !constructionSite.Completed && constructionSite.Build != null && !((Object)(object)constructionSite.HQ != (Object)(object)((Unit)ac).NetworkHQ) && constructionSite.Wants(materialKey) && !(OutstandingAt(constructionSite, ConstructionCatalogue.FamilyOf(materialKey)) <= 0f))
			{
				float num2 = FastMath.SquareDistance(val, constructionSite.Position);
				if (!(num2 >= num))
				{
					num = num2;
					result = constructionSite;
				}
			}
		}
		return result;
	}

	private static float OutstandingAt(ConstructionSite site, string family)
	{
		return Mathf.Max(0f, site.OutstandingFor(family) - InFlightFor(site.Id, family));
	}

	private static bool StillWanted(Sortie sortie)
	{
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		if (sortie.IsCrate)
		{
			return CrateStillWanted(sortie);
		}
		ConstructionSite constructionSite = FindSiteById(sortie.SiteId);
		if (constructionSite == null || constructionSite.Completed || (constructionSite.Build != null && !constructionSite.Wants(sortie.MaterialKey)))
		{
			ConstructionSite constructionSite2 = NearestSiteWanting(sortie);
			if (constructionSite2 == null)
			{
				Plugin.Log.LogInfo((object)("[ai] " + Describe(sortie) + ": the site no longer wants it and no other site does — returning to base with the load."));
				return false;
			}
			Plugin.Log.LogInfo((object)("[ai] " + Describe(sortie) + ": original site is done — diverting to " + $"site {constructionSite2.Id}."));
			sortie.SiteId = constructionSite2.Id;
			constructionSite = constructionSite2;
		}
		GlobalPosition position = (sortie.Target = SlotPosition(constructionSite.Position, sortie.Slot));
		sortie.State?.Retarget(position);
		return true;
	}

	private static bool CrateStillWanted(Sortie sortie)
	{
		if (sortie.Dropped > 0)
		{
			return true;
		}
		ConstructBuildingObjective constructBuildingObjective = FindObjective(sortie.Objective);
		if (constructBuildingObjective == null)
		{
			return true;
		}
		if (constructBuildingObjective.CountMatching() >= constructBuildingObjective.RequiredCountForDiagnostics)
		{
			Plugin.Log.LogInfo((object)("[ai] " + Describe(sortie) + ": the objective is already satisfied — returning to base with the crate."));
			return false;
		}
		FactionHQ factionHQ = ((Objective)constructBuildingObjective).FactionHQ;
		if ((Object)(object)factionHQ != (Object)null && FindSiteFor(constructBuildingObjective, factionHQ) != null)
		{
			Plugin.Log.LogInfo((object)("[ai] " + Describe(sortie) + ": a site already stands at the spot — returning to base with the crate."));
			return false;
		}
		return true;
	}

	private static ConstructionSite NearestSiteWanting(Sortie sortie)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: 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_0075: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)sortie.Aircraft == (Object)null || string.IsNullOrEmpty(sortie.MaterialKey))
		{
			return null;
		}
		GlobalPosition val = GlobalPositionExtensions.GlobalPosition((Unit)(object)sortie.Aircraft);
		ConstructionSite result = null;
		float num = float.MaxValue;
		IList<ConstructionSite> sites = ConstructionManager.Sites;
		for (int i = 0; i < sites.Count; i++)
		{
			ConstructionSite constructionSite = sites[i];
			if (!constructionSite.Completed && !((Object)(object)constructionSite.HQ != (Object)(object)sortie.HQ) && constructionSite.Wants(sortie.MaterialKey))
			{
				float num2 = FastMath.SquareDistance(val, constructionSite.Position);
				if (!(num2 >= num))
				{
					num = num2;
					result = constructionSite;
				}
			}
		}
		return result;
	}

	private static ConstructBuildingObjective FindObjective(string uniqueName)
	{
		if (string.IsNullOrEmpty(uniqueName))
		{
			return null;
		}
		MissionRunner runner = MissionManager.Runner;
		if (runner == null || runner.ActiveObjectives == null)
		{
			return null;
		}
		for (int i = 0; i < runner.ActiveObjectives.Count; i++)
		{
			if (runner.ActiveObjectives[i] is ConstructBuildingObjective constructBuildingObjective && ((Objective)constructBuildingObjective).SavedObjective.UniqueName == uniqueName)
			{
				return constructBuildingObjective;
			}
		}
		return null;
	}

	private static void OnReleased(Sortie sortie)
	{
		//IL_001f: 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)
		sortie.Dropped++;
		sortie.LastDropAt = Time.timeSinceLevelLoad;
		float num = FastMath.Distance(sortie.State.ReleasePosition, sortie.Target);
		Plugin.Log.LogInfo((object)($"[ai] container {sortie.Dropped}/{sortie.Containers} released for {Describe(sortie)} — " + $"{num:F0} m from the aim point (delivery radius {Plugin.DeliveryRadius.Value:F0} m)."));
		if (sortie.Dropped >= sortie.Containers)
		{
			sortie.Released = true;
			sortie.ReleasedAt = Time.timeSinceLevelLoad;
		}
	}

	private static void Plan()
	{
		if (Time.timeSinceLevelLoad - _lastDispatch < Plugin.AiDispatchInterval.Value)
		{
			_pacing = Plugin.AiDispatchInterval.Value - (Time.timeSinceLevelLoad - _lastDispatch);
			return;
		}
		_pacing = 0f;
		_verdictSeen.Clear();
		if (!PlanCrates())
		{
			PlanMaterials();
		}
		PruneVerdicts();
	}

	private static bool PlanCrates()
	{
		MissionRunner runner = MissionManager.Runner;
		if (runner == null || runner.ActiveObjectives == null)
		{
			return false;
		}
		for (int i = 0; i < runner.ActiveObjectives.Count; i++)
		{
			if (!(runner.ActiveObjectives[i] is ConstructBuildingObjective { AiBuild: not false } constructBuildingObjective))
			{
				continue;
			}
			FactionHQ factionHQ = ((Objective)constructBuildingObjective).FactionHQ;
			if ((Object)(object)factionHQ == (Object)null || constructBuildingObjective.CountMatching() >= constructBuildingObjective.RequiredCountForDiagnostics)
			{
				continue;
			}
			ConstructionSite constructionSite = FindSiteFor(constructBuildingObjective, factionHQ);
			if (constructionSite != null)
			{
				constructionSite.AiSupplied = true;
				ClearCrateAttempts(((Objective)constructBuildingObjective).SavedObjective.UniqueName);
				if (constructionSite.AwaitingChoice && !AutoChoose(constructionSite, constructBuildingObjective))
				{
					Verdict(((Objective)constructBuildingObjective).SavedObjective.UniqueName, $"waiting — site {constructionSite.Id} is untasked; the AI leaves a new crate alone " + $"for AI/ClaimDelay = {Plugin.AiClaimDelay.Value:F0}s so a player can choose first");
				}
				continue;
			}
			if (CrateInFlightFor(constructBuildingObjective) != null)
			{
				Verdict(((Objective)constructBuildingObjective).SavedObjective.UniqueName, "waiting — the crate is on its way; nothing else flies until it is down");
				continue;
			}
			string uniqueName = ((Objective)constructBuildingObjective).SavedObjective.UniqueName;
			CrateAttempts crateAttempts = AttemptsFor(uniqueName);
			if (crateAttempts != null && Time.timeSinceLevelLoad - crateAttempts.LastFailureAt < 12f)
			{
				Verdict(uniqueName, "waiting — the last crate run failed (" + crateAttempts.LastReason + "); " + $"attempt {crateAttempts.Failures + 1} goes out in " + $"{12f - (Time.timeSinceLevelLoad - crateAttempts.LastFailureAt):F0}s");
			}
			else if (TryLaunchCrate(constructBuildingObjective, factionHQ))
			{
				return true;
			}
		}
		return false;
	}

	private static bool PlanMaterials()
	{
		IList<ConstructionSite> sites = ConstructionManager.Sites;
		for (int i = 0; i < sites.Count; i++)
		{
			ConstructionSite constructionSite = sites[i];
			if (constructionSite.AiSupplied && !constructionSite.Completed && constructionSite.Build != null && !((Object)(object)constructionSite.HQ == (Object)null) && TryLaunchMaterial(constructionSite))
			{
				return true;
			}
		}
		return false;
	}

	private static Sortie CrateInFlightFor(ConstructBuildingObjective objective)
	{
		string uniqueName = ((Objective)objective).SavedObjective.UniqueName;
		for (int i = 0; i < _sorties.Count; i++)
		{
			Sortie sortie = _sorties[i];
			if (sortie.IsCrate && sortie.Objective == uniqueName)
			{
				return sortie;
			}
		}
		return null;
	}

	private static GlobalPosition SlotPosition(GlobalPosition centre, int slot)
	{
		//IL_0052: 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_006d: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Min(Plugin.DeliveryRadius.Value * 0.5f, 45f);
		num = Mathf.Clamp(num, 18f, Mathf.Max(18f, Plugin.DeliveryRadius.Value - 8f));
		float num2 = (float)(slot % 6) * 60f * (MathF.PI / 180f);
		return centre + new Vector3(Mathf.Cos(num2) * num, 0f, Mathf.Sin(num2) * num);
	}

	private static int FreeSlot(int siteId)
	{
		for (int i = 0; i < 6; i++)
		{
			bool flag = false;
			for (int j = 0; j < _sorties.Count; j++)
			{
				if (_sorties[j].SiteId == siteId && _sorties[j].Slot == i)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return i;
			}
		}
		return 0;
	}

	private static ConstructionSite FindSiteFor(ConstructBuildingObjective objective, FactionHQ hq)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		GlobalPosition targetPosition = objective.TargetPosition;
		float targetRange = objective.TargetRange;
		float num = targetRange * targetRange;
		IList<ConstructionSite> sites = ConstructionManager.Sites;
		for (int i = 0; i < sites.Count; i++)
		{
			ConstructionSite constructionSite = sites[i];
			if (!constructionSite.Completed && !((Object)(object)constructionSite.HQ != (Object)(object)hq) && !(FastMath.SquareDistance(constructionSite.Position, targetPosition) > num))
			{
				return constructionSite;
			}
		}
		return null;
	}

	private static ConstructionSite FindSiteById(int id)
	{
		IList<ConstructionSite> sites = ConstructionManager.Sites;
		for (int i = 0; i < sites.Count; i++)
		{
			if (sites[i].Id == id)
			{
				return sites[i];
			}
		}
		return null;
	}

	private static bool AutoChoose(ConstructionSite site, ConstructBuildingObjective objective)
	{
		if (Time.timeSinceLevelLoad - site.CreatedAt < Plugin.AiClaimDelay.Value)
		{
			return false;
		}
		ConstructionCatalogue.BuildOption buildOption = ResolveBuild(site, objective);
		if (buildOption == null)
		{
			WarnOnce(objective, "cannot pick a build for '" + objective.BuildIdForDiagnostics + "' — no catalogue entry matches, or its prerequisites are unmet here.");
			return false;
		}
		string text = ChosenProduction(buildOption, objective);
		if (!ConstructionManager.ChooseBuild(site, buildOption, text))
		{
			return false;
		}
		Plugin.Log.LogInfo((object)($"[ai] site {site.Id} tasked by objective " + "'" + ((Objective)objective).SavedObjective.UniqueName + "' -> " + buildOption.DisplayName + ((text != null) ? (" producing " + ConstructionCatalogue.ProductionName(text)) : "")));
		return true;
	}

	private static ConstructionCatalogue.BuildOption ResolveBuild(ConstructionSite site, ConstructBuildingObjective objective)
	{
		string buildIdForDiagnostics = objective.BuildIdForDiagnostics;
		if (!string.IsNullOrEmpty(buildIdForDiagnostics) && buildIdForDiagnostics != "any")
		{
			ConstructionCatalogue.BuildOption buildOption = ConstructionCatalogue.ById(buildIdForDiagnostics);
			if (buildOption == null || !Buildable(site, buildOption))
			{
				return null;
			}
			return buildOption;
		}
		ConstructionCatalogue.BuildOption result = null;
		float num = float.MaxValue;
		IList<ConstructionCatalogue.BuildOption> options = ConstructionCatalogue.Options;
		for (int i = 0; i < options.Count; i++)
		{
			ConstructionCatalogue.BuildOption buildOption2 = options[i];
			if (Buildable(site, buildOption2))
			{
				float num2 = ConstructionCatalogue.TotalLoads(ConstructionCatalogue.ResolveManifest(buildOption2, CheapestProduction(buildOption2)));
				if (!(num2 <= 0f) && !(num2 >= num))
				{
					result = buildOption2;
					num = num2;
				}
			}
		}
		return result;
	}

	private static bool Buildable(ConstructionSite site, ConstructionCatalogue.BuildOption option)
	{
		if (option == null || (Object)(object)option.Definition == (Object)null)
		{
			return false;
		}
		if (option.RequiresFriendlyAirbase && (Object)(object)ConstructionManager.NearestFriendlyAirbase(site, Plugin.AirbaseAttachRadius.Value) == (Object)null)
		{
			return false;
		}
		if (option.RequiresWarheadStorage && !ConstructionManager.FactionHasStorage(site.HQ))
		{
			return false;
		}
		return true;
	}

	private static string ChosenProduction(ConstructionCatalogue.BuildOption option, ConstructBuildingObjective objective)
	{
		string text = objective?.RequestedProduction;
		if (!string.IsNullOrEmpty(text) && option != null && option.ProductionOptions != null)
		{
			string[] productionOptions = option.ProductionOptions;
			foreach (string text2 in productionOptions)
			{
				if (string.Equals(text2, text, StringComparison.OrdinalIgnoreCase))
				{
					return text2;
				}
			}
			WarnOnce(objective, "'" + option.DisplayName + "' cannot produce '" + text + "' — building the cheapest option instead.");
		}
		return CheapestProduction(option);
	}

	private static string CheapestProduction(ConstructionCatalogue.BuildOption option)
	{
		if (option == null || option.ProductionOptions == null || option.ProductionOptions.Length == 0)
		{
			return null;
		}
		string text = null;
		int num = int.MaxValue;
		string[] productionOptions = option.ProductionOptions;
		foreach (string text2 in productionOptions)
		{
			if (!string.IsNullOrEmpty(text2))
			{
				int num2 = ConstructionCatalogue.ProductionRank(text2);
				if (num2 < num)
				{
					text = text2;
					num = num2;
				}
			}
		}
		return text ?? option.ProductionOptions[0];
	}

	private static bool TryLaunchCrate(ConstructBuildingObjective objective, FactionHQ hq)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		if (!AllowedAnother(hq, -1, ((Objective)objective).SavedObjective.UniqueName))
		{
			return false;
		}
		if ((Object)(object)ConstructionAssets.Mount == (Object)null)
		{
			return false;
		}
		GlobalPosition? val = FindBuildableSpot(objective.TargetPosition, Mathf.Min(objective.TargetRange, 400f));
		if (!val.HasValue)
		{
			WarnOnce(objective, "no ground flat enough to build on within range of the target " + $"spot (limit {Plugin.MaxSlopeDegrees.Value:F0}°) — the AI has " + "nowhere to put a crate.");
			return false;
		}
		CrateAttempts crateAttempts = AttemptsFor(((Objective)objective).SavedObjective.UniqueName);
		return Launch(hq, ConstructionAssets.Mount, val.Value, -1, ((Objective)objective).SavedObjective.UniqueName, null, 1, crateAttempts?.Tried);
	}

	private static bool TryLaunchMaterial(ConstructionSite site)
	{
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		string text = "site " + site.Id;
		if (!AllowedAnother(site.HQ, site.Id, text))
		{
			return false;
		}
		bool flag = false;
		for (int i = 0; i < site.Required.Count; i++)
		{
			ConstructionCatalogue.MaterialLoad materialLoad = site.Required[i];
			float num = site.Outstanding(materialLoad) - InFlightFor(site.Id, materialLoad.Family);
			if (num <= 0f)
			{
				continue;
			}
			flag = true;
			List<KeyValuePair<string, WeaponMount>> list = MountsForFamily(materialLoad.Family);
			if (list.Count == 0)
			{
				WarnOnce(text, "nothing in the Encyclopedia delivers " + materialLoad.DisplayName + " that an aircraft can carry — the AI cannot fly this build's manifest.");
				continue;
			}
			bool flag2 = false;
			for (int j = 0; j < list.Count; j++)
			{
				if (flag2)
				{
					break;
				}
				string key = list[j].Key;
				float num2 = ContainerMass(key);
				int num3 = ((!(num2 > 0f)) ? 1 : Mathf.CeilToInt(num / num2));
				flag2 = Launch(site.HQ, list[j].Value, site.Position, site.Id, text, key, Mathf.Max(1, num3));
			}
			if (flag2)
			{
				return true;
			}
		}
		if (!flag)
		{
			Verdict(text, "nothing outstanding — every remaining load is already in the air");
		}
		return false;
	}

	private static bool Launch(FactionHQ hq, WeaponMount mount, GlobalPosition target, int siteId, string objectiveName, string materialKey, int wanted, HashSet<string> avoid = null)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: 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_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		if (!ChooseHauler(hq, mount, target, wanted, avoid, out var definition, out var airbase, out var cargoSets, out var containers))
		{
			Verdict(objectiveName, "BLOCKED — no airframe can carry '" + mount.mountName + "': every candidate either has no hardpoint set offering that mount, is " + $"down to its supply reserve (AI/SupplyReserve = {Plugin.AiSupplyReserve.Value}), " + "or has no airbase able to launch it");
			return false;
		}
		Loadout val = BuildLoadout(definition, mount, cargoSets);
		if (val == null)
		{
			Verdict(objectiveName, "BLOCKED — could not build a loadout for " + ((UnitDefinition)definition).jsonKey);
			return false;
		}
		AircraftParameters aircraftParameters = definition.aircraftParameters;
		LiveryKey val2 = default(LiveryKey);
		((LiveryKey)(ref val2))..ctor(aircraftParameters.GetRandomLiveryForFaction(hq.faction));
		TrySpawnResult val3;
		try
		{
			val3 = airbase.TrySpawnAircraft((Player)null, definition, val2, val, aircraftParameters.DefaultFuelLevel);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("[ai] spawning " + ((UnitDefinition)definition).jsonKey + " threw: " + ex.Message));
			return false;
		}
		if (!val3.Allowed)
		{
			Verdict(objectiveName, "waiting — " + ((Object)airbase).name + " refused to spawn " + ((UnitDefinition)definition).jsonKey + " (no free hangar, or the airbase cannot field that type right now)");
			return false;
		}
		Sortie sortie = new Sortie
		{
			Loadout = val,
			Definition = definition,
			HQ = hq,
			SiteId = siteId,
			Objective = objectiveName,
			MaterialKey = materialKey,
			Target = target,
			LaunchedAt = Time.timeSinceLevelLoad,
			DelayedSpawn = val3.DelayedSpawn,
			Containers = Mathf.Clamp(containers, 1, Mathf.Max(1, wanted)),
			Family = ConstructionCatalogue.FamilyOf(materialKey),
			TonnesEach = ContainerMass(materialKey),
			Slot = ((siteId >= 0) ? FreeSlot(siteId) : 0)
		};
		if (siteId >= 0)
		{
			sortie.Target = SlotPosition(target, sortie.Slot);
		}
		_sorties.Add(sortie);
		Plugin.Log.LogInfo((object)("[ai] dispatching " + ((UnitDefinition)definition).jsonKey + " from " + ((Object)airbase).name + " for " + $"{Describe(sortie)} x{sortie.Containers}" + (val3.DelayedSpawn ? " (queued behind hangar doors)" : "")));
		Verdict(objectiveName, null);
		_lastDispatch = Time.timeSinceLevelLoad;
		return true;
	}

	private static bool ChooseHauler(FactionHQ hq, WeaponMount mount, GlobalPosition target, int wanted, HashSet<string> avoid, out AircraftDefinition definition, out Airbase airbase, out List<int> cargoSets, out int containers)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		definition = null;
		airbase = null;
		cargoSets = null;
		containers = 0;
		for (int i = 0; i < 2; i++)
		{
			bool flag = i == 0 && avoid != null && avoid.Count > 0;
			if (i == 1 && (avoid == null || avoid.Count <= 0))
			{
				break;
			}
			if (Pick(hq, mount, target, wanted, flag ? avoid : null, out definition, out airbase, out cargoSets, out containers))
			{
				return true;
			}
		}
		return false;
	}

	private static bool Pick(FactionHQ hq, WeaponMount mount, GlobalPosition target, int wanted, HashSet<string> avoid, out AircraftDefinition definition, out Airbase airbase, out List<int> cargoSets, out int containers)
	{
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		definition = null;
		airbase = null;
		cargoSets = null;
		containers = 0;
		int num = int.MinValue;
		float num2 = float.MaxValue;
		foreach (AircraftDefinition item in Encyclopedia.i.aircraft)
		{
			if ((Object)(object)item == (Object)null || (Object)(object)((UnitDefinition)item).unitPrefab == (Object)null || (avoid != null && avoid.Contains(((UnitDefinition)item).jsonKey)))
			{
				continue;
			}
			int containers2;
			List<int> list = CargoSetIndices(item, mount, wanted, out containers2);
			if (list.Count == 0 || containers2 <= 0 || hq.GetUnitSupply((UnitDefinition)(object)item) <= Plugin.AiSupplyReserve.Value)
			{
				continue;
			}
			float distance;
			Airbase val = NearestSpawnableAirbase(hq, item, target, out distance);
			if (!((Object)(object)val == (Object)null))
			{
				int num3 = Mathf.Min(containers2, Mathf.Max(1, wanted));
				bool flag = IsRotorcraft(item);
				int num4 = num3 * 10000 + ((flag && Plugin.AiPreferRotorcraft.Value) ? 1000 : 0) - item.aircraftParameters.rankRequired;
				if (num4 >= num && (num4 != num || !(distance >= num2)))
				{
					num = num4;
					num2 = distance;
					definition = item;
					airbase = val;
					cargoSets = list;
					containers = containers2;
				}
			}
		}
		return (Object)(object)definition != (Object)null;
	}

	private static List<int> CargoSetIndices(AircraftDefinition definition, WeaponMount mount, int wanted, out int containers)
	{
		containers = 0;
		List<int> list = new List<int>();
		WeaponManager componentInChildren = ((UnitDefinition)definition).unitPrefab.GetComponentInChildren<WeaponManager>(true);
		if ((Object)(object)componentInChildren == (Object)null || componentInChildren.hardpointSets == null)
		{
			return list;
		}
		int num = Mathf.Max(1, mount.ammo);
		int num2 = Mathf.Max(1, wanted);
		for (int i = 0; i < componentInChildren.hardpointSets.Length; i++)
		{
			if (containers >= num2)
			{
				break;
			}
			HardpointSet val = componentInChildren.hardpointSets[i];
			if (val != null && val.weaponOptions != null && val.weaponOptions.Contains(mount))
			{
				list.Add(i);
				containers += Mathf.Max(1, (val.hardpoints == null) ? 1 : val.hardpoints.Count) * num;
			}
		}
		return list;
	}

	private static Loadout BuildLoadout(AircraftDefinition definition, WeaponMount mount, List<int> cargoSets)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		WeaponManager componentInChildren = ((UnitDefinition)definition).unitPrefab.GetComponentInChildren<WeaponManager>(true);
		if ((Object)(object)componentInChildren == (Object)null || componentInChildren.hardpointSets == null)
		{
			return null;
		}
		Loadout val = new Loadout();
		for (int i = 0; i < componentInChildren.hardpointSets.Length; i++)
		{
			val.weapons.Add(cargoSets.Contains(i) ? mount : null);
		}
		return val;
	}

	private static Airbase NearestSpawnableAirbase(FactionHQ hq, AircraftDefinition definition, GlobalPosition target, out float distance)
	{
		//IL_0036: 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)
		Airbase result = null;
		distance = float.MaxValue;
		foreach (Airbase airbasis in hq.GetAirbases())
		{
			if (!((Object)(object)airbasis == (Object)null) && airbasis.CanSpawnAircraft(definition))
			{
				float num = FastMath.Distance(GlobalPositionExtensions.GlobalPosition(airbasis.center), target);
				if (!(num >= distance))
				{
					distance = num;
					result = airbasis;
				}
			}
		}
		return result;
	}

	private static GlobalPosition? FindBuildableSpot(GlobalPosition centre, float searchRadius)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: 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)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		if (TryGround(centre, out var ground))
		{
			return ground;
		}
		float num = Mathf.Max(20f, searchRadius);
		for (float num2 = 40f; num2 <= num; num2 += 40f)
		{
			for (int i = 0; i < 8; i++)
			{
				float num3 = (float)i * MathF.PI * 0.25f;
				if (TryGround(centre + new Vector3(Mathf.Cos(num3) * num2, 0f, Mathf.Sin(num3) * num2), out var ground2))
				{
					return ground2;
				}
			}
		}
		return null;
	}

	private static bool TryGround(GlobalPosition position, out GlobalPosition ground)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or m

BepInEx/plugins/NOHenDev.Common/NOHenDev.Common.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NuclearOption.SavedMission;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NOHenDev.Common
{
	public static class MissionContainerExtras
	{
		public delegate JToken WriteExtra(SavedContainer container, JsonSerializer serializer);

		public delegate void ReadExtra(SavedContainer container, JToken stored, JsonSerializer serializer);

		private sealed class Extra
		{
			public string Property;

			public WriteExtra Write;

			public ReadExtra Read;

			public Action<string> Log;
		}

		private sealed class ContainerConverter : JsonConverter<SavedContainer>
		{
			[ThreadStatic]
			private static bool _isWriting;

			public override bool CanWrite => !_isWriting;

			public override void WriteJson(JsonWriter writer, SavedContainer value, JsonSerializer serializer)
			{
				if (value == null)
				{
					writer.WriteNull();
					return;
				}
				_isWriting = true;
				try
				{
					JObject val = JObject.FromObject((object)value, serializer);
					for (int i = 0; i < _extras.Count; i++)
					{
						Extra extra = _extras[i];
						try
						{
							JToken val2 = extra.Write(value, serializer);
							if (val2 != null)
							{
								val[extra.Property] = val2;
							}
						}
						catch (Exception ex)
						{
							Report(extra, "could not write '" + extra.Property + "' for container '" + ((SavedUnit)value).UniqueName + "': " + ex.GetType().Name + ": " + ex.Message);
						}
					}
					((JToken)val).WriteTo(writer, Array.Empty<JsonConverter>());
				}
				finally
				{
					_isWriting = false;
				}
			}

			public override SavedContainer ReadJson(JsonReader reader, Type objectType, SavedContainer existingValue, bool hasExistingValue, JsonSerializer serializer)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Invalid comparison between Unknown and I4
				//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Expected O, but got Unknown
				if ((int)reader.TokenType == 11)
				{
					return null;
				}
				JObject val = JObject.Load(reader);
				List<KeyValuePair<Extra, JToken>> list = null;
				for (int i = 0; i < _extras.Count; i++)
				{
					Extra extra = _extras[i];
					JToken val2 = val[extra.Property];
					if (val2 != null)
					{
						val.Remove(extra.Property);
						if (list == null)
						{
							list = new List<KeyValuePair<Extra, JToken>>();
						}
						list.Add(new KeyValuePair<Extra, JToken>(extra, val2));
					}
				}
				SavedContainer val3 = (SavedContainer)((hasExistingValue && existingValue != null) ? ((object)existingValue) : ((object)new SavedContainer()));
				JsonReader val4 = ((JToken)val).CreateReader();
				try
				{
					serializer.Populate(val4, (object)val3);
				}
				finally
				{
					((IDisposable)val4)?.Dispose();
				}
				if (list != null)
				{
					for (int j = 0; j < list.Count; j++)
					{
						Extra key = list[j].Key;
						try
						{
							key.Read(val3, list[j].Value, serializer);
						}
						catch (Exception ex)
						{
							Report(key, "ignoring unreadable '" + key.Property + "' on container '" + ((SavedUnit)val3).UniqueName + "': " + ex.GetType().Name + ": " + ex.Message);
						}
					}
				}
				return val3;
			}

			private static void Report(Extra extra, string message)
			{
				if (extra.Log == null)
				{
					return;
				}
				try
				{
					extra.Log(message);
				}
				catch
				{
				}
			}
		}

		private static readonly List<Extra> _extras = new List<Extra>();

		private static bool _installed;

		public static void Register(string property, WriteExtra write, ReadExtra read, Action<string> log = null)
		{
			if (string.IsNullOrEmpty(property) || write == null || read == null)
			{
				return;
			}
			for (int i = 0; i < _extras.Count; i++)
			{
				if (!(_extras[i].Property != property))
				{
					_extras[i].Write = write;
					_extras[i].Read = read;
					_extras[i].Log = log;
					Install();
					return;
				}
			}
			_extras.Add(new Extra
			{
				Property = property,
				Write = write,
				Read = read,
				Log = log
			});
			Install();
		}

		public static void Install()
		{
			if (_installed)
			{
				return;
			}
			JsonSerializerSettings val = NewtonsoftHelper.Default;
			if (val == null || val.Converters == null)
			{
				return;
			}
			foreach (JsonConverter converter in val.Converters)
			{
				if (converter is ContainerConverter)
				{
					_installed = true;
					return;
				}
			}
			val.Converters.Add((JsonConverter)(object)new ContainerConverter());
			_installed = true;
		}
	}
}