Decompiled source of DSPGuideCheck v2.1.83

BepInEx/plugins/DSP-Guide-Check/DspGuideCheck.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("DspGuideCheck")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("An on-demand progression companion for Dyson Sphere Program.")]
[assembly: AssemblyFileVersion("2.1.83.0")]
[assembly: AssemblyInformationalVersion("2.1.83.22a5998")]
[assembly: AssemblyProduct("DSP Guide Check")]
[assembly: AssemblyTitle("DspGuideCheck")]
[assembly: AssemblyVersion("2.1.83.0")]
namespace DspProgressionStatusExporter;

public static class BuildFeatures
{
	public const string Variant = "public";

	public const bool SnapshotControlEnabled = false;
}
internal static class BuildVersion
{
	public const string BepInPluginVersion = "2.1.83";

	public const string PluginVersion = "2.1.83";

	public const string ReleaseLabel = "2.1.83.22a5998";
}
internal static class CompactSnapshotBuilder
{
	private const int ReceiverDetailLimit = 8;

	private const int BufferSourceDetailLimit = 12;

	private static readonly int[] CubeIds = new int[6] { 6001, 6002, 6003, 6004, 6005, 6006 };

	private static readonly int[] IlsPlayerItems = new int[8] { 2001, 2011, 2101, 2201, 2203, 2204, 2301, 2302 };

	private static readonly int[] IlsCargoItems = new int[4] { 1003, 1004, 1105, 1106 };

	private static readonly int[] IlsReserveItems = new int[8] { 1103, 1107, 1203, 1206, 1303, 2104, 5002, 6003 };

	private static readonly Dictionary<string, int[]> PhaseItems = new Dictionary<string, int[]>(StringComparer.OrdinalIgnoreCase)
	{
		{
			"blue",
			new int[14]
			{
				1101, 1104, 1202, 1301, 2001, 2011, 2301, 2302, 2303, 2101,
				2106, 2203, 2201, 6001
			}
		},
		{
			"red",
			new int[3] { 6002, 1114, 1120 }
		},
		{
			"ils",
			new int[20]
			{
				1003, 1004, 1103, 1105, 1106, 1107, 1203, 1206, 1303, 2001,
				2011, 2101, 2104, 2201, 2203, 2204, 2301, 2302, 5002, 6003
			}
		},
		{
			"yellow",
			new int[3] { 6003, 1112, 1118 }
		},
		{
			"purple",
			new int[3] { 6004, 1303, 1402 }
		},
		{
			"green",
			new int[3] { 6005, 1305, 1209 }
		},
		{
			"dyson",
			new int[1] { 1501 }
		},
		{
			"photon",
			new int[2] { 1208, 1122 }
		},
		{
			"white",
			new int[7] { 6001, 6002, 6003, 6004, 6005, 6006, 1122 }
		}
	};

	private static readonly Dictionary<string, int> PhaseRecipeIds = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
	{
		{ "blue", 9 },
		{ "red", 18 },
		{ "yellow", 27 },
		{ "purple", 55 },
		{ "green", 102 },
		{ "white", 75 }
	};

	public static Dictionary<string, object> Build(string schemaVersion, string exporterVersion, Dictionary<string, object> provenance, Dictionary<string, object> game, Dictionary<string, object> location, Dictionary<string, object> research, ObservedGameState state, Dictionary<string, object> selection, Dictionary<string, object> analysis, Dictionary<string, object> presentation, Dictionary<string, object> samplingPerformance, bool includeCollectorDiagnostics)
	{
		string phaseId = Text(Value(Dictionary(analysis, "phase"), "id"));
		Dictionary<string, object> obj = new Dictionary<string, object>
		{
			{ "schemaVersion", schemaVersion },
			{ "exporterVersion", exporterVersion },
			{
				"exportedAtUtc",
				DateTime.UtcNow.ToString("o")
			},
			{ "provenance", provenance },
			{ "game", game },
			{ "location", location },
			{ "guideSelection", selection },
			{
				"guide",
				GuideSummary(analysis)
			},
			{ "presentation", presentation },
			{
				"summary",
				new Dictionary<string, object>
				{
					{
						"research",
						ResearchSummary(research, state)
					},
					{
						"cubes",
						CubeSummary(state)
					}
				}
			},
			{
				"evidence",
				Evidence(phaseId, state, samplingPerformance, includeCollectorDiagnostics)
			},
			{
				"omissions",
				new Dictionary<string, object>
				{
					{ "policy", "Only conclusions and evidence used by implemented guide functions are exported." },
					{
						"omitted",
						new List<object> { "raw factory and entity state", "all-technology rows", "player and mecha detail", "broad inventory detail", "all station slots", "all-item and per-factory telemetry", "broad reflection diagnostics" }
					},
					{
						"detailsTruncated",
						state.Dyson.Receivers.Count > 8
					}
				}
			}
		};
		Validate(obj);
		return obj;
	}

	private static Dictionary<string, object> GuideSummary(Dictionary<string, object> analysis)
	{
		return new Dictionary<string, object>
		{
			{
				"analysisVersion",
				Value(analysis, "analysisVersion")
			},
			{
				"selectionAuthority",
				Value(analysis, "phaseSelectionAuthority")
			},
			{
				"phase",
				Value(analysis, "phase")
			},
			{
				"objectives",
				Value(analysis, "progression")
			},
			{
				"productionRisk",
				Value(analysis, "productionRisk")
			},
			{
				"currentStatus",
				Value(analysis, "findings")
			},
			{
				"limitations",
				Value(analysis, "limitations")
			}
		};
	}

	private static Dictionary<string, object> ResearchSummary(Dictionary<string, object> research, ObservedGameState state)
	{
		int num = 0;
		foreach (object item in Enumerate(Value(research, "technologies")))
		{
			_ = item;
			num++;
		}
		int num2 = 0;
		foreach (object item2 in Enumerate(Value(research, "techQueue")))
		{
			_ = item2;
			num2++;
		}
		Dictionary<string, object> dictionary = new Dictionary<string, object>
		{
			{
				"available",
				Bool(Value(research, "available"))
			},
			{ "totalTechnologies", num },
			{
				"unlockedTechnologies",
				state.UnlockedTechIds.Count
			},
			{ "queuedTechnologies", num2 },
			{
				"currentTechId",
				Value(research, "currentTech")
			},
			{
				"missionAccomplished",
				Value(research, "missionAccomplished")
			}
		};
		if (state.TechProgress.TryGetValue(1508, out var value))
		{
			dictionary["missionCompletedProgress"] = new Dictionary<string, object>
			{
				{ "available", true },
				{ "hashUploaded", value.HashUploaded },
				{ "hashNeeded", value.HashNeeded },
				{ "percent", value.Percent }
			};
		}
		else
		{
			dictionary["missionCompletedProgress"] = new Dictionary<string, object> { { "available", false } };
		}
		return dictionary;
	}

	private static List<object> CubeSummary(ObservedGameState state)
	{
		List<object> list = new List<object>();
		int[] cubeIds = CubeIds;
		foreach (int itemId in cubeIds)
		{
			list.Add(ItemEvidence(state, itemId, includeLifetime: true, includeBufferEvidence: false));
		}
		return list;
	}

	private static Dictionary<string, object> Evidence(string phaseId, ObservedGameState state, Dictionary<string, object> samplingPerformance, bool includeCollectorDiagnostics)
	{
		Dictionary<string, object> dictionary = new Dictionary<string, object>
		{
			{
				"collectors",
				CollectorHealth(state, samplingPerformance, includeCollectorDiagnostics)
			},
			{
				"phaseItems",
				PhaseItemEvidence(phaseId, state)
			},
			{
				"phaseRecipe",
				RecipeEvidence(phaseId, state)
			},
			{
				"logistics",
				LogisticsEvidence(phaseId, state)
			},
			{
				"power",
				PowerEvidence(state)
			}
		};
		if (IsDysonPhase(phaseId))
		{
			dictionary["dyson"] = DysonEvidence(phaseId, state);
		}
		return dictionary;
	}

	private static Dictionary<string, object> CollectorHealth(ObservedGameState state, Dictionary<string, object> samplingPerformance, bool includeCollectorDiagnostics)
	{
		Dictionary<string, object> dictionary = new Dictionary<string, object>
		{
			{ "available", state.ProductionWindowReady },
			{ "source", state.ProductionSource },
			{ "scope", state.ProductionScope },
			{ "period", state.ProductionPeriod },
			{ "windowGameSeconds", state.ProductionWindowSeconds },
			{ "sampleCount", state.ProductionSampleCount },
			{ "watchedItemCount", state.ProductionWatchedItemCount },
			{ "itemCoverage", state.ProductionItemCoverage },
			{ "factoryCount", state.ProductionFactoryCount },
			{
				"windows",
				new Dictionary<string, object>
				{
					{
						"oneMinute",
						new Dictionary<string, object>
						{
							{ "available", state.ProductionWindowReady },
							{ "ready", state.ProductionWindowReady },
							{
								"status",
								state.ProductionWindowReady ? "ready" : "unavailable"
							},
							{ "windowGameSeconds", state.ProductionWindowSeconds }
						}
					},
					{
						"tenMinute",
						new Dictionary<string, object>
						{
							{ "available", state.ProductionTenMinuteWindowAvailable },
							{ "ready", state.ProductionTenMinuteWindowReady },
							{ "status", state.ProductionTenMinuteWindowStatus },
							{ "windowGameSeconds", state.ProductionTenMinuteWindowSeconds },
							{ "readinessSource", state.ProductionTenMinuteReadinessSource },
							{ "availableItemCount", state.ProductionTenMinuteAvailableItemCount },
							{ "readyItemCount", state.ProductionTenMinuteReadyItemCount }
						}
					}
				}
			}
		};
		if (!string.IsNullOrEmpty(state.ProductionFailure))
		{
			dictionary["failure"] = state.ProductionFailure;
		}
		Dictionary<string, object> dictionary2 = new Dictionary<string, object>
		{
			{ "cadenceSeconds", 5.0 },
			{ "production", dictionary },
			{
				"traffic",
				new Dictionary<string, object>
				{
					{ "available", state.TrafficWindowReady },
					{ "windowGameSeconds", state.TrafficWindowSeconds }
				}
			},
			{
				"power",
				new Dictionary<string, object>
				{
					{
						"available",
						state.PowerPlanets.Count > 0
					},
					{ "windowGameSeconds", state.PowerWindowSeconds },
					{
						"planetCount",
						state.PowerPlanets.Count
					}
				}
			},
			{
				"recipes",
				new Dictionary<string, object> { { "available", state.RecipeTelemetryAvailable } }
			},
			{
				"receiverContinuity",
				new Dictionary<string, object>
				{
					{
						"available",
						state.Dyson.ReceiverTelemetryAvailable
					},
					{
						"windowSeconds",
						state.Dyson.ReceiverContinuityWindowSeconds
					}
				}
			}
		};
		if (includeCollectorDiagnostics)
		{
			dictionary2["performance"] = samplingPerformance;
		}
		return dictionary2;
	}

	private static List<object> PhaseItemEvidence(string phaseId, ObservedGameState state)
	{
		if (!PhaseItems.TryGetValue(phaseId ?? "", out var value))
		{
			value = new int[0];
		}
		List<object> list = new List<object>();
		int[] array = value;
		foreach (int itemId in array)
		{
			list.Add(ItemEvidence(state, itemId, includeLifetime: false, includeBufferEvidence: true));
		}
		return list;
	}

	private static Dictionary<string, object> ItemEvidence(ObservedGameState state, int itemId, bool includeLifetime, bool includeBufferEvidence)
	{
		state.ItemFlows.TryGetValue(itemId, out var value);
		state.LifetimeItemTotals.TryGetValue(itemId, out var value2);
		state.OwnedItemCounts.TryGetValue(itemId, out var value3);
		string value4 = ((value != null) ? value.Name : ((value2 != null) ? value2.Name : Plugin.ItemName(itemId)));
		Dictionary<string, object> dictionary = new Dictionary<string, object>
		{
			{ "itemId", itemId },
			{ "name", value4 },
			{ "owned", value3 },
			{
				"nativeWindowAvailable",
				state.ProductionWindowReady && value != null
			},
			{
				"producedPerMinute",
				(value != null) ? ((object)value.ProducedPerMinute) : null
			},
			{
				"consumedPerMinute",
				(value != null) ? ((object)value.ConsumedPerMinute) : null
			},
			{
				"netPerMinute",
				(value != null) ? ((object)value.NetPerMinute) : null
			},
			{
				"observedIntervals",
				(value != null) ? ((object)value.ObservedIntervals) : null
			},
			{
				"productionActiveFraction",
				(value != null) ? ((object)value.ProductionActiveFraction) : null
			},
			{
				"productionContinuity",
				value?.ProductionContinuity
			}
		};
		dictionary["nativeWindows"] = new Dictionary<string, object>
		{
			{
				"oneMinute",
				new Dictionary<string, object>
				{
					{
						"available",
						value?.OneMinuteAvailable ?? false
					},
					{
						"status",
						(value != null) ? value.OneMinuteStatus : "unavailable"
					},
					{
						"producedPerMinute",
						(value != null && value.OneMinuteAvailable) ? ((object)value.ProducedPerMinute) : null
					},
					{
						"consumedPerMinute",
						(value != null && value.OneMinuteAvailable) ? ((object)value.ConsumedPerMinute) : null
					},
					{
						"netPerMinute",
						(value != null && value.OneMinuteAvailable) ? ((object)value.NetPerMinute) : null
					}
				}
			},
			{
				"tenMinute",
				new Dictionary<string, object>
				{
					{
						"available",
						value?.TenMinuteAvailable ?? false
					},
					{
						"ready",
						value?.TenMinuteReady ?? false
					},
					{
						"status",
						(value != null) ? value.TenMinuteStatus : "unavailable"
					},
					{
						"observedGameSeconds",
						(value != null) ? ((object)value.TenMinuteObservedGameSeconds) : null
					},
					{
						"producedPerMinute",
						(value != null && value.TenMinuteAvailable) ? ((object)value.TenMinuteProducedPerMinute) : null
					},
					{
						"consumedPerMinute",
						(value != null && value.TenMinuteAvailable) ? ((object)value.TenMinuteConsumedPerMinute) : null
					},
					{
						"netPerMinute",
						(value != null && value.TenMinuteAvailable) ? ((object)value.TenMinuteNetPerMinute) : null
					}
				}
			}
		};
		if (includeLifetime)
		{
			dictionary["lifetimeProduced"] = ((value2 != null) ? ((object)value2.Produced) : null);
			dictionary["lifetimeConsumed"] = ((value2 != null) ? ((object)value2.Consumed) : null);
		}
		if (includeBufferEvidence)
		{
			dictionary["buffer"] = BufferEvidence(state, itemId);
		}
		return dictionary;
	}

	private static Dictionary<string, object> BufferEvidence(ObservedGameState state, int itemId)
	{
		if (!state.ItemBuffers.TryGetValue(itemId, out var value))
		{
			return new Dictionary<string, object>
			{
				{ "sourcePolicy", "Item-configured logistics slots in local Supply mode only." },
				{ "scopePolicy", "Planet-local stock and planet-local native consumption." },
				{ "importsExportsIncluded", false },
				{ "eligibleSourceAvailable", false },
				{ "accessibleCount", 0L },
				{ "accessibleCapacity", 0L },
				{ "backpressureStatus", "unknown" },
				{
					"scopes",
					new List<object>()
				},
				{
					"excludedSources",
					new List<object>()
				}
			};
		}
		List<object> list = new List<object>();
		foreach (ObservedBufferScopeEvidence scope in value.Scopes)
		{
			int num = Math.Min(scope.Contributors.Count, 12);
			List<object> list2 = new List<object>();
			for (int i = 0; i < num; i++)
			{
				list2.Add(BufferSource(scope.Contributors[i]));
			}
			list.Add(new Dictionary<string, object>
			{
				{ "planetId", scope.PlanetId },
				{ "planetName", scope.PlanetName },
				{ "accessibleCount", scope.AccessibleCount },
				{ "accessibleCapacity", scope.AccessibleCapacity },
				{ "demandEvidenceAvailable", scope.DemandEvidenceAvailable },
				{
					"demandPerMinute",
					scope.DemandEvidenceAvailable ? ((object)scope.DemandPerMinute) : null
				},
				{ "runwayAvailable", scope.RunwayAvailable },
				{
					"runwayMinutes",
					scope.RunwayAvailable ? ((object)scope.RunwayMinutes) : null
				},
				{ "backpressureStatus", scope.BackpressureStatus },
				{
					"contributorCount",
					scope.Contributors.Count
				},
				{ "contributors", list2 },
				{
					"contributorsTruncated",
					scope.Contributors.Count > num
				}
			});
		}
		int num2 = Math.Min(value.ExcludedSources.Count, 12);
		List<object> list3 = new List<object>();
		for (int j = 0; j < num2; j++)
		{
			list3.Add(BufferSource(value.ExcludedSources[j]));
		}
		return new Dictionary<string, object>
		{
			{ "sourcePolicy", "Item-configured logistics slots in local Supply mode only." },
			{ "scopePolicy", "Planet-local stock and planet-local native consumption." },
			{ "importsExportsIncluded", false },
			{
				"eligibleSourceAvailable",
				value.Scopes.Count > 0
			},
			{ "accessibleCount", value.AccessibleCount },
			{ "accessibleCapacity", value.AccessibleCapacity },
			{ "backpressureStatus", value.BackpressureStatus },
			{ "scopes", list },
			{
				"excludedSourceCount",
				value.ExcludedSources.Count
			},
			{ "excludedSources", list3 },
			{
				"excludedSourcesTruncated",
				value.ExcludedSources.Count > num2
			}
		};
	}

	private static Dictionary<string, object> BufferSource(ObservedBufferSourceEvidence source)
	{
		Dictionary<string, object> dictionary = new Dictionary<string, object>
		{
			{ "sourceType", source.SourceType },
			{ "planetId", source.PlanetId },
			{ "planetName", source.PlanetName },
			{ "stationId", source.StationId },
			{ "count", source.Count },
			{ "capacity", source.Capacity },
			{ "localLogic", source.LocalLogic },
			{ "remoteLogic", source.RemoteLogic }
		};
		if (!string.IsNullOrEmpty(source.ExclusionReason))
		{
			dictionary["exclusionReason"] = source.ExclusionReason;
		}
		return dictionary;
	}

	private static Dictionary<string, object> LogisticsEvidence(string phaseId, ObservedGameState state)
	{
		if (!PhaseItems.TryGetValue(phaseId ?? "", out var value))
		{
			value = new int[0];
		}
		HashSet<int> hashSet = new HashSet<int>(value);
		Dictionary<int, Dictionary<string, object>> dictionary = new Dictionary<int, Dictionary<string, object>>();
		foreach (ObservedTrafficFlow trafficFlow in state.TrafficFlows)
		{
			if (hashSet.Contains(trafficFlow.ItemId))
			{
				if (!dictionary.TryGetValue(trafficFlow.ItemId, out var value2))
				{
					value2 = new Dictionary<string, object>
					{
						{ "itemId", trafficFlow.ItemId },
						{ "name", trafficFlow.Name },
						{ "inputPerMinute", 0.0 },
						{ "outputPerMinute", 0.0 },
						{ "internalPerMinute", 0.0 }
					};
					dictionary[trafficFlow.ItemId] = value2;
				}
				value2["inputPerMinute"] = Plugin.ToDouble(value2["inputPerMinute"]) + trafficFlow.InputPerMinute;
				value2["outputPerMinute"] = Plugin.ToDouble(value2["outputPerMinute"]) + trafficFlow.OutputPerMinute;
				value2["internalPerMinute"] = Plugin.ToDouble(value2["internalPerMinute"]) + trafficFlow.InternalPerMinute;
			}
		}
		List<object> list = new List<object>();
		List<int> list2 = new List<int>(dictionary.Keys);
		list2.Sort();
		foreach (int item in list2)
		{
			list.Add(dictionary[item]);
		}
		Dictionary<string, object> dictionary2 = new Dictionary<string, object>
		{
			{ "available", state.TrafficWindowReady },
			{ "windowGameSeconds", state.TrafficWindowSeconds },
			{ "selectedPhaseItems", list }
		};
		if (string.Equals(phaseId, "ils", StringComparison.OrdinalIgnoreCase))
		{
			int num = 0;
			int num2 = 0;
			foreach (ObservedStationState station in state.Stations)
			{
				if (station.IsStellar)
				{
					num++;
					num2 += station.IdleShipCount + station.WorkShipCount;
				}
			}
			dictionary2["stellarStationCount"] = num;
			dictionary2["deployedVesselCount"] = num2;
			dictionary2["stageEvidence"] = IlsStageEvidence(state);
		}
		return dictionary2;
	}

	private static Dictionary<string, object> IlsStageEvidence(ObservedGameState state)
	{
		return new Dictionary<string, object>
		{
			{ "playerPlanetId", state.PlayerPlanetId },
			{ "starterPlanetId", state.StarterPlanetId },
			{
				"playerInventory",
				CountEvidence(state.PlayerItemCounts, IlsPlayerItems)
			},
			{
				"planetCargo",
				IlsPlanetCargoEvidence(state)
			},
			{
				"protectedReserve",
				CountEvidence(BestIlsReserve(state), IlsReserveItems)
			}
		};
	}

	private static List<object> IlsPlanetCargoEvidence(ObservedGameState state)
	{
		HashSet<int> hashSet = new HashSet<int>();
		foreach (int key in state.PlanetItemCounts.Keys)
		{
			hashSet.Add(key);
		}
		foreach (ObservedFactoryItemFlow factoryItemFlow in state.FactoryItemFlows)
		{
			if (Array.IndexOf(IlsCargoItems, factoryItemFlow.ItemId) >= 0)
			{
				hashSet.Add(factoryItemFlow.PlanetId);
			}
		}
		List<int> list = new List<int>(hashSet);
		list.Sort();
		List<object> list2 = new List<object>();
		foreach (int item in list)
		{
			if (!state.PlanetItemCounts.TryGetValue(item, out var value))
			{
				value = new Dictionary<int, long>();
			}
			Dictionary<int, double> dictionary = new Dictionary<int, double>();
			foreach (ObservedFactoryItemFlow factoryItemFlow2 in state.FactoryItemFlows)
			{
				if (factoryItemFlow2.PlanetId == item && Array.IndexOf(IlsCargoItems, factoryItemFlow2.ItemId) >= 0)
				{
					dictionary.TryGetValue(factoryItemFlow2.ItemId, out var value2);
					dictionary[factoryItemFlow2.ItemId] = value2 + factoryItemFlow2.ProducedPerMinute;
				}
			}
			if (HasCount(value, IlsCargoItems) || dictionary.Count != 0)
			{
				state.PlanetNames.TryGetValue(item, out var value3);
				list2.Add(new Dictionary<string, object>
				{
					{ "planetId", item },
					{
						"planetName",
						value3 ?? ""
					},
					{
						"items",
						CountAndProductionEvidence(value, dictionary, IlsCargoItems)
					}
				});
			}
		}
		return list2;
	}

	private static Dictionary<int, long> BestIlsReserve(ObservedGameState state)
	{
		if (state.PlayerPlanetId > 0 && state.PlanetItemCounts.TryGetValue(state.PlayerPlanetId, out var value))
		{
			return value;
		}
		Dictionary<int, long> result = new Dictionary<int, long>();
		long num = -1L;
		foreach (Dictionary<int, long> value3 in state.PlanetItemCounts.Values)
		{
			long num2 = 0L;
			int[] ilsReserveItems = IlsReserveItems;
			foreach (int key in ilsReserveItems)
			{
				if (value3.TryGetValue(key, out var value2))
				{
					num2 += value2;
				}
			}
			if (num2 > num)
			{
				result = value3;
				num = num2;
			}
		}
		return result;
	}

	private static List<object> CountEvidence(Dictionary<int, long> counts, int[] itemIds)
	{
		return CountAndProductionEvidence(counts, new Dictionary<int, double>(), itemIds);
	}

	private static List<object> CountAndProductionEvidence(Dictionary<int, long> counts, Dictionary<int, double> production, int[] itemIds)
	{
		List<object> list = new List<object>();
		foreach (int num in itemIds)
		{
			counts.TryGetValue(num, out var value);
			production.TryGetValue(num, out var value2);
			Dictionary<string, object> dictionary = new Dictionary<string, object>
			{
				{ "itemId", num },
				{
					"name",
					Plugin.ItemName(num)
				},
				{ "count", value }
			};
			if (production.Count > 0)
			{
				dictionary["producedPerMinute"] = value2;
			}
			list.Add(dictionary);
		}
		return list;
	}

	private static bool HasCount(Dictionary<int, long> counts, int[] itemIds)
	{
		foreach (int key in itemIds)
		{
			if (counts.TryGetValue(key, out var value) && value > 0)
			{
				return true;
			}
		}
		return false;
	}

	private static Dictionary<string, object> RecipeEvidence(string phaseId, ObservedGameState state)
	{
		if (!PhaseRecipeIds.TryGetValue(phaseId ?? "", out var value))
		{
			return new Dictionary<string, object> { { "available", state.RecipeTelemetryAvailable } };
		}
		int num = 0;
		foreach (ObservedRecipeConfiguration recipeConfiguration in state.RecipeConfigurations)
		{
			if (recipeConfiguration.RecipeId == value)
			{
				num += recipeConfiguration.ConfiguredMachineCount;
			}
		}
		return new Dictionary<string, object>
		{
			{ "available", state.RecipeTelemetryAvailable },
			{ "recipeId", value },
			{ "configuredMachineCount", num }
		};
	}

	private static Dictionary<string, object> PowerEvidence(ObservedGameState state)
	{
		ObservedPowerState observedPowerState = null;
		foreach (ObservedPowerState powerPlanet in state.PowerPlanets)
		{
			if (observedPowerState == null || powerPlanet.MinimumSatisfaction < observedPowerState.MinimumSatisfaction)
			{
				observedPowerState = powerPlanet;
			}
		}
		return new Dictionary<string, object>
		{
			{
				"available",
				observedPowerState != null
			},
			{ "windowGameSeconds", state.PowerWindowSeconds },
			{
				"worstPlanet",
				(observedPowerState == null) ? null : new Dictionary<string, object>
				{
					{ "planetId", observedPowerState.PlanetId },
					{ "planetName", observedPowerState.PlanetName },
					{ "observations", observedPowerState.Observations },
					{ "minimumSatisfaction", observedPowerState.MinimumSatisfaction },
					{ "undersuppliedFraction", observedPowerState.UndersuppliedFraction },
					{ "maximumDemandToCapacity", observedPowerState.MaximumDemandToCapacity }
				}
			}
		};
	}

	private static Dictionary<string, object> DysonEvidence(string phaseId, ObservedGameState state)
	{
		ObservedDysonState dyson = state.Dyson;
		Dictionary<string, object> dictionary = new Dictionary<string, object>
		{
			{ "available", dyson.Available },
			{ "aggregateSource", dyson.AggregateSource },
			{ "aggregateSystemCount", dyson.AggregateSystemCount },
			{ "constructionAggregateAvailable", dyson.ConstructionAggregateAvailable },
			{ "aggregateNodesRead", dyson.AggregateNodesRead },
			{ "aggregateNodesMissing", dyson.AggregateNodesMissing },
			{ "generationWatts", dyson.GenerationWatts },
			{ "permanentGenerationWatts", dyson.PermanentGenerationWatts },
			{ "swarmGenerationWatts", dyson.SwarmGenerationWatts },
			{ "requestedWatts", dyson.RequestedWatts }
		};
		if (phaseId == "dyson")
		{
			dictionary["swarm"] = new Dictionary<string, object>
			{
				{ "sailCount", dyson.SwarmSailCount },
				{ "netSailPopulationPerMinute", dyson.NetSwarmSailsPerMinute },
				{ "ejectorCount", dyson.EjectorCount },
				{ "ejectorsOnTarget", dyson.EjectorsOnTarget },
				{ "ejectorsSupplied", dyson.EjectorsSupplied },
				{ "ejectorsFiringNow", dyson.EjectorsFiringNow }
			};
		}
		if (phaseId == "photon" || phaseId == "white")
		{
			dictionary["receivers"] = ReceiverEvidence(dyson);
		}
		return dictionary;
	}

	private static Dictionary<string, object> ReceiverEvidence(ObservedDysonState d)
	{
		List<object> list = new List<object>();
		foreach (ObservedReceiverState receiver in d.Receivers)
		{
			if (list.Count >= 8)
			{
				break;
			}
			list.Add(new Dictionary<string, object>
			{
				{ "planetId", receiver.PlanetId },
				{ "planetName", receiver.PlanetName },
				{ "entityId", receiver.EntityId },
				{ "sampleCount", receiver.SampleCount },
				{ "windowSeconds", receiver.WindowSeconds },
				{ "windowReady", receiver.WindowReady },
				{ "unhealthySampleCount", receiver.UnhealthySampleCount },
				{ "maximumUnhealthySamples", receiver.MaximumUnhealthySamples },
				{ "configuredForPhotonGeneration", receiver.ConfiguredForPhotonGeneration },
				{ "lensedNow", receiver.LensedNow },
				{ "continuousReceivingNow", receiver.ContinuousReceivingNow },
				{ "minimumWarmup", receiver.MinimumWarmup },
				{ "minimumStrength", receiver.MinimumStrength },
				{ "sustainedHealthy", receiver.SustainedHealthy },
				{ "requestedDysonPowerWatts", receiver.RequestedDysonPowerWatts },
				{ "suppliedPowerWatts", receiver.SuppliedPowerWatts },
				{ "criticalPhotonOutputPerMinute", receiver.CriticalPhotonOutputPerMinute }
			});
		}
		return new Dictionary<string, object>
		{
			{ "deployed", d.ReceiverCount },
			{ "configuredForPhotonGeneration", d.ConfiguredPhotonReceiverCount },
			{ "lensed", d.LensedPhotonReceiverCount },
			{ "fullStrength", d.FullStrengthPhotonReceiverCount },
			{ "continuous", d.ContinuousPhotonReceiverCount },
			{ "sustainedHealthy", d.SustainedPhotonReceiverCount },
			{ "continuityWindowSeconds", d.ReceiverContinuityWindowSeconds },
			{ "maximumUnhealthySamples", d.ReceiverMaximumUnhealthySamples },
			{ "requestedDysonPowerWatts", d.ReceiverArrayRequestedDysonPowerWatts },
			{ "suppliedPowerWatts", d.ReceiverArraySuppliedPowerWatts },
			{ "criticalPhotonOutputPerMinute", d.ReceiverArrayCriticalPhotonOutputPerMinute },
			{ "details", list },
			{
				"detailsTruncated",
				d.Receivers.Count > 8
			},
			{
				"omittedDetailCount",
				Math.Max(0, d.Receivers.Count - 8)
			}
		};
	}

	private static bool IsDysonPhase(string phaseId)
	{
		switch (phaseId)
		{
		default:
			return phaseId == "white";
		case "green":
		case "dyson":
		case "photon":
			return true;
		}
	}

	private static void Validate(Dictionary<string, object> snapshot)
	{
		string[] array = new string[9] { "schemaVersion", "exporterVersion", "provenance", "game", "guideSelection", "guide", "summary", "evidence", "omissions" };
		foreach (string text in array)
		{
			if (!snapshot.ContainsKey(text))
			{
				throw new InvalidOperationException("Compact snapshot is missing " + text + ".");
			}
		}
		array = new string[11]
		{
			"factories", "player", "research", "productionTelemetry", "trafficTelemetry", "powerTelemetry", "recipeTelemetry", "observedState", "guideAnalysis", "guidePanel",
			"diagnostics"
		};
		foreach (string text2 in array)
		{
			if (snapshot.ContainsKey(text2))
			{
				throw new InvalidOperationException("Compact snapshot contains legacy section " + text2 + ".");
			}
		}
	}

	private static Dictionary<string, object> Dictionary(Dictionary<string, object> source, string key)
	{
		return (Value(source, key) as Dictionary<string, object>) ?? new Dictionary<string, object>();
	}

	private static object Value(Dictionary<string, object> source, string key)
	{
		if (source == null || !source.TryGetValue(key, out var value))
		{
			return null;
		}
		return value;
	}

	private static IEnumerable Enumerate(object value)
	{
		return (value as IEnumerable) ?? new object[0];
	}

	private static string Text(object value)
	{
		if (value != null)
		{
			return value.ToString();
		}
		return "";
	}

	private static bool Bool(object value)
	{
		if (value is bool)
		{
			return (bool)value;
		}
		bool result = default(bool);
		return value != null && bool.TryParse(value.ToString(), out result) && result;
	}
}
internal sealed class EmbeddedBasicFont : IDisposable
{
	private const string ResourceName = "DspGuideCheck.Fonts.Basic-Regular.ttf";

	private IntPtr fontMemory;

	private IntPtr fontResource;

	private bool ownsFont;

	public Font Font { get; private set; }

	public string Source { get; private set; }

	private EmbeddedBasicFont()
	{
	}

	public static EmbeddedBasicFont Load(Font fallback, int size)
	{
		Font val = FindLoadedFont();
		if ((Object)(object)val != (Object)null)
		{
			return new EmbeddedBasicFont
			{
				Font = val,
				Source = "loaded-basic-font"
			};
		}
		EmbeddedBasicFont embeddedBasicFont = new EmbeddedBasicFont
		{
			Font = fallback,
			Source = "native-fallback"
		};
		try
		{
			byte[] array = ReadResource();
			embeddedBasicFont.fontMemory = Marshal.AllocCoTaskMem(array.Length);
			Marshal.Copy(array, 0, embeddedBasicFont.fontMemory, array.Length);
			uint fontCount = 0u;
			embeddedBasicFont.fontResource = AddFontMemResourceEx(embeddedBasicFont.fontMemory, (uint)array.Length, IntPtr.Zero, ref fontCount);
			if (embeddedBasicFont.fontResource == IntPtr.Zero || fontCount == 0)
			{
				embeddedBasicFont.ReleaseResource();
				return embeddedBasicFont;
			}
			Font val2 = Font.CreateDynamicFontFromOSFont(new string[2] { "Basic", "Basic Regular" }, size);
			if ((Object)(object)val2 == (Object)null)
			{
				embeddedBasicFont.ReleaseResource();
				return embeddedBasicFont;
			}
			embeddedBasicFont.Font = val2;
			embeddedBasicFont.Source = "embedded-google-fonts-basic";
			embeddedBasicFont.ownsFont = true;
		}
		catch
		{
			embeddedBasicFont.ReleaseResource();
		}
		return embeddedBasicFont;
	}

	public void Dispose()
	{
		if (ownsFont && (Object)(object)Font != (Object)null)
		{
			Object.Destroy((Object)(object)Font);
		}
		Font = null;
		ownsFont = false;
		ReleaseResource();
	}

	private static Font FindLoadedFont()
	{
		Font[] array = Resources.FindObjectsOfTypeAll<Font>();
		if (array == null)
		{
			return null;
		}
		Font[] array2 = array;
		foreach (Font val in array2)
		{
			if ((Object)(object)val != (Object)null && ((Object)val).name.IndexOf("basic", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return val;
			}
		}
		return null;
	}

	private static byte[] ReadResource()
	{
		using Stream stream = typeof(EmbeddedBasicFont).Assembly.GetManifestResourceStream("DspGuideCheck.Fonts.Basic-Regular.ttf");
		if (stream == null)
		{
			throw new InvalidOperationException("Embedded Basic font resource was not found.");
		}
		using MemoryStream memoryStream = new MemoryStream();
		stream.CopyTo(memoryStream);
		return memoryStream.ToArray();
	}

	private void ReleaseResource()
	{
		if (fontResource != IntPtr.Zero)
		{
			try
			{
				RemoveFontMemResourceEx(fontResource);
			}
			catch
			{
			}
			fontResource = IntPtr.Zero;
		}
		if (fontMemory != IntPtr.Zero)
		{
			Marshal.FreeCoTaskMem(fontMemory);
			fontMemory = IntPtr.Zero;
		}
	}

	[DllImport("gdi32.dll")]
	private static extern IntPtr AddFontMemResourceEx(IntPtr fontData, uint dataSize, IntPtr reserved, ref uint fontCount);

	[DllImport("gdi32.dll")]
	[return: MarshalAs(UnmanagedType.Bool)]
	private static extern bool RemoveFontMemResourceEx(IntPtr fontResourceHandle);
}
internal sealed class EmbeddedMatrixIcons : IDisposable
{
	private const string ResourcePrefix = "DspGuideCheck.MatrixIcons.";

	private static readonly Dictionary<string, string> ResourceNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		{ "blue", "t-matrix.png" },
		{ "red", "e-matrix.png" },
		{ "yellow", "c-matrix.png" },
		{ "purple", "i-matrix.png" },
		{ "green", "g-matrix.png" },
		{ "white", "u-matrix.png" },
		{ "ils", "1605.png" },
		{ "dyson", "solar-collector.png" },
		{ "photon", "photon-capacitor-full.png" },
		{ "risk-draining", "signal-402.png" },
		{ "risk-starved", "signal-404.png" }
	};

	private readonly Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);

	private readonly List<Texture2D> textures = new List<Texture2D>();

	private EmbeddedMatrixIcons()
	{
	}

	public static EmbeddedMatrixIcons Load()
	{
		EmbeddedMatrixIcons embeddedMatrixIcons = new EmbeddedMatrixIcons();
		foreach (KeyValuePair<string, string> resourceName in ResourceNames)
		{
			embeddedMatrixIcons.TryLoad(resourceName.Key, "DspGuideCheck.MatrixIcons." + resourceName.Value);
		}
		return embeddedMatrixIcons;
	}

	public Sprite Get(string cubeId)
	{
		if (string.IsNullOrEmpty(cubeId) || !sprites.TryGetValue(cubeId, out var value))
		{
			return null;
		}
		return value;
	}

	public void Dispose()
	{
		foreach (Sprite value in sprites.Values)
		{
			if ((Object)(object)value != (Object)null)
			{
				Object.Destroy((Object)(object)value);
			}
		}
		foreach (Texture2D texture in textures)
		{
			if ((Object)(object)texture != (Object)null)
			{
				Object.Destroy((Object)(object)texture);
			}
		}
		sprites.Clear();
		textures.Clear();
	}

	private void TryLoad(string cubeId, string resourceName)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = null;
		Sprite val2 = null;
		try
		{
			byte[] array = ReadResource(resourceName);
			val = new Texture2D(2, 2, (TextureFormat)4, false);
			((Object)val).name = "DSPGuideCheck-" + cubeId + "-panel-icon";
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			if (!ImageConversion.LoadImage(val, array, true) || ((Texture)val).width <= 0 || ((Texture)val).height <= 0)
			{
				throw new InvalidOperationException("Embedded panel icon could not be decoded.");
			}
			val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			if ((Object)(object)val2 == (Object)null)
			{
				throw new InvalidOperationException("Embedded panel icon sprite could not be created.");
			}
			((Object)val2).name = ((Object)val).name;
			textures.Add(val);
			sprites[cubeId] = val2;
		}
		catch
		{
			if ((Object)(object)val2 != (Object)null)
			{
				Object.Destroy((Object)(object)val2);
			}
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)val);
			}
		}
	}

	private static byte[] ReadResource(string resourceName)
	{
		using Stream stream = typeof(EmbeddedMatrixIcons).Assembly.GetManifestResourceStream(resourceName);
		if (stream == null)
		{
			throw new InvalidOperationException("Embedded panel icon resource was not found.");
		}
		using MemoryStream memoryStream = new MemoryStream();
		stream.CopyTo(memoryStream);
		return memoryStream.ToArray();
	}
}
internal static class GuideAnalyzer
{
	private sealed class Phase
	{
		public string Id;

		public string Title;

		public int GateTechId;

		public int NextTechId;

		public string NextResearch;
	}

	private sealed class RiskItemSpec
	{
		public int ItemId;

		public string Name;

		public double ExactTargetPerMinute;

		public double DemandCeilingPerMinute;
	}

	private sealed class OrderedRisk
	{
		public ProductionRiskResult Result;

		public int PhaseOrder;
	}

	private static readonly Phase[] Phases = new Phase[9]
	{
		new Phase
		{
			Id = "blue",
			Title = "Sustain the Blue Cube science loop",
			GateTechId = 1002,
			NextTechId = 1111,
			NextResearch = "Energy Matrix"
		},
		new Phase
		{
			Id = "red",
			Title = "Sustain Red Cubes without refinery deadlock",
			GateTechId = 1111,
			NextTechId = 2902,
			NextResearch = "Drive Engine Lv2"
		},
		new Phase
		{
			Id = "ils",
			Title = "Complete the first interplanetary logistics expedition",
			GateTechId = 2902,
			NextTechId = 1124,
			NextResearch = "Structure Matrix"
		},
		new Phase
		{
			Id = "yellow",
			Title = "Run three continuous Yellow Cube labs",
			GateTechId = 1124,
			NextTechId = 1312,
			NextResearch = "Information Matrix"
		},
		new Phase
		{
			Id = "purple",
			Title = "Run three continuous Purple Cube labs",
			GateTechId = 1312,
			NextTechId = 1705,
			NextResearch = "Gravity Matrix"
		},
		new Phase
		{
			Id = "green",
			Title = "Run two continuous Green Cube labs",
			GateTechId = 1705,
			NextTechId = 1505,
			NextResearch = "Planetary Ionosphere Utilization"
		},
		new Phase
		{
			Id = "dyson",
			Title = "Build the Photon swarm",
			GateTechId = 1505,
			NextTechId = 1506,
			NextResearch = "Dirac Inversion Mechanism"
		},
		new Phase
		{
			Id = "photon",
			Title = "Run the critical-photon receiver array",
			GateTechId = 1506,
			NextTechId = 1507,
			NextResearch = "Universe Matrix"
		},
		new Phase
		{
			Id = "white",
			Title = "Complete the main progression route",
			GateTechId = 1507,
			NextTechId = 1508,
			NextResearch = "Mission Completed"
		}
	};

	private static readonly Dictionary<string, RiskItemSpec[]> RiskItems = new Dictionary<string, RiskItemSpec[]>(StringComparer.OrdinalIgnoreCase)
	{
		{
			"blue",
			new RiskItemSpec[1] { RiskItem(6001, "Blue Cubes", 20.0) }
		},
		{
			"red",
			new RiskItemSpec[1] { RiskItem(6002, "Red Cubes", 20.0) }
		},
		{
			"ils",
			new RiskItemSpec[2]
			{
				RiskItem(1106, "Titanium Ingots", 0.0),
				RiskItem(1105, "High-Purity Silicon", 0.0)
			}
		},
		{
			"yellow",
			new RiskItemSpec[3]
			{
				RiskItem(1112, "Diamonds", 0.0),
				RiskItem(1118, "Titanium Crystals", 0.0),
				RiskItem(6003, "Yellow Cubes", 0.0)
			}
		},
		{
			"purple",
			new RiskItemSpec[3]
			{
				RiskItem(1303, "Processors", 0.0),
				RiskItem(1402, "Particle Broadband", 0.0),
				RiskItem(6004, "Purple Cubes", 0.0)
			}
		},
		{
			"green",
			new RiskItemSpec[3]
			{
				RiskItem(1305, "Quantum Chips", 0.0),
				RiskItem(1209, "Graviton Lenses", 0.0),
				RiskItem(6005, "Green Cubes", 0.0)
			}
		},
		{
			"dyson",
			new RiskItemSpec[1] { RiskItem(1501, "Solar Sails", 0.0) }
		},
		{
			"photon",
			new RiskItemSpec[2]
			{
				RiskItem(1208, "Critical Photons", 0.0),
				RiskItem(1122, "Antimatter", 0.0)
			}
		},
		{
			"white",
			new RiskItemSpec[7]
			{
				RiskItem(6001, "Blue Cubes", 0.0),
				RiskItem(6002, "Red Cubes", 0.0),
				RiskItem(6003, "Yellow Cubes", 0.0),
				RiskItem(6004, "Purple Cubes", 0.0),
				RiskItem(6005, "Green Cubes", 0.0),
				RiskItem(1122, "Antimatter", 0.0),
				RiskItem(6006, "White Cubes", 40.0)
			}
		}
	};

	public static Dictionary<string, object> AnalyzeSelected(ObservedGameState state, string selectedPhaseId)
	{
		selectedPhaseId = ManualPhaseNavigator.NormalizePhase(selectedPhaseId);
		GuideProgressionEvaluation guideProgressionEvaluation = GuideGateEngine.EvaluatePhase(selectedPhaseId, state);
		Phase phase = FindPhase(selectedPhaseId) ?? FindPhase("blue");
		List<object> list = new List<object>();
		ProductionRiskResult selected;
		Dictionary<string, object> value = AnalyzeProductionRisk(state, phase.Id, out selected);
		if (selected != null && selected.Actionable)
		{
			list.Add(RiskFinding(selected));
		}
		if (phase.Id == "red")
		{
			AddRefineryCongestionFinding(list, state);
		}
		if (phase.Id == "photon")
		{
			AddPhotonPowerFinding(list, state);
		}
		KeepStrongestFinding(list);
		Dictionary<string, object> value2 = new Dictionary<string, object>
		{
			{ "id", phase.Id },
			{ "title", phase.Title },
			{ "gateTechId", phase.GateTechId },
			{ "nextTechId", phase.NextTechId },
			{ "nextResearch", phase.NextResearch },
			{ "basis", "Player-selected phase; runtime evidence evaluates this phase but cannot change it." }
		};
		return new Dictionary<string, object>
		{
			{ "analysisVersion", "3.3" },
			{ "phaseSelectionAuthority", "player" },
			{ "phase", value2 },
			{
				"progression",
				guideProgressionEvaluation.Export()
			},
			{
				"normalizedState",
				state.Export()
			},
			{ "productionRisk", value },
			{ "findings", list },
			{
				"limitations",
				new List<object> { "A technology unlock proves availability, not that the corresponding factory objective is complete.", "Production claims require a valid native Statistics Panel observation window.", "Only positively observed runtime evidence is reported as ready; player checks remain explicit." }
			}
		};
	}

	private static Phase FindPhase(string id)
	{
		Phase[] phases = Phases;
		foreach (Phase phase in phases)
		{
			if (string.Equals(phase.Id, id, StringComparison.OrdinalIgnoreCase))
			{
				return phase;
			}
		}
		return null;
	}

	private static RiskItemSpec RiskItem(int itemId, string name, double exactTargetPerMinute)
	{
		return new RiskItemSpec
		{
			ItemId = itemId,
			Name = name,
			ExactTargetPerMinute = exactTargetPerMinute,
			DemandCeilingPerMinute = (IsCubeItem(itemId) ? 40.0 : 0.0)
		};
	}

	private static bool IsCubeItem(int itemId)
	{
		if (itemId >= 6001)
		{
			return itemId <= 6006;
		}
		return false;
	}

	private static Dictionary<string, object> AnalyzeProductionRisk(ObservedGameState state, string phaseId, out ProductionRiskResult selected)
	{
		selected = null;
		int num = 0;
		List<OrderedRisk> list = new List<OrderedRisk>();
		List<object> list2 = new List<object>();
		if (!RiskItems.TryGetValue(phaseId ?? "", out var value))
		{
			value = new RiskItemSpec[0];
		}
		for (int i = 0; i < value.Length; i++)
		{
			RiskItemSpec riskItemSpec = value[i];
			ProductionRiskResult productionRiskResult = null;
			bool num2 = ExactTargetSatisfied(state, riskItemSpec);
			bool flag = DemandReferenceSatisfied(state, riskItemSpec);
			ObservedItemBufferEvidence value2;
			bool flag2 = state.ItemBuffers.TryGetValue(riskItemSpec.ItemId, out value2) && value2.Scopes.Count > 0;
			if (num2 || flag)
			{
				productionRiskResult = ProductionRiskAnalyzer.Evaluate(ClusterRiskInput(state, riskItemSpec));
				num++;
			}
			else if (flag2)
			{
				foreach (ObservedBufferScopeEvidence scope in value2.Scopes)
				{
					ProductionRiskResult candidate = ProductionRiskAnalyzer.Evaluate(PlanetRiskInput(state, riskItemSpec, scope));
					num++;
					productionRiskResult = WorseRisk(productionRiskResult, candidate);
				}
				if (riskItemSpec.ExactTargetPerMinute > 0.0)
				{
					ProductionRiskInput productionRiskInput = ClusterRiskInput(state, riskItemSpec);
					productionRiskInput.BackpressureStatus = value2.BackpressureStatus;
					ProductionRiskResult candidate2 = ProductionRiskAnalyzer.Evaluate(productionRiskInput);
					num++;
					productionRiskResult = WorseRisk(productionRiskResult, candidate2);
				}
			}
			else
			{
				ProductionRiskResult candidate3 = ProductionRiskAnalyzer.Evaluate(ClusterRiskInput(state, riskItemSpec));
				num++;
				productionRiskResult = WorseRisk(productionRiskResult, candidate3);
			}
			selected = WorseRisk(selected, productionRiskResult);
			if (productionRiskResult != null && productionRiskResult.TargetSatisfied)
			{
				list2.Add(productionRiskResult.Export());
			}
			if (productionRiskResult != null && productionRiskResult.Actionable)
			{
				list.Add(new OrderedRisk
				{
					Result = productionRiskResult,
					PhaseOrder = i
				});
			}
		}
		list.Sort(CompareOrderedRisks);
		if (list.Count > 0)
		{
			selected = list[0].Result;
		}
		List<object> list3 = new List<object>();
		foreach (OrderedRisk item in list)
		{
			list3.Add(item.Result.Export());
		}
		return new Dictionary<string, object>
		{
			{ "contractVersion", "1.2" },
			{ "basis", "Deterministic selected-phase evaluation from scope-matched native rates and conservative accessible-buffer evidence." },
			{ "evaluatedItemScopes", num },
			{ "actionable", list3 },
			{ "satisfiedExactTargets", list2 },
			{
				"selected",
				(selected != null) ? selected.Export() : null
			}
		};
	}

	private static int CompareOrderedRisks(OrderedRisk left, OrderedRisk right)
	{
		int num = RiskRank(right.Result.State).CompareTo(RiskRank(left.Result.State));
		if (num != 0)
		{
			return num;
		}
		if (left.Result.DepletionMinutesAvailable != right.Result.DepletionMinutesAvailable)
		{
			if (!left.Result.DepletionMinutesAvailable)
			{
				return 1;
			}
			return -1;
		}
		if (left.Result.DepletionMinutesAvailable)
		{
			int num2 = left.Result.DepletionMinutes.CompareTo(right.Result.DepletionMinutes);
			if (num2 != 0)
			{
				return num2;
			}
		}
		return left.PhaseOrder.CompareTo(right.PhaseOrder);
	}

	private static bool ExactTargetSatisfied(ObservedGameState state, RiskItemSpec spec)
	{
		if (spec.ExactTargetPerMinute <= 0.0)
		{
			return false;
		}
		if (state.ItemFlows.TryGetValue(spec.ItemId, out var value) && value != null && value.OneMinuteAvailable)
		{
			return value.ProducedPerMinute >= spec.ExactTargetPerMinute;
		}
		return false;
	}

	private static bool DemandReferenceSatisfied(ObservedGameState state, RiskItemSpec spec)
	{
		if (spec.DemandCeilingPerMinute <= 0.0)
		{
			return false;
		}
		if (state.ItemFlows.TryGetValue(spec.ItemId, out var value) && value != null && value.OneMinuteAvailable)
		{
			return ProductionRiskAnalyzer.DemandSatisfied(value.ProducedPerMinute, value.ConsumedPerMinute, spec.DemandCeilingPerMinute);
		}
		return false;
	}

	private static ProductionRiskInput ClusterRiskInput(ObservedGameState state, RiskItemSpec spec)
	{
		state.ItemFlows.TryGetValue(spec.ItemId, out var value);
		return new ProductionRiskInput
		{
			ItemId = spec.ItemId,
			Name = spec.Name,
			Scope = "entire-star-cluster",
			OneMinuteAvailable = (value?.OneMinuteAvailable ?? false),
			ProducedPerMinute = (value?.ProducedPerMinute ?? 0.0),
			ConsumedPerMinute = (value?.ConsumedPerMinute ?? 0.0),
			TenMinuteAvailable = (value?.TenMinuteAvailable ?? false),
			TenMinuteReady = (value?.TenMinuteReady ?? false),
			TenMinuteProducedPerMinute = (value?.TenMinuteProducedPerMinute ?? 0.0),
			TenMinuteConsumedPerMinute = (value?.TenMinuteConsumedPerMinute ?? 0.0),
			BackpressureStatus = "unknown",
			ExactTargetPerMinute = spec.ExactTargetPerMinute,
			DemandCeilingPerMinute = spec.DemandCeilingPerMinute
		};
	}

	private static ProductionRiskInput PlanetRiskInput(ObservedGameState state, RiskItemSpec spec, ObservedBufferScopeEvidence scope)
	{
		bool flag = false;
		bool flag2 = false;
		bool flag3 = false;
		bool flag4 = true;
		double num = 0.0;
		double num2 = 0.0;
		double num3 = 0.0;
		double num4 = 0.0;
		foreach (ObservedFactoryItemFlow factoryItemFlow in state.FactoryItemFlows)
		{
			if (factoryItemFlow.ItemId == spec.ItemId && factoryItemFlow.PlanetId == scope.PlanetId)
			{
				flag = true;
				flag2 |= factoryItemFlow.OneMinuteAvailable;
				flag3 |= factoryItemFlow.TenMinuteAvailable;
				flag4 &= factoryItemFlow.TenMinuteReady;
				num += factoryItemFlow.ProducedPerMinute;
				num2 += factoryItemFlow.ConsumedPerMinute;
				num3 += factoryItemFlow.TenMinuteProducedPerMinute;
				num4 += factoryItemFlow.TenMinuteConsumedPerMinute;
			}
		}
		return new ProductionRiskInput
		{
			ItemId = spec.ItemId,
			Name = spec.Name,
			Scope = "planet-local",
			PlanetId = scope.PlanetId,
			PlanetName = scope.PlanetName,
			OneMinuteAvailable = (flag && flag2),
			ProducedPerMinute = num,
			ConsumedPerMinute = num2,
			TenMinuteAvailable = (flag && flag3),
			TenMinuteReady = (flag && flag4),
			TenMinuteProducedPerMinute = num3,
			TenMinuteConsumedPerMinute = num4,
			RunwayAvailable = scope.RunwayAvailable,
			RunwayMinutes = scope.RunwayMinutes,
			AccessibleCount = scope.AccessibleCount,
			BackpressureStatus = scope.BackpressureStatus,
			ExactTargetPerMinute = 0.0,
			DemandCeilingPerMinute = spec.DemandCeilingPerMinute
		};
	}

	private static ProductionRiskResult WorseRisk(ProductionRiskResult current, ProductionRiskResult candidate)
	{
		if (current == null)
		{
			return candidate;
		}
		int num = RiskRank(current.State);
		int num2 = RiskRank(candidate.State);
		if (num2 > num)
		{
			return candidate;
		}
		if (num2 < num)
		{
			return current;
		}
		if (candidate.DepletionMinutesAvailable != current.DepletionMinutesAvailable)
		{
			if (!candidate.DepletionMinutesAvailable)
			{
				return current;
			}
			return candidate;
		}
		if (candidate.DepletionMinutesAvailable && candidate.DepletionMinutes != current.DepletionMinutes)
		{
			if (!(candidate.DepletionMinutes < current.DepletionMinutes))
			{
				return current;
			}
			return candidate;
		}
		if (!(candidate.Score > current.Score))
		{
			return current;
		}
		return candidate;
	}

	private static int RiskRank(string state)
	{
		return state switch
		{
			"starved" => 6, 
			"draining" => 5, 
			"warming" => 4, 
			"unknown" => 3, 
			"backpressured" => 2, 
			_ => 1, 
		};
	}

	private static Dictionary<string, object> RiskFinding(ProductionRiskResult result)
	{
		string value = ((result.State == "starved") ? (result.Name + " production is starved.") : ((!result.DemandDeficit) ? (result.Name + " production is below the phase target.") : (result.Name + " are draining faster than they are replenished.")));
		string text = "Found " + Rate(result.ProducedPerMinute) + "/min produced";
		if (result.ConsumedPerMinute > 0.0)
		{
			text = text + " and " + Rate(result.ConsumedPerMinute) + "/min consumed";
		}
		if (result.ExactTargetPerMinute > 0.0)
		{
			text = text + " against a " + Rate(result.ExactTargetPerMinute) + "/min target";
		}
		if (result.RunwayAvailable)
		{
			text = text + "; accessible runway is " + Rate(result.RunwayMinutes) + " min";
		}
		text = text + "; the ten-minute production baseline is " + Rate(result.BaselinePerMinute) + "/min. " + ((result.State == "starved") ? "Restore the upstream supply or stopped production line." : "Increase production before the deficit consumes its buffer.");
		return new Dictionary<string, object>
		{
			{
				"id",
				"production-risk-" + result.ItemId
			},
			{
				"status",
				(result.State == "starved") ? "blocked" : "watch"
			},
			{ "claim", value },
			{ "evidence", text },
			{ "confidence", "high" },
			{
				"priority",
				(result.State == "starved") ? 20 : 30
			},
			{
				"risk",
				result.Export()
			}
		};
	}

	private static string Rate(double value)
	{
		return Math.Round(value, 1).ToString("0.0", CultureInfo.InvariantCulture);
	}

	private static void KeepStrongestFinding(List<object> findings)
	{
		if (findings.Count <= 1)
		{
			return;
		}
		object obj = findings[0];
		int num = FindingPriority(obj);
		for (int i = 1; i < findings.Count; i++)
		{
			int num2 = FindingPriority(findings[i]);
			if (num2 < num)
			{
				obj = findings[i];
				num = num2;
			}
		}
		findings.Clear();
		findings.Add(obj);
	}

	private static int FindingPriority(object value)
	{
		if (!(value is Dictionary<string, object> dictionary) || !dictionary.TryGetValue("priority", out var value2))
		{
			return 100;
		}
		return Convert.ToInt32(value2, CultureInfo.InvariantCulture);
	}

	private static void AddPhotonPowerFinding(List<object> findings, ObservedGameState state)
	{
		if (state.Dyson.Available && state.Dyson.ConfiguredPhotonReceiverCount > 0)
		{
			double receiverArrayRequestedDysonPowerWatts = state.Dyson.ReceiverArrayRequestedDysonPowerWatts;
			double receiverArraySuppliedPowerWatts = state.Dyson.ReceiverArraySuppliedPowerWatts;
			double generationWatts = state.Dyson.GenerationWatts;
			string text = ((receiverArrayRequestedDysonPowerWatts > generationWatts || generationWatts <= 0.0) ? "watch" : "ready");
			findings.Add(Finding("photon-receiver-power", text, "Photon receivers request " + FormatPower(receiverArrayRequestedDysonPowerWatts) + " from " + FormatPower(generationWatts) + " of Dyson generation.", "The receiver array is currently supplied with " + FormatPower(receiverArraySuppliedPowerWatts) + ".", "high", (text == "watch") ? 10 : 80));
		}
	}

	private static string FormatPower(double watts)
	{
		if (watts >= 1000000000.0)
		{
			return Math.Round(watts / 1000000000.0, 3) + " GW";
		}
		if (watts >= 1000000.0)
		{
			return Math.Round(watts / 1000000.0, 1) + " MW";
		}
		if (watts >= 1000.0)
		{
			return Math.Round(watts / 1000.0, 1) + " kW";
		}
		return Math.Round(watts, 0) + " W";
	}

	private static void AddRefineryCongestionFinding(List<object> findings, ObservedGameState state)
	{
		if (state.ProductionWindowReady && state.ItemFlows.TryGetValue(1114, out var value) && value != null && state.TankStorage.TryGetValue(1114, out var value2) && value2.Capacity > 0)
		{
			double num = value.ProducedPerMinute - value.ConsumedPerMinute;
			double num2 = (double)value2.Count * 1.0 / (double)value2.Capacity;
			double num3 = ((num > 0.0) ? ((double)(value2.Capacity - value2.Count) / num) : double.PositiveInfinity);
			if (!(num2 < 0.8) || !(num3 > 20.0))
			{
				string status = ((num2 >= 0.98 || num3 <= 2.0) ? "blocked" : "watch");
				string text = (double.IsInfinity(num3) ? "not filling at the current net rate" : ("about " + Math.Max(0.0, Math.Round(num3, 1)) + " production minutes remain"));
				findings.Add(Finding("refined-oil-congestion", status, "Refined Oil tanks are " + Math.Round(num2 * 100.0, 1) + "% full; " + text + ".", "Use Refined Oil or expand storage to avoid refinery bottlenecks.", "high", 10));
			}
		}
	}

	private static Dictionary<string, object> Finding(string id, string status, string claim, string evidence, string confidence, int priority)
	{
		return new Dictionary<string, object>
		{
			{ "id", id },
			{ "status", status },
			{ "claim", claim },
			{ "evidence", evidence },
			{ "confidence", confidence },
			{ "priority", priority }
		};
	}
}
internal sealed class GuideGateCondition
{
	public string Id;

	public string Label;

	public string Status;

	public bool Required;

	public string Evidence;

	public string EvidenceKind;

	public string Action;

	public Dictionary<string, object> Export()
	{
		return new Dictionary<string, object>
		{
			{ "id", Id },
			{ "label", Label },
			{ "status", Status },
			{ "required", Required },
			{ "evidence", Evidence },
			{ "evidenceKind", EvidenceKind },
			{ "action", Action }
		};
	}
}
internal sealed class GuideGateResult
{
	public string Id;

	public string Title;

	public string Status;

	public string Basis;

	public readonly List<GuideGateCondition> Conditions = new List<GuideGateCondition>();

	public Dictionary<string, object> Export()
	{
		List<object> list = new List<object>();
		foreach (GuideGateCondition condition in Conditions)
		{
			list.Add(condition.Export());
		}
		return new Dictionary<string, object>
		{
			{ "id", Id },
			{ "title", Title },
			{ "status", Status },
			{ "basis", Basis },
			{ "conditions", list }
		};
	}
}
internal sealed class GuideProgressionEvaluation
{
	public string SelectedPhase;

	public readonly List<GuideGateResult> Gates = new List<GuideGateResult>();

	public Dictionary<string, object> Export()
	{
		List<object> list = new List<object>();
		foreach (GuideGateResult gate in Gates)
		{
			list.Add(gate.Export());
		}
		return new Dictionary<string, object>
		{
			{ "contractVersion", "3.1" },
			{ "selectionAuthority", "player" },
			{ "selectedPhase", SelectedPhase },
			{ "gateEvaluations", list }
		};
	}
}
internal static class GuideGateEngine
{
	private sealed class GateDefinition
	{
		public string Id;

		public string Title;
	}

	private static readonly GateDefinition[] Gates = new GateDefinition[9]
	{
		new GateDefinition
		{
			Id = "blue",
			Title = "Sustain the Blue Cube science loop"
		},
		new GateDefinition
		{
			Id = "red",
			Title = "Sustain Red Cubes without refinery deadlock"
		},
		new GateDefinition
		{
			Id = "ils",
			Title = "Complete the first interplanetary logistics expedition"
		},
		new GateDefinition
		{
			Id = "yellow",
			Title = "Run three continuous Yellow Cube labs"
		},
		new GateDefinition
		{
			Id = "purple",
			Title = "Run three continuous Purple Cube labs"
		},
		new GateDefinition
		{
			Id = "green",
			Title = "Run two continuous Green Cube labs"
		},
		new GateDefinition
		{
			Id = "dyson",
			Title = "Build the Photon swarm"
		},
		new GateDefinition
		{
			Id = "photon",
			Title = "Run the Critical Photon receiver array"
		},
		new GateDefinition
		{
			Id = "white",
			Title = "Complete the main progression route"
		}
	};

	public static GuideProgressionEvaluation EvaluatePhase(string selectedPhaseId, ObservedGameState state)
	{
		string text = ManualPhaseNavigator.NormalizePhase(selectedPhaseId);
		GuideGateResult item = EvaluateCurrentGate(FindGate(text) ?? Gates[0], state);
		return new GuideProgressionEvaluation
		{
			SelectedPhase = text,
			Gates = { item }
		};
	}

	private static GateDefinition FindGate(string id)
	{
		GateDefinition[] gates = Gates;
		foreach (GateDefinition gateDefinition in gates)
		{
			if (string.Equals(gateDefinition.Id, id, StringComparison.OrdinalIgnoreCase))
			{
				return gateDefinition;
			}
		}
		return null;
	}

	private static GuideGateResult EvaluateCurrentGate(GateDefinition definition, ObservedGameState state)
	{
		GuideGateResult guideGateResult = new GuideGateResult
		{
			Id = definition.Id,
			Title = definition.Title,
			Basis = "Current practical conditions evaluated from normalized live evidence."
		};
		if (definition.Id == "blue")
		{
			EvaluateBlue(guideGateResult, state);
		}
		else if (definition.Id == "red")
		{
			EvaluateRed(guideGateResult, state);
		}
		else if (definition.Id == "ils")
		{
			EvaluateIls(guideGateResult, state);
		}
		else if (definition.Id == "yellow")
		{
			EvaluateYellow(guideGateResult, state);
		}
		else if (definition.Id == "purple")
		{
			EvaluatePurple(guideGateResult, state);
		}
		else if (definition.Id == "green")
		{
			EvaluateGreen(guideGateResult, state);
		}
		else if (definition.Id == "dyson")
		{
			EvaluateDyson(guideGateResult, state);
		}
		else if (definition.Id == "photon")
		{
			EvaluatePhoton(guideGateResult, state);
		}
		else if (definition.Id == "white")
		{
			EvaluateWhite(guideGateResult, state);
		}
		bool flag = false;
		bool flag2 = false;
		bool flag3 = false;
		foreach (GuideGateCondition condition in guideGateResult.Conditions)
		{
			if (condition.Required)
			{
				if (condition.Status == "blocked")
				{
					flag = true;
				}
				else if (condition.Status == "watch")
				{
					flag2 = true;
				}
				else if (condition.Status == "unknown")
				{
					flag3 = true;
				}
			}
		}
		guideGateResult.Status = ((flag || flag2) ? "in-progress" : (flag3 ? "evidence-incomplete" : "complete"));
		return guideGateResult;
	}

	private static void EvaluateBlue(GuideGateResult gate, ObservedGameState state)
	{
		AddNamedFlowSet(gate, state, "starter-inputs", "Starter inputs arrive continuously", new int[4] { 1101, 1104, 1202, 1301 }, new string[4] { "Iron Ingots", "Copper Ingots", "Magnetic Coils", "Circuit Boards" }, "Connect the missing starter inputs to continuous production.");
		AddNamedAvailabilitySet(gate, state, "starter-mall", "Routine factory hardware replenishes automatically", new int[9] { 2001, 2011, 2301, 2302, 2303, 2101, 2106, 2203, 2201 }, new string[9] { "Conveyor Belts", "Sorters", "Mining Machines", "Arc Smelters", "Assembling Machines", "Storage", "Storage Tanks", "Wind Turbines", "Tesla Towers" }, "Automate the missing routine factory hardware.");
		AddFlow(gate, state, "blue-continuous", "Blue Cubes (Electromagnetic Matrices) run continuously at 20/min", 6001, 20.0, required: true);
		AddManualCondition(gate, "blue-labs-fed", "Research labs run without hand feeding", "Confirm that the Blue science loop reaches research automatically.", "Connect Blue Cube production to the research labs.");
	}

	private static void EvaluateRed(GuideGateResult gate, ObservedGameState state)
	{
		if (!state.ProductionWindowReady)
		{
			gate.Conditions.Add(Condition("red-loop", "Two labs sustain 20 Red Cubes (Energy Matrices) per minute", "unknown", required: true, "Production statistics are still warming up.", "unknown", "Let the factory run long enough to measure the Red science loop."));
			return;
		}
		double num = ItemRate(state, 6002);
		int num2 = ConfiguredRecipeMachines(state, 18);
		bool flag = num2 >= 2 && num >= 20.0;
		gate.Conditions.Add(Condition("red-loop", "Two labs sustain 20 Red Cubes (Energy Matrices) per minute", flag ? "ready" : "blocked", required: true, "Found " + num2 + " configured lab(s), " + Math.Round(num, 1) + " Red Cubes/min.", "derived", flag ? null : "Configure and supply two Red Cube labs at 20/min."));
	}

	private static void EvaluateYellow(GuideGateResult gate, ObservedGameState state)
	{
		AddConfiguredLabFlow(gate, state, "yellow-labs", "Three Yellow Cube (Structure Matrix) labs run continuously", 27, 6003, 3, "Configure and supply three Yellow Cube labs.");
		AddVisibleCubeInputs(gate, state, "yellow-inputs", "Diamonds and Titanium Crystals are visible in storage", 1112, "Diamonds", 1118, "Titanium Crystals", "Buffer both Yellow Cube inputs in visible storage.");
	}

	private static void EvaluateIls(GuideGateResult gate, ObservedGameState state)
	{
		int num = FindExpeditionPlanet(state);
		double num2 = PlanetProduction(state, num, 1004, 1106);
		double num3 = PlanetProduction(state, num, 1003, 1105);
		long num4 = PlanetOwned(state, num, 1106);
		long num5 = PlanetOwned(state, num, 1105);
		bool num6 = num > 0 && (num2 > 0.0 || num3 > 0.0 || num4 > 0 || num5 > 0);
		bool flag = (num4 >= 860 && num5 >= 520) || TechStarted(state, 1414) || TechStarted(state, 1604) || TechStarted(state, 2903) || TechStarted(state, 1605) || CountStellarStations(state) > 0;
		if (!num6 && !flag)
		{
			EvaluateIlsPreparation(gate, state);
		}
		else if (!flag)
		{
			EvaluateIlsExpedition(gate, state, num, num2, num3, num4, num5);
		}
		else
		{
			EvaluateIlsRush(gate, state);
		}
	}

	private static void EvaluateIlsPreparation(GuideGateResult gate, ObservedGameState state)
	{
		List<string> list = new List<string>();
		if (!state.UnlockedTechIds.Contains(2902))
		{
			list.Add("Drive Engine Lv2");
		}
		if (!state.UnlockedTechIds.Contains(1413))
		{
			list.Add("Titanium Smelting");
		}
		AddMissingPlayerItem(state, list, 2301, "Mining Machine");
		AddMissingPlayerItem(state, list, 2302, "Arc Smelter");
		AddMissingPlayerItem(state, list, 2101, "Storage Mk.I");
		AddMissingPlayerItem(state, list, 2001, "Conveyor Belt");
		AddMissingPlayerItem(state, list, 2011, "Sorter");
		AddMissingPlayerItem(state, list, 2201, "Tesla Tower");
		if (PlayerOwned(state, 2203) <= 0 && PlayerOwned(state, 2204) <= 0)
		{
			list.Add("independent power");
		}
		bool flag = list.Count == 0;
		gate.Conditions.Add(Condition("ils-preparation", "The interplanetary expedition is ready to launch", flag ? "ready" : "blocked", required: true, flag ? "Required flight technology and outpost essentials are in Icarus." : ("Still needed: " + string.Join(", ", list.ToArray()) + "."), "observed", flag ? null : "Research the missing technology and load the listed outpost essentials."));
	}

	private static void EvaluateIlsExpedition(GuideGateResult gate, ObservedGameState state, int planetId, double titaniumRate, double siliconRate, long titaniumCargo, long siliconCargo)
	{
		bool flag = titaniumRate > 0.0 && siliconRate > 0.0;
		string text = PlanetName(state, planetId);
		gate.Conditions.Add(Condition("ils-expedition-production", "Titanium and Silicon production is active on " + text, flag ? "ready" : "blocked", required: true, "Found Titanium at " + Math.Round(titaniumRate, 1) + "/min and Silicon at " + Math.Round(siliconRate, 1) + "/min.", "observed", flag ? null : "Start both Titanium and Silicon production on the expedition planet."));
		bool flag2 = titaniumCargo >= 860 && siliconCargo >= 520;
		gate.Conditions.Add(Condition("ils-expedition-cargo", "The return cargo is buffered in local storage", flag2 ? "ready" : "blocked", required: true, titaniumCargo + "/860 Titanium Ingots and " + siliconCargo + "/520 High-Purity Silicon stored on " + text + ".", "observed", flag2 ? null : "Buffer the full return cargo in local storage."));
	}

	private static void EvaluateIlsRush(GuideGateResult gate, ObservedGameState state)
	{
		int[] obj = new int[4] { 1414, 1604, 2903, 1605 };
		int num = 0;
		int[] array = obj;
		foreach (int num2 in array)
		{
			if (!state.UnlockedTechIds.Contains(num2))
			{
				num = num2;
				break;
			}
		}
		bool flag = num == 0;
		gate.Conditions.Add(Condition("ils-rush-tech", flag ? "The ILS research chain is complete" : ("Current research target: " + TechName(state, num)), flag ? "ready" : (state.QueuedTechIds.Contains(num) ? "watch" : "blocked"), required: true, flag ? "Interstellar Logistics System is researched." : (state.QueuedTechIds.Contains(num) ? "This technology is queued." : "This technology is not queued."), "observed", flag ? null : ("Research " + TechName(state, num) + ".")));
		int num3 = CountStellarStations(state) + (int)Owned(state, 2104);
		int num4 = CountLogisticsVessels(state) + (int)Owned(state, 5002);
		bool flag2 = num3 >= 2 && num4 >= 5;
		List<string> list = MissingIlsReserve(state);
		bool flag3 = flag2 || list.Count == 0;
		gate.Conditions.Add(Condition("ils-rush-reserve", "The protected ILS build reserve is complete", flag3 ? "ready" : "blocked", required: true, flag2 ? "Found two ILS stations and five Logistics Vessels." : (flag3 ? "All protected components are stored together." : ("Still needed: " + string.Join(", ", list.ToArray()) + ".")), "observed", flag3 ? null : "Store the missing components without spending the protected reserve."));
		bool num5 = HasSustainableRoute(state, 1106);
		bool flag4 = HasSustainableRoute(state, 1105) || HasSustainableRoute(state, 1003);
		bool flag5 = num5 && flag4;
		List<string> list2 = new List<string>();
		if (!num5)
		{
			list2.Add("Titanium");
		}
		if (!flag4)
		{
			list2.Add("Silicon");
		}
		gate.Conditions.Add(Condition("ils-rush-routes", "Titanium and Silicon arrive home automatically", flag5 ? "ready" : "blocked", required: true, flag5 ? "Both activated ILS routes were found." : ("Missing activated route: " + string.Join(" and ", list2.ToArray()) + "."), flag5 ? "derived" : "observed", flag5 ? null : "Activate the missing ILS route."));
	}

	private static void EvaluatePurple(GuideGateResult gate, ObservedGameState state)
	{
		AddConfiguredLabFlow(gate, state, "purple-labs", "Three Purple Cube (Information Matrix) labs run continuously", 55, 6004, 3, "Configure and supply three Purple Cube labs.");
		AddVisibleCubeInputs(gate, state, "purple-inputs", "Processors and Particle Broadband are visible in storage", 1303, "Processors", 1402, "Particle Broadband", "Buffer both Purple Cube inputs in visible storage.");
	}

	private static void EvaluateGreen(GuideGateResult gate, ObservedGameState state)
	{
		AddConfiguredLabFlow(gate, state, "green-labs", "Two Green Cube (Gravity Matrix) labs run continuously", 102, 6005, 2, "Configure and supply two Green Cube labs.");
		AddVisibleCubeInputs(gate, state, "green-inputs", "Quantum Chips and Graviton Lenses are visible in storage", 1305, "Quantum Chips", 1209, "Graviton Lenses", "Buffer both Green Cube inputs in visible storage.");
	}

	private static void EvaluateDyson(GuideGateResult gate, ObservedGameState state)
	{
		double num = ItemRate(state, 1501);
		double num2 = ItemConsumption(state, 1501);
		bool flag = state.ProductionWindowReady && num > 0.0 && num2 > 0.0;
		gate.Conditions.Add(Condition("dyson-sails", "Solar Sails are being produced and launched", flag ? "ready" : (state.ProductionWindowReady ? "blocked" : "unknown"), required: true, "Found " + Math.Round(num, 1) + "/min produced and " + Math.Round(num2, 1) + "/min launched.", state.ProductionWindowReady ? "observed" : "unknown", flag ? null : "Supply an active EM-Rail Ejector line with Solar Sails."));
		bool flag2 = state.Dyson.SwarmSailCount > 0 && state.Dyson.SwarmGenerationWatts > 0.0;
		gate.Conditions.Add(Condition("dyson-swarm", "The Dyson swarm is generating power", flag2 ? "ready" : "blocked", required: true, "Found " + state.Dyson.SwarmSailCount + " active sails generating " + FormatPower(state.Dyson.SwarmGenerationWatts) + ".", "observed", flag2 ? null : "Keep sails in orbit and confirm the swarm is generating power."));
	}

	private static void EvaluatePhoton(GuideGateResult gate, ObservedGameState state)
	{
		bool receiverTelemetryAvailable = state.Dyson.ReceiverTelemetryAvailable;
		bool flag = receiverTelemetryAvailable && state.Dyson.ConfiguredPhotonReceiverCount >= 4 && state.Dyson.LensedPhotonReceiverCount >= 4 && state.Dyson.SustainedPhotonReceiverCount >= 4;
		gate.Conditions.Add(Condition("photon-receivers", "Four lensed Ray Receivers remain continuously supplied", flag ? "ready" : (receiverTelemetryAvailable ? "blocked" : "unknown"), required: true, receiverTelemetryAvailable ? (state.Dyson.SustainedPhotonReceiverCount + "/4 sustained; " + state.Dyson.LensedPhotonReceiverCount + "/4 currently lensed.") : "Receiver continuity telemetry is not ready.", receiverTelemetryAvailable ? "observed" : "unknown", flag ? null : "Keep four Photon Generation receivers lensed and continuously supplied."));
		double num = ItemRate(state, 1208);
		double num2 = ItemRate(state, 1122);
		bool flag2 = state.ProductionWindowReady && num > 0.0 && num2 > 0.0;
		gate.Conditions.Add(Condition("photon-production", "Critical Photon and Antimatter production is running", flag2 ? "ready" : (state.ProductionWindowReady ? "blocked" : "unknown"), required: true, "Found " + Math.Round(num, 1) + " Critical Photons/min and " + Math.Round(num2, 1) + " Antimatter/min; 48/min is the receiver-array reference.", state.ProductionWindowReady ? "observed" : "unknown", flag2 ? null : "Establish continuous Critical Photon and Antimatter production."));
		long num3 = Owned(state, 1122);
		gate.Conditions.Add(Condition("antimatter-stock", "The Antimatter bank reaches the 2,000 midpoint", (num3 >= 2000) ? "ready" : "blocked", required: true, num3 + "/2,000 stored" + ((num3 >= 2000) ? " - halfway to the final research cost." : "."), "observed", (num3 >= 2000) ? null : "Bank 2,000 Antimatter to reach the midway checkpoint."));
	}

	private static void EvaluateWhite(GuideGateResult gate, ObservedGameState state)
	{
		bool flag = state.UnlockedTechIds.Contains(1507);
		gate.Conditions.Add(Condition("tech-1507", "White Cubes researched", flag ? "ready" : "blocked", required: true, null, "observed", null));
		bool flag2 = state.UnlockedTechIds.Contains(1508);
		int num = ConfiguredRecipeMachines(state, 75);
		double num2 = ItemRate(state, 6006);
		long num3 = Owned(state, 6006);
		bool flag3 = flag2 || (state.ProductionWindowReady && num >= 10 && num2 >= 40.0);
		gate.Conditions.Add(Condition("white-production", "Ten labs sustain 40 White Cubes/min", flag3 ? "ready" : (state.ProductionWindowReady ? "blocked" : "unknown"), required: true, num + "/10 labs configured; " + num3.ToString("N0", CultureInfo.InvariantCulture) + " White Cubes stored", state.ProductionWindowReady ? "observed" : "unknown", null));
		ObservedTechProgress value;
		bool flag4 = state.TechProgress.TryGetValue(1508, out value) && value.HashUploaded > 0;
		string evidence = (flag2 ? "Mission Completed complete" : (flag4 ? ("Mission Completed " + Math.Min(99, value.Percent) + "% done") : (state.QueuedTechIds.Contains(1508) ? "Mission Completed queued" : "Mission Completed not queued")));
		gate.Conditions.Add(Condition("mission-completed", "Mission Completed", flag2 ? "ready" : (state.QueuedTechIds.Contains(1508) ? "watch" : "blocked"), required: true, evidence, "observed", flag2 ? null : "Complete Mission Completed research."));
	}

	private static void AddConfiguredLabFlow(GuideGateResult gate, ObservedGameState state, string id, string label, int recipeId, int itemId, int desiredLabs, string action)
	{
		int num = ConfiguredRecipeMachines(state, recipeId);
		if (!state.ProductionWindowReady)
		{
			gate.Conditions.Add(Condition(id, label, "unknown", required: true, "Found " + num + " configured lab(s); production statistics are still warming up.", "unknown", action));
			return;
		}
		double num2 = ItemRate(state, itemId);
		bool flag = num >= desiredLabs && num2 > 0.0;
		gate.Conditions.Add(Condition(id, label, flag ? "ready" : "blocked", required: true, "Found " + num + " configured lab(s) producing " + Math.Round(num2, 1) + "/min.", "observed", flag ? null : action));
	}

	private static void AddVisibleCubeInputs(GuideGateResult gate, ObservedGameState state, string id, string label, int firstItemId, string firstItemName, int secondItemId, string secondItemName, string action)
	{
		long num = Owned(state, firstItemId);
		long num2 = Owned(state, secondItemId);
		bool flag = num > 0 && num2 > 0;
		gate.Conditions.Add(Condition(id, label, flag ? "ready" : "blocked", required: true, "Owned: " + num + " " + firstItemName + " and " + num2 + " " + secondItemName + ".", "observed", flag ? null : action));
	}

	private static int CountStellarStations(ObservedGameState state)
	{
		int num = 0;
		foreach (ObservedStationState station in state.Stations)
		{
			if (station.IsStellar)
			{
				num++;
			}
		}
		return num;
	}

	private static int CountLogisticsVessels(ObservedGameState state)
	{
		int num = 0;
		foreach (ObservedStationState station in state.Stations)
		{
			if (station.IsStellar)
			{
				num += station.IdleShipCount + station.WorkShipCount;
			}
		}
		return num;
	}

	private static void AddFlow(GuideGateResult gate, ObservedGameState state, string id, string label, int itemId, double minimum, bool required)
	{
		if (!state.ProductionWindowReady)
		{
			gate.Conditions.Add(Condition(id, label, "unknown", required, "Production observation window is not ready.", "unknown", "Let the factory run long enough to establish a rate."));
			return;
		}
		state.ItemFlows.TryGetValue(itemId, out var value);
		double num = value?.ProducedPerMinute ?? 0.0;
		bool flag = num >= minimum;
		string status = (flag ? "ready" : "blocked");
		string text = ((value != null && !string.IsNullOrEmpty(value.Name)) ? value.Name : ItemNameForAction(itemId, label));
		gate.Conditions.Add(Condition(id, label, status, required, "Found " + Math.Round(num, 1) + "/min; desired " + minimum + "/min.", "observed", flag ? null : ("Build or stabilize " + text + " at or above " + minimum + "/min.")));
	}

	private static void AddNamedFlowSet(GuideGateResult gate, ObservedGameState state, string id, string label, int[] itemIds, string[] itemNames, string action)
	{
		if (!state.ProductionWindowReady)
		{
			gate.Conditions.Add(Condition(id, label, "unknown", required: true, "The production statistics window is not ready.", "unknown", "Let the factory run long enough to check this objective."));
			return;
		}
		List<string> list = new List<string>();
		for (int i = 0; i < itemIds.Length; i++)
		{
			if (ItemRate(state, itemIds[i]) <= 0.0)
			{
				list.Add(itemNames[i]);
			}
		}
		bool flag = list.Count == 0;
		gate.Conditions.Add(Condition(id, label, flag ? "ready" : "blocked", required: true, flag ? "All four starter inputs are producing." : ("Not producing: " + string.Join(", ", list.ToArray()) + "."), "observed", flag ? null : action));
	}

	private static void AddNamedAvailabilitySet(GuideGateResult gate, ObservedGameState state, string id, string label, int[] itemIds, string[] itemNames, string action)
	{
		List<string> list = new List<string>();
		for (int i = 0; i < itemIds.Length; i++)
		{
			long num = Owned(state, itemIds[i]);
			double num2 = ItemRate(state, itemIds[i]);
			if (num < 1 && num2 <= 0.0)
			{
				list.Add(itemNames[i]);
			}
		}
		bool flag = list.Count == 0;
		gate.Conditions.Add(Condition(id, label, flag ? "ready" : "blocked", required: true, flag ? "Routine factory hardware is stocked or replenishing." : ("Missing: " + string.Join(", ", list.ToArray()) + "."), "derived", flag ? null : action));
	}

	private static void AddManualCondition(GuideGateResult gate, string id, string label, string evidence, string action)
	{
		gate.Conditions.Add(Condition(id, label, "unknown", required: true, evidence, "player-check", action));
	}

	private static void AddTech(GuideGateResult gate, ObservedGameState state, int techId, string label, bool required)
	{
		bool flag = state.UnlockedTechIds.Contains(techId);
		gate.Conditions.Add(Condition("tech-" + techId, label, flag ? "ready" : "blocked", required, "Technology " + techId + (flag ? " is complete." : " is incomplete."), "observed", flag ? null : ("Research " + TechName(state, techId) + ".")));
	}

	private static void AddAutomatedRoute(GuideGateResult gate, ObservedGameState state, int itemId, string id, string label, bool required)
	{
		bool flag = HasImportAndExport(state, itemId);
		bool flag2 = flag || HasSustainableRoute(state, itemId);
		gate.Conditions.Add(Condition(id, label, flag2 ? "ready" : "blocked", required, flag ? "Matching import and export traffic was observed during the rolling window." : (flag2 ? "A one-sided traffic observation is corroborated by matching remote Supply/Demand station policy and source production or stock." : "No traffic or corroborated supplied/demanded route was proven."), flag ? "observed" : (flag2 ? "derived" : "observed"), flag2 ? null : "Activate the automated interplanetary route."));
	}

	private static bool HasImportAndExport(ObservedGameState state, int itemId)
	{
		bool flag = false;
		bool flag2 = false;
		foreach (ObservedTrafficFlow trafficFlow in state.TrafficFlows)
		{
			if (trafficFlow.ItemId == itemId)
			{
				if (trafficFlow.InputPerMinute > 0.0)
				{
					flag = true;
				}
				if (trafficFlow.OutputPerMinute > 0.0)
				{
					flag2 = true;
				}
			}
		}
		return flag && flag2;
	}

	private static bool HasSustainableRoute(ObservedGameState state, int itemId)
	{
		if (HasImportAndExport(state, itemId))
		{
			return true;
		}
		bool flag = false;
		bool flag2 = false;
		foreach (ObservedTrafficFlow trafficFlow in state.TrafficFlows)
		{
			if (trafficFlow.ItemId == itemId)
			{
				if (trafficFlow.InputPerMinute > 0.0)
				{
					flag = true;
				}
				if (trafficFlow.OutputPerMinute > 0.0)
				{
					flag2 = true;
				}
			}
		}
		HashSet<int> hashSet = new HashSet<int>();
		HashSet<int> hashSet2 = new HashSet<int>();
		foreach (ObservedStationSlot stationSlot in state.StationSlots)
		{
			if (stationSlot.IsStellar && stationSlot.ItemId == itemId)
			{
				string obj = stationSlot.RemoteLogic ?? "";
				if (obj.IndexOf("Supply", StringComparison.OrdinalIgnoreCase) >= 0 && (stationSlot.Count > 0 || RemotePlanetProduction(state, stationSlot.PlanetId, itemId) > 0.0))
				{
					hashSet.Add(stationSlot.PlanetId);
				}
				if (obj.IndexOf("Demand", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					hashSet2.Add(stationSlot.PlanetId);
				}
			}
		}
		bool flag3 = false;
		foreach (int item in hashSet)
		{
			foreach (int item2 in hashSet2)
			{
				if (item != item2)
				{
					flag3 = true;
				}
			}
		}
		if (flag3)
		{
			return flag || flag2;
		}
		return false;
	}

	private static double RemotePlanetProduction(ObservedGameState state, int planetId, int itemId)
	{
		double num = 0.0;
		foreach (ObservedFactoryItemFlow factoryItemFlow in state.FactoryItemFlows)
		{
			if (factoryItemFlow.PlanetId == planetId && factoryItemFlow.ItemId == itemId)
			{
				num += factoryItemFlow.ProducedPerMinute;
			}
		}
		return num;
	}

	private static int FindExpeditionPlanet(ObservedGameState state)
	{
		HashSet<int> hashSet = new HashSet<int>();
		foreach (ObservedFactoryItemFlow factoryItemFlow in state.FactoryItemFlows)
		{
			if (factoryItemFlow.PlanetId > 0)
			{
				hashSet.Add(factoryItemFlow.PlanetId);
			}
		}
		foreach (int key in state.PlanetItemCounts.Keys)
		{
			if (key > 0)
			{
				hashSet.Add(key);
			}
		}
		int result = 0;
		double num = 0.0;
		foreach (int item in hashSet)
		{
			if (state.StarterPlanetId <= 0 || item != state.StarterPlanetId)
			{
				double num2 = PlanetProduction(state, item, 1004, 1106);
				double num3 = PlanetProduction(state, item, 1003, 1105);
				long val = PlanetOwned(state, item, 1106);
				long val2 = PlanetOwned(state, item, 1105);
				double num4 = ((num2 > 0.0) ? 1000.0 : 0.0) + ((num3 > 0.0) ? 1000.0 : 0.0) + (double)Math.Min(val, 860L) / 860.0 + (double)Math.Min(val2, 520L) / 520.0;
				if (num4 > num)
				{
					num = num4;
					result = item;
				}
			}
		}
		return result;
	}

	private static double PlanetProduction(ObservedGameState state, int planetId, params int[] itemIds)
	{
		if (planetId <= 0)
		{
			return 0.0;
		}
		double num = 0.0;
		foreach (ObservedFactoryItemFlow factoryItemFlow in state.FactoryItemFlows)
		{
			if (factoryItemFlow.PlanetId != planetId)
			{
				continue;
			}
			foreach (int num2 in itemIds)
			{
				if (factoryItemFlow.ItemId == num2)
				{
					num += factoryItemFlow.ProducedPerMinute;
				}
			}
		}
		return num;
	}

	private static long PlanetOwned(ObservedGameState state, int planetId, int itemId)
	{
		if (planetId <= 0 || !state.PlanetItemCounts.TryGetValue(planetId, out var value) || !value.TryGetValue(itemId, out var value2))
		{
			return 0L;
		}
		return value2;
	}

	private static long PlayerOwned(ObservedGameState state, int itemId)
	{
		if (!state.PlayerItemCounts.TryGetValue(itemId, out var value))
		{
			return 0L;
		}
		return value;
	}

	private static string PlanetName(ObservedGameState state, int planetId)
	{
		if (!state.PlanetNames.TryGetValue(planetId, out var value) || string.IsNullOrEmpty(value))
		{
			return "the expedition planet";
		}
		return value;
	}

	private static bool TechStarted(ObservedGameState state, int techId)
	{
		if (!state.UnlockedTechIds.Contains(techId))
		{
			return state.QueuedTechIds.Contains(techId);
		}
		return true;
	}

	private static void AddMissingPlayerItem(ObservedGameState state, List<string> missing, int itemId, string name)
	{
		if (PlayerOwned(state, itemId) <= 0)
		{
			missing.Add(name);
		}
	}

	private static List<string> MissingIlsReserve(ObservedGameState state)
	{
		int planetId = BestIlsReservePlanet(state);
		int[] array = new int[6] { 1103, 1106, 1303, 1206, 1107, 1203 };
		long[] array2 = new long[6] { 80L, 80L, 130L, 80L, 180L, 50L };
		string[] array3 = new string[6] { "Steel", "Titanium Ingots", "Processors", "Particle Containers", "Titanium Alloy", "Electromagnetic Turbines" };
		List<string> list = new List<string>();
		for (int i = 0; i < array.Length; i++)
		{
			long num = PlanetOwned(state, planetId, array[i]) + PlayerOwned(state, array[i]);
			if (num < array2[i])
			{
				list.Add(array2[i] - num + " " + array3[i]);
			}
		}
		long num2 = ((!state.UnlockedTechIds.Contains(1605)) ? (state.UnlockedTechIds.Contains(1414) ? 120 : 200) : 0);
		long num3 = PlanetOwned(state, planetId, 6003) + PlayerOwned(state, 6003);
		if (num3 < num2)
		{
			list.Add(num2 - num3 + " Yellow Cubes");
		}
		return list;
	}

	private static int BestIlsReservePlanet(ObservedGameState state)
	{
		if (state.PlayerPlanetId > 0 && state.PlanetItemCounts.ContainsKey(state.PlayerPlanetId))
		{
			return state.PlayerPlanetId;
		}
		int result = 0;
		long num = -1L;
		foreach (int key in state.PlanetItemCounts.Keys)
		{
			long num2 = PlanetOwned(state, key, 1103) + PlanetOwned(state, key, 1106) + PlanetOwned(state, key, 1303) + PlanetOwned(state, key, 1206) + PlanetOwned(state, key, 1107) + PlanetOwned(state, key, 1203) + PlanetOwned(state, key, 6003);
			if (num2 > num)
			{
				num = num2;
				result = key;
			}
		}
		return result;
	}

	private static string FormatPower(double watts)
	{
		if (watts >= 1000000000.0)
		{
			return Math.Round(watts / 1000000000.0, 3) + " GW";
		}
		if (watts >= 1000000.0)
		{
			return Math.Round(watts / 1000000.0, 1) + " MW";
		}
		if (watts >= 1000.0)
		{
			return Math.Round(watts / 1000.0, 1) + " kW";
		}
		return Math.Round(watts, 0) + " W";
	}

	private static bool HasStellarStation(ObservedGameState state)
	{
		foreach (ObservedStationSlot stationSlot in state.StationSlots)
		{
			if (stationSlot.IsStellar)
			{
				return true;
			}
		}
		return false;
	}

	private static int DistinctFactoryPlanets(ObservedGameState state)
	{
		HashSet<int> hashSet = new HashSet<int>();
		foreach (ObservedFactoryItemFlow factoryItemFlow in state.FactoryItemFlows)
		{
			if (factoryItemFlow.PlanetId > 0)
			{
				hashSet.Add(factoryItemFlow.PlanetId);
			}
		}
		return hashSet.Count;
	}

	private static long Owned(ObservedGameState state, int itemId)
	{
		if (!state.OwnedItemCounts.TryGetValue(itemId, out var value))
		{
			return 0L;
		}
		return value;
	}

	private static int ConfiguredRecipeMachines(ObservedGameState state, int recipeId)
	{
		int num = 0;
		foreach (ObservedRecipeConfiguration recipeConfiguration in state.RecipeConfigurations)
		{
			if (recipeConfiguration.RecipeId == recipeId)
			{
				num += recipeConfiguration.ConfiguredMachineCount;
			}
		}
		return num;
	}

	private static double ItemRate(ObservedGameState state, int itemId)
	{
		if (!state.ItemFlows.TryGetValue(itemId, out var value))
		{
			return 0.0;
		}
		return value.ProducedPerMinute;
	}

	private static double ItemConsumption(ObservedGameState state, int itemId)
	{
		if (!state.ItemFlows.TryGetValue(itemId, out var value))
		{
			return 0.0;
		}
		return value.ConsumedPerMinute;
	}

	private static string TechName(ObservedGameState state, int techId)
	{
		if (!state.TechNames.TryGetValue(techId, out var value))
		{
			return "Technology " + techId;
		}
		return value;
	}

	private static string ItemNameForAction(int itemId, string fallback)
	{
		return itemId switch
		{
			6001 => "Electromagnetic Matrix production", 
			6002 => "Energy Matrix production", 
			6003 => "Structure Matrix production", 
			6004 => "Information Matrix production", 
			6005 => "Gravity Matrix production", 
			1101 => "Iron Ingot production", 
			1104 => "Copper Ingot production", 
			1121 => "Deuterium supply", 
			1123 => "Graphene production", 
			1124 => "Carbon Nanotube production", 
			1127 => "Strange Matter production", 
			1209 => "Graviton Lens production", 
			1303 => "Processor production", 
			1305 => "Quantum Chip production", 
			1402 => "Particle Broadband production", 
			_ => fallback, 
		};
	}

	private static GuideGateCondition Condition(string id, string label, string status, bool required, string evidence, string evidenceKind, string action)
	{
		return new GuideGateCondition
		{
			Id = id,
			Label = label,
			Status = status,
			Required = required,
			Evidence = evidence,
			EvidenceKind = evidenceKind,
			Action = action
		};
	}
}
internal sealed class GuidePanelController
{
	private sealed class RowView
	{
		public GameObject Root;

		public Image Dot;

		public Image Check;

		public Text Label;

		public Text Detail;

		public readonly List<Image> Strikes = new List<Image>();

		public bool Completed;

		public float CompletionProgress;

		public float StrikeWidth;
	}

	private sealed class CubeRateView
	{
		public GameObject Root;

		public Image Icon;

		public Text Rate;

		public string CubeId;
	}

	private sealed class ImageStyle
	{
		public Sprite Sprite;

		public Material Material;

		public Color Color = Color.white;

		public Type Type;

		public bool PreserveAspect;

		public void Apply(Image image)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)image == (Object)null))
			{
				image.sprite = Sprite;
				((Graphic)image).material = Material;
				((Graphic)image).color = Color;
				image.type = Type;
				image.preserveAspect = PreserveAspect;
			}
		}

		public static ImageStyle Capture(Image image)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if ((Object)(object)image == (Object)null)
			{
				return null;
			}
			return new ImageStyle
			{
				Sprite = image.sprite,
				Material = ((Graphic)image).material,
				Color = ((Graphic)image).color,
				Type = image.type,
				PreserveAspect = image.preserveAspect
			};
		}
	}

	private sealed class TextStyle
	{
		public Font Font;

		public int FontSize;

		public FontStyle FontStyle;

		public Color Color;

		public float LineSpacing;

		public Material Material;

		public void Apply(Text text)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)text == (Object)null))
			{
				text.font = Font;
				text.fontSize = FontSize;
				text.fontStyle = FontStyle;
				((Graphic)text).color = Color;
				text.lineSpacing = LineSpacing;
				((Graphic)text).material = Material;
				text.supportRichText = true;
			}
		}

		public static TextStyle Capture(Text text, TextStyle fallback)
		{
			//IL_0076: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_0034: 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)
			if ((Object)(object)text == (Object)null)
			{
				return new TextStyle
				{
					Font = fallback.Font,
					FontSize = fallback.FontSize,
					FontStyle = fallback.FontStyle,
					Color = fallback.Color,
					LineSpacing = fallback.LineSpacing,
					Material = fallback.Material
				};
			}
			return new TextStyle
			{
				Font = text.font,
				FontSize = text.fontSize,
				FontStyle = text.fontStyle,
				Color = ((Graphic)text).color,
				LineSpacing = text.lineSpacing,
				Material = ((Graphic)text).material
			};
		}
	}

	private sealed class NativeTextPresentation
	{
		public sealed class EffectStyle
		{
			public bool IsOutline;

			public Color Color;

			public Vector2 Distance;

			public bool UsesGraphicAlpha;
		}

		public const string RuntimeSource = "UIRoot.instance.uiGame.veinDetail.nodePrefab.infoText";

		public const string LoadedNodeSource = "loaded UIVeinDetailNode.infoText";

		public string Source;

		public Font Font;

		public FontStyle FontStyle;

		public float LineSpacing;

		public Material Material;

		public readonly List<EffectStyle> Effects = new List<EffectStyle>();

		public EffectStyle PrimaryEffect
		{
			get
			{
				if (Effects.Count <= 0)
				{
					return null;
				}
				return Effects[0];
			}
		}

		public List<object> ExportEffects()
		{
			//IL_0048: 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)
			List<object> list = new List<object>();
			foreach (EffectStyle effect in Effects)
			{
				list.Add(new Dictionary<string, object>
				{
					{
						"type",
						effect.IsOutline ? "outline" : "shadow"
					},
					{
						"color",
						ColorValue(effect.Color)
					},
					{
						"distance",
						Vector(effect.Distance)
					},
					{ "usesGraphicAlpha", effect.UsesGraphicAlpha }
				});
			}
			return list;
		}

		public void Apply(NativeGoalStyle goalStyle)
		{
			Apply(goalStyle.HeaderText);
			Apply(goalStyle.GroupText);
			Apply(goalStyle.InfoText);
		}

		private void Apply(TextStyle textStyle)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			textStyle.Font = Font;
			textStyle.FontStyle = FontStyle;
			textStyle.LineSpacing = LineSpacing;
			textStyle.Material = Material;
		}

		public void ApplyEffects(GameObject target)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			foreach (EffectStyle effect in Effects)
			{
				Component obj = target.AddComponent(effect.IsOutline ? typeof(Outline) : typeof(Shadow));
				Shadow val = (Shadow)(object)((obj is Shadow) ? obj : null);
				if (!((Object)(object)val == (Object)null))
				{
					val.effectColor = effect.Color;
					val.effectDistance = effect.Distance;
					val.useGraphicAlpha = effect.UsesGraphicAlpha;
				}
			}
		}

		public static NativeTextPresentation Capture()
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				object member = GetMember(GetMember(GetMember(GetMember(GetStatic(FindType("UIRoot"), "instance", "_instance"), "uiGame"), "veinDetail"), "nodePrefab"), "infoText");
				Text val = (Text)((member is Text) ? member : null);
				string source = "UIRoot.instance.uiGame.veinDetail.nodePrefab.infoText";
				if ((Object)(object)val == (Object)null || (Object)(object)val.font == (Object)null)
				{
					val = FindLoadedVeinText();
					source = "loaded UIVeinDetailNode.infoText";
				}
				if ((Object)(object)val == (Object)null || (Object)(object)val.font == (Object)null)
				{
					return null;
				}
				NativeTextPresentation nativeTextPresentation = new NativeTextPresentation
				{
					Source = source,
					Font = val.font,
					FontStyle = val.fontStyle,
					LineSpacing = val.lineSpacing,
					Material = ((Graphic)val).material
				};
				Shadow[] components = ((Component)val).GetComponents<Shadow>();
				if (components != null)
				{
					Shadow[] array = components;
					foreach (Shadow val2 in array)
					{
						if ((Object)(object)val2 != (Object)null)
						{
							nativeTextPresentation.Effects.Add(new EffectStyle
							{
								IsOutline = (val2 is Outline),
								Color = val2.effectColor,
								Distance = val2.effectDistance,
								UsesGraphicAlpha = val2.useGraphicAlpha
							});
						}
					}
				}
				return nativeTextPresentation;
			}
			catch
			{
				return null;
			}
		}

		private static Text FindLoadedVeinText()
		{
			Type type = FindType("UIVeinDetailNode");
			if (type == null)
			{
				return null;
			}
			Object[] array = Resources.FindObjectsOfTypeAll(type);
			if (array == null)
			{
				return null;
			}
			Object[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				object member = GetMember(array2[i], "infoText");
				Text val = (Text)((member is Text) ? member : null);
				if ((Object)(object)val != (Object)null && (Object)(object)val.font != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static Type FindType(string name)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType(name, throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}

		private static object GetStatic(Type type, params string[] names)
		{
			if (type == null)
			{
				return null;
			}
			foreach (string name in names)
			{
				FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field.GetValue(null);
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.GetIndexParameters().Length == 0)
				{
					return property.GetValue(null, null);
				}
			}
			return null;
		}

		private static object GetMember(object target, params string[] names)
		{
			if (target == null)
			{
				return null;
			}
			Type type = target.GetType();
			foreach (string name in names)
			{
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field.GetValue(target);
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.GetIndexParameters().Length == 0)
				{
					return property.GetValue(target, null);
				}
			}
			return null;
		}
	}

	private sealed class NativeGoalStyle
	{
		public Transform Parent;

		public RectTransform NativeRect;

		public TextStyle HeaderText;

		public TextStyle GroupText;

		public TextStyle InfoText;

		public Color CompletedTextColor;

		public ImageStyle Background;

		public ImageStyle Edge;

		public ImageStyle Dot;

		public ImageStyle Check;

		public ImageStyle Strike;

		public ImageStyle Collapse;

		public Vector2 CollapseSize = new Vector2(30f, 30f);

		public static NativeGoalStyle Capture(Font fallbackFont)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0536: Unknown result type (might be due to invalid IL or missing references)
			//IL_053b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Unknown result typ