Decompiled source of DSPGuideCheck v1.18.22

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

Decompiled a day 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("1.18.22.0")]
[assembly: AssemblyInformationalVersion("1.18.22.4491517")]
[assembly: AssemblyProduct("DSP Guide Check")]
[assembly: AssemblyTitle("DspGuideCheck")]
[assembly: AssemblyVersion("1.18.22.0")]
namespace DspProgressionStatusExporter;

internal static class BuildVersion
{
	public const string BepInPluginVersion = "1.18.22";

	public const string PluginVersion = "1.18.22";

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

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

	private static readonly Dictionary<string, int[]> PhaseItems = new Dictionary<string, int[]>(StringComparer.OrdinalIgnoreCase)
	{
		{
			"bootstrap",
			new int[13]
			{
				1101, 1104, 1202, 1301, 2001, 2011, 2301, 2302, 2303, 2101,
				2106, 2203, 2201
			}
		},
		{
			"blue",
			new int[1] { 6001 }
		},
		{
			"red",
			new int[3] { 6002, 1114, 1120 }
		},
		{
			"ils",
			new int[6] { 1106, 1105, 1003, 6003, 2104, 5002 }
		},
		{
			"yellow",
			new int[1] { 6003 }
		},
		{
			"purple",
			new int[1] { 6004 }
		},
		{
			"green",
			new int[3] { 6005, 1305, 1209 }
		},
		{
			"dyson",
			new int[2] { 1208, 1122 }
		},
		{
			"photon",
			new int[1] { 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> 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)
			},
			{
				"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")
			},
			{
				"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++;
		}
		return 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")
			}
		};
	}

	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));
		}
		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 }
		};
		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));
		}
		return list;
	}

	private static Dictionary<string, object> ItemEvidence(ObservedGameState state, int itemId, bool includeLifetime)
	{
		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
			}
		};
		if (includeLifetime)
		{
			dictionary["lifetimeProduced"] = ((value2 != null) ? ((object)value2.Produced) : null);
			dictionary["lifetimeConsumed"] = ((value2 != null) ? ((object)value2.Consumed) : null);
		}
		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;
		}
		return dictionary2;
	}

	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 },
				{ "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 },
			{ "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 static class GuideAnalyzer
{
	private sealed class Phase
	{
		public string Id;

		public string Title;

		public int GateTechId;

		public int NextTechId;

		public string NextResearch;
	}

	private static readonly Phase[] Phases = new Phase[10]
	{
		new Phase
		{
			Id = "bootstrap",
			Title = "Automate the starter factory",
			GateTechId = 0,
			NextTechId = 1002,
			NextResearch = "Electromagnetism"
		},
		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 = "Establish reliable Antimatter production",
			GateTechId = 1505,
			NextTechId = 1506,
			NextResearch = "Dirac Inversion Mechanism"
		},
		new Phase
		{
			Id = "photon",
			Title = "Bank Antimatter for White science",
			GateTechId = 1506,
			NextTechId = 1507,
			NextResearch = "Universe Matrix"
		},
		new Phase
		{
			Id = "white",
			Title = "Complete the main progression route",
			GateTechId = 1507,
			NextTechId = 1508,
			NextResearch = "Mission Completed"
		}
	};

	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("bootstrap");
		List<object> list = new List<object>();
		if (phase.Id == "red" || phase.Id == "ils")
		{
			AddRefineryCongestionFinding(list, state);
		}
		AddPowerFinding(list, state);
		Dictionary<string, object> value = 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", "2.5" },
			{ "phaseSelectionAuthority", "player" },
			{ "phase", value },
			{
				"progression",
				guideProgressionEvaluation.Export()
			},
			{
				"normalizedState",
				state.Export()
			},
			{ "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 void AddPowerFinding(List<object> findings, ObservedGameState state)
	{
		foreach (ObservedPowerState powerPlanet in state.PowerPlanets)
		{
			if (powerPlanet.Observations >= 2 && !(powerPlanet.MinimumSatisfaction >= 0.99))
			{
				string status = ((powerPlanet.MinimumSatisfaction < 0.9) ? "blocked" : "watch");
				findings.Add(Finding("power-satisfaction-" + powerPlanet.PlanetId, status, (powerPlanet.PlanetName ?? ("Planet " + powerPlanet.PlanetId)) + " power satisfaction fell to " + Math.Round(powerPlanet.MinimumSatisfaction * 100.0, 1) + "%.", "Found across " + powerPlanet.Observations + " rolling power samples.", "high"));
			}
		}
	}

	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"));
			}
		}
	}

	private static Dictionary<string, object> Finding(string id, string status, string claim, string evidence, string confidence)
	{
		return new Dictionary<string, object>
		{
			{ "id", id },
			{ "status", status },
			{ "claim", claim },
			{ "evidence", evidence },
			{ "confidence", confidence }
		};
	}
}
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", "2.5" },
			{ "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[10]
	{
		new GateDefinition
		{
			Id = "bootstrap",
			Title = "Automate the starter factory"
		},
		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 = "Establish reliable Antimatter production"
		},
		new GateDefinition
		{
			Id = "photon",
			Title = "Bank Antimatter for White science"
		},
		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 == "bootstrap")
		{
			EvaluateBootstrap(guideGateResult, state);
		}
		else 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 EvaluateBootstrap(GuideGateResult gate, ObservedGameState state)
	{
		AddCombinedFlow(gate, state, "starter-inputs", "Iron, Copper, Magnetic Coils, and Circuit Boards arrive continuously", new int[4] { 1101, 1104, 1202, 1301 }, new double[4] { 0.1, 0.1, 0.1, 0.1 }, "Connect the four starter inputs to continuous production.");
		AddCombinedAvailability(gate, state, "starter-mall", "Routine buildings replenish automatically", new int[9] { 2001, 2011, 2301, 2302, 2303, 2101, 2106, 2203, 2201 }, new long[9] { 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L }, "Automate the routine buildings used to extend the factory.");
		AddPower(gate, state, required: true);
	}

	private static void EvaluateBlue(GuideGateResult gate, ObservedGameState state)
	{
		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.");
		AddPower(gate, state, required: true);
	}

	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 without refinery deadlock", "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);
		double num2 = ItemConsumption(state, 1114);
		double num3 = ItemConsumption(state, 1120);
		int num4 = ConfiguredRecipeMachines(state, 18);
		bool flag = num4 >= 2 && num >= 20.0 && num2 > 0.0 && num3 > 0.0;
		gate.Conditions.Add(Condition("red-loop", "Two labs sustain 20 Red Cubes (Energy Matrices) per minute while both refinery outputs keep moving", flag ? "ready" : "blocked", required: true, "Found " + num4 + " configured lab(s), " + Math.Round(num, 1) + " Red Cubes/min, " + Math.Round(num2, 1) + " Refined Oil/min leaving production, and " + Math.Round(num3, 1) + " Hydrogen/min leaving production.", "derived", flag ? null : "Sustain two Red labs and keep both refinery outputs moving."));
	}

	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.");
	}

	private static void EvaluateIls(GuideGateResult gate, ObservedGameState state)
	{
		AddTech(gate, state, 2902, "Drive Engine Lv2 is researched", required: true);
		AddTech(gate, state, 1413, "Titanium Smelting is researched", required: true);
		AddManualCondition(gate, "expedition-loadout", "The round-trip fuel, power, buildings, and defense loadout is ready", "Confirm the expedition loadout before launch.", "Prepare the complete interplanetary expedition loadout.");
		double num = RemoteProduction(state, 1106);
		double num2 = RemoteProduction(state, 1105) + RemoteProduction(state, 1003);
		bool flag = num > 0.0 && num2 > 0.0;
		gate.Conditions.Add(Condition("remote-lines", "Remote Titanium and Silicon production is operating", flag ? "ready" : "blocked", required: true, "Found remote Titanium at " + Math.Round(num, 1) + "/min and Silicon at " + Math.Round(num2, 1) + "/min.", "observed", flag ? null : "Establish remote Titanium and Silicon production."));
		long num3 = Owned(state, 1106);
		long num4 = Owned(state, 1105) + Owned(state, 1003);
		bool flag2 = num3 >= 860 && num4 >= 520;
		gate.Conditions.Add(Condition("first-cargo", "The first return carries 860 Titanium Ingots and 520 Silicon", flag2 ? "ready" : "blocked", required: true, "Owned cargo: " + num3 + " Titanium Ingots and " + num4 + " Silicon.", "observed", flag2 ? null : "Return with the full 860 Titanium and 520 Silicon cargo."));
		bool flag3 = state.UnlockedTechIds.Contains(1414) && state.UnlockedTechIds.Contains(1605);
		long num5 = Owned(state, 6003);
		gate.Conditions.Add(Condition("yellow-purchase", "The 200 Yellow Cube research purchase is funded or complete", (num5 >= 200 || flag3) ? "ready" : "blocked", required: true, flag3 ? "Titanium Alloy and Interstellar Logistics are complete." : ("Owned Yellow Cubes: " + num5 + "/200."), flag3 ? "derived" : "observed", (num5 >= 200 || flag3) ? null : "Reserve 200 Yellow Cubes for the ILS purchase."));
		int num6 = CountStellarStations(state) + (int)Owned(state, 2104);
		int num7 = CountLogisticsVessels(state) + (int)Owned(state, 5002);
		bool flag4 = num6 >= 2 && num7 >= 5;
		gate.Conditions.Add(Condition("ils-fleet", "Two ILS stations and five Logistics Vessels are available", flag4 ? "ready" : "blocked", required: true, "Found " + num6 + " station(s) and " + num7 + " vessel(s) deployed or owned.", "observed", flag4 ? null : "Prepare two ILS stations and five Logistics Vessels."));
		AddManualCondition(gate, "source-outpost", "The source outpost is powered, buffered, placed safely, and defended as needed", "Confirm the source outpost checklist in game.", "Finish the source outpost checklist before depending on it.");
		AddAutomatedRoute(gate, state, 1106, "automated-titanium", "Titanium arrives home without Icarus", required: true);
		bool flag5 = HasSustainableRoute(state, 1105) || HasSustainableRoute(state, 1003);
		gate.Conditions.Add(Condition("automated-silicon", "Silicon arrives home without Icarus", flag5 ? "ready" : "blocked", required: true, flag5 ? "An active interstellar Silicon route was found." : "An active interstellar Silicon route wasn't found.", flag5 ? "derived" : "observed", flag5 ? null : "Activate the interstellar Silicon 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.");
	}

	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.");
		bool flag = Owned(state, 1305) > 0 && Owned(state, 1209) > 0;
		gate.Conditions.Add(Condition("green-inputs", "Quantum Chips and Graviton Lenses are visible in storage", flag ? "ready" : "blocked", required: true, "Owned: " + Owned(state, 1305) + " Quantum Chips and " + Owned(state, 1209) + " Graviton Lenses.", "observed", flag ? null : "Buffer both Green Cube inputs in visible storage."));
	}

	private static void EvaluateDyson(GuideGateResult gate, ObservedGameState state)
	{
		if (!state.ProductionWindowReady)
		{
			gate.Conditions.Add(Condition("antimatter-production", "Critical Photons become reliable Antimatter production", "unknown", required: true, "Production statistics are still warming up.", "unknown", "Let the factory run long enough to measure Photon and Antimatter production."));
		}
		else
		{
			double num = ItemRate(state, 1208);
			double num2 = ItemRate(state, 1122);
			bool flag = num > 0.0 && num2 > 0.0;
			gate.Conditions.Add(Condition("antimatter-production", "Critical Photons become reliable Antimatter production", flag ? "ready" : "blocked", required: true, "Found " + Math.Round(num, 1) + " Critical Photons/min and " + Math.Round(num2, 1) + " Antimatter/min.", "observed", flag ? null : "Establish continuous Critical Photon and Antimatter production."));
		}
		bool flag2 = ItemConsumption(state, 1122) > 0.0 || HasSustainableRoute(state, 1122);
		gate.Conditions.Add(Condition("antimatter-delivery", "Antimatter reaches the science build without manual carrying", flag2 ? "ready" : "blocked", required: true, flag2 ? "Antimatter consumption or an active logistics route was found." : "Automatic Antimatter delivery wasn't found.", flag2 ? "derived" : "observed", flag2 ? null : "Connect Antimatter production to the science build."));
	}

	private static void EvaluatePhoton(GuideGateResult gate, ObservedGameState state)
	{
		long num = Owned(state, 1122);
		gate.Conditions.Add(Condition("antimatter-stock", "At least 2,000 Antimatter is stored", (num >= 2000) ? "ready" : "blocked", required: true, "Owned Antimatter: " + num + "/2,000.", "observed", (num >= 2000) ? null : "Accumulate 2,000 Antimatter."));
		AddManualCondition(gate, "antimatter-pace", "The current Antimatter rate is sufficient for the planned White science run", "Confirm that the observed rate is sufficient for your intended finish.", "Keep expanding Photon and Antimatter production until the pace is acceptable.");
	}

	private static void EvaluateWhite(GuideGateResult gate, ObservedGameState state)
	{
		AddTech(gate, state, 1507, "Universe Matrix is researched", required: true);
		bool flag = state.UnlockedTechIds.Contains(1508);
		bool flag2 = flag || SixWhiteInputsReachScience(state);
		gate.Conditions.Add(Condition("white-inputs", "All six White science inputs reach the labs continuously", flag2 ? "ready" : "blocked", required: true, flag2 ? "All five Matrix inputs and Antimatter are reaching active White production." : "One or more White science inputs are not reaching active production.", "derived", flag2 ? null : "Connect all five Matrix colors and Antimatter to White science."));
		int num = ConfiguredRecipeMachines(state, 75);
		double num2 = ItemRate(state, 6006);
		bool flag3 = flag || (state.ProductionWindowReady && num >= 10 && num2 >= 40.0);
		gate.Conditions.Add(Condition("white-production", "Ten labs sustain 40 White Cubes (Universe Matrices) per minute", flag3 ? "ready" : (state.ProductionWindowReady ? "blocked" : "unknown"), required: true, "Found " + num + " configured lab(s) and " + Math.Round(num2, 1) + " White Cubes/min.", state.ProductionWindowReady ? "observed" : "unknown", flag3 ? null : "Build and supply ten White Cube labs at 40/min."));
		gate.Conditions.Add(Condition("mission-completed", "Mission Completed consumes the final 4,000 White Cubes", flag ? "ready" : (state.QueuedTechIds.Contains(1508) ? "watch" : "blocked"), required: true, flag ? "Mission Completed is researched." : (state.QueuedTechIds.Contains(1508) ? "Mission Completed is in the research queue." : "Mission Completed has not been queued."), "observed", flag ? null : "Research Mission Completed with 4,000 White Cubes."));
	}

	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 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 bool SixWhiteInputsReachScience(ObservedGameState state)
	{
		if (!state.ProductionWindowReady || ItemRate(state, 6006) <= 0.0)
		{
			return false;
		}
		for (int i = 6001; i <= 6005; i++)
		{
			if (ItemConsumption(state, i) <= 0.0 && Owned(state, i) <= 0)
			{
				return false;
			}
		}
		if (!(ItemConsumption(state, 1122) > 0.0))
		{
			return Owned(state, 1122) > 0;
		}
		return true;
	}

	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 AddCombinedFlow(GuideGateResult gate, ObservedGameState state, string id, string label, int[] itemIds, double[] desiredRates, 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;
		}
		bool flag = true;
		List<string> list = new List<string>();
		for (int i = 0; i < itemIds.Length; i++)
		{
			double num = ItemRate(state, itemIds[i]);
			if (num < desiredRates[i])
			{
				flag = false;
			}
			list.Add(Math.Round(num, 1) + "/" + desiredRates[i] + "/min");
		}
		gate.Conditions.Add(Condition(id, label, flag ? "ready" : "blocked", required: true, "Found rates: " + string.Join(", ", list.ToArray()) + ".", "observed", flag ? null : action));
	}

	private static void AddCombinedAvailability(GuideGateResult gate, ObservedGameState state, string id, string label, int[] itemIds, long[] usefulStocks, string action)
	{
		bool flag = true;
		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 < usefulStocks[i] && num2 <= 0.0)
			{
				flag = false;
			}
			list.Add(num + " owned, " + Math.Round(num2, 1) + "/min");
		}
		gate.Conditions.Add(Condition(id, label, flag ? "ready" : "blocked", required: true, "Found " + 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 AddPower(GuideGateResult gate, ObservedGameState state, bool required)
	{
		if (state.PowerPlanets.Count == 0)
		{
			gate.Conditions.Add(Condition("power", "Power remains supplied with useful headroom", "unknown", required, "No rolling power observations are available.", "unknown", "Let the factory run long enough to observe power."));
			return;
		}
		double num = 1.0;
		double num2 = 0.0;
		foreach (ObservedPowerState powerPlanet in state.PowerPlanets)
		{
			if (powerPlanet.Observations > 0)
			{
				if (powerPlanet.MinimumSatisfaction < num)
				{
					num = powerPlanet.MinimumSatisfaction;
				}
				if (powerPlanet.MaximumDemandToCapacity > num2)
				{
					num2 = powerPlanet.MaximumDemandToCapacity;
				}
			}
		}
		string text = ((num < 0.99) ? "blocked" : ((num2 > 0.85) ? "watch" : "ready"));
		gate.Conditions.Add(Condition("power", "Power remains supplied with useful headroom", text, required, "Minimum satisfaction " + Math.Round(num * 100.0, 1) + "%; peak demand/capacity " + Math.Round(num2 * 100.0, 1) + "%.", "observed", (text == "ready") ? null : "Increase reliable generation or reduce charging pressure."));
	}

	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 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 double RemoteProduction(ObservedGameState state, int itemId)
	{
		double num = 0.0;
		foreach (ObservedFactoryItemFlow factoryItemFlow in state.FactoryItemFlows)
		{
			if (factoryItemFlow.FactoryIndex > 0 && factoryItemFlow.ItemId == itemId)
			{
				num += factoryItemFlow.ProducedPerMinute;
			}
		}
		return num;
	}

	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 Background;

		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 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 type (might be due to invalid IL or missing references)
			//IL_04ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_050a: Unknown result type (might be due to invalid IL or missing references)
			//IL_050f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0503: Unknown result type (might be due to invalid IL or missing references)
			TextStyle textStyle = new TextStyle
			{
				Font = fallbackFont,
				FontSize = 18,
				FontStyle = (FontStyle)0,
				Color = new Color(0.92f, 0.94f, 0.95f, 1f),
				LineSpacing = 1f
			};
			TextStyle textStyle2 = new TextStyle
			{
				Font = fallbackFont,
				FontSize = 14,
				FontStyle = (FontStyle)0,
				Color = new Color(0.87f, 0.89f, 0.9f, 1f),
				LineSpacing = 1f
			};
			NativeGoalStyle nativeGoalStyle = new NativeGoalStyle
			{
				HeaderText = textStyle,
				GroupText = textStyle2,
				InfoText = textStyle2,
				CompletedTextColor = new Color(0.68f, 0.72f, 0.73f, 1f),
				Background = new ImageStyle
				{
					Color = new Color(0.025f, 0.035f, 0.055f, 0.86f)
				},
				Edge = null,
				Dot = new ImageStyle
				{
					Color = new Color(0.8f, 0.82f, 0.83f, 1f)
				},
				Check = new ImageStyle
				{
					Color = new Color(0.68f, 0.8f, 0.7f, 1f)
				},
				Strike = new ImageStyle
				{
					Color = new Color(0.62f, 0.66f, 0.67f, 0.8f)
				}
			};
			try
			{
				object member = GetMember(GetMember(GetStatic(FindType("UIRoot"), "instance", "_instance"), "uiGame"), "goalPanel");
				object member2 = GetMember(member, "rect");
				RectTransform val = (RectTransform)((member2 is RectTransform) ? member2 : null);
				if ((Object)(object)val == (Object)null || (Object)(object)((Transform)val).parent == (Object)null)
				{
					return nativeGoalStyle;
				}
				Canvas componentInParent = ((Component)val).GetComponentInParent<Canvas>();
				nativeGoalStyle.Parent = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).transform : ((Transform)val).parent);
				nativeGoalStyle.NativeRect = val;
				object member3 = GetMember(member, "headerText");
				Text text = (Text)((member3 is Text) ? member3 : null);
				nativeGoalStyle.HeaderText = TextStyle.Capture(text, textStyle);
				object member4 = GetMember(member, "normalHeaderTextColor");
				if (member4 is Color)
				{
					nativeGoalStyle.HeaderText.Color = (Color)member4;
				}
				object member5 = GetMember(GetMember(member, "uiGoalGroupEntryPrefab"), "nameText");
				Text text2 = (Text)((member5 is Text) ? member5 : null);
				nativeGoalStyle.GroupText = TextStyle.Capture(text2, nativeGoalStyle.HeaderText);
				object member6 = GetMember(member, "normalHeaderOffSignTextColor");
				if (member6 is Color)
				{
					nativeGoalStyle.GroupText.Color = (Color)member6;
				}
				object member7 = GetMember(member, "uiGoalInfoEntryPrefab");
				object member8 = GetMember(member7, "nameText");
				Text text3 = (Text)((member8 is Text) ? member8 : null);
				nativeGoalStyle.InfoText = TextStyle.Capture(text3, textStyle2);
				object member9 = GetMember(member, "normalInfoTextColor");
				if (member9 is Color)
				{
					nativeGoalStyle.InfoText.Color = (Color)member9;
				}
				nativeGoalStyle.Dot = ImageStyle.Capture(FindImage(GetMember(member7, "dotImage"))) ?? nativeGoalStyle.Dot;
				nativeGoalStyle.Check = ImageStyle.Capture(FindImage(GetMember(member7, "checkImage"))) ?? nativeGoalStyle.Check;
				nativeGoalStyle.Strike = ImageStyle.Capture(FindImage(GetMember(member7, "delLinePrefab"))) ?? ImageStyle.Capture(FindImage(GetMember(member, "delLine"))) ?? nativeGoalStyle.Strike;
				nativeGoalStyle.Background = ImageStyle.Capture(FindImage(GetMember(member, "raycastBG"))) ?? nativeGoalStyle.Background;
				nativeGoalStyle.Edge = ImageStyle.Capture(FindImage(GetMember(member, "raycastBGEdge")));
				Image val2 = FindImage(GetMember(member, "collapseExpandImage"));
				nativeGoalStyle.Collapse = ImageStyle.Capture(val2);
				if ((Object)(object)val2 != (Object)null)
				{
					Rect rect = ((Graphic)val2).rectTransform.rect;
					Vector2 size = ((Rect)(ref rect)).size;
					nativeGoalStyle.CollapseSize = new Vector2((size.x >= 12f && size.x <= 48f) ? size.x : 24f, (size.y >= 12f && size.y <= 48f) ? size.y : 24f);
				}
				object member10 = GetMember(member, "tickTextColor");
				if (member10 is Color)
				{
					nativeGoalStyle.CompletedTextColor = (Color)member10;
				}
			}
			catch
			{
			}
			return nativeGoalStyle;
		}

		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 static Image FindImage(object value)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			if (value is Image)
			{
				return (Image)value;
			}
			Component val = (Component)((value is Component) ? value : null);
			if ((Object)(object)val != (Object)null)
			{
				return val.GetComponent<Image>();
			}
			GameObject val2 = (GameObject)((value is GameObject) ? value : null);
			if (!((Object)(object)val2 != (Object)null))
			{
				return null;
			}
			return val2.GetComponent<Image>();
		}
	}

	private static class GuideRichText
	{
		private static readonly Dictionary<string, Color> PhaseColors = new Dictionary<string, Color>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"blue",
				new Color(0.22f, 0.72f, 1f)
			},
			{
				"red",
				new Color(1f, 0.31f, 0.35f)
			},
			{
				"yellow",
				new Color(1f, 0.76f, 0.18f)
			},
			{
				"purple",
				new Color(0.72f, 0.42f, 1f)
			},
			{
				"green",
				new Color(0.27f, 0.9f, 0.48f)
			},
			{
				"white",
				new Color(0.94f, 0.94f, 0.96f)
			}
		};

		private static readonly string[] CubePhrases = new string[12]
		{
			"Blue Cubes (Electromagnetic Matrices)", "Blue Cube (Electromagnetic Matrix)", "Red Cubes (Energy Matrices)", "Red Cube (Energy Matrix)", "Yellow Cubes (Structure Matrices)", "Yellow Cube (Structure Matrix)", "Purple Cubes (Information Matrices)", "Purple Cube (Information Matrix)", "Green Cubes (Gravity Matrices)", "Green Cube (Gravity Matrix)",
			"White Cubes (Universe Matrices)", "White Cube (Universe Matrix)"
		};

		public static string Title(string phaseId, string title)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Color color = PhaseColor(phaseId);
			return Colorize(Escape((phaseId ?? "Guide").ToUpperInvariant()), color) + "  —  " + Cubes(title);
		}

		public static string Cubes(string text)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			string text2 = Escape(text ?? "");
			string[] cubePhrases = CubePhrases;
			foreach (string text3 in cubePhrases)
			{
				string text4 = Escape(text3);
				string phaseId = text3.Substring(0, text3.IndexOf(' '));
				text2 = text2.Replace(text4, Colorize(text4, PhaseColor(phaseId)));
			}
			return text2;
		}

		private static Color PhaseColor(string phaseId)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (phaseId == null || !PhaseColors.TryGetValue(phaseId, out var value))
			{
				return new Color(0.45f, 0.82f, 0.93f);
			}
			return value;
		}

		private static string Colorize(string text, Color color)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return "<color=#" + ColorUtility.ToHtmlStringRGB(color) + ">" + text + "</color>";
		}

		private static string Escape(string text)
		{
			return (text ?? "").Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;");
		}
	}

	private const float FallbackWidth = 440f;

	private const float OuterPadding = 12f;

	private const float SectionHeight = 25f;

	private const float FooterHeight = 42f;

	private const float RowGap = 5f;

	private const float PanelTop = 8f;

	private const float PanelRight = 28f;

	private const float SafeBottom = 230f;

	private const float ScrollControlWidth = 28f;

	private const float ScrollStep = 120f;

	private const float CubeRateSquareSize = 44f;

	private const float CubeRateGap = 4f;

	private const float CubeRateColumnInset = 48f;

	private const float BodyRightInset = 76f;

	private const float InteractiveControlHoverScale = 1.12f;

	private const float CompletionSeconds = 0.28f;

	private const float SnapshotFeedbackSeconds = 2f;

	private const string SourceGuideUrl = "https://dsp-beginner-guide.pages.dev/#";

	private const string DontPanicLabel = "DON'T\nPANIC";

	private static readonly Color DontPanicColor = new Color(1f, 0.04f, 0.07f, 1f);

	private static readonly Color SnapshotSuccessColor = new Color(0.23f, 1f, 0.44f, 1f);

	private static readonly Color SnapshotFailureColor = new Color(1f, 0.22f, 0.18f, 1f);

	private static readonly Color TextOutlineColor = new Color(0f, 0f, 0f, 0.9f);

	private static readonly Color SelectedControlOutlineColor = new Color(0.08f, 0.72f, 0.94f, 1f);

	private GameObject fallbackCanvasObject;

	private GameObject panelObject;

	private RectTransform panelRect;

	private RectTransform parentRect;

	private RectTransform viewportRect;

	private RectTransform contentRect;

	private ScrollRect scrollRect;

	private Text titleText;

	private Text objectiveHeader;

	private Text pendingHeader;

	private Text contextHeader;

	private Text snapshotLinkText;

	private Text sourceGuideLinkText;

	private Font dontPanicFont;

	private bool ownsDontPanicFont;

	private EmbeddedBasicFont presentationFont;

	private RectTransform snapshotLinkRect;

	private RectTransform sourceGuideLinkRect;

	private RectTransform scrollUpRect;

	private RectTransform scrollDownRect;

	private RectTransform collapseButtonRect;

	private RectTransform previousPhaseRect;

	private RectTransform nextPhaseRect;

	private RectTransform cubeRateColumnRect;

	private Image collapseImage;

	private Text collapseFallbackText;

	private NativeGoalStyle style;

	private bool collapsed;

	private string phaseId;

	private Func<bool> snapshotAction;

	private Action<string> navigationAction;

	private bool bodyCanScroll;

	private float panelWidth;

	private Color snapshotLinkDefaultColor;

	private float snapshotFeedbackRemaining;

	private readonly List<RowView> objectiveViews = new List<RowView>();

	private readonly List<RowView> pendingViews = new List<RowView>();

	private readonly List<RowView> contextViews = new List<RowView>();

	private readonly List<CubeRateView> cubeRateViews = new List<CubeRateView>();

	public bool IsVisible
	{
		get
		{
			if ((Object)(object)panelObject != (Object)null)
			{
				return panelObject.activeSelf;
			}
			return false;
		}
	}

	public void Prepare()
	{
		EnsureCreated();
	}

	public void SetSnapshotAction(Func<bool> action)
	{
		snapshotAction = action;
	}

	public void SetNavigationAction(Action<string> action)
	{
		navigationAction = action;
	}

	public Dictionary<string, object> ExportDiagnostics()
	{
		//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0519: Unknown result type (might be due to invalid IL or missing references)
		//IL_0539: Unknown result type (might be due to invalid IL or missing references)
		//IL_053e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0541: Unknown result type (might be due to invalid IL or missing references)
		EnsureCreated();
		Dictionary<string, object> dictionary = new Dictionary<string, object>();
		dictionary["styleSource"] = ((style != null && (Object)(object)style.NativeRect != (Object)null) ? "native-uigoalpanel" : "fallback");
		dictionary["parentName"] = (((Object)(object)panelRect != (Object)null && (Object)(object)((Transform)panelRect).parent != (Object)null) ? ((Object)((Transform)panelRect).parent).name : null);
		dictionary["adoptedWidth"] = panelWidth;
		dictionary["anchorStrategy"] = "canvas-top-right-fixed";
		dictionary["panelTop"] = 8f;
		dictionary["panelRight"] = 28f;
		dictionary["safeBottom"] = 230f;
		dictionary["boundedViewport"] = true;
		dictionary["manualWheelSupport"] = false;
		dictionary["scrollControls"] = "explicit-up-down-buttons";
		dictionary["phaseNavigation"] = "player-controlled-critical-path-previous-next";
		dictionary["panelPointerPolicy"] = "click-through-except-interactive-controls";
		dictionary["cubeRateColumn"] = "native-one-minute-rates-click-through-fixed-below-collapse";
		dictionary["textOutline"] = true;
		dictionary["presentationFontSource"] = ((presentationFont != null) ? presentationFont.Source : "not-loaded");
		dictionary["phaseControlStyle"] = "transparent-bounded-hover-with-selected-outline";
		dictionary["headerFont"] = ((style != null && style.HeaderText != null && (Object)(object)style.HeaderText.Font != (Object)null) ? ((Object)style.HeaderText.Font).name : null);
		dictionary["headerFontSize"] = ((style != null && style.HeaderText != null) ? style.HeaderText.FontSize : 0);
		dictionary["infoFont"] = ((style != null && style.InfoText != null && (Object)(object)style.InfoText.Font != (Object)null) ? ((Object)style.InfoText.Font).name : null);
		dictionary["infoFontSize"] = ((style != null && style.InfoText != null) ? style.InfoText.FontSize : 0);
		dictionary["sourceGuideLabel"] = "DON'T PANIC";
		dictionary["sourceGuideFont"] = (((Object)(object)dontPanicFont != (Object)null) ? ((Object)dontPanicFont).name : null);
		dictionary["sourceGuideFontSize"] = (((Object)(object)sourceGuideLinkText != (Object)null) ? sourceGuideLinkText.fontSize : 0);
		dictionary["sourceGuideColor"] = new Dictionary<string, object>
		{
			{ "r", DontPanicColor.r },
			{ "g", DontPanicColor.g },
			{ "b", DontPanicColor.b },
			{ "a", DontPanicColor.a }
		};
		dictionary["nativeSprites"] = new Dictionary<string, object>
		{
			{
				"background",
				HasSprite((style != null) ? style.Background : null)
			},
			{
				"edge",
				HasSprite((style != null) ? style.Edge : null)
			},
			{
				"dot",
				HasSprite((style != null) ? style.Dot : null)
			},
			{
				"check",
				HasSprite((style != null) ? style.Check : null)
			},
			{
				"strike",
				HasSprite((style != null) ? style.Strike : null)
			},
			{
				"collapse",
				HasSprite((style != null) ? style.Collapse : null)
			}
		};
		if (style != null && (Object)(object)style.NativeRect != (Object)null)
		{
			dictionary["nativeAnchorMin"] = Vector(style.NativeRect.anchorMin);
			dictionary["nativeAnchorMax"] = Vector(style.NativeRect.anchorMax);
			dictionary["nativePivot"] = Vector(style.NativeRect.pivot);
			dictionary["nativeAnchoredPosition"] = Vector(style.NativeRect.anchoredPosition);
			Rect rect = style.NativeRect.rect;
			dictionary["nativeSize"] = Vector(((Rect)(ref rect)).size);
		}
		return dictionary;
	}

	public void Show(GuidePanelModel model)
	{
		EnsureCreated();
		panelObject.SetActive(true);
		Apply(model);
	}

	public void Hide()
	{
		ResetSnapshotFeedback();
		ResetInteractiveControlScales();
		if ((Object)(object)panelObject != (Object)null)
		{
			panelObject.SetActive(false);
		}
	}

	public void UpdateModel(GuidePanelModel model)
	{
		if (IsVisible && model != null)
		{
			Apply(model);
		}
	}

	public void Tick(float unscaledDeltaTime)
	{
		if (!IsVisible)
		{
			return;
		}
		bool flag = AnimateRows(objectiveViews, unscaledDeltaTime);
		flag |= AnimateRows(pendingViews, unscaledDeltaTime);
		flag |= AnimateRows(contextViews, unscaledDeltaTime);
		if (snapshotFeedbackRemaining > 0f)
		{
			snapshotFeedbackRemaining = Mathf.Max(0f, snapshotFeedbackRemaining - unscaledDeltaTime);
			if (snapshotFeedbackRemaining <= 0f)
			{
				ResetSnapshotFeedback();
				flag = true;
			}
		}
		if (flag)
		{
			Canvas.ForceUpdateCanvases();
		}
	}

	public void Destroy()
	{
		if ((Object)(object)panelObject != (Object)null)
		{
			Object.Destroy((Object)(object)panelObject);
		}
		if ((Object)(object)fallbackCanvasObject != (Object)null)
		{
			Object.Destroy((Object)(object)fallbackCanvasObject);
		}
		if (ownsDontPanicFont && (Object)(object)dontPanicFont != (Object)null)
		{
			Object.Destroy((Object)(object)dontPanicFont);
		}
		panelObject = null;
		fallbackCanvasObject = null;
		dontPanicFont = null;
		ownsDontPanicFont = false;
		if (presentationFont != null)
		{
			presentationFont.Dispose();
		}
		presentationFont = null;
		objectiveViews.Clear();
		pendingViews.Clear();
		contextViews.Clear();
		cubeRateViews.Clear();
	}

	private void EnsureCreated()
	{
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Expected O, but got Unknown
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0310: Unknown result type (might be due to invalid IL or missing references)
		//IL_034d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0357: Expected O, but got Unknown
		//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_04dc: Expected O, but got Unknown
		//IL_04ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_0500: Expected O, but got Unknown
		//IL_05d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0637: Unknown result type (might be due to invalid IL or missing references)
		//IL_0651: Unknown result type (might be due to invalid IL or missing references)
		//IL_066b: Unknown result type (might be due to invalid IL or missing references)
		//IL_067b: Unknown result type (might be due to invalid IL or missing references)
		//IL_068b: Unknown result type (might be due to invalid IL or missing references)
		//IL_076e: Unknown result type (might be due to invalid IL or missing references)
		//IL_077e: Expected O, but got Unknown
		//IL_078a: Unknown result type (might be due to invalid IL or missing references)
		//IL_078f: Unknown result type (might be due to invalid IL or missing references)
		//IL_07b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_07c2: Expected O, but got Unknown
		//IL_083a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0872: Unknown result type (might be due to invalid IL or missing references)
		//IL_0882: Expected O, but got Unknown
		//IL_0894: Unknown result type (might be due to invalid IL or missing references)
		//IL_08a4: Expected O, but got Unknown
		//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_0401: Unknown result type (might be due to invalid IL or missing references)
		//IL_0416: Unknown result type (might be due to invalid IL or missing references)
		//IL_0427: Unknown result type (might be due to invalid IL or missing references)
		//IL_0431: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)panelObject != (Object)null))
		{
			objectiveViews.Clear();
			pendingViews.Clear();
			contextViews.Clear();
			cubeRateViews.Clear();
			phaseId = null;
			Font fallbackFont = FindFont();
			style = NativeGoalStyle.Capture(fallbackFont);
			presentationFont = EmbeddedBasicFont.Load(style.InfoText.Font, style.InfoText.FontSize);
			style.HeaderText.Font = presentationFont.Font;
			style.GroupText.Font = presentationFont.Font;
			style.InfoText.Font = presentationFont.Font;
			Transform val = style.Parent;
			if ((Object)(object)val == (Object)null)
			{
				fallbackCanvasObject = new GameObject("DSPGuideCheckFallbackCanvas", new Type[4]
				{
					typeof(RectTransform),
					typeof(Canvas),
					typeof(CanvasScaler),
					typeof(GraphicRaycaster)
				});
				Object.DontDestroyOnLoad((Object)(object)fallbackCanvasObject);
				Canvas component = fallbackCanvasObject.GetComponent<Canvas>();
				component.renderMode = (RenderMode)0;
				component.sortingOrder = 32000;
				CanvasScaler component2 = fallbackCanvasObject.GetComponent<CanvasScaler>();
				component2.uiScaleMode = (ScaleMode)1;
				component2.referenceResolution = new Vector2(1920f, 1080f);
				component2.screenMatchMode = (ScreenMatchMode)0;
				component2.matchWidthOrHeight = 0.5f;
				val = fallbackCanvasObject.transform;
			}
			parentRect = (RectTransform)(object)((val is RectTransform) ? val : null);
			panelObject = CreateObject("DSPGuideCheckPanel", val, typeof(Image));
			panelRect = panelObject.GetComponent<RectTransform>();
			ConfigurePanelAnchor();
			Image component3 = panelObject.GetComponent<Image>();
			style.Background.Apply(component3);
			((Graphic)component3).raycastTarget = false;
			if (style.Edge != null)
			{
				GameObject obj = CreateObject("NativeGoalEdge", panelObject.transform, typeof(Image));
				Stretch(obj.GetComponent<RectTransform>(), 0f, 0f, 0f, 0f);
				Image component4 = obj.GetComponent<Image>();
				style.Edge.Apply(component4);
				((Graphic)component4).raycastTarget = false;
			}
			titleText = CreateText("Title", panelObject.transform, style.HeaderText);
			titleText.alignment = (TextAnchor)0;
			GameObject val2 = CreateObject("CollapseButton", panelObject.transform, typeof(Image), typeof(Button));
			collapseButtonRect = val2.GetComponent<RectTransform>();
			Image component5 = val2.GetComponent<Image>();
			((Graphic)component5).color = new Color(1f, 1f, 1f, 0.001f);
			Button component6 = val2.GetComponent<Button>();
			((Selectable)component6).targetGraphic = (Graphic)(object)component5;
			((Selectable)component6).transition = (Transition)0;
			DisableNavigation((Selectable)(object)component6);
			AddBoundedHoverScale(val2, collapseButtonRect);
			((UnityEvent)component6.onClick).AddListener((UnityAction)delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				((Transform)collapseButtonRect).localScale = Vector3.one;
				ToggleCollapsed();
			});
			if (style.Collapse != null && (Object)(object)style.Collapse.Sprite != (Object)null)
			{
				GameObject val3 = CreateObject("NativeCollapseIcon", val2.transform, typeof(Image));
				collapseImage = val3.GetComponent<Image>();
				style.Collapse.Apply(collapseImage);
				((Graphic)collapseImage).raycastTarget = false;
				RectTransform rectTransform = ((Graphic)collapseImage).rectTransform;
				rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
				rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
				rectTransform.pivot = new Vector2(0.5f, 0.5f);
				rectTransform.sizeDelta = style.CollapseSize;
				rectTransform.anchoredPosition = Vector2.zero;
			}
			else
			{
				collapseFallbackText = CreateText("CollapseGlyph", val2.transform, style.HeaderText);
				collapseFallbackText.alignment = (TextAnchor)4;
				Stretch(((Graphic)collapseFallbackText).rectTransform, 0f, 0f, 0f, 0f);
			}
			GameObject val4 = CreateObject("CubeRateColumn", panelObject.transform);
			cubeRateColumnRect = val4.GetComponent<RectTransform>();
			CreateHeaderControl("PreviousPhase", "◀", (UnityAction)delegate
			{
				Navigate("previous");
			}, out previousPhaseRect, out var outline);
			CreateHeaderControl("NextPhase", "▶", (UnityAction)delegate
			{
				Navigate("next");
			}, out nextPhaseRect, out outline);
			GameObject val5 = CreateObject("ScrollArea", panelObject.transform, typeof(ScrollRect));
			scrollRect = val5.GetComponent<ScrollRect>();
			scrollRect.horizontal = false;
			scrollRect.vertical = false;
			scrollRect.movementType = (MovementType)2;
			scrollRect.inertia = false;
			scrollRect.scrollSensitivity = 0f;
			GameObject val6 = CreateObject("Viewport", val5.transform, typeof(Image), typeof(RectMask2D));
			viewportRect = val6.GetComponent<RectTransform>();
			Image component7 = val6.GetComponent<Image>();
			((Graphic)component7).color = new Color(0f, 0f, 0f, 0.001f);
			((Graphic)component7).raycastTarget = false;
			Stretch(viewportRect, 0f, 0f, 0f, 0f);
			GameObject val7 = CreateObject("Content", val6.transform);
			contentRect = val7.GetComponent<RectTransform>();
			contentRect.anchorMin = new Vector2(0f, 1f);
			contentRect.anchorMax = new Vector2(1f, 1f);
			contentRect.pivot = new Vector2(0.5f, 1f);
			contentRect.anchoredPosition = Vector2.zero;
			contentRect.sizeDelta = Vector2.zero;
			scrollRect.viewport = viewportRect;
			scrollRect.content = contentRect;
			objectiveHeader = CreateText("ObjectivesHeader", val7.transform, style.GroupText);
			objectiveHeader.text = "Objectives";
			pendingHeader = CreateText("PendingHeader", val7.transform, style.GroupText);
			pendingHeader.text = "Pending:";
			contextHeader = CreateText("ContextHeader", val7.transform, style.GroupText);
			contextHeader.text = "Current Status";
			snapshotLinkText = CreateFooterLink("SnapshotLink", panelObject.transform, "Save snapshot", new UnityAction(SaveSnapshot), out snapshotLinkRect);
			snapshotLinkDefaultColor = ((Graphic)snapshotLinkText).color;
			sourceGuideLinkText = CreateFooterLink("SourceGuideLink", panelObject.transform, "DON'T\nPANIC", new UnityAction(OpenSourceGuide), out sourceGuideLinkRect);
			dontPanicFont = FindDontPanicFont(style.InfoText.Font, style.InfoText.FontSize + 3, out ownsDontPanicFont);
			sourceGuideLinkText.font = dontPanicFont;
			sourceGuideLinkText.fontSize = style.InfoText.FontSize + 3;
			sourceGuideLinkText.fontStyle = (FontStyle)1;
			((Graphic)sourceGuideLinkText).color = DontPanicColor;
			sourceGuideLinkText.lineSpacing = 0.82f;
			sourceGuideLinkText.alignment = (TextAnchor)4;
			CreateScrollControl("ScrollUp", "▲", new UnityAction(ScrollUp), out scrollUpRect);
			CreateScrollControl("ScrollDown", "▼", new UnityAction(ScrollDown), out scrollDownRect);
			((Transform)cubeRateColumnRect).SetAsLastSibling();
			panelObject.transform.SetAsLastSibling();
			panelObject.SetActive(false);
		}
	}

	private void ConfigurePanelAnchor()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		RectTransform nativeRect = style.NativeRect;
		if ((Object)(object)nativeRect != (Object)null)
		{
			Rect rect = nativeRect.rect;
			panelWidth = ((Rect)(ref rect)).width;
			if (panelWidth < 280f || panelWidth > 720f)
			{
				panelWidth = Mathf.Abs(nativeRect.sizeDelta.x);
			}
		}
		if (panelWidth < 280f || panelWidth > 720f)
		{
			panelWidth = 440f;
		}
		ResetPanelAnchor();
		panelRect.sizeDelta = new Vector2(panelWidth, 300f);
	}

	private void ResetPanelAnchor()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		panelRect.anchorMin = new Vector2(1f, 1f);
		panelRect.anchorMax = new Vector2(1f, 1f);
		panelRect.pivot = new Vector2(1f, 1f);
		panelRect.anchoredPosition = new Vector2(-28f, -8f);
		((Transform)panelRect).localRotation = Quaternion.identity;
		((Transform)panelRect).localScale = Vector3.one;
	}

	private void Apply(GuidePanelModel model)
	{
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		if (model != null)
		{
			titleText.text = GuideRichText.Title(model.PhaseId, model.Title);
			snapshotLinkText.text = "Save snapshot";
			sourceGuideLinkText.text = "DON'T\nPANIC";
			bool num = !string.Equals(phaseId, model.PhaseId, StringComparison.OrdinalIgnoreCase);
			if (num || !RowsMatch(objectiveViews, model.Objectives))
			{
				phaseId = model.PhaseId;
				RebuildRows(objectiveViews, model.Objectives, "Objective");
			}
			else
			{
				UpdateRows(objectiveViews, model.Objectives);
			}
			if (!RowsMatch(pendingViews, model.Pending))
			{
				RebuildRows(pendingViews, model.Pending, "Pending");
			}
			else
			{
				UpdateRows(pendingViews, model.Pending);
			}
			if (!RowsMatch(contextViews, model.Context))
			{
				RebuildRows(contextViews, model.Context, "Context");
			}
			else
			{
				UpdateRows(contextViews, model.Context);
			}
			ApplyCubeRates(model.CubeRates);
			Layout();
			if (num)
			{
				contentRect.anchoredPosition = Vector2.zero;
			}
		}
	}

	private void ApplyCubeRates(List<GuidePanelCubeRateModel> rates)
	{
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		bool flag = cubeRateViews.Count != rates.Count;
		if (!flag)
		{
			for (int i = 0; i < rates.Count; i++)
			{
				if (!string.Equals(cubeRateViews[i].CubeId, rates[i].CubeId, StringComparison.OrdinalIgnoreCase))
				{
					flag = true;
					break;
				}
			}
		}
		if (flag)
		{
			foreach (CubeRateView cubeRateView2 in cubeRateViews)
			{
				if ((Object)(object)cubeRateView2.Root != (Object)null)
				{
					Object.Destroy((Object)(object)cubeRateView2.Root);
				}
			}
			cubeRateViews.Clear();
			foreach (GuidePanelCubeRateModel rate in rates)
			{
				GameObject val = CreateObject("CubeRate-" + rate.CubeId, (Transform)(object)cubeRateColumnRect, typeof(Image));
				Image component = val.GetComponent<Image>();
				((Graphic)component).raycastTarget = false;
				Text val2 = CreateText("Rate", val.transform, style.InfoText);
				val2.alignment = (TextAnchor)4;
				val2.fontSize = Math.Max(10, style.InfoText.FontSize - 1);
				Stretch(((Graphic)val2).rectTransform, 2f, 2f, 2f, 2f);
				cubeRateViews.Add(new CubeRateView
				{
					Root = val,
					Background = component,
					Rate = val2,
					CubeId = rate.CubeId
				});
			}
		}
		for (int j = 0; j < rates.Count; j++)
		{
			GuidePanelCubeRateModel guidePanelCubeRateModel = rates[j];
			CubeRateView cubeRateView = cubeRateViews[j];
			((Graphic)cubeRateView.Background).color = CubeBackgroundColor(guidePanelCubeRateModel.CubeId);
			cubeRateView.Rate.text = guidePanelCubeRateModel.RateText;
			((Graphic)cubeRateView.Rate).color = CubeRateTextColor(guidePanelCubeRateModel.Level);
		}
	}

	private static Color CubeBackgroundColor(string cubeId)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		if (string.Equals(cubeId, "blue", StringComparison.OrdinalIgnoreCase))
		{
			return new Color(0.05f, 0.62f, 1f, 0.38f);
		}
		if (string.Equals(cubeId, "red", StringComparison.OrdinalIgnoreCase))
		{
			return new Color(1f, 0.12f, 0.16f, 0.38f);
		}
		if (string.Equals(cubeId, "yellow", StringComparison.OrdinalIgnoreCase))
		{
			return new Color(1f, 0.72f, 0.04f, 0.38f);
		}
		if (string.Equals(cubeId, "purple", StringComparison.OrdinalIgnoreCase))
		{
			return new Color(0.68f, 0.18f, 1f, 0.38f);
		}
		if (string.Equals(cubeId, "green", StringComparison.OrdinalIgnoreCase))
		{
			return new Color(0.12f, 0.9f, 0.32f, 0.38f);
		}
		return new Color(0.9f, 0.94f, 1f, 0.38f);
	}

	private static Color CubeRateTextColor(CubeRateLevel level)
	{
		//IL_0018: 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_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		return (Color)(level switch
		{
			CubeRateLevel.BelowMinimum => new Color(1f, 0.12f, 0.12f, 1f), 
			CubeRateLevel.Minimum => new Color(1f, 0.55f, 0.08f, 1f), 
			CubeRateLevel.Later => new Color(0.22f, 1f, 0.4f, 1f), 
			_ => Color.white, 
		});
	}

	private bool RowsMatch(List<RowView> views, List<GuidePanelRowModel> rows)
	{
		if (views.Count != rows.Count)
		{
			return false;
		}
		for (int i = 0; i < rows.Count; i++)
		{
			if (!string.Equals(((Object)views[i].Root).name, "GuideRow-" + rows[i].Id, StringComparison.Ordinal))
			{
				return false;
			}
		}
		return true;
	}

	private void RebuildRows(List<RowView> views, List<GuidePanelRowModel> rows, string group)
	{
		foreach (RowView view in views)
		{
			if ((Object)(object)view.Root != (Object)null)
			{
				Object.Destroy((Object)(object)view.Root);
			}
		}
		views.Clear();
		foreach (GuidePanelRowModel row in rows)
		{
			views.Add(CreateRow(group, row));
		}
	}

	private RowView CreateRow(string group, GuidePanelRowModel row)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = CreateObject("GuideRow-" + row.Id, (Transform)(object)contentRect);
		Image obj = val.AddComponent<Image>();
		((Graphic)obj).color = new Color(1f, 1f, 1f, 0f);
		((Graphic)obj).raycastTarget = false;
		Image component = CreateObject("Dot", val.transform, typeof(Image)).GetComponent<Image>();
		style.Dot.Apply(component);
		((Graphic)component).raycastTarget = false;
		Image component2 = CreateObject("Check", val.transform, typeof(Image)).GetComponent<Image>();
		style.Check.Apply(component2);
		((Graphic)component2).raycastTarget = false;
		Text label = CreateText("Label", val.transform, style.InfoText);
		Text val2 = CreateText("Detail", val.transform, style.InfoText);
		Color color = ((Graphic)val2).color;
		color.a *= 0.75f;
		((Graphic)val2).color = color;
		RowView rowView = new RowView
		{
			Root = val,
			Dot = component,
			Check = component2,
			Label = label,
			Detail = val2
		};
		ApplyRow(rowView, row);
		return rowView;
	}

	private void UpdateRows(List<RowView> views, List<GuidePanelRowModel> rows)
	{
		for (int i = 0; i < rows.Count; i++)
		{
			ApplyRow(views[i], rows[i]);
		}
	}

	private void ApplyRow(RowView view, GuidePanelRowModel row)
	{
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		bool completed = view.Completed;
		view.Completed = row.Completed;
		if (view.Completed && !completed)
		{
			view.CompletionProgress = 0f;
		}
		else if (!view.Completed)
		{
			view.CompletionProgress = 0f;
		}
		((Behaviour)view.Dot).enabled = false;
		view.Label.text = GuideRichText.Cubes(row.Label);
		view.Detail.text = GuideRichText.Cubes(row.Detail ?? "");
		((Graphic)view.Label).color = (row.Completed ? style.CompletedTextColor : style.InfoText.Color);
		Color color = (row.Completed ? style.CompletedTextColor : style.InfoText.Color);
		color.a *= 0.72f;
		((Graphic)view.Detail).color = color;
		UpdateCompletionVisual(view);
	}

	private void Layout()
	{
		//IL_0380: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_04eb: Unknown result type (might be due to invalid IL or missing references)
		ResetPanelAnchor();
		((Component)previousPhaseRect).gameObject.SetActive(!string.Equals(phaseId, "bootstrap", StringComparison.OrdinalIgnoreCase));
		((Component)nextPhaseRect).gameObject.SetActive(!string.Equals(phaseId, "white", StringComparison.OrdinalIgnoreCase));
		float num = panelWidth - 52f;
		SetTopRect(nextPhaseRect, num - 28f, 10f, 26f, 28f);
		num -= 31f;
		SetTopRect(previousPhaseRect, num - 28f, 10f, 26f, 28f);
		num -= 31f;
		float right = panelWidth - num + 4f;
		float num2 = Mathf.Max(150f, num - 12f - 4f);
		SetTopStretchRect(((Graphic)titleText).rectTransform, 12f, 9f, right, 78f);
		((Graphic)titleText).rectTransform.SetSizeWithCurrentAnchors((Axis)0, num2);
		float num3 = Mathf.Max(28f, Mathf.Min(78f, titleText.preferredHeight));
		((Graphic)titleText).rectTransform.SetSizeWithCurrentAnchors((Axis)1, num3);
		float num4 = Mathf.Max(48f, num3 + 15f);
		SetTopRect(collapseButtonRect, panelWidth - 48f, 7f, 38f, 38f);
		SetTopRect(cubeRateColumnRect, panelWidth - 51f, 49f, 44f, (float)cubeRateViews.Count * 48f);
		for (int i = 0; i < cubeRateViews.Count; i++)
		{
			SetTopRect(cubeRateViews[i].Root.GetComponent<RectTransform>(), 0f, (float)i * 48f, 44f, 44f);
		}
		if ((Object)(object)collapseImage != (Object)null)
		{
			((Transform)((Graphic)collapseImage).rectTransform).localEulerAngles = new Vector3(0f, 0f, collapsed ? 180f : 0f);
		}
		if ((Object)(object)collapseFallbackText != (Object)null)
		{
			collapseFallbackText.text = (collapsed ? "+" : "−");
		}
		if (collapsed)
		{
			((Component)viewportRect).gameObject.SetActive(false);
			((Component)snapshotLinkRect).gameObject.SetActive(false);
			((Component)sourceGuideLinkRect).gameObject.SetActive(false);
			((Component)scrollUpRect).gameObject.SetActive(false);
			((Component)scrollDownRect).gameObject.SetActive(false);