Decompiled source of WikiDumpMods v1.0.4

WikiDumpMods.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace WikiDumpMods;

internal sealed class Baseline
{
	public string GameVersion;

	public string Created;

	public string Path;

	public string Source;

	public bool Partial;

	public readonly HashSet<string> Covered = new HashSet<string>();

	public readonly HashSet<string> Keys = new HashSet<string>();

	public readonly Dictionary<string, Dictionary<string, string>> Fp = new Dictionary<string, Dictionary<string, string>>();

	private Func<Stream> _open;

	public bool Contains(string key)
	{
		return Keys.Contains(key);
	}

	public void Save(string path)
	{
		JObj jObj = new JObj();
		jObj["format"] = 2;
		jObj["gameVersion"] = GameVersion;
		jObj["created"] = Created;
		jObj["source"] = Source ?? "WikiDumpMods vanilla run";
		jObj["partial"] = false;
		JArr jArr = new JArr();
		foreach (string item in Keys.OrderBy<string, string>((string x) => x, StringComparer.Ordinal))
		{
			jArr.Add(item);
		}
		jObj["keys"] = jArr;
		Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
		using FileStream stream = File.Create(path);
		using GZipStream stream2 = new GZipStream(stream, CompressionMode.Compress);
		using StreamWriter streamWriter = new StreamWriter(stream2, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
		Json.Write(streamWriter, jObj, -1);
		streamWriter.Write('\n');
		foreach (KeyValuePair<string, Dictionary<string, string>> item2 in Fp.OrderBy<KeyValuePair<string, Dictionary<string, string>>, string>((KeyValuePair<string, Dictionary<string, string>> x) => x.Key, StringComparer.Ordinal))
		{
			JObj jObj2 = new JObj();
			foreach (KeyValuePair<string, string> item3 in item2.Value)
			{
				jObj2[item3.Key] = item3.Value;
			}
			Json.Write(streamWriter, new JObj
			{
				{ "k", item2.Key },
				{ "fp", jObj2 }
			}, -1);
			streamWriter.Write('\n');
		}
	}

	public static Baseline Load(string path)
	{
		if (!File.Exists(path))
		{
			return null;
		}
		return Open(() => File.OpenRead(path), path);
	}

	public static Baseline LoadEmbedded(Assembly asm, string resource)
	{
		if (asm == null || asm.GetManifestResourceInfo(resource) == null)
		{
			return null;
		}
		return Open(() => asm.GetManifestResourceStream(resource), "embedded:" + resource);
	}

	private static Baseline Open(Func<Stream> open, string label)
	{
		Baseline baseline = new Baseline();
		baseline.Path = label;
		baseline._open = open;
		Baseline baseline2 = baseline;
		using StreamReader streamReader = baseline2.Reader();
		if (!(JsonParse.Parse(streamReader.ReadLine()) is JObj jObj))
		{
			return null;
		}
		baseline2.GameVersion = jObj["gameVersion"] as string;
		baseline2.Created = jObj["created"] as string;
		baseline2.Source = jObj["source"] as string;
		baseline2.Partial = jObj["partial"] is bool && (bool)jObj["partial"];
		foreach (object item in (jObj["keys"] as JArr) ?? new JArr())
		{
			if (item is string)
			{
				baseline2.Keys.Add((string)item);
			}
		}
		foreach (object item2 in (jObj["covered"] as JArr) ?? new JArr())
		{
			if (item2 is string)
			{
				baseline2.Covered.Add((string)item2);
			}
		}
		return baseline2;
	}

	private StreamReader Reader()
	{
		Stream stream = _open();
		BufferedStream bufferedStream = new BufferedStream(stream);
		int num = bufferedStream.ReadByte();
		int num2 = bufferedStream.ReadByte();
		bufferedStream.Seek(0L, SeekOrigin.Begin);
		Stream stream2 = ((num != 31 || num2 != 139) ? ((Stream)bufferedStream) : ((Stream)new GZipStream(bufferedStream, CompressionMode.Decompress)));
		return new StreamReader(stream2, Encoding.UTF8);
	}

	public IEnumerable<KeyValuePair<string, Dictionary<string, string>>> EachFingerprint()
	{
		if (_open == null)
		{
			yield break;
		}
		using StreamReader r = Reader();
		r.ReadLine();
		while (true)
		{
			string text;
			string line = (text = r.ReadLine());
			if (text == null)
			{
				break;
			}
			if (line.Length == 0)
			{
				continue;
			}
			JObj o = JsonParse.Parse(line) as JObj;
			JObj fp = ((o != null) ? (o["fp"] as JObj) : null);
			if (fp == null)
			{
				continue;
			}
			Dictionary<string, string> d = new Dictionary<string, string>();
			foreach (KeyValuePair<string, object> item in fp)
			{
				d[item.Key] = item.Value as string;
			}
			yield return new KeyValuePair<string, Dictionary<string, string>>(o["k"] as string, d);
		}
	}
}
internal static class JsonParse
{
	public static object Parse(string s)
	{
		int i = 0;
		return Val(s, ref i);
	}

	private static void Ws(string s, ref int i)
	{
		while (i < s.Length && char.IsWhiteSpace(s[i]))
		{
			i++;
		}
	}

	private static object Val(string s, ref int i)
	{
		Ws(s, ref i);
		if (i >= s.Length)
		{
			throw new FormatException("unexpected end");
		}
		switch (s[i])
		{
		case '{':
		{
			JObj jObj = new JObj();
			i++;
			Ws(s, ref i);
			if (s[i] == '}')
			{
				i++;
				return jObj;
			}
			while (true)
			{
				Ws(s, ref i);
				string k = Str(s, ref i);
				Ws(s, ref i);
				if (s[i] != ':')
				{
					throw new FormatException("':' expected at " + i);
				}
				i++;
				jObj[k] = Val(s, ref i);
				Ws(s, ref i);
				if (s[i] != ',')
				{
					break;
				}
				i++;
			}
			if (s[i] == '}')
			{
				i++;
				return jObj;
			}
			throw new FormatException("',' or '}' expected at " + i);
		}
		case '[':
		{
			JArr jArr = new JArr();
			i++;
			Ws(s, ref i);
			if (s[i] == ']')
			{
				i++;
				return jArr;
			}
			while (true)
			{
				jArr.Add(Val(s, ref i));
				Ws(s, ref i);
				if (s[i] != ',')
				{
					break;
				}
				i++;
			}
			if (s[i] == ']')
			{
				i++;
				return jArr;
			}
			throw new FormatException("',' or ']' expected at " + i);
		}
		case '"':
			return Str(s, ref i);
		default:
		{
			if (string.CompareOrdinal(s, i, "true", 0, 4) == 0)
			{
				i += 4;
				return true;
			}
			if (string.CompareOrdinal(s, i, "false", 0, 5) == 0)
			{
				i += 5;
				return false;
			}
			if (string.CompareOrdinal(s, i, "null", 0, 4) == 0)
			{
				i += 4;
				return null;
			}
			int num = i;
			while (i < s.Length && "+-0123456789.eE".IndexOf(s[i]) >= 0)
			{
				i++;
			}
			return double.Parse(s.Substring(num, i - num), CultureInfo.InvariantCulture);
		}
		}
	}

	private static string Str(string s, ref int i)
	{
		if (s[i] != '"')
		{
			throw new FormatException("string expected at " + i);
		}
		i++;
		StringBuilder stringBuilder = new StringBuilder();
		while (s[i] != '"')
		{
			char c = s[i++];
			if (c != '\\')
			{
				stringBuilder.Append(c);
				continue;
			}
			char c2 = s[i++];
			switch (c2)
			{
			case 'n':
				stringBuilder.Append('\n');
				break;
			case 'r':
				stringBuilder.Append('\r');
				break;
			case 't':
				stringBuilder.Append('\t');
				break;
			case 'b':
				stringBuilder.Append('\b');
				break;
			case 'f':
				stringBuilder.Append('\f');
				break;
			case 'u':
				stringBuilder.Append((char)int.Parse(s.Substring(i, 4), NumberStyles.HexNumber));
				i += 4;
				break;
			default:
				stringBuilder.Append(c2);
				break;
			}
		}
		i++;
		return stringBuilder.ToString();
	}
}
internal sealed class DumpOptions
{
	public string OutDir;

	public string BaselinePath;

	public string[] Languages = new string[2] { "English", "Ukrainian" };

	public bool Icons = true;

	public string IconColor = "LinearToSRGB";

	public bool ScanVanillaLocations = true;

	public bool IncludeVanilla;

	public bool Tooltips = true;

	public bool ModStatics = true;

	public bool ForceBaseline;

	public string ConfigDir;

	public int RawDepth = 4;

	public string PluginVersion;

	public string SelfGuid;
}
internal sealed class Dumper
{
	private readonly DumpOptions _opt;

	private readonly List<ModEntry> _mods;

	private readonly Action<string> _log;

	private readonly Action<string> _hud;

	private Registry _r;

	private Origin _o;

	private Loc _loc;

	private DataIndex _ix;

	private Icons _icons;

	private readonly JObj _manifest = new JObj();

	private readonly JArr _errors = new JArr();

	private readonly Dictionary<string, JObj> _tooltips = new Dictionary<string, JObj>();

	private readonly Dictionary<string, JArr> _iconFiles = new Dictionary<string, JArr>();

	private readonly Dictionary<string, HashSet<string>> _modTokens = new Dictionary<string, HashSet<string>>();

	private readonly Dictionary<string, JObj> _modContent = new Dictionary<string, JObj>();

	private readonly Stopwatch _sw = new Stopwatch();

	public bool BaselineMode;

	public string Summary;

	private bool _restoreWarning;

	private bool _tooltipErr;

	private readonly JObj _locDiag = new JObj();

	private int _locLoaded;

	private int _locFailed;

	private static readonly string[] PerLevel = new string[4] { "m_armor|m_armorPerLevel", "m_maxDurability|m_durabilityPerLevel", "m_blockPower|m_blockPowerPerLevel", "m_deflectionForce|m_deflectionForcePerLevel" };

	public Dumper(DumpOptions opt, List<ModEntry> mods, Action<string> log, Action<string> hud)
	{
		_opt = opt;
		_mods = mods;
		_log = log ?? ((Action<string>)delegate
		{
		});
		_hud = hud ?? ((Action<string>)delegate
		{
		});
	}

	private string P(params string[] parts)
	{
		return Path.Combine(_opt.OutDir, Path.Combine(parts));
	}

	private void Step(string name, Action a)
	{
		long elapsedMilliseconds = _sw.ElapsedMilliseconds;
		try
		{
			a();
		}
		catch (Exception ex)
		{
			Exception ex2 = ((!(ex is TargetInvocationException) || ex.InnerException == null) ? ex : ex.InnerException);
			_errors.Add(new JObj
			{
				{ "section", name },
				{
					"error",
					ex2.GetType().Name + ": " + ex2.Message
				},
				{ "stack", ex2.StackTrace }
			});
			_log("section " + name + " failed: " + ex2);
		}
		JObj jObj = _manifest.Obj("timingsMs");
		jObj[name] = ((!(jObj[name] is long)) ? 0 : ((long)jObj[name])) + (_sw.ElapsedMilliseconds - elapsedMilliseconds);
	}

	private bool InScope(string key)
	{
		return _opt.IncludeVanilla || _o.IsModKey(key);
	}

	private string ModOfKey(string key)
	{
		OriginInfo originInfo = _o.Get(key);
		return (!originInfo.IsMod) ? null : (originInfo.Mod ?? "unknown");
	}

	private JObj Content(string mod)
	{
		if (!_modContent.TryGetValue(mod, out var value))
		{
			value = (_modContent[mod] = new JObj());
		}
		return value;
	}

	private void Track(string key, string kind, string name, string token)
	{
		string text = ModOfKey(key);
		if (text == null)
		{
			return;
		}
		Content(text).Arr(kind).Add(name);
		foreach (string item in _loc.Tokens(token))
		{
			if (!_modTokens.TryGetValue(text, out var value))
			{
				value = (_modTokens[text] = new HashSet<string>());
			}
			value.Add(item);
		}
	}

	public IEnumerator Run()
	{
		_sw.Start();
		Directory.CreateDirectory(_opt.OutDir);
		CleanOutput();
		_hud("WikiDumpMods: збираю дані…");
		_manifest["plugin"] = _opt.PluginVersion;
		_manifest["gameVersion"] = GameVersion();
		_manifest["dumpedAtUtc"] = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss");
		_manifest["includeVanilla"] = _opt.IncludeVanilla;
		BaselineMode = _opt.ForceBaseline || _mods.All((ModEntry m) => m.Guid == _opt.SelfGuid || m.Guid == "com.jotunn.jotunn");
		JArr present = new JArr();
		foreach (ModEntry mod in _mods)
		{
			present.Add(mod.Guid + " " + mod.Version);
		}
		_manifest["plugins"] = present;
		_manifest["mode"] = ((!BaselineMode) ? "mods" : "vanilla-baseline");
		Step("registry", delegate
		{
			_r = Registry.Collect();
		});
		yield return null;
		if (_r == null)
		{
			Finish();
			yield break;
		}
		foreach (string problem in _r.Problems)
		{
			_errors.Add(new JObj
			{
				{ "section", "registry" },
				{ "error", problem }
			});
		}
		_o = new Origin(_mods);
		if (!BaselineMode)
		{
			Step("baseline.load", delegate
			{
				_o.Baseline = Baseline.Load(_opt.BaselinePath) ?? Baseline.LoadEmbedded(typeof(Dumper).Assembly, "WikiDumpMods.vanilla_baseline.jsonl.gz");
				if (_o.Baseline != null && _o.Baseline.GameVersion != GameVersion())
				{
					_errors.Add(new JObj
					{
						{ "section", "baseline" },
						{
							"warning",
							"baseline is for game " + _o.Baseline.GameVersion + ", running " + GameVersion() + ": things the update added may show as modded"
						}
					});
				}
			});
		}
		JObj jotunn = new JObj();
		JObj statics = new JObj();
		Step("origin", delegate
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			jotunn = _o.FromJotunn();
			statics = _o.FromStatics();
			_o.FromBundles();
			foreach (GameObject value2 in _r.Prefabs.Values)
			{
				_o.Inspect((Object)(object)value2);
			}
			foreach (object recipe in _r.Recipes)
			{
				_o.Inspect((Object)recipe);
			}
			foreach (object statusEffect in _r.StatusEffects)
			{
				_o.Inspect((Object)statusEffect);
			}
			foreach (GameObject value3 in _r.Prefabs.Values)
			{
				_o.Registered.Add("prefab:" + ((Object)value3).name);
			}
			_o.BaselineCovers = delegate(string key)
			{
				if (!key.StartsWith("prefab:"))
				{
					return true;
				}
				string text3 = key.Substring(7);
				if (_r.Items.ContainsKey(text3))
				{
					return true;
				}
				if (!_r.Networked.Contains(text3))
				{
					return false;
				}
				if (!_r.Prefabs.TryGetValue(text3, out var value))
				{
					return false;
				}
				foreach (string item in _o.Baseline.Covered)
				{
					if (Object.op_Implicit((Object)(object)Refl.Comp(value, item)))
					{
						return true;
					}
				}
				return false;
			};
			foreach (object recipe2 in _r.Recipes)
			{
				_o.Registered.Add(Origin.KeyOf(recipe2));
			}
			foreach (object statusEffect2 in _r.StatusEffects)
			{
				_o.Registered.Add(Origin.KeyOf(statusEffect2));
			}
			foreach (object location in _r.Locations)
			{
				string text = Refl.S(Refl.Get(location, "m_prefabName"));
				if (text != null)
				{
					_o.Registered.Add("loc:" + text);
				}
			}
			foreach (object @event in _r.Events)
			{
				string text2 = Refl.S(Refl.Get(@event, "m_name"));
				if (text2 != null)
				{
					_o.Registered.Add("event:" + text2);
				}
			}
			foreach (object recipe3 in _r.Recipes)
			{
				_o.Inherit(Origin.KeyOf(recipe3), Origin.KeyOf(Refl.Get(recipe3, "m_item")), "result item", markModded: true);
			}
			foreach (GameObject value4 in _r.Items.Values)
			{
				string[] array = new string[4] { "m_consumeStatusEffect", "m_equipStatusEffect", "m_setStatusEffect", "m_attackStatusEffect" };
				foreach (string name in array)
				{
					_o.Inherit(Origin.KeyOf(Refl.Get(Registry.Shared(value4), name)), "prefab:" + ((Object)value4).name, "used by item", markModded: false);
				}
			}
		});
		yield return null;
		if (BaselineMode)
		{
			Step("baseline.write", WriteBaseline);
			Finish();
			yield break;
		}
		_loc = new Loc
		{
			Original = Loc.Current()
		};
		Step("localization", delegate
		{
			Languages();
		});
		yield return null;
		IEnumerator it = BuildIndex();
		while (it.MoveNext())
		{
			yield return it.Current;
		}
		Step("origin.refine", delegate
		{
			_o.Refine(_r, _ix.Refs);
		});
		yield return null;
		IEnumerator it2 = BuildIndex();
		while (it2.MoveNext())
		{
			yield return it2.Current;
		}
		JArr locations = new JArr();
		JArr rooms = new JArr();
		int n = 0;
		foreach (object zl in _r.Locations)
		{
			Step("locations", delegate
			{
				JObj jObj = Location(zl, room: false);
				if (jObj != null)
				{
					locations.Add(jObj);
				}
			});
			int num;
			n = (num = n + 1);
			if (num % 10 == 0)
			{
				yield return null;
			}
		}
		foreach (object rd in _r.Rooms)
		{
			Step("rooms", delegate
			{
				JObj jObj = Location(rd, room: true);
				if (jObj != null)
				{
					rooms.Add(jObj);
				}
			});
			int num;
			n = (num = n + 1);
			if (num % 10 == 0)
			{
				yield return null;
			}
		}
		if (_opt.Icons)
		{
			_icons = new Icons(_opt.IconColor);
			Step("icons", ExportIcons);
			yield return null;
		}
		_hud("WikiDumpMods: записую файли…");
		Step("items", WriteItems);
		yield return null;
		Step("pieces", WritePieces);
		yield return null;
		Step("creatures", WriteCreatures);
		yield return null;
		Step("status_effects", WriteStatusEffects);
		yield return null;
		Step("recipes", WriteRecipes);
		yield return null;
		Step("world", delegate
		{
			WriteWorld(locations, rooms);
		});
		yield return null;
		Step("vanilla_links", WriteVanillaLinks);
		yield return null;
		Step("vanilla_changes", WriteVanillaChanges);
		yield return null;
		Step("references", WriteReferences);
		yield return null;
		Step("raw_prefabs", WriteRaw);
		yield return null;
		Step("localization.files", WriteLocalization);
		yield return null;
		Step("origin.file", delegate
		{
			WriteOrigin(jotunn, statics);
		});
		yield return null;
		Step("mods", WriteMods);
		yield return null;
		if (_icons != null)
		{
			_icons.Dispose();
		}
		Finish();
	}

	private IEnumerator BuildIndex()
	{
		_ix = new DataIndex(_r, _o, _loc);
		Step("index.recipes", _ix.BuildRecipes);
		yield return null;
		Step("index.prefabs", _ix.BuildPrefabs);
		yield return null;
		Step("index.spawns", _ix.BuildSpawns);
		yield return null;
		int n = 0;
		foreach (GameObject go in _r.Prefabs.Values.ToList())
		{
			Step("index.references", delegate
			{
				_ix.ScanReferences(go);
			});
			int num;
			n = (num = n + 1);
			if (num % 60 == 0)
			{
				yield return null;
			}
		}
		foreach (object so in _r.Recipes.Concat(_r.StatusEffects))
		{
			Step("index.references", delegate
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Expected O, but got Unknown
				_ix.ScanReferencesOf((Object)so);
			});
		}
		yield return null;
	}

	private void CleanOutput()
	{
		string[] array = new string[4] { "icons", "raw", "mods", "localization" };
		foreach (string text in array)
		{
			string path = P(text);
			try
			{
				if (Directory.Exists(path))
				{
					Directory.Delete(path, recursive: true);
				}
			}
			catch
			{
			}
		}
		string[] files = Directory.GetFiles(_opt.OutDir, "*.json");
		foreach (string path2 in files)
		{
			if (!string.Equals(Path.GetFullPath(path2), Path.GetFullPath(_opt.BaselinePath ?? ""), StringComparison.OrdinalIgnoreCase))
			{
				try
				{
					File.Delete(path2);
				}
				catch
				{
				}
			}
		}
	}

	private void Finish()
	{
		if (_locLoaded + _locFailed > 0)
		{
			_manifest["locationLoading"] = new JObj
			{
				{ "loaded", _locLoaded },
				{ "failed", _locFailed },
				{ "diagnostics", _locDiag }
			};
		}
		_manifest["errors"] = _errors;
		_manifest["totalMs"] = _sw.ElapsedMilliseconds;
		if (_icons != null)
		{
			_manifest["icons"] = new JObj
			{
				{ "saved", _icons.Saved },
				{ "reused", _icons.Reused },
				{ "failed", _icons.Failed },
				{ "lastError", _icons.LastError },
				{ "colorMode", _opt.IconColor }
			};
		}
		if (_o != null && _o.Baseline != null)
		{
			_manifest["baseline"] = new JObj
			{
				{
					"path",
					_o.Baseline.Path
				},
				{
					"gameVersion",
					_o.Baseline.GameVersion
				},
				{
					"created",
					_o.Baseline.Created
				}
			};
		}
		else if (!BaselineMode)
		{
			_manifest["baseline"] = "none (modded/vanilla split uses heuristics; see README)";
		}
		Json.WriteFile(P("manifest.json"), _manifest, pretty: true);
		Summary = ((!BaselineMode) ? ("WikiDumpMods: готово" + ((_errors.Count <= 0) ? "" : (" (помилок: " + _errors.Count + ")")) + ((!_restoreWarning) ? "" : ". Перезапусти гру: частина перекладів модів зникла")) : "WikiDumpMods: збережено ванільний еталон");
		_hud(Summary);
		_log(Summary + " in " + _sw.ElapsedMilliseconds + " ms -> " + _opt.OutDir);
	}

	private static string GameVersion()
	{
		object[][] array = new object[2][]
		{
			new object[0],
			new object[1] { false }
		};
		foreach (object[] args in array)
		{
			string text = Refl.CallStatic("Version", "GetVersionString", args) as string;
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
		}
		object obj = Refl.GetStatic("Version", "CurrentVersion");
		return (obj == null) ? "?" : obj.ToString();
	}

	private void Languages()
	{
		string text = _loc.Original ?? "English";
		List<string> list = new List<string>();
		list.Add(text);
		List<string> list2 = list;
		string[] languages = _opt.Languages;
		foreach (string text2 in languages)
		{
			if (!string.IsNullOrEmpty(text2) && !list2.Contains(text2.Trim()))
			{
				list2.Add(text2.Trim());
			}
		}
		List<string> tokens = AllTokens();
		_loc.Mod = new ModTexts(list2);
		try
		{
			string configDir = _opt.ConfigDir;
			_loc.Mod.Collect(_mods, configDir, _opt.OutDir);
			_manifest["translationSources"] = _loc.Mod.SourcesRead;
		}
		catch (Exception ex)
		{
			_errors.Add(new JObj
			{
				{ "section", "localization.files" },
				{ "error", ex.Message }
			});
		}
		bool flag = false;
		try
		{
			foreach (string item in list2)
			{
				if (item != text)
				{
					if (!Loc.Switch(item))
					{
						_errors.Add(new JObj
						{
							{ "section", "localization" },
							{
								"error",
								"language not available: " + item
							}
						});
						continue;
					}
					flag = true;
				}
				_loc.Capture(item);
				_loc.ResolveTokens(item, tokens);
				if (_opt.Tooltips)
				{
					Tooltips(item);
				}
			}
		}
		finally
		{
			if (flag)
			{
				Loc.Switch(text);
			}
		}
		if (flag && _loc.Resolved.TryGetValue(text, out var value))
		{
			int num = 0;
			JArr jArr = new JArr();
			foreach (KeyValuePair<string, string> item2 in value)
			{
				if (item2.Value != null)
				{
					num++;
					if (Loc.GameLocalize(item2.Key) == null && jArr.Count < 50)
					{
						jArr.Add(item2.Key);
					}
				}
			}
			_manifest["languageRestore"] = new JObj
			{
				{ "language", text },
				{ "tokensChecked", num },
				{ "lostAfterRestore", jArr }
			};
			if (jArr.Count > 0)
			{
				_restoreWarning = true;
			}
		}
		_manifest["languages"] = new JArr();
		foreach (string language in _loc.Languages)
		{
			((JArr)_manifest["languages"]).Add(language);
		}
	}

	private List<string> AllTokens()
	{
		HashSet<string> hs = new HashSet<string>();
		Action<object> action = delegate(object obj)
		{
			foreach (string item in _loc.Tokens(obj as string))
			{
				hs.Add(item);
			}
		};
		foreach (GameObject value in _r.Prefabs.Values)
		{
			action(DataIndex.DisplayToken(value));
			object o = Registry.Shared(value);
			action(Refl.Get(o, "m_name"));
			action(Refl.Get(o, "m_description"));
			action(Refl.Get(o, "m_setName"));
			Component o2 = Refl.Comp(value, "Piece");
			action(Refl.Get(o2, "m_name"));
			action(Refl.Get(o2, "m_description"));
			string[] array = new string[10] { "Character", "CraftingStation", "Smelter", "CookingStation", "Trader", "OfferingBowl", "Container", "Pickable", "Fermenter", "Incinerator" };
			foreach (string typeName in array)
			{
				Component o3 = Refl.Comp(value, typeName);
				action(Refl.Get(o3, "m_name"));
				action(Refl.Get(o3, "m_overrideName"));
			}
		}
		foreach (object statusEffect in _r.StatusEffects)
		{
			action(Refl.Get(statusEffect, "m_name"));
			action(Refl.Get(statusEffect, "m_tooltip"));
		}
		foreach (object @event in _r.Events)
		{
			action(Refl.Get(@event, "m_startMessage"));
			action(Refl.Get(@event, "m_endMessage"));
		}
		return hs.ToList();
	}

	private void Tooltips(string lang)
	{
		//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
		Type tID = Refl.T("ItemDrop+ItemData");
		MethodInfo methodInfo = ((!(tID == null)) ? (from m in tID.GetMethods(BindingFlags.Static | BindingFlags.Public)
			where m.Name == "GetTooltip" && m.GetParameters().Length >= 2 && m.GetParameters()[0].ParameterType == tID
			orderby m.GetParameters().Length
			select m).FirstOrDefault() : null);
		foreach (GameObject value in _r.Items.Values)
		{
			if (!InScope("prefab:" + ((Object)value).name))
			{
				continue;
			}
			object obj = Registry.ItemData(value);
			if (obj == null || methodInfo == null)
			{
				continue;
			}
			int num = Math.Max(1, Refl.I(Refl.Get(Registry.Shared(value), "m_maxQuality"), 1));
			JObj jObj = new JObj();
			for (int num2 = 1; num2 <= num; num2++)
			{
				try
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					object[] array = new object[parameters.Length];
					for (int num3 = 0; num3 < parameters.Length; num3++)
					{
						Type parameterType = parameters[num3].ParameterType;
						if (num3 == 0)
						{
							array[num3] = obj;
						}
						else if (parameterType == typeof(int) && parameters[num3].Name.IndexOf("quality", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							array[num3] = num2;
						}
						else if (parameterType == typeof(bool))
						{
							array[num3] = parameters[num3].Name.IndexOf("craft", StringComparison.OrdinalIgnoreCase) >= 0;
						}
						else if (parameterType == typeof(float))
						{
							array[num3] = 0f;
						}
						else if (parameterType == typeof(int))
						{
							array[num3] = ((!parameters[num3].IsOptional) ? ((object)(-1)) : parameters[num3].DefaultValue);
						}
						else
						{
							array[num3] = ((!parameters[num3].IsOptional) ? null : parameters[num3].DefaultValue);
						}
					}
					jObj[num2.ToString()] = methodInfo.Invoke(null, array) as string;
				}
				catch (Exception ex)
				{
					jObj[num2.ToString()] = null;
					if (!_tooltipErr)
					{
						_tooltipErr = true;
						_errors.Add(new JObj
						{
							{ "section", "tooltips" },
							{
								"error",
								(ex.InnerException ?? ex).Message
							}
						});
					}
				}
			}
			TipFor("item:" + ((Object)value).name)[lang] = jObj;
		}
		foreach (object statusEffect in _r.StatusEffects)
		{
			if (InScope(Origin.KeyOf(statusEffect)))
			{
				string text = null;
				try
				{
					text = Refl.Call(statusEffect, "GetTooltipString") as string;
				}
				catch
				{
				}
				if (text != null)
				{
					TipFor("se:" + ((Object)statusEffect).name)[lang] = text;
				}
			}
		}
	}

	private static string Localize(string s)
	{
		object obj = Refl.Singleton("Localization");
		return (obj != null) ? ((Refl.Call(obj, "Localize", s) as string) ?? s) : s;
	}

	private JObj LocalizedTips(JObj tips)
	{
		JObj jObj = new JObj();
		foreach (KeyValuePair<string, object> tip in tips)
		{
			if (tip.Value is string)
			{
				jObj[tip.Key] = _loc.Text((string)tip.Value, tip.Key) ?? tip.Value;
			}
			else
			{
				if (!(tip.Value is JObj jObj2))
				{
					continue;
				}
				JObj jObj3 = new JObj();
				foreach (KeyValuePair<string, object> item in jObj2)
				{
					jObj3[item.Key] = ((!(item.Value is string)) ? null : (_loc.Text((string)item.Value, tip.Key) ?? item.Value));
				}
				jObj[tip.Key] = jObj3;
			}
		}
		return jObj;
	}

	private JObj TipFor(string key)
	{
		if (!_tooltips.TryGetValue(key, out var value))
		{
			value = (_tooltips[key] = new JObj());
		}
		return value;
	}

	private Dictionary<string, Dictionary<string, string>> Fingerprints(bool onlyVanilla)
	{
		Dictionary<string, Dictionary<string, string>> fp = new Dictionary<string, Dictionary<string, string>>();
		Action<string, object> action = delegate(string k, object node)
		{
			if (node != null)
			{
				Dictionary<string, string> dictionary = new Dictionary<string, string>();
				Ser.Flatten(node, "", dictionary);
				fp[k] = dictionary;
			}
		};
		foreach (GameObject value in _r.Items.Values)
		{
			if (!onlyVanilla || !_o.IsModKey("prefab:" + ((Object)value).name))
			{
				action("item:" + ((Object)value).name, Ser.Node(Registry.Shared(value), 3));
			}
		}
		foreach (object recipe in _r.Recipes)
		{
			string text = Origin.KeyOf(recipe);
			if (!onlyVanilla || !_o.IsModKey(text))
			{
				action(text, Ser.Node(recipe, 2));
			}
		}
		foreach (object statusEffect in _r.StatusEffects)
		{
			string text2 = Origin.KeyOf(statusEffect);
			if (!onlyVanilla || !_o.IsModKey(text2))
			{
				action(text2, Ser.Node(statusEffect, 2));
			}
		}
		foreach (GameObject value2 in _r.Prefabs.Values)
		{
			if (onlyVanilla && _o.IsModKey("prefab:" + ((Object)value2).name))
			{
				continue;
			}
			string[] array = new string[24]
			{
				"Piece", "Character", "CharacterDrop", "Container", "Pickable", "DropOnDestroyed", "MineRock5", "MineRock", "TreeBase", "TreeLog",
				"Trader", "Smelter", "CookingStation", "Fermenter", "Incinerator", "MonsterAI", "Tameable", "CraftingStation", "StationExtension", "WearNTear",
				"Plant", "Fish", "OfferingBowl", "SpawnArea"
			};
			foreach (string text3 in array)
			{
				Component val = Refl.Comp(value2, text3);
				if (Object.op_Implicit((Object)(object)val))
				{
					action(text3 + ":" + ((Object)value2).name, Ser.Node(val, (!(text3 == "Character") && !(text3 == "MonsterAI")) ? 3 : 2));
				}
			}
		}
		return fp;
	}

	private void WriteBaseline()
	{
		Baseline baseline = new Baseline();
		baseline.GameVersion = GameVersion();
		baseline.Created = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss");
		baseline.Source = "WikiDumpMods " + _opt.PluginVersion + " vanilla run";
		Baseline baseline2 = baseline;
		foreach (GameObject value in _r.Prefabs.Values)
		{
			baseline2.Keys.Add("prefab:" + ((Object)value).name);
		}
		foreach (object recipe in _r.Recipes)
		{
			baseline2.Keys.Add(Origin.KeyOf(recipe));
		}
		foreach (object statusEffect in _r.StatusEffects)
		{
			baseline2.Keys.Add(Origin.KeyOf(statusEffect));
		}
		foreach (object location in _r.Locations)
		{
			string text = Refl.S(Refl.Get(location, "m_prefabName"));
			if (text != null)
			{
				baseline2.Keys.Add("loc:" + text);
			}
		}
		foreach (object @event in _r.Events)
		{
			string text2 = Refl.S(Refl.Get(@event, "m_name"));
			if (text2 != null)
			{
				baseline2.Keys.Add("event:" + text2);
			}
		}
		foreach (KeyValuePair<string, Dictionary<string, string>> item in Fingerprints(onlyVanilla: false))
		{
			baseline2.Fp[item.Key] = item.Value;
		}
		baseline2.Save(_opt.BaselinePath);
		_manifest["baselineWritten"] = new JObj
		{
			{ "path", _opt.BaselinePath },
			{
				"keys",
				baseline2.Keys.Count
			},
			{
				"fingerprints",
				baseline2.Fp.Count
			}
		};
	}

	private void WriteVanillaChanges()
	{
		JObj jObj = new JObj();
		if (_o.Baseline == null)
		{
			jObj["note"] = "No vanilla baseline: run once with only WikiDumpMods installed to enable this file (see README).";
			Json.WriteFile(P("vanilla_changes.json"), jObj, pretty: true);
			return;
		}
		jObj["baseline"] = new JObj
		{
			{
				"path",
				_o.Baseline.Path
			},
			{
				"source",
				_o.Baseline.Source
			},
			{
				"gameVersion",
				_o.Baseline.GameVersion
			},
			{
				"partial",
				_o.Baseline.Partial
			}
		};
		if (_o.Baseline.GameVersion != GameVersion())
		{
			jObj["warning"] = "baseline game version " + _o.Baseline.GameVersion + " differs from " + GameVersion() + ": some changes may come from the game update, not from mods";
		}
		Dictionary<string, Dictionary<string, string>> dictionary = Fingerprints(onlyVanilla: true);
		JArr jArr = new JArr();
		foreach (KeyValuePair<string, Dictionary<string, string>> item in _o.Baseline.EachFingerprint())
		{
			if (item.Key == null || !dictionary.TryGetValue(item.Key, out var value))
			{
				continue;
			}
			JArr jArr2 = Diff(item.Value, value);
			if (jArr2.Count != 0)
			{
				string key = item.Key.Substring(item.Key.IndexOf(':') + 1);
				_r.Prefabs.TryGetValue(key, out var value2);
				JObj jObj2 = new JObj();
				jObj2.Add("key", item.Key);
				JObj jObj3 = jObj2;
				if (Object.op_Implicit((Object)(object)value2))
				{
					jObj3.Opt("names", _loc.Names(DataIndex.DisplayToken(value2)));
				}
				jObj3["changes"] = jArr2;
				jArr.Add(jObj3);
			}
		}
		jObj["note"] = "Values that differ from the unmodded game. Which mod made a change cannot be read from the data; see mods.json -> harmonyPatches for candidates. Fields one side does not record are not compared.";
		jObj["changed"] = jArr;
		Json.WriteFile(P("vanilla_changes.json"), jObj, pretty: false);
		_manifest.Obj("counts")["vanillaChanged"] = jArr.Count;
	}

	private static JArr Diff(Dictionary<string, string> old, Dictionary<string, string> cur)
	{
		JArr jArr = new JArr();
		foreach (KeyValuePair<string, string> item in cur)
		{
			if (old.TryGetValue(item.Key, out var value))
			{
				if (item.Key.EndsWith(".#"))
				{
					if (value != item.Value)
					{
						jArr.Add(new JObj
						{
							{ "path", item.Key },
							{ "vanilla", value },
							{ "now", item.Value }
						});
					}
					continue;
				}
				string text = NormVal(value);
				string text2 = NormVal(item.Value);
				if (text != null && text2 != null && !Same(text, text2))
				{
					jArr.Add(new JObj
					{
						{ "path", item.Key },
						{
							"vanilla",
							Show(text)
						},
						{
							"now",
							Show(text2)
						}
					});
				}
			}
			else if (BeyondList(item.Key, old))
			{
				string text3 = NormVal(item.Value);
				if (text3 != null)
				{
					jArr.Add(new JObj
					{
						{ "path", item.Key },
						{ "vanilla", null },
						{
							"now",
							Show(text3)
						}
					});
				}
			}
		}
		foreach (KeyValuePair<string, string> item2 in old)
		{
			if (!cur.ContainsKey(item2.Key) && BeyondList(item2.Key, cur))
			{
				string text4 = NormVal(item2.Value);
				if (text4 != null)
				{
					jArr.Add(new JObj
					{
						{ "path", item2.Key },
						{
							"vanilla",
							Show(text4)
						},
						{ "now", null }
					});
				}
			}
		}
		return jArr;
	}

	private static bool BeyondList(string path, Dictionary<string, string> other)
	{
		for (int num = path.LastIndexOf('['); num > 0; num = path.LastIndexOf('[', num - 1))
		{
			int num2 = path.IndexOf(']', num);
			int result2;
			if (num2 > num && int.TryParse(path.Substring(num + 1, num2 - num - 1), out var result) && other.TryGetValue(path.Substring(0, num) + ".#", out var value))
			{
				return int.TryParse(value, out result2) && result >= result2;
			}
		}
		return false;
	}

	private static string NormVal(string v)
	{
		if (v == null || v == "null")
		{
			return "null";
		}
		object obj;
		try
		{
			obj = JsonParse.Parse(v);
		}
		catch
		{
			return "s:" + v;
		}
		if (obj is JObj jObj)
		{
			string[] array = new string[2] { "$go", "$sprite" };
			foreach (string k in array)
			{
				if (jObj[k] is string)
				{
					return "s:" + jObj[k];
				}
			}
			if (jObj.Has("$comp"))
			{
				return "s:" + jObj["go"];
			}
			if (jObj.Has("$so") || jObj.Has("$asset"))
			{
				return "s:" + jObj["name"];
			}
			return null;
		}
		if (obj is double)
		{
			return "n:" + ((double)obj).ToString("R", CultureInfo.InvariantCulture);
		}
		if (obj is bool)
		{
			return "b:" + ((!(bool)obj) ? "false" : "true");
		}
		if (!(obj is string text))
		{
			return "null";
		}
		if (text.StartsWith("$depth") || text.StartsWith("$cycle") || text == "<cycle>" || text.StartsWith("$error"))
		{
			return null;
		}
		return "s:" + text;
	}

	private static bool Same(string a, string b)
	{
		if (a == b)
		{
			return true;
		}
		if (a.StartsWith("n:") && b.StartsWith("n:"))
		{
			double num = double.Parse(a.Substring(2), CultureInfo.InvariantCulture);
			double num2 = double.Parse(b.Substring(2), CultureInfo.InvariantCulture);
			return Math.Abs(num - num2) <= 0.0001 * Math.Max(1.0, Math.Abs(num));
		}
		return false;
	}

	private static object Show(string n)
	{
		if (n == "null")
		{
			return null;
		}
		if (n.StartsWith("n:"))
		{
			return double.Parse(n.Substring(2), CultureInfo.InvariantCulture);
		}
		if (n.StartsWith("b:"))
		{
			return n == "b:true";
		}
		return n.Substring(2);
	}

	private JObj Location(object holder, bool room)
	{
		string text = Refl.S(Refl.Get(holder, "m_prefabName"));
		List<object> list = new List<object>();
		try
		{
			GameObject val = null;
			if (text == null || room)
			{
				val = Registry.LoadSoft(holder, list, _locDiag);
				text = text ?? ((!Object.op_Implicit((Object)(object)val)) ? null : ((Object)val).name);
			}
			if (text == null)
			{
				return null;
			}
			string text2 = ((!room) ? "loc:" : "room:") + text;
			bool flag = _o.IsModKey(text2);
			if (!flag && !_opt.ScanVanillaLocations && !_opt.IncludeVanilla)
			{
				return null;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				val = Registry.LoadSoft(holder, list, _locDiag);
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				_locLoaded++;
			}
			else
			{
				_locFailed++;
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				_o.Inspect((Object)(object)val);
			}
			if (Object.op_Implicit((Object)(object)val) && _o.IsMod(val))
			{
				flag = true;
			}
			JObj jObj = new JObj();
			jObj.Add("location", text);
			JObj jObj2 = jObj;
			JArr source = ((!Object.op_Implicit((Object)(object)val)) ? new JArr() : _ix.ScanContainer(val, jObj2));
			List<JObj> list2 = (from JObj f in source
				where (f["item"] is string && _o.IsModKey("prefab:" + f["item"])) || (f["creature"] is string && _o.IsModKey("prefab:" + f["creature"]))
				select f).ToList();
			if (!flag && !_opt.IncludeVanilla && list2.Count == 0)
			{
				return null;
			}
			JObj jObj3 = new JObj();
			jObj3["name"] = text;
			if (flag)
			{
				jObj3["mod"] = ModOfKey(text2) ?? _o.ModOf(val) ?? "unknown";
			}
			if (Ser.Node(holder, 2) is JObj jObj4)
			{
				jObj4.Remove("m_prefab");
				jObj3["meta"] = jObj4;
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				Component val2 = Refl.Comp(val, "Location");
				if (Object.op_Implicit((Object)(object)val2))
				{
					jObj3["location"] = Ser.Node(val2, 2);
				}
			}
			JArr jArr = new JArr();
			foreach (JObj item in (!flag && !_opt.IncludeVanilla) ? list2 : source.Cast<JObj>())
			{
				jArr.Add(item);
			}
			jObj3["contents"] = jArr;
			if (flag)
			{
				Content(ModOfKey(text2) ?? _o.ModOf(val) ?? "unknown").Arr((!room) ? "locations" : "dungeonRooms").Add(text);
			}
			return jObj3;
		}
		finally
		{
			foreach (object item2 in list)
			{
				try
				{
					Refl.Call(item2, "Release");
				}
				catch
				{
				}
			}
		}
	}

	private void Icon(string key, string mod, string kind, string name, object sprite, int variant)
	{
		if (sprite == null)
		{
			return;
		}
		string relPath = "icons/" + Icons.SafeName(mod ?? "vanilla") + "/" + kind + "/" + Icons.SafeName(name) + ((variant <= 0) ? "" : ("_" + variant)) + ".png";
		string text = _icons.Save(sprite, _opt.OutDir, relPath);
		if (text != null)
		{
			if (!_iconFiles.TryGetValue(key, out var value))
			{
				value = (_iconFiles[key] = new JArr());
			}
			value.Add(text);
		}
	}

	private void ExportIcons()
	{
		//IL_027a: Unknown result type (might be due to invalid IL or missing references)
		if (!_icons.Ready)
		{
			_errors.Add(new JObj
			{
				{ "section", "icons" },
				{ "error", "Unity texture API not found" }
			});
			return;
		}
		foreach (GameObject value2 in _r.Items.Values)
		{
			string key = "prefab:" + ((Object)value2).name;
			if (!InScope(key))
			{
				continue;
			}
			int num = 0;
			foreach (object item in Refl.Enum(Refl.Get(Registry.Shared(value2), "m_icons")))
			{
				Icon(key, ModOfKey(key), "items", ((Object)value2).name, item, num++);
			}
		}
		foreach (GameObject value3 in _r.Prefabs.Values)
		{
			string key2 = "prefab:" + ((Object)value3).name;
			if (InScope(key2))
			{
				Component val = Refl.Comp(value3, "Piece");
				if (Object.op_Implicit((Object)(object)val) && !_r.Items.ContainsKey(((Object)value3).name))
				{
					Icon(key2, ModOfKey(key2), "pieces", ((Object)value3).name, Refl.Get(val, "m_icon"), 0);
				}
				Component val2 = Refl.Comp(value3, "CraftingStation");
				if (Object.op_Implicit((Object)(object)val2) && !Object.op_Implicit((Object)(object)val))
				{
					Icon(key2, ModOfKey(key2), "stations", ((Object)value3).name, Refl.Get(val2, "m_icon"), 0);
				}
			}
		}
		foreach (object statusEffect in _r.StatusEffects)
		{
			string key3 = Origin.KeyOf(statusEffect);
			if (InScope(key3))
			{
				Icon(key3, ModOfKey(key3), "status", ((Object)statusEffect).name, Refl.Get(statusEffect, "m_icon"), 0);
			}
		}
		if (_r.Prefabs.TryGetValue("Player", out var value))
		{
			foreach (object item2 in Refl.Enum(Refl.Get(Refl.Comp(value, "Skills"), "m_skills")))
			{
				string text = Refl.S(Refl.Get(item2, "m_skill"));
				if (text != null && (_opt.IncludeVanilla || !IsVanillaSkill(text)))
				{
					Icon("skill:" + text, null, "skills", text, Refl.Get(item2, "m_icon"), 0);
				}
			}
		}
		foreach (ModEntry mod in _mods)
		{
			if (mod.Folder == null)
			{
				continue;
			}
			string text2 = Path.Combine(mod.Folder, "icon.png");
			if (File.Exists(text2))
			{
				string text3 = "icons/" + Icons.SafeName(mod.Guid) + "/mod_icon.png";
				try
				{
					Directory.CreateDirectory(Path.GetDirectoryName(P(text3)));
					File.Copy(text2, P(text3), overwrite: true);
					_iconFiles["mod:" + mod.Guid] = new JArr { text3 };
				}
				catch
				{
				}
			}
		}
	}

	private static bool IsVanillaSkill(string s)
	{
		Type type = Refl.T("Skills+SkillType");
		return type != null && type.IsEnum && Enum.GetNames(type).Contains(s);
	}

	private JArr IconsOf(string key)
	{
		JArr value;
		return (!_iconFiles.TryGetValue(key, out value)) ? null : value;
	}

	private JArr QualityStats(object shared)
	{
		JArr jArr = new JArr();
		int num = Math.Max(1, Refl.I(Refl.Get(shared, "m_maxQuality"), 1));
		object obj = Refl.Get(shared, "m_damages");
		object obj2 = Refl.Get(shared, "m_damagesPerLevel");
		for (int i = 1; i <= num; i++)
		{
			JObj jObj = new JObj();
			jObj.Add("quality", i);
			JObj jObj2 = jObj;
			if (obj != null)
			{
				JObj jObj3 = new JObj();
				FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!(fieldInfo.FieldType != typeof(float)))
					{
						float num2 = (float)fieldInfo.GetValue(obj) + ((obj2 != null) ? ((float)fieldInfo.GetValue(obj2)) : 0f) * (float)(i - 1);
						if ((double)Math.Abs(num2) > 1E-06)
						{
							jObj3[fieldInfo.Name.Substring(2)] = num2;
						}
					}
				}
				jObj2.Opt("damage", jObj3);
			}
			string[] perLevel = PerLevel;
			foreach (string text in perLevel)
			{
				string[] array = text.Split('|');
				object obj3 = Refl.Get(shared, array[0]);
				if (obj3 != null)
				{
					float num3 = Refl.F(obj3) + Refl.F(Refl.Get(shared, array[1])) * (float)(i - 1);
					if ((double)Math.Abs(num3) > 1E-06)
					{
						jObj2[array[0].Substring(2)] = num3;
					}
				}
			}
			jArr.Add(jObj2);
		}
		return jArr;
	}

	private JArr RecipesFor(string item, int maxQ)
	{
		JArr jArr = new JArr();
		if (!_ix.Sources.TryGetValue(item, out var value))
		{
			return jArr;
		}
		foreach (JObj item2 in value)
		{
			if ((string)item2["type"] != "craft")
			{
				continue;
			}
			JObj jObj2 = new JObj();
			foreach (KeyValuePair<string, object> item3 in item2)
			{
				jObj2[item3.Key] = item3.Value;
			}
			int num = Math.Max(1, Refl.I(item2["minStationLevel"], 1));
			JArr jArr2 = new JArr();
			for (int i = 1; i <= maxQ; i++)
			{
				JObj jObj3 = new JObj();
				jObj3.Add("quality", i);
				jObj3.Add("stationLevel", num + i - 1);
				JObj jObj4 = jObj3;
				JArr jArr3 = new JArr();
				foreach (JObj item4 in (JArr)item2["requirements"])
				{
					int num2 = ((i > 1) ? ((i - 1) * Refl.I(item4["amountPerLevel"])) : Refl.I(item4["amount"]));
					if (num2 > 0)
					{
						jArr3.Add(new JObj
						{
							{
								"prefab",
								item4["prefab"]
							},
							{
								"name",
								item4["name"]
							},
							{ "amount", num2 }
						});
					}
				}
				jObj4["cost"] = jArr3;
				jArr2.Add(jObj4);
			}
			jObj2["perQuality"] = jArr2;
			jArr.Add(jObj2);
		}
		return jArr;
	}

	private JArr SourcesExceptCraft(string item)
	{
		JArr jArr = new JArr();
		if (_ix.Sources.TryGetValue(item, out var value))
		{
			foreach (JObj item2 in value)
			{
				if ((string)item2["type"] != "craft")
				{
					jArr.Add(item2);
				}
			}
		}
		return jArr;
	}

	private JArr Of(Dictionary<string, JArr> d, string k)
	{
		JArr value;
		return (!d.TryGetValue(k, out value)) ? new JArr() : value;
	}

	private void WriteItems()
	{
		JArr jArr = new JArr();
		Dictionary<string, List<GameObject>> dictionary = new Dictionary<string, List<GameObject>>();
		foreach (GameObject value3 in _r.Items.Values)
		{
			string text = Refl.S(Refl.Get(Registry.Shared(value3), "m_setName"));
			if (!string.IsNullOrEmpty(text))
			{
				if (!dictionary.TryGetValue(text, out var value))
				{
					value = (dictionary[text] = new List<GameObject>());
				}
				value.Add(value3);
			}
		}
		foreach (GameObject value4 in _r.Items.Values)
		{
			string text2 = "prefab:" + ((Object)value4).name;
			if (!InScope(text2))
			{
				continue;
			}
			object obj = Registry.Shared(value4);
			string text3 = Refl.S(Refl.Get(obj, "m_name"));
			JObj jObj = new JObj();
			jObj["prefab"] = ((Object)value4).name;
			jObj["mod"] = ModOfKey(text2);
			jObj["modName"] = _o.ModName(ModOfKey(text2));
			jObj["names"] = _loc.Names(text3);
			jObj.Opt("description", _loc.Names(Refl.S(Refl.Get(obj, "m_description"))));
			jObj["itemType"] = Refl.S(Refl.Get(obj, "m_itemType"));
			jObj.Opt("icons", IconsOf(text2));
			int num = Math.Max(1, Refl.I(Refl.Get(obj, "m_maxQuality"), 1));
			jObj["maxQuality"] = num;
			jObj["perQuality"] = QualityStats(obj);
			jObj.Opt("recipes", RecipesFor(((Object)value4).name, num));
			jObj.Opt("obtain", SourcesExceptCraft(((Object)value4).name));
			jObj.Opt("usedIn", Of(_ix.Uses, ((Object)value4).name));
			string text4 = Refl.S(Refl.Get(obj, "m_setName"));
			if (!string.IsNullOrEmpty(text4))
			{
				JObj jObj2 = new JObj();
				jObj2.Add("name", text4);
				jObj2.Add("size", Refl.I(Refl.Get(obj, "m_setSize")));
				JObj jObj3 = jObj2;
				jObj3.Opt("effect", Refl.UName(Refl.Get(obj, "m_setStatusEffect")));
				JArr jArr2 = new JArr();
				foreach (GameObject item in dictionary[text4])
				{
					jArr2.Add(_ix.Who(item));
				}
				jObj3["members"] = jArr2;
				jObj["set"] = jObj3;
			}
			JObj jObj4 = new JObj();
			string[] array = new string[4] { "m_consumeStatusEffect", "m_equipStatusEffect", "m_setStatusEffect", "m_attackStatusEffect" };
			foreach (string text5 in array)
			{
				jObj4.Opt(text5.Substring(2), Refl.UName(Refl.Get(obj, text5)));
			}
			jObj.Opt("statusEffects", jObj4);
			if (_tooltips.TryGetValue("item:" + ((Object)value4).name, out var value2))
			{
				jObj["tooltips"] = LocalizedTips(value2);
			}
			jObj.Opt("referencedBy", Of(_ix.Refs, text2));
			jObj["origin"] = _o.Get(text2).ToJson();
			jObj["shared"] = Ser.Node(obj, 5);
			JObj jObj5 = new JObj();
			Component[] components = value4.GetComponents(typeof(MonoBehaviour));
			foreach (Component val in components)
			{
				string name = ((object)val).GetType().Name;
				switch (name)
				{
				case "ItemDrop":
				case "ZNetView":
				case "ZSyncTransform":
					continue;
				}
				if (!((object)val).GetType().Assembly.GetName().Name.StartsWith("Unity"))
				{
					jObj5[name] = Ser.Node(val, 3);
				}
			}
			jObj.Opt("components", jObj5);
			Track(text2, "items", ((Object)value4).name, text3);
			jArr.Add(jObj);
		}
		Json.WriteFile(P("items.json"), jArr, pretty: false);
		_manifest.Obj("counts")["items"] = jArr.Count;
	}

	private void WritePieces()
	{
		JArr jArr = new JArr();
		Dictionary<string, JArr> dictionary = new Dictionary<string, JArr>();
		foreach (KeyValuePair<string, JArr> source in _ix.Sources)
		{
			foreach (JObj item in source.Value)
			{
				if ((string)item["type"] != "craft")
				{
					continue;
				}
				string text = ((item["station"] is JObj jObj2) ? (jObj2["prefab"] as string) : null);
				if (text != null)
				{
					if (!dictionary.TryGetValue(text, out var value))
					{
						value = (dictionary[text] = new JArr());
					}
					value.Add(new JObj
					{
						{ "item", source.Key },
						{
							"recipe",
							item["recipe"]
						},
						{
							"minStationLevel",
							item["minStationLevel"]
						}
					});
				}
			}
		}
		Dictionary<string, JArr> dictionary2 = new Dictionary<string, JArr>();
		foreach (GameObject value6 in _r.Prefabs.Values)
		{
			Component o = Refl.Comp(value6, "StationExtension");
			string text2 = Refl.UName(Refl.Get(o, "m_craftingStation"));
			if (text2 != null)
			{
				if (!dictionary2.TryGetValue(text2, out var value2))
				{
					value2 = (dictionary2[text2] = new JArr());
				}
				value2.Add(_ix.Who(value6));
			}
		}
		foreach (GameObject value7 in _r.Prefabs.Values)
		{
			Component val = Refl.Comp(value7, "Piece");
			if (!Object.op_Implicit((Object)(object)val) || _r.Items.ContainsKey(((Object)value7).name))
			{
				continue;
			}
			string text3 = "prefab:" + ((Object)value7).name;
			bool flag = Refl.Enum(Refl.Get(val, "m_resources")).Any((object q) => _o.IsMod(Refl.Get(q, "m_resItem")));
			bool flag2 = dictionary.ContainsKey(((Object)value7).name) && dictionary[((Object)value7).name].Cast<JObj>().Any((JObj x) => _o.IsModKey("prefab:" + x["item"]));
			if (!InScope(text3) && !flag && !flag2)
			{
				continue;
			}
			string text4 = Refl.S(Refl.Get(val, "m_name"));
			JObj jObj3 = new JObj();
			jObj3["prefab"] = ((Object)value7).name;
			jObj3["mod"] = ModOfKey(text3);
			jObj3["modName"] = _o.ModName(ModOfKey(text3));
			if (!InScope(text3))
			{
				jObj3["vanillaWithModdedLinks"] = true;
			}
			jObj3["names"] = _loc.Names(text4);
			jObj3.Opt("description", _loc.Names(Refl.S(Refl.Get(val, "m_description"))));
			jObj3.Opt("icons", IconsOf(text3));
			if (_r.PieceTools.TryGetValue(((Object)value7).name, out var value3))
			{
				JArr jArr4 = new JArr();
				foreach (string item2 in value3)
				{
					jArr4.Add(_ix.Who(_r.Prefabs[item2]));
				}
				jObj3["builtWith"] = jArr4;
			}
			jObj3["category"] = Refl.S(Refl.Get(val, "m_category"));
			jObj3.Opt("station", _ix.Station(Refl.Get(val, "m_craftingStation")));
			jObj3["requirements"] = DataIndex.Requirements(Refl.Get(val, "m_resources"), _ix.Who);
			jObj3["comfort"] = Refl.I(Refl.Get(val, "m_comfort"));
			jObj3["comfortGroup"] = Refl.S(Refl.Get(val, "m_comfortGroup"));
			if (dictionary.TryGetValue(((Object)value7).name, out var value4))
			{
				jObj3["craftsHere"] = value4;
			}
			if (dictionary2.TryGetValue(((Object)value7).name, out var value5))
			{
				jObj3["extensions"] = value5;
			}
			jObj3.Opt("obtain", SourcesExceptCraft(((Object)value7).name));
			jObj3.Opt("referencedBy", Of(_ix.Refs, text3));
			jObj3["origin"] = _o.Get(text3).ToJson();
			JObj jObj4 = new JObj();
			Component[] components = value7.GetComponents(typeof(MonoBehaviour));
			foreach (Component val2 in components)
			{
				string name = ((object)val2).GetType().Name;
				if (!(name == "ZNetView") && !((object)val2).GetType().Assembly.GetName().Name.StartsWith("Unity"))
				{
					jObj4[name] = Ser.Node(val2, 3);
				}
			}
			jObj3["components"] = jObj4;
			if (InScope(text3))
			{
				Track(text3, "pieces", ((Object)value7).name, text4);
			}
			jArr.Add(jObj3);
		}
		Json.WriteFile(P("pieces.json"), jArr, pretty: false);
		_manifest.Obj("counts")["pieces"] = jArr.Count;
	}

	private void WriteCreatures()
	{
		JArr jArr = new JArr();
		foreach (GameObject value2 in _r.Prefabs.Values)
		{
			Component val = Refl.Comp(value2, "Character");
			if (!Object.op_Implicit((Object)(object)val))
			{
				continue;
			}
			string text = "prefab:" + ((Object)value2).name;
			bool flag = Refl.Enum(Refl.Get(Refl.Comp(value2, "CharacterDrop"), "m_drops")).Any((object d) => _o.IsMod(Refl.Get(d, "m_prefab")));
			bool flag2 = Refl.Enum(Refl.Get(Refl.Comp(value2, "MonsterAI"), "m_consumeItems")).Any((object i) => _o.IsMod(i));
			if ((!InScope(text) && !flag && !flag2) || ((Object)value2).name == "Player")
			{
				continue;
			}
			string text2 = Refl.S(Refl.Get(val, "m_name"));
			JObj jObj = new JObj();
			jObj["prefab"] = ((Object)value2).name;
			jObj["mod"] = ModOfKey(text);
			jObj["modName"] = _o.ModName(ModOfKey(text));
			if (!InScope(text))
			{
				jObj["vanillaWithModdedLinks"] = true;
			}
			jObj["names"] = _loc.Names(text2);
			jObj["health"] = Refl.F(Refl.Get(val, "m_health"));
			jObj["faction"] = Refl.S(Refl.Get(val, "m_faction"));
			jObj["boss"] = Refl.B(Refl.Get(val, "m_boss"));
			jObj.Opt("bossEvent", Refl.S(Refl.Get(val, "m_bossEvent")));
			jObj.Opt("defeatSetGlobalKey", Refl.S(Refl.Get(val, "m_defeatSetGlobalKey")));
			jObj["damageModifiers"] = Ser.Node(Refl.Get(val, "m_damageModifiers"), 2);
			Component val2 = Refl.Comp(value2, "Humanoid");
			if (Object.op_Implicit((Object)(object)val2))
			{
				JArr jArr2 = new JArr();
				string[] array = new string[4] { "m_defaultItems", "m_randomWeapon", "m_randomArmor", "m_randomShield" };
				foreach (string text3 in array)
				{
					foreach (object item in Refl.Enum(Refl.Get(val2, text3)))
					{
						GameObject val3 = (GameObject)((item is GameObject) ? item : null);
						if (Object.op_Implicit((Object)(object)val3))
						{
							object obj = Registry.Shared(val3);
							JObj jObj2 = new JObj();
							jObj2.Add("slot", text3.Substring(2));
							jObj2.Add("prefab", ((Object)val3).name);
							JObj jObj3 = jObj2;
							jObj3.Opt("names", _loc.Names(Refl.S(Refl.Get(obj, "m_name"))));
							jObj3["itemType"] = Refl.S(Refl.Get(obj, "m_itemType"));
							jObj3.Opt("damage", QualityStats(obj)[0]);
							jObj3["attack"] = Ser.Node(Refl.Get(obj, "m_attack"), 2);
							jArr2.Add(jObj3);
						}
					}
				}
				foreach (object item2 in Refl.Enum(Refl.Get(val2, "m_randomSets")))
				{
					JArr jArr3 = new JArr();
					foreach (object item3 in Refl.Enum(Refl.Get(item2, "m_items")))
					{
						jArr3.Add(Refl.UName(item3));
					}
					jArr2.Add(new JObj
					{
						{ "slot", "randomSet" },
						{ "items", jArr3 }
					});
				}
				jObj.Opt("equipmentAndAttacks", jArr2);
			}
			JArr jArr4 = new JArr();
			foreach (KeyValuePair<string, JArr> source in _ix.Sources)
			{
				foreach (JObj item4 in source.Value)
				{
					if (!((string)item4["type"] == "creatureDrop") || !(item4["from"] is JObj) || !((string)((JObj)item4["from"])["prefab"] == ((Object)value2).name))
					{
						continue;
					}
					JObj jObj2 = new JObj();
					jObj2.Add("item", source.Key);
					JObj jObj5 = jObj2;
					if (_r.Items.TryGetValue(source.Key, out var value))
					{
						jObj5["names"] = _loc.Names(Refl.S(Refl.Get(Registry.Shared(value), "m_name")));
					}
					foreach (KeyValuePair<string, object> item5 in item4)
					{
						if (item5.Key != "type" && item5.Key != "from" && item5.Key != "component")
						{
							jObj5[item5.Key] = item5.Value;
						}
					}
					jArr4.Add(jObj5);
				}
			}
			jObj.Opt("drops", jArr4);
			jObj.Opt("spawns", Of(_ix.Spawns, ((Object)value2).name));
			string[] array2 = new string[6] { "MonsterAI", "AnimalAI", "Tameable", "Procreation", "Growup", "Saddle" };
			foreach (string text4 in array2)
			{
				Component val4 = Refl.Comp(value2, text4);
				if (Object.op_Implicit((Object)(object)val4))
				{
					jObj[text4] = Ser.Node(val4, 2);
				}
			}
			List<object> list = Refl.Enum(Refl.Get(Refl.Comp(value2, "MonsterAI"), "m_consumeItems")).Select((Func<object, object>)((object x) => _ix.Who(x))).ToList();
			if (list.Count > 0)
			{
				JArr jArr5 = new JArr();
				jArr5.AddRange(list);
				jObj["eats"] = jArr5;
			}
			jObj.Opt("referencedBy", Of(_ix.Refs, text));
			jObj["origin"] = _o.Get(text).ToJson();
			jObj["character"] = Ser.Node(val, 3);
			if (InScope(text))
			{
				Track(text, "creatures", ((Object)value2).name, text2);
			}
			jArr.Add(jObj);
		}
		Json.WriteFile(P("creatures.json"), jArr, pretty: false);
		_manifest.Obj("counts")["creatures"] = jArr.Count;
	}

	private void WriteStatusEffects()
	{
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		Dictionary<string, JArr> dictionary = new Dictionary<string, JArr>();
		foreach (GameObject value4 in _r.Items.Values)
		{
			object o = Registry.Shared(value4);
			string[] array = new string[4] { "m_consumeStatusEffect", "m_equipStatusEffect", "m_setStatusEffect", "m_attackStatusEffect" };
			foreach (string text in array)
			{
				string text2 = Refl.UName(Refl.Get(o, text));
				if (text2 != null)
				{
					if (!dictionary.TryGetValue(text2, out var value))
					{
						value = (dictionary[text2] = new JArr());
					}
					JObj jObj = _ix.Who(value4);
					jObj["as"] = text.Substring(2);
					value.Add(jObj);
				}
			}
		}
		JArr jArr2 = new JArr();
		foreach (object statusEffect in _r.StatusEffects)
		{
			string text3 = Origin.KeyOf(statusEffect);
			string name = ((Object)statusEffect).name;
			if (InScope(text3) || (dictionary.ContainsKey(name) && dictionary[name].Cast<JObj>().Any((JObj u) => u["mod"] != null)))
			{
				string text4 = Refl.S(Refl.Get(statusEffect, "m_name"));
				JObj jObj2 = new JObj();
				jObj2["name"] = name;
				jObj2["type"] = statusEffect.GetType().Name;
				jObj2["mod"] = ModOfKey(text3);
				jObj2["modName"] = _o.ModName(ModOfKey(text3));
				jObj2.Opt("names", _loc.Names(text4));
				jObj2.Opt("tooltipText", _loc.Names(Refl.S(Refl.Get(statusEffect, "m_tooltip"))));
				if (_tooltips.TryGetValue(text3, out var value2))
				{
					jObj2["tooltips"] = LocalizedTips(value2);
				}
				jObj2.Opt("icons", IconsOf(text3));
				if (dictionary.TryGetValue(name, out var value3))
				{
					jObj2["usedBy"] = value3;
				}
				jObj2.Opt("referencedBy", Of(_ix.Refs, text3));
				jObj2["origin"] = _o.Get(text3).ToJson();
				jObj2["fields"] = Ser.Node(statusEffect, 3);
				if (InScope(text3))
				{
					Track(text3, "statusEffects", name, text4);
				}
				jArr2.Add(jObj2);
			}
		}
		Json.WriteFile(P("status_effects.json"), jArr2, pretty: false);
		_manifest.Obj("counts")["statusEffects"] = jArr2.Count;
	}

	private void WriteRecipes()
	{
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		JArr jArr = new JArr();
		foreach (object recipe in _r.Recipes)
		{
			string key = Origin.KeyOf(recipe);
			object obj = Refl.Get(recipe, "m_item");
			if (InScope(key) || _o.IsMod(obj) || _o.IsMod(Refl.Get(recipe, "m_craftingStation")) || Refl.Enum(Refl.Get(recipe, "m_resources")).Any((object q) => _o.IsMod(Refl.Get(q, "m_resItem"))))
			{
				JObj jObj = new JObj();
				jObj["name"] = ((Object)recipe).name;
				jObj["mod"] = ModOfKey(key);
				jObj["modName"] = _o.ModName(ModOfKey(key));
				jObj["result"] = ((obj != null) ? _ix.Who(obj) : null);
				jObj["amount"] = Refl.I(Refl.Get(recipe, "m_amount"), 1);
				jObj["enabled"] = Refl.B(Refl.Get(recipe, "m_enabled"));
				jObj.Opt("station", _ix.Station(Refl.Get(recipe, "m_craftingStation")));
				jObj.Opt("repairStation", _ix.Station(Refl.Get(recipe, "m_repairStation")));
				jObj["minStationLevel"] = Refl.I(Refl.Get(recipe, "m_minStationLevel"), 1);
				jObj["requireOnlyOneIngredient"] = Refl.B(Refl.Get(recipe, "m_requireOnlyOneIngredient"));
				jObj["requirements"] = DataIndex.Requirements(Refl.Get(recipe, "m_resources"), _ix.Who);
				jObj["origin"] = _o.Get(key).ToJson();
				jObj["fields"] = Ser.Node(recipe, 2);
				if (InScope(key))
				{
					Track(key, "recipes", jObj["name"] as string, null);
				}
				jArr.Add(jObj);
			}
		}
		Json.WriteFile(P("recipes.json"), jArr, pretty: false);
		_manifest.Obj("counts")["recipes"] = jArr.Count;
	}

	private void WriteWorld(JArr locations, JArr rooms)
	{
		JObj jObj = new JObj();
		JObj jObj2 = new JObj();
		foreach (KeyValuePair<string, JArr> spawn in _ix.Spawns)
		{
			string key = "prefab:" + spawn.Key;
			if (InScope(key))
			{
				jObj2[spawn.Key] = spawn.Value;
			}
		}
		jObj["spawnsByCreature"] = jObj2;
		JArr jArr = new JArr();
		foreach (object @event in _r.Events)
		{
			string text = Refl.S(Refl.Get(@event, "m_name"));
			string k = "event:" + text;
			bool flag = _o.IsModKey(k);
			bool flag2 = Refl.Enum(Refl.Get(@event, "m_spawn")).Any((object sd) => _o.IsMod(Refl.Get(sd, "m_prefab")));
			if (flag || flag2 || _opt.IncludeVanilla)
			{
				JObj jObj3 = new JObj();
				jObj3.Add("name", text);
				jObj3.Add("modded", flag);
				jObj3.Add("involvesModdedCreatures", flag2);
				JObj jObj4 = jObj3;
				jObj4.Opt("startMessage", _loc.Names(Refl.S(Refl.Get(@event, "m_startMessage"))));
				jObj4.Opt("endMessage", _loc.Names(Refl.S(Refl.Get(@event, "m_endMessage"))));
				jObj4["fields"] = Ser.Node(@event, 3);
				jArr.Add(jObj4);
			}
		}
		jObj["events"] = jArr;
		jObj["locations"] = locations;
		jObj["dungeonRooms"] = rooms;
		Json.WriteFile(P("world.json"), jObj, pretty: false);
		_manifest.Obj("counts")["locations"] = locations.Count;
		_manifest.Obj("counts")["dungeonRooms"] = rooms.Count;
		_manifest.Obj("counts")["events"] = jArr.Count;
	}

	private void WriteVanillaLinks()
	{
		JArr jArr = new JArr();
		foreach (GameObject value in _r.Items.Values)
		{
			string k = "prefab:" + ((Object)value).name;
			if (!_o.IsModKey(k))
			{
				List<JObj> list = Of(_ix.Sources, ((Object)value).name).Cast<JObj>().Where(ModRecord).ToList();
				List<JObj> list2 = Of(_ix.Uses, ((Object)value).name).Cast<JObj>().Where(ModRecord).ToList();
				if (list.Count != 0 || list2.Count != 0)
				{
					JObj jObj = new JObj();
					jObj.Add("prefab", ((Object)value).name);
					jObj.Add("names", _loc.Names(Refl.S(Refl.Get(Registry.Shared(value), "m_name"))));
					JObj jObj2 = jObj;
					JArr jArr2 = new JArr();
					jArr2.AddRange(list.Cast<object>());
					jObj2.Opt("newWaysToObtain", jArr2);
					JArr jArr3 = new JArr();
					jArr3.AddRange(list2.Cast<object>());
					jObj2.Opt("newUses", jArr3);
					jArr.Add(jObj2);
				}
			}
		}
		Json.WriteFile(P("vanilla_items_linked.json"), jArr, pretty: false);
	}

	private static bool ModRecord(JObj r)
	{
		if (r["mod"] != null)
		{
			return true;
		}
		foreach (KeyValuePair<string, object> item in r)
		{
			if (item.Value is JObj jObj && (jObj["mod"] != null || ModRecord(jObj)))
			{
				return true;
			}
			if (!(item.Value is JArr jArr))
			{
				continue;
			}
			foreach (object item2 in jArr)
			{
				if (item2 is JObj && ModRecord((JObj)item2))
				{
					return true;
				}
			}
		}
		return false;
	}

	private void WriteReferences()
	{
		JObj jObj = new JObj();
		foreach (KeyValuePair<string, JArr> @ref in _ix.Refs)
		{
			jObj[@ref.Key] = @ref.Value;
		}
		Json.WriteFile(P("references.json"), jObj, pretty: false);
	}

	private void WriteRaw()
	{
		Dictionary<string, JObj> dictionary = new Dictionary<string, JObj>();
		foreach (GameObject value2 in _r.Prefabs.Values)
		{
			string text = "prefab:" + ((Object)value2).name;
			if (!_o.IsModKey(text))
			{
				continue;
			}
			string key = ModOfKey(text);
			if (!dictionary.TryGetValue(key, out var value))
			{
				value = (dictionary[key] = new JObj());
			}
			JObj jObj2 = new JObj();
			Component[] componentsInChildren = value2.GetComponentsInChildren(typeof(MonoBehaviour), true);
			foreach (Component val in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)val) && !((object)val).GetType().Assembly.GetName().Name.StartsWith("Unity"))
				{
					string text2 = ((object)val).GetType().Name + ((!((Object)(object)val.gameObject == (Object)(object)value2)) ? ("@" + ((Object)val.gameObject).name) : "");
					int num = 2;
					string text3 = text2;
					while (jObj2.Has(text2))
					{
						text2 = text3 + "#" + num++;
					}
					jObj2[text2] = Ser.Node(val, _opt.RawDepth);
				}
			}
			value[((Object)value2).name] = jObj2;
		}
		foreach (KeyValuePair<string, JObj> item in dictionary)
		{
			Json.WriteFile(P("raw", Icons.SafeName(item.Key) + ".json"), item.Value, pretty: false);
		}
	}

	private void WriteLocalization()
	{
		foreach (KeyValuePair<string, Dictionary<string, string>> table in _loc.Tables)
		{
			JObj jObj = new JObj();
			foreach (KeyValuePair<string, string> item in table.Value.OrderBy<KeyValuePair<string, string>, string>((KeyValuePair<string, string> x) => x.Key, StringComparer.Ordinal))
			{
				jObj[item.Key] = item.Value;
			}
			Json.WriteFile(P("localization", table.Key + ".json"), jObj, pretty: false);
		}
		JObj jObj2 = new JObj();
		string text = ((!_loc.Languages.Contains("English")) ? _loc.Languages.FirstOrDefault() : "English");
		foreach (KeyValuePair<string, HashSet<string>> modToken in _modTokens)
		{
			JObj jObj3 = new JObj();
			foreach (string language in _loc.Languages)
			{
				JArr jArr = new JArr();
				JArr jArr2 = new JArr();
				foreach (string item2 in modToken.Value.OrderBy((string x) => x))
				{
					string text2 = _loc.Text("$" + item2, language);
					if (text2 == null)
					{
						jArr.Add(item2);
					}
					else if (language != text && text2 == _loc.Text("$" + item2, text))
					{
						jArr2.Add(item2);
					}
				}
				JObj jObj4 = new JObj();
				jObj4.Opt("noText", jArr);
				jObj4.Opt("sameAsEnglish", jArr2);
				jObj3.Opt(language, jObj4);
			}
			jObj2.Opt(modToken.Key, jObj3);
			JObj jObj5 = new JObj();
			foreach (string item3 in modToken.Value.OrderBy((string x) => x))
			{
				JObj jObj6 = new JObj();
				JObj jObj7 = new JObj();
				foreach (string language2 in _loc.Languages)
				{
					jObj6[language2] = _loc.Word(item3, language2, out var source);
					jObj7[language2] = source;
				}
				jObj6["source"] = jObj7;
				jObj5[item3] = jObj6;
			}
			Json.WriteFile(P("localization", "mod_" + Icons.SafeName(modToken.Key) + ".json"), jObj5, pretty: false);
		}
		Json.WriteFile(P("localization", "missing_translations.json"), jObj2, pretty: true);
	}

	private void WriteOrigin(JObj jotunn, JObj statics)
	{
		JObj jObj = new JObj();
		jObj["note"] = "status: mod | vanilla_replaced. Signals: jotunn/manager = registered by that mod (exact); bundle = asset ships in that mod's AssetBundle; runtime-clone = created at runtime (owner may be unknown); not-in-vanilla-baseline = absent from the unmodded game; static = owner hint only.";
		jObj["jotunn"] = jotunn;
		jObj["managerLibraries"] = statics;
		jObj["bundles"] = _o.Bundles;
		JObj jObj2 = new JObj();
		foreach (OriginInfo item in (from x in _o.All()
			where x.IsMod
			select x).OrderBy<OriginInfo, string>((OriginInfo x) => x.Key, StringComparer.Ordinal))
		{
			jObj2[item.Key] = item.ToJson();
		}
		jObj["modded"] = jObj2;
		JArr jArr = new JArr();
		jArr.AddRange(_r.DuplicatePrefabs.Cast<object>());
		jObj.Opt("duplicatePrefabNames", jArr);
		Json.WriteFile(P("origin.json"), jObj, pretty: false);
	}

	private void WriteMods()
	{
		Dictionary<string, JArr> dictionary = HarmonyOwners();
		JArr jArr = new JArr();
		foreach (ModEntry item in _mods.OrderBy((ModEntry x) => x.Name))
		{
			JObj jObj = new JObj();
			jObj["guid"] = item.Guid;
			jObj["name"] = item.Name;
			jObj["version"] = item.Version;
			jObj["folder"] = item.FolderName;
			jObj["dll"] = ((item.DllPath != null) ? Path.GetFileName(item.DllPath) : null);
			jObj.Opt("icon", IconsOf("mod:" + item.Guid));
			if (item.Folder != null)
			{
				string path = Path.Combine(item.Folder, "manifest.json");
				if (File.Exists(path))
				{
					try
					{
						jObj["thunderstore"] = JsonParse.Parse(File.ReadAllText(path));
					}
					catch
					{
						jObj["thunderstore"] = File.ReadAllText(path);
					}
				}
				string path2 = Path.Combine(item.Folder, "README.md");
				if (File.Exists(path2))
				{
					try
					{
						jObj["readme"] = File.ReadAllText(path2);
					}
					catch
					{
					}
				}
				string path3 = Path.Combine(item.Folder, "CHANGELOG.md");
				if (File.Exists(path3))
				{
					try
					{
						jObj["changelog"] = File.ReadAllText(path3);
					}
					catch
					{
					}
				}
			}
			jObj.Opt("config", ConfigOf(item));
			JArr jArr2 = new JArr();
			jArr2.AddRange(item.BundleNames.Cast<object>());
			jObj.Opt("assetBundles", jArr2);
			if (dictionary.TryGetValue(item.Guid, out var value))
			{
				jObj["harmonyPatches"] = value;
			}
			if (_modContent.TryGetValue(item.Guid, out var value2))
			{
				jObj["content"] = value2;
			}
			if (_opt.ModStatics && item.Asm != null && item.Guid != _opt.SelfGuid)
			{
				jObj.Opt("staticData", Statics(item));
			}
			jArr.Add(jObj);
		}
		if (_modContent.TryGetValue("unknown", out var value3))
		{
			jArr.Add(new JObj
			{
				{ "guid", "unknown" },
				{ "name", "(modded, owner not determinable)" },
				{ "content", value3 }
			});
		}
		JArr jArr3 = new JArr();
		foreach (KeyValuePair<string, JArr> kv in dictionary)
		{
			if (!_mods.Any((ModEntry m) => m.Guid == kv.Key))
			{
				jArr3.Add(new JObj
				{
					{ "owner", kv.Key },
					{ "patches", kv.Value }
				});
			}
		}
		Json.WriteFile(P("mods.json"), new JObj
		{
			{ "mods", jArr },
			{ "otherHarmonyOwners", jArr3 }
		}, pretty: true);
		foreach (KeyValuePair<string, JObj> item2 in _modContent)
		{
			Json.WriteFile(P("mods", Icons.SafeName(item2.Key) + ".json"), item2.Value, pretty: true);
		}
	}

	private JArr ConfigOf(ModEntry m)
	{
		JArr jArr = new JArr();
		object v = Refl.Get(m.Instance, "Config");
		foreach (object item in Refl.Enum(v))
		{
			object o = Refl.Get(item, "Key");
			object obj = Refl.Get(item, "Value");
			if (obj != null)
			{
				object o2 = Refl.Get(obj, "Description");
				JObj jObj = new JObj();
				jObj.Add("section", Refl.S(Refl.Get(o, "Section")));
				jObj.Add("key", Refl.S(Refl.Get(o, "Key")));
				jObj.Add("value", Ser.Node(Refl.Get(obj, "BoxedValue"), 1));
				jObj.Add("default", Ser.Node(Refl.Get(obj, "DefaultValue"), 1));
				jObj.Add("type", (!(Refl.Get(obj, "SettingType") as Type == null)) ? ((Type)Refl.Get(obj, "SettingType")).Name : null);
				jObj.Add("description", Refl.S(Refl.Get(o2, "Description")));
				JObj jObj2 = jObj;
				object obj2 = Refl.Get(o2, "AcceptableValues");
				if (obj2 != null)
				{
					jObj2["acceptable"] = Refl.S(Refl.Call(obj2, "ToDescriptionString"));
				}
				jArr.Add(jObj2);
			}
		}
		return jArr;
	}

	private Dictionary<string, JArr> HarmonyOwners()
	{
		Dictionary<string, JArr> dictionary = new Dictionary<string, JArr>();
		Type type = Refl.T("HarmonyLib.Harmony");
		if (type == null)
		{
			return dictionary;
		}
		object v = Refl.Invoke(type, null, "GetAllPatchedMethods", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, new object[0]);
		foreach (object item in Refl.Enum(v))
		{
			object obj = Refl.Invoke(type, null, "GetPatchInfo", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, new object[1] { item });
			if (obj == null)
			{
				continue;
			}
			MethodBase methodBase = item as MethodBase;
			string v2 = ((!(methodBase == null)) ? (((!(methodBase.DeclaringType == null)) ? methodBase.DeclaringType.FullName : "") + "." + methodBase.Name) : Refl.S(item));
			string[] array = new string[4] { "Prefixes", "Postfixes", "Transpilers", "Finalizers" };
			foreach (string text in array)
			{
				foreach (object item2 in Refl.Enum(Refl.Get(obj, text)))
				{
					string key = Refl.S(Refl.Get(item2, "owner")) ?? "?";
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = (dictionary[key] = new JArr());
					}
					value.Add(new JObj
					{
						{ "target", v2 },
						{
							"kind",
							text.TrimEnd('s').Replace("Prefixe", "Prefix")
						}
					});
				}
			}
		}
		return dictionary;
	}

	private JObj Statics(ModEntry m)
	{
		JObj jObj = new JObj();
		Type[] array;
		try
		{
			array = m.Asm.GetTypes();
		}
		catch (ReflectionTypeLoadException ex)
		{
			array = ex.Types.Where((Type x) => x != null).ToArray();
		}
		catch
		{
			return jObj;
		}
		int num = 400;
		int maxList = Ser.MaxList;
		Ser.MaxList = 300;
		try
		{
			Type[] array2 = array;
			foreach (Type type in array2)
			{
				if (type.IsGenericTypeDefinition || type.Name.StartsWith("<"))
				{
					continue;
				}
				string text = type.Namespace ?? "";
				if (!Origin.SafeStatics(type, m, text.EndsWith("Manager")) || text.StartsWith("ServerSync") || text.StartsWith("Microsoft") || text.StartsWith("System") || text.StartsWith("YamlDotNet") || text.StartsWith("Newtonsoft"))
				{
					continue;
				}
				FieldInfo[] fields;
				try
				{
					fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch
				{
					continue;
				}
				FieldInfo[] array3 = fields;
				foreach (FieldInfo fieldInfo in array3)
				{
					if (num <= 0)
					{
						return jObj;
					}
					if (fieldInfo.IsLiteral || fieldInfo.Name.StartsWith("<") || typeof(Delegate).IsAssignableFrom(fieldInfo.FieldType) || typeof(Object).IsAssignableFrom(fieldInfo.FieldType))
					{
						continue;
					}
					string text2 = fieldInfo.FieldType.Namespace ?? "";
					if ((text2.StartsWith("System") && !fieldInfo.FieldType.IsPrimitive && fieldInfo.FieldType != typeof(string) && !fieldInfo.FieldType.IsEnum && !typeof(IEnumerable).IsAssignableFrom(fieldInfo.FieldType)) || (fieldInfo.FieldType.FullName != null && (fieldInfo.FieldType.FullName.StartsWith("BepInEx") || fieldInfo.FieldType.FullName.StartsWith("HarmonyLib"))))
					{
						continue;
					}
					object value;
					try
					{
						value = fieldInfo.GetValue(null);
					}
					catch
					{
						continue;
					}
					if (value != null)
					{
						object obj4;
						try
						{
							obj4 = Ser.Node(value, 0, 3, new HashSet<object>(RefEq.I), privateToo: true);
						}
						catch
						{
							continue;
						}
						if (obj4 != null && (!(obj4 is JArr) || ((JArr)obj4).Count != 0) && (!(obj4 is JObj) || ((JObj)obj4).Count != 0))
						{
							jObj[type.FullName + "." + fieldInfo.Name] = obj4;
							num--;
						}
					}
				}
			}
			return jObj;
		}
		finally
		{
			Ser.MaxList = maxList;
		}
	}
}
internal sealed class Registry
{
	public readonly Dictionary<string, GameObject> Prefabs = new Dictionary<string, GameObject>();

	public readonly List<string> DuplicatePrefabs = new List<string>();

	public readonly HashSet<string> Networked = new HashSet<string>();

	public readonly Dictionary<string, GameObject> Items = new Dictionary<string, GameObject>();

	public readonly List<object> Recipes = new List<object>();

	public readonly List<object> StatusEffects = new List<object>();

	public readonly List<object> Locations = new List<object>();

	public readonly List<object> Rooms = new List<object>();

	public readonly List<object> SpawnLists = new List<object>();

	public readonly List<object> Events = new List<object>();

	public readonly Dictionary<string, List<string>> PieceTools = new Dictionary<string, List<string>>();

	public readonly List<string> Problems = new List<string>();

	public static Registry Collect()
	{
		//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c1: Expected O, but got Unknown
		//IL_0326: Unknown result type (might be due to invalid IL or missing references)
		//IL_0330: Expected O, but got Unknown
		Registry registry = new Registry();
		object obj = Refl.Singleton("ZNetScene");
		object obj2 = Refl.Singleton("ObjectDB");
		if (obj == null)
		{
			registry.Problems.Add("ZNetScene not ready");
		}
		if (obj2 == null)
		{
			registry.Problems.Add("ObjectDB not ready");
		}
		foreach (object item in Refl.Enum(Refl.Get(obj, "m_prefabs")))
		{
			registry.AddPrefab((GameObject)((item is GameObject) ? item : null));
		}
		if (Refl.Get(obj, "m_namedPrefabs") is IDictionary dictionary)
		{
			foreach (object value2 in dictionary.Values)
			{
				registry.AddPrefab((GameObject)((value2 is GameObject) ? value2 : null));
			}
		}
		foreach (string key in registry.Prefabs.Keys)
		{
			registry.Networked.Add(key);
		}
		foreach (object item2 in Refl.Enum(Refl.Get(obj2, "m_items")))
		{
			GameObject val = (GameObject)((item2 is GameObject) ? item2 : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				if (!registry.Items.ContainsKey(((Object)val).name))
				{
					registry.Items[((Object)val).name] = val;
				}
				if (!registry.Prefabs.ContainsKey(((Object)val).name))
				{
					registry.Prefabs[((Object)val).name] = val;
				}
			}
		}
		foreach (GameObject value3 in registry.Prefabs.Values)
		{
			if (!registry.Items.ContainsKey(((Object)value3).name) && Object.op_Implicit((Object)(object)Refl.Comp(value3, "ItemDrop")))
			{
				registry.Items[((Object)value3).name] = value3;
			}
		}
		foreach (object item3 in Refl.Enum(Refl.Get(obj2, "m_recipes")))
		{
			if (item3 is Object && Object.op_Implicit((Object)item3))
			{
				registry.Recipes.Add(item3);
			}
		}
		foreach (object item4 in Refl.Enum(Refl.Get(obj2, "m_StatusEffects")))
		{
			if (item4 is Object && Object.op_Implicit((Object)item4))
			{
				registry.StatusEffects.Add(item4);
			}
		}
		foreach (GameObject value4 in registry.Items.Values)
		{
			object o = Refl.Get(Shared(value4), "m_buildPieces");
			foreach (object item5 in Refl.Enum(Refl.Get(o, "m_pieces")))
			{
				GameObject val2 = (GameObject)((item5 is GameObject) ? item5 : null);
				if (Object.op_Implicit((Object)(object)val2))
				{
					if (!registry.PieceTools.TryGetValue(((Object)val2).name, out var value))
					{
						value = (registry.PieceTools[((Object)val2).name] = new List<string>());
					}
					if (!value.Contains(((Object)value4).name))
					{
						value.Add(((Object)value4).name);
					}
					if (!registry.Prefabs.ContainsKey(((Object)val2).name))
					{
						registry.Prefabs[((Object)val2).name] = val2;
					}
				}
			}
		}
		object o2 = Refl.Singleton("ZoneSystem");
		foreach (object item6 in Refl.Enum(Refl.Get(o2, "m_locations")))
		{
			if (item6 != null)
			{
				registry.Locations.Add(item6);
			}
		}
		object o3 = Refl.Singleton("DungeonDB");
		object v = Refl.Get(o3, "m_rooms") ?? Refl.Call(o3, "GetRooms") ?? Refl.CallStatic("DungeonDB", "GetRooms");
		foreach (object item7 in Refl.Enum(v))
		{
			if (item7 != null)
			{
				registry.Rooms.Add(item7);
			}
		}
		HashSet<object> hashSet = new HashSet<object>(RefEq.I);
		Type type = Refl.T("SpawnSystemList");
		if (type != null)
		{
			foreach (object item8 in FindAll(type))
			{
				if (hashSet.Add(item8))
				{
					registry.SpawnLists.Add(item8);
				}
			}
			foreach (GameObject value5 in registry.Prefabs.Values)
			{
				Component[] array = Refl.Comps(value5, "SpawnSystem", children: true);
				foreach (Component o4 in array)
				{
					foreach (object item9 in Refl.Enum(Refl.Get(o4, "m_spawnLists")))
					{
						if (item9 != null && hashSet.Add(item9))
						{
							registry.SpawnLists.Add(item9);
						}
					}
				}
			}
		}
		object o5 = Refl.Singleton("RandEventSystem");
		foreach (object item10 in Refl.Enum(Refl.Get(o5, "m_events")))
		{
			if (item10 != null)
			{
				registry.Events.Add(item10);
			}
		}
		return registry;
	}

	private void AddPrefab(GameObject go)
	{
		if (!Object.op_Implicit((Object)(object)go))
		{
			return;
		}
		if (Prefabs.TryGetValue(((Object)go).name, out var value))
		{
			if (!object.ReferenceEquals(value, go) && !DuplicatePrefabs.Contains(((Object)go).name))
			{
				DuplicatePrefabs.Add(((Object)go).name);
			}
		}
		else
		{
			Prefabs[((Object)go).name] = go;
		}
	}

	public static IEnumerable<object> FindAll(Type t)
	{
		Type type = Refl.T("UnityEngine.Resources");
		object v = ((!(type == null)) ? Refl.Invoke(type, null, "FindObjectsOfTypeAll", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, new object[1] { t }) : null);
		return (from o in Refl.Enum(v)
			where o is Object && Object.op_Implicit((Object)o)
			select o).ToList();
	}

	public static object ItemData(GameObject go)
	{
		return Refl.Get(Refl.Comp(go, "ItemDrop"), "m_itemData");
	}

	public static object Shared(GameObject go)
	{
		return Refl.Get(ItemData(go), "m_shared");
	}

	public static GameObject LoadSoft(object holder, List<object> toRelease, JObj diag = null)
	{
		object obj = Refl.Get(holder, "m_prefab");
		GameObject val = Refl.GO(obj);
		if (Object.op_Implicit((Object)(object)val))
		{
			return val;
		}
		if (obj == null)
		{
			if (diag != null)
			{
				diag["m_prefab"] = "null";
			}
			return null;
		}
		try
		{
			Type type = obj.GetType();
			if (diag != null && !diag.Has("type"))
			{
				diag["type"] = type.FullName;
				JArr jArr = new JArr();
				MemberInfo[] members = type.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MemberInfo memberInfo in members)
				{
					if (!(memberInfo is ConstructorInfo) && !memberInfo.Name.StartsWith("<"))
					{
						jArr.Add(string.Concat(memberInfo.MemberType, " ", memberInfo.Name));
					}
				}
				diag["members"] = jArr;
			}
			GameObject val2 = Refl.GO(Refl.Get(obj, "Asset"));
			if (Object.op_Implicit((Object)(object)val2))
			{
				return val2;
			}
			MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "Load" && m.GetParameters().Length == 0);
			if (methodInfo == null)
			{
				if (diag != null)
				{
					diag["error"] = "no Load()";
				}
				return null;
			}
			methodInfo.Invoke(obj, null);
			toRelease.Add(obj);
			object obj2 = Refl.Get(obj, "Asset");
			val = Refl.GO(obj2);
			if (!Object.op_Implicit((Object)(object)val) && diag != null)
			{
				diag["error"] = "Asset after Load(): " + ((obj2 != null) ? obj2.GetType().Name : "null");
			}
			return val;
		}
		catch (Exception ex)
		{
			if (diag != null)
			{
				diag["error"] = (ex.InnerException ?? ex).GetType().Name + ": " + (ex.InnerException ?? ex).Message;
			}
			return null;
		}
	}
}
internal sealed class Loc
{
	public readonly Dictionary<string, Dictionary<string, string>> Tables = new Dictionary<string, Dictionary<string, string>>();

	public readonly List<string> Languages = new List<string>();

	public string Original;

	private static readonly Regex Token = new Regex("\\$[A-Za-z0-9_]+", RegexOptions.Compiled);

	public readonly Dictionary<string, Dictionary<string, string>> Resolved = new Dictionary<string, Dictionary<string, string>>();

	public ModTexts Mod;

	public static string Current()
	{
		return Refl.Call(Refl.Singleton("Localization"), "GetSelectedLanguage") as string;
	}

	public static bool Switch(string lang)
	{
		object obj = Refl.Call(Refl.Singleton("Localization"), "SetupLanguage", lang);
		return !(obj is bool) || (bool)obj;
	}

	public string Word(string token, string lang, out string source)
	{
		source = null;
		string source2 = null;
		string text = ((Mod != null) ? Mod.Get(lang, token, out source2) : null);
		if (text != null && source2.StartsWith("config:"))
		{
			source = source2;
			return text;
		}
		if (Resolved.TryGetValue(lang, out var value) && value.TryGetValue(token, out var value2) && value2 != null)
		{
			source = "game";
			return value2;
		}
		if (text != null)
		{
			source = source2;
			return text;
		}
		if (Tables.TryGetValue(lang, out value) && value.TryGetValue(token, out value2) && value2 != null)
		{
			source = "vanilla";
			return value2;
		}
		return null;
	}

	public static string GameLocalize(string token)
	{
		object obj = Refl.Singleton("Localization");
		if (obj == null)
		{
			return null;
		}
		string text = Refl.Call(obj, "Localize", "$" + token) as string;
		if (string.IsNullOrEmpty(text) || text == "$" + token || text == token || text == "[" + token + "]" || text == "[$" + token + "]")
		{
			return null;
		}
		return text;
	}

	public void ResolveTokens(string lang, IEnumerable<string> tokens)
	{
		if (!Resolved.TryGetValue(lang, out var value))
		{
			value = (Resolved[lang] = new Dictionary<string, string>());
		}
		foreach (string token in tokens)
		{
			if (!value.ContainsKey(token))
			{
				value[token] = GameLocalize(token);
			}
		}
	}

	public static string LocalizeText(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return text;
		}
		object obj = Refl.Singleton("Localization");
		return (obj != null) ? ((Refl.Call(obj, "Localize", text) as string) ?? text) : text;
	}

	public void Capture(string lang)
	{
		Dictionary<string, string> dictionary = new Dictionary<string, string>();
		if (Refl.Get(Refl.Singleton("Localization"), "m_translations") is IDictionary dictionary2)
		{
			foreach (DictionaryEntry item in dictionary2)
			{
				if (item.Key != null)
				{
					dictionary[item.Key.ToString()] = ((item.Value != null) ? item.Value.ToString() : null);
				}
			}
		}
		Tables[lang] = dictionary;
		if (!Languages.Contains(lang))
		{
			Languages.Add(lang);
		}
	}

	public string Text(string raw, string lang)
	{
		if (string.IsNullOrEmpty(raw))
		{
			return null;
		}
		if (!Languages.Contains(lang))
		{
			return null;
		}
		bool any = false;
		string text = Token.Replace(raw, delegate(Match m)
		{
			string source;
			string text2 = Word(m.Value.Substring(1), lang, out source);
			if (text2 != null)
			{
				any = true;
				return text2;
			}
			return m.Value;
		});
		if (!raw.Contains("$"))
		{
			return raw;
		}
		return (!any) ? null : text;
	}

	public JObj Names(string raw)
	{
		if (string.IsNullOrEmpty(raw))
		{
			return null;
		}
		JObj jObj = new JObj();
		jObj["token"] = raw;
		foreach (string language in Languages)
		{
			jObj[language] = Text(raw, language);
		}
		return jObj;
	}

	public IEnumerable<string> Tokens(string raw)
	{
		if (string.IsNullOrEmpty(raw))
		{
			yield break;
		}
		IEnumerator enumerator = Token.Matches(raw).GetEnumerator();
		try
		{
			while (enumerator.MoveNext())
			{
				Match m = (Match)enumerator.Current;
				yield return m.Value.Substring(1);
			}
		}
		finally
		{
			IDisposable disposable2;
			IDisposable disposable = (disposable2 = enumerator as IDisposable);
			if (disposable2 != null)
			{
				disposable.Dispose();
			}
		}
	}
}
internal sealed class Icons : IDisposable
{
	private readonly Type _tSprite;

	private readonly Type _tTex2D;

	private readonly Type _tRT;

	private readonly Type _tRTFmt;

	private readonly Type _tRTRW;

	private readonly Type _tTexFmt;

	private readonly Type _tRect;

	private readonly Type _tGraphics;

	private readonly Type _tImgConv;

	private readonly Type _tObject;

	private readonly Type _tTexture;

	private readonly Type _tColor;

	private readonly string _mode;

	private readonly LinkedList<KeyValuePair<object, object>> _cache = new LinkedList<KeyValuePair<object, object>>();

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

	private bool _floatFailed;

	public int Saved;

	public int Failed;

	public int Reused;

	public string LastError;

	public bool Ready => _tSprite != null && _tTex2D != null && _tRT != null && _tGraphics != null && _tImgConv != null && _tRect != null && _tColor != null;

	private bool LinearRead => !_mode.Equals("sRGB", StringComparison.OrdinalIgnoreCase);

	private bool Convert => _mode.Equals("LinearToSRGB", StringComparison.OrdinalIgnoreCase);

	public Icons(string mode)
	{
		_mode = (mode ?? "LinearToSRGB").Trim();
		_tSprite = Refl.T("UnityEngine.Sprite");
		_tTex2D = Refl.T("UnityEngine.Texture2D");
		_tTexture = Refl.T("UnityEngine.Texture");
		_tRT = Refl.T("UnityEngine.RenderTexture");
		_tRTFmt = Refl.T("UnityEngine.RenderTextureFormat");
		_tRTRW = Refl.T("UnityEngine.RenderTextureReadWrite");
		_tTexFmt = Refl.T("UnityEngine.TextureFormat");
		_tRect = Refl.T("UnityEngine.Rect");
		_tGraphics = Refl.T("UnityEngine.Graphics");
		_tImgConv = Refl.T("UnityEngine.ImageConversion");
		_tObject = Refl.T("UnityEngine.Object");
		_tColor = Refl.T("UnityEngine.Color");
	}

	private static object SCall(Type t, string name, Type[] sig, params object[] args)
	{
		MethodInfo method = t.GetMethod(name, BindingFlags.Static | BindingFlags.Public, null, sig, null);
		if (method == null)
		{
			throw new MissingMethodException(t.Name + "." + name);
		}
		return method.Invoke(null, args);
	}

	private static object ICall(object o, string name, Type[] sig, params object[] args)
	{
		MethodInfo method = o.GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public, null, sig, null);
		if (method == null)
		{
			throw new MissingMethodException(o.GetType().Name + "." + name);
		}
		return method.Invoke(o, args);
	}

	private object Readable(object tex)
	{
		foreach (KeyValuePair<object, object> item in _cache)
		{
			if (object.ReferenceEquals(item.Key, tex))
			{
				_cache.Remove(item);
				_cache.AddFirst(item);
				return item.Value;
			}
		}
		int w = Refl.I(Refl.Get(tex, "width"));
		int h = Refl.I(Refl.Get(tex, "height"));
		object obj = null;
		if (LinearRead && Convert && !_floatFailed)
		{
			try
			{
				obj = Blit(tex, w, h, "ARGBFloat", "RGBAFloat");
			}
			catch
			{
				_floatFailed = true;
			}
		}
		if (obj == null)
		{
			obj = Blit(tex, w, h, "ARGB32", "RGBA32");
		}
		_cache.AddFirst(new KeyValuePair<object, object>(tex, obj));
		while (_cache.Count > 4)
		{
			Destroy(_cache.Last.Value.Value);
			_cache.RemoveLast();
		}
		return obj;
	}

	private object Blit(object tex, int w, int h, string rtFormat, string texFormat)
	{
		object obj = Enum.Parse(_tRTRW, (!LinearRead) ? "sRGB" : "Linear");
		object obj2 = SCall(_tRT, "GetTemporary", new Type[5]
		{
			typeof(int),
			typeof(int),
			typeof(int),
			_tRTFmt,
			_tRTRW
		}, w, h, 0, Enum.Parse(_tRTFmt, rtFormat), obj);
		PropertyInfo property = _tRT.GetProperty("active");
		object value = property.GetValue(null, null);
		try
		{
			SCall(_tGraphics, "Blit", new Type[2] { _tTexture, _tRT }, tex, obj2);
			property.SetValue(null, obj2, null);
			object obj3 = Activator.CreateInstance(_tTex2D, w, h, Enum.Parse(_tTexFmt, texFormat), false, LinearRead);
			object obj4 = Activator.CreateInstance(_tRect, 0f, 0f, (float)w, (float)h);
			ICall(obj3, "ReadPixels", new Type[3]
			{
				_tRect,
				typeof(int),
				typeof(int)
			}, obj4, 0, 0);
			ICall(obj3, "Apply", Type.EmptyTypes);
			return obj3;
		}
		finally
		{
			property.SetValue(null, value, null);
			SCall(_tRT, "ReleaseTemporary", new Type[1] { _tRT }, obj2);
		}
	}

	private static float ToSrgb(float c)
	{
		if (c <= 0f)
		{
			return 0f;
		}
		if (c >= 1f)
		{
			return 1f;
		}
		return (!(c <= 0.0031308f)) ? (1.055f * (float)Math.Pow(c, 5.0 / 12.0) - 0.055f) : (c * 12.92f);
	}

	public string Save(object sprite, string outRoot, string relPath)
	{
		if (sprite == null || !_tSprite.IsInstanceOfType(sprite))
		{
			return null;
		}
		Object val = (Object)((sprite is Object) ? sprite : null);
		if (object.ReferenceEquals(val, null) || !Object.op_Implicit(val))
		{
			return null;
		}
		string key = val.GetInstanceID().ToString();
		if (_savedBySprite.TryGetValue(key, out var value))
		{
			Reused++;
			return value;
		}
		try
		{
			object obj = Refl.Get(sprite, "texture");
			if (obj == null)
			{
				Failed++;
				LastError = "sprite has no texture";
				return null;
			}
			object obj2 = null;
			try
			{
				obj2 = Refl.Get(sprite, "textureRect");
			}
			catch
			{
			}
			if (obj2 == null)
			{
				obj2 = Refl.Get(sprite, "rect");
			}
			int num = (int)Math.Round(Refl.F(Refl.Get(obj2, "x")));
			int num2 = (int)Math.Round(Refl.F(Refl.Get(obj2, "y")));
			int num3 = (int)Math.Round(Refl.F(Refl.Get(obj2, "width")));
			int num4 = (int)Math.Round(Refl.F(Refl.Get(obj2, "height")));
			if (num3 <= 0 || num4 <= 0)
			{
				Failed++;
				LastError = "empty sprite rect";
				return null;
			}
			object o = Readable(obj);
			Array array = (Array)ICall(o, "GetPixels", new Type[5]
			{
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(int)
			}, num, num2, num3, num4, 0);
			if (Convert)
			{
				Color[] array2 = (Color[])array;
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i].r = ToSrgb(array2[i].r);
					array2[i].g = ToSrgb(array2[i].g);
					array2[i].b = ToSrgb(array2[i].b);
				}
			}
			object obj4 = Activator.CreateInstance(_tTex2D, num3, num4, Enum.Parse(_tTexFmt, "RGBA32"), false, LinearRead);
			ICall(obj4, "SetPixels", new Type[1] { _tColor.MakeArrayType() }, array);
			ICall(obj4, "Apply", Type.EmptyTypes);
			byte[] bytes = (byte[])SCall(_tImgConv, "EncodeToPNG", new Type[1] { _tTex2D }, obj4);
			Destroy(obj4);
			string path = Path.Combine(outRoot, relPath.Replace('/', Path.DirectorySeparatorChar));
			Directory.CreateDirectory(Path.GetDirectoryName(path));
			File.WriteAllBytes(path, bytes);
			Saved++;
			_savedBySprite[key] = relPath;
			return relPath;
		}
		catch (Exception ex)
		{
			Failed++;
			Exception ex2 = ex.InnerException ?? ex;
			LastError = ex2.GetType().Name + ": " + ex2.Message;
			return null;
		}
	}

	private void Destroy(object o)
	{
		try
		{
			SCall(_tObject, "Destroy", new Type[1] { _tObject }, o);
		}
		catch
		{
		}
	}

	public void Dispose()
	{
		foreach (KeyValuePair<object, object> item in _cache)
		{
			Destroy(item.Value);
		}
		_cache.Clear();
	}

	public static string SafeName(string s)
	{
		if (string.IsNullOrEmpty(s))
		{
			return "_";
		}
		char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
		foreach (char oldChar in invalidFileNameChars)
		{
			s = s.Replace(oldChar, '_');
		}
		return s.Replace(' ', '_');
	}
}
internal sealed class DataIndex
{
	public readonly Dictionary<string, JArr> Sources = new Dictionary<string, JArr>();

	public readonly Dictionary<string, JArr> Uses = new Dictionary<string, JArr>();

	public readonly Dictionary<string, JArr> Spawns = new Dictionary<string, JArr>();

	public readonly Dictionary<string, JArr> Refs = new Dictionary<string, JArr>();

	private readonly Registry _r;

	private readonly Origin _o;

	private readonly Loc _loc;

	private static readonly string[] Interesting = new string[31]
	{
		"CharacterDrop", "Container", "Pickable", "PickableItem", "DropOnDestroyed", "MineRock", "MineRock5", "TreeBase", "TreeLog", "LootSpawner",
		"Destructible", "Beehive", "SapCollector", "Smelter", "CookingStation", "Fermenter", "Incinerator", "Trader", "Fireplace", "ShieldGenerator",
		"Turret", "MonsterAI", "OfferingBowl", "ItemStand", "Plant", "Fish", "SpawnArea", "CreatureSpawner", "Humanoid", "Procreation",
		"Growup"
	};

	public DataIndex(Registry r, Origin o, Loc loc)
	{
		_r = r;
		_o = o;
		_loc = loc;
	}

	private static void Add(Dictionary<string, JArr> d, string key, JObj rec)
	{
		if (key != null)
		{
			if (!d.TryGetValue(key, out var value))
			{
				value = (d[key] = new JArr());
			}
			value.Add(rec);
		}
	}

	private string Mod(object o)
	{
		return _o.ModOf(o);
	}

	public JObj Who(object o)
	{
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Refl.GO(o);
		JObj jObj = new JObj();
		if (Object.op_Implicit((Object)(object)val))
		{
			jObj["prefab"] = ((Object)val).name;
		}
		else if (o is Object)
		{
			jObj["object"] = ((Object)o).name;
		}
		string text = DisplayToken(val);
		if (text != null)
		{
			jObj["name"] = _loc.Names(text);
		}
		string text2 = Origin.KeyOf((!Object.op_Implicit((Object)(object)val)) ? o : val);
		if (text2 != null)
		{
			OriginInfo originInfo = _o.Get(text2);
			if (originInfo.IsMod)
			{
				jObj["mod"] = originInfo.Mod ?? "unknown";
			}
		}
		return jObj;
	}

	public static string DisplayToken(GameObject go)
	{
		if (!Object.op_Implicit((Object)(object)go))
		{
			return null;
		}
		string[][] array = new string[11][]
		{
			new string[2] { "Character", "m_name" },
			new string[2] { "Piece", "m_name" },
			new string[2] { "CraftingStation", "m_name" },
			new string[2] { "Pickable", "m_overrideName" },
			new string[2] { "Smelter", "m_name" },
			new string[2] { "CookingStation", "m_name" },
			new string[2] { "Trader", "m_name" },
			new string[2] { "OfferingBowl", "m_name" },
			new string[2] { "Container", "m_name" },
			new string[2] { "MineRock", "m_name" },
			new string[2] { "Location", "m_discoverLabel" }
		};
		foreach (string[] array2 in array)
		{
			string text = Refl.S(Refl.Get(Refl.Comp(go, array2[0]), array2[1]));
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
		}
		object o = Registry.Shared(go);
		string text2 = Refl.S(Refl.Get(o, "m_name"));
		return (!string.IsNullOrEmpty(text2)) ? text2 : null;
	}

	private static string Name(object o)
	{
		return Refl.UName(o);
	}

	public static JArr Requirements(object reqs, Func<object, JObj> who)
	{
		JArr jArr = new JArr();
		foreach (object item in Refl.Enum(reqs))
		{
			object obj = Refl.Get(item, "m_resItem");
			if (Name(obj) != null)
			{
				JObj jObj = who(obj);
				jObj["amount"] = Refl.I(Refl.Get(item, "m_amount"));
				jObj["amountPerLevel"] = Refl.I(Refl.Get(item, "m_amountPerLevel"));
				jObj["recover"] = Refl.B(Refl.Get(item, "m_recover"));
				object obj2 = Refl.Get(item, "m_extraAmountOnlyOneIngredient");
				if (obj2 != null)
				{
					jObj["extraAmountOnlyOneIngredient"] = Refl.I(obj2);
				}
				jArr.Add(jObj);
			}
		}
		return jArr;
	}

	public JObj Station(object station)
	{
		if (Name(station) == null)
		{
			return null;
		}
		JObj jObj = Who(station);
		string text = Refl.S(Refl.Get(station, "m_name"));
		if (text != null)
		{
			jObj["name"] = _loc.Names(text);
		}
		return jObj;
	}

	public void BuildRecipes()
	{
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		foreach (object recipe in _r.Recipes)
		{
			object obj = Refl.Get(recipe, "m_item");
			string text = Name(obj);
			JObj jObj = new JObj();
			jObj["type"] = "craft";
			jObj["recipe"] = ((Object)recipe).name;
			jObj["enabled"] = Refl.B(Refl.Get(recipe, "m_enabled"));
			jObj["amount"] = Refl.I(Refl.Get(recipe, "m_amount"), 1);
			jObj.Opt("station", Station(Refl.Get(recipe, "m_craftingStation")));
			jObj.Opt("repairStation", Station(Refl.Get(recipe, "m_repairStation")));
			jObj["minStationLevel"] = Refl.I(Refl.Get(recipe, "m_minStationLevel"), 1);
			jObj["requireOnlyOneIngredient"] = Refl.B(Refl.Get(recipe, "m_requireOnlyOneIngredient"));
			object obj2 = Refl.Get(recipe, "m_qualityResultAmountMultiplier");
			if (obj2 != null)
			{
				jObj["qualityResultAmountMultiplier"] = Refl.F(obj2);
			}
			jObj["requirements"] = Requirements(Refl.Get(recipe, "m_resources"), Who);
			string key = Origin.KeyOf(recipe);
			OriginInfo originInfo = _o.Get(key);
			if (originInfo.IsMod)
			{
				jObj["mod"] = originInfo.Mod ?? "unknown";
			}
			if (text != null)
			{
				Add(Sources, text, jObj);
			}
			foreach (object item in Refl.Enum(Refl.Get(recipe, "m_resources")))
			{
				string text2 = Name(Refl.Get(item, "m_resItem"));
				if (text2 != null)
				{
					JObj jObj2 = new JObj();
					jObj2.Add("type", "ingredient");
					jObj2.Add("recipe", jObj["recipe"]);
					JObj jObj3 = jObj2;
					jObj3["result"] = ((obj != null) ? Who(obj) : null);
					jObj3["amount"] = Refl.I(Refl.Get(item, "m_amount"));
					jObj3["amountPerLevel"] = Refl.I(Refl.Get(item, "m_amountPerLevel"));
					jObj3.Opt("station", jObj["station"]);
					jObj3.Opt("mod", jObj["mod"]);
					Add(Uses, text2, jObj3);
				}
			}
		}
		foreach (GameObject value in _r.Prefabs.Values)
		{
			Component val = Refl.Comp(value, "Piece");
			if (!Object.op_Implicit((Object)(object)val))
			{
				continue;
			}
			foreach (object item2 in Refl.Enum(Refl.Get(val, "m_resources")))
			{
				string text3 = Name(Refl.Get(item2, "m_resItem"));
				if (text3 != null)
				{
					JObj jObj2 = new JObj();
					jObj2.Add("type", "buildMaterial");
					jObj2.Add("piece", Who(value));
					JObj jObj4 = jObj2;
					jObj4["amount"] = Refl.I(Refl.Get(item2, "m_amount"));
					jObj4["recover"] = Refl.B(Refl.Get(item2, "m_recover"));
					jObj4.Opt("station", Station(Refl.Get(val, "m_craftingStation")));
					Add(Uses, text3, jObj4);
				}
			}
		}
	}

	public void BuildPrefabs()
	{
		foreach (GameObject value in _r.Prefabs.Values)
		{
			Scan(value, null, children: false, 1f);
		}
	}

	public JArr ScanContainer(GameObject root, JObj where)
	{
		JArr jArr = new JArr();
		Scan(root, where, children: true, 1f, jArr);
		return jArr;
	}

	private void Scan(GameObject go, JObj where, bool children, float chance, JArr found = null)
	{
		if (!Object.op_Implicit((Object)(object)go))
		{
			return;
		}
		string[] interesting = Interesting;
		foreach (string text in interesting)
		{
			Component[] array = Refl.Comps(go, text, children);
			foreach (Component val in array)
			{
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				GameObject gameObject = val.gameObject;
				float num = ((!children) ? 1f : RandomSpawnOdds(val, go));
				JObj jObj = new JObj();
				jObj["from"] = Who((where != null) ? gameObject : go);
				if (where != null)
				{
					jObj["in"] = where;
					jObj["object"] = ((Object)gameObject).name;
					if (num < 1f)
					{
						jObj["presenceChance"] = num;
					}
				}
				jObj["component"] = text;
				try
				{
					Handle(text, val, jObj, found);
				}
				catch (Exception ex)
				{
					jObj["error"] = ex.GetType().Name;
				}
			}
		}
	}

	private static float RandomSpawnOdds(Component c, GameObject root)
	{
		float num = 1f;
		Type type = Refl.T("RandomSpawn");
		if (type == null)
		{
			return 1f;
		}
		Transform val = c.transform;
		while ((Object)(object)val != (Object)null)
		{
			Component component = ((Component)val).gameObject.GetComponent(type);
			if (Object.op_Implicit((Object)(object)component))
			{
				num *= Mathf01(Refl.F(Refl.Get(component, "m_chance"), 100f) / 100f);
			}
			if (object.ReferenceEquals(((Component)val).gameObject, root))
			{
				break;
			}
			val = val.parent;
		}
		return num;
	}

	private static float Mathf01(float v)
	{
		return (v < 0f) ? 0f : ((!(v > 1f)) ? v : 1f);
	}

	private JObj Clone(JObj ctx, string type)
	{
		JObj jObj = new JObj();
		jObj.Add("type", type);
		JObj jObj2 = jObj;
		foreach (KeyValuePair<string, object> item in ctx)
		{
			jObj2[item.Key] = item.Value;
		}
		return jObj2;
	}

	private void Src(string item, JObj rec, JArr found)
	{
		if (item == null)
		{
			return;
		}
		Add(Sources, item, rec);
		if (found == null)
		{
			return;
		}
		JObj jObj = new JObj();
		jObj.Add("item", item);
		JObj jObj2 = jObj;
		foreach (KeyValuePair<s