Decompiled source of Gooee v1.1.5

Gooee.dll

Decompiled 8 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml.Serialization;
using BepInEx;
using BepInEx.Logging;
using Colossal;
using Colossal.IO.AssetDatabase;
using Colossal.IO.AssetDatabase.Internal;
using Colossal.Localization;
using Colossal.Logging;
using Colossal.OdinSerializer.Utilities;
using Colossal.Reflection;
using Colossal.Serialization.Entities;
using Colossal.UI;
using Colossal.UI.Binding;
using Game;
using Game.Common;
using Game.SceneFlow;
using Game.Settings;
using Game.UI;
using Game.UI.Menu;
using Gooee.Helpers;
using Gooee.Injection;
using Gooee.Patches;
using Gooee.Plugins;
using Gooee.Plugins.Attributes;
using Gooee.Systems;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Unity.Entities;
using UnityEngine;
using cohtml.Net;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Cities2Modding")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Cities2Modding")]
[assembly: AssemblyFileVersion("0.1.1.5")]
[assembly: AssemblyInformationalVersion("0.1.1.5+33c41fb9300aaf8ef4f915879f967d525fb840cd")]
[assembly: AssemblyProduct("Gooee")]
[assembly: AssemblyTitle("Gooee")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Cities2Modding/Gooee")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.5")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Gooee
{
	public abstract class GooeeSettings : Setting
	{
		[SettingsUIHidden]
		public string ID { get; }

		[XmlIgnore]
		[SettingsUIHidden]
		protected abstract string UIResource { get; }

		public GooeeSettings()
		{
			Type type = ((object)this).GetType();
			ID = type.Assembly.GetName().Name + "." + type.Name;
			((Setting)this).ApplyAndSave();
		}

		private static bool Register(Setting instance, string name, bool addPrefix)
		{
			World defaultGameObjectInjectionWorld = World.DefaultGameObjectInjectionWorld;
			OptionsUISystem val = ((defaultGameObjectInjectionWorld != null) ? defaultGameObjectInjectionWorld.GetOrCreateSystemManaged<OptionsUISystem>() : null);
			if (val == null)
			{
				return false;
			}
			val.RegisterSetting(instance, name, addPrefix);
			return true;
		}

		public static GooeeSettings Load(Type type, GooeeSettings defaults = null)
		{
			GooeeSettings gooeeSettings = (GooeeSettings)Activator.CreateInstance(type);
			((Setting)gooeeSettings).SetDefaults();
			AssetDatabase.global.LoadSettings(type.Name, (object)gooeeSettings, (object)defaults);
			return gooeeSettings;
		}

		public static T Load<T>(T defaults = null) where T : GooeeSettings
		{
			Type typeFromHandle = typeof(T);
			T val = Activator.CreateInstance<T>();
			((Setting)val).SetDefaults();
			AssetDatabase.global.LoadSettings(typeFromHandle.Name, (object)val, (object)defaults);
			return val;
		}

		internal void Register(string name, bool addPrefix = false)
		{
			Register((Setting)(object)this, name, addPrefix);
		}

		public void Register()
		{
			Register(ID, addPrefix: true);
		}

		public string GetSettingsLocaleID()
		{
			return "Options.SECTION[" + ID + "]";
		}

		public string GetOptionLabelLocaleID(string optionName)
		{
			return "Options.OPTION[" + ID + "." + optionName + "]";
		}

		public string GetOptionDescLocaleID(string optionName)
		{
			return "Options.OPTION_DESCRIPTION[" + ID + "." + optionName + "]";
		}

		public string GetOptionWarningLocaleID(string optionName)
		{
			return "Options.WARNING[" + ID + "." + optionName + "]";
		}

		public string GetOptionTabLocaleID(string tabName)
		{
			return "Options.TAB[" + ID + "." + tabName + "]";
		}

		public string GetOptionGroupLocaleID(string groupName)
		{
			return "Options.GROUP[" + ID + "." + groupName + "]";
		}

		public string GetEnumValueLocaleID<T>(T value) where T : Enum
		{
			return $"Options.{ID}.[{value}]";
		}

		public override SettingPageData GetPageData(string id, bool addPrefix)
		{
			if (EmbeddedResource.Exists(UIResource, ((object)this).GetType().Assembly))
			{
				string text = EmbeddedResource.LoadText(UIResource, ((object)this).GetType().Assembly);
				if (!string.IsNullOrEmpty(text))
				{
					GooeeSettingsView gooeeSettingsView = GooeeSettingsView.Deserialise(text);
					SettingPageData pageData = ((Setting)this).GetPageData(id, addPrefix);
					pageData.tabs.Clear();
					List<GooeeSettingsGroup> groups = gooeeSettingsView.Groups;
					if (groups != null && groups.Count > 0)
					{
						GenerateGroups(pageData, gooeeSettingsView.Groups);
					}
					{
						foreach (GooeeSettingsTab tab in gooeeSettingsView.Tabs)
						{
							List<GooeeSettingsGroup> groups2 = tab.Groups;
							if (groups2 != null && groups2.Count > 0)
							{
								GenerateGroups(pageData, tab.Groups, tab.Title);
							}
						}
						return pageData;
					}
				}
				return ((Setting)this).GetPageData(id, addPrefix);
			}
			return ((Setting)this).GetPageData(id, addPrefix);
		}

		private void GenerateGroups(SettingPageData pageData, List<GooeeSettingsGroup> groups, string tab = "General")
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Expected O, but got Unknown
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_018c: 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_01b0: Expected O, but got Unknown
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: 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_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Expected O, but got Unknown
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Expected O, but got Unknown
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Expected O, but got Unknown
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Expected O, but got Unknown
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Expected O, but got Unknown
			foreach (GooeeSettingsGroup group in groups)
			{
				if (!string.IsNullOrEmpty(group.Description))
				{
					SettingItemData val = new SettingItemData((WidgetType)8)
					{
						setting = (Setting)(object)this,
						property = (IProxyProperty)new ManualProperty(((object)this).GetType(), typeof(string), group.Description)
						{
							canRead = true,
							canWrite = false,
							getter = (object instance) => group.Description
						},
						simpleGroup = group.Title,
						advancedGroup = group.Title
					};
					pageData[tab].AddItem(val);
					pageData.AddGroup(val.simpleGroup);
					pageData.AddGroupToShowName(val.simpleGroup);
				}
				foreach (GooeeFieldElement field in group.Fields)
				{
					foreach (GooeeSettingElement element in field.Elements)
					{
						GooeeSettingButton button = element as GooeeSettingButton;
						if (button != null)
						{
							SettingItemData val2 = new SettingItemData((WidgetType)1)
							{
								setting = (Setting)(object)this,
								property = (IProxyProperty)new ManualProperty(((object)this).GetType(), typeof(string), button.Content)
								{
									canRead = false,
									canWrite = true,
									attributes = { (Attribute)new SettingsUIButtonAttribute() },
									setter = delegate(object instance, object value)
									{
										((object)(GooeeSettings)instance).GetType().GetMethod(button.Content, BindingFlags.Instance | BindingFlags.Public)?.Invoke(instance, null);
									}
								},
								simpleGroup = group.Title,
								advancedGroup = group.Title
							};
							pageData[tab].AddItem(val2);
							pageData.AddGroup(val2.simpleGroup);
							pageData.AddGroupToShowName(val2.simpleGroup);
						}
						else
						{
							if (element is GooeeSettingSlider)
							{
								continue;
							}
							GooeeSettingCheckBox checkbox = element as GooeeSettingCheckBox;
							if (checkbox != null)
							{
								SettingItemData val3 = new SettingItemData((WidgetType)3)
								{
									setting = (Setting)(object)this,
									property = (IProxyProperty)new ManualProperty(((object)this).GetType(), typeof(string), checkbox.IsChecked)
									{
										canRead = true,
										canWrite = true,
										getter = delegate(object instance)
										{
											GooeeSettings gooeeSettings4 = (GooeeSettings)instance;
											return (bool)((object)gooeeSettings4).GetType().GetProperty(checkbox.IsChecked, BindingFlags.Instance | BindingFlags.Public).GetValue(gooeeSettings4);
										},
										setter = delegate(object instance, object value)
										{
											GooeeSettings gooeeSettings3 = (GooeeSettings)instance;
											((object)gooeeSettings3).GetType().GetProperty(checkbox.IsChecked, BindingFlags.Instance | BindingFlags.Public).SetValue(gooeeSettings3, value);
										}
									},
									simpleGroup = group.Title,
									advancedGroup = group.Title
								};
								pageData[tab].AddItem(val3);
								pageData.AddGroup(val3.simpleGroup);
								pageData.AddGroupToShowName(val3.simpleGroup);
								continue;
							}
							GooeeSettingDropdown dropDown = element as GooeeSettingDropdown;
							if (dropDown != null)
							{
								SettingItemData val4 = new SettingItemData((WidgetType)7)
								{
									setting = (Setting)(object)this,
									property = (IProxyProperty)new ManualProperty(((object)this).GetType(), typeof(string), dropDown.Selected)
									{
										canRead = true,
										canWrite = true,
										attributes = { (Attribute)new SettingsUIDropdownAttribute(((object)this).GetType(), dropDown.Options) },
										getter = delegate(object instance)
										{
											GooeeSettings gooeeSettings2 = (GooeeSettings)instance;
											return (string)((object)gooeeSettings2).GetType().GetProperty(dropDown.Selected, BindingFlags.Instance | BindingFlags.Public).GetValue(gooeeSettings2);
										},
										setter = delegate(object instance, object value)
										{
											GooeeSettings gooeeSettings = (GooeeSettings)instance;
											((object)gooeeSettings).GetType().GetProperty(dropDown.Selected, BindingFlags.Instance | BindingFlags.Public).SetValue(gooeeSettings, value);
										}
									},
									simpleGroup = group.Title,
									advancedGroup = group.Title
								};
								pageData[tab].AddItem(val4);
								pageData.AddGroup(val4.simpleGroup);
								pageData.AddGroupToShowName(val4.simpleGroup);
							}
						}
					}
				}
			}
		}
	}
	public abstract class GooeeSettingElement
	{
	}
	public class GooeeFieldElement
	{
		[XmlAttribute("title")]
		public string Title { get; set; }

		[XmlElement("description")]
		public string Description { get; set; }

		[XmlElement("button", Type = typeof(GooeeSettingButton))]
		[XmlElement("checkbox", Type = typeof(GooeeSettingCheckBox))]
		[XmlElement("select", Type = typeof(GooeeSettingDropdown))]
		[XmlElement("slider", Type = typeof(GooeeSettingSlider))]
		public List<GooeeSettingElement> Elements { get; set; }
	}
	public class GooeeSettingsGroup : GooeeSettingElement
	{
		[XmlAttribute("title")]
		public string Title { get; set; }

		[XmlElement("description")]
		public string Description { get; set; }

		[XmlElement("field")]
		public List<GooeeFieldElement> Fields { get; set; }
	}
	public class GooeeSettingButton : GooeeSettingElement
	{
		[XmlText]
		public string Content { get; set; }

		[XmlAttribute("onClick")]
		public string OnClick { get; set; }
	}
	public class GooeeSettingCheckBox : GooeeSettingElement
	{
		[XmlAttribute("isChecked")]
		public string IsChecked { get; set; }
	}
	public class GooeeSettingDropdown : GooeeSettingElement
	{
		[XmlAttribute("options")]
		public string Options { get; set; }

		[XmlAttribute("selected")]
		public string Selected { get; set; }
	}
	public class GooeeSettingSlider : GooeeSettingElement
	{
		[XmlAttribute("value")]
		public int Value { get; set; }

		[XmlAttribute("min")]
		public int Minimum { get; set; }

		[XmlAttribute("max")]
		public int Maximum { get; set; }
	}
	public class GooeeSettingsTab
	{
		[XmlAttribute("title")]
		public string Title { get; set; }

		[XmlElement("group")]
		public List<GooeeSettingsGroup> Groups { get; set; }
	}
	[XmlRoot("settings")]
	public class GooeeSettingsView
	{
		[XmlElement("group")]
		public List<GooeeSettingsGroup> Groups { get; set; }

		[XmlElement("tab")]
		public List<GooeeSettingsTab> Tabs { get; set; }

		public static GooeeSettingsView Deserialise(string xml)
		{
			if (string.IsNullOrEmpty(xml))
			{
				return null;
			}
			using MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml));
			return (GooeeSettingsView)new XmlSerializer(typeof(GooeeSettingsView)).Deserialize(stream);
		}
	}
	internal class LibrarySettings : GooeeSettings
	{
		[SettingsUIHidden]
		protected override string UIResource => "Gooee.Resources.settings.xml";

		public bool ChangeLog { get; set; }

		public bool AVal { get; set; }

		public bool BVal { get; set; }

		public bool CVal { get; set; }

		public override void SetDefaults()
		{
			ChangeLog = true;
		}

		public void ShowChangeLog()
		{
			GameManager.instance.userInterface.view.View.ExecuteScript("engine.trigger('gooee.resetChangeLog');");
		}
	}
	[BepInPlugin("Gooee", "Gooee", "0.1.1.5")]
	public class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			Harmony obj = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Gooee_Cities2Harmony");
			UIPatches.InstallGameResourceHook(obj);
			MethodBase[] array = obj.GetPatchedMethods().ToArray();
			((BaseUnityPlugin)this).Logger.LogInfo((object)(Environment.NewLine + " @@@@@@@@   @@@@@@    @@@@@@   @@@@@@@@  @@@@@@@@  \r\n@@@@@@@@@  @@@@@@@@  @@@@@@@@  @@@@@@@@  @@@@@@@@  \r\n!@@        @@!  @@@  @@!  @@@  @@!       @@!       \r\n!@!        !@!  @!@  !@!  @!@  !@!       !@!       \r\n!@! @!@!@  @!@  !@!  @!@  !@!  @!!!:!    @!!!:!    \r\n!!! !!@!!  !@!  !!!  !@!  !!!  !!!!!:    !!!!!:    \r\n:!!   !!:  !!:  !!!  !!:  !!!  !!:       !!:       \r\n:!:   !::  :!:  !:!  :!:  !:!  :!:       :!:       \r\n ::: ::::  ::::: ::  ::::: ::   :: ::::   :: ::::  \r\n :: :: :    : :  :    : :  :   : :: ::   : :: ::   \r\n                                                   "));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin Gooee is loaded! Patched methods: " + array.Length));
			MethodBase[] array2 = array;
			foreach (MethodBase methodBase in array2)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched method: " + methodBase.Module.Name + ":" + methodBase.Name));
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Gooee";

		public const string PLUGIN_NAME = "Gooee";

		public const string PLUGIN_VERSION = "0.1.1.5";
	}
}
namespace Gooee.Systems
{
	public class GooeeUISystem : UISystemBase
	{
		private readonly Dictionary<string, (IController Controller, MethodInfo Method)> _toolbarChildSubscribers = new Dictionary<string, (IController, MethodInfo)>();

		private readonly Dictionary<string, List<PluginToolbarChildItem>> _toolbarChildCache = new Dictionary<string, List<PluginToolbarChildItem>>();

		private string _toolbarChildJsonCache;

		private static MethodInfo updateAt = typeof(UpdateSystem).GetMethod("UpdateAt", BindingFlags.Instance | BindingFlags.Public);

		private readonly GooeeLogger _log = GooeeLogger.Get("Gooee");

		private GetterValueBinding<string> _toolbarItemsBinding;

		private bool HasMoveIt { get; set; }

		protected override void OnCreate()
		{
			((UISystemBase)this).OnCreate();
			if (ResourceInjector.InvalidVersion)
			{
				_log.Error("Critical error, mods using Gooee cannot be loaded because the game version has changed. Please ensure you are using the latest version of Gooee and if no new version is out yet please be aware it takes a bit of time to adjust to patch updates. Thank you.");
			}
			else
			{
				ResourceInjector.Inject();
				HelperExtensions.ForEach<IGooeePlugin>((IEnumerable<IGooeePlugin>)PluginLoader.Plugins.Values.OrderBy((IGooeePlugin v) => v.Name), (Action<IGooeePlugin>)ProcessPlugin);
				GameManager.instance.userInterface.view.View.Reload();
			}
			Dictionary<string, (IController Controller, MethodInfo Method)> toolbarChildSubscribers = _toolbarChildSubscribers;
			if (toolbarChildSubscribers != null && toolbarChildSubscribers.Count > 0)
			{
				BuildToolbarChildCache();
				((UISystemBase)this).AddUpdateBinding((IUpdateBinding)(object)(_toolbarItemsBinding = new GetterValueBinding<string>("gooee", "toolbarChildren", (Func<string>)(() => _toolbarChildJsonCache), (IWriter<string>)null, (EqualityComparer<string>)null)));
			}
			((UISystemBase)this).AddUpdateBinding((IUpdateBinding)(object)new GetterValueBinding<bool>("Gooee", "hasMoveIt", (Func<bool>)(() => HasMoveIt), (IWriter<bool>)null, (EqualityComparer<bool>)null));
		}

		protected override void OnGameLoadingComplete(Purpose purpose, GameMode mode)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			((GameSystemBase)this).OnGameLoadingComplete(purpose, mode);
			if ((int)mode == 8)
			{
				HasMoveIt = AppDomain.CurrentDomain.GetAssemblies().SelectMany((Assembly a) => a.GetTypes()).Count((Type t) => t.FullName == "MoveIt.Systems.MIT_System") > 0;
			}
		}

		public void BuildToolbarChildCache(bool forceUpdate = false)
		{
			foreach (KeyValuePair<string, (IController, MethodInfo)> toolbarChildSubscriber in _toolbarChildSubscribers)
			{
				(IController, MethodInfo) value = toolbarChildSubscriber.Value;
				if (value.Item2 == null || value.Item1 == null)
				{
					continue;
				}
				List<PluginToolbarChildItem> list = (List<PluginToolbarChildItem>)value.Item2.Invoke(value.Item1, null);
				if (list != null)
				{
					if (_toolbarChildCache.ContainsKey(toolbarChildSubscriber.Key))
					{
						_toolbarChildCache[toolbarChildSubscriber.Key] = list;
					}
					else
					{
						_toolbarChildCache.Add(toolbarChildSubscriber.Key, list);
					}
				}
			}
			_toolbarChildJsonCache = JsonConvert.SerializeObject((object)_toolbarChildCache);
			if (forceUpdate)
			{
				_toolbarItemsBinding?.TriggerUpdate();
			}
		}

		private void ProcessPlugin(IGooeePlugin plugin)
		{
			PluginLoader.GetControllerTypes(plugin, out var controllerTypes, out var _);
			Type pluginType = plugin.GetType();
			IEnumerable<Attribute> customAttributes = pluginType.GetCustomAttributes();
			customAttributes.FirstOrDefault((Attribute a) => typeof(ControllerTypeAttribute<>).IsAssignableFrom(a.GetType()));
			ProcessPluginLanguagesAndSettings(plugin, pluginType, customAttributes);
			if (controllerTypes != null && controllerTypes.Count > 0)
			{
				PluginToolbarAttribute toolbarAttribute = plugin.GetType().GetCustomAttribute<PluginToolbarAttribute>();
				IGooeePluginWithControllers obj = (IGooeePluginWithControllers)plugin;
				List<IController> controllers = new List<IController>();
				controllerTypes.ForEach(delegate(Type t)
				{
					IEnumerable<ControllerDependsAttribute> customAttributes2 = t.GetCustomAttributes<ControllerDependsAttribute>();
					PropertyInfo? property = t.GetProperty("Plugin", BindingFlags.Instance | BindingFlags.Public);
					IController controller = (IController)((ComponentSystemBase)this).World.GetOrCreateSystemManaged(t);
					property.SetValue(controller, plugin);
					controllers.Add(controller);
					ReflectionUtils.Invoke(updateAt.MakeGenericMethod(controller.GetType()), (object)((ComponentSystemBase)this).World.GetExistingSystemManaged<UpdateSystem>(), new object[1] { (object)(SystemUpdatePhase)22 });
					if (customAttributes2 != null && customAttributes2.Any())
					{
						HelperExtensions.ForEach<ControllerDependsAttribute>(customAttributes2, (Action<ControllerDependsAttribute>)delegate(ControllerDependsAttribute dependency)
						{
							//IL_0018: Unknown result type (might be due to invalid IL or missing references)
							//IL_001e: Invalid comparison between Unknown and I4
							//IL_0052: Unknown result type (might be due to invalid IL or missing references)
							((ComponentSystemBase)this).World.GetOrCreateSystemManaged(dependency.Type);
							if ((int)dependency.UpdatePhase != -1)
							{
								ReflectionUtils.Invoke(updateAt.MakeGenericMethod(dependency.Type), (object)((ComponentSystemBase)this).World.GetExistingSystemManaged<UpdateSystem>(), new object[1] { dependency.UpdatePhase });
							}
						});
					}
					if (toolbarAttribute?.ControllerType == t)
					{
						InternalPluginToolbarItem item = toolbarAttribute.Item;
						if (item.OnGetChildren != null)
						{
							_toolbarChildSubscribers.TryAdd(plugin.Name.ToLowerInvariant(), (controller, item.OnGetChildren));
						}
					}
					controller.OnLoaded();
					_log.Debug("Gooee instantiated controller " + controller.GetType().FullName + " for plugin " + pluginType.FullName);
				});
				obj.Controllers = controllers.ToArray();
			}
			else
			{
				_log.Error("Gooee failed to find any controller types for " + pluginType.FullName);
			}
		}

		private void ProcessPluginLanguagesAndSettings(IGooeePlugin plugin, Type pluginType, IEnumerable<Attribute> customAttributes)
		{
			if (plugin is IGooeeLanguages gooeeLanguages && plugin is IGooeeSettings gooeeSettings)
			{
				GooeeSettingsMenuAttribute gooeeSettingsMenuAttribute = (GooeeSettingsMenuAttribute)customAttributes.FirstOrDefault((Attribute a) => a.GetType() == typeof(GooeeSettingsMenuAttribute));
				if (gooeeSettingsMenuAttribute != null)
				{
					gooeeSettings.Settings = GooeeSettings.Load(gooeeSettingsMenuAttribute.Type);
					gooeeSettings.Settings.Register();
					LocalisationHelper.Load(gooeeLanguages.LanguageResourceFolder, pluginType.Assembly, gooeeSettingsMenuAttribute.Type.Name);
					_log.Debug("Gooee loaded settings for plugin " + pluginType.FullName);
				}
			}
			else if (plugin is IGooeeLanguages gooeeLanguages2)
			{
				LocalisationHelper.Load(gooeeLanguages2.LanguageResourceFolder, pluginType.Assembly);
			}
		}
	}
}
namespace Gooee.Plugins
{
	public abstract class Controller<TModel> : UISystemBase, IController where TModel : class, IModel, IJsonWritable
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static OnSettingsAppliedHandler <>9__40_0;

			public static Func<ParameterInfo, bool> <>9__40_3;

			internal void <OnLoaded>b__40_0(Setting setting)
			{
				Interlocked.Increment(ref Controller<TModel>._settingsUpdates);
			}

			internal bool <OnLoaded>b__40_3(ParameterInfo p)
			{
				return p.ParameterType != typeof(string);
			}
		}

		private readonly GooeeLogger _log = GooeeLogger.Get("Gooee");

		private string _lastModelJson = string.Empty;

		private string _modelJson = string.Empty;

		private static long _settingsUpdates = 0L;

		private static ConcurrentDictionary<string, string> _closeRequests = new ConcurrentDictionary<string, string>();

		private GooeeUISystem _gooeeUISystem;

		public IGooeePlugin Plugin { get; protected set; }

		protected TModel Model { get; private set; }

		protected GooeeSettings Settings
		{
			get
			{
				if (!(Plugin is IGooeeSettings gooeeSettings))
				{
					return null;
				}
				return gooeeSettings.Settings;
			}
		}

		protected GetterValueBinding<string> Binding { get; set; }

		private FieldInfo DirtyField { get; set; }

		private MethodInfo[] TriggerMethods { get; set; }

		protected string PluginID { get; private set; }

		protected string ControllerID { get; private set; }

		protected GooeeLogger Log { get; private set; }

		public virtual void OnLoaded()
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			_gooeeUISystem = ((ComponentSystemBase)this).World.GetExistingSystemManaged<GooeeUISystem>();
			if (Plugin is IGooeeLogger gooeeLogger)
			{
				Log = gooeeLogger.Log;
			}
			PluginID = Plugin.Name.ToLowerInvariant().Replace(" ", "_").Trim();
			ControllerID = PluginID + "." + ((object)this).GetType().Name.Replace("Controller", "").ToLowerInvariant().Trim();
			if (Settings != null)
			{
				GooeeSettings settings = Settings;
				object obj = <>c.<>9__40_0;
				if (obj == null)
				{
					OnSettingsAppliedHandler val = delegate
					{
						Interlocked.Increment(ref _settingsUpdates);
					};
					<>c.<>9__40_0 = val;
					obj = (object)val;
				}
				((Setting)settings).onSettingsApplied += (OnSettingsAppliedHandler)obj;
			}
			Model = Configure();
			Binding = new GetterValueBinding<string>(ControllerID, "model", (Func<string>)delegate
			{
				if (!string.IsNullOrEmpty(_modelJson))
				{
					return _modelJson;
				}
				_modelJson = JsonConvert.SerializeObject((object)Model, ResourceInjector._jsonSettings);
				return _modelJson;
			}, (IWriter<string>)null, (EqualityComparer<string>)null);
			DirtyField = ((object)Binding).GetType().GetField("m_ValueDirty", BindingFlags.Instance | BindingFlags.NonPublic);
			((UISystemBase)this).AddUpdateBinding((IUpdateBinding)(object)Binding);
			TriggerMethods = ReflectionUtils.GetMethodsWithAttribute<OnTriggerAttribute>(((object)this).GetType()).ToArray();
			MethodInfo[] triggerMethods = TriggerMethods;
			if (triggerMethods != null && triggerMethods.Length != 0)
			{
				LinqExtensions.ForEach<MethodInfo>((IEnumerable<MethodInfo>)TriggerMethods, (Action<MethodInfo>)delegate(MethodInfo m)
				{
					//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
					//IL_00e0: Expected O, but got Unknown
					ParameterInfo[] parameters = m.GetParameters();
					if (parameters != null && parameters.Length != 0 && parameters.Length < 3 && parameters.Count((ParameterInfo p) => p.ParameterType != typeof(string)) == 0)
					{
						if (parameters.Length == 1)
						{
							((UISystemBase)this).AddBinding((IBinding)(object)new TriggerBinding<string>(ControllerID, m.Name, (Action<string>)delegate(string a)
							{
								ReflectionUtils.Invoke(m, (object)this, new object[1] { a });
							}, (IReader<string>)null));
						}
						else
						{
							((UISystemBase)this).AddBinding((IBinding)(object)new TriggerBinding<string, string>(ControllerID, m.Name, (Action<string, string>)delegate(string a, string b)
							{
								ReflectionUtils.Invoke(m, (object)this, new object[2] { a, b });
							}, (IReader<string>)null, (IReader<string>)null));
						}
					}
					else
					{
						((UISystemBase)this).AddBinding((IBinding)new TriggerBinding(ControllerID, m.Name, (Action)delegate
						{
							ReflectionUtils.Invoke(m, (object)this, Array.Empty<object>());
						}));
					}
				});
			}
			((UISystemBase)this).AddBinding((IBinding)(object)new TriggerBinding<string>(ControllerID, "updateProperty", (Action<string>)OnUpdateProperty, (IReader<string>)null));
			_log.Info("Controller '" + ControllerID + "' registered.");
		}

		protected void TryRequestClose(string pluginName, string controllerName)
		{
			string key = pluginName.ToLowerInvariant() + "." + controllerName.ToLowerInvariant().Replace("controller", "").Trim();
			if (!_closeRequests.ContainsKey(pluginName))
			{
				_closeRequests.TryAdd(key, ControllerID);
			}
		}

		protected override void OnUpdate()
		{
			((UISystemBase)this).OnUpdate();
			if (Interlocked.Read(ref _settingsUpdates) > 0)
			{
				Interlocked.Exchange(ref _settingsUpdates, 0L);
				OnSettingsUpdated();
			}
			if (_closeRequests.ContainsKey(ControllerID))
			{
				OnCloseRequested(_closeRequests[ControllerID]);
				_closeRequests.TryRemove(ControllerID, out var _);
			}
		}

		protected virtual void OnCloseRequested(string requesterControllerID)
		{
		}

		public abstract TModel Configure();

		protected void MountResources(string route, string path)
		{
			ResourceInjector.MountResources(route, path);
		}

		protected void TriggerUpdate()
		{
			_modelJson = JsonConvert.SerializeObject((object)Model, ResourceInjector._jsonSettings);
			OnModelUpdated();
			DirtyField.SetValue(Binding, true);
		}

		private void OnUpdateProperty(string json)
		{
			if (string.IsNullOrEmpty(json))
			{
				return;
			}
			Type type = Model.GetType();
			Gooee.Plugins.Model.EnsureType(type);
			if (!Gooee.Plugins.Model._propertiesCache.ContainsKey(type))
			{
				return;
			}
			PropertyInfo[] array = Gooee.Plugins.Model._propertiesCache[type];
			if (array == null)
			{
				return;
			}
			Dictionary<string, object> dictionary = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
			if (dictionary == null || !dictionary.TryGetValue("property", out var propertyName))
			{
				return;
			}
			PropertyInfo propertyInfo = array.FirstOrDefault((PropertyInfo p) => p.Name == (string)propertyName);
			if (propertyInfo == null || !dictionary.TryGetValue("value", out var value))
			{
				return;
			}
			if (value.GetType() != propertyInfo.PropertyType)
			{
				if (TryConvertValue(propertyInfo.PropertyType, value, out var result))
				{
					propertyInfo.SetValue(Model, result);
				}
			}
			else
			{
				propertyInfo.SetValue(Model, value);
			}
			TriggerUpdate();
		}

		protected virtual void OnModelUpdated()
		{
		}

		protected virtual void OnSettingsUpdated()
		{
		}

		private bool TryConvertValue(Type propertyType, object val, out object result)
		{
			result = null;
			if (propertyType == typeof(decimal))
			{
				if (val is string s && int.TryParse(s, out var result2))
				{
					result = (decimal)result2 / 100m;
					return true;
				}
				if (val is long num)
				{
					result = (decimal)num / 100m;
					return true;
				}
				if (val is int num2)
				{
					result = (decimal)num2 / 100m;
					return true;
				}
			}
			else
			{
				if (propertyType == typeof(int) && val is long num3)
				{
					result = (int)num3;
					return true;
				}
				if (propertyType.IsEnum && val is string value)
				{
					if (Enum.TryParse(propertyType, value, out object result3))
					{
						result = result3;
						return true;
					}
				}
				else if (propertyType.IsEnum && val is int num4)
				{
					result = Convert.ChangeType(num4, propertyType);
					return true;
				}
			}
			return false;
		}

		protected void TriggerToolbarUpdate()
		{
			_gooeeUISystem?.BuildToolbarChildCache();
		}
	}
	public interface IController
	{
		IGooeePlugin Plugin { get; }

		void OnLoaded();
	}
	public interface IGooeePlugin
	{
		string Name { get; }

		string ScriptResource { get; }
	}
	[Obsolete("Please use ControllerTypes with IGooeePluginWithControllers instead!")]
	public interface IGooeePluginWithController : IGooeePlugin
	{
		IController Controller { get; set; }
	}
	public interface IGooeePluginWithControllers : IGooeePlugin
	{
		IController[] Controllers { get; set; }
	}
	public interface IGooeeChangeLog
	{
		string Version { get; }

		string ChangeLogResource { get; }
	}
	public interface IGooeeStyleSheet
	{
		string StyleResource { get; }
	}
	public interface IGooeeSettings
	{
		GooeeSettings Settings { get; set; }
	}
	public interface IGooeeLanguages
	{
		string LanguageResourceFolder { get; }
	}
	public interface IGooeeLogger
	{
		GooeeLogger Log { get; set; }
	}
	public interface IModel
	{
		IController Controller { get; }
	}
	public abstract class Model : IModel, IJsonWritable
	{
		public static Dictionary<Type, PropertyInfo[]> _propertiesCache = new Dictionary<Type, PropertyInfo[]>();

		[JsonIgnore]
		public IController Controller { get; private set; }

		public static void EnsureType(Type type)
		{
			try
			{
				if (!_propertiesCache.TryGetValue(type, out var value))
				{
					value = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
					_propertiesCache[type] = value;
				}
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
			}
		}

		public void Write(IJsonWriter writer)
		{
			try
			{
				Type type = GetType();
				if (!_propertiesCache.TryGetValue(type, out var value))
				{
					value = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
					_propertiesCache[type] = value;
				}
				ParseType(writer, this, value);
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
			}
		}

		private void ParseType(IJsonWriter writer, object instance, PropertyInfo[] properties)
		{
			writer.TypeBegin(instance.GetType().FullName);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (!typeof(IController).IsAssignableFrom(propertyInfo.PropertyType))
				{
					object value = propertyInfo.GetValue(instance);
					if (value == null)
					{
						writer.WriteNull();
					}
					else
					{
						WriteProperty(writer, propertyInfo, value);
					}
				}
			}
			writer.TypeEnd();
		}

		private void WriteProperty(IJsonWriter writer, PropertyInfo property, object value)
		{
			writer.PropertyName(property.Name);
			WritePropertyValue(writer, value);
		}

		private void WritePropertyValue(IJsonWriter writer, object value)
		{
			Type type = value.GetType();
			if (!(value is string text))
			{
				if (!(value is float num))
				{
					if (!(value is double num2))
					{
						if (!(value is short num3))
						{
							if (!(value is uint num4))
							{
								if (!(value is int num5))
								{
									if (!(value is long num6))
									{
										if (!(value is bool flag))
										{
											if (!(value is decimal num7))
											{
												if (value is Enum @enum)
												{
													writer.Write(@enum.ToString());
												}
												else
												{
													WriteComplexType(writer, value, type);
												}
											}
											else
											{
												writer.Write((int)(num7 * 100m));
											}
										}
										else
										{
											writer.Write(flag);
										}
									}
									else
									{
										writer.Write((float)num6);
									}
								}
								else
								{
									writer.Write(num5);
								}
							}
							else
							{
								writer.Write(num4);
							}
						}
						else
						{
							writer.Write((int)num3);
						}
					}
					else
					{
						writer.Write(num2);
					}
				}
				else
				{
					writer.Write(num);
				}
			}
			else
			{
				writer.Write(text);
			}
		}

		private void WriteComplexType(IJsonWriter writer, object value, Type valueType)
		{
			if (ReflectionUtils.IsSubclassOfRawGeneric(valueType, typeof(List<>)))
			{
				HandleList(writer, value, valueType);
			}
			else if (valueType == typeof(Dictionary<string, string>))
			{
				HandleDictionary(writer, value);
			}
		}

		private void HandleList(IJsonWriter writer, object value, Type valueType)
		{
			if (!(value is IList list))
			{
				return;
			}
			int count = list.Count;
			JsonWriterExtensions.ArrayBegin(writer, count);
			foreach (object item in list)
			{
				if (!(item is string text))
				{
					if (!(item is float num))
					{
						if (!(item is double num2))
						{
							if (!(item is short num3))
							{
								if (!(item is uint num4))
								{
									if (!(item is int num5))
									{
										if (!(item is long num6))
										{
											if (!(item is bool flag))
											{
												if (!(item is decimal num7))
												{
													if (item is Enum @enum)
													{
														writer.Write(@enum.ToString());
														continue;
													}
													PropertyInfo[] properties = valueType.GenericTypeArguments[0].GetProperties(BindingFlags.Instance | BindingFlags.Public);
													ParseType(writer, item, properties);
												}
												else
												{
													writer.Write((int)(num7 * 100m));
												}
											}
											else
											{
												writer.Write(flag);
											}
										}
										else
										{
											writer.Write((float)num6);
										}
									}
									else
									{
										writer.Write(num5);
									}
								}
								else
								{
									writer.Write(num4);
								}
							}
							else
							{
								writer.Write((int)num3);
							}
						}
						else
						{
							writer.Write(num2);
						}
					}
					else
					{
						writer.Write(num);
					}
				}
				else
				{
					writer.Write(text);
				}
			}
			writer.ArrayEnd();
		}

		private void HandleArray(IJsonWriter writer, Array value, Type valueType)
		{
			if (value == null)
			{
				return;
			}
			int length = value.Length;
			JsonWriterExtensions.ArrayBegin(writer, length);
			foreach (object item in value)
			{
				if (!(item is string text))
				{
					if (!(item is float num))
					{
						if (!(item is double num2))
						{
							if (!(item is short num3))
							{
								if (!(item is uint num4))
								{
									if (!(item is int num5))
									{
										if (!(item is long num6))
										{
											if (!(item is bool flag))
											{
												if (!(item is decimal num7))
												{
													if (item is Enum @enum)
													{
														writer.Write(@enum.ToString());
														continue;
													}
													PropertyInfo[] properties = valueType.GetElementType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
													ParseType(writer, item, properties);
												}
												else
												{
													writer.Write((int)(num7 * 100m));
												}
											}
											else
											{
												writer.Write(flag);
											}
										}
										else
										{
											writer.Write((float)num6);
										}
									}
									else
									{
										writer.Write(num5);
									}
								}
								else
								{
									writer.Write(num4);
								}
							}
							else
							{
								writer.Write((int)num3);
							}
						}
						else
						{
							writer.Write(num2);
						}
					}
					else
					{
						writer.Write(num);
					}
				}
				else
				{
					writer.Write(text);
				}
			}
			writer.ArrayEnd();
		}

		private void HandleDictionary(IJsonWriter writer, object value)
		{
			if (!(value is IDictionary<string, string> dictionary))
			{
				return;
			}
			int count = dictionary.Count;
			if (count == 0)
			{
				JsonWriterExtensions.WriteEmptyMap(writer);
				return;
			}
			JsonWriterExtensions.MapBegin(writer, count);
			foreach (KeyValuePair<string, string> item in dictionary)
			{
				writer.Write(item.Key);
				writer.Write(item.Value);
			}
			writer.MapEnd();
		}
	}
	internal class PluginLoader
	{
		private static readonly GooeeLogger _log = GooeeLogger.Get("Gooee");

		public static Dictionary<string, IGooeePlugin> Plugins { get; private set; } = new Dictionary<string, IGooeePlugin>();


		public static void Load()
		{
			FindPlugins();
			ExportPlugins();
		}

		private static void FindPlugins()
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				List<Type> list = (from t in assemblies[i].GetTypes()
					where t.IsClass && typeof(IGooeePlugin).IsAssignableFrom(t)
					select t).ToList();
				if (list == null || list.Count == 0)
				{
					continue;
				}
				foreach (Type item in list)
				{
					IGooeePlugin gooeePlugin = (IGooeePlugin)Activator.CreateInstance(item);
					if (gooeePlugin == null || string.IsNullOrEmpty(gooeePlugin.Name) || Plugins.ContainsKey(gooeePlugin.Name))
					{
						_log.Error("Gooee plugin failed to load '" + gooeePlugin.Name + ".'");
						continue;
					}
					if (gooeePlugin is IGooeeLogger gooeeLogger)
					{
						gooeeLogger.Log = new GooeeLogger(gooeePlugin.Name);
					}
					_log.Info("Gooee plugin loaded '" + gooeePlugin.Name + ".'");
					Plugins.Add(gooeePlugin.Name, gooeePlugin);
				}
			}
		}

		private static void ExportPlugins()
		{
			foreach (KeyValuePair<string, IGooeePlugin> plugin in Plugins)
			{
				IGooeePlugin value = plugin.Value;
				Assembly assembly = value.GetType().Assembly;
				if (value is IGooeeStyleSheet gooeeStyleSheet && !string.IsNullOrEmpty(gooeeStyleSheet.StyleResource))
				{
					ResourceInjector.SavePluginResource(assembly, value.Name, gooeeStyleSheet.StyleResource);
				}
				if (!string.IsNullOrEmpty(value.ScriptResource))
				{
					ResourceInjector.SavePluginResource(assembly, value.Name, value.ScriptResource);
				}
				if (value is IGooeeChangeLog gooeeChangeLog && !string.IsNullOrEmpty(gooeeChangeLog.ChangeLogResource))
				{
					ResourceInjector.SavePluginResource(assembly, value.Name, gooeeChangeLog.ChangeLogResource);
				}
			}
		}

		public static void GetControllerTypes(IGooeePlugin plugin, out List<Type> controllerTypes, out List<Type> modelTypes)
		{
			controllerTypes = new List<Type>();
			modelTypes = new List<Type>();
			Type type = plugin.GetType();
			if (type.GetCustomAttributes().FirstOrDefault((Attribute a) => typeof(ControllerTypeAttribute<>).IsAssignableFrom(a.GetType())) != null && plugin is IGooeePluginWithController gooeePluginWithController)
			{
				Type type2 = gooeePluginWithController.GetType();
				controllerTypes.Add(type2);
				modelTypes.Add(type2.BaseType.GetGenericArguments()[0]);
				return;
			}
			ControllerTypesAttribute customAttribute = type.GetCustomAttribute<ControllerTypesAttribute>();
			if (customAttribute != null && typeof(IGooeePluginWithControllers).IsAssignableFrom(plugin.GetType()))
			{
				Type[] types = customAttribute.Types;
				if (types != null && types.Length != 0)
				{
					_ = (IGooeePluginWithControllers)plugin;
					Type[] types2 = customAttribute.Types;
					foreach (Type type3 in types2)
					{
						controllerTypes.Add(type3);
						modelTypes.Add(type3.BaseType.GetGenericArguments()[0]);
					}
				}
				else
				{
					_log.Error("Gooee failed to find any controller types for " + type.FullName);
				}
			}
			else
			{
				_log.Error("Gooee failed to instantiate a controller for plugin " + type.FullName);
			}
		}
	}
}
namespace Gooee.Plugins.Attributes
{
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
	public class ControllerDependsAttribute : Attribute
	{
		public SystemUpdatePhase UpdatePhase { get; private set; }

		public Type Type { get; private set; }

		public ControllerDependsAttribute(SystemUpdatePhase updatePhase, Type type)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			UpdatePhase = updatePhase;
			Type = type;
		}
	}
	[Obsolete("Please use ControllerTypes with IGooeePluginWithControllers instead!")]
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
	public class ControllerTypeAttribute<TController> : Attribute where TController : IController
	{
	}
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
	public class ControllerTypesAttribute : Attribute
	{
		public Type[] Types { get; private set; }

		public ControllerTypesAttribute(params Type[] types)
		{
			Types = types;
		}
	}
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
	public class GooeeSettingsMenuAttribute : Attribute
	{
		public Type Type { get; private set; }

		public GooeeSettingsMenuAttribute(Type type)
		{
			Type = type;
		}
	}
	[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
	public class ObservableAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
	public class OnTriggerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
	public class PluginToolbarAttribute : Attribute
	{
		public Type ControllerType { get; private set; }

		internal InternalPluginToolbarItem Item { get; private set; }

		public PluginToolbarAttribute(Type controllerType, string onClickMethod, string label = null, string icon = null)
		{
			ControllerType = controllerType;
			Item = new InternalPluginToolbarItem
			{
				OnClickMethod = controllerType.GetMethod(onClickMethod, BindingFlags.Instance | BindingFlags.NonPublic),
				Label = label,
				Icon = icon,
				IsFAIcon = false
			};
		}

		public PluginToolbarAttribute(Type controllerType, string jsonResource)
		{
			ControllerType = controllerType;
			string text = EmbeddedResource.LoadText(jsonResource, controllerType.Assembly);
			if (string.IsNullOrEmpty(text))
			{
				throw new InvalidOperationException("Specify the correct JSON schema for your Gooee toolbar.");
			}
			PluginToolbarItem pluginToolbarItem = JsonConvert.DeserializeObject<PluginToolbarItem>(text);
			if (pluginToolbarItem == null)
			{
				throw new InvalidOperationException("Unable to serialize JSON for Gooee toolbar item");
			}
			Item = new InternalPluginToolbarItem
			{
				OnClickMethod = controllerType.GetMethod(pluginToolbarItem.OnClick, BindingFlags.Instance | BindingFlags.NonPublic),
				OnGetChildren = (string.IsNullOrEmpty(pluginToolbarItem.OnGetChildren) ? null : controllerType.GetMethod(pluginToolbarItem.OnGetChildren, BindingFlags.Instance | BindingFlags.NonPublic)),
				OnClickKey = pluginToolbarItem.OnClickKey,
				Label = pluginToolbarItem.Label,
				Icon = pluginToolbarItem.Icon,
				IconClassName = pluginToolbarItem.IconClassName,
				IsFAIcon = pluginToolbarItem.IsFAIcon
			};
			PluginToolbarChildItem[] children = pluginToolbarItem.Children;
			if (children != null && children.Length != 0)
			{
				Item.Children = pluginToolbarItem.Children.Select((PluginToolbarChildItem c) => new InternalPluginToolbarItem
				{
					OnClickMethod = controllerType.GetMethod(c.OnClick, BindingFlags.Instance | BindingFlags.NonPublic),
					OnClickKey = c.OnClickKey,
					Label = c.Label,
					Icon = c.Icon,
					IconClassName = c.IconClassName,
					IsFAIcon = c.IsFAIcon
				}).ToArray();
			}
		}
	}
	internal class InternalPluginToolbarItem
	{
		public MethodInfo OnClickMethod { get; set; }

		public string OnClickKey { get; set; }

		public MethodInfo OnGetChildren { get; set; }

		public string Label { get; set; }

		public string Icon { get; set; }

		public bool IsFAIcon { get; set; }

		public string IconClassName { get; set; }

		public InternalPluginToolbarItem[] Children { get; set; }
	}
	internal class PluginToolbarItem
	{
		public string Label { get; set; }

		public string Icon { get; set; }

		public bool IsFAIcon { get; set; }

		public string IconClassName { get; set; }

		public string OnClick { get; set; }

		public string OnClickKey { get; set; }

		public PluginToolbarChildItem[] Children { get; set; }

		public string OnGetChildren { get; set; }
	}
	public class PluginToolbarChildItem
	{
		public string Label { get; set; }

		public string Icon { get; set; }

		public bool IsFAIcon { get; set; }

		public string IconClassName { get; set; }

		public string OnClick { get; set; }

		public string OnClickKey { get; set; }
	}
}
namespace Gooee.Patches
{
	[HarmonyPatch(typeof(OptionsUISystem), "OnCreate")]
	public static class OptionsUISystem_OnCreatePatch
	{
		public static void Postfix()
		{
			ResourceInjector.SetupResourceHandler();
		}
	}
	[HarmonyPatch(typeof(SystemOrder))]
	public static class SystemOrderPatch
	{
		[HarmonyPatch("Initialize")]
		[HarmonyPostfix]
		public static void Postfix(UpdateSystem updateSystem)
		{
			updateSystem.UpdateAt<GooeeUISystem>((SystemUpdatePhase)22);
		}
	}
	public static class UIPatches
	{
		[HarmonyPatch(typeof(GameManager), "InitializeUI")]
		public static class GameManager_InitializeUIPatch
		{
			public static void Postfix(GameManager __instance)
			{
				if (!ResourceInjector.IsHookUILoaded())
				{
					Debug.Log((object)"Using non-HookUI injection!");
					EnsureFolder();
					ResourceInjector.Inject();
					__instance.userInterface.view.url = "coui://gooeeui/index.html";
					UIManager.defaultUISystem.defaultUIView.url = "coui://gooeeui/index.html";
				}
			}
		}

		[HarmonyPatch(typeof(UISystemBootstrapper), "Awake")]
		public static class UISystemBootstrapper_AwakePatch
		{
			public static void Postfix(UISystemBootstrapper __instance)
			{
				if (!ResourceInjector.IsHookUILoaded())
				{
					EnsureFolder();
					ResourceInjector.Inject();
					UIManager.defaultUISystem.defaultUIView.url = "coui://gooeeui/index.html";
					__instance.m_Url = "coui://gooeeui/index.html";
				}
			}
		}

		private const string UI_URL = "coui://gooeeui/";

		private const string INDEX_PATH = "coui://gooeeui/index.html";

		private static void EnsureFolder()
		{
			ResourceInjector.SetupResourceHandler();
		}

		public static void InstallGameResourceHook(Harmony harmony)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			ConstructorInfo constructorInfo = (typeof(GameUIResourceHandler).GetNestedTypes(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((Type t) => t.Name == "GameResourceRequestData") ?? throw new Exception("Gooee: Failed to find GameResourceRequestData to hook!")).GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[3]
			{
				typeof(uint),
				typeof(string),
				typeof(IResourceResponse)
			}, null) ?? throw new Exception("Gooee: Failed to find the constructor to hook!");
			harmony.Patch((MethodBase)constructorInfo, new HarmonyMethod(typeof(UIPatches), "GameResourceRequestDataPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void GameResourceRequestDataPrefix(ref uint id, ref string uri, ref IResourceResponse response)
		{
			if (!ResourceInjector.IsHookUILoaded())
			{
				string text = uri.ToLowerInvariant();
				if (text.StartsWith("coui://gooeeui/media/"))
				{
					uri = "coui://GameUI/Media/" + uri.Substring("coui://gooeeui/media/".Length);
				}
				else if (text.StartsWith("coui://gooeeui/media%5c"))
				{
					uri = "coui://GameUI/Media/" + uri.Substring("coui://gooeeui/media%5c".Length);
				}
				else if (text.StartsWith("coui://gooeeui/static/"))
				{
					uri = "coui://GameUI/Static/" + uri.Substring("coui://gooeeui/static/".Length);
				}
				else if (text.StartsWith("coui://gooeeui/index.css"))
				{
					uri = "coui://GameUI/index.css";
				}
			}
		}
	}
}
namespace Gooee.Injection
{
	internal class ResourceInjector
	{
		private const string UI_IDENTIFIER = "gooeeui";

		private const string URL_PREFIX = "coui://gooeeui/";

		public static bool MakeHookUICompatible;

		private static readonly string ASSEMBLY_PATH;

		public static readonly string MOD_PATH;

		private static readonly string PLUGIN_PATH;

		private static readonly string CHANGELOG_READ_PATH;

		private static readonly string UI_PATH;

		private static readonly string GAMEUI_PATH;

		private static readonly string HOOKUI_PATH;

		private static readonly string GAMEUI_INDEX_HTML;

		private static readonly string GAMEUI_INDEX_JS;

		public static readonly string HOOKUI_INDEX_HTML;

		private static readonly string HOOKUI_INDEX_JS;

		public static readonly string NON_HOOKUI_INDEX_HTML;

		private static readonly string NON_HOOKUI_INDEX_JS;

		private const string CV_JS_FILENAME = "gooee.js";

		private const string CV_CSS_FILENAME = "gooee.css";

		private const string SCRIPT_ELEMENT = "<script src=\"index.js\"></script>";

		private const string NON_HOOKUI_SCRIPT_ELEMENT = "<script src=\"coui://gooeeui/index.js\"></script>";

		private const string STYLE_ELEMENT = "<link href=\"index.css\" rel=\"stylesheet\"/>";

		private const string NON_HOOKUI_STYLE_ELEMENT = "<link href=\"index.css\" rel=\"stylesheet\">";

		private const string GOOEE_STYLE_ELEMENT = "<link href=\"coui://GameUI/index.css\" rel=\"stylesheet\"/>";

		private const string CV_SCRIPT_ELEMENT = "<script src=\"coui://gooeeui/gooee.js\"></script>";

		private const string CV_STYLE_ELEMENT = "    <link href=\"coui://gooeeui/gooee.css\" rel=\"stylesheet\"/>";

		private static readonly (string Search, string Replacement)[] INJECTION_POINTS;

		private static readonly (string Search, string Replacement) HOOKUI_INJECTION_POINT;

		private static readonly (string Search, string Replacement) NON_HOOKUI_INJECTION_POINT;

		private static readonly GooeeLogger _log;

		private static bool HasInjected;

		public static JsonSerializerSettings _jsonSettings;

		private static FileSystemWatcher _watcher;

		public static FieldInfo _liveReload;

		public static MethodInfo _onChanged;

		public static bool InvalidVersion { get; private set; }

		static ResourceInjector()
		{
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Expected O, but got Unknown
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Expected O, but got Unknown
			MakeHookUICompatible = false;
			ASSEMBLY_PATH = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			MOD_PATH = Path.Combine(Application.persistentDataPath, "Mods", "Gooee");
			PLUGIN_PATH = Path.Combine(MOD_PATH, "Plugins");
			CHANGELOG_READ_PATH = Path.Combine(MOD_PATH, "changelog.ini");
			UI_PATH = Path.Combine(Application.streamingAssetsPath, "~UI~");
			GAMEUI_PATH = Path.Combine(UI_PATH, "GameUI");
			HOOKUI_PATH = Path.Combine(UI_PATH, "HookUI");
			GAMEUI_INDEX_HTML = Path.Combine(GAMEUI_PATH, "index.html");
			GAMEUI_INDEX_JS = Path.Combine(GAMEUI_PATH, "index.js");
			HOOKUI_INDEX_HTML = Path.Combine(HOOKUI_PATH, "index.html");
			HOOKUI_INDEX_JS = Path.Combine(HOOKUI_PATH, "index.js");
			NON_HOOKUI_INDEX_HTML = Path.Combine(MOD_PATH, "index.html");
			NON_HOOKUI_INDEX_JS = Path.Combine(MOD_PATH, "index.js");
			INJECTION_POINTS = new(string, string)[6]
			{
				("(0,z.jsx)(BSe,{})]", "(0,z.jsx)(BSe,{}),(0,z.jsx)(window.$_gooee.container,{react:Y,pluginType:'bottom-right-toolbar'})]"),
				("className:nbe.pauseMenuLayout,children:[", "className:nbe.pauseMenuLayout,children:[(0,z.jsx)(window.$_gooee.container,{react:Y,pluginType:'top-right-toolbar'}),"),
				("(0,z.jsx)(vSe,{})]", "(0,z.jsx)(vSe,{}),(0,z.jsx)(window.$_gooee.container,{react:Y,pluginType:'bottom-left-toolbar'})]"),
				("(0,z.jsx)(rTe,{focusKey:pIe.toolbar})", "(0,z.jsx)(rTe,{focusKey:pIe.toolbar}),(0,z.jsx)(window.$_gooee.container,{react:Y,pluginType:'default'})"),
				("]}),(0,z.jsx)(rTe,{focusKey:pIe.toolbar})", ",(0,z.jsx)(window.$_gooee.container,{react:Y,pluginType:'main-container'}),(0,z.jsx)(window.$_gooee.container,{react:Y,pluginType:'main-container-end'})]}),(0,z.jsx)(rTe,{focusKey:pIe.toolbar})"),
				("var t=e.children;return(0,z.jsx)(\"div\",{className:_d()(nbe.photoModePanelLayout),children:t})", "var t=e.children;return(0,z.jsx)(window.$_gooee.container,{react:Y,pluginType:'photomode-container',photoMode:{className:_d()(nbe.photoModePanelLayout),children:t}})")
			};
			HOOKUI_INJECTION_POINT = ("(0,z.jsx)(window._$hookui_menu,{react:Y})]", "(0,z.jsx)(window._$hookui_menu,{react:Y}),(0,z.jsx)(window.$_gooee.container,{react:Y,pluginType:'top-left-toolbar'})]");
			NON_HOOKUI_INJECTION_POINT = ("ube.lock})})})})]", "ube.lock})})})}),(0,z.jsx)(window.$_gooee.container,{react:Y,pluginType:'top-left-toolbar'})]");
			_log = GooeeLogger.Get("Gooee");
			HasInjected = false;
			JsonSerializerSettings val = new JsonSerializerSettings();
			val.DefaultValueHandling = (DefaultValueHandling)2;
			val.NullValueHandling = (NullValueHandling)0;
			val.Converters = (IList<JsonConverter>)(object)new StringEnumConverter[1]
			{
				new StringEnumConverter()
			};
			_jsonSettings = val;
			_liveReload = typeof(UIView).GetField("m_LiveReload", BindingFlags.Instance | BindingFlags.NonPublic);
			_onChanged = typeof(UILiveReload).GetMethod("OnChanged", BindingFlags.Instance | BindingFlags.NonPublic);
			InvalidVersion = !ValidateVersion();
		}

		public static bool IsHookUILoaded()
		{
			if (MakeHookUICompatible)
			{
				return true;
			}
			Directory.GetFiles(Directory.GetParent(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)).FullName, "*.dll", SearchOption.AllDirectories);
			MakeHookUICompatible = AppDomain.CurrentDomain.GetAssemblies().Count((Assembly a) => !a.IsDynamic && Path.GetFileName(a.Location).ToLowerInvariant() == "hookuimod.dll") > 0;
			return MakeHookUICompatible;
		}

		public static void Inject()
		{
			if (!HasInjected && !InvalidVersion)
			{
				MakeHookUICompatible = IsHookUILoaded();
				if (!Directory.Exists(MakeHookUICompatible ? HOOKUI_PATH : GAMEUI_PATH))
				{
					_log.Error("No UI folder found!");
					return;
				}
				SaveResources();
				PluginLoader.Load();
				InjectJS();
				InjectHTML();
				SetupFileWatcher();
				_log.Info("Installed Gooee (" + (MakeHookUICompatible ? "HOOKUI-INJECTION" : "DEFAULT-INJECTION") + ").");
				HasInjected = true;
			}
		}

		private static void InjectJS()
		{
			string text = File.ReadAllText(MakeHookUICompatible ? HOOKUI_INDEX_JS : GAMEUI_INDEX_JS);
			text = ((!MakeHookUICompatible) ? text.Replace(NON_HOOKUI_INJECTION_POINT.Search, NON_HOOKUI_INJECTION_POINT.Replacement) : text.Replace(HOOKUI_INJECTION_POINT.Search, HOOKUI_INJECTION_POINT.Replacement));
			(string, string)[] iNJECTION_POINTS = INJECTION_POINTS;
			for (int i = 0; i < iNJECTION_POINTS.Length; i++)
			{
				(string, string) tuple = iNJECTION_POINTS[i];
				text = text.Replace(tuple.Item1, tuple.Item2);
			}
			File.WriteAllText(MakeHookUICompatible ? HOOKUI_INDEX_JS : NON_HOOKUI_INDEX_JS, text);
		}

		private static bool ValidateVersion()
		{
			return File.ReadAllText(GAMEUI_INDEX_JS).Contains(NON_HOOKUI_INJECTION_POINT.Search);
		}

		private static void InjectHTML()
		{
			string html = File.ReadAllText(MakeHookUICompatible ? HOOKUI_INDEX_HTML : GAMEUI_INDEX_HTML);
			html = TransformHTML(html);
			File.WriteAllText(MakeHookUICompatible ? HOOKUI_INDEX_HTML : NON_HOOKUI_INDEX_HTML, html);
		}

		private static string TransformHTML(string html)
		{
			StringBuilder stringBuilder = new StringBuilder("<script src=\"coui://gooeeui/gooee.js\"></script>");
			StringBuilder stringBuilder2 = new StringBuilder("<link href=\"coui://GameUI/index.css\" rel=\"stylesheet\"/>");
			stringBuilder2.AppendLine();
			stringBuilder2.AppendLine("    <link href=\"coui://gooeeui/gooee.css\" rel=\"stylesheet\"/>");
			stringBuilder.AppendLine();
			IncludePlugins(stringBuilder, stringBuilder2);
			stringBuilder.AppendLine("    " + (MakeHookUICompatible ? "<script src=\"index.js\"></script>" : "<script src=\"coui://gooeeui/index.js\"></script>"));
			html = html.Replace("<script src=\"index.js\"></script>", stringBuilder.ToString());
			html = html.Replace(MakeHookUICompatible ? "<link href=\"index.css\" rel=\"stylesheet\"/>" : "<link href=\"index.css\" rel=\"stylesheet\">", stringBuilder2.ToString());
			return html;
		}

		private static void IncludePlugins(StringBuilder scriptBuilder, StringBuilder styleBuilder)
		{
			List<string> list = new List<string>();
			scriptBuilder.AppendLine("<script type=\"text/javascript\">");
			scriptBuilder.AppendLine("window.$_gooee_defaultModel = [];");
			scriptBuilder.AppendLine("window.$_gooee_toolbar = [];");
			int num = 0;
			foreach (IGooeePlugin value5 in PluginLoader.Plugins.Values)
			{
				PluginLoader.GetControllerTypes(value5, out var controllerTypes, out var modelTypes);
				if (controllerTypes != null && controllerTypes.Count > 0 && modelTypes != null && modelTypes.Count > 0)
				{
					for (int i = 0; i < controllerTypes.Count; i++)
					{
						Type type = controllerTypes[i];
						string input = JsonConvert.SerializeObject(Activator.CreateInstance(modelTypes[i]), _jsonSettings);
						string value = "   window.$_gooee_defaultModel[\"" + value5.Name.ToLower() + "." + type.Name.ToLower().Replace("controller", "") + "\"] = " + Regex.Replace(input, "\\\"([A-Za-z0-9_@]+)\\\"\\:", "$1:") + ";";
						scriptBuilder.AppendLine(value);
					}
					PluginToolbarAttribute customAttribute = value5.GetType().GetCustomAttribute<PluginToolbarAttribute>();
					if (customAttribute?.Item != null)
					{
						InternalPluginToolbarItem item = customAttribute.Item;
						StringBuilder stringBuilder = new StringBuilder();
						InternalPluginToolbarItem[] children = item.Children;
						if (children != null && children.Length != 0)
						{
							stringBuilder.Append("[");
							InternalPluginToolbarItem[] children2 = item.Children;
							foreach (InternalPluginToolbarItem internalPluginToolbarItem in children2)
							{
								if (stringBuilder.Length > 1)
								{
									stringBuilder.Append("," + Environment.NewLine);
								}
								stringBuilder.Append("{Label:" + ((internalPluginToolbarItem.Label != null) ? ("\"" + internalPluginToolbarItem.Label + "\"") : "null") + ", Icon:" + ((internalPluginToolbarItem.Icon != null) ? ("\"" + internalPluginToolbarItem.Icon + "\"") : "null") + ", IconClassName:" + ((internalPluginToolbarItem.IconClassName != null) ? ("\"" + internalPluginToolbarItem.IconClassName + "\"") : "null") + ", IsFAIcon: " + internalPluginToolbarItem.IsFAIcon.ToString().ToLower() + ", Method:\"" + internalPluginToolbarItem.OnClickMethod.Name + "\", MethodKey:" + ((internalPluginToolbarItem.OnClickKey != null) ? ("\"" + internalPluginToolbarItem.OnClickKey + "\"") : "null") + "}");
							}
							stringBuilder.Append("]");
						}
						else
						{
							stringBuilder.Append("null");
						}
						string value2 = string.Format("   window.$_gooee_toolbar[\"{0}\"] = {{Name:\"{1}\", Label:{2}, Icon:{3}, IconClassName:{4}, IsFAIcon: {5}, Controller:\"{6}\", Method:\"{7}\", MethodKey:{8}, Children:{9}}};", value5.Name.ToLower(), value5.Name, (item.Label != null) ? ("\"" + item.Label + "\"") : "null", (item.Icon != null) ? ("\"" + item.Icon + "\"") : "null", (item.IconClassName != null) ? ("\"" + item.IconClassName + "\"") : "null", item.IsFAIcon.ToString().ToLower(), customAttribute.ControllerType.Name.ToLower().Replace("controller", ""), item.OnClickMethod.Name, (item.OnClickKey != null) ? ("\"" + item.OnClickKey + "\"") : "null", stringBuilder);
						scriptBuilder.AppendLine(value2);
					}
				}
				num++;
			}
			scriptBuilder.AppendLine("</script>");
			foreach (IGooeePlugin value6 in PluginLoader.Plugins.Values)
			{
				if (!string.IsNullOrEmpty(value6.ScriptResource))
				{
					string text = value6.Name.Replace(" ", "_") + Path.GetExtension(value6.ScriptResource);
					string value3 = "    <script src=\"coui://gooeeui/Plugins/" + text + "\"></script>";
					scriptBuilder.AppendLine(value3);
				}
				if (value6 is IGooeeStyleSheet gooeeStyleSheet && !string.IsNullOrEmpty(gooeeStyleSheet.StyleResource))
				{
					string text2 = value6.Name.Replace(" ", "_") + Path.GetExtension(gooeeStyleSheet.StyleResource);
					string value4 = "    <link href=\"coui://gooeeui/Plugins/" + text2 + "\" rel=\"stylesheet\"/>";
					styleBuilder.AppendLine(value4);
				}
				if (value6 is IGooeeChangeLog gooeeChangeLog && !string.IsNullOrEmpty(gooeeChangeLog.ChangeLogResource))
				{
					list.Add("{ \"name\": \"" + value6.Name + "\", \"version\": \"" + gooeeChangeLog.Version + "\", \"timestamp\": \"" + GetPluginTimeStamp(value6.GetType().Assembly).ToString() + "\" }");
				}
			}
		}

		public static bool HasChangeLogUpdated()
		{
			List<IGooeePlugin> list = PluginLoader.Plugins.Values.Where((IGooeePlugin p) => p is IGooeeChangeLog).ToList();
			if (list.Count <= 0)
			{
				return false;
			}
			if (!File.Exists(CHANGELOG_READ_PATH))
			{
				return true;
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (IGooeePlugin item in list)
			{
				IGooeeChangeLog gooeeChangeLog = item as IGooeeChangeLog;
				stringBuilder.AppendLine(item.Name + "," + gooeeChangeLog.Version);
			}
			string text = File.ReadAllText(CHANGELOG_READ_PATH);
			if (string.IsNullOrEmpty(text))
			{
				return true;
			}
			return text != stringBuilder.ToString();
		}

		public static void WriteChangeLogRead()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (IGooeePlugin item in PluginLoader.Plugins.Values.Where((IGooeePlugin p) => p is IGooeeChangeLog))
			{
				IGooeeChangeLog gooeeChangeLog = item as IGooeeChangeLog;
				stringBuilder.AppendLine(item.Name + "," + gooeeChangeLog.Version);
			}
			File.WriteAllText(CHANGELOG_READ_PATH, stringBuilder.ToString());
		}

		public static void ResetChangeLog()
		{
			if (File.Exists(CHANGELOG_READ_PATH))
			{
				File.Delete(CHANGELOG_READ_PATH);
			}
		}

		private static DateTime GetPluginTimeStamp(Assembly assembly)
		{
			byte[] array = new byte[2048];
			using (FileStream fileStream = new FileStream(assembly.Location, FileMode.Open, FileAccess.Read))
			{
				fileStream.Read(array, 0, 2048);
			}
			int num = BitConverter.ToInt32(array, 60);
			int num2 = BitConverter.ToInt32(array, num + 8);
			DateTime time = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(num2);
			return time.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(time).Hours);
		}

		private static void SaveResources()
		{
			SaveResource("Gooee.Resources", "gooee.js");
			SaveResource("Gooee.Resources", "gooee.css");
			ExtractIcons();
		}

		private static void ExtractIcons()
		{
			string path = Path.Combine(MOD_PATH, "FA");
			string text = Path.Combine(ASSEMBLY_PATH, "FA.zip");
			if (!Directory.Exists(path) && File.Exists(text))
			{
				using (ZipArchive source = ZipFile.OpenRead(text))
				{
					source.ExtractToDirectory(MOD_PATH, overwriteFiles: true);
				}
			}
		}

		public static void SaveResource(string resourceFolder, string fileName)
		{
			string text = resourceFolder + "." + fileName;
			Directory.CreateDirectory(MOD_PATH);
			string text2 = EmbeddedResource.LoadText(text);
			if (text2 == null)
			{
				_log.Error("Failed to load resource: " + text);
			}
			else
			{
				File.WriteAllText(Path.Combine(MOD_PATH, fileName), text2);
			}
		}

		public static void SavePluginResource(Assembly pluginAssembly, string pluginName, string resourceName)
		{
			Directory.CreateDirectory(PLUGIN_PATH);
			string text = EmbeddedResource.LoadText(resourceName, pluginAssembly);
			if (text == null)
			{
				_log.Error("Failed to load resource: " + resourceName);
				return;
			}
			string extension = Path.GetExtension(resourceName);
			File.WriteAllText(Path.Combine(PLUGIN_PATH, pluginName.Replace(" ", "_") + extension), text);
		}

		public static void SetupResourceHandler()
		{
			UISystem uiSystem = GameManager.instance.userInterface.view.uiSystem;
			if (uiSystem == null)
			{
				_log.Error("Failed to setup resource handler for Gooee.");
				return;
			}
			_log.Info("Setup resource handler for Gooee.");
			uiSystem.AddHostLocation("gooeeui", MOD_PATH, false);
		}

		public static void MountResources(string uri, string path)
		{
			UISystem uiSystem = GameManager.instance.userInterface.view.uiSystem;
			if (uiSystem == null)
			{
				_log.Error("Failed to setup resource handler for " + uri + ".");
				return;
			}
			_log.Info("Setup resource handler for " + uri + ".");
			uiSystem.AddHostLocation(uri, path, false);
		}

		private static void SetupFileWatcher()
		{
			if (_watcher == null)
			{
				_watcher = new FileSystemWatcher
				{
					Path = MOD_PATH,
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastWrite),
					Filter = "*.*",
					IncludeSubdirectories = true
				};
				_watcher.Changed += OnChanged;
				_watcher.Created += OnChanged;
				_watcher.EnableRaisingEvents = true;
			}
		}

		private static void OnChanged(object source, FileSystemEventArgs e)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			if (e.ChangeType == WatcherChangeTypes.Changed && (e.FullPath.EndsWith(".js") || e.FullPath.EndsWith(".css") || e.FullPath.EndsWith(".md")))
			{
				UILiveReload val = (UILiveReload)_liveReload.GetValue(GameManager.instance.userInterface.view);
				if (val != null)
				{
					ReflectionUtils.Invoke(_onChanged, (object)val, new object[1] { e.FullPath });
				}
				else
				{
					GameManager.instance.userInterface.view.View.Reload();
				}
				_log.Info("Gooee reloaded the UI view.");
			}
		}
	}
}
namespace Gooee.Helpers
{
	public static class EmbeddedResource
	{
		private static readonly Assembly _assembly = Assembly.GetExecutingAssembly();

		public static byte[] Load(string resourceName, Assembly targetAssembly = null)
		{
			using Stream stream = (targetAssembly ?? _assembly).GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				throw new InvalidOperationException("Resource not found: " + resourceName);
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			return array;
		}

		public static string LoadText(string resourceName, Assembly targetAssembly = null)
		{
			using Stream stream = (targetAssembly ?? _assembly).GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				throw new InvalidOperationException("Resource not found: " + resourceName);
			}
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}

		public static bool Exists(string resourceName, Assembly targetAssembly = null)
		{
			if (string.IsNullOrEmpty(resourceName) || targetAssembly == null)
			{
				return false;
			}
			Assembly assembly = targetAssembly ?? _assembly;
			try
			{
				using Stream stream = assembly.GetManifestResourceStream(resourceName);
				if (stream == null)
				{
					return false;
				}
				return true;
			}
			catch (Exception)
			{
				return false;
			}
		}
	}
	public class GooeeLogger
	{
		private static Dictionary<string, GooeeLogger> _loggers = new Dictionary<string, GooeeLogger>();

		protected readonly ILog _gameLog;

		protected readonly ManualLogSource _bepInEx;

		public static GooeeLogger Get(string name)
		{
			if (_loggers.ContainsKey(name))
			{
				return _loggers[name];
			}
			GooeeLogger gooeeLogger = new GooeeLogger(name);
			_loggers[name] = gooeeLogger;
			return gooeeLogger;
		}

		internal GooeeLogger(string name)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			_gameLog = LogManager.GetLogger(name);
			_bepInEx = (ManualLogSource)((IEnumerable<ILogSource>)Logger.Sources).FirstOrDefault((Func<ILogSource, bool>)((ILogSource s) => s.SourceName == name));
		}

		public void Trace(string message)
		{
			_gameLog.Trace((object)message);
			_bepInEx.LogInfo((object)message);
		}

		public void Info(string message)
		{
			_gameLog.Info((object)message);
			_bepInEx.LogInfo((object)message);
		}

		public void Debug(string message)
		{
			_gameLog.Debug((object)message);
			_bepInEx.LogDebug((object)message);
		}

		public void Warning(string message)
		{
			_gameLog.Warn((object)message);
		}

		public void Warning(Exception exception)
		{
			_gameLog.Warn(exception);
		}

		public void Error(string message)
		{
			_gameLog.Error((object)message);
		}

		public void Error(Exception exception)
		{
			_gameLog.Error(exception);
		}
	}
	public static class LocalisationHelper
	{
		private static readonly Lazy<LocalizationManager> _localizationManager = new Lazy<LocalizationManager>((Func<LocalizationManager>)(() => GameManager.instance.localizationManager));

		private static readonly Lazy<string[]> _locales = new Lazy<string[]>(() => _localizationManager.Value.GetSupportedLocales());

		private static readonly GooeeLogger _log = GooeeLogger.Get("Gooee");

		public static void Load(string resourcePath, Assembly targetAssembly = null, string settingsName = null)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			bool flag = false;
			LocalizationManager value = _localizationManager.Value;
			List<string> list = new List<string>();
			string[] value2 = _locales.Value;
			foreach (string text in value2)
			{
				string resourceName = resourcePath + "." + text + ".yml";
				if (EmbeddedResource.Exists(resourceName, targetAssembly))
				{
					string contents = EmbeddedResource.LoadText(resourceName, targetAssembly);
					Dictionary<string, Dictionary<string, string>> dictionary = YmlHelper.Parse(Path.GetFileNameWithoutExtension(targetAssembly.Location), settingsName, contents);
					if (dictionary != null && dictionary.TryGetValue("lang", out var value3))
					{
						value.AddSource(text, (IDictionarySource)new MemorySource(value3));
						list.Add(text);
						flag = true;
					}
				}
			}
			if (!flag)
			{
				_log.Warning("Could not find localisation for '" + resourcePath + "'.");
				return;
			}
			_log.Info("Loaded localisation for '" + targetAssembly.GetName().Name + "' [" + string.Join(", ", list) + "].");
		}
	}
	public static class ModOptionsBuilder
	{
		public static void Add()
		{
		}
	}
	public static class YmlHelper
	{
		public static Dictionary<string, Dictionary<string, string>> Parse(string assemblyName, string settingsName, string contents)
		{
			if (string.IsNullOrEmpty(contents))
			{
				return null;
			}
			Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>();
			string key = null;
			string[] array = contents.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				if (string.IsNullOrWhiteSpace(text) || text.Trim().StartsWith("#"))
				{
					continue;
				}
				if (!text.StartsWith(" "))
				{
					key = text.Trim(':').Trim();
					dictionary[key] = new Dictionary<string, string>();
					continue;
				}
				string[] array2 = text.Trim().Split(new char[1] { ':' }, 2);
				if (array2.Length != 2)
				{
					throw new FormatException("Invalid line format");
				}
				string text2 = array2[0].Trim();
				string value = array2[1].Trim();
				if (settingsName != null && text2.Trim() == "ModName")
				{
					dictionary[key]["Options.SECTION[" + assemblyName + "." + settingsName + "]"] = value;
				}
				else if (settingsName != null && text2.EndsWith(".Option_desc"))
				{
					dictionary[key]["Options.OPTION_DESCRIPTION[" + assemblyName + "." + settingsName + "." + settingsName + "." + text2.Replace(".Option_desc", "") + "]"] = value;
				}
				else if (settingsName != null && text2.EndsWith(".Option"))
				{
					dictionary[key]["Options.OPTION[" + assemblyName + "." + settingsName + "." + settingsName + "." + text2.Replace(".Option", "") + "]"] = value;
				}
				else if (settingsName != null && text2.EndsWith(".Group"))
				{
					dictionary[key]["Options.GROUP[" + assemblyName + "." + settingsName + "." + text2.Replace(".Group", "") + "]"] = value;
				}
				else if (settingsName != null && text2.EndsWith(".Tab"))
				{
					dictionary[key]["Options.TAB[" + assemblyName + "." + settingsName + "." + text2.Replace(".Tab", "") + "]"] = value;
				}
				else
				{
					dictionary[key][text2] = value;
				}
			}
			return dictionary;
		}
	}
}
namespace Gooee.Extensions
{
	public static class GooeePluginExtensions
	{
		public static string GetPath(this IGooeePlugin plugin)
		{
			return Path.Combine(Application.persistentDataPath, "Mods", plugin.Name);
		}
	}
}