Decompiled source of IDRSJsonLoader v1.0.3

plugins/IDRSJsonLoader/IDRSJsonLoader.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HG.Coroutines;
using HG.Reflection;
using IDRSJsonLoader.Models;
using R2API;
using RoR2;
using UnityEngine;
using UnityEngine.AddressableAssets;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace IDRSJsonLoader
{
	public delegate void ParseCallback(ItemDisplayRuleSet idrs);
	[BepInPlugin("com.KingEnderBrine.IDRSJsonLoader", "IDRS Json Loader", "1.0.3")]
	public class IDRSJsonLoaderPlugin : BaseUnityPlugin
	{
		public const string Guid = "com.KingEnderBrine.IDRSJsonLoader";

		public const string Name = "IDRS Json Loader";

		public const string Version = "1.0.3";

		private static readonly List<DelayedReplacementInfo> delayedReplacementInfos = new List<DelayedReplacementInfo>();

		internal static IDRSJsonLoaderPlugin Instance { get; private set; }

		internal static ManualLogSource InstanceLogger
		{
			get
			{
				IDRSJsonLoaderPlugin instance = Instance;
				if (instance == null)
				{
					return null;
				}
				return ((BaseUnityPlugin)instance).Logger;
			}
		}

		private void Awake()
		{
			Instance = this;
			string[] files = Directory.GetFiles(Paths.PluginPath, "*.idrsjson", SearchOption.AllDirectories);
			foreach (string text in files)
			{
				try
				{
					ParseAndUpdate(File.ReadAllText(text), null);
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Couldn't load file " + text));
					((BaseUnityPlugin)this).Logger.LogError((object)ex);
				}
			}
		}

		public static void ParseAndUpdate(string json, ParseCallback beforeGenerateRuntimeValues)
		{
			DelayedReplacementInfo item = new DelayedReplacementInfo
			{
				exportIdrs = JsonUtility.FromJson<ExportItemDisplayRuleSet>(json),
				beforeGenerateRuntimeValues = beforeGenerateRuntimeValues
			};
			delayedReplacementInfos.Add(item);
		}

		public static void ParseAndUpdate(string json, ItemDisplayRuleSet idrs, ParseCallback beforeGenerateRuntimeValues)
		{
			DelayedReplacementInfo item = new DelayedReplacementInfo
			{
				exportIdrs = JsonUtility.FromJson<ExportItemDisplayRuleSet>(json),
				idrs = idrs,
				beforeGenerateRuntimeValues = beforeGenerateRuntimeValues
			};
			delayedReplacementInfos.Add(item);
		}

		[SystemInitializer(new Type[]
		{
			typeof(ItemDisplayRuleSet),
			typeof(BodyCatalog),
			typeof(SkinCatalog)
		})]
		internal static IEnumerator Init()
		{
			Dictionary<string, AssetBundle> assetBundles = AssetBundle.GetAllLoadedAssetBundles().ToDictionary((AssetBundle b) => ((Object)b).name);
			Dictionary<ItemDisplayRuleSet, AssetsInfo> dictionary = new Dictionary<ItemDisplayRuleSet, AssetsInfo>();
			Dictionary<SkinDef, AssetsInfo> dictionary2 = new Dictionary<SkinDef, AssetsInfo>();
			AssetsInfo value2;
			foreach (DelayedReplacementInfo delayedReplacementInfo in delayedReplacementInfos)
			{
				ExportItemDisplayRuleSet exportIdrs = delayedReplacementInfo.exportIdrs;
				if (!Object.op_Implicit((Object)(object)delayedReplacementInfo.idrs) && !string.IsNullOrEmpty(exportIdrs.bodyName))
				{
					GameObject val = BodyCatalog.FindBodyPrefab(exportIdrs.bodyName);
					if (Object.op_Implicit((Object)(object)val))
					{
						CharacterBody component = val.GetComponent<CharacterBody>();
						ModelLocator component2 = val.GetComponent<ModelLocator>();
						object obj;
						if (component2 == null)
						{
							obj = null;
						}
						else
						{
							Transform modelTransform = component2.modelTransform;
							obj = ((modelTransform != null) ? ((Component)modelTransform).GetComponent<CharacterModel>() : null);
						}
						CharacterModel val2 = (CharacterModel)obj;
						if (Object.op_Implicit((Object)(object)val2))
						{
							delayedReplacementInfo.characterModel = val2;
							if (!Object.op_Implicit((Object)(object)val2.itemDisplayRuleSet))
							{
								val2.itemDisplayRuleSet = ScriptableObject.CreateInstance<ItemDisplayRuleSet>();
							}
							if (!string.IsNullOrEmpty(exportIdrs.skinName))
							{
								SkinDef[] bodySkinDefs = SkinCatalog.GetBodySkinDefs(component.bodyIndex);
								delayedReplacementInfo.skinDef = ((IEnumerable<SkinDef>)bodySkinDefs).FirstOrDefault((Func<SkinDef, bool>)((SkinDef s) => ((Object)s).name == exportIdrs.skinName));
							}
							else
							{
								delayedReplacementInfo.idrs = val2.itemDisplayRuleSet;
							}
						}
					}
				}
				AssetsInfo value = null;
				if (Object.op_Implicit((Object)(object)delayedReplacementInfo.idrs))
				{
					if (!dictionary.TryGetValue(delayedReplacementInfo.idrs, out value))
					{
						value = (dictionary[delayedReplacementInfo.idrs] = new AssetsInfo());
					}
				}
				else if (Object.op_Implicit((Object)(object)delayedReplacementInfo.skinDef) && !dictionary2.TryGetValue(delayedReplacementInfo.skinDef, out value))
				{
					value = (dictionary2[delayedReplacementInfo.skinDef] = new AssetsInfo());
				}
				if (value == null)
				{
					continue;
				}
				value2 = value;
				if (value2.characterModel == null)
				{
					value2.characterModel = delayedReplacementInfo.characterModel;
				}
				for (int num = 0; num < exportIdrs.itemGroups.Count; num++)
				{
					ExportKeyAssetRuleGroup exportKeyAssetRuleGroup = exportIdrs.itemGroups[num];
					ItemDef itemDef = ItemCatalog.GetItemDef(ItemCatalog.FindItemIndex(exportKeyAssetRuleGroup.name));
					if (Object.op_Implicit((Object)(object)itemDef))
					{
						value.groups[(Object)(object)itemDef] = exportKeyAssetRuleGroup;
					}
				}
				for (int num2 = 0; num2 < exportIdrs.equipmentGroups.Count; num2++)
				{
					ExportKeyAssetRuleGroup exportKeyAssetRuleGroup2 = exportIdrs.equipmentGroups[num2];
					EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(EquipmentCatalog.FindEquipmentIndex(exportKeyAssetRuleGroup2.name));
					if (Object.op_Implicit((Object)(object)equipmentDef))
					{
						value.groups[(Object)(object)equipmentDef] = exportKeyAssetRuleGroup2;
					}
				}
			}
			ParallelCoroutine assetsCoroutine = null;
			Object key2;
			ExportKeyAssetRuleGroup value4;
			foreach (KeyValuePair<ItemDisplayRuleSet, AssetsInfo> item in dictionary)
			{
				item.Deconstruct(out var key, out value2);
				ItemDisplayRuleSet val3 = key;
				AssetsInfo assetsInfo3 = value2;
				HashSet<string> addedChildren = new HashSet<string>(0);
				for (int num3 = 0; num3 < val3.keyAssetRuleGroups.Length; num3++)
				{
					Object keyAsset = val3.keyAssetRuleGroups[num3].keyAsset;
					if (!Object.op_Implicit(keyAsset) || !assetsInfo3.groups.Remove(keyAsset, out var value3))
					{
						continue;
					}
					IEnumerator enumerator3 = MapGroup(val3, num3, keyAsset, value3, assetBundles, assetsInfo3.characterModel, addedChildren);
					if (enumerator3.MoveNext())
					{
						if (assetsCoroutine == null)
						{
							assetsCoroutine = new ParallelCoroutine();
						}
						assetsCoroutine.Add(enumerator3);
					}
				}
				if (assetsInfo3.groups.Count == 0)
				{
					continue;
				}
				int num4 = val3.keyAssetRuleGroups.Length;
				Array.Resize(ref val3.keyAssetRuleGroups, val3.keyAssetRuleGroups.Length + assetsInfo3.groups.Count);
				foreach (KeyValuePair<Object, ExportKeyAssetRuleGroup> group in assetsInfo3.groups)
				{
					group.Deconstruct(out key2, out value4);
					Object keyAsset2 = key2;
					ExportKeyAssetRuleGroup exportGroup = value4;
					IEnumerator enumerator5 = MapGroup(val3, num4++, keyAsset2, exportGroup, assetBundles, assetsInfo3.characterModel, addedChildren);
					if (enumerator5.MoveNext())
					{
						if (assetsCoroutine == null)
						{
							assetsCoroutine = new ParallelCoroutine();
						}
						assetsCoroutine.Add(enumerator5);
					}
				}
			}
			foreach (KeyValuePair<SkinDef, AssetsInfo> item2 in dictionary2)
			{
				item2.Deconstruct(out var key3, out value2);
				SkinDef skinDef = key3;
				AssetsInfo assetsInfo4 = value2;
				if (assetsInfo4.groups.Count == 0)
				{
					continue;
				}
				HashSet<string> addedChildren2 = new HashSet<string>(0);
				foreach (KeyValuePair<Object, ExportKeyAssetRuleGroup> group2 in assetsInfo4.groups)
				{
					group2.Deconstruct(out key2, out value4);
					Object keyAsset3 = key2;
					ExportKeyAssetRuleGroup exportGroup2 = value4;
					IEnumerator enumerator7 = MapGroup(skinDef, keyAsset3, exportGroup2, assetBundles, assetsInfo4.characterModel, addedChildren2);
					if (enumerator7.MoveNext())
					{
						if (assetsCoroutine == null)
						{
							assetsCoroutine = new ParallelCoroutine();
						}
						assetsCoroutine.Add(enumerator7);
					}
				}
			}
			if (assetsCoroutine != null)
			{
				while (assetsCoroutine.MoveNext())
				{
					yield return null;
				}
			}
			ParallelCoroutine idrsCoroutine = new ParallelCoroutine();
			foreach (DelayedReplacementInfo delayedReplacementInfo2 in delayedReplacementInfos)
			{
				if (Object.op_Implicit((Object)(object)delayedReplacementInfo2.idrs))
				{
					delayedReplacementInfo2.beforeGenerateRuntimeValues?.Invoke(delayedReplacementInfo2.idrs);
					idrsCoroutine.Add(delayedReplacementInfo2.idrs.GenerateRuntimeValuesAsync());
				}
			}
			while (idrsCoroutine.MoveNext())
			{
				yield return null;
			}
			delayedReplacementInfos.Clear();
		}

		private static IEnumerator MapGroup(ItemDisplayRuleSet idrs, int index, Object keyAsset, ExportKeyAssetRuleGroup exportGroup, Dictionary<string, AssetBundle> assetBundles, CharacterModel characterModel, HashSet<string> addedChildren)
		{
			ParallelCoroutine coroutine = null;
			KeyAssetRuleGroup group = new KeyAssetRuleGroup
			{
				displayRuleGroup = 
				{
					rules = (ItemDisplayRule[])(object)new ItemDisplayRule[exportGroup.rules.Count]
				},
				keyAsset = keyAsset
			};
			for (int i = 0; i < exportGroup.rules.Count; i++)
			{
				IEnumerator enumerator = MapRule(group.displayRuleGroup.rules, i, exportGroup.rules[i], assetBundles, characterModel, addedChildren);
				if (enumerator.MoveNext())
				{
					if (coroutine == null)
					{
						coroutine = new ParallelCoroutine();
					}
					coroutine.Add(enumerator);
				}
			}
			if (coroutine != null)
			{
				while (coroutine.MoveNext())
				{
					yield return null;
				}
			}
			idrs.keyAssetRuleGroups[index] = group;
		}

		private static IEnumerator MapGroup(SkinDef skinDef, Object keyAsset, ExportKeyAssetRuleGroup exportGroup, Dictionary<string, AssetBundle> assetBundles, CharacterModel characterModel, HashSet<string> addedChildren)
		{
			ParallelCoroutine coroutine = null;
			DisplayRuleGroup group = new DisplayRuleGroup
			{
				rules = (ItemDisplayRule[])(object)new ItemDisplayRule[exportGroup.rules.Count]
			};
			for (int i = 0; i < exportGroup.rules.Count; i++)
			{
				IEnumerator enumerator = MapRule(group.rules, i, exportGroup.rules[i], assetBundles, characterModel, addedChildren);
				if (enumerator.MoveNext())
				{
					if (coroutine == null)
					{
						coroutine = new ParallelCoroutine();
					}
					coroutine.Add(enumerator);
				}
			}
			if (coroutine != null)
			{
				while (coroutine.MoveNext())
				{
					yield return null;
				}
			}
			SkinIDRS.AddGroupOverride(skinDef, keyAsset, group);
		}

		private static IEnumerator MapRule(ItemDisplayRule[] rules, int index, ExportItemDisplayRule exportRule, Dictionary<string, AssetBundle> assetBundles, CharacterModel characterModel, HashSet<string> addedChildren)
		{
			string text = exportRule.childName;
			if (!string.IsNullOrEmpty(exportRule.childPath) && Object.op_Implicit((Object)(object)characterModel))
			{
				text = StringHelpers.ChildNameFromPath(exportRule.childPath);
				if (!addedChildren.Contains(text))
				{
					addedChildren.Add(text);
					Transform val = ((Component)characterModel).transform.Find(exportRule.childPath);
					if (Object.op_Implicit((Object)(object)val))
					{
						((Component)characterModel).GetComponent<ChildLocator>().AddChild(text, val);
					}
				}
			}
			ItemDisplayRule rule = new ItemDisplayRule
			{
				childName = text,
				followerPrefabAddress = new AssetReferenceGameObject(exportRule.guid ?? ""),
				limbMask = exportRule.limbMask,
				localAngles = exportRule.localAngles,
				localPos = exportRule.localPos,
				localScale = exportRule.localScale,
				ruleType = exportRule.ruleType
			};
			if (!string.IsNullOrEmpty(exportRule.assetBundle))
			{
				if (assetBundles.TryGetValue(exportRule.assetBundle, out var value))
				{
					AssetBundleRequest request = value.LoadAssetAsync<GameObject>(exportRule.assetPath);
					while (!((AsyncOperation)request).isDone)
					{
						yield return null;
					}
					Object asset = request.asset;
					rule.followerPrefab = (GameObject)(object)((asset is GameObject) ? asset : null);
				}
				else
				{
					InstanceLogger.LogError((object)("AssetBundle " + exportRule.assetBundle + " was not found."));
				}
			}
			rules[index] = rule;
		}
	}
	public static class StringHelpers
	{
		public static readonly string NamePostfix = "|IJL";

		public static string ChildNameFromPath(string path)
		{
			string fileName = Path.GetFileName(path);
			return $"{fileName}_{(uint)GetStableHashCode(path)}{NamePostfix}";
		}

		public static int GetStableHashCode(string str)
		{
			int num = 5381;
			int num2 = num;
			for (int i = 0; i < str.Length && str[i] != 0; i += 2)
			{
				num = ((num << 5) + num) ^ str[i];
				if (i == str.Length - 1 || str[i + 1] == '\0')
				{
					break;
				}
				num2 = ((num2 << 5) + num2) ^ str[i + 1];
			}
			return num + num2 * 1566083941;
		}
	}
}
namespace IDRSJsonLoader.Models
{
	internal class AssetsInfo
	{
		public Dictionary<Object, ExportKeyAssetRuleGroup> groups = new Dictionary<Object, ExportKeyAssetRuleGroup>();

		public CharacterModel characterModel;
	}
	internal class DelayedReplacementInfo
	{
		public ExportItemDisplayRuleSet exportIdrs;

		public ParseCallback beforeGenerateRuntimeValues;

		public ItemDisplayRuleSet idrs;

		public SkinDef skinDef;

		public CharacterModel characterModel;
	}
	[Serializable]
	public class ExportItemDisplayRule
	{
		public string guid;

		public string assetBundle;

		public string assetPath;

		public Vector3 localScale;

		public Vector3 localPos;

		public Vector3 localAngles;

		public string childName;

		public string childPath;

		public LimbFlags limbMask;

		public ItemDisplayRuleType ruleType;
	}
	[Serializable]
	public class ExportItemDisplayRuleSet
	{
		public string bodyName;

		public string skinName;

		public List<ExportKeyAssetRuleGroup> itemGroups = new List<ExportKeyAssetRuleGroup>();

		public List<ExportKeyAssetRuleGroup> equipmentGroups = new List<ExportKeyAssetRuleGroup>();
	}
	[Serializable]
	public class ExportKeyAssetRuleGroup
	{
		public string name;

		public List<ExportItemDisplayRule> rules = new List<ExportItemDisplayRule>();
	}
}