Decompiled source of DSPEasy Framework v0.2.34

DSPEasy.Framework.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using ABN;
using HarmonyLib;
using Microsoft.CodeAnalysis;
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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("DSPEasy.Framework")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.34.0")]
[assembly: AssemblyInformationalVersion("0.2.34+8d07755fdac77ea113d82f799a4e08686c89e363")]
[assembly: AssemblyProduct("DSPEasy.Framework")]
[assembly: AssemblyTitle("DSPEasy.Framework")]
[assembly: AssemblyVersion("0.2.34.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DSPEasy.Framework.UI
{
	public class UiDrag : MonoBehaviour
	{
		public RectTransform target;

		public RectTransform grabArea;

		public bool keepInsideParent = true;

		private bool dragging;

		private Camera cam;

		private RectTransform parentRt;

		private Vector2 beginLocal;

		private Vector2 beginAnchored;

		private void OnDisable()
		{
			dragging = false;
		}

		private void Update()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			if ((Object)(object)target == (Object)null)
			{
				dragging = false;
			}
			else if (!Input.GetMouseButton(0))
			{
				dragging = false;
			}
			else if ((dragging || (Input.GetMouseButtonDown(0) && TryBegin())) && RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRt, Vector2.op_Implicit(Input.mousePosition), cam, ref val))
			{
				target.anchoredPosition = beginAnchored + (val - beginLocal);
				if (keepInsideParent)
				{
					ClampInsideParent();
				}
			}
		}

		private bool TryBegin()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			ref RectTransform reference = ref parentRt;
			Transform parent = ((Transform)target).parent;
			reference = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if ((Object)(object)parentRt == (Object)null)
			{
				return false;
			}
			RectTransform val = (RectTransform)(((Object)(object)grabArea != (Object)null) ? ((object)grabArea) : ((object)(RectTransform)((Component)this).transform));
			cam = UiFactory.CanvasCamera((Component)(object)val);
			Vector2 val2 = Vector2.op_Implicit(Input.mousePosition);
			if (!RectTransformUtility.RectangleContainsScreenPoint(val, val2, cam))
			{
				return false;
			}
			if (!UiFocus.TopmostIs(((Component)target).gameObject))
			{
				return false;
			}
			Vector2 val3 = default(Vector2);
			if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRt, val2, cam, ref val3))
			{
				return false;
			}
			beginLocal = val3;
			beginAnchored = target.anchoredPosition;
			dragging = true;
			return true;
		}

		private void ClampInsideParent()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = parentRt.rect;
			Rect rect2 = target.rect;
			Vector2 size = ((Rect)(ref rect2)).size;
			Vector2 pivot = target.pivot;
			Vector2 anchorMin = target.anchorMin;
			Vector2 anchorMax = target.anchorMax;
			Vector2 anchoredPosition = target.anchoredPosition;
			if (Mathf.Approximately(anchorMin.x, anchorMax.x) && ((Rect)(ref rect)).width > size.x + 8f)
			{
				float num = anchorMin.x * ((Rect)(ref rect)).width + anchoredPosition.x - pivot.x * size.x;
				float num2 = Mathf.Clamp(num, 2f, ((Rect)(ref rect)).width - size.x - 2f);
				anchoredPosition.x += num2 - num;
			}
			if (Mathf.Approximately(anchorMin.y, anchorMax.y) && ((Rect)(ref rect)).height > size.y + 8f)
			{
				float num3 = anchorMin.y * ((Rect)(ref rect)).height + anchoredPosition.y - pivot.y * size.y;
				float num4 = Mathf.Clamp(num3, 2f, ((Rect)(ref rect)).height - size.y - 2f);
				anchoredPosition.y += num4 - num3;
			}
			target.anchoredPosition = anchoredPosition;
		}
	}
	public static class UiFactory
	{
		public static readonly Color PanelColor = new Color(0.1f, 0.12f, 0.15f, 0.97f);

		public static readonly Color TextColor = new Color(0.92f, 0.95f, 0.97f, 1f);

		public static readonly Color ButtonColor = new Color(0.17f, 0.24f, 0.3f, 0.98f);

		public static readonly Color SliderBackColor = new Color(0.12f, 0.16f, 0.19f, 1f);

		public static readonly Color SliderFillColor = new Color(0.35f, 0.75f, 0.95f, 1f);

		private static Font cachedFont;

		public static Font DefaultFont
		{
			get
			{
				if ((Object)(object)cachedFont == (Object)null)
				{
					cachedFont = FindFont();
				}
				return cachedFont;
			}
			set
			{
				cachedFont = value;
			}
		}

		public static void EnsureFont()
		{
			cachedFont = FindFont();
		}

		public static Font FindFont()
		{
			Text[] array = Resources.FindObjectsOfTypeAll<Text>();
			for (int i = 0; i < array.Length; i++)
			{
				if (!((Object)(object)array[i] == (Object)null) && !((Object)(object)array[i].font == (Object)null))
				{
					return array[i].font;
				}
			}
			try
			{
				return Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
			}
			catch (Exception)
			{
				return null;
			}
		}

		public static Camera CanvasCamera(Component ui)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ui == (Object)null)
			{
				return null;
			}
			Canvas componentInParent = ui.GetComponentInParent<Canvas>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return null;
			}
			if ((int)componentInParent.renderMode != 0)
			{
				return componentInParent.worldCamera;
			}
			return null;
		}

		public static RectTransform NewRect(string name, Transform parent, float w, float h)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform;
			((Transform)val).SetParent(parent, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 1f);
			val.anchorMax = val2;
			val.anchorMin = val2;
			val.pivot = new Vector2(0f, 1f);
			val.anchoredPosition = Vector2.zero;
			val.sizeDelta = new Vector2(w, h);
			return val;
		}

		public static RectTransform Place(RectTransform rt, float x, float y, float w, float h)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0037: 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)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			rt.anchorMax = val;
			rt.anchorMin = val;
			rt.pivot = new Vector2(0f, 1f);
			rt.anchoredPosition = new Vector2(x, y);
			rt.sizeDelta = new Vector2(w, h);
			return rt;
		}

		public static void Pos(RectTransform rt, float x, float y, float w, float h)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0037: 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)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			rt.anchorMax = val;
			rt.anchorMin = val;
			rt.pivot = new Vector2(0f, 1f);
			rt.anchoredPosition = new Vector2(x, y);
			rt.sizeDelta = new Vector2(w, h);
		}

		public static Text MakeText(string name, Transform parent, float x, float y, float w, float h, int size, TextAnchor align)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			Text obj = ((Component)Place(NewRect(name, parent, w, h), x, y, w, h)).gameObject.AddComponent<Text>();
			obj.font = DefaultFont;
			obj.fontSize = size;
			((Graphic)obj).color = TextColor;
			obj.alignment = align;
			((Graphic)obj).raycastTarget = false;
			obj.supportRichText = false;
			obj.horizontalOverflow = (HorizontalWrapMode)0;
			obj.verticalOverflow = (VerticalWrapMode)1;
			return obj;
		}

		public static Text MakeButton(string name, Transform parent, float x, float y, float w, float h, string label, Action onClick)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			RectTransform val = Place(NewRect(name, parent, w, h), x, y, w, h);
			Image val2 = ((Component)val).gameObject.AddComponent<Image>();
			((Graphic)val2).color = ButtonColor;
			((Graphic)val2).raycastTarget = true;
			Button val3 = ((Component)val).gameObject.AddComponent<Button>();
			((Selectable)val3).targetGraphic = (Graphic)(object)val2;
			if (onClick != null)
			{
				((UnityEvent)val3.onClick).AddListener((UnityAction)delegate
				{
					onClick();
				});
			}
			Text obj = MakeText(name + "Label", (Transform)(object)val, 0f, 0f, w, h, 14, (TextAnchor)4);
			RectTransform rectTransform = ((Graphic)obj).rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.offsetMin = Vector2.zero;
			rectTransform.offsetMax = Vector2.zero;
			obj.text = label;
			return obj;
		}

		public static Image MakeImage(string name, Transform parent, float x, float y, float w, float h, Color color, Sprite sprite = null)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Image val = ((Component)Place(NewRect(name, parent, w, h), x, y, w, h)).gameObject.AddComponent<Image>();
			((Graphic)val).color = color;
			val.sprite = sprite;
			((Graphic)val).raycastTarget = false;
			if ((Object)(object)sprite != (Object)null)
			{
				val.preserveAspect = true;
			}
			return val;
		}

		public static InputField MakeInputField(string name, Transform parent, float x, float y, float w, float h, string placeholder, int fontSize)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: 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)
			RectTransform val = Place(NewRect(name, parent, w, h), x, y, w, h);
			Image val2 = ((Component)val).gameObject.AddComponent<Image>();
			((Graphic)val2).color = SliderBackColor;
			((Graphic)val2).raycastTarget = true;
			InputField obj = ((Component)val).gameObject.AddComponent<InputField>();
			Text val3 = MakeText(name + "Text", (Transform)(object)val, 6f, 0f, w - 12f, h, fontSize, (TextAnchor)3);
			((Graphic)val3).raycastTarget = false;
			val3.horizontalOverflow = (HorizontalWrapMode)1;
			Text val4 = MakeText(name + "Placeholder", (Transform)(object)val, 6f, 0f, w - 12f, h, fontSize, (TextAnchor)3);
			((Graphic)val4).raycastTarget = false;
			((Graphic)val4).color = new Color(1f, 1f, 1f, 0.35f);
			val4.text = placeholder;
			obj.textComponent = val3;
			obj.placeholder = (Graphic)(object)val4;
			((Selectable)obj).targetGraphic = (Graphic)(object)val2;
			obj.contentType = (ContentType)2;
			obj.characterLimit = 7;
			obj.text = "";
			Vector2 val5 = default(Vector2);
			((Vector2)(ref val5))..ctor(0f, 1f);
			val.anchorMax = val5;
			val.anchorMin = val5;
			return obj;
		}

		public static Slider MakeSlider(Transform parent, string name, float x, float y, float w, float h, float min, float max, bool wholeNumbers, float value, Action<float> onChange)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = Place(NewRect(name, parent, w, h), x, y, w, h);
			Slider obj = ((Component)val).gameObject.AddComponent<Slider>();
			RectTransform obj2 = NewRect("Background", (Transform)(object)val, w, 6f);
			obj2.anchorMin = new Vector2(0f, 0.5f);
			obj2.anchorMax = new Vector2(1f, 0.5f);
			obj2.pivot = new Vector2(0.5f, 0.5f);
			obj2.anchoredPosition = Vector2.zero;
			obj2.sizeDelta = new Vector2(0f, 6f);
			Image obj3 = ((Component)obj2).gameObject.AddComponent<Image>();
			((Graphic)obj3).color = SliderBackColor;
			((Graphic)obj3).raycastTarget = true;
			RectTransform val2 = NewRect("Fill", (Transform)(object)val, 0f, h);
			Image obj4 = ((Component)val2).gameObject.AddComponent<Image>();
			((Graphic)obj4).color = SliderFillColor;
			((Graphic)obj4).raycastTarget = false;
			RectTransform val3 = NewRect("Handle", (Transform)(object)val, 14f, h);
			Image val4 = ((Component)val3).gameObject.AddComponent<Image>();
			((Graphic)val4).color = new Color(0.85f, 0.93f, 1f, 1f);
			((Graphic)val4).raycastTarget = true;
			obj.fillRect = val2;
			obj.handleRect = val3;
			((Selectable)obj).targetGraphic = (Graphic)(object)val4;
			obj.direction = (Direction)0;
			obj.minValue = min;
			obj.maxValue = max;
			obj.wholeNumbers = wholeNumbers;
			obj.value = value;
			((UnityEvent<float>)(object)obj.onValueChanged).AddListener((UnityAction<float>)delegate(float v)
			{
				if (onChange != null)
				{
					onChange(v);
				}
			});
			return obj;
		}
	}
	public static class UiFocus
	{
		private static readonly List<RaycastResult> Hits = new List<RaycastResult>(16);

		public static void BringToFront(GameObject root)
		{
			if (!((Object)(object)root == (Object)null))
			{
				root.transform.SetAsLastSibling();
			}
		}

		public static void Poll(GameObject root)
		{
			if (!((Object)(object)root == (Object)null) && root.activeInHierarchy && Input.GetMouseButtonDown(0) && TopmostIs(root))
			{
				root.transform.SetAsLastSibling();
			}
		}

		public static bool TopmostIs(GameObject root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			Transform val = Topmost();
			if ((Object)(object)val != (Object)null)
			{
				if (!((Object)(object)val == (Object)(object)root.transform))
				{
					return val.IsChildOf(root.transform);
				}
				return true;
			}
			return false;
		}

		private static Transform Topmost()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			EventSystem current = EventSystem.current;
			if ((Object)(object)current == (Object)null)
			{
				return null;
			}
			PointerEventData val = new PointerEventData(current)
			{
				position = Vector2.op_Implicit(Input.mousePosition)
			};
			Hits.Clear();
			current.RaycastAll(val, Hits);
			if (Hits.Count == 0)
			{
				return null;
			}
			RaycastResult val2 = Hits[0];
			GameObject gameObject = ((RaycastResult)(ref val2)).gameObject;
			if (!((Object)(object)gameObject != (Object)null))
			{
				return null;
			}
			return gameObject.transform;
		}
	}
}
namespace DSPEasy.Framework.Save
{
	public static class ModSave
	{
		private sealed class Entry
		{
			public string Namespace;

			public IModSaveChunk Chunk;
		}

		public const uint Magic = 827346244u;

		public const byte Format = 2;

		public static Action<string> LogInfo = delegate
		{
		};

		public static Action<string> LogWarn = delegate
		{
		};

		private static readonly object sync = new object();

		private static readonly List<Entry> Entries = new List<Entry>();

		private static readonly Dictionary<string, Entry> ByKey = new Dictionary<string, Entry>(StringComparer.Ordinal);

		public static object Sync => sync;

		public static void Register(string ns, IModSaveChunk chunk)
		{
			if (chunk == null)
			{
				throw new ArgumentNullException("chunk");
			}
			if (string.IsNullOrEmpty(ns))
			{
				throw new ArgumentException("命名空间不能为空,用插件名(例如 DSPEasy.Buildings)", "ns");
			}
			if (ns.Length > 64 || ns.IndexOf('/') >= 0)
			{
				throw new ArgumentException("命名空间不合法(不超过 64 字符、不含 '/'):" + ns, "ns");
			}
			if (chunk.Id == null || chunk.Id.Length != 4)
			{
				throw new ArgumentException("状态块 ID 必须是 4 个字符:" + chunk.Id, "chunk");
			}
			for (int i = 0; i < chunk.Id.Length; i++)
			{
				char c = chunk.Id[i];
				if (c < ' ' || c > '~')
				{
					throw new ArgumentException("状态块 ID 必须是可打印 ASCII:" + chunk.Id, "chunk");
				}
			}
			lock (sync)
			{
				string key = Key(ns, chunk.Id);
				if (ByKey.ContainsKey(key))
				{
					throw new ArgumentException("状态块重复注册:" + ns + "/" + chunk.Id, "chunk");
				}
				Entry entry = new Entry
				{
					Namespace = ns,
					Chunk = chunk
				};
				Entries.Add(entry);
				ByKey[key] = entry;
			}
		}

		public static string[] Namespaces()
		{
			lock (sync)
			{
				List<string> list = new List<string>();
				for (int i = 0; i < Entries.Count; i++)
				{
					if (!list.Contains(Entries[i].Namespace))
					{
						list.Add(Entries[i].Namespace);
					}
				}
				return list.ToArray();
			}
		}

		public static bool HasSidecar(string saveName)
		{
			string text = SidecarPath(SavePathOf(saveName));
			if (text != null)
			{
				return File.Exists(text);
			}
			return false;
		}

		public static bool WriteForSaveName(string saveName)
		{
			return WriteForSaveName(saveName, null);
		}

		public static bool WriteForSaveName(string saveName, string ns)
		{
			lock (sync)
			{
				string text = SavePathOf(saveName);
				return text != null && WriteSidecar(text, ns);
			}
		}

		public static bool ReadForSaveName(string saveName)
		{
			return ReadForSaveName(saveName, null);
		}

		public static bool ReadForSaveName(string saveName, string ns)
		{
			lock (sync)
			{
				ClearAll(ns);
				string text = SavePathOf(saveName);
				return text != null && ReadSidecar(text, ns);
			}
		}

		public static void ClearAll()
		{
			ClearAll(null);
		}

		public static void ClearAll(string ns)
		{
			lock (sync)
			{
				for (int i = 0; i < Entries.Count; i++)
				{
					Entry entry = Entries[i];
					if (ns == null || !(entry.Namespace != ns))
					{
						entry.Chunk.Clear();
					}
				}
			}
		}

		public static string DescribeCounts()
		{
			return DescribeCounts(null);
		}

		public static string DescribeCounts(string ns)
		{
			lock (sync)
			{
				StringBuilder stringBuilder = new StringBuilder();
				for (int i = 0; i < Entries.Count; i++)
				{
					Entry entry = Entries[i];
					if (ns == null || !(entry.Namespace != ns))
					{
						if (stringBuilder.Length > 0)
						{
							stringBuilder.Append(' ');
						}
						stringBuilder.Append(entry.Namespace).Append('/').Append(entry.Chunk.Id)
							.Append('=')
							.Append(entry.Chunk.Count);
					}
				}
				return stringBuilder.ToString();
			}
		}

		public static string SidecarPath(string dsvPath)
		{
			if (string.IsNullOrEmpty(dsvPath))
			{
				return null;
			}
			string text = Path.GetDirectoryName(dsvPath);
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(dsvPath);
			if (text == null)
			{
				text = string.Empty;
			}
			return Path.Combine(text, fileNameWithoutExtension + ".mod.dat");
		}

		public static void DeleteSidecar(string dsvPath)
		{
			lock (sync)
			{
				string text = SidecarPath(dsvPath);
				if (text != null)
				{
					TryDelete(text);
				}
			}
		}

		public static string SavePathOf(string saveName)
		{
			if (string.IsNullOrEmpty(saveName))
			{
				return null;
			}
			try
			{
				return GameSave.SavePath(saveName);
			}
			catch (Exception ex)
			{
				LogWarn("[ModSave] 解析存档路径失败:" + saveName + " -> " + ex.Message);
				return null;
			}
		}

		private static string Key(string ns, string id)
		{
			return ns + "/" + id;
		}

		private static bool WriteSidecar(string dsvPath, string ns)
		{
			FileInfo fileInfo = new FileInfo(dsvPath);
			if (!fileInfo.Exists)
			{
				LogWarn("[ModSave] 主存档不存在,跳过旁车写入:" + dsvPath);
				return false;
			}
			string text = SidecarPath(dsvPath);
			List<Entry> list = new List<Entry>();
			for (int i = 0; i < Entries.Count; i++)
			{
				Entry entry = Entries[i];
				if (ns == null || entry.Namespace == ns)
				{
					list.Add(entry);
				}
			}
			List<SidecarChunk> list2 = new List<SidecarChunk>();
			int num = 0;
			if (SidecarFile.TryRead(text, out var header, out var chunks, out var error))
			{
				bool flag = header.Format < 2;
				for (int j = 0; j < chunks.Count; j++)
				{
					SidecarChunk sidecarChunk = chunks[j];
					Entry entry2 = (flag ? FindUnique(sidecarChunk.IdText) : Lookup(sidecarChunk.Namespace, sidecarChunk.IdText));
					if (entry2 == null || (ns != null && !(entry2.Namespace == ns)) || sidecarChunk.Version > entry2.Chunk.Version)
					{
						list2.Add(sidecarChunk);
						num++;
					}
				}
				if (flag)
				{
					LogInfo("[ModSave] 旁车是格式 " + header.Format + " 的旧文件,本次写出会升级为格式 " + (byte)2 + "(块头带命名空间)");
				}
			}
			else if (File.Exists(text))
			{
				LogWarn("[ModSave] 旧旁车无法解析(" + error + "),本次按当前内存状态整体重写:" + text);
			}
			for (int k = 0; k < list.Count; k++)
			{
				list2.Add(SerializeEntry(list[k]));
			}
			SidecarHeader header2 = new SidecarHeader
			{
				SaveLength = fileInfo.Length,
				SaveTicks = fileInfo.LastWriteTimeUtc.Ticks,
				GameTick = GameMain.gameTick,
				Format = 2
			};
			if (!SidecarFile.TryWrite(text, header2, list2, out var error2))
			{
				LogWarn("[ModSave] 写入旁车失败:" + error2);
				return false;
			}
			if (num > 0)
			{
				LogInfo("[ModSave] 旁车已保留 " + num + " 个不属于本次命名空间的数据块");
			}
			return true;
		}

		private static bool ReadSidecar(string dsvPath, string ns)
		{
			string text = SidecarPath(dsvPath);
			if (!SidecarFile.TryRead(text, out var header, out var chunks, out var error))
			{
				if (File.Exists(text))
				{
					LogWarn("[ModSave] 读取旁车失败:" + error + "(" + text + ")");
				}
				return false;
			}
			long length = new FileInfo(dsvPath).Length;
			if (length != header.SaveLength)
			{
				LogWarn("[ModSave] 旁车与存档不配对(存档 " + length + " 字节,旁车记录 " + header.SaveLength + " 字节),本次按无模组数据加载:" + text);
				return false;
			}
			int num = 0;
			for (int i = 0; i < chunks.Count; i++)
			{
				SidecarChunk sidecarChunk = chunks[i];
				Entry entry = Resolve(sidecarChunk, header.Format);
				if (entry == null || (ns != null && entry.Namespace != ns))
				{
					continue;
				}
				string text2 = entry.Namespace + "/" + sidecarChunk.IdText;
				if (sidecarChunk.Version > entry.Chunk.Version)
				{
					LogWarn("[ModSave] 跳过版本过新的数据块 " + text2 + " v" + sidecarChunk.Version + "(支持到 v" + entry.Chunk.Version + ")");
					continue;
				}
				if (SidecarFile.Fnv1a(sidecarChunk.Payload) != sidecarChunk.Hash)
				{
					LogWarn("[ModSave] 数据块校验失败,已跳过:" + text2);
					continue;
				}
				try
				{
					using MemoryStream input = new MemoryStream(sidecarChunk.Payload, writable: false);
					using BinaryReader reader = new BinaryReader(input, Encoding.UTF8);
					entry.Chunk.Read(reader, sidecarChunk.Version);
					num++;
				}
				catch (Exception ex)
				{
					LogWarn("[ModSave] 读取数据块失败,已跳过:" + text2 + " -> " + ex.Message);
					entry.Chunk.Clear();
				}
			}
			LogInfo("[ModSave] 已读取旁车 " + Path.GetFileName(text) + ":块 " + num + "/" + chunks.Count + ((ns == null) ? "" : ("(命名空间 " + ns + ")")) + ",存档 tick " + header.GameTick + ",写出时间 " + new DateTime(header.SaveTicks, DateTimeKind.Utc));
			return num > 0;
		}

		private static Entry Resolve(SidecarChunk chunk, byte format)
		{
			if (format >= 2)
			{
				return Lookup(chunk.Namespace, chunk.IdText);
			}
			if (chunk.Namespace.Length == 0)
			{
				return FindUnique(chunk.IdText);
			}
			return Lookup(chunk.Namespace, chunk.IdText);
		}

		private static Entry Lookup(string ns, string id)
		{
			if (!ByKey.TryGetValue(Key(ns, id), out var value))
			{
				return null;
			}
			return value;
		}

		private static Entry FindUnique(string id)
		{
			Entry result = null;
			int num = 0;
			for (int i = 0; i < Entries.Count; i++)
			{
				if (!(Entries[i].Chunk.Id != id))
				{
					result = Entries[i];
					num++;
				}
			}
			if (num == 1)
			{
				return result;
			}
			if (num > 1)
			{
				LogWarn("[ModSave] 旧格式旁车里的块 " + id + " 同时被 " + num + " 个命名空间注册,无法判断归属,已跳过");
			}
			return null;
		}

		private static SidecarChunk SerializeEntry(Entry entry)
		{
			byte[] array = Serialize(entry.Chunk);
			return new SidecarChunk
			{
				Namespace = entry.Namespace,
				Id = SidecarFile.PackId(entry.Chunk.Id),
				Version = entry.Chunk.Version,
				Payload = array,
				Hash = SidecarFile.Fnv1a(array)
			};
		}

		private static byte[] Serialize(IModSaveChunk chunk)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter writer = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true))
			{
				chunk.Write(writer);
			}
			return memoryStream.ToArray();
		}

		private static void TryDelete(string path)
		{
			try
			{
				if (File.Exists(path))
				{
					File.Delete(path);
				}
			}
			catch (Exception)
			{
			}
		}
	}
	public interface IModSaveChunk
	{
		string Id { get; }

		int Version { get; }

		int Count { get; }

		void Write(BinaryWriter writer);

		void Read(BinaryReader reader, int version);

		void Clear();
	}
	public abstract class EntityStateChunk<T> : IModSaveChunk
	{
		public readonly Dictionary<long, T> Map;

		private const int MaxRecords = 1000000;

		public abstract string Id { get; }

		public abstract int Version { get; }

		public int Count => Map.Count;

		protected EntityStateChunk(Dictionary<long, T> map)
		{
			if (map == null)
			{
				throw new ArgumentNullException("map");
			}
			Map = map;
		}

		protected abstract void WriteValue(BinaryWriter writer, T value);

		protected abstract T ReadValue(BinaryReader reader, int version);

		public void Write(BinaryWriter writer)
		{
			writer.Write(Map.Count);
			foreach (KeyValuePair<long, T> item in Map)
			{
				writer.Write(item.Key);
				WriteValue(writer, item.Value);
			}
		}

		public void Read(BinaryReader reader, int version)
		{
			Map.Clear();
			int num = reader.ReadInt32();
			if (num < 0 || num > 1000000)
			{
				throw new InvalidDataException("状态块 " + Id + " 记录数非法:" + num);
			}
			for (int i = 0; i < num; i++)
			{
				long key = reader.ReadInt64();
				Map[key] = ReadValue(reader, version);
			}
		}

		public void Clear()
		{
			Map.Clear();
		}
	}
	public struct SidecarHeader
	{
		public long SaveLength;

		public long SaveTicks;

		public long GameTick;

		public byte Format;
	}
	public sealed class SidecarChunk
	{
		public string Namespace = "";

		public uint Id;

		public int Version;

		public byte[] Payload;

		public uint Hash;

		public string IdText => SidecarFile.UnpackId(Id);
	}
	public static class SidecarFile
	{
		public const uint Magic = 827346244u;

		public const byte Format = 2;

		public const byte MinFormat = 1;

		public const int MaxChunkBytes = 8388608;

		public const int MaxChunks = 4096;

		private const int HeaderOverhead = 32;

		private static readonly object FileLock = new object();

		public static bool TryRead(string path, out SidecarHeader header, out List<SidecarChunk> chunks, out string error)
		{
			bool num = ReadCore(path, out header, out chunks, out error);
			if (!num)
			{
				chunks = null;
			}
			return num;
		}

		private static bool ReadCore(string path, out SidecarHeader header, out List<SidecarChunk> chunks, out string error)
		{
			header = default(SidecarHeader);
			chunks = new List<SidecarChunk>();
			error = null;
			if (string.IsNullOrEmpty(path))
			{
				error = "路径为空";
				return false;
			}
			lock (FileLock)
			{
				if (!File.Exists(path))
				{
					error = "文件不存在";
					return false;
				}
				try
				{
					using FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
					using BinaryReader binaryReader = new BinaryReader(input, Encoding.UTF8);
					if (binaryReader.ReadUInt32() != 827346244)
					{
						error = "magic 不匹配";
						return false;
					}
					byte b = binaryReader.ReadByte();
					if (b < 1 || b > 2)
					{
						error = "格式版本不支持:" + b;
						return false;
					}
					binaryReader.ReadByte();
					int num = binaryReader.ReadUInt16();
					header.Format = b;
					header.SaveLength = binaryReader.ReadInt64();
					header.SaveTicks = binaryReader.ReadInt64();
					header.GameTick = binaryReader.ReadInt64();
					if (num > 4096)
					{
						error = "块数量非法:" + num;
						return false;
					}
					for (int i = 0; i < num; i++)
					{
						string text = ((b >= 2) ? binaryReader.ReadString() : "");
						uint id = binaryReader.ReadUInt32();
						int version = binaryReader.ReadInt32();
						int num2 = binaryReader.ReadInt32();
						if (num2 < 0 || num2 > 8388608)
						{
							error = "数据块长度非法:" + num2;
							return false;
						}
						byte[] array = binaryReader.ReadBytes(num2);
						if (array.Length != num2)
						{
							error = "数据块被截断";
							return false;
						}
						uint hash = binaryReader.ReadUInt32();
						chunks.Add(new SidecarChunk
						{
							Namespace = (text ?? ""),
							Id = id,
							Version = version,
							Payload = array,
							Hash = hash
						});
					}
				}
				catch (Exception ex)
				{
					error = ex.Message;
					return false;
				}
			}
			return true;
		}

		public static bool TryWrite(string path, SidecarHeader header, IList<SidecarChunk> chunks, out string error)
		{
			error = null;
			if (string.IsNullOrEmpty(path))
			{
				error = "路径为空";
				return false;
			}
			if (chunks == null)
			{
				error = "块列表为空";
				return false;
			}
			if (chunks.Count > 4096)
			{
				error = "块数量超过上限:" + chunks.Count;
				return false;
			}
			string text = path + ".tmp";
			lock (FileLock)
			{
				try
				{
					using (FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None))
					{
						using BinaryWriter binaryWriter = new BinaryWriter(fileStream, Encoding.UTF8);
						binaryWriter.Write(827346244u);
						binaryWriter.Write((byte)2);
						binaryWriter.Write((byte)0);
						binaryWriter.Write((ushort)chunks.Count);
						binaryWriter.Write(header.SaveLength);
						binaryWriter.Write(header.SaveTicks);
						binaryWriter.Write(header.GameTick);
						for (int i = 0; i < chunks.Count; i++)
						{
							SidecarChunk sidecarChunk = chunks[i];
							binaryWriter.Write(sidecarChunk.Namespace ?? "");
							binaryWriter.Write(sidecarChunk.Id);
							binaryWriter.Write(sidecarChunk.Version);
							binaryWriter.Write(sidecarChunk.Payload.Length);
							binaryWriter.Write(sidecarChunk.Payload);
							binaryWriter.Write(sidecarChunk.Hash);
						}
						binaryWriter.Flush();
						fileStream.Flush(flushToDisk: true);
					}
					Replace(text, path);
					return true;
				}
				catch (Exception ex)
				{
					error = ex.Message;
					TryDelete(text);
					return false;
				}
			}
		}

		public static int EstimateSize(int chunkCount, int payloadBytes)
		{
			return 32 + chunkCount * 16 + payloadBytes;
		}

		public static uint Fnv1a(byte[] data)
		{
			uint num = 2166136261u;
			for (int i = 0; i < data.Length; i++)
			{
				num ^= data[i];
				num *= 16777619;
			}
			return num;
		}

		public static uint PackId(string id)
		{
			return id[0] | ((uint)id[1] << 8) | ((uint)id[2] << 16) | ((uint)id[3] << 24);
		}

		public static string UnpackId(uint id)
		{
			return new string(new char[4]
			{
				(char)(id & 0xFF),
				(char)((id >> 8) & 0xFF),
				(char)((id >> 16) & 0xFF),
				(char)((id >> 24) & 0xFF)
			});
		}

		private static void Replace(string tmp, string path)
		{
			if (File.Exists(path))
			{
				try
				{
					File.Replace(tmp, path, null);
					return;
				}
				catch (Exception)
				{
					File.Delete(path);
				}
			}
			File.Move(tmp, path);
		}

		private static void TryDelete(string path)
		{
			try
			{
				if (File.Exists(path))
				{
					File.Delete(path);
				}
			}
			catch (Exception)
			{
			}
		}
	}
}
namespace DSPEasy.Framework.Recipes
{
	public interface IRecipePolicy
	{
		int Signature { get; }

		bool IsRaw(int itemId);

		int Choose(int itemId, List<RecipeProto> producers);
	}
	public sealed class RecipePlan
	{
		public int Target;

		public int OutPer = 1;

		public readonly Dictionary<int, int> Crafts = new Dictionary<int, int>();

		public readonly Dictionary<int, int> External = new Dictionary<int, int>();

		public readonly Dictionary<int, int> Byprod = new Dictionary<int, int>();

		public readonly Dictionary<int, int> Consumed = new Dictionary<int, int>();

		public readonly Dictionary<int, int> Produced = new Dictionary<int, int>();

		public readonly HashSet<int> Crafted = new HashSet<int>();

		public int Ticks;

		public int[] Overflow = new int[0];

		public int Kinds => External.Count + Byprod.Count + 1;
	}
	public sealed class RecipeSolver
	{
		public int MaxKinds = 12;

		public int SpeedScale = 1;

		public int MaxRounds = 24;

		public int DepthLimit = 64;

		private readonly Dictionary<int, List<RecipeProto>> producerCache = new Dictionary<int, List<RecipeProto>>();

		private readonly Dictionary<long, RecipePlan> planCache = new Dictionary<long, RecipePlan>();

		private readonly List<RecipeProto> empty = new List<RecipeProto>();

		public List<RecipeProto> Producers(int itemId)
		{
			if (itemId <= 0)
			{
				return empty;
			}
			if (producerCache.TryGetValue(itemId, out var value))
			{
				return value;
			}
			List<RecipeProto> list = new List<RecipeProto>(4);
			RecipeProto[] dataArray = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray;
			for (int i = 0; i < 2; i++)
			{
				foreach (RecipeProto val in dataArray)
				{
					if (val == null || ((Proto)val).ID <= 0 || val.Results == null || val.ResultCounts == null)
					{
						continue;
					}
					bool flag = false;
					bool flag2 = false;
					for (int k = 0; k < val.Results.Length; k++)
					{
						if (val.Results[k] == itemId && val.ResultCounts[k] > 0)
						{
							flag2 = true;
							if (k == 0)
							{
								flag = true;
							}
						}
					}
					if (flag2 && flag == (i == 0) && !list.Contains(val))
					{
						list.Add(val);
					}
				}
			}
			producerCache[itemId] = list;
			return list;
		}

		public RecipeProto Choose(int itemId, IRecipePolicy policy, out int outIdx, out int per)
		{
			outIdx = -1;
			per = 0;
			List<RecipeProto> list = Producers(itemId);
			if (list.Count == 0)
			{
				return null;
			}
			int num = policy?.Choose(itemId, list) ?? 0;
			if (num < 0 || num >= list.Count)
			{
				num = 0;
			}
			RecipeProto val = list[num];
			for (int i = 0; i < val.Results.Length; i++)
			{
				if (val.Results[i] == itemId && val.ResultCounts[i] > 0)
				{
					outIdx = i;
					per = val.ResultCounts[i];
					break;
				}
			}
			if (outIdx >= 0)
			{
				return val;
			}
			return null;
		}

		public RecipePlan Plan(int target, IRecipePolicy policy)
		{
			if (target <= 0)
			{
				return null;
			}
			int num = policy?.Signature ?? 0;
			long key = ((long)target << 40) ^ ((long)MaxKinds << 32) ^ (uint)num;
			if (planCache.TryGetValue(key, out var value))
			{
				return value;
			}
			RecipePlan recipePlan = Build(target, policy);
			if (recipePlan == null)
			{
				return null;
			}
			if (planCache.Count > 128)
			{
				planCache.Clear();
			}
			planCache[key] = recipePlan;
			return recipePlan;
		}

		public void ClearCache()
		{
			planCache.Clear();
		}

		private RecipePlan Build(int target, IRecipePolicy policy)
		{
			if (Choose(target, policy, out var _, out var per) == null)
			{
				return null;
			}
			per = Math.Max(1, per);
			HashSet<int> hashSet = new HashSet<int>();
			RecipePlan recipePlan = new RecipePlan
			{
				Target = target,
				OutPer = per
			};
			Expand(target, policy, hashSet, recipePlan);
			for (int i = 0; i < MaxRounds; i++)
			{
				if (recipePlan.Kinds <= MaxKinds)
				{
					break;
				}
				int kinds = recipePlan.Kinds;
				int num = 0;
				int num2 = int.MaxValue;
				foreach (int item in recipePlan.Crafted)
				{
					if (item == target)
					{
						continue;
					}
					hashSet.Add(item);
					RecipePlan recipePlan2 = NewPlan(target, policy, hashSet);
					hashSet.Remove(item);
					if (recipePlan2 != null)
					{
						int kinds2 = recipePlan2.Kinds;
						if (kinds2 < num2)
						{
							num2 = kinds2;
							num = item;
						}
					}
				}
				if (num == 0 || num2 >= kinds)
				{
					break;
				}
				hashSet.Add(num);
				recipePlan = NewPlan(target, policy, hashSet);
				if (recipePlan == null)
				{
					return null;
				}
			}
			if (recipePlan.Kinds > MaxKinds)
			{
				return null;
			}
			recipePlan.OutPer = ((recipePlan.Produced.TryGetValue(target, out var value) && value > 0) ? value : per);
			List<int> list = new List<int>();
			foreach (int item2 in hashSet)
			{
				if (recipePlan.External.ContainsKey(item2))
				{
					list.Add(item2);
				}
			}
			recipePlan.Overflow = list.ToArray();
			return recipePlan;
		}

		private RecipePlan NewPlan(int target, IRecipePolicy policy, HashSet<int> forced)
		{
			RecipePlan recipePlan = new RecipePlan
			{
				Target = target
			};
			Expand(target, policy, forced, recipePlan);
			recipePlan.Target = target;
			return recipePlan;
		}

		private void Expand(int target, IRecipePolicy policy, HashSet<int> forced, RecipePlan plan)
		{
			Choose(target, policy, out var _, out var per);
			plan.OutPer = Math.Max(1, (per <= 0) ? 1 : per);
			HashSet<int> stack = new HashSet<int>();
			Demand(target, plan.OutPer, policy, forced, stack, plan, 0);
			HashSet<int> hashSet = new HashSet<int>();
			foreach (int key in plan.External.Keys)
			{
				hashSet.Add(key);
			}
			foreach (int key2 in plan.Byprod.Keys)
			{
				hashSet.Add(key2);
			}
			foreach (int item in hashSet)
			{
				plan.External.TryGetValue(item, out var value);
				plan.Byprod.TryGetValue(item, out var value2);
				int num = value - value2;
				if (num > 0)
				{
					plan.External[item] = num;
					plan.Byprod.Remove(item);
				}
				else if (num < 0)
				{
					plan.Byprod[item] = -num;
					plan.External.Remove(item);
				}
				else
				{
					plan.External.Remove(item);
					plan.Byprod.Remove(item);
				}
			}
			plan.External.Remove(target);
			plan.Byprod.Remove(target);
		}

		private void Demand(int item, int amount, IRecipePolicy policy, HashSet<int> forced, HashSet<int> stack, RecipePlan plan, int depth)
		{
			if (item <= 0 || amount <= 0)
			{
				return;
			}
			if (depth > DepthLimit)
			{
				AddTo(plan.External, item, amount);
				return;
			}
			bool num = !forced.Contains(item) && (policy == null || !policy.IsRaw(item));
			RecipeProto val = null;
			int outIdx = -1;
			int per = 1;
			if (num)
			{
				val = Choose(item, policy, out outIdx, out per);
			}
			if (val == null || stack.Contains(item))
			{
				AddTo(plan.External, item, amount);
				return;
			}
			per = Math.Max(1, per);
			int num2 = (amount + per - 1) / per;
			plan.Crafts.TryGetValue(((Proto)val).ID, out var value);
			plan.Crafts[((Proto)val).ID] = value + num2;
			plan.Crafted.Add(item);
			plan.Ticks += Math.Max(1, val.TimeSpend) * num2;
			stack.Add(item);
			for (int i = 0; i < val.Items.Length; i++)
			{
				int num3 = ((i < val.ItemCounts.Length) ? val.ItemCounts[i] : 0) * num2;
				if (num3 > 0)
				{
					Demand(val.Items[i], num3, policy, forced, stack, plan, depth + 1);
				}
			}
			stack.Remove(item);
			for (int j = 0; j < val.Results.Length; j++)
			{
				if (j != outIdx)
				{
					int num4 = Math.Max(0, (j < val.ResultCounts.Length) ? val.ResultCounts[j] : 0) * num2;
					if (num4 > 0)
					{
						AddTo(plan.Byprod, val.Results[j], num4);
					}
				}
			}
			AddTo(plan.Consumed, item, amount);
			AddTo(plan.Produced, item, num2 * per);
		}

		private static void AddTo(Dictionary<int, int> dict, int key, int value)
		{
			if (key > 0 && value > 0)
			{
				dict.TryGetValue(key, out var value2);
				dict[key] = value2 + value;
			}
		}
	}
}
namespace DSPEasy.Framework.Items
{
	public static class ItemStack
	{
		public static int SplitInc(ref int n, ref int m, int p)
		{
			if (n == 0)
			{
				return 0;
			}
			int num = m / n;
			int num2 = m - num * n;
			n -= p;
			num2 -= n;
			int num3 = ((num2 > 0) ? (num * p + num2) : (num * p));
			m -= num3;
			return num3;
		}

		public static void TakeFromHand(Player player, int count)
		{
			if (player != null && count > 0 && player.inhandItemCount > 0)
			{
				int n = player.inhandItemCount;
				int m = player.inhandItemInc;
				int num = SplitInc(ref n, ref m, count);
				player.AddHandItemCount_Unsafe(-count);
				player.SetHandItemInc_Unsafe(player.inhandItemInc - num);
				if (player.inhandItemCount <= 0)
				{
					player.SetHandItemId_Unsafe(0);
					player.SetHandItemCount_Unsafe(0);
					player.SetHandItemInc_Unsafe(0);
				}
			}
		}
	}
}
namespace DSPEasy.Framework.Diagnostics
{
	public static class ModProfiler
	{
		private const string HarmonyId = "DSPEasy.Framework.ModProfiler";

		private static readonly List<ProfilerNode> Modules;

		private static readonly Dictionary<string, ProfilerNode> ModuleIndex;

		private static readonly bool useGameCounter;

		private static readonly long frequency;

		private static bool installed;

		private static int lastFrame;

		public static bool Installed => installed;

		public static bool Active => PerformanceMonitor.CpuProfilerOn;

		static ModProfiler()
		{
			Modules = new List<ProfilerNode>();
			ModuleIndex = new Dictionary<string, ProfilerNode>(StringComparer.Ordinal);
			try
			{
				long num = PerformanceCounter.Frequency;
				if (num > 0)
				{
					frequency = num;
					useGameCounter = true;
				}
			}
			catch (Exception)
			{
			}
			if (frequency <= 0)
			{
				frequency = Stopwatch.Frequency;
				useGameCounter = false;
			}
		}

		internal static long NowTicks()
		{
			if (!useGameCounter)
			{
				return Stopwatch.GetTimestamp();
			}
			return PerformanceCounter.Counter;
		}

		public static ProfilerNode RegisterModule(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				throw new ArgumentException("模组统计名不能为空", "name");
			}
			if (ModuleIndex.TryGetValue(name, out var value))
			{
				return value;
			}
			ProfilerNode profilerNode = new ProfilerNode(name, 0, null);
			Modules.Add(profilerNode);
			ModuleIndex[name] = profilerNode;
			return profilerNode;
		}

		public static bool Install(Action<string> info = null, Action<string> warn = null)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if (installed)
			{
				return true;
			}
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(UIPerformancePanel), "RefreshCpuStatTexts", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					warn?.Invoke("[EasyFramework] 性能面板统计:找不到 UIPerformancePanel.RefreshCpuStatTexts,已跳过");
					return false;
				}
				Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
				if (patchInfo != null && patchInfo.Postfixes != null)
				{
					for (int i = 0; i < patchInfo.Postfixes.Count; i++)
					{
						if (patchInfo.Postfixes[i].owner == "DSPEasy.Framework.ModProfiler")
						{
							installed = true;
							info?.Invoke("[EasyFramework] 性能面板统计补丁已存在(DSPEasy.Framework.ModProfiler)");
							return true;
						}
					}
				}
				new Harmony("DSPEasy.Framework.ModProfiler").PatchAll(typeof(ModProfilerPatches));
				installed = true;
				info?.Invoke("[EasyFramework] 性能面板统计补丁已安装(DSPEasy.Framework.ModProfiler)");
				return true;
			}
			catch (Exception ex)
			{
				warn?.Invoke("[EasyFramework] 性能面板统计补丁安装失败:" + ex);
				return false;
			}
		}

		internal static void OnRefresh(UIPerformancePanel panel)
		{
			if (!installed)
			{
				return;
			}
			if (!Active || PerformanceMonitor.aveFrame <= -7)
			{
				ResetAll();
				return;
			}
			int frameCount = Time.frameCount;
			int num = frameCount - lastFrame;
			if (num <= 0)
			{
				return;
			}
			lastFrame = frameCount;
			if (frequency > 0)
			{
				double num2 = (double)num / 30.0;
				if (num2 > 1.0)
				{
					num2 = 1.0;
				}
				for (int i = 0; i < Modules.Count; i++)
				{
					Modules[i].ApplyFrame(num2, num, frequency);
				}
				AppendToPanel(panel);
			}
		}

		internal static void ResetAll()
		{
			for (int i = 0; i < Modules.Count; i++)
			{
				Modules[i].Reset();
			}
			lastFrame = Time.frameCount;
		}

		private static void AppendToPanel(UIPerformancePanel panel)
		{
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)panel == (Object)null)
			{
				return;
			}
			Text cpuLabelText = panel.cpuLabelText;
			Text cpuValueText = panel.cpuValueText1;
			Text cpuValueText2 = panel.cpuValueText2;
			RectTransform cpuContentTrans = panel.cpuContentTrans;
			if ((Object)(object)cpuLabelText == (Object)null || (Object)(object)cpuValueText == (Object)null || (Object)(object)cpuValueText2 == (Object)null || (Object)(object)cpuContentTrans == (Object)null)
			{
				return;
			}
			double total = (PerformanceMonitor.showCompleteEngineCost ? PerformanceMonitor.totalTimeCostsShowingComplete : PerformanceMonitor.totalTimeCostsShowing);
			StringBuilder stringBuilder = new StringBuilder(512);
			StringBuilder stringBuilder2 = new StringBuilder(256);
			StringBuilder stringBuilder3 = new StringBuilder(256);
			bool flag = false;
			for (int i = 0; i < Modules.Count; i++)
			{
				ProfilerNode profilerNode = Modules[i];
				if (profilerNode.IsVisible)
				{
					flag = true;
					stringBuilder.AppendLine();
					stringBuilder2.AppendLine();
					stringBuilder3.AppendLine();
					AppendRow(profilerNode, stringBuilder, stringBuilder2, stringBuilder3, total);
				}
			}
			if (flag)
			{
				cpuLabelText.text += stringBuilder;
				cpuValueText.text += stringBuilder2;
				cpuValueText2.text += stringBuilder3;
				cpuContentTrans.sizeDelta = new Vector2(cpuContentTrans.sizeDelta.x, cpuLabelText.preferredHeight - 10f);
			}
		}

		private static void AppendRow(ProfilerNode node, StringBuilder b0, StringBuilder b1, StringBuilder b2, double total)
		{
			string value = Localization.Translate(node.Name);
			if (node.Level == 1)
			{
				b0.Append("  · ").Append(value).AppendLine();
			}
			else if (node.Level >= 2)
			{
				b0.Append("    - ").Append(value).AppendLine();
			}
			else
			{
				b0.AppendLine(value);
			}
			double num = node.DisplaySeconds();
			if (num >= 2.5E-07)
			{
				b1.AppendFormat("{0:0.000} ms\r\n", num * 1000.0);
			}
			else
			{
				b1.AppendLine("-");
			}
			if (total < 1E-08)
			{
				b2.AppendLine();
			}
			else
			{
				b2.AppendFormat("{0:0.00} %\r\n", num / total * 100.0);
			}
			IReadOnlyList<ProfilerNode> children = node.Children;
			for (int i = 0; i < children.Count; i++)
			{
				if (children[i].IsVisible)
				{
					AppendRow(children[i], b0, b1, b2, total);
				}
			}
		}
	}
	[HarmonyPatch(typeof(UIPerformancePanel), "RefreshCpuStatTexts")]
	internal static class ModProfilerPatches
	{
		private static void Postfix(UIPerformancePanel __instance)
		{
			ModProfiler.OnRefresh(__instance);
		}
	}
	public sealed class ProfilerNode
	{
		private readonly Dictionary<string, ProfilerNode> childIndex = new Dictionary<string, ProfilerNode>(StringComparer.Ordinal);

		private readonly List<ProfilerNode> childList = new List<ProfilerNode>();

		internal long PendingTicks;

		private bool hasSample;

		public string Name { get; }

		public int Level { get; }

		public ProfilerNode Parent { get; }

		public IReadOnlyList<ProfilerNode> Children => childList;

		public bool HasSelfTiming { get; private set; }

		public double ShowingSeconds { get; private set; }

		internal bool IsVisible
		{
			get
			{
				if (HasSelfTiming)
				{
					return true;
				}
				for (int i = 0; i < childList.Count; i++)
				{
					if (childList[i].IsVisible)
					{
						return true;
					}
				}
				return false;
			}
		}

		internal ProfilerNode(string name, int level, ProfilerNode parent)
		{
			Name = name;
			Level = level;
			Parent = parent;
		}

		public ProfilerNode GetOrAddChild(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				throw new ArgumentException("统计节点名不能为空", "name");
			}
			if (childIndex.TryGetValue(name, out var value))
			{
				return value;
			}
			int num = Level + 1;
			if (num > 2)
			{
				num = 2;
			}
			ProfilerNode profilerNode = new ProfilerNode(name, num, this);
			childList.Add(profilerNode);
			childIndex[name] = profilerNode;
			return profilerNode;
		}

		public TimingScope Measure()
		{
			if (!ModProfiler.Active)
			{
				return default(TimingScope);
			}
			return new TimingScope(this, ModProfiler.NowTicks());
		}

		internal void AddTicks(long ticks)
		{
			HasSelfTiming = true;
			if (ticks > 0)
			{
				PendingTicks += ticks;
			}
		}

		internal void ApplyFrame(double alpha, int frames, long frequency)
		{
			if (HasSelfTiming)
			{
				double num = (double)PendingTicks / (double)frames / (double)frequency;
				if (!hasSample)
				{
					ShowingSeconds = num;
					hasSample = true;
				}
				else
				{
					ShowingSeconds += (num - ShowingSeconds) * alpha;
				}
				PendingTicks = 0L;
			}
			for (int i = 0; i < childList.Count; i++)
			{
				childList[i].ApplyFrame(alpha, frames, frequency);
			}
		}

		internal void Reset()
		{
			PendingTicks = 0L;
			ShowingSeconds = 0.0;
			HasSelfTiming = false;
			hasSample = false;
			for (int i = 0; i < childList.Count; i++)
			{
				childList[i].Reset();
			}
		}

		internal double DisplaySeconds()
		{
			if (HasSelfTiming)
			{
				return ShowingSeconds;
			}
			double num = 0.0;
			for (int i = 0; i < childList.Count; i++)
			{
				ProfilerNode profilerNode = childList[i];
				if (profilerNode.IsVisible)
				{
					num += profilerNode.DisplaySeconds();
				}
			}
			return num;
		}
	}
	public readonly struct TimingScope : IDisposable
	{
		private readonly ProfilerNode node;

		private readonly long startTicks;

		internal TimingScope(ProfilerNode node, long startTicks)
		{
			this.node = node;
			this.startTicks = startTicks;
		}

		public void Dispose()
		{
			if (node != null)
			{
				node.AddTicks(ModProfiler.NowTicks() - startTicks);
			}
		}
	}
}
namespace DSPEasy.Framework.Blueprint
{
	public interface IBlueprintProvider
	{
		int ProtoId { get; }

		int Version { get; }

		void Write(PlanetFactory factory, int entityId, BinaryWriter writer);

		void Read(PlanetFactory factory, int entityId, BinaryReader reader, int version);
	}
	public static class BlueprintChannel
	{
		public const string ContentPrefix = "DSPBP1:";

		private const uint PayloadMagic = 827343428u;

		private static readonly Dictionary<int, IBlueprintProvider> Providers = new Dictionary<int, IBlueprintProvider>();

		public static Action<string> LogWarn = delegate
		{
		};

		public static void Register(IBlueprintProvider provider)
		{
			if (provider == null)
			{
				throw new ArgumentNullException("provider");
			}
			if (Providers.ContainsKey(provider.ProtoId))
			{
				throw new ArgumentException("蓝图读写器重复注册:" + provider.ProtoId);
			}
			Providers.Add(provider.ProtoId, provider);
		}

		public static IBlueprintProvider Find(int protoId)
		{
			if (!Providers.TryGetValue(protoId, out var value))
			{
				return null;
			}
			return value;
		}

		public static string Capture(PlanetFactory factory, int entityId)
		{
			if (factory == null || factory.entityPool == null)
			{
				return null;
			}
			if (entityId <= 0 || entityId >= factory.entityPool.Length)
			{
				return null;
			}
			int protoId = factory.entityPool[entityId].protoId;
			IBlueprintProvider blueprintProvider = Find(protoId);
			if (blueprintProvider == null)
			{
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true))
			{
				binaryWriter.Write(827343428u);
				binaryWriter.Write(protoId);
				binaryWriter.Write(blueprintProvider.Version);
				blueprintProvider.Write(factory, entityId, binaryWriter);
			}
			return "DSPBP1:" + Convert.ToBase64String(memoryStream.ToArray());
		}

		public static bool Apply(PlanetFactory factory, int entityId, string content)
		{
			if (string.IsNullOrEmpty(content) || !content.StartsWith("DSPBP1:", StringComparison.Ordinal))
			{
				return false;
			}
			if (factory == null || factory.entityPool == null)
			{
				return false;
			}
			if (entityId <= 0 || entityId >= factory.entityPool.Length)
			{
				return false;
			}
			int protoId = factory.entityPool[entityId].protoId;
			byte[] buffer;
			try
			{
				buffer = Convert.FromBase64String(content.Substring("DSPBP1:".Length));
			}
			catch (FormatException)
			{
				LogWarn("[Blueprint] content 不是合法的 Base64,已忽略:" + content);
				return false;
			}
			try
			{
				using MemoryStream input = new MemoryStream(buffer, writable: false);
				using BinaryReader binaryReader = new BinaryReader(input, Encoding.UTF8);
				if (binaryReader.ReadUInt32() != 827343428)
				{
					return false;
				}
				int num = binaryReader.ReadInt32();
				int num2 = binaryReader.ReadInt32();
				if (num != protoId)
				{
					return false;
				}
				IBlueprintProvider blueprintProvider = Find(num);
				if (blueprintProvider == null)
				{
					return false;
				}
				if (num2 > blueprintProvider.Version)
				{
					LogWarn("[Blueprint] 蓝图数据版本过新,已忽略:proto=" + num + " v" + num2 + "(支持到 v" + blueprintProvider.Version + ")");
					return false;
				}
				blueprintProvider.Read(factory, entityId, binaryReader, num2);
				return true;
			}
			catch (Exception ex2)
			{
				LogWarn("[Blueprint] 读取蓝图数据失败:proto=" + protoId + " -> " + ex2.Message);
				return false;
			}
		}
	}
	internal static class BlueprintPatches
	{
		[HarmonyPatch(typeof(BlueprintUtils), "GenerateBlueprintData")]
		private static class Patch_CaptureBlueprintContent
		{
			private static void Postfix(BlueprintData _blueprintData, PlanetData _planet, int[] _objIds, int _objCount)
			{
				if (_blueprintData == null || _planet == null || _objIds == null)
				{
					return;
				}
				PlanetFactory factory = _planet.factory;
				if (factory == null)
				{
					return;
				}
				int num = Math.Min(_objCount, Math.Min(_objIds.Length, _blueprintData.buildings.Length));
				for (int i = 0; i < num; i++)
				{
					int num2 = _objIds[i];
					if (num2 <= 0)
					{
						continue;
					}
					try
					{
						string text = BlueprintChannel.Capture(factory, num2);
						if (text != null)
						{
							_blueprintData.buildings[i].content = text;
						}
					}
					catch (Exception ex)
					{
						BlueprintChannel.LogWarn("[Blueprint] 抓取建筑设置失败:entity=" + num2 + " -> " + ex.Message);
					}
				}
			}
		}

		[HarmonyPatch(typeof(BuildingParameters), "ApplyPrebuildParametersToEntity")]
		private static class Patch_ApplyBlueprintContent
		{
			private static void Postfix(int entityId, string content, PlanetFactory factory)
			{
				BlueprintChannel.Apply(factory, entityId, content);
			}
		}
	}
}
namespace DSPEasy.Framework.Abnormal
{
	public static class AbnormalityGuard
	{
		public static Action<string> LogInfo = delegate
		{
		};

		public static Action<string> LogWarn = delegate
		{
		};

		internal static void Info(string msg)
		{
			try
			{
				LogInfo?.Invoke(msg);
			}
			catch
			{
			}
		}

		internal static void Warn(string msg)
		{
			try
			{
				LogWarn?.Invoke(msg);
			}
			catch
			{
			}
		}

		public static void Bind(Action<string> logInfo, Action<string> logWarn)
		{
			if (logInfo != null)
			{
				LogInfo = logInfo;
			}
			if (logWarn != null)
			{
				LogWarn = logWarn;
			}
		}
	}
	[HarmonyPatch(typeof(GameAbnormalityData_0925), "TriggerAbnormality")]
	internal static class Patch_BlockAbnormality
	{
		private static readonly HashSet<int> Logged = new HashSet<int>();

		private static bool Prefix(int protoId, long[] vals)
		{
			if (!Logged.Add(protoId))
			{
				return false;
			}
			string arg = "?";
			try
			{
				AbnormalityProto val = (((Object)(object)LDB.abnormalities != (Object)null) ? ((ProtoSet<AbnormalityProto>)(object)LDB.abnormalities).Select(protoId) : null);
				if (val != null)
				{
					arg = ((Proto)val).Name;
				}
			}
			catch
			{
			}
			string arg2 = "";
			try
			{
				if (vals != null)
				{
					StringBuilder stringBuilder = new StringBuilder();
					for (int i = 0; i < vals.Length; i++)
					{
						if (i > 0)
						{
							stringBuilder.Append(',');
						}
						stringBuilder.Append(vals[i]);
					}
					arg2 = stringBuilder.ToString();
				}
			}
			catch
			{
			}
			AbnormalityGuard.Info($"[Framework] 已拦截数据异常 protoId={protoId}({arg}) evidences=[{arg2}]");
			return false;
		}
	}
	[HarmonyPatch(typeof(GameAbnormalityData_0925), "Import")]
	internal static class Patch_ClearAbnormalityOnImport
	{
		private static void Postfix(GameAbnormalityData_0925 __instance)
		{
			try
			{
				if (__instance != null && __instance.runtimeDatas != null)
				{
					__instance.ClearAbnormality(0);
				}
			}
			catch (Exception ex)
			{
				AbnormalityGuard.Warn("[Framework] 清理存档异常记录失败:" + ex.Message);
			}
		}
	}
	[HarmonyPatch(typeof(GameAbnormalityData_0925), "Export")]
	internal static class Patch_ClearAbnormalityOnExport
	{
		private static void Prefix(GameAbnormalityData_0925 __instance)
		{
			try
			{
				if (__instance != null && __instance.runtimeDatas != null)
				{
					__instance.ClearAbnormality(0);
				}
			}
			catch (Exception ex)
			{
				AbnormalityGuard.Warn("[Framework] 写存档前清理异常记录失败:" + ex.Message);
			}
		}
	}
}