Decompiled source of AWOPartialDataFixer v0.0.5

AWOPartialDataFixer.dll

Decompiled a month ago
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using AIGraph;
using AssetShards;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CellMenu;
using GTFO.API.Utilities;
using GameData;
using Gear;
using Globals;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using InjectLib.JsonNETInjection.Supports;
using LevelGeneration;
using Localization;
using MTFO.Ext.PartialData.DTO;
using MTFO.Ext.PartialData.DataBlockTypes;
using MTFO.Ext.PartialData.JsonConverters;
using MTFO.Ext.PartialData.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("MTFO.Ext.PartialData")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+git840f432-dirty-master.840f43267d7d12578827bcb6ba31777d303c912e")]
[assembly: AssemblyProduct("MTFO.Ext.PartialData")]
[assembly: AssemblyTitle("MTFO.Ext.PartialData")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace MTFO.Ext.PartialData
{
	[BepInPlugin("MTFO.Extension.PartialBlocks", "MTFO pDataBlock", "1.4.5")]
	[BepInProcess("GTFO.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal class EntryPoint : BasePlugin
	{
		private bool once;

		public override void Load()
		{
			//IL_001b: 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_0036: Expected O, but got Unknown
			//IL_0036: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_0062: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			Logger.LogInstance = ((BasePlugin)this).Log;
			ConfigEntry<bool> val = ((BasePlugin)this).Config.Bind<bool>(new ConfigDefinition("Logging", "UseLog"), false, new ConfigDescription("Using Log Message for Debug?", (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigEntry<bool> obj = ((BasePlugin)this).Config.Bind<bool>(new ConfigDefinition("Developer", "UseLiveEdit"), false, new ConfigDescription("Using Live Edit?", (AcceptableValueBase)null, Array.Empty<object>()));
			Logger.UsingLog = val.Value;
			PartialDataManager.CanLiveEdit = obj.Value;
			if (!DataBlockTypeManager.Initialize())
			{
				Logger.Error("Unable to Initialize DataBlockTypeCache");
				return;
			}
			if (!PartialDataManager.Initialize())
			{
				Logger.Error("Unable to Initialize PartialData");
				return;
			}
			PersistentIDManager.DumpToFile(Path.Combine(PartialDataManager.PartialDataPath, "_persistentID.json"));
			AssetShardManager.OnStartupAssetsLoaded += Action.op_Implicit((Action)OnAssetLoaded);
			new Harmony("MTFO.pBlock.Harmony").PatchAll();
		}

		private void OnAssetLoaded()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			if (once)
			{
				return;
			}
			once = true;
			PartialDataManager.LoadPartialData();
			GameDataTextLocalizationService val = ((Il2CppObjectBase)Text.TextLocalizationService).Cast<GameDataTextLocalizationService>();
			val.m_textDataBlocks = null;
			val.m_texts.Clear();
			Language currentLanguage = Text.TextLocalizationService.CurrentLanguage;
			TextDataBlock[] array = Il2CppArrayBase<TextDataBlock>.op_Implicit(GameDataBlockBase<TextDataBlock>.GetAllBlocks());
			val.m_textDataBlocks = Il2CppReferenceArray<TextDataBlock>.op_Implicit(array);
			int num = array.Length;
			for (int i = 0; i < num; i++)
			{
				TextDataBlock val2 = array[i];
				string text = val2.GetText(currentLanguage, false);
				if (string.IsNullOrWhiteSpace(text))
				{
					text = val2.English;
				}
				val.m_texts[((GameDataBlockBase<TextDataBlock>)(object)val2).persistentID] = text;
			}
			Text.TextLocalizationService.SetCurrentLanguage(Text.TextLocalizationService.CurrentLanguage);
			Text.UpdateAllTexts();
			PartialDataManager.WriteAllFile(Path.Combine(MTFOUtil.GameDataPath, "CompiledPartialData"));
		}
	}
	public static class LocalizedTextManager
	{
		public static Dictionary<LocalizedText, (uint, string)> _lookup = new Dictionary<LocalizedText, (uint, string)>();

		public static void Register(LocalizedText localizedText, uint id, string unlocalized)
		{
			_lookup[localizedText] = (id, unlocalized);
		}

		public static void Get(LocalizedText localizedText)
		{
		}
	}
	internal class PartialDataCache
	{
		public string Name => DataBlockType.GetShortName();

		public IDataBlockType DataBlockType { get; private set; }

		public Queue<string> JsonsToRead { get; private set; } = new Queue<string>();


		private PartialDataCache()
		{
		}

		public PartialDataCache(IDataBlockType dbTypeCache)
		{
			DataBlockType = dbTypeCache;
		}
	}
	public class PartialDataManager
	{
		private static List<DataBlockDefinition> _Config;

		private static readonly List<string> _AddedFileList = new List<string>();

		private static readonly List<PartialDataCache> _DataCache = new List<PartialDataCache>();

		public static string PartialDataPath { get; private set; }

		public static string ConfigPath { get; private set; }

		public static bool Initialized { get; private set; } = false;


		public static bool CanLiveEdit { get; set; } = false;


		public static PersistentIDConverter IDConverter { get; private set; } = new PersistentIDConverter();


		internal static bool Initialize()
		{
			if (Initialized)
			{
				return false;
			}
			if (!MTFOUtil.IsLoaded)
			{
				return false;
			}
			PartialDataPath = Path.GetFullPath(Path.Combine(MTFOUtil.GameDataPath, "PartialData"));
			if (!Directory.Exists(PartialDataPath))
			{
				Logger.Error("Unable to setup PartialData::PartialData folder is missing");
				return false;
			}
			ConfigPath = Path.GetFullPath(Path.Combine(PartialDataPath, "_config.json"));
			if (!File.Exists(ConfigPath))
			{
				Logger.Error("Unable to setup PartialData::Config File (_config.json) is missing");
				return false;
			}
			_AddedFileList.Clear();
			_DataCache.Clear();
			_Config = JSON.Deserialize<List<DataBlockDefinition>>(File.ReadAllText(ConfigPath));
			Initialized = true;
			ReadAndAssignIDs();
			return true;
		}

		private static void ReadAndAssignIDs()
		{
			foreach (DataBlockDefinition item in _Config)
			{
				DataBlockTypeManager.SetIDBuffer(item.TypeName, item.StartFromID, item.IncrementMode);
			}
			foreach (string item2 in from f in Directory.GetFiles(PartialDataPath, "*.json", SearchOption.AllDirectories)
				orderby f
				select f)
			{
				if (Path.GetFileName(item2).StartsWith("_"))
				{
					Logger.Log(item2 + " have discard prefix (_) excluding from loader!");
					continue;
				}
				if (!File.Exists(item2))
				{
					Logger.Error("File (" + item2 + ") is not exist somehow?");
					continue;
				}
				if (_AddedFileList.Contains(item2))
				{
					Logger.Error("File (" + item2 + ") has loaded multiple times!");
					continue;
				}
				_AddedFileList.Add(item2);
				AssignPersistentID(item2);
				Logger.Log(" - " + item2);
			}
		}

		private static void AssignPersistentID(string file)
		{
			using JsonDocument jsonDocument = JsonDocument.Parse(File.ReadAllText(file), new JsonDocumentOptions
			{
				CommentHandling = JsonCommentHandling.Skip,
				AllowTrailingCommas = true
			});
			JsonElement rootElement = jsonDocument.RootElement;
			switch (rootElement.ValueKind)
			{
			case JsonValueKind.Array:
			{
				foreach (JsonElement item in rootElement.EnumerateArray())
				{
					Read(item, assignID: true, file);
				}
				break;
			}
			case JsonValueKind.Object:
				Read(rootElement, assignID: true, file);
				break;
			}
		}

		private static void ReadChangedFile(string content, string debugName)
		{
			using JsonDocument jsonDocument = JsonDocument.Parse(content, new JsonDocumentOptions
			{
				CommentHandling = JsonCommentHandling.Skip,
				AllowTrailingCommas = true
			});
			JsonElement rootElement = jsonDocument.RootElement;
			switch (rootElement.ValueKind)
			{
			case JsonValueKind.Array:
			{
				foreach (JsonElement item in rootElement.EnumerateArray())
				{
					Read(item, assignID: false, debugName);
				}
				break;
			}
			case JsonValueKind.Object:
				Read(rootElement, assignID: false, debugName);
				break;
			}
		}

		private static void ReadChangedFile(string file)
		{
			ReadChangedFile(File.ReadAllText(file), file);
		}

		private static void Read(JsonElement objNode, bool assignID, string debugName)
		{
			if (!objNode.TryGetProperty("persistentID", out var value))
			{
				Logger.Error("persistentID field is missing: " + debugName);
				return;
			}
			if (!objNode.TryGetProperty("datablock", out var value2))
			{
				Logger.Error("datablock field is missing: " + debugName);
				return;
			}
			if (assignID && value.ValueKind == JsonValueKind.String)
			{
				if (!DataBlockTypeManager.TryGetNextID(value2.GetString(), out var id))
				{
					Logger.Error($"datablock field is not valid: {debugName} {objNode}");
					return;
				}
				PersistentIDManager.TryAssignId(value.GetString(), id);
			}
			string datablockName = DataBlockTypeManager.GetBlockName(value2.GetString());
			if (!DataBlockTypeManager.TryFindCache(datablockName, out IDataBlockType cache))
			{
				Logger.Error($"datablock field is not valid: {debugName} {objNode}");
				return;
			}
			PartialDataCache partialDataCache = _DataCache.FirstOrDefault((PartialDataCache x) => x.Name.Equals(datablockName));
			if (partialDataCache == null)
			{
				partialDataCache = new PartialDataCache(cache);
				_DataCache.Add(partialDataCache);
			}
			partialDataCache.JsonsToRead.Enqueue(objNode.ToString());
		}

		internal static void LoadPartialData()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			if (Initialized)
			{
				if (CanLiveEdit)
				{
					LiveEdit.CreateListener(PartialDataPath, "*.json", true).FileChanged += new LiveEditEventHandler(Listener_FileChanged1);
				}
				AddAllCache();
			}
		}

		private static void Listener_FileChanged1(LiveEditEventArgs e)
		{
			LiveEditEventArgs e2 = e;
			Logger.Warning("LiveEdit File Changed: " + e2.FullPath);
			LiveEdit.TryReadFileContent(e2.FullPath, (Action<string>)delegate(string content)
			{
				ReadChangedFile(content, e2.FullPath);
				AddAllCache(isLiveEdit: true);
			});
		}

		internal static void WriteAllFile(string path)
		{
			if (!Directory.Exists(path))
			{
				return;
			}
			foreach (PartialDataCache item in _DataCache)
			{
				string fullPath = Path.GetFullPath(Path.Combine(path, "GameData_" + item.DataBlockType.GetFullName() + "_bin.json"));
				item.DataBlockType.DoSaveToDisk(fullPath);
			}
		}

		private static void AddAllCache(bool isLiveEdit = false)
		{
			foreach (PartialDataCache item in _DataCache)
			{
				bool flag = false;
				while (item.JsonsToRead.Count > 0)
				{
					string json = item.JsonsToRead.Dequeue();
					item.DataBlockType.AddJsonBlock(json);
					flag = true;
				}
				if (flag && isLiveEdit)
				{
					item.DataBlockType.OnChanged();
				}
			}
		}

		public static uint GetID(string guid)
		{
			if (!Initialized)
			{
				return 0u;
			}
			return PersistentIDManager.GetId(guid);
		}
	}
	public class PartialDataPack
	{
		private readonly List<string> _AddedFiles = new List<string>();

		private readonly List<PartialDataCache> _DataCaches = new List<PartialDataCache>();

		public string Namespace { get; private set; } = string.Empty;


		public bool CheckFileChange { get; set; } = true;


		public PartialDataPack()
		{
		}

		public PartialDataPack(string namespaceString)
			: this()
		{
			Namespace = namespaceString;
		}

		public string GetGUIDFormat(string guid)
		{
			if (!string.IsNullOrEmpty(Namespace))
			{
				guid = Namespace + "." + guid;
			}
			return guid;
		}

		public void ClearPack()
		{
			_AddedFiles.Clear();
			_DataCaches.Clear();
		}

		public void ReadPack(string packPath)
		{
			foreach (string item in from f in Directory.GetFiles(packPath, "*.json", SearchOption.AllDirectories)
				orderby f
				select f)
			{
				if (Path.GetFileName(item).StartsWith("_"))
				{
					Logger.Log(item + " have discard prefix (_) excluding from loader!");
					continue;
				}
				if (!File.Exists(item))
				{
					Logger.Error("File (" + item + ") is not exist somehow?");
					continue;
				}
				if (_AddedFiles.Contains(item))
				{
					Logger.Error("File (" + item + ") has loaded multiple times!");
					continue;
				}
				_AddedFiles.Add(item);
				AllocateGUIDFromFile(item);
				Logger.Log(" - " + item);
			}
			_ = CheckFileChange;
		}

		public void AddToGame()
		{
			foreach (PartialDataCache dataCache in _DataCaches)
			{
				while (dataCache.JsonsToRead.Count > 0)
				{
					string json = dataCache.JsonsToRead.Dequeue();
					dataCache.DataBlockType.AddJsonBlock(json);
				}
			}
		}

		public void WriteGameDataFile(string path)
		{
			if (!Directory.Exists(path))
			{
				return;
			}
			foreach (PartialDataCache dataCache in _DataCaches)
			{
				string fullPath = Path.GetFullPath(Path.Combine(path, "GameData_" + dataCache.DataBlockType.GetFullName() + "_bin.json"));
				dataCache.DataBlockType.DoSaveToDisk(fullPath);
			}
		}

		private void AllocateGUIDFromFile(string file)
		{
			using JsonDocument jsonDocument = JsonDocument.Parse(File.ReadAllText(file), new JsonDocumentOptions
			{
				CommentHandling = JsonCommentHandling.Skip,
				AllowTrailingCommas = true
			});
			JsonElement rootElement = jsonDocument.RootElement;
			switch (rootElement.ValueKind)
			{
			case JsonValueKind.Array:
			{
				foreach (JsonElement item in rootElement.EnumerateArray())
				{
					Read(item, assignID: true, file);
				}
				break;
			}
			case JsonValueKind.Object:
				Read(rootElement, assignID: true, file);
				break;
			}
		}

		private void ReadChangedFile(string file)
		{
			using JsonDocument jsonDocument = JsonDocument.Parse(File.ReadAllText(file), new JsonDocumentOptions
			{
				CommentHandling = JsonCommentHandling.Skip,
				AllowTrailingCommas = true
			});
			JsonElement rootElement = jsonDocument.RootElement;
			switch (rootElement.ValueKind)
			{
			case JsonValueKind.Array:
			{
				foreach (JsonElement item in rootElement.EnumerateArray())
				{
					Read(item, assignID: false, file);
				}
				break;
			}
			case JsonValueKind.Object:
				Read(rootElement, assignID: false, file);
				break;
			}
		}

		private void OnDatablockChanged()
		{
			foreach (PartialDataCache dataCache in _DataCaches)
			{
				bool flag = false;
				while (dataCache.JsonsToRead.Count > 0)
				{
					if (dataCache.Name.Equals("Rundown"))
					{
						dataCache.JsonsToRead.Clear();
						Logger.Error("Editing Rundown DataBlock will leads to crash, Ignored");
					}
					else
					{
						string json = dataCache.JsonsToRead.Dequeue();
						dataCache.DataBlockType.AddJsonBlock(json);
						flag = true;
					}
				}
				if (flag)
				{
					dataCache.DataBlockType.OnChanged();
				}
			}
		}

		private void Read(JsonElement objNode, bool assignID, string debugName)
		{
			if (!objNode.TryGetProperty("persistentID", out var value))
			{
				Logger.Error("persistentID field is missing: " + debugName);
				return;
			}
			if (!objNode.TryGetProperty("datablock", out var value2))
			{
				Logger.Error("datablock field is missing: " + debugName);
				return;
			}
			if (assignID && value.ValueKind == JsonValueKind.String)
			{
				if (!DataBlockTypeManager.TryGetNextID(value2.GetString(), out var id))
				{
					Logger.Error($"datablock field is not valid: {debugName} {objNode}");
					return;
				}
				PersistentIDManager.TryAssignId(value.GetString(), id);
			}
			string datablockName = DataBlockTypeManager.GetBlockName(value2.GetString());
			if (!DataBlockTypeManager.TryFindCache(datablockName, out IDataBlockType cache))
			{
				Logger.Error($"datablock field is not valid: {debugName} {objNode}");
				return;
			}
			PartialDataCache partialDataCache = _DataCaches.FirstOrDefault((PartialDataCache x) => x.Name.Equals(datablockName));
			if (partialDataCache == null)
			{
				partialDataCache = new PartialDataCache(cache);
				_DataCaches.Add(partialDataCache);
			}
			string text = objNode.ToString();
			if (partialDataCache.DataBlockType.GetShortName() == "PlayerOfflineGear")
			{
				if (!objNode.TryGetProperty("GearJSON", out var value3))
				{
					Logger.Warning("GearJSON field is missing, Ignore Stuff: " + debugName);
				}
				else if (value3.ValueKind == JsonValueKind.String)
				{
					string @string = value3.GetString();
					if (GearJSONUtil.TryProcessGUID(@string, Namespace, out string processedJson))
					{
						@string = @string.Replace("\"", "\\\"");
						processedJson = processedJson.Replace("\"", "\\\"");
						text = text.Replace(@string, processedJson);
						Logger.Warning(text);
					}
				}
			}
			partialDataCache.JsonsToRead.Enqueue(text);
		}
	}
	internal static class PersistentIDManager
	{
		private static readonly Dictionary<string, uint> _GUIDDict = new Dictionary<string, uint>();

		public static bool TryAssignId(string guid, uint id)
		{
			if (_GUIDDict.ContainsKey(guid))
			{
				Logger.Error("GUID is already used: " + guid);
				return false;
			}
			_GUIDDict.Add(guid, id);
			return true;
		}

		public static uint GetId(string guid)
		{
			if (!_GUIDDict.TryGetValue(guid, out var value))
			{
				Logger.Error("GUID is Missing: " + guid);
				return 0u;
			}
			return value;
		}

		public static bool TryGetId(string guid, out uint id)
		{
			if (_GUIDDict.TryGetValue(guid, out id))
			{
				return true;
			}
			id = 0u;
			return false;
		}

		public static void DumpToFile(string path)
		{
			string text = "[\n\t//AUTO-GENERATED PERSISTENT ID LIST\n";
			foreach (KeyValuePair<string, uint> item in _GUIDDict)
			{
				text = text + "\t{ \"GUID\": \"" + item.Key + "\", \"ID\": " + item.Value + " },\n";
			}
			if (text.Length > 2)
			{
				string text2 = text;
				text = text2.Substring(0, text2.Length - 2);
			}
			text += "\n]";
			File.WriteAllText(path, text);
		}
	}
	[GeneratedCode("VersionInfoGenerator", "2.0.0+git50a4b1a-master")]
	[CompilerGenerated]
	internal static class VersionInfo
	{
		public const string RootNamespace = "MTFO.Ext.PartialData";

		public const string Version = "1.0.0";

		public const string VersionPrerelease = null;

		public const string VersionMetadata = "git840f432-dirty-master";

		public const string SemVer = "1.0.0+git840f432-dirty-master";

		public const string GitRevShort = "840f432-dirty";

		public const string GitRevLong = "840f43267d7d12578827bcb6ba31777d303c912e-dirty";

		public const string GitBranch = "master";

		public const string GitTag = null;

		public const bool GitIsDirty = true;
	}
}
namespace MTFO.Ext.PartialData.Utils
{
	public static class GearJSONUtil
	{
		private const string COMP_CHARS = "abcdefghijklmnopqrst";

		public static bool TryProcessGUID(string gearjson, string namespaceStr, out string processedJson)
		{
			string text = gearjson;
			bool flag = false;
			using JsonDocument jsonDocument = JsonDocument.Parse(gearjson);
			if (!jsonDocument.RootElement.TryGetProperty("Packet", out var value))
			{
				processedJson = string.Empty;
				return false;
			}
			if (!value.TryGetProperty("Comps", out var value2))
			{
				processedJson = string.Empty;
				return false;
			}
			string text2 = "abcdefghijklmnopqrst";
			for (int i = 0; i < text2.Length; i++)
			{
				if (value2.TryGetProperty(text2[i].ToString(), out var value3) && value3.TryGetProperty("v", out var value4) && value4.ValueKind == JsonValueKind.String)
				{
					string @string = value4.GetString();
					Logger.Warning("Found String id: " + @string);
					uint id = PersistentIDManager.GetId(@string);
					if (id != 0)
					{
						text = new Regex("(\"v\")\\s*:\\s*(\"" + @string + "\")").Replace(text, $"\"v\":{id}");
						flag = true;
					}
				}
			}
			if (flag)
			{
				Logger.Warning(gearjson);
				Logger.Warning(text);
				processedJson = text;
				return true;
			}
			processedJson = string.Empty;
			return false;
		}
	}
	public class IDBuffer
	{
		public uint CurrentID { get; set; } = 65535u;


		public IncrementMode IncrementMode { get; set; }

		public uint GetNext()
		{
			if (IncrementMode == IncrementMode.Increment)
			{
				return CurrentID++;
			}
			if (IncrementMode == IncrementMode.Decrement)
			{
				return CurrentID--;
			}
			return 0u;
		}
	}
	public enum IncrementMode
	{
		Decrement,
		Increment
	}
	public static class InjectLibUtil
	{
		public const string PLUGIN_GUID = "GTFO.InjectLib";

		public static JsonConverter InjectLibConnector { get; private set; }

		public static bool IsLoaded { get; private set; }

		static InjectLibUtil()
		{
			if (!((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue("GTFO.InjectLib", out var value))
			{
				return;
			}
			try
			{
				Assembly obj = ((value == null) ? null : value.Instance?.GetType()?.Assembly) ?? null;
				if ((object)obj == null)
				{
					throw new Exception("Assembly is Missing!");
				}
				InjectLibConnector = (JsonConverter)Activator.CreateInstance(obj.GetTypes().First((Type t) => t.Name == "InjectLibConnector") ?? throw new Exception("Unable to Find InjectLibConnector Class"));
				IsLoaded = true;
			}
			catch (Exception value2)
			{
				Logger.Error($"Exception thrown while reading data from GTFO.AWO: {value2}");
			}
		}
	}
	internal static class JSON
	{
		private static readonly JsonSerializerOptions _Setting;

		static JSON()
		{
			_Setting = CreateSetting();
			_Setting = CreateSetting();
			_Setting.Converters.Add(new PersistentIDConverter());
		}

		private static JsonSerializerOptions CreateSetting()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			return new JsonSerializerOptions
			{
				ReadCommentHandling = JsonCommentHandling.Skip,
				IncludeFields = true,
				AllowTrailingCommas = true,
				WriteIndented = true,
				Converters = 
				{
					(JsonConverter)new Il2CppListConverterFactory(),
					(JsonConverter)new ColorConverter(),
					(JsonConverter)new JsonStringEnumConverter(),
					(JsonConverter)new LocalizedTextConverter(),
					(JsonConverter)new InjectLibConnector()
				}
			};
		}

		public static T Deserialize<T>(string json)
		{
			return JsonSerializer.Deserialize<T>(json, _Setting);
		}

		public static object Deserialize(string json, Type type)
		{
			return JsonSerializer.Deserialize(json, type, _Setting);
		}
	}
	internal static class Logger
	{
		public static ManualLogSource LogInstance;

		public static bool UsingLog;

		public static void Log(string format, params object[] args)
		{
			Log(string.Format(format, args));
		}

		public static void Log(string str)
		{
			if (UsingLog)
			{
				ManualLogSource logInstance = LogInstance;
				if (logInstance != null)
				{
					logInstance.Log((LogLevel)8, (object)str);
				}
			}
		}

		public static void Warning(string format, params object[] args)
		{
			Warning(string.Format(format, args));
		}

		public static void Warning(string str)
		{
			ManualLogSource logInstance = LogInstance;
			if (logInstance != null)
			{
				logInstance.Log((LogLevel)4, (object)str);
			}
		}

		public static void Error(string format, params object[] args)
		{
			Error(string.Format(format, args));
		}

		public static void Error(string str)
		{
			ManualLogSource logInstance = LogInstance;
			if (logInstance != null)
			{
				logInstance.Log((LogLevel)2, (object)str);
			}
		}

		public static void Debug(string format, params object[] args)
		{
			Debug(string.Format(format, args));
		}

		public static void Debug(string str)
		{
			ManualLogSource logInstance = LogInstance;
			if (logInstance != null)
			{
				logInstance.Log((LogLevel)32, (object)str);
			}
		}
	}
	internal static class MTFOUtil
	{
		public const string MTFOGUID = "com.dak.MTFO";

		public static string GameDataPath { get; private set; }

		public static string CustomPath { get; private set; }

		public static bool HasCustomContent { get; private set; }

		public static bool IsLoaded { get; private set; }

		static MTFOUtil()
		{
			GameDataPath = string.Empty;
			CustomPath = string.Empty;
			HasCustomContent = false;
			IsLoaded = false;
			if (!((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue("com.dak.MTFO", out var info))
			{
				return;
			}
			try
			{
				Type obj = (AppDomain.CurrentDomain.GetAssemblies().First((Assembly a) => !a.IsDynamic && a.Location == info.Location) ?? throw new Exception("Assembly is Missing!")).GetTypes().First((Type t) => t.Name == "ConfigManager") ?? throw new Exception("Unable to Find ConfigManager Class");
				FieldInfo field = obj.GetField("GameDataPath", BindingFlags.Static | BindingFlags.Public);
				FieldInfo field2 = obj.GetField("CustomPath", BindingFlags.Static | BindingFlags.Public);
				FieldInfo? field3 = obj.GetField("HasCustomContent", BindingFlags.Static | BindingFlags.Public);
				if ((object)field == null)
				{
					throw new Exception("Unable to Find Field: GameDataPath");
				}
				if ((object)field2 == null)
				{
					throw new Exception("Unable to Find Field: CustomPath");
				}
				if ((object)field3 == null)
				{
					throw new Exception("Unable to Find Field: HasCustomContent");
				}
				GameDataPath = (string)field.GetValue(null);
				CustomPath = (string)field2.GetValue(null);
				HasCustomContent = (bool)field3.GetValue(null);
				IsLoaded = true;
			}
			catch (Exception value)
			{
				Console.WriteLine($"Exception thrown while reading path from Data Dumper (MTFO):\n{value}");
			}
		}
	}
}
namespace MTFO.Ext.PartialData.JsonConverters
{
	internal class ColorConverter : JsonConverter<Color>
	{
		public override bool HandleNull => false;

		public override Color Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			Color result = default(Color);
			switch (reader.TokenType)
			{
			case JsonTokenType.StartObject:
				while (reader.Read())
				{
					if (reader.TokenType == JsonTokenType.EndObject)
					{
						return result;
					}
					if (reader.TokenType != JsonTokenType.PropertyName)
					{
						throw new JsonException("Expected PropertyName token");
					}
					string? @string = reader.GetString();
					reader.Read();
					switch (@string.ToLower())
					{
					case "r":
						result.r = reader.GetSingle();
						break;
					case "g":
						result.g = reader.GetSingle();
						break;
					case "b":
						result.b = reader.GetSingle();
						break;
					case "a":
						result.a = reader.GetSingle();
						break;
					}
				}
				throw new JsonException("Expected EndObject token");
			case JsonTokenType.String:
			{
				string text = reader.GetString().Trim();
				if (ColorUtility.TryParseHtmlString(text, ref result))
				{
					return result;
				}
				throw new JsonException("Color format is not right: " + text);
			}
			default:
				throw new JsonException($"ColorJson type: {reader.TokenType} is not implemented!");
			}
		}

		public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			JsonSerializer.Serialize<Color>(writer, value, options);
		}
	}
	internal class Il2CppListConverter<T> : JsonConverter<List<T>>
	{
		public override bool HandleNull => false;

		public override List<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			List<T> val = new List<T>();
			if (reader.TokenType == JsonTokenType.StartArray)
			{
				foreach (T item in JsonSerializer.Deserialize<List<T>>(ref reader, options))
				{
					val.Add(item);
				}
				return val;
			}
			return null;
		}

		public override void Write(Utf8JsonWriter writer, List<T> value, JsonSerializerOptions options)
		{
			writer.WriteStartArray();
			Enumerator<T> enumerator = value.GetEnumerator();
			while (enumerator.MoveNext())
			{
				T current = enumerator.Current;
				JsonSerializer.Serialize(writer, current, options);
			}
			writer.WriteEndArray();
		}
	}
	internal class Il2CppListConverterFactory : JsonConverterFactory
	{
		public override bool CanConvert(Type typeToConvert)
		{
			if (!typeToConvert.IsGenericType)
			{
				return false;
			}
			if (typeToConvert.GetGenericTypeDefinition() != typeof(List<>))
			{
				return false;
			}
			return true;
		}

		public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
		{
			Type type = typeToConvert.GetGenericArguments()[0];
			return (JsonConverter)Activator.CreateInstance(typeof(Il2CppListConverter<>).MakeGenericType(type), BindingFlags.Instance | BindingFlags.Public, null, null, null);
		}
	}
	internal class LocalizedTextConverter : JsonConverter<LocalizedText>
	{
		public override bool HandleNull => false;

		public override LocalizedText Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			switch (reader.TokenType)
			{
			case JsonTokenType.String:
			{
				string @string = reader.GetString();
				if (!PersistentIDManager.TryGetId(@string, out var id))
				{
					return new LocalizedText
					{
						Id = 0u,
						UntranslatedText = @string
					};
				}
				return new LocalizedText
				{
					Id = id,
					UntranslatedText = null
				};
			}
			case JsonTokenType.Number:
				return new LocalizedText
				{
					Id = reader.GetUInt32(),
					UntranslatedText = null
				};
			default:
				throw new JsonException($"LocalizedTextJson type: {reader.TokenType} is not implemented!");
			}
		}

		public override void Write(Utf8JsonWriter writer, LocalizedText value, JsonSerializerOptions options)
		{
			JsonSerializer.Serialize<LocalizedText>(writer, value, options);
		}
	}
	public class PersistentIDConverter : JsonConverter<uint>
	{
		public override uint Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			if (reader.TokenType == JsonTokenType.String)
			{
				return PersistentIDManager.GetId(reader.GetString());
			}
			if (reader.TokenType == JsonTokenType.Number)
			{
				return reader.GetUInt32();
			}
			throw new JsonException("TOKEN IS NOT VALID!");
		}

		public override void Write(Utf8JsonWriter writer, uint value, JsonSerializerOptions options)
		{
			writer.WriteNumberValue(value);
		}
	}
	internal class Vector2Converter : JsonConverter<Vector2>
	{
		public override Vector2 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return JsonSerializer.Deserialize<Vector2>(ref reader);
		}

		public override void Write(Utf8JsonWriter writer, Vector2 value, JsonSerializerOptions options)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			writer.WriteStartObject();
			writer.WriteNumber("x", value.x);
			writer.WriteNumber("y", value.y);
			writer.WriteEndObject();
		}
	}
}
namespace MTFO.Ext.PartialData.Injects
{
	[HarmonyPatch(typeof(GearManager))]
	internal class Inject_GearManager
	{
		private const string COMP_CHARS = "abcdefghijklmnopqrst";

		[HarmonyPrefix]
		[HarmonyWrapSafe]
		[HarmonyPatch("LoadOfflineGearDatas")]
		private static void Pre_LoadOfflineGearDatas()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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
			foreach (PlayerOfflineGearDataBlock allBlock in GameDataBlockBase<PlayerOfflineGearDataBlock>.GetAllBlocks())
			{
				if (!((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)allBlock).internalEnabled || string.IsNullOrEmpty(allBlock.GearJSON) || ((int)allBlock.Type != 1 && (int)allBlock.Type != 2))
				{
					continue;
				}
				string text = allBlock.GearJSON;
				bool flag = false;
				using JsonDocument jsonDocument = JsonDocument.Parse(allBlock.GearJSON);
				if (!jsonDocument.RootElement.TryGetProperty("Packet", out var value) || !value.TryGetProperty("Comps", out var value2))
				{
					continue;
				}
				string text2 = "abcdefghijklmnopqrst";
				for (int i = 0; i < text2.Length; i++)
				{
					if (value2.TryGetProperty(text2[i].ToString(), out var value3) && value3.TryGetProperty("v", out var value4) && value4.ValueKind == JsonValueKind.String)
					{
						string @string = value4.GetString();
						Logger.Warning("Found String id: " + @string);
						uint id = PersistentIDManager.GetId(@string);
						if (id != 0)
						{
							text = new Regex("(\"v\")\\s*:\\s*(\"" + @string + "\")").Replace(text, $"\"v\":{id}");
							flag = true;
						}
					}
				}
				if (flag)
				{
					Logger.Warning(allBlock.GearJSON);
					Logger.Warning(text);
					allBlock.GearJSON = text;
				}
			}
		}
	}
}
namespace MTFO.Ext.PartialData.DTO
{
	internal class DataBlockDefinition
	{
		public string TypeName { get; set; } = "DataBlock?";


		public uint StartFromID { get; set; } = 65535u;


		public IncrementMode IncrementMode { get; set; }
	}
	internal class DatapackConfig
	{
		public string PackName { get; set; } = string.Empty;


		public string Author { get; set; } = string.Empty;


		public string Namespace { get; set; } = string.Empty;

	}
}
namespace MTFO.Ext.PartialData.DataBlockTypes
{
	internal static class DataBlockTypeManager
	{
		private static readonly List<IDataBlockType> _DataBlockCache = new List<IDataBlockType>();

		private static readonly List<IDBuffer> _DataBlockIdBuffers = new List<IDBuffer>();

		public static bool Initialize()
		{
			try
			{
				Assembly assembly = (from a in AppDomain.CurrentDomain.GetAssemblies()
					where !a.IsDynamic && a.Location.Contains("interop", StringComparison.InvariantCultureIgnoreCase)
					select a).First((Assembly a) => a.Location.EndsWith("Modules-ASM.dll", StringComparison.InvariantCultureIgnoreCase));
				List<Type> list = new List<Type>();
				foreach (Type exportedType in assembly.ExportedTypes)
				{
					if (!(exportedType == null) && !string.IsNullOrEmpty(exportedType.Namespace) && exportedType.Namespace.Equals("GameData"))
					{
						Type baseType = exportedType.BaseType;
						if (!(baseType == null) && baseType.Name.Equals("GameDataBlockBase`1"))
						{
							list.Add(exportedType);
						}
					}
				}
				Type typeFromHandle = typeof(DataBlockTypeWrapper<>);
				foreach (Type item in list)
				{
					IDataBlockType dataBlockType = (IDataBlockType)Activator.CreateInstance(typeFromHandle.MakeGenericType(item));
					AssignForceChangeMethod(dataBlockType);
					_DataBlockCache.Add(dataBlockType);
					_DataBlockIdBuffers.Add(new IDBuffer());
				}
				return true;
			}
			catch (Exception value)
			{
				Logger.Error($"Can't make cache from Modules-ASM.dll!: {value}");
				return false;
			}
		}

		public static void AssignForceChangeMethod(IDataBlockType blockTypeCache)
		{
			switch (blockTypeCache.GetShortName().ToLower())
			{
			case "rundown":
				blockTypeCache.RegisterOnChangeEvent(delegate
				{
					CM_PageRundown_New pageRundownNew = MainMenuGuiLayer.Current.PageRundownNew;
					pageRundownNew.m_dataIsSetup = false;
					try
					{
						clearIcon(pageRundownNew.m_expIconsTier1);
						clearIcon(pageRundownNew.m_expIconsTier2);
						clearIcon(pageRundownNew.m_expIconsTier3);
						clearIcon(pageRundownNew.m_expIconsTier4);
						clearIcon(pageRundownNew.m_expIconsTier5);
						clearIcon(pageRundownNew.m_expIconsTierExt);
					}
					catch (Exception value)
					{
						Logger.Error($"{value}");
					}
					pageRundownNew.m_currentRundownData = GameDataBlockBase<RundownDataBlock>.GetBlock(Global.RundownIdToLoad);
					if (pageRundownNew.m_currentRundownData != null)
					{
						pageRundownNew.PlaceRundown(pageRundownNew.m_currentRundownData);
						pageRundownNew.m_dataIsSetup = true;
					}
				});
				break;
			case "fogsettings":
				blockTypeCache.RegisterOnChangeEvent(delegate
				{
					if (Builder.CurrentFloor.IsBuilt)
					{
						pEnvironmentState state = EnvironmentStateManager.Current.m_stateReplicator.State;
						EnvironmentStateManager.Current.UpdateFogSettingsForState(state);
					}
				});
				break;
			case "lightsettings":
				blockTypeCache.RegisterOnChangeEvent(delegate
				{
					if (Builder.CurrentFloor.IsBuilt)
					{
						Enumerator<LG_Zone> enumerator2 = Builder.CurrentFloor.allZones.GetEnumerator();
						while (enumerator2.MoveNext())
						{
							LG_Zone current2 = enumerator2.Current;
							Enumerator<AIG_CourseNode> enumerator3 = current2.m_courseNodes.GetEnumerator();
							while (enumerator3.MoveNext())
							{
								AIG_CourseNode current3 = enumerator3.Current;
								LG_BuildZoneLightsJob.ApplyLightSettings(0u, current3.m_lightsInNode, current2.m_lightSettings, false);
							}
						}
					}
				});
				break;
			}
			static void clearIcon(List<CM_ExpeditionIcon_New> tier)
			{
				if (tier != null)
				{
					Enumerator<CM_ExpeditionIcon_New> enumerator = tier.GetEnumerator();
					while (enumerator.MoveNext())
					{
						CM_ExpeditionIcon_New current = enumerator.Current;
						if ((Object)(object)((Component)current).gameObject != (Object)null)
						{
							Object.Destroy((Object)(object)((Component)current).gameObject);
						}
					}
				}
			}
		}

		public static bool TryFindCache(string blockTypeName, out IDataBlockType cache)
		{
			int index = GetIndex(blockTypeName);
			if (index != -1)
			{
				cache = _DataBlockCache[index];
				return true;
			}
			cache = null;
			return false;
		}

		public static bool TryGetNextID(string blockTypeName, out uint id)
		{
			int index = GetIndex(blockTypeName);
			if (index != -1)
			{
				id = _DataBlockIdBuffers[index].GetNext();
				return true;
			}
			id = 0u;
			return false;
		}

		public static void SetIDBuffer(string blockTypeName, uint id)
		{
			int index = GetIndex(blockTypeName);
			if (index != -1)
			{
				_DataBlockIdBuffers[index].CurrentID = id;
			}
		}

		public static void SetIDBuffer(string blockTypeName, uint id, IncrementMode mode)
		{
			int index = GetIndex(blockTypeName);
			if (index != -1)
			{
				IDBuffer iDBuffer = _DataBlockIdBuffers[index];
				iDBuffer.CurrentID = id;
				iDBuffer.IncrementMode = mode;
			}
		}

		private static int GetIndex(string blockTypeName)
		{
			string blockTypeName2 = blockTypeName;
			blockTypeName2 = GetBlockName(blockTypeName2);
			return _DataBlockCache.FindIndex((IDataBlockType x) => x.GetShortName().Equals(blockTypeName2, StringComparison.OrdinalIgnoreCase));
		}

		public static string GetBlockName(string blockTypeName)
		{
			blockTypeName = blockTypeName.Trim();
			if (blockTypeName.EndsWith("DataBlock"))
			{
				string text = blockTypeName;
				blockTypeName = text.Substring(0, text.Length - 9);
			}
			return blockTypeName;
		}
	}
	internal class DataBlockTypeWrapper<T> : IDataBlockType where T : GameDataBlockBase<T>
	{
		public Action OnForceChange;

		public string FullName { get; private set; }

		public string ShortenName { get; private set; }

		public DataBlockTypeWrapper()
		{
			FullName = typeof(T).Name.Trim();
			ShortenName = FullName.Replace("DataBlock", "");
		}

		public void OnChanged()
		{
			OnForceChange?.Invoke();
		}

		public void AddBlock(T block)
		{
			T block2 = GameDataBlockBase<T>.GetBlock(((GameDataBlockBase<T>)block).persistentID);
			if (block2 != null)
			{
				CopyProperties(block, block2);
				Logger.Warning($"Replaced Block: {((GameDataBlockBase<T>)block2).persistentID}, {((GameDataBlockBase<T>)block2).name}");
			}
			else
			{
				GameDataBlockBase<T>.AddBlock(block, -1);
				Logger.Log($"Added Block: {((GameDataBlockBase<T>)block).persistentID}, {((GameDataBlockBase<T>)block).name}");
			}
		}

		public void AddJsonBlock(string json)
		{
			try
			{
				switch (JsonDocument.Parse(json, new JsonDocumentOptions
				{
					CommentHandling = JsonCommentHandling.Skip
				}).RootElement.ValueKind)
				{
				case JsonValueKind.Array:
				{
					T[] array = (T[])JSON.Deserialize(json, typeof(T).MakeArrayType());
					foreach (T block2 in array)
					{
						AddBlock(block2);
					}
					break;
				}
				case JsonValueKind.Object:
				{
					T block = (T)JSON.Deserialize(json, typeof(T));
					AddBlock(block);
					break;
				}
				}
			}
			catch (Exception value)
			{
				Logger.Error($"Error While Adding Block: {value}");
			}
		}

		public void DoSaveToDisk(string fullPath)
		{
			string filePathFull = GameDataBlockBase<T>.m_filePathFull;
			GameDataBlockBase<T>.m_filePathFull = fullPath;
			GameDataBlockBase<T>.DoSaveToDisk(false, false, true);
			GameDataBlockBase<T>.m_filePathFull = filePathFull;
		}

		private static object CopyProperties(object source, object target)
		{
			PropertyInfo[] properties = source.GetType().GetProperties();
			foreach (PropertyInfo sourceProp in properties)
			{
				Type propertyType = sourceProp.PropertyType;
				PropertyInfo propertyInfo = target.GetType().GetProperties().FirstOrDefault((PropertyInfo x) => x.Name == sourceProp.Name && x.PropertyType == sourceProp.PropertyType && x.CanWrite);
				if (propertyInfo != null && !sourceProp.Name.Contains("_k__BackingField"))
				{
					if (propertyType == typeof(IntPtr))
					{
						Logger.Error("Pointer has detected on CopyProperties!!!!");
					}
					else
					{
						propertyInfo.SetValue(target, sourceProp.GetValue(source));
					}
				}
			}
			return target;
		}

		public string GetShortName()
		{
			return ShortenName;
		}

		public string GetFullName()
		{
			return FullName;
		}

		public void RegisterOnChangeEvent(Action onChanged)
		{
			OnForceChange = (Action)Delegate.Combine(OnForceChange, onChanged);
		}
	}
	internal interface IDataBlockType
	{
		string GetShortName();

		string GetFullName();

		void DoSaveToDisk(string fullPath);

		void AddJsonBlock(string json);

		void OnChanged();

		void RegisterOnChangeEvent(Action onChanged);
	}
}