Decompiled source of StationRangePlus v1.0.1

plugins\StationRangePlus.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using StationRangePlus.Localization;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("PONEIS")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Hold Alt + scroll to adjust crafting station build range per bench, with a global multiplier")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+d304014157d4464f965ee2a75b11b45fa3a2a2e4")]
[assembly: AssemblyProduct("StationRangePlus")]
[assembly: AssemblyTitle("StationRangePlus")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace StationRangePlus
{
	internal static class ModConfig
	{
		internal static ConfigEntry<KeyCode> HoldKey;

		internal static ConfigEntry<bool> BlockCameraZoom;

		internal static ConfigEntry<float> ScrollStep;

		internal static ConfigEntry<float> MinRange;

		internal static ConfigEntry<float> MaxRange;

		internal static ConfigEntry<float> GlobalMultiplier;

		internal static ConfigEntry<bool> RequireLookingAtStation;

		internal static ConfigEntry<float> MaxAdjustDistance;

		internal static ConfigEntry<bool> ShowAreaMarker;

		internal static ConfigEntry<string> Language;

		internal static void Bind(ConfigFile config)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			HoldKey = config.Bind<KeyCode>("Controls", "HoldKey", (KeyCode)308, "Hold this key and scroll to change the nearest crafting station build range. Default LeftAlt (RightAlt also works when Alt is chosen).");
			BlockCameraZoom = config.Bind<bool>("Controls", "BlockCameraZoom", true, "While HoldKey is held, block character camera zoom so scroll only changes station range.");
			ScrollStep = config.Bind<float>("Controls", "ScrollStep", 1f, new ConfigDescription("Meters added/removed per scroll tick.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
			MinRange = config.Bind<float>("Range", "MinRange", 2f, new ConfigDescription("Minimum base build range (meters).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			MaxRange = config.Bind<float>("Range", "MaxRange", 100f, new ConfigDescription("Maximum base build range (meters).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 500f), Array.Empty<object>()));
			GlobalMultiplier = config.Bind<float>("Range", "GlobalMultiplier", 1f, new ConfigDescription("Multiplies every station base range (custom or vanilla). 1 = no change.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
			RequireLookingAtStation = config.Bind<bool>("Controls", "RequireLookingAtStation", true, "If true, prefer the station under the crosshair; otherwise the nearest station in MaxAdjustDistance.");
			MaxAdjustDistance = config.Bind<float>("Controls", "MaxAdjustDistance", 8f, new ConfigDescription("Max distance to a station for Alt+scroll adjust.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 30f), Array.Empty<object>()));
			ShowAreaMarker = config.Bind<bool>("Controls", "ShowAreaMarker", true, "Show the station area circle while adjusting range.");
			Language = config.Bind<string>("Localization", "Language", "Auto", "Language for StationRangePlus messages. Auto follows the game. Values: Auto, English, Portuguese.");
			Language.SettingChanged += delegate
			{
				Loc.ApplyLanguagePreference();
			};
			GlobalMultiplier.SettingChanged += delegate
			{
				StationRangeService.ReapplyAll();
			};
		}

		internal static bool IsHoldKeyDown()
		{
			//IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			KeyCode value = HoldKey.Value;
			if ((int)value == 308 || (int)value == 307)
			{
				if (!Input.GetKey((KeyCode)308))
				{
					return Input.GetKey((KeyCode)307);
				}
				return true;
			}
			if ((int)value == 306 || (int)value == 305)
			{
				if (!Input.GetKey((KeyCode)306))
				{
					return Input.GetKey((KeyCode)305);
				}
				return true;
			}
			if ((int)value == 304 || (int)value == 303)
			{
				if (!Input.GetKey((KeyCode)304))
				{
					return Input.GetKey((KeyCode)303);
				}
				return true;
			}
			return Input.GetKey(value);
		}
	}
	[BepInPlugin("poneis.valheim.StationRangePlus", "StationRangePlus", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "poneis.valheim.StationRangePlus";

		public const string PluginName = "StationRangePlus";

		public const string PluginVersion = "1.0.1";

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			Loc.Init();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "poneis.valheim.StationRangePlus");
			((Component)this).gameObject.AddComponent<RangeInputListener>();
			Log.LogInfo((object)"StationRangePlus 1.0.1 loaded.");
		}
	}
	internal sealed class RangeInputListener : MonoBehaviour
	{
		private void Update()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			StationRangeService.TickMarkers();
			if (!ModConfig.IsHoldKeyDown())
			{
				return;
			}
			float y = Input.mouseScrollDelta.y;
			if (!(Mathf.Abs(y) < 0.01f))
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !Console.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()))
				{
					StationRangeService.TryAdjustFromScroll(localPlayer, y);
				}
			}
		}
	}
	internal static class StationRangeService
	{
		internal static readonly int RangeHash = StringExtensionMethods.GetStableHashCode("srp_range");

		private static readonly Dictionary<CraftingStation, float> VanillaDefaults = new Dictionary<CraftingStation, float>();

		private static float _nextMsg;

		private static CraftingStation _lastMarker;

		internal static void RememberVanillaDefault(CraftingStation station)
		{
			if (!((Object)(object)station == (Object)null) && !VanillaDefaults.ContainsKey(station))
			{
				VanillaDefaults[station] = station.m_rangeBuild;
			}
		}

		internal static void Forget(CraftingStation station)
		{
			if ((Object)(object)station != (Object)null)
			{
				VanillaDefaults.Remove(station);
			}
		}

		internal static float GetVanillaDefault(CraftingStation station)
		{
			RememberVanillaDefault(station);
			if (!VanillaDefaults.TryGetValue(station, out var value))
			{
				return station.m_rangeBuild;
			}
			return value;
		}

		internal static float GetStoredBase(CraftingStation station)
		{
			RememberVanillaDefault(station);
			ZDO val = (((Object)(object)station.m_nview != (Object)null) ? station.m_nview.GetZDO() : null);
			float num = default(float);
			if (val != null && val.IsValid() && val.GetFloat(RangeHash, ref num) && num > 0.01f)
			{
				return num;
			}
			return GetVanillaDefault(station);
		}

		internal static void SetStoredBase(CraftingStation station, float baseRange)
		{
			baseRange = Mathf.Clamp(baseRange, ModConfig.MinRange.Value, ModConfig.MaxRange.Value);
			ZNetView nview = station.m_nview;
			if ((Object)(object)nview != (Object)null && nview.IsValid())
			{
				if (!nview.IsOwner())
				{
					nview.ClaimOwnership();
				}
				ZDO zDO = nview.GetZDO();
				if (zDO != null && zDO.IsValid())
				{
					zDO.Set(RangeHash, baseRange);
				}
			}
			Apply(station, baseRange);
		}

		internal static void Apply(CraftingStation station, float? baseRange = null)
		{
			if (!((Object)(object)station == (Object)null))
			{
				RememberVanillaDefault(station);
				float num = baseRange ?? GetStoredBase(station);
				float num2 = Mathf.Max(0.01f, ModConfig.GlobalMultiplier.Value);
				float rangeBuild = Mathf.Clamp(num * num2, ModConfig.MinRange.Value, ModConfig.MaxRange.Value * Mathf.Max(1f, num2));
				station.m_rangeBuild = rangeBuild;
				station.m_updateExtensionTimer = 2f;
				RefreshVisuals(station);
			}
		}

		internal static void RefreshVisuals(CraftingStation station)
		{
			if ((Object)(object)station == (Object)null)
			{
				return;
			}
			float radius = ((station.m_buildRange > 0.01f) ? station.m_buildRange : station.m_rangeBuild);
			if ((Object)(object)station.m_areaMarkerCircle != (Object)null)
			{
				station.m_areaMarkerCircle.m_radius = radius;
			}
			Collider effectAreaCollider = station.m_effectAreaCollider;
			SphereCollider val = (SphereCollider)(object)((effectAreaCollider is SphereCollider) ? effectAreaCollider : null);
			if (val != null)
			{
				val.radius = radius;
				return;
			}
			CapsuleCollider val2 = (CapsuleCollider)(object)((effectAreaCollider is CapsuleCollider) ? effectAreaCollider : null);
			if (val2 != null)
			{
				val2.radius = radius;
			}
		}

		internal static void ReapplyAll()
		{
			foreach (CraftingStation allStation in CraftingStation.m_allStations)
			{
				if ((Object)(object)allStation != (Object)null)
				{
					Apply(allStation);
				}
			}
		}

		internal static CraftingStation FindAdjustTarget(Player player)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			float value = ModConfig.MaxAdjustDistance.Value;
			CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
			if ((Object)(object)currentCraftingStation != (Object)null && Vector3.Distance(((Component)player).transform.position, ((Component)currentCraftingStation).transform.position) <= value)
			{
				return currentCraftingStation;
			}
			CraftingStation result = null;
			float num = float.MaxValue;
			Vector3 eyePoint = ((Character)player).GetEyePoint();
			Vector3 lookDir = ((Character)player).GetLookDir();
			foreach (CraftingStation allStation in CraftingStation.m_allStations)
			{
				if ((Object)(object)allStation == (Object)null)
				{
					continue;
				}
				float num2 = Vector3.Distance(((Component)player).transform.position, ((Component)allStation).transform.position);
				if (num2 > value)
				{
					continue;
				}
				float num3 = num2;
				if (ModConfig.RequireLookingAtStation.Value)
				{
					Vector3 val = ((Component)allStation).transform.position - eyePoint;
					Vector3 normalized = ((Vector3)(ref val)).normalized;
					float num4 = Vector3.Dot(lookDir, normalized);
					if (num4 < 0.35f)
					{
						continue;
					}
					num3 = num2 * (1.5f - num4);
				}
				if (num3 < num)
				{
					num = num3;
					result = allStation;
				}
			}
			return result;
		}

		internal static void TryAdjustFromScroll(Player player, float scrollY)
		{
			if ((Object)(object)player == (Object)null || Mathf.Abs(scrollY) < 0.01f)
			{
				return;
			}
			CraftingStation val = FindAdjustTarget(player);
			if ((Object)(object)val == (Object)null)
			{
				if (Time.time >= _nextMsg)
				{
					_nextMsg = Time.time + 0.4f;
					((Character)player).Message((MessageType)2, Loc.T("srp_msg_no_station"), 0, (Sprite)null, false);
				}
				return;
			}
			float value = ModConfig.ScrollStep.Value;
			float num = ((scrollY > 0f) ? value : (0f - value));
			float baseRange = GetStoredBase(val) + num;
			SetStoredBase(val, baseRange);
			if (ModConfig.ShowAreaMarker.Value)
			{
				if ((Object)(object)_lastMarker != (Object)null && (Object)(object)_lastMarker != (Object)(object)val)
				{
					HideMarker(_lastMarker);
				}
				val.ShowAreaMarker();
				_lastMarker = val;
			}
			float stationBuildRange = val.GetStationBuildRange();
			((Character)player).Message((MessageType)2, Loc.Tf("srp_msg_range", stationBuildRange, ModConfig.GlobalMultiplier.Value), 0, (Sprite)null, false);
		}

		internal static void HideMarker(CraftingStation station)
		{
			if ((Object)(object)station?.m_areaMarker != (Object)null)
			{
				station.m_areaMarker.SetActive(false);
			}
		}

		internal static void TickMarkers()
		{
			if (!ModConfig.IsHoldKeyDown() && (Object)(object)_lastMarker != (Object)null)
			{
				HideMarker(_lastMarker);
				_lastMarker = null;
			}
		}
	}
}
namespace StationRangePlus.Patches
{
	[HarmonyPatch]
	internal static class CameraZoomBlockPatch
	{
		private static float _savedDistance;

		private static bool _restore;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static void Prefix(GameCamera __instance)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			_restore = false;
			if (ModConfig.BlockCameraZoom.Value && ModConfig.IsHoldKeyDown() && Input.mouseScrollDelta.y != 0f && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				_savedDistance = __instance.m_distance;
				_restore = true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static void Postfix(GameCamera __instance)
		{
			if (_restore)
			{
				__instance.m_distance = _savedDistance;
			}
		}
	}
	[HarmonyPatch]
	internal static class CraftingStationRangePatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(CraftingStation), "Start")]
		private static void StartPostfix(CraftingStation __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				StationRangeService.RememberVanillaDefault(__instance);
				StationRangeService.Apply(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CraftingStation), "OnDestroy")]
		private static void OnDestroyPostfix(CraftingStation __instance)
		{
			StationRangeService.Forget(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CraftingStation), "GetExtensions")]
		private static void GetExtensionsPostfix(CraftingStation __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				float num = Mathf.Clamp(StationRangeService.GetStoredBase(__instance) * Mathf.Max(0.01f, ModConfig.GlobalMultiplier.Value), ModConfig.MinRange.Value, ModConfig.MaxRange.Value * Mathf.Max(1f, ModConfig.GlobalMultiplier.Value));
				if (Mathf.Abs(__instance.m_rangeBuild - num) > 0.05f)
				{
					__instance.m_rangeBuild = num;
				}
				__instance.m_buildRange = __instance.m_rangeBuild + (float)__instance.GetExtentionCount(false) * __instance.m_extraRangePerLevel;
				StationRangeService.RefreshVisuals(__instance);
			}
		}
	}
}
namespace StationRangePlus.Localization
{
	internal static class Loc
	{
		private static readonly Dictionary<string, Dictionary<string, string>> Tables = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);

		private static string _activeCode = "en";

		private static string LangDir => Path.Combine(Paths.ConfigPath, "StationRangePlus", "lang");

		internal static void Init()
		{
			EnsureLangFolder();
			LoadEmbedded("en");
			LoadEmbedded("pt");
			LoadDiskOverrides();
			ApplyLanguagePreference();
			Plugin.Log.LogInfo((object)("Localization ready (active=" + _activeCode + ", files in " + LangDir + ")"));
		}

		internal static string T(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return key;
			}
			if (Tables.TryGetValue(_activeCode, out var value) && value.TryGetValue(key, out var value2))
			{
				return value2;
			}
			if (Tables.TryGetValue("en", out var value3) && value3.TryGetValue(key, out value2))
			{
				return value2;
			}
			return key;
		}

		internal static string Tf(string key, params object[] args)
		{
			try
			{
				return string.Format(T(key), args);
			}
			catch (FormatException)
			{
				return T(key);
			}
		}

		private static void EnsureLangFolder()
		{
			Directory.CreateDirectory(LangDir);
			WriteEmbedded("en");
			WriteEmbedded("pt");
		}

		private static void WriteEmbedded(string code)
		{
			string path = Path.Combine(LangDir, code + ".json");
			string text = ReadEmbedded(code);
			if (!string.IsNullOrEmpty(text))
			{
				File.WriteAllText(path, text, Encoding.UTF8);
			}
		}

		private static void LoadEmbedded(string code)
		{
			string text = ReadEmbedded(code);
			if (!string.IsNullOrEmpty(text))
			{
				Tables[code] = ParseFlatJson(text);
			}
		}

		private static void LoadDiskOverrides()
		{
			if (!Directory.Exists(LangDir))
			{
				return;
			}
			string[] files = Directory.GetFiles(LangDir, "*.json");
			foreach (string text in files)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
				try
				{
					Dictionary<string, string> dictionary = ParseFlatJson(File.ReadAllText(text, Encoding.UTF8));
					if (dictionary.Count == 0)
					{
						continue;
					}
					if (!Tables.TryGetValue(fileNameWithoutExtension, out var value))
					{
						Tables[fileNameWithoutExtension] = dictionary;
						continue;
					}
					foreach (KeyValuePair<string, string> item in dictionary)
					{
						value[item.Key] = item.Value;
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Failed to load lang file " + text + ": " + ex.Message));
				}
			}
		}

		private static string ReadEmbedded(string code)
		{
			string text = "StationRangePlus.Languages." + code + ".json";
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text);
			if (stream == null)
			{
				Plugin.Log.LogWarning((object)("Missing embedded language resource: " + text));
				return null;
			}
			using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
			return streamReader.ReadToEnd();
		}

		internal static void ApplyLanguagePreference()
		{
			string a = ModConfig.Language?.Value ?? "Auto";
			if (string.Equals(a, "Portuguese", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "pt", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "pt-BR", StringComparison.OrdinalIgnoreCase))
			{
				_activeCode = (Tables.ContainsKey("pt") ? "pt" : "en");
				return;
			}
			if (string.Equals(a, "English", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "en", StringComparison.OrdinalIgnoreCase))
			{
				_activeCode = "en";
				return;
			}
			try
			{
				string text = ((Localization.instance != null) ? Localization.instance.GetSelectedLanguage() : null);
				if (!string.IsNullOrEmpty(text) && (text.IndexOf("Portuguese", StringComparison.OrdinalIgnoreCase) >= 0 || text.StartsWith("pt", StringComparison.OrdinalIgnoreCase) || text.IndexOf("Brazil", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					_activeCode = (Tables.ContainsKey("pt") ? "pt" : "en");
					return;
				}
			}
			catch
			{
			}
			_activeCode = "en";
		}

		internal static Dictionary<string, string> ParseFlatJson(string json)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(json))
			{
				return dictionary;
			}
			int i = 0;
			SkipWs(json, ref i);
			if (i >= json.Length || json[i] != '{')
			{
				return dictionary;
			}
			i++;
			while (i < json.Length)
			{
				SkipWs(json, ref i);
				if (i < json.Length && json[i] == '}')
				{
					break;
				}
				if (i < json.Length && json[i] == ',')
				{
					i++;
					continue;
				}
				if (!TryReadString(json, ref i, out var value))
				{
					break;
				}
				SkipWs(json, ref i);
				if (i >= json.Length || json[i] != ':')
				{
					break;
				}
				i++;
				SkipWs(json, ref i);
				if (!TryReadString(json, ref i, out var value2))
				{
					break;
				}
				dictionary[value] = value2;
			}
			return dictionary;
		}

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

		private static bool TryReadString(string s, ref int i, out string value)
		{
			value = null;
			SkipWs(s, ref i);
			if (i >= s.Length || s[i] != '"')
			{
				return false;
			}
			i++;
			StringBuilder stringBuilder = new StringBuilder();
			while (i < s.Length)
			{
				char c = s[i++];
				switch (c)
				{
				case '"':
					value = stringBuilder.ToString();
					return true;
				case '\\':
					if (i < s.Length)
					{
						char c2 = s[i++];
						StringBuilder stringBuilder2 = stringBuilder;
						stringBuilder2.Append(c2 switch
						{
							'n' => '\n', 
							'r' => '\r', 
							't' => '\t', 
							'"' => '"', 
							'\\' => '\\', 
							_ => c2, 
						});
						continue;
					}
					break;
				}
				stringBuilder.Append(c);
			}
			return false;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}