using System;
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.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 InheritanceDataBlocks.API;
using InjectLib.JsonNETInjection.Supports;
using LevelGeneration;
using Localization;
using MTFO.Ext.PartialData.DTO;
using MTFO.Ext.PartialData.DataBlockTypes;
using MTFO.Ext.PartialData.Dependencies;
using MTFO.Ext.PartialData.JsonConverters;
using MTFO.Ext.PartialData.Utils;
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("PartialDataModCompatible")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+e0694a3f32feddb5282c6739f48e5686346b02d8")]
[assembly: AssemblyProduct("PartialDataModCompatible")]
[assembly: AssemblyTitle("PartialDataModCompatible")]
[assembly: AssemblyVersion("0.1.0.0")]
namespace MTFO.Ext.PartialData
{
[BepInPlugin("MTFO.Extension.PartialBlocks", "MTFO pDataBlock", "1.5.0")]
[BepInProcess("GTFO.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[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 var 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());
cache.CacheInheritance(objNode, value);
}
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)
{
Logger.Warning("LiveEdit File Changed: " + e.FullPath);
LiveEdit.TryReadFileContent(e.FullPath, (Action<string>)delegate(string content)
{
ReadChangedFile(content, e.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;
}
item.DataBlockType.ApplyInheritance();
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 var 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 var 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);
}
}
}
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
}
internal static class InheritanceUtil
{
public const string GUID = "Dinorush.InheritanceDataBlocks";
public static readonly bool HasInheritance;
static InheritanceUtil()
{
HasInheritance = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.ContainsKey("Dinorush.InheritanceDataBlocks");
}
}
internal static class InjectLibUtil
{
public const string GUID = "GTFO.InjectLib";
public static readonly bool HasInjectLib;
static InjectLibUtil()
{
HasInjectLib = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.ContainsKey("GTFO.InjectLib");
}
}
internal static class JSON
{
private static readonly JsonSerializerOptions _Setting;
static JSON()
{
_Setting = CreateSetting();
_Setting = CreateSetting();
_Setting.Converters.Add(new PersistentIDConverter());
}
private static JsonSerializerOptions CreateSetting()
{
JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions
{
ReadCommentHandling = JsonCommentHandling.Skip,
IncludeFields = true,
AllowTrailingCommas = true,
WriteIndented = true
};
jsonSerializerOptions.Converters.Add(new Il2CppListConverterFactory());
jsonSerializerOptions.Converters.Add(new ColorConverter());
jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
jsonSerializerOptions.Converters.Add(new LocalizedTextConverter());
if (InjectLibUtil.HasInjectLib)
{
jsonSerializerOptions.Converters.Add(new InjectLibConnectorWrapper());
}
return jsonSerializerOptions;
}
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 InjectLibConnectorWrapper : JsonConverterFactory
{
private static readonly InjectLibConnector _connector = new InjectLibConnector();
public override bool CanConvert(Type typeToConvert)
{
Type baseType = typeToConvert.BaseType;
if (!baseType.IsGenericType)
{
return ((JsonConverter)(object)_connector).CanConvert(typeToConvert);
}
if (baseType.GetGenericTypeDefinition() == typeof(GameDataBlockBase<>))
{
return false;
}
return ((JsonConverter)(object)_connector).CanConvert(typeToConvert);
}
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
return ((JsonConverterFactory)(object)_connector).CreateConverter(typeToConvert, options);
}
}
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.Dependencies
{
internal class InheritanceConnector<T> where T : GameDataBlockBase<T>
{
private struct InheritanceCache
{
public uint id;
public List<string> propertyNames;
public uint parentID;
public string parentStr;
}
private readonly Queue<InheritanceCache> _caches;
private static bool HasInheritance => InheritanceUtil.HasInheritance;
public InheritanceConnector()
{
if (HasInheritance)
{
_caches = new Queue<InheritanceCache>();
}
}
public void CacheInheritance(JsonElement objNode, JsonElement idNode)
{
if (!HasInheritance)
{
return;
}
uint id = ((idNode.ValueKind == JsonValueKind.String) ? PersistentIDManager.GetId(idNode.GetString()) : idNode.GetUInt32());
RemoveInheritance_Internal(id);
if (!objNode.TryGetProperty("parentID", out var value))
{
return;
}
InheritanceCache inheritanceCache = default(InheritanceCache);
inheritanceCache.propertyNames = new List<string>();
inheritanceCache.parentID = 0u;
inheritanceCache.parentStr = "";
inheritanceCache.id = id;
InheritanceCache item = inheritanceCache;
if (value.ValueKind == JsonValueKind.String)
{
item.parentStr = value.GetString();
}
else
{
item.parentID = value.GetUInt32();
}
foreach (JsonProperty item2 in objNode.EnumerateObject())
{
if (!item2.NameEquals("parentID") && !item2.NameEquals("datablock"))
{
item.propertyNames.Add(item2.Name);
}
}
_caches.Enqueue(item);
}
private static void RemoveInheritance_Internal(uint id)
{
InheritanceAPI<T>.GetRoot().RemoveNode(id);
}
public void AddInheritance(T data)
{
if (HasInheritance && _caches.TryPeek(out var result) && ((GameDataBlockBase<T>)data).persistentID == result.id)
{
AddInheritance_Internal(data, _caches.Dequeue());
}
}
private static void AddInheritance_Internal(T data, InheritanceCache cache)
{
Type typeFromHandle = typeof(T);
uint num = ((cache.parentID != 0) ? cache.parentID : PersistentIDManager.GetId(cache.parentStr));
List<PropertyInfo> list = new List<PropertyInfo>(cache.propertyNames.Count - 2);
foreach (string propertyName in cache.propertyNames)
{
PropertyInfo propertyInfo = InheritanceAPI<T>.CacheProperty(typeFromHandle, propertyName);
if (propertyInfo != null)
{
list.Add(propertyInfo);
}
}
InheritanceAPI<T>.AddNode(cache.id, data, list, num);
}
public void ApplyAllInheritance()
{
if (HasInheritance)
{
ApplyAllInheritance_Internal();
}
}
public static void ApplyAllInheritance_Internal()
{
InheritanceAPI<T>.ApplyAllInheritance();
}
}
}
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)
{
blockTypeName = GetBlockName(blockTypeName);
return _DataBlockCache.FindIndex((IDataBlockType x) => x.GetShortName().Equals(blockTypeName, 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 InheritanceConnector<T> InheritanceConnector { get; private set; } = new InheritanceConnector<T>();
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);
InheritanceConnector.AddInheritance(block);
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);
}
public void CacheInheritance(JsonElement objNode, JsonElement idNode)
{
InheritanceConnector.CacheInheritance(objNode, idNode);
}
public void ApplyInheritance()
{
InheritanceConnector.ApplyAllInheritance();
}
}
internal interface IDataBlockType
{
string GetShortName();
string GetFullName();
void DoSaveToDisk(string fullPath);
void AddJsonBlock(string json);
void OnChanged();
void RegisterOnChangeEvent(Action onChanged);
void CacheInheritance(JsonElement objNode, JsonElement idNode);
void ApplyInheritance();
}
}