Decompiled source of IngameWiki v0.3.0

ValheimIngameWiki.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ValheimIngameWiki;

public class InfoCell
{
	public string Label = "";

	public string Value = "";

	public List<string> Links = new List<string>();
}
public class InfoRow
{
	public string Header;

	public bool Stacked;

	public List<InfoCell> Cells = new List<InfoCell>();
}
public class Infobox
{
	public List<InfoRow> Rows = new List<InfoRow>();
}
public static class HtmlInfobox
{
	internal class HNode
	{
		public string Tag;

		public string Class = "";

		public string Style = "";

		public string Title;

		public string Href;

		public string Src;

		public int Width;

		public string Text;

		public int ColSpan = 1;

		public HNode Parent;

		public List<HNode> Kids = new List<HNode>();
	}

	private class Cell
	{
		public bool Th;

		public string Text;

		public List<string> Links = new List<string>();
	}

	private static readonly HashSet<string> Void = new HashSet<string> { "br", "img", "hr", "input", "meta", "link", "wbr", "col", "source" };

	private static readonly Regex AttrRx = new Regex("([a-zA-Z_:][-a-zA-Z0-9_:.]*)\\s*(?:=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s\"'>]+)))?", RegexOptions.Compiled);

	private const int MaxImages = 12;

	private static readonly HashSet<string> BlockTags = new HashSet<string>
	{
		"p", "div", "ul", "ol", "dl", "table", "h1", "h2", "h3", "h4",
		"h5", "h6", "blockquote", "figure"
	};

	public static Infobox Parse(string html, string pageTitle)
	{
		if (string.IsNullOrEmpty(html))
		{
			return null;
		}
		try
		{
			HNode n = Build(html);
			HNode hNode = FindByClass(n, "infobox-root");
			if (hNode != null)
			{
				Infobox infobox = BuildDivInfobox(hNode, pageTitle);
				if (infobox.Rows.Count > 0)
				{
					return infobox;
				}
			}
			HNode hNode2 = FindInfobox(n);
			if (hNode2 == null)
			{
				return null;
			}
			List<HNode> list = new List<HNode>();
			CollectRows(hNode2, list);
			Infobox infobox2 = BuildRows(list, pageTitle);
			return (infobox2.Rows.Count > 0) ? infobox2 : null;
		}
		catch
		{
			return null;
		}
	}

	internal static HNode Build(string s)
	{
		HNode hNode = new HNode
		{
			Tag = "#root"
		};
		HNode hNode2 = hNode;
		int num = 0;
		while (num < s.Length)
		{
			int num2 = s.IndexOf('<', num);
			if (num2 < 0)
			{
				AddText(hNode2, s.Substring(num));
				break;
			}
			if (num2 > num)
			{
				AddText(hNode2, s.Substring(num, num2 - num));
			}
			if (string.CompareOrdinal(s, num2, "<!--", 0, 4) == 0)
			{
				int num3 = s.IndexOf("-->", num2 + 4, StringComparison.Ordinal);
				num = ((num3 < 0) ? s.Length : (num3 + 3));
				continue;
			}
			int num4 = s.IndexOf('>', num2);
			if (num4 < 0)
			{
				break;
			}
			string text = s.Substring(num2 + 1, num4 - num2 - 1);
			num = num4 + 1;
			if (text.Length == 0)
			{
				continue;
			}
			if (text[0] == '/')
			{
				string text2 = text.Substring(1).Trim().ToLowerInvariant();
				HNode hNode3 = hNode2;
				while (hNode3 != null && hNode3.Tag != "#root")
				{
					if (hNode3.Tag == text2)
					{
						hNode2 = hNode3.Parent;
						break;
					}
					hNode3 = hNode3.Parent;
				}
			}
			else
			{
				if (text[0] == '!' || text[0] == '?')
				{
					continue;
				}
				bool flag = text.EndsWith("/");
				int i;
				for (i = 0; i < text.Length && !char.IsWhiteSpace(text[i]) && text[i] != '/'; i++)
				{
				}
				string text3 = text.Substring(0, i).ToLowerInvariant();
				HNode hNode4 = new HNode
				{
					Tag = text3,
					Parent = hNode2
				};
				foreach (Match item in AttrRx.Matches(text.Substring(i)))
				{
					string text4 = (item.Groups[2].Success ? item.Groups[2].Value : (item.Groups[3].Success ? item.Groups[3].Value : item.Groups[4].Value));
					switch (item.Groups[1].Value.ToLowerInvariant())
					{
					case "class":
						hNode4.Class = text4;
						break;
					case "style":
						hNode4.Style = text4;
						break;
					case "title":
						hNode4.Title = WebUtility.HtmlDecode(text4);
						break;
					case "href":
						hNode4.Href = text4;
						break;
					case "src":
						hNode4.Src = WebUtility.HtmlDecode(text4);
						break;
					case "width":
						int.TryParse(text4, out hNode4.Width);
						break;
					case "colspan":
						int.TryParse(text4, out hNode4.ColSpan);
						break;
					}
				}
				hNode2.Kids.Add(hNode4);
				if (text3 == "script" || text3 == "style")
				{
					int num5 = s.IndexOf("</" + text3, num, StringComparison.OrdinalIgnoreCase);
					if (num5 < 0)
					{
						break;
					}
					int num6 = s.IndexOf('>', num5);
					num = ((num6 < 0) ? s.Length : (num6 + 1));
				}
				else if (!flag && !Void.Contains(text3))
				{
					hNode2 = hNode4;
				}
			}
		}
		return hNode;
	}

	private static void AddText(HNode parent, string t)
	{
		parent.Kids.Add(new HNode
		{
			Tag = "#text",
			Text = t,
			Parent = parent
		});
	}

	private static bool HasRow(HNode n)
	{
		foreach (HNode kid in n.Kids)
		{
			if (kid.Tag == "tr" || HasRow(kid))
			{
				return true;
			}
		}
		return false;
	}

	internal static bool IsInfobox(HNode n)
	{
		if (!n.Class.Contains("infobox-root"))
		{
			if (n.Tag == "table" && n.Class.IndexOf("infobox", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return HasRow(n);
			}
			return false;
		}
		return true;
	}

	private static bool Has(HNode n, string cls)
	{
		return (" " + n.Class + " ").Contains(" " + cls + " ");
	}

	private static HNode FindByClass(HNode n, string cls)
	{
		if (Has(n, cls))
		{
			return n;
		}
		foreach (HNode kid in n.Kids)
		{
			HNode hNode = FindByClass(kid, cls);
			if (hNode != null)
			{
				return hNode;
			}
		}
		return null;
	}

	private static void ExtractLabel(HNode n, StringBuilder sb, List<string> links)
	{
		if (n.Tag == "#text")
		{
			sb.Append(Regex.Replace(WebUtility.HtmlDecode(n.Text).Replace('\u00a0', ' '), "\\s+", " "));
		}
		else
		{
			if (n.Tag == "script" || n.Tag == "style" || n.Tag == "sup" || Has(n, "mw-collapsible-content"))
			{
				return;
			}
			if (n.Tag == "a" && n.Title != null && n.Href != null && !n.Class.Contains("new") && (n.Href.StartsWith("/w/") || n.Href.StartsWith("/wiki/")) && n.Title.IndexOf(':') < 0 && !links.Contains(n.Title))
			{
				links.Add(n.Title);
			}
			foreach (HNode kid in n.Kids)
			{
				ExtractLabel(kid, sb, links);
			}
		}
	}

	private static InfoCell DivCell(HNode row)
	{
		InfoCell infoCell = new InfoCell();
		foreach (HNode kid in row.Kids)
		{
			if (Has(kid, "infobox-row-label"))
			{
				StringBuilder stringBuilder = new StringBuilder();
				ExtractLabel(kid, stringBuilder, new List<string>());
				infoCell.Label = Clean(stringBuilder.ToString()).Replace('\n', ' ');
			}
			else if (Has(kid, "infobox-row-value"))
			{
				StringBuilder stringBuilder2 = new StringBuilder();
				Extract(kid, stringBuilder2, infoCell.Links);
				infoCell.Value = Clean(stringBuilder2.ToString());
			}
		}
		return infoCell;
	}

	private static void DivGroup(HNode group, Infobox info)
	{
		foreach (HNode kid in group.Kids)
		{
			if (Has(kid, "infobox-header"))
			{
				StringBuilder stringBuilder = new StringBuilder();
				Extract(kid, stringBuilder, new List<string>());
				string text = Clean(stringBuilder.ToString());
				if (text.Length > 0)
				{
					info.Rows.Add(new InfoRow
					{
						Header = text
					});
				}
			}
			else if (Has(kid, "infobox-row-container"))
			{
				InfoCell infoCell = DivCell(kid);
				if (infoCell.Label.Length != 0 || infoCell.Value.Length != 0)
				{
					InfoRow infoRow = new InfoRow();
					infoRow.Cells.Add(infoCell);
					info.Rows.Add(infoRow);
				}
			}
			else
			{
				if (!Has(kid, "infobox-group"))
				{
					continue;
				}
				if (Has(kid, "horizontal"))
				{
					InfoRow infoRow2 = new InfoRow
					{
						Stacked = true
					};
					foreach (HNode kid2 in kid.Kids)
					{
						if (Has(kid2, "infobox-row-container"))
						{
							InfoCell infoCell2 = DivCell(kid2);
							if (infoCell2.Label.Length > 0 || infoCell2.Value.Length > 0)
							{
								infoRow2.Cells.Add(infoCell2);
							}
						}
					}
					if (infoRow2.Cells.Count > 0)
					{
						info.Rows.Add(infoRow2);
					}
				}
				else
				{
					DivGroup(kid, info);
				}
			}
		}
	}

	private static Infobox BuildDivInfobox(HNode root, string pageTitle)
	{
		Infobox infobox = new Infobox();
		DivGroup(root, infobox);
		return infobox;
	}

	private static HNode FindInfobox(HNode n)
	{
		if (n.Tag == "table" && n.Class.IndexOf("infobox", StringComparison.OrdinalIgnoreCase) >= 0 && HasRow(n))
		{
			return n;
		}
		foreach (HNode kid in n.Kids)
		{
			HNode hNode = FindInfobox(kid);
			if (hNode != null)
			{
				return hNode;
			}
		}
		return null;
	}

	internal static bool Skipped(HNode n)
	{
		if (n.Tag == "script" || n.Tag == "style" || n.Tag == "sup")
		{
			return true;
		}
		if (n.Class.Contains("tabbernav") || n.Class.Contains("tabber__tabs") || n.Class.Contains("mw-collapsible-toggle"))
		{
			return true;
		}
		if (n.Style.Replace(" ", "").Contains("display:none"))
		{
			return true;
		}
		return false;
	}

	private static bool IsPanel(HNode n)
	{
		if (!n.Class.Contains("tabbertab"))
		{
			return n.Class.Contains("tabber__panel");
		}
		return true;
	}

	internal static IEnumerable<HNode> Kids(HNode n)
	{
		bool seenPanel = false;
		foreach (HNode kid in n.Kids)
		{
			if (Skipped(kid))
			{
				continue;
			}
			if (IsPanel(kid))
			{
				if (seenPanel)
				{
					continue;
				}
				seenPanel = true;
			}
			yield return kid;
		}
	}

	private static void CollectRows(HNode n, List<HNode> rows)
	{
		foreach (HNode item in Kids(n))
		{
			if (item.Tag == "tr")
			{
				rows.Add(item);
			}
			else if (item.Tag != "td" && item.Tag != "th")
			{
				CollectRows(item, rows);
			}
		}
	}

	internal static void Extract(HNode n, StringBuilder sb, List<string> links)
	{
		if (n.Tag == "#text")
		{
			sb.Append(Regex.Replace(WebUtility.HtmlDecode(n.Text).Replace('\u00a0', ' '), "\\s+", " "));
			return;
		}
		if (n.Tag == "br")
		{
			sb.Append('\n');
			return;
		}
		if (n.Tag == "li")
		{
			Newline(sb);
			sb.Append("• ");
		}
		if (n.Tag == "tr")
		{
			Newline(sb);
		}
		if ((n.Tag == "td" || n.Tag == "th") && n.Parent != null && n.Parent.Tag == "tr" && n.Parent.Kids.IndexOf(n) > 0 && sb.Length > 0 && sb[sb.Length - 1] != '\n' && sb[sb.Length - 1] != ' ')
		{
			sb.Append(": ");
		}
		if (n.Tag == "a" && n.Title != null && n.Href != null && !n.Class.Contains("new") && (n.Href.StartsWith("/w/") || n.Href.StartsWith("/wiki/")) && n.Title.IndexOf(':') < 0 && !links.Contains(n.Title))
		{
			links.Add(n.Title);
		}
		foreach (HNode item in Kids(n))
		{
			Extract(item, sb, links);
		}
		if (n.Tag == "li" || n.Tag == "p" || n.Tag == "div" || n.Tag == "tr")
		{
			Newline(sb);
		}
	}

	internal static void Newline(StringBuilder sb)
	{
		if (sb.Length > 0 && sb[sb.Length - 1] != '\n')
		{
			sb.Append('\n');
		}
	}

	internal static string Clean(string s)
	{
		string[] array = s.Split(new char[1] { '\n' });
		StringBuilder stringBuilder = new StringBuilder();
		string[] array2 = array;
		for (int i = 0; i < array2.Length; i++)
		{
			string text = array2[i].Trim();
			if (text.Length != 0)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append(text);
			}
		}
		return stringBuilder.ToString();
	}

	private static List<Cell> Cells(HNode tr)
	{
		List<Cell> list = new List<Cell>();
		foreach (HNode item in Kids(tr))
		{
			if (!(item.Tag != "th") || !(item.Tag != "td"))
			{
				StringBuilder stringBuilder = new StringBuilder();
				Cell cell = new Cell
				{
					Th = (item.Tag == "th")
				};
				Extract(item, stringBuilder, cell.Links);
				cell.Text = Clean(stringBuilder.ToString());
				if (cell.Text.Length > 0)
				{
					list.Add(cell);
				}
			}
		}
		return list;
	}

	private static Infobox BuildRows(List<HNode> trs, string pageTitle)
	{
		Infobox infobox = new Infobox();
		List<List<Cell>> list = new List<List<Cell>>();
		foreach (HNode tr in trs)
		{
			List<Cell> list2 = Cells(tr);
			if (list2.Count > 0)
			{
				list.Add(list2);
			}
		}
		for (int i = 0; i < list.Count; i++)
		{
			List<Cell> list3 = list[i];
			bool flag = list3.TrueForAll((Cell c) => c.Th);
			bool flag2 = list3.TrueForAll((Cell c) => !c.Th);
			List<Cell> list4 = ((i + 1 < list.Count) ? list[i + 1] : null);
			bool flag3 = list4?.TrueForAll((Cell c) => !c.Th) ?? false;
			if (flag && list4 != null && flag3 && list4.Count == list3.Count)
			{
				InfoRow infoRow = new InfoRow
				{
					Stacked = true
				};
				for (int num = 0; num < list3.Count; num++)
				{
					infoRow.Cells.Add(new InfoCell
					{
						Label = list3[num].Text,
						Value = list4[num].Text,
						Links = list4[num].Links
					});
				}
				infobox.Rows.Add(infoRow);
				i++;
				continue;
			}
			if (flag)
			{
				string text = string.Join(" / ", list3.ConvertAll((Cell c) => c.Text).ToArray());
				if (infobox.Rows.Count != 0 || !string.Equals(text, pageTitle, StringComparison.OrdinalIgnoreCase))
				{
					infobox.Rows.Add(new InfoRow
					{
						Header = text
					});
				}
				continue;
			}
			if (flag2)
			{
				InfoRow infoRow2 = new InfoRow
				{
					Stacked = true
				};
				foreach (Cell item in list3)
				{
					infoRow2.Cells.Add(new InfoCell
					{
						Value = item.Text,
						Links = item.Links
					});
				}
				infobox.Rows.Add(infoRow2);
				continue;
			}
			InfoCell infoCell = new InfoCell();
			StringBuilder stringBuilder = new StringBuilder();
			foreach (Cell item2 in list3)
			{
				if (item2.Th && infoCell.Label.Length == 0)
				{
					infoCell.Label = item2.Text;
					continue;
				}
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append(item2.Text);
				infoCell.Links.AddRange(item2.Links);
			}
			infoCell.Value = stringBuilder.ToString();
			InfoRow infoRow3 = new InfoRow();
			infoRow3.Cells.Add(infoCell);
			infobox.Rows.Add(infoRow3);
		}
		return infobox;
	}

	private static bool Ignored(HNode n)
	{
		string text = n.Class;
		if (!text.Contains("toc") && !text.Contains("navbox") && !text.Contains("catlinks") && !text.Contains("mw-editsection") && !text.Contains("printfooter") && !text.Contains("mw-empty-elt"))
		{
			return n.Tag == "noscript";
		}
		return true;
	}

	public static List<WikiSection> ParseSections(string html)
	{
		if (string.IsNullOrEmpty(html))
		{
			return null;
		}
		try
		{
			HNode hNode = Build(html);
			HNode obj = FindContent(hNode) ?? hNode;
			List<WikiSection> sections = new List<WikiSection>();
			WikiSection cur = new WikiSection();
			StringBuilder text = new StringBuilder();
			Action flush = delegate
			{
				cur.Text = Regex.Replace(Clean(text.ToString()), "\n{3,}", "\n\n");
				if (cur.Heading != null || cur.Text.Length > 0 || cur.Images.Count > 0 || cur.Tables.Count > 0)
				{
					sections.Add(cur);
				}
				text.Length = 0;
			};
			Action<HNode> walk = null;
			walk = delegate(HNode n)
			{
				foreach (HNode item in Kids(n))
				{
					if (!(item.Tag == "#text") && !Ignored(item) && !IsInfobox(item))
					{
						if (item.Tag.Length == 2 && item.Tag[0] == 'h' && item.Tag[1] >= '1' && item.Tag[1] <= '6')
						{
							StringBuilder stringBuilder = new StringBuilder();
							Extract(item, stringBuilder, new List<string>());
							string text2 = Regex.Replace(stringBuilder.ToString(), "\\[edit\\]", "").Trim();
							if (text2.Length != 0)
							{
								flush();
								cur = new WikiSection
								{
									Heading = text2,
									Level = item.Tag[1] - 48
								};
							}
						}
						else if (item.Tag == "table")
						{
							List<List<string>> list = TableRows(item, cur.Links);
							if (list.Count > 0)
							{
								cur.Tables.Add(list);
							}
						}
						else if (BlockTags.Contains(item.Tag) && HasBlockChild(item))
						{
							Newline(text);
							walk(item);
						}
						else if (item.Tag == "div" || item.Tag == "p" || item.Tag == "ul" || item.Tag == "ol" || item.Tag == "dl" || item.Tag == "blockquote" || item.Tag == "figure" || item.Tag == "a" || item.Tag == "span")
						{
							Extract(item, text, cur.Links);
							Newline(text);
							AddImages(item, cur);
						}
					}
				}
			};
			walk(obj);
			flush();
			foreach (WikiSection s in sections)
			{
				s.Links.RemoveAll((string l) => s.Heading == l);
			}
			return sections;
		}
		catch
		{
			return null;
		}
	}

	private static HNode FindContent(HNode n)
	{
		if (n.Class.Contains("mw-parser-output"))
		{
			return n;
		}
		foreach (HNode kid in n.Kids)
		{
			HNode hNode = FindContent(kid);
			if (hNode != null)
			{
				return hNode;
			}
		}
		return null;
	}

	private static bool HasBlockChild(HNode n)
	{
		foreach (HNode kid in n.Kids)
		{
			if (kid.Tag != "#text" && (BlockTags.Contains(kid.Tag) || (kid.Tag != "a" && kid.Tag != "span" && HasBlockChild(kid))))
			{
				return true;
			}
		}
		return false;
	}

	private static void AddImages(HNode n, WikiSection sec)
	{
		foreach (HNode item in Kids(n))
		{
			if (item.Tag == "img" && !string.IsNullOrEmpty(item.Src) && sec.Images.Count < 12 && (item.Width == 0 || item.Width >= 24))
			{
				string text = item.Src;
				if (text.StartsWith("//"))
				{
					text = "https:" + text;
				}
				else if (text.StartsWith("/"))
				{
					text = "https://valheim.weirdgloop.org" + text;
				}
				if (text.IndexOf(".svg", StringComparison.OrdinalIgnoreCase) < 0 && !sec.Images.Contains(text))
				{
					sec.Images.Add(text);
				}
			}
			else
			{
				AddImages(item, sec);
			}
		}
	}

	private static List<List<string>> TableRows(HNode table, List<string> links)
	{
		List<HNode> list = new List<HNode>();
		CollectRows(table, list);
		List<List<string>> list2 = new List<List<string>>();
		foreach (HNode item in list)
		{
			List<string> list3 = new List<string>();
			foreach (HNode item2 in Kids(item))
			{
				if (!(item2.Tag != "th") || !(item2.Tag != "td"))
				{
					StringBuilder stringBuilder = new StringBuilder();
					Extract(item2, stringBuilder, links);
					list3.Add(Clean(stringBuilder.ToString()).Replace('\n', ' '));
				}
			}
			if (list3.Exists((string c) => c.Length > 0))
			{
				list2.Add(list3);
			}
		}
		return list2;
	}
}
public static class MiniJson
{
	public static object Parse(string json)
	{
		int i = 0;
		try
		{
			return Value(json, ref i);
		}
		catch
		{
			return null;
		}
	}

	public static string Str(object o, string key)
	{
		if (!(o is Dictionary<string, object> dictionary) || !dictionary.TryGetValue(key, out var value))
		{
			return null;
		}
		return value as string;
	}

	public static Dictionary<string, object> Obj(object o, string key)
	{
		if (!(o is Dictionary<string, object> dictionary) || !dictionary.TryGetValue(key, out var value))
		{
			return null;
		}
		return value as Dictionary<string, object>;
	}

	public static List<object> List(object o, string key)
	{
		if (!(o is Dictionary<string, object> dictionary) || !dictionary.TryGetValue(key, out var value))
		{
			return null;
		}
		return value as List<object>;
	}

	public static double Num(object o, string key, double def = 0.0)
	{
		if (o is Dictionary<string, object> dictionary && dictionary.TryGetValue(key, out var value) && value is double)
		{
			return (double)value;
		}
		return def;
	}

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

	private static object Value(string s, ref int i)
	{
		Ws(s, ref i);
		switch (s[i])
		{
		case '{':
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			i++;
			Ws(s, ref i);
			if (s[i] == '}')
			{
				i++;
				return dictionary;
			}
			do
			{
				Ws(s, ref i);
				string key = String(s, ref i);
				Ws(s, ref i);
				i++;
				dictionary[key] = Value(s, ref i);
				Ws(s, ref i);
			}
			while (s[i++] != '}');
			return dictionary;
		}
		case '[':
		{
			List<object> list = new List<object>();
			i++;
			Ws(s, ref i);
			if (s[i] == ']')
			{
				i++;
				return list;
			}
			do
			{
				list.Add(Value(s, ref i));
				Ws(s, ref i);
			}
			while (s[i++] != ']');
			return list;
		}
		case '"':
			return String(s, ref i);
		default:
		{
			if (s.Length - i >= 4 && string.CompareOrdinal(s, i, "true", 0, 4) == 0)
			{
				i += 4;
				return true;
			}
			if (s.Length - i >= 5 && string.CompareOrdinal(s, i, "false", 0, 5) == 0)
			{
				i += 5;
				return false;
			}
			if (s.Length - i >= 4 && 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 String(string s, ref int i)
	{
		StringBuilder stringBuilder = new StringBuilder();
		i++;
		while (s[i] != '"')
		{
			char c = s[i++];
			if (c != '\\')
			{
				stringBuilder.Append(c);
				continue;
			}
			c = s[i++];
			switch (c)
			{
			case 'n':
				stringBuilder.Append('\n');
				break;
			case 't':
				stringBuilder.Append('\t');
				break;
			case 'u':
				stringBuilder.Append((char)int.Parse(s.Substring(i, 4), NumberStyles.HexNumber));
				i += 4;
				break;
			default:
				stringBuilder.Append(c);
				break;
			case 'b':
			case 'f':
			case 'r':
				break;
			}
		}
		i++;
		return stringBuilder.ToString();
	}
}
[BepInPlugin("srcrowder.valheim.ingamewiki", "Valheim Ingame Wiki", "0.3.0")]
[DefaultExecutionOrder(-32000)]
public class Plugin : BaseUnityPlugin
{
	[HarmonyPatch]
	private static class InputPatches
	{
		[HarmonyPatch(typeof(Player), "TakeInput")]
		[HarmonyPostfix]
		private static void PlayerTakeInput(ref bool __result)
		{
			if (Visible)
			{
				__result = false;
			}
		}

		[HarmonyPatch(typeof(PlayerController), "TakeInput")]
		[HarmonyPostfix]
		private static void ControllerTakeInput(ref bool __result)
		{
			if (Visible)
			{
				__result = false;
			}
		}

		[HarmonyPatch(typeof(Menu), "Update")]
		[HarmonyPrefix]
		private static bool MenuUpdate()
		{
			return !Visible;
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
		[HarmonyPrefix]
		private static bool CameraCapture()
		{
			return !Visible;
		}

		internal static bool SkipWhenVisible()
		{
			return !Visible;
		}

		internal static void NoScroll(ref float __result)
		{
			if (Visible)
			{
				__result = 0f;
			}
		}
	}

	private class Styles
	{
		public static readonly Color GoldC = new Color(0.83f, 0.62f, 0.25f);

		public static readonly Texture2D Gold = Solid(GoldC);

		public static readonly Texture2D Accent = Solid(new Color(0.85f, 0.4f, 0.15f));

		public static readonly Texture2D Line = Solid(new Color(0.3f, 0.22f, 0.1f));

		private static readonly Color Text = new Color(0.92f, 0.88f, 0.8f);

		public GUIStyle Window;

		public GUIStyle Panel;

		public GUIStyle Title;

		public GUIStyle PageTitle;

		public GUIStyle Button;

		public GUIStyle Input;

		public GUIStyle Muted;

		public GUIStyle Centered;

		public GUIStyle Row;

		public GUIStyle RowSelected;

		public GUIStyle RowTitle;

		public GUIStyle RowSummary;

		public GUIStyle Body;

		public GUIStyle Cell;

		public GUIStyle Chip;

		public GUIStyle InfoHead;

		public GUIStyle InfoLabel;

		public GUIStyle InfoLabelC;

		public GUIStyle InfoValue;

		public GUIStyle InfoValueC;

		private readonly GUIStyle[] heads = (GUIStyle[])(object)new GUIStyle[4];

		public GUIStyle Heading(int level)
		{
			return heads[Mathf.Clamp(level - 2, 0, 3)];
		}

		private static Texture2D Solid(Color c)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, c);
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		private static Texture2D Border(Color fill, Color border)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(8, 8);
			for (int i = 0; i < 8; i++)
			{
				for (int j = 0; j < 8; j++)
				{
					val.SetPixel(i, j, (i == 0 || j == 0 || i == 7 || j == 7) ? border : fill);
				}
			}
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		public Styles()
		{
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			//IL_0125: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			//IL_015e: Expected O, but got Unknown
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Expected O, but got Unknown
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_0368: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_039b: Expected O, but got Unknown
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_03da: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Expected O, but got Unknown
			//IL_0412: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0446: Expected O, but got Unknown
			//IL_0451: Unknown result type (might be due to invalid IL or missing references)
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Unknown result type (might be due to invalid IL or missing references)
			//IL_046a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0474: Expected O, but got Unknown
			//IL_0479: Expected O, but got Unknown
			//IL_048e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0502: Unknown result type (might be due to invalid IL or missing references)
			//IL_0516: Unknown result type (might be due to invalid IL or missing references)
			//IL_0520: Expected O, but got Unknown
			//IL_052b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0530: Unknown result type (might be due to invalid IL or missing references)
			//IL_0538: Unknown result type (might be due to invalid IL or missing references)
			//IL_053f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0544: Unknown result type (might be due to invalid IL or missing references)
			//IL_054e: Expected O, but got Unknown
			//IL_0553: Expected O, but got Unknown
			//IL_0568: Unknown result type (might be due to invalid IL or missing references)
			//IL_056d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0583: Unknown result type (might be due to invalid IL or missing references)
			//IL_0588: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d9: Expected O, but got Unknown
			//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f8: Expected O, but got Unknown
			//IL_05fd: Expected O, but got Unknown
			//IL_0612: Unknown result type (might be due to invalid IL or missing references)
			//IL_0626: Unknown result type (might be due to invalid IL or missing references)
			//IL_063f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0644: Unknown result type (might be due to invalid IL or missing references)
			//IL_065d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0662: Unknown result type (might be due to invalid IL or missing references)
			//IL_0678: Unknown result type (might be due to invalid IL or missing references)
			//IL_0682: Expected O, but got Unknown
			//IL_0691: Unknown result type (might be due to invalid IL or missing references)
			//IL_0696: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			Font val = null;
			Font[] array = Resources.FindObjectsOfTypeAll<Font>();
			foreach (Font val2 in array)
			{
				if (((Object)val2).name == "AveriaSerifLibre-Regular")
				{
					val = val2;
					break;
				}
			}
			Font val3 = null;
			array = Resources.FindObjectsOfTypeAll<Font>();
			foreach (Font val4 in array)
			{
				if (((Object)val4).name == "Norse" || ((Object)val4).name == "Norsebold")
				{
					val3 = val4;
					break;
				}
			}
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = val;
			}
			Color fill = default(Color);
			((Color)(ref fill))..ctor(0.07f, 0.05f, 0.035f, 0.96f);
			Color fill2 = default(Color);
			((Color)(ref fill2))..ctor(0.12f, 0.09f, 0.06f, 0.9f);
			Color border = default(Color);
			((Color)(ref border))..ctor(0.55f, 0.4f, 0.17f);
			Window = new GUIStyle(GUI.skin.window)
			{
				padding = new RectOffset(0, 0, 0, 0),
				border = new RectOffset(2, 2, 2, 2)
			};
			SetBg(Window, Border(fill, border));
			Panel = new GUIStyle(GUI.skin.box)
			{
				border = new RectOffset(2, 2, 2, 2)
			};
			SetBg(Panel, Border(fill2, new Color(0.3f, 0.22f, 0.1f)));
			Title = Label(val3, 24, GoldC, (FontStyle)0);
			PageTitle = Label(val3, 24, GoldC, (FontStyle)0);
			Muted = Label(val, 13, new Color(0.65f, 0.6f, 0.5f), (FontStyle)2);
			Centered = Label(val, 16, new Color(0.65f, 0.6f, 0.5f), (FontStyle)2);
			Centered.alignment = (TextAnchor)4;
			Body = Label(val, 15, Text, (FontStyle)0);
			Body.wordWrap = true;
			Cell = Label(val, 13, Text, (FontStyle)0);
			Cell.wordWrap = true;
			RowTitle = Label(val3, 16, GoldC, (FontStyle)0);
			RowSummary = Label(val, 12, new Color(0.78f, 0.74f, 0.66f), (FontStyle)0);
			RowSummary.wordWrap = true;
			RowSummary.clipping = (TextClipping)1;
			for (int j = 0; j < heads.Length; j++)
			{
				heads[j] = Label(val3, 22 - j * 3, (Color)((j == 0) ? GoldC : new Color(0.9f, 0.75f, 0.45f)), (FontStyle)0);
				heads[j].wordWrap = true;
			}
			Button = new GUIStyle(GUI.skin.button)
			{
				fontSize = 14,
				font = val,
				alignment = (TextAnchor)4
			};
			SetBg(Button, Border(new Color(0.2f, 0.14f, 0.08f), border), Border(new Color(0.32f, 0.22f, 0.1f), GoldC), Border(new Color(0.4f, 0.28f, 0.12f), GoldC));
			SetText(Button, Text);
			Button.border = new RectOffset(2, 2, 2, 2);
			InfoHead = Label(val, 15, new Color(0.1f, 0.05f, 0.02f), (FontStyle)1);
			InfoHead.alignment = (TextAnchor)4;
			InfoHead.wordWrap = true;
			InfoLabel = Label(val, 13, GoldC, (FontStyle)1);
			InfoLabel.wordWrap = true;
			InfoLabelC = new GUIStyle(InfoLabel)
			{
				alignment = (TextAnchor)1
			};
			InfoValue = Label(val, 13, Text, (FontStyle)0);
			InfoValue.wordWrap = true;
			InfoValueC = new GUIStyle(InfoValue)
			{
				alignment = (TextAnchor)1
			};
			Chip = new GUIStyle(GUI.skin.button)
			{
				fontSize = 13,
				font = val,
				padding = new RectOffset(8, 8, 2, 2)
			};
			SetBg(Chip, Border(new Color(0.1f, 0.12f, 0.2f), new Color(0.4f, 0.45f, 0.7f)), Border(new Color(0.16f, 0.2f, 0.33f), GoldC), Border(new Color(0.2f, 0.25f, 0.4f), GoldC));
			SetText(Chip, new Color(0.65f, 0.78f, 1f));
			Chip.border = new RectOffset(2, 2, 2, 2);
			Input = new GUIStyle(GUI.skin.textField)
			{
				fontSize = 15,
				font = val,
				padding = new RectOffset(8, 8, 6, 6)
			};
			SetBg(Input, Border(new Color(0.04f, 0.03f, 0.02f), border), Border(new Color(0.04f, 0.03f, 0.02f), GoldC), Border(new Color(0.04f, 0.03f, 0.02f), GoldC));
			SetText(Input, Text);
			Input.border = new RectOffset(2, 2, 2, 2);
			Row = new GUIStyle(GUI.skin.button)
			{
				border = new RectOffset(2, 2, 2, 2)
			};
			SetBg(Row, Border(new Color(0.16f, 0.12f, 0.08f), new Color(0.25f, 0.18f, 0.09f)), Border(new Color(0.24f, 0.17f, 0.09f), GoldC), Border(new Color(0.3f, 0.21f, 0.1f), GoldC));
			RowSelected = new GUIStyle(Row);
			Texture2D val5 = Border(new Color(0.28f, 0.2f, 0.09f), GoldC);
			SetBg(RowSelected, val5, val5, val5);
		}

		private static GUIStyle Label(Font f, int size, Color c, FontStyle fs)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = size,
				fontStyle = fs,
				richText = false
			};
			if ((Object)(object)f != (Object)null)
			{
				val.font = f;
			}
			SetText(val, c);
			return val;
		}

		private static void SetBg(GUIStyle s, Texture2D normal, Texture2D hover = null, Texture2D active = null)
		{
			s.normal.background = normal;
			s.onNormal.background = normal;
			s.focused.background = hover ?? normal;
			s.onFocused.background = hover ?? normal;
			s.hover.background = hover ?? normal;
			s.onHover.background = hover ?? normal;
			s.active.background = active ?? hover ?? normal;
			s.onActive.background = active ?? hover ?? normal;
		}

		private static void SetText(GUIStyle s, Color c)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			GUIStyleState normal = s.normal;
			GUIStyleState hover = s.hover;
			GUIStyleState active = s.active;
			Color val = (s.focused.textColor = c);
			Color val3 = (active.textColor = val);
			Color textColor = (hover.textColor = val3);
			normal.textColor = textColor;
			GUIStyleState onNormal = s.onNormal;
			GUIStyleState onHover = s.onHover;
			GUIStyleState onActive = s.onActive;
			val = (s.onFocused.textColor = c);
			val3 = (onActive.textColor = val);
			textColor = (onHover.textColor = val3);
			onNormal.textColor = textColor;
		}
	}

	public const string Guid = "srcrowder.valheim.ingamewiki";

	private ConfigEntry<KeyboardShortcut> toggleKey;

	public static bool Visible;

	private Rect window = new Rect(80f, 60f, 860f, 600f);

	private string query = "";

	private string lastQuery = "";

	private float lastEdit = -1f;

	private string status = "Type to search the wiki.";

	private List<WikiHit> hits = new List<WikiHit>();

	private WikiPage page;

	private string loadingTitle;

	private Vector2 hitsScroll;

	private Vector2 pageScroll;

	private readonly List<string> history = new List<string>();

	private int historyPos = -1;

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

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

	private readonly HashSet<string> texLoading = new HashSet<string>();

	private string pendingOpen;

	private Coroutine searchRoutine;

	private Coroutine pageRoutine;

	private Styles st;

	private void Awake()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Expected O, but got Unknown
		toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Key to open/close the wiki window.");
		Harmony val = new Harmony("srcrowder.valheim.ingamewiki");
		val.PatchAll(typeof(InputPatches));
		TryPatch(val, AccessTools.TypeByName("Chat"), "Update", "SkipWhenVisible");
		TryPatch(val, AccessTools.TypeByName("ZInput"), "GetMouseScrollWheel", "NoScroll", prefix: false);
	}

	private void TryPatch(Harmony harmony, Type type, string method, string patch, bool prefix = true)
	{
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Expected O, but got Unknown
		try
		{
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Type not found for patch " + method));
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Method not found: " + type.Name + "." + method));
				return;
			}
			HarmonyMethod val = new HarmonyMethod(typeof(InputPatches).GetMethod(patch, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
			if (prefix)
			{
				harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Patch failed " + type.Name + "." + method + ": " + ex.Message));
		}
	}

	private void Update()
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (pendingOpen != null)
		{
			string title = pendingOpen;
			pendingOpen = null;
			OpenFromSearch(title);
		}
		KeyboardShortcut value = toggleKey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			Visible = !Visible;
		}
		if (Visible && Input.GetKeyDown((KeyCode)27))
		{
			Visible = false;
		}
		if (Visible && lastEdit >= 0f && Time.unscaledTime - lastEdit > 0.5f)
		{
			lastEdit = -1f;
			RunSearch();
		}
		if (Visible)
		{
			Input.ResetInputAxes();
		}
	}

	private void LateUpdate()
	{
		if (Visible)
		{
			Input.ResetInputAxes();
		}
	}

	private void OnGUI()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Expected O, but got Unknown
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Invalid comparison between Unknown and I4
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		if (Visible)
		{
			if (st == null)
			{
				st = new Styles();
			}
			if ((int)Cursor.lockState != 0 || !Cursor.visible)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
			window = GUI.Window(2003397481, window, new WindowFunction(Draw), "", st.Window);
			if (((Rect)(ref window)).Contains(Event.current.mousePosition) && ((int)Event.current.type == 6 || (int)Event.current.type == 0))
			{
				Event.current.Use();
			}
		}
	}

	private void Draw(int id)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Invalid comparison between Unknown and I4
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Invalid comparison between Unknown and I4
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		//IL_028c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		float width = ((Rect)(ref window)).width;
		float height = ((Rect)(ref window)).height;
		GUI.Label(new Rect(16f, 8f, width - 100f, 30f), "Valheim Wiki", st.Title);
		if (GUI.Button(new Rect(width - 38f, 8f, 28f, 28f), "X", st.Button))
		{
			Visible = false;
		}
		GUI.DragWindow(new Rect(0f, 0f, width - 44f, 40f));
		GUI.enabled = historyPos > 0;
		if (GUI.Button(new Rect(16f, 46f, 32f, 30f), "<", st.Button))
		{
			Navigate(historyPos - 1);
		}
		GUI.enabled = historyPos >= 0 && historyPos < history.Count - 1;
		if (GUI.Button(new Rect(52f, 46f, 32f, 30f), ">", st.Button))
		{
			Navigate(historyPos + 1);
		}
		GUI.enabled = true;
		GUI.SetNextControlName("q");
		string text = GUI.TextField(new Rect(92f, 46f, width - 92f - 16f - 90f, 30f), query, st.Input);
		if (text != query)
		{
			query = text;
			lastEdit = Time.unscaledTime;
		}
		bool flag = (int)Event.current.type == 4 && (int)Event.current.keyCode == 13 && GUI.GetNameOfFocusedControl() == "q";
		if (flag)
		{
			Event.current.Use();
		}
		if (GUI.Button(new Rect(width - 106f, 46f, 90f, 30f), "Search", st.Button) || flag)
		{
			lastEdit = -1f;
			RunSearch();
		}
		GUI.Label(new Rect(16f, 82f, width - 32f, 22f), status, st.Muted);
		float num = 108f;
		float num2 = height - num - 14f;
		DrawResults(new Rect(16f, num, 300f, num2));
		DrawPage(new Rect(326f, num, width - 326f - 16f, num2));
	}

	private void DrawResults(Rect r)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		GUI.Box(r, GUIContent.none, st.Panel);
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref r)).width - 20f, Mathf.Max((float)hits.Count * 66f, ((Rect)(ref r)).height));
		hitsScroll = GUI.BeginScrollView(r, hitsScroll, val);
		Rect val2 = default(Rect);
		for (int i = 0; i < hits.Count; i++)
		{
			WikiHit wikiHit = hits[i];
			((Rect)(ref val2))..ctor(4f, (float)i * 66f + 4f, ((Rect)(ref val)).width - 8f, 62f);
			bool flag = (page != null && page.Title == wikiHit.Title) || loadingTitle == wikiHit.Title;
			if (GUI.Button(val2, GUIContent.none, flag ? st.RowSelected : st.Row))
			{
				OpenFromSearch(wikiHit.Title);
			}
			Texture2D val3 = Tex(wikiHit.ThumbUrl);
			float num = ((Rect)(ref val2)).x + 6f;
			if ((Object)(object)val3 != (Object)null)
			{
				GUI.DrawTexture(new Rect(num, ((Rect)(ref val2)).y + 6f, 48f, 48f), (Texture)(object)val3, (ScaleMode)2);
			}
			float num2 = ((Rect)(ref val2)).x + 60f;
			GUI.Label(new Rect(num2, ((Rect)(ref val2)).y + 2f, ((Rect)(ref val2)).width - 64f, 20f), wikiHit.Title, st.RowTitle);
			GUI.Label(new Rect(num2, ((Rect)(ref val2)).y + 22f, ((Rect)(ref val2)).width - 64f, 38f), wikiHit.Summary, st.RowSummary);
		}
		GUI.EndScrollView();
	}

	private void DrawPage(Rect r)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Expected O, but got Unknown
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Expected O, but got Unknown
		//IL_0245: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_024c: Unknown result type (might be due to invalid IL or missing references)
		//IL_024e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_034e: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b4: Expected O, but got Unknown
		//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0431: Unknown result type (might be due to invalid IL or missing references)
		//IL_043c: Expected O, but got Unknown
		//IL_0448: Unknown result type (might be due to invalid IL or missing references)
		GUI.Box(r, GUIContent.none, st.Panel);
		if (page == null)
		{
			GUI.Label(r, (loadingTitle != null) ? ("Loading " + loadingTitle + "...") : "Select a result to read it here.", st.Centered);
			return;
		}
		float num = ((Rect)(ref r)).width - 36f;
		bool flag = page.Info != null;
		float num2 = (flag ? (num - 250f - 12f) : num);
		float num3 = (flag ? DrawInfobox(page.Info, 0f, 0f, 250f, draw: false) : 0f);
		float num4 = 8f;
		Texture2D val = Tex(page.ImageUrl);
		float num5 = 34f;
		num4 += num5;
		float num6 = (((Object)(object)val != (Object)null) ? Mathf.Min(((Texture)val).height, 200) : 0);
		List<float> list = new List<float>();
		foreach (WikiSection section in page.Sections)
		{
			float num7 = 0f;
			if (section.Heading != null)
			{
				num7 += st.Heading(section.Level).CalcHeight(new GUIContent(section.Heading), num2) + 6f;
			}
			if (section.Text.Length > 0)
			{
				num7 += st.Body.CalcHeight(new GUIContent(section.Text), num2) + 8f;
			}
			num7 += Extras(section, num2, 0f, 0f, draw: false);
			num7 += Chips(section.Links, num2, 0f, 0f, draw: false, label: true);
			list.Add(num7);
			num4 += num7;
		}
		num4 += num6 + 50f;
		if (flag)
		{
			num4 = Mathf.Max(num4, 8f + num5 + num3 + 20f);
		}
		Rect val2 = default(Rect);
		((Rect)(ref val2))..ctor(0f, 0f, ((Rect)(ref r)).width - 20f, num4);
		pageScroll = GUI.BeginScrollView(r, pageScroll, val2);
		float num8 = 8f;
		GUI.Label(new Rect(14f, num8, num - 150f, num5), page.Title, st.PageTitle);
		if (GUI.Button(new Rect(((Rect)(ref val2)).width - 150f, num8 + 2f, 140f, 26f), "Open in browser", st.Button))
		{
			Application.OpenURL(WikiClient.PageUrl(page.Title));
		}
		num8 += num5;
		if (flag)
		{
			DrawInfobox(page.Info, 14f + num2 + 12f, num8, 250f, draw: true);
		}
		if ((Object)(object)val != (Object)null)
		{
			float num9 = Mathf.Min(1f, num6 / (float)((Texture)val).height);
			GUI.DrawTexture(new Rect(14f, num8, (float)((Texture)val).width * num9, (float)((Texture)val).height * num9), (Texture)(object)val, (ScaleMode)2);
			num8 += num6 + 8f;
		}
		for (int i = 0; i < page.Sections.Count; i++)
		{
			WikiSection wikiSection = page.Sections[i];
			if (wikiSection.Heading != null)
			{
				float num10 = st.Heading(wikiSection.Level).CalcHeight(new GUIContent(wikiSection.Heading), num2);
				GUI.Label(new Rect(14f, num8, num2, num10), wikiSection.Heading, st.Heading(wikiSection.Level));
				num8 += num10;
				GUI.DrawTexture(new Rect(14f, num8, num2, 1f), (Texture)(object)Styles.Gold);
				num8 += 5f;
			}
			if (wikiSection.Text.Length > 0)
			{
				float num11 = st.Body.CalcHeight(new GUIContent(wikiSection.Text), num2);
				GUI.Label(new Rect(14f, num8, num2, num11), wikiSection.Text, st.Body);
				num8 += num11 + 8f;
			}
			num8 += Extras(wikiSection, num2, 14f, num8, draw: true);
			num8 += Chips(wikiSection.Links, num2, 14f, num8, draw: true, label: true);
		}
		GUI.EndScrollView();
	}

	private float Extras(WikiSection s, float width, float x0, float y0, bool draw)
	{
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Expected O, but got Unknown
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		float num = 0f;
		if (s.Images.Count > 0)
		{
			float num2 = 0f;
			foreach (string image in s.Images)
			{
				Texture2D val = Tex(image);
				if (num2 + 64f > width && num2 > 0f)
				{
					num2 = 0f;
					num += 70f;
				}
				if (draw && (Object)(object)val != (Object)null)
				{
					GUI.DrawTexture(new Rect(x0 + num2, y0 + num, 64f, 64f), (Texture)(object)val, (ScaleMode)2);
				}
				num2 += 70f;
			}
			num += 72f;
		}
		foreach (List<List<string>> table in s.Tables)
		{
			int num3 = 1;
			foreach (List<string> item in table)
			{
				num3 = Mathf.Max(num3, item.Count);
			}
			float num4 = width / (float)num3;
			foreach (List<string> item2 in table)
			{
				float num5 = 0f;
				for (int i = 0; i < item2.Count; i++)
				{
					num5 = Mathf.Max(num5, st.Cell.CalcHeight(new GUIContent(item2[i]), num4 - 8f));
				}
				num5 += 6f;
				if (draw)
				{
					for (int j = 0; j < item2.Count; j++)
					{
						GUI.Label(new Rect(x0 + (float)j * num4 + 4f, y0 + num + 3f, num4 - 8f, num5 - 3f), item2[j], st.Cell);
					}
					GUI.DrawTexture(new Rect(x0, y0 + num + num5, width, 1f), (Texture)(object)Styles.Line);
				}
				num += num5 + 1f;
			}
			num += 10f;
		}
		return num;
	}

	private float DrawInfobox(Infobox info, float x, float y, float w, bool draw)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Expected O, but got Unknown
		//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c8: Expected O, but got Unknown
		//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e8: Expected O, but got Unknown
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0332: Unknown result type (might be due to invalid IL or missing references)
		//IL_0363: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Expected O, but got Unknown
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Expected O, but got Unknown
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		float num = y;
		if (draw)
		{
			GUI.Box(new Rect(x, y, w, DrawInfobox(info, x, y, w, draw: false)), GUIContent.none, st.Panel);
		}
		foreach (InfoRow row in info.Rows)
		{
			if (row.Header != null)
			{
				float num2 = st.InfoHead.CalcHeight(new GUIContent(row.Header), w - 8f) + 8f;
				if (draw)
				{
					GUI.DrawTexture(new Rect(x, y, w, num2), (Texture)(object)Styles.Accent);
					GUI.Label(new Rect(x + 4f, y + 4f, w - 8f, num2 - 4f), row.Header, st.InfoHead);
				}
				y += num2;
				continue;
			}
			float num3 = 0f;
			int count = row.Cells.Count;
			if (row.Stacked)
			{
				float num4 = w / (float)count;
				for (int i = 0; i < count; i++)
				{
					InfoCell infoCell = row.Cells[i];
					float num5 = x + (float)i * num4;
					float num6 = y + 6f;
					if (infoCell.Label.Length > 0)
					{
						float num7 = st.InfoLabel.CalcHeight(new GUIContent(infoCell.Label), num4 - 12f);
						if (draw)
						{
							GUI.Label(new Rect(num5 + 6f, num6, num4 - 12f, num7), infoCell.Label, st.InfoLabelC);
						}
						num6 += num7;
					}
					float num8 = st.InfoValue.CalcHeight(new GUIContent(infoCell.Value), num4 - 12f);
					if (draw)
					{
						GUI.Label(new Rect(num5 + 6f, num6, num4 - 12f, num8), infoCell.Value, st.InfoValueC);
					}
					num6 += num8;
					num6 += Chips(infoCell.Links, num4 - 12f, num5 + 6f, num6, draw, label: false);
					num3 = Mathf.Max(num3, num6 - y + 6f);
				}
				if (draw)
				{
					for (int j = 1; j < count; j++)
					{
						GUI.DrawTexture(new Rect(x + (float)j * num4, y, 1f, num3), (Texture)(object)Styles.Line);
					}
				}
			}
			else
			{
				InfoCell infoCell2 = row.Cells[0];
				float num9 = w * 0.36f;
				float num10 = w - num9 - 18f;
				float num11 = st.InfoLabel.CalcHeight(new GUIContent(infoCell2.Label), num9 - 6f);
				float num12 = st.InfoValue.CalcHeight(new GUIContent(infoCell2.Value), num10);
				float y2 = y + 6f + num12;
				float num13 = Chips(infoCell2.Links, num10, x + num9 + 6f, y2, draw, label: false);
				if (draw)
				{
					GUI.Label(new Rect(x + 6f, y + 6f, num9 - 6f, num11), infoCell2.Label, st.InfoLabel);
					GUI.Label(new Rect(x + num9 + 6f, y + 6f, num10, num12), infoCell2.Value, st.InfoValue);
				}
				num3 = Mathf.Max(num11, num12 + num13) + 12f;
			}
			if (draw)
			{
				GUI.DrawTexture(new Rect(x, y + num3, w, 1f), (Texture)(object)Styles.Line);
			}
			y += num3 + 1f;
		}
		return y - num;
	}

	private float Chips(List<string> links, float width, float x0, float y0, bool draw, bool label)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Expected O, but got Unknown
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		if (links.Count == 0)
		{
			return 0f;
		}
		float num = 0f;
		float num2 = 0f;
		string text = null;
		if (label && draw)
		{
			GUI.Label(new Rect(x0, y0, width, 18f), "Links:", st.Muted);
		}
		num2 = (label ? 20 : 0);
		foreach (string link in links)
		{
			float num3 = Mathf.Min(st.Chip.CalcSize(new GUIContent(link)).x + 4f, width);
			if (num + num3 > width && num > 0f)
			{
				num = 0f;
				num2 += 30f;
			}
			if (draw && GUI.Button(new Rect(x0 + num, y0 + num2, num3, 24f), link, st.Chip))
			{
				text = link;
			}
			num += num3 + 6f;
		}
		if (text != null)
		{
			pendingOpen = text;
		}
		return num2 + 24f + 10f;
	}

	private void RunSearch()
	{
		string text = query.Trim();
		if (text.Length >= 2 && !(text == lastQuery))
		{
			lastQuery = text;
			status = "Searching...";
			if (searchRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(searchRoutine);
			}
			searchRoutine = ((MonoBehaviour)this).StartCoroutine(WikiClient.Search(text, delegate(List<WikiHit> r)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				hits = r;
				hitsScroll = Vector2.zero;
				status = ((r.Count == 0) ? "No results." : (r.Count + " result(s)."));
			}, delegate(string e)
			{
				status = "Error: " + e;
				lastQuery = "";
			}));
		}
	}

	private void OpenFromSearch(string title)
	{
		if (historyPos < history.Count - 1)
		{
			history.RemoveRange(historyPos + 1, history.Count - historyPos - 1);
		}
		history.Add(title);
		historyPos = history.Count - 1;
		Load(title);
	}

	private void Navigate(int pos)
	{
		if (pos >= 0 && pos < history.Count)
		{
			historyPos = pos;
			Load(history[pos]);
		}
	}

	private void Load(string title)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		pageScroll = Vector2.zero;
		if (pageCache.TryGetValue(title, out var value))
		{
			page = value;
			loadingTitle = null;
			return;
		}
		loadingTitle = title;
		page = null;
		if (pageRoutine != null)
		{
			((MonoBehaviour)this).StopCoroutine(pageRoutine);
		}
		pageRoutine = ((MonoBehaviour)this).StartCoroutine(WikiClient.GetPage(title, delegate(WikiPage p)
		{
			pageCache[title] = p;
			if (loadingTitle == title)
			{
				page = p;
				loadingTitle = null;
			}
		}, delegate(string e)
		{
			if (loadingTitle == title)
			{
				loadingTitle = null;
				status = "Error: " + e;
			}
		}));
	}

	private Texture2D Tex(string url)
	{
		if (string.IsNullOrEmpty(url))
		{
			return null;
		}
		if (textures.TryGetValue(url, out var value))
		{
			return value;
		}
		if (texLoading.Add(url))
		{
			((MonoBehaviour)this).StartCoroutine(WikiClient.GetTexture(url, delegate(Texture2D tx)
			{
				textures[url] = tx;
			}));
		}
		return null;
	}
}
public class WikiHit
{
	public string Title;

	public string Summary;

	public string ThumbUrl;

	public int Index;
}
public class WikiSection
{
	public string Heading;

	public int Level;

	public string Text;

	public List<string> Links = new List<string>();

	public List<string> Images = new List<string>();

	public List<List<List<string>>> Tables = new List<List<List<string>>>();
}
public class WikiPage
{
	public string Title;

	public string ImageUrl;

	public List<WikiSection> Sections = new List<WikiSection>();

	public List<string> Links = new List<string>();

	public Infobox Info;
}
public static class WikiClient
{
	public const string BaseUrl = "https://valheim.weirdgloop.org";

	private const string Api = "https://valheim.weirdgloop.org/api.php";

	private static readonly Regex HeadingRx = new Regex("^(=+)\\s*(.*?)\\s*=+\\s*$");

	public static string PageUrl(string title)
	{
		return "https://valheim.weirdgloop.org/w/" + UnityWebRequest.EscapeURL(title.Replace(' ', '_'));
	}

	private static IEnumerator Get(string url, Action<object> done, Action<string> error)
	{
		UnityWebRequest req = UnityWebRequest.Get(url);
		try
		{
			req.timeout = 15;
			req.SetRequestHeader("User-Agent", "ValheimIngameWiki/0.1 (BepInEx mod)");
			yield return req.SendWebRequest();
			if ((int)req.result != 1)
			{
				error(req.error);
				yield break;
			}
			object obj = MiniJson.Parse(req.downloadHandler.text);
			if (obj == null)
			{
				error("Invalid response");
				yield break;
			}
			done(obj);
		}
		finally
		{
			((IDisposable)req)?.Dispose();
		}
	}

	public static IEnumerator Search(string query, Action<List<WikiHit>> done, Action<string> error)
	{
		return Get("https://valheim.weirdgloop.org/api.php?action=query&format=json&generator=search&gsrlimit=12&gsrnamespace=0&prop=extracts|pageimages&exintro=1&explaintext=1&exlimit=max&exchars=140&piprop=thumbnail&pithumbsize=64&pilimit=max&gsrsearch=" + UnityWebRequest.EscapeURL(query), delegate(object json)
		{
			List<WikiHit> list = new List<WikiHit>();
			Dictionary<string, object> dictionary = MiniJson.Obj(MiniJson.Obj(json, "query"), "pages");
			if (dictionary != null)
			{
				foreach (KeyValuePair<string, object> item in dictionary)
				{
					list.Add(new WikiHit
					{
						Title = MiniJson.Str(item.Value, "title"),
						Summary = (MiniJson.Str(item.Value, "extract") ?? "").Replace('\n', ' ').Trim(),
						ThumbUrl = MiniJson.Str(MiniJson.Obj(item.Value, "thumbnail"), "source"),
						Index = (int)MiniJson.Num(item.Value, "index")
					});
				}
			}
			list.RemoveAll((WikiHit h) => h.Title == null);
			list.Sort((WikiHit a, WikiHit b) => a.Index.CompareTo(b.Index));
			done(list);
		}, error);
	}

	public static IEnumerator GetPage(string title, Action<WikiPage> done, Action<string> error)
	{
		string url = "https://valheim.weirdgloop.org/api.php?action=query&format=json&redirects=1&prop=extracts|pageimages|links&explaintext=1&piprop=thumbnail&pithumbsize=300&pllimit=max&plnamespace=0&titles=" + UnityWebRequest.EscapeURL(title);
		WikiPage page = null;
		string err = null;
		yield return Get(url, delegate(object json)
		{
			Dictionary<string, object> dictionary = MiniJson.Obj(MiniJson.Obj(json, "query"), "pages");
			if (dictionary != null)
			{
				using Dictionary<string, object>.Enumerator enumerator = dictionary.GetEnumerator();
				if (enumerator.MoveNext())
				{
					KeyValuePair<string, object> current = enumerator.Current;
					page = new WikiPage
					{
						Title = (MiniJson.Str(current.Value, "title") ?? title),
						ImageUrl = MiniJson.Str(MiniJson.Obj(current.Value, "thumbnail"), "source")
					};
					ParseSections(MiniJson.Str(current.Value, "extract") ?? "", page);
					List<object> list = MiniJson.List(current.Value, "links");
					if (list != null)
					{
						foreach (object item in list)
						{
							string text = MiniJson.Str(item, "title");
							if (text != null)
							{
								page.Links.Add(text);
							}
						}
					}
					AssignLinks(page);
					if (page.Sections.Count == 0)
					{
						page.Sections.Add(new WikiSection
						{
							Text = "(This page has no text.)"
						});
					}
				}
			}
			if (page == null)
			{
				err = "Page not found";
			}
		}, delegate(string e)
		{
			err = e;
		});
		if (err != null)
		{
			error(err);
			yield break;
		}
		done(page);
		string url2 = "https://valheim.weirdgloop.org/api.php?action=parse&format=json&redirects=1&prop=text&disablelimitreport=1&disableeditsection=1&page=" + UnityWebRequest.EscapeURL(page.Title);
		yield return Get(url2, delegate(object json)
		{
			string html = MiniJson.Str(MiniJson.Obj(MiniJson.Obj(json, "parse"), "text"), "*");
			page.Info = HtmlInfobox.Parse(html, page.Title);
			List<WikiSection> list = HtmlInfobox.ParseSections(html);
			if (list != null && list.Count > 0)
			{
				page.Sections = list;
			}
		}, delegate
		{
		});
	}

	private static void AssignLinks(WikiPage page)
	{
		foreach (WikiSection section in page.Sections)
		{
			string input = section.Heading + " " + section.Text;
			foreach (string link in page.Links)
			{
				if (!(link == page.Title) && !section.Links.Contains(link) && Regex.IsMatch(input, "(?<![\\w])" + Regex.Escape(link) + "(?![\\w])", RegexOptions.IgnoreCase))
				{
					section.Links.Add(link);
				}
			}
		}
	}

	private static void ParseSections(string text, WikiPage page)
	{
		WikiSection cur = new WikiSection();
		StringBuilder body = new StringBuilder();
		Action action = delegate
		{
			cur.Text = Regex.Replace(body.ToString().Trim(), "\n{3,}", "\n\n");
			if (cur.Heading != null || cur.Text.Length > 0)
			{
				page.Sections.Add(cur);
			}
			body.Length = 0;
		};
		string[] array = text.Split(new char[1] { '\n' });
		foreach (string text2 in array)
		{
			Match match = HeadingRx.Match(text2);
			if (match.Success)
			{
				action();
				cur = new WikiSection
				{
					Heading = match.Groups[2].Value,
					Level = match.Groups[1].Length
				};
			}
			else
			{
				body.AppendLine(text2);
			}
		}
		action();
	}

	public static IEnumerator GetTexture(string url, Action<Texture2D> done)
	{
		UnityWebRequest req = UnityWebRequestTexture.GetTexture(url);
		try
		{
			req.timeout = 15;
			yield return req.SendWebRequest();
			if ((int)req.result == 1)
			{
				done(DownloadHandlerTexture.GetContent(req));
			}
		}
		finally
		{
			((IDisposable)req)?.Dispose();
		}
	}
}