Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Master of Disguise v1.0.0
YouDied.MasterOfDisguise.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("YouDied.MasterOfDisguise")] [assembly: AssemblyProduct("Master of Disguise")] [assembly: AssemblyFileVersion("1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace YouDied.MasterOfDisguise { internal static class BossBiomes { public const string DefaultMap = "TrophyEikthyr:Meadows, TrophyTheElder:BlackForest, TrophyBonemass:Swamp, TrophyDragonQueen:Mountain, TrophyGoblinKing:Plains, TrophySeekerQueen:Mistlands, TrophyFader:AshLands"; private static string s_raw; private static readonly Dictionary<string, Biome> s_map = new Dictionary<string, Biome>(StringComparer.OrdinalIgnoreCase); public static bool TryGet(string trophy, out Biome biome) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected I4, but got Unknown Parse(); if (s_map.TryGetValue(trophy, out biome)) { return true; } TrophyInfo trophyInfo = TrophyDatabase.Get(trophy); if (trophyInfo != null && trophyInfo.FromBoss && Plugin.UnlistedBossBiome.Value != "None") { try { biome = (Biome)(int)(Biome)Enum.Parse(typeof(Biome), Plugin.UnlistedBossBiome.Value, ignoreCase: true); return true; } catch { } } biome = (Biome)0; return false; } public static bool IsListed(string trophy) { Parse(); return s_map.ContainsKey(trophy); } public static bool Fools(string trophy, Character creature) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 if (!TryGet(trophy, out var biome)) { return false; } WorldGenerator instance = WorldGenerator.instance; if (instance == null) { return false; } return (instance.GetBiome(((Component)creature).transform.position) & biome) > 0; } public unsafe static string DisplayName(string trophy) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 if (!TryGet(trophy, out var biome)) { return "boss's biome (not set, see config)"; } if ((int)biome != 8) { if ((int)biome != 32) { if ((int)biome == 64) { return "Deep North"; } return ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString(); } return "Ashlands"; } return "Black Forest"; } private static void Parse() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) string text = Plugin.BossBiomeMap.Value ?? ""; if (text == s_raw) { return; } s_raw = text; s_map.Clear(); string[] array = text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ':' }); if (array2.Length == 2) { string text2 = array2[0].Trim(); string text3 = array2[1].Trim(); try { Biome value = (Biome)Enum.Parse(typeof(Biome), text3, ignoreCase: true); s_map[text2] = value; } catch { Plugin.Warn("Boss trophy biomes: '" + text3 + "' isn't a biome (for " + text2 + ")."); } } } } } internal static class Cost { internal const string EffectName = "YouDied_Disguised"; private static readonly int EffectHash = StringExtensionMethods.GetStableHashCode("YouDied_Disguised"); private const string UsedKeyPrefix = "YouDied.MasterOfDisguise.Used."; private static readonly FieldRef<StatusEffect, float> SeTime = AccessTools.FieldRefAccess<StatusEffect, float>("m_time"); private static SE_Stats s_template; private static float s_used; private static string s_usedFor; private static float s_nextSave; internal static SE_Stats Template { get { if ((Object)(object)s_template == (Object)null) { s_template = ScriptableObject.CreateInstance<SE_Stats>(); ((Object)s_template).name = "YouDied_Disguised"; ((StatusEffect)s_template).m_name = "Disguised"; ((StatusEffect)s_template).m_tooltip = "Creatures fooled by your trophy treat you as one of their own."; } return s_template; } } public static float LifetimeSeconds(string trophy) { if (!Plugin.NeverBreaks.Value && Plugin.Enabled.Value) { return (float)Plugin.Lifetime.Value * 60f; } return 0f; } public static float UsedSeconds(Player player, string trophy) { if (trophy == s_usedFor && (Object)(object)player == (Object)(object)Player.m_localPlayer) { return s_used; } if (!player.m_customData.TryGetValue("YouDied.MasterOfDisguise.Used." + trophy, out var value) || !float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return 0f; } return result; } public static void Update(Player player, string trophy) { if (s_usedFor != trophy) { Save(player); s_usedFor = trophy; s_used = UsedSeconds(player, trophy); } float num = LifetimeSeconds(trophy); if (num > 0f) { if (!FitMode.Active) { s_used += Time.deltaTime; } if (Time.time >= s_nextSave) { s_nextSave = Time.time + 2f; Save(player); } if (s_used >= num) { Consume(player, trophy); return; } } ApplyEffect(player, trophy, num); } private static void ApplyEffect(Player player, string trophy, float lifetime) { SEMan sEMan = ((Character)player).GetSEMan(); if (sEMan == null) { return; } bool num = Plugin.ShowStatusIcon.Value || Plugin.StaminaRegen.Value < 100 || Plugin.MoveSpeed.Value < 100; StatusEffect statusEffect = sEMan.GetStatusEffect(EffectHash); SE_Stats val = (SE_Stats)(object)((statusEffect is SE_Stats) ? statusEffect : null); if (!num) { if ((Object)(object)val != (Object)null) { sEMan.RemoveStatusEffect(EffectHash, true); } return; } if ((Object)(object)val == (Object)null) { sEMan.AddStatusEffect((StatusEffect)(object)Template, false, 0, 0f, (short)(-1)); StatusEffect statusEffect2 = sEMan.GetStatusEffect(EffectHash); val = (SE_Stats)(object)((statusEffect2 is SE_Stats) ? statusEffect2 : null); if ((Object)(object)val == (Object)null) { return; } } ((StatusEffect)val).m_icon = (Plugin.ShowStatusIcon.Value ? TrophyIcon(player, trophy) : null); val.m_staminaRegenMultiplier = (float)Plugin.StaminaRegen.Value / 100f; val.m_speedModifier = (float)(Plugin.MoveSpeed.Value - 100) / 100f; ((StatusEffect)val).m_ttl = ((lifetime > 0f) ? (lifetime + 1f) : 0f); SeTime.Invoke((StatusEffect)(object)val) = ((lifetime > 0f) ? s_used : 0f); } public static void Clear(Player player) { Save(player); s_usedFor = null; SEMan val = (((Object)(object)player != (Object)null) ? ((Character)player).GetSEMan() : null); if (val != null && val.HaveStatusEffect(EffectHash)) { val.RemoveStatusEffect(EffectHash, true); } } private static void Consume(Player player, string trophy) { Inventory inventory = ((Humanoid)player).GetInventory(); ItemData val = null; foreach (ItemData allItem in inventory.GetAllItems()) { if ((Object)(object)allItem.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == trophy) { val = allItem; break; } } string text = ((val != null) ? Loc.T(val.m_shared.m_name) : "trophy"); if (val != null) { inventory.RemoveItem(val, 1); } player.m_customData.Remove("YouDied.MasterOfDisguise.Used." + trophy); s_usedFor = null; s_used = 0f; Disguise.Remove(player, "Your " + text + " crumbles to dust. Your disguise is gone."); } private static void Save(Player player) { if (!((Object)(object)player == (Object)null) && !string.IsNullOrEmpty(s_usedFor)) { player.m_customData["YouDied.MasterOfDisguise.Used." + s_usedFor] = s_used.ToString("0.#", CultureInfo.InvariantCulture); } } private static Sprite TrophyIcon(Player player, string trophy) { foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if ((Object)(object)allItem.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == trophy) { return allItem.GetIcon(); } } return null; } public static string FormatTime(float seconds) { int num = Mathf.Max(0, Mathf.CeilToInt(seconds)); if (num < 60) { return $"{num}s"; } return $"{num / 60}m {num % 60:00}s"; } public static void Register(ObjectDB db) { if (!((Object)(object)db == (Object)null) && db.m_StatusEffects != null && !db.m_StatusEffects.Contains((StatusEffect)(object)Template)) { db.m_StatusEffects.Add((StatusEffect)(object)Template); } } } internal static class Disguise { internal static readonly int ZTrophy = StringExtensionMethods.GetStableHashCode("YouDied.MoD.Trophy"); internal static readonly int ZExposed = StringExtensionMethods.GetStableHashCode("YouDied.MoD.Exposed"); internal static readonly int ZFit = StringExtensionMethods.GetStableHashCode("YouDied.MoD.Fit"); internal const string SaveKey = "YouDied.MasterOfDisguise.Trophy"; internal static readonly FieldRef<Character, ZNetView> CharNView = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview"); private static readonly Dictionary<int, string> s_prefabNames = new Dictionary<int, string>(); private static Player s_initFor; private static float s_exposedUntil; private static float s_nextInventoryCheck; private static readonly FieldRef<Character, Faction> FactionField = AccessTools.FieldRefAccess<Character, Faction>("m_faction"); internal static bool Probing; public static ZDO GetZDO(Character c) { if ((Object)(object)c == (Object)null) { return null; } ZNetView val = CharNView.Invoke(c); if (!((Object)(object)val != (Object)null) || !val.IsValid()) { return null; } return val.GetZDO(); } public static string GetWorn(Player p) { ZDO zDO = GetZDO((Character)(object)p); return ((zDO != null) ? zDO.GetString(ZTrophy, "") : null) ?? ""; } public static bool IsExposed(Player p) { ZDO zDO = GetZDO((Character)(object)p); return zDO != null && zDO.GetInt(ZExposed, 0) != 0; } private static string PrefabName(Character c) { int instanceID = ((Object)c).GetInstanceID(); if (!s_prefabNames.TryGetValue(instanceID, out var value)) { value = Utils.GetPrefabName(((Component)c).gameObject); s_prefabNames[instanceID] = value; } return value; } public static bool Fools(Player player, Character creature, bool ignoreExposed = false) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Enabled.Value || (Object)(object)player == (Object)null || (Object)(object)creature == (Object)null) { return false; } if (creature.IsPlayer() || (int)creature.GetFaction() == 8 || creature.IsTamed()) { return false; } ZDO zDO = GetZDO((Character)(object)player); if (zDO == null) { return false; } string text = zDO.GetString(ZTrophy, ""); if (text.Length == 0) { return false; } if (!ignoreExposed && zDO.GetInt(ZExposed, 0) != 0) { return false; } TrophyInfo trophyInfo = TrophyDatabase.Get(text); if (trophyInfo == null || TrophyDatabase.IsExcluded(text)) { return false; } if (trophyInfo.FromBoss && !Plugin.BossFoolsAll.Value) { return false; } Faction faction = creature.GetFaction(); if (!TrophyDatabase.IsDisguisableFaction(faction)) { return false; } BaseAI baseAI = creature.GetBaseAI(); if ((Object)(object)baseAI != (Object)null && baseAI.IsAggravated()) { return false; } if (trophyInfo.FromBoss) { return BossBiomes.Fools(text, creature); } switch (Plugin.Scope.Value) { case DisguiseScope.Creature: return trophyInfo.Creatures.Contains(PrefabName(creature)); case DisguiseScope.Faction: return trophyInfo.Factions.Contains(faction); default: if (trophyInfo.Factions.Contains(faction)) { return true; } foreach (Faction faction2 in trophyInfo.Factions) { if (TrophyDatabase.IsDisguisableFaction(faction2) && GameSaysFriendly(creature, player, faction2)) { return true; } } return false; } } private static bool GameSaysFriendly(Character creature, Player player, Faction asFaction) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected I4, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected I4, but got Unknown ref Faction reference = ref FactionField.Invoke((Character)(object)player); Faction val = reference; Probing = true; reference = (Faction)(int)asFaction; try { return !BaseAI.IsEnemy(creature, (Character)(object)player); } finally { reference = (Faction)(int)val; Probing = false; } } internal static IEnumerable<Faction> AlliesOf(IEnumerable<Faction> trophyFactions) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) HashSet<Faction> hashSet = new HashSet<Faction>(); foreach (Faction trophyFaction in trophyFactions) { if (!TrophyDatabase.IsDisguisableFaction(trophyFaction)) { continue; } hashSet.Add(trophyFaction); foreach (Faction value in Enum.GetValues(typeof(Faction))) { if (TrophyDatabase.IsDisguisableFaction(value) && !TableIsEnemy(value, trophyFaction)) { hashSet.Add(value); } } } return hashSet; } private static bool TableIsEnemy(Faction a, Faction b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected I4, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Invalid comparison between Unknown and I4 //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Invalid comparison between Unknown and I4 //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Invalid comparison between Unknown and I4 //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Invalid comparison between Unknown and I4 //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Invalid comparison between Unknown and I4 //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Invalid comparison between Unknown and I4 //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Invalid comparison between Unknown and I4 //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Invalid comparison between Unknown and I4 //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Invalid comparison between Unknown and I4 //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Invalid comparison between Unknown and I4 if (a == b) { return false; } switch ((int)a) { case 0: return (int)b != 10; case 1: case 11: return true; case 2: case 9: case 13: if ((int)b != 1) { return (int)b != 8; } return false; case 3: if ((int)b != 4) { return (int)b != 8; } return false; case 4: if ((int)b != 3) { return (int)b != 8; } return false; case 5: case 6: case 7: return (int)b != 8; case 8: if ((int)b != 0) { return (int)b == 11; } return true; case 10: if ((int)b != 1 && (int)b != 8) { return (int)b > 0; } return false; case 12: return (int)b == 0; default: return false; } } public static void Wear(Player player, ItemData item) { string text = (((Object)(object)item?.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null); if (!string.IsNullOrEmpty(text)) { if (GetWorn(player) == text) { Remove(player); return; } if (FitStore.IsSkipped(text)) { Message(player, "The " + Loc.T(item.m_shared.m_name) + " can't be worn."); return; } SetWorn(player, text); Message(player, DescribeDisguise(text, item)); } } public static void Remove(Player player, string reason = null) { if (GetWorn(player).Length != 0) { FitMode.Exit(player, save: true); Cost.Clear(player); SetWorn(player, ""); Message(player, reason ?? "You take off your disguise."); } } private static void SetWorn(Player player, string trophy) { ZDO zDO = GetZDO((Character)(object)player); if (zDO != null) { zDO.Set(ZTrophy, trophy); zDO.Set(ZFit, (trophy.Length > 0) ? FitStore.Get(trophy).Serialize() : ""); zDO.Set(ZExposed, 0, false); s_exposedUntil = 0f; if (trophy.Length > 0) { player.m_customData["YouDied.MasterOfDisguise.Trophy"] = trophy; } else { player.m_customData.Remove("YouDied.MasterOfDisguise.Trophy"); } } } private static string DescribeDisguise(string trophy, ItemData item) { return "You put on the " + Loc.T(item.m_shared.m_name) + "."; } internal static IEnumerable<string> Fmt(IEnumerable<Faction> factions) { foreach (Faction faction in factions) { if (TrophyDatabase.IsDisguisableFaction(faction)) { yield return TrophyDatabase.FactionDisplayName(faction); } } } internal static string JoinNames(TrophyInfo info) { List<string> list = new List<string>(); foreach (string creatureDisplayName in info.CreatureDisplayNames) { list.Add(Loc.T(creatureDisplayName)); } return string.Join(", ", list); } private static string Cap(string s) { if (!string.IsNullOrEmpty(s)) { return char.ToUpperInvariant(s[0]) + s.Substring(1); } return s; } public static void OnLocalAttack(Player player, Character target) { if (Plugin.BreakOnAttack.Value && !((Object)(object)target == (Object)null) && !target.IsDead() && GetWorn(player).Length != 0 && Fools(player, target, ignoreExposed: true)) { ZDO zDO = GetZDO((Character)(object)player); bool flag = zDO.GetInt(ZExposed, 0) != 0; zDO.Set(ZExposed, 1, false); s_exposedUntil = Time.time + (float)Plugin.BreakSeconds.Value; if (!flag) { Message(player, $"Your disguise is broken! ({Plugin.BreakSeconds.Value}s)"); } } } public static void LocalUpdate(Player player) { ZDO zDO = GetZDO((Character)(object)player); if (zDO == null) { return; } if ((Object)(object)s_initFor != (Object)(object)player) { s_initFor = player; s_exposedUntil = 0f; zDO.Set(ZExposed, 0, false); if (player.m_customData.TryGetValue("YouDied.MasterOfDisguise.Trophy", out var value) && !string.IsNullOrEmpty(value)) { if (!FitStore.IsSkipped(value) && HasTrophy(player, value)) { zDO.Set(ZTrophy, value); zDO.Set(ZFit, FitStore.Get(value).Serialize()); } else { player.m_customData.Remove("YouDied.MasterOfDisguise.Trophy"); zDO.Set(ZTrophy, ""); } } } string text = zDO.GetString(ZTrophy, ""); if (text.Length == 0) { return; } Cost.Update(player, text); text = zDO.GetString(ZTrophy, ""); if (text.Length == 0) { return; } if (zDO.GetInt(ZExposed, 0) != 0 && Time.time >= s_exposedUntil) { zDO.Set(ZExposed, 0, false); Message(player, "Your disguise holds again."); } if (Time.time >= s_nextInventoryCheck) { s_nextInventoryCheck = Time.time + 1f; if (!HasTrophy(player, text)) { Remove(player, "Your disguise is gone. The trophy left your inventory."); } } } internal static bool HasTrophy(Player player, string prefabName) { Inventory val = (((Object)(object)player != (Object)null) ? ((Humanoid)player).GetInventory() : null); if (val == null) { return false; } foreach (ItemData allItem in val.GetAllItems()) { if ((Object)(object)allItem.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == prefabName) { return true; } } return false; } private static void Message(Player player, string msg) { if (Plugin.ShowMessages.Value && (Object)(object)player == (Object)(object)Player.m_localPlayer) { ((Character)player).Message((MessageType)2, msg, 0, (Sprite)null, false); } } } internal enum AttachPoint { Head, Back, Hips, LeftArm, RightArm, LeftLeg, RightLeg } internal struct Fit { public AttachPoint Bone; public Vector3 Offset; public Vector3 Euler; public float Scale; public static Fit Default => new Fit { Bone = AttachPoint.Head, Offset = Vector3.zero, Euler = Vector3.zero, Scale = 1f }; public string Serialize() { CultureInfo invariantCulture = CultureInfo.InvariantCulture; return string.Join(",", Offset.x.ToString("0.###", invariantCulture), Offset.y.ToString("0.###", invariantCulture), Offset.z.ToString("0.###", invariantCulture), Euler.x.ToString("0.#", invariantCulture), Euler.y.ToString("0.#", invariantCulture), Euler.z.ToString("0.#", invariantCulture), Scale.ToString("0.###", invariantCulture)) + ((Bone != AttachPoint.Head) ? ("," + Bone) : ""); } public static Fit Parse(string s) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) Fit result = Default; if (string.IsNullOrEmpty(s)) { return result; } string[] array = s.Split(new char[1] { ',' }); if (array.Length != 7 && array.Length != 8) { return result; } float[] array2 = new float[7]; for (int i = 0; i < 7; i++) { if (!float.TryParse(array[i], NumberStyles.Float, CultureInfo.InvariantCulture, out array2[i])) { return Default; } } result.Offset = new Vector3(array2[0], array2[1], array2[2]); result.Euler = new Vector3(array2[3], array2[4], array2[5]); result.Scale = Mathf.Clamp(array2[6], 0.1f, 5f); if (array.Length == 8) { try { result.Bone = (AttachPoint)Enum.Parse(typeof(AttachPoint), array[7].Trim(), ignoreCase: true); } catch { result.Bone = AttachPoint.Head; } } return result; } } internal static class FitStore { private static readonly Dictionary<string, Fit> s_fits = new Dictionary<string, Fit>(); private static readonly Dictionary<string, bool> s_skip = new Dictionary<string, bool>(); private static readonly HashSet<string> BuiltInSkips = new HashSet<string> { "TrophyAbomination", "TrophyBarka", "TrophyKvastur", "TrophyHare", "TrophyMole", "TrophyCharredArcher", "TrophyCharredMage", "TrophyWraith", "TrophyFenring" }; private static readonly Dictionary<string, string> BuiltInFits = new Dictionary<string, string> { { "TrophyEikthyr", "0.007,0.379,0.322,2.8,-179.8,0,1" }, { "TrophyTheElder", "0.157,-0.123,0.267,-33.4,-175.2,0,1" }, { "TrophyAbomination", "-0.269,-0.502,0.087,27.1,-136.5,-80.3,0.954" }, { "TrophyAsksvin", "0.016,-0.221,0.177,-57.5,-0.2,-178.1,1.137" }, { "TrophyBjorn", "0.027,0,0.135,-52.6,5.6,177.9,0.976" }, { "TrophyBlob", "-0.001,-0.294,0.18,-15.6,169.4,0,1" }, { "TrophyBoar", "0.012,-0.301,0.327,-11.6,-178.1,0,1" }, { "TrophyBonemawSerpent", "-0.009,0.924,0.587,46.2,179.1,0,0.863" }, { "TrophyCultist", "0.014,-0.09,0.323,0,-178.6,0,1" }, { "TrophyDeathsquito", "0.003,-0.302,0.571,-36.4,-179.4,0,0.998" }, { "TrophyDeer", "0.015,0.039,0.241,38.3,0,0,1" }, { "TrophyHatchling", "0,-0.085,0.159,-1.2,178.8,0,1" }, { "TrophyDraugrElite", "0.019,-0.344,0.235,0,179.4,0,1" }, { "TrophyDraugr", "0.001,-0.384,0.309,0,174.4,0,1" }, { "TrophyDraugrFem", "0.019,-0.402,0.109,0,175.8,0,1" }, { "TrophyDvergr", "0.002,-0.602,0.286,-114,178.9,0,0.997" }, { "TrophyElaking", "0,-0.273,0.213,-89.9,-179.9,0,1.126" }, { "TrophyFader", "0,0.164,0.871,170.9,1.1,0,1" }, { "TrophyFallenValkyrie", "0,-0.201,0.311,67.5,178.8,0,1" }, { "TrophyFenring", "0.199,-0.263,0.032,140.7,7.1,5.1,0.464,RightArm" }, { "TrophyGoblinBrute", "0,-0.05,0.189,0,-179,0,1" }, { "TrophyGoblinShaman", "0,-0.162,0.082,44.5,-179.7,0,1" }, { "TrophyGoblin", "0,-0.263,0.185,-35.8,-179.3,0,1" }, { "TrophyCultist_Hildir", "0.003,-0.14,0.287,0,-179.7,0,1" }, { "TrophyGhost", "0,-0.277,0.233,-116.8,0.8,0,1.124" }, { "TrophyGjall", "-0.012,-0.872,0.351,-116.2,-176.1,0,1" }, { "TrophyGreydwarfBrute", "-0.031,-0.099,0.156,-31,-177,0,1" }, { "TrophyGreydwarfShaman", "0.003,0.001,0.175,-35.7,178.4,0,1" }, { "TrophyGreydwarf", "0,-0.309,0.204,-29.5,-179.9,0,1" }, { "TrophyGrowth", "0.018,-0.139,0.307,-9.4,-177.9,0,1" }, { "TrophyJotunWitch", "0,-0.19,0.471,-71.4,177,0,1" }, { "TrophyJotunWarrior", "0,-0.255,0.205,-65.5,-179.8,0,1" }, { "TrophyLox", "0,0,0.063,-46.3,180,0,1" }, { "TrophyDragonQueen", "0.021,0.322,-0.446,12.5,176.5,0,1" }, { "TrophyMoose", "0,0,0.291,-123,178.8,0,1" }, { "TrophyNeck", "0.011,-0.279,0.152,0,178.9,0,1" }, { "TrophySkeletonPoison", "0,-0.291,0.169,-28.9,-178.7,0,1" }, { "TrophySeal", "0,-0.155,0.213,-88.5,-179.4,0,1" }, { "TrophySeekerBrute", "0,-0.43,0.137,-89.1,-177.8,0,1" }, { "TrophySeeker", "0,0.916,-0.288,-52.4,0,0,1,Back" }, { "TrophySerpent", "-0.028,0.551,1.011,-13.5,-178.8,0,1" }, { "TrophySkeleton", "0,-0.28,0.189,-35.8,-178.5,0,1" }, { "TrophySeekerQueen", "0.022,0.548,0.563,-175,-3,0,1" }, { "TrophyGoblinBruteBrosBrute", "0,-0.026,0.184,0,176.8,0,1" }, { "TrophyTick", "-0.003,-0.389,0.321,59.3,0,0,1" }, { "TrophyFrostTroll", "0.012,0,0,60,-178.2,0,1" }, { "TrophyUlv", "0.542,-0.159,-0.263,0,-3.5,0,1,Hips" }, { "TrophyBjornUndead", "0,-0.123,0.29,-45.9,177.5,0,1" }, { "TrophyVolture", "0,-0.278,0.402,-129.6,179.6,0,1" }, { "TrophyCharredMelee", "0,-0.279,0.217,-35,178.7,0,1" }, { "TrophyWolf", "0,-0.213,0.291,-29.7,178.9,0,1" }, { "TrophyWraith", "-0.038,-0.343,0.266,-16.8,176.5,0,1,Back" }, { "TrophyGoblinKing", "0,0.52,0.033,40.3,-178.3,0,1" }, { "TrophyGoblinBruteBrosShaman", "0.008,-0.276,0.192,0,-176.2,0,1" }, { "TrophyDeerWhite", "0.021,0.022,0.306,46.9,3.6,0,1" }, { "TrophyBarka", "-0.047,0.32,0.015,-96.9,-180,0,1" }, { "TrophyBonemass", "0.056,-0.254,0.024,-19.6,177.2,0,1" }, { "TrophySkeletonHildir", "0.005,-0.289,0.195,-30.2,178.2,0,1" }, { "TrophyBlob_Frost", "-0.003,-0.262,0.242,6.7,167.9,0,1" }, { "TrophyBlob_Lava", "0.014,-0.254,0.24,-15.6,-174.1,0,1" }, { "TrophyLeech", "-0.028,-0.236,0.173,0,-172.3,0,1" }, { "TrophyCharredArcher", "0,-0.286,0.07,-22.1,-173.5,0,0.762,Hips" }, { "TrophyMorgen", "0,0.055,0.154,2.3,172.6,0,1,Back" }, { "TrophyBlob_Morkhalla", "0.021,-0.293,0.221,-20.5,178.5,0,1" }, { "TrophySGolem", "-0.074,0.403,0.409,0,0,0,1" }, { "TrophySurtling", "0,-0.221,0.226,-25.4,-179.6,0,1" }, { "TrophyCharredMage", "0,-0.322,0.144,-26.6,-178.2,0,1,Back" }, { "TrophyWrithan", "0,-0.253,0.288,56.9,0,0,1" } }; private static Dictionary<string, Fit> s_builtInParsed; private static string FilePath => Path.Combine(Paths.ConfigPath, "YouDied.MasterOfDisguise.fits.txt"); public static bool IsSkipped(string trophy) { if (string.IsNullOrEmpty(trophy)) { return false; } if (!s_skip.TryGetValue(trophy, out var value)) { return BuiltInSkips.Contains(trophy); } return value; } public static void ToggleSkip(string trophy) { bool flag = !IsSkipped(trophy); if (flag == BuiltInSkips.Contains(trophy)) { s_skip.Remove(trophy); } else { s_skip[trophy] = flag; } Save(); } public static Fit Get(string trophy) { if (!s_fits.TryGetValue(trophy, out var value)) { return BuiltIn(trophy); } return value; } public static Fit BuiltIn(string trophy) { if (s_builtInParsed == null) { s_builtInParsed = new Dictionary<string, Fit>(); foreach (KeyValuePair<string, string> builtInFit in BuiltInFits) { s_builtInParsed[builtInFit.Key] = Fit.Parse(builtInFit.Value); } } if (trophy == null || !s_builtInParsed.TryGetValue(trophy, out var value)) { return Fit.Default; } return value; } public static void Set(string trophy, Fit fit) { s_fits[trophy] = fit; Save(); } public static void Reset(string trophy) { s_fits.Remove(trophy); Save(); } public static void Load() { s_fits.Clear(); s_skip.Clear(); try { if (!File.Exists(FilePath)) { return; } string[] array = File.ReadAllLines(FilePath); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0 || text.StartsWith("#")) { continue; } int num = text.IndexOf('='); if (num > 0) { string key = text.Substring(0, num).Trim(); string text2 = text.Substring(num + 1).Trim(); if (text2.Equals("skip", StringComparison.OrdinalIgnoreCase)) { s_skip[key] = true; } else if (text2.Equals("wear", StringComparison.OrdinalIgnoreCase)) { s_skip[key] = false; } else { s_fits[key] = Fit.Parse(text2); } } } } catch (Exception ex) { Plugin.Warn("Could not read trophy fits: " + ex.Message); } } private static void Save() { try { List<string> list = new List<string> { "# Master of Disguise trophy fits. Made with fit mode in game (default F7).", "# TrophyName = offsetX,offsetY,offsetZ (m), rotX,rotY,rotZ (deg), scale[, bodyPart]", "# TrophyName = skip (can't be worn: arms, legs, cloaks...) TrophyName = wear (undo a default skip)" }; foreach (KeyValuePair<string, Fit> s_fit in s_fits) { list.Add(s_fit.Key + "=" + s_fit.Value.Serialize()); } foreach (KeyValuePair<string, bool> item in s_skip) { list.Add(item.Key + "=" + (item.Value ? "skip" : "wear")); } File.WriteAllLines(FilePath, list.ToArray()); } catch (Exception ex) { Plugin.Warn("Could not save trophy fits: " + ex.Message); } } } internal static class FitMode { private static readonly KeyboardShortcut Fwd = new KeyboardShortcut((KeyCode)273, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut Back = new KeyboardShortcut((KeyCode)274, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut Left = new KeyboardShortcut((KeyCode)276, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut Right = new KeyboardShortcut((KeyCode)275, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut Up = new KeyboardShortcut((KeyCode)273, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }); private static readonly KeyboardShortcut Down = new KeyboardShortcut((KeyCode)274, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }); private static readonly KeyboardShortcut PitchUp = new KeyboardShortcut((KeyCode)273, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }); private static readonly KeyboardShortcut PitchDown = new KeyboardShortcut((KeyCode)274, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }); private static readonly KeyboardShortcut YawLeft = new KeyboardShortcut((KeyCode)276, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }); private static readonly KeyboardShortcut YawRight = new KeyboardShortcut((KeyCode)275, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }); private static readonly KeyboardShortcut RollLeft = new KeyboardShortcut((KeyCode)276, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }); private static readonly KeyboardShortcut RollRight = new KeyboardShortcut((KeyCode)275, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }); private static readonly KeyboardShortcut Grow = new KeyboardShortcut((KeyCode)273, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }); private static readonly KeyboardShortcut Shrink = new KeyboardShortcut((KeyCode)274, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }); private static readonly KeyboardShortcut ResetKey = new KeyboardShortcut((KeyCode)8, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut BoneKey = new KeyboardShortcut((KeyCode)98, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut SlowerKey = new KeyboardShortcut((KeyCode)91, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut FasterKey = new KeyboardShortcut((KeyCode)93, Array.Empty<KeyCode>()); private static readonly int[] Speeds = new int[6] { 5, 10, 25, 50, 100, 200 }; private static int s_speedIndex = 3; private const float MoveSpeed = 0.12f; private const float TurnSpeed = 60f; private const float ScaleSpeed = 0.6f; private static bool s_active; private static string s_trophy; private static Fit s_fit; private static float s_nextBroadcast; public static int SpeedPercent => Speeds[s_speedIndex]; public static bool Active => s_active; public static void Update(Player player) { //IL_0027: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) string worn = Disguise.GetWorn(player); if (s_active && worn != s_trophy) { Exit(player, save: true); } KeyboardShortcut val = Plugin.FitModeKey.Value; if (((KeyboardShortcut)(ref val)).IsDown()) { if (s_active) { Exit(player, save: true); } else if (worn.Length > 0) { Enter(player, worn); } else { ((Character)player).Message((MessageType)2, "Wear a trophy first, then fit it.", 0, (Sprite)null, false); } } if (!s_active) { return; } Fit fit = Nudge(s_fit); val = ResetKey; if (((KeyboardShortcut)(ref val)).IsDown()) { fit = FitStore.BuiltIn(s_trophy); ((Character)player).Message((MessageType)1, "Trophy fit reset.", 0, (Sprite)null, false); } s_fit = fit; Visual(player)?.SetLive(s_fit); if (Time.time >= s_nextBroadcast) { s_nextBroadcast = Time.time + 0.25f; ZDO zDO = Disguise.GetZDO((Character)(object)player); if (zDO != null) { zDO.Set(Disguise.ZFit, s_fit.Serialize()); } } } internal static Fit Nudge(Fit f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut val = SlowerKey; if (((KeyboardShortcut)(ref val)).IsDown() && s_speedIndex > 0) { s_speedIndex--; } val = FasterKey; if (((KeyboardShortcut)(ref val)).IsDown() && s_speedIndex < Speeds.Length - 1) { s_speedIndex++; } float num = Time.unscaledDeltaTime * (float)SpeedPercent / 100f; val = BoneKey; if (((KeyboardShortcut)(ref val)).IsDown()) { AttachPoint bone = (AttachPoint)((int)(f.Bone + 1) % Enum.GetValues(typeof(AttachPoint)).Length); f = Fit.Default; f.Bone = bone; } val = Fwd; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Offset.z += 0.12f * num; } val = Back; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Offset.z -= 0.12f * num; } val = Left; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Offset.x -= 0.12f * num; } val = Right; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Offset.x += 0.12f * num; } val = Up; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Offset.y += 0.12f * num; } val = Down; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Offset.y -= 0.12f * num; } val = PitchUp; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Euler.x -= 60f * num; } val = PitchDown; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Euler.x += 60f * num; } val = YawLeft; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Euler.y -= 60f * num; } val = YawRight; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Euler.y += 60f * num; } val = RollLeft; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Euler.z += 60f * num; } val = RollRight; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Euler.z -= 60f * num; } val = Grow; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Scale *= 1f + 0.6f * num; } val = Shrink; if (((KeyboardShortcut)(ref val)).IsPressed()) { f.Scale /= 1f + 0.6f * num; } f.Scale = Mathf.Clamp(f.Scale, 0.1f, 5f); f.Euler = new Vector3(Wrap(f.Euler.x), Wrap(f.Euler.y), Wrap(f.Euler.z)); return f; } internal static bool ResetPressed() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut resetKey = ResetKey; return ((KeyboardShortcut)(ref resetKey)).IsDown(); } private static void Enter(Player player, string trophy) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) s_active = true; s_trophy = trophy; s_fit = FitStore.Get(trophy); ((Character)player).Message((MessageType)2, "Fit mode: arrows move, Shift+Up/Down height, Ctrl+arrows turn, B body part, [ ] speed,\n" + $"Alt+Left/Right roll, Alt+Up/Down size, Backspace reset. {Plugin.FitModeKey.Value} saves.\nDisguise timer paused.", 0, (Sprite)null, false); } public static void Exit(Player player, bool save) { if (!s_active) { return; } s_active = false; if (save && !string.IsNullOrEmpty(s_trophy)) { if (s_fit.Serialize() == FitStore.BuiltIn(s_trophy).Serialize()) { FitStore.Reset(s_trophy); } else { FitStore.Set(s_trophy, s_fit); } ZDO zDO = Disguise.GetZDO((Character)(object)player); if (zDO != null) { zDO.Set(Disguise.ZFit, s_fit.Serialize()); } ((Character)player).Message((MessageType)2, "Trophy fit saved.", 0, (Sprite)null, false); } Visual(player)?.ClearLive(); s_trophy = null; } private static TrophyVisual Visual(Player player) { VisEquipment component = ((Component)player).GetComponent<VisEquipment>(); if (!((Object)(object)component != (Object)null)) { return null; } return ((Component)component).GetComponent<TrophyVisual>(); } private static float Wrap(float deg) { deg %= 360f; if (deg > 180f) { deg -= 360f; } if (deg < -180f) { deg += 360f; } return deg; } } internal static class TrophyVisualLiveExt { public static void SetLive(this TrophyVisual tv, Fit fit) { tv.LiveFit = fit; } public static void ClearLive(this TrophyVisual tv) { tv.LiveFit = null; tv.ForceRefit(); } } internal static class Loc { private static bool s_resolved; private static PropertyInfo s_instance; private static MethodInfo s_localize; public static string T(string token) { if (string.IsNullOrEmpty(token)) { return token; } if (!s_resolved) { s_resolved = true; Type type = AccessTools.TypeByName("Localization"); s_instance = ((type != null) ? AccessTools.Property(type, "instance") : null); s_localize = ((type != null) ? AccessTools.Method(type, "Localize", new Type[1] { typeof(string) }, (Type[])null) : null); } try { object obj = s_instance?.GetValue(null, null); if (obj != null && s_localize != null) { return (string)s_localize.Invoke(obj, new object[1] { token }); } } catch { } return token.TrimStart(new char[1] { '$' }); } } internal static class MenuFitting { private static readonly KeyboardShortcut PrevKey = new KeyboardShortcut((KeyCode)44, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut NextKey = new KeyboardShortcut((KeyCode)46, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut TurnLeft = new KeyboardShortcut((KeyCode)113, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut TurnRight = new KeyboardShortcut((KeyCode)101, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut SkipKey = new KeyboardShortcut((KeyCode)127, Array.Empty<KeyCode>()); private static readonly KeyboardShortcut RefKey = new KeyboardShortcut((KeyCode)114, Array.Empty<KeyCode>()); private static bool s_showRef = true; private static GameObject s_reference; private static string s_referenceFor; private const float SpinSpeed = 90f; private static bool s_active; private static GameObject s_preview; private static List<KeyValuePair<string, string>> s_trophies; private static int s_index; private static Fit s_fit; private static readonly FieldRef<FejdStartup, GameObject> PlayerInstance = AccessTools.FieldRefAccess<FejdStartup, GameObject>("m_playerInstance"); private static bool s_guiResolved; private static MethodInfo s_box; public static bool Active => s_active; private static string Current { get { if (!s_active || s_trophies == null || s_trophies.Count <= 0) { return null; } return s_trophies[s_index].Key; } } private static GameObject Preview() { if (!Plugin.FittingRoom.Value) { return null; } FejdStartup instance = FejdStartup.instance; GameObject val = (((Object)(object)instance != (Object)null) ? PlayerInstance.Invoke(instance) : null); if ((Object)(object)val == (Object)null) { return null; } if ((Object)(object)instance.m_characterSelectScreen == (Object)null || !instance.m_characterSelectScreen.activeInHierarchy) { return null; } return val; } public static void Drive(VisEquipment vis) { FejdStartup instance = FejdStartup.instance; GameObject val = (((Object)(object)instance != (Object)null) ? PlayerInstance.Invoke(instance) : null); if ((Object)(object)val == (Object)null || (Object)(object)((Component)vis).gameObject != (Object)(object)val) { return; } TrophyVisual trophyVisual = TrophyVisual.For(vis); if (s_active && (Object)(object)s_preview == (Object)(object)((Component)vis).gameObject && Current != null) { trophyVisual.SyncLocal(Current, s_fit); return; } Player component = ((Component)vis).GetComponent<Player>(); string value = null; if ((Object)(object)component != (Object)null) { component.m_customData.TryGetValue("YouDied.MasterOfDisguise.Trophy", out value); } if (string.IsNullOrEmpty(value) || FitStore.IsSkipped(value) || !Disguise.HasTrophy(component, value)) { value = ""; } trophyVisual.SyncLocal(value, (value.Length == 0) ? Fit.Default : FitStore.Get(value)); } public static void Update() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) GameObject val = Preview(); if ((Object)(object)val == (Object)null) { if (s_active) { Exit(); } return; } if (s_active && (Object)(object)val != (Object)(object)s_preview) { Exit(); } VisEquipment component = val.GetComponent<VisEquipment>(); if ((Object)(object)component != (Object)null) { Drive(component); } KeyboardShortcut val2 = Plugin.FitModeKey.Value; if (((KeyboardShortcut)(ref val2)).IsDown()) { if (s_active) { Exit(); } else { Enter(val); } } if (s_active && Current != null) { val2 = NextKey; if (((KeyboardShortcut)(ref val2)).IsDown()) { Step(1); } val2 = PrevKey; if (((KeyboardShortcut)(ref val2)).IsDown()) { Step(-1); } val2 = TurnLeft; if (((KeyboardShortcut)(ref val2)).IsPressed()) { val.transform.Rotate(0f, 90f * Time.unscaledDeltaTime, 0f, (Space)0); } val2 = TurnRight; if (((KeyboardShortcut)(ref val2)).IsPressed()) { val.transform.Rotate(0f, -90f * Time.unscaledDeltaTime, 0f, (Space)0); } val2 = SkipKey; if (((KeyboardShortcut)(ref val2)).IsDown()) { FitStore.ToggleSkip(Current); } val2 = RefKey; if (((KeyboardShortcut)(ref val2)).IsDown()) { s_showRef = !s_showRef; } UpdateReference(val); s_fit = FitMode.Nudge(s_fit); if (FitMode.ResetPressed()) { s_fit = FitStore.BuiltIn(Current); } } } private static void Enter(GameObject preview) { BuildList(); if (s_trophies.Count == 0) { return; } s_active = true; s_preview = preview; Player component = preview.GetComponent<Player>(); s_index = 0; if ((Object)(object)component != (Object)null && component.m_customData.TryGetValue("YouDied.MasterOfDisguise.Trophy", out var saved)) { int num = s_trophies.FindIndex((KeyValuePair<string, string> t) => t.Key == saved); if (num >= 0) { s_index = num; } } s_fit = FitStore.Get(Current); } private static void Step(int dir) { SaveCurrent(); s_index = (s_index + dir + s_trophies.Count) % s_trophies.Count; s_fit = FitStore.Get(Current); } private static void Exit() { ClearReference(); SaveCurrent(); s_active = false; s_preview = null; } private static void UpdateReference(GameObject preview) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) if (!s_showRef || Current == null) { ClearReference(); return; } if ((Object)(object)s_reference == (Object)null || s_referenceFor != Current) { ClearReference(); s_reference = BuildReference(Current); s_referenceFor = Current; } if (!((Object)(object)s_reference == (Object)null)) { Transform transform = preview.transform; s_reference.transform.position = transform.position + transform.right * 0.9f + Vector3.up * 1.5f; s_reference.transform.rotation = transform.rotation; } } private static GameObject BuildReference(string trophy) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(trophy) : null); if ((Object)(object)val == (Object)null) { return null; } try { return TrophyVisual.MeshCopy(val); } catch (Exception ex) { Plugin.Warn("Couldn't build a size reference for " + trophy + ": " + ex.Message); return null; } } private static void ClearReference() { if ((Object)(object)s_reference != (Object)null) { Object.Destroy((Object)(object)s_reference); } s_reference = null; s_referenceFor = null; } private static void SaveCurrent() { string current = Current; if (current != null && !(s_fit.Serialize() == FitStore.Get(current).Serialize())) { if (s_fit.Serialize() == FitStore.BuiltIn(current).Serialize()) { FitStore.Reset(current); } else { FitStore.Set(current, s_fit); } } } private static void BuildList() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between Unknown and I4 s_trophies = new List<KeyValuePair<string, string>>(); ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return; } foreach (GameObject item in instance.m_items) { if (!((Object)(object)item == (Object)null)) { ItemDrop component = item.GetComponent<ItemDrop>(); SharedData val = ((!((Object)(object)component != (Object)null)) ? null : component.m_itemData?.m_shared); if (val != null && (int)val.m_itemType == 13 && item.GetComponentsInChildren<Renderer>(true).Length != 0) { s_trophies.Add(new KeyValuePair<string, string>(((Object)item).name, Loc.T(val.m_name))); } } } s_trophies.Sort((KeyValuePair<string, string> a, KeyValuePair<string, string> b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase)); } public static void OnGUI() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Preview() == (Object)null)) { string text; if (!s_active) { text = $"Master of Disguise: press {Plugin.FitModeKey.Value} to open the trophy fitting room"; Draw(new Rect(20f, 20f, 520f, 28f), text); return; } KeyValuePair<string, string> keyValuePair = s_trophies[s_index]; bool flag = FitStore.Get(keyValuePair.Key).Serialize() != FitStore.BuiltIn(keyValuePair.Key).Serialize() || s_fit.Serialize() != FitStore.BuiltIn(keyValuePair.Key).Serialize(); text = $"TROPHY FITTING ROOM {s_index + 1}/{s_trophies.Count}\n" + keyValuePair.Value + " (" + keyValuePair.Key + ")" + (flag ? " [custom fit]" : "") + "\n" + (FitStore.IsSkipped(keyValuePair.Key) ? "*** SKIPPED: can't be worn in game (Delete to undo) ***\n\n" : "\n") + ", / . previous / next trophy\nQ / E turn your character\n" + $"[ / ] slower / faster adjusting: {FitMode.SpeedPercent}%\n" + "R size reference beside you: " + (s_showRef ? "on" : "off") + " (true in-game size)\n" + $"B body part: {s_fit.Bone} (Head, Back, Hips, arms, legs)\n" + "Arrows move forward/back/left/right\nShift+Up/Dn raise / lower\nCtrl+arrows tilt / turn\nAlt+Lt/Rt roll\nAlt+Up/Dn bigger / smaller\nBackspace reset this trophy\nDelete skip this trophy (not a head) / undo\n" + $"{Plugin.FitModeKey.Value} save and close (switching trophies also saves)"; Draw(new Rect(20f, 20f, 600f, 350f), text); } } private static void Draw(Rect rect, string text) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (!s_guiResolved) { s_guiResolved = true; s_box = Type.GetType("UnityEngine.GUI, UnityEngine.IMGUIModule")?.GetMethod("Box", new Type[2] { typeof(Rect), typeof(string) }); } try { s_box?.Invoke(null, new object[2] { rect, text }); } catch { } } } [HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[] { typeof(Character), typeof(Character) })] internal static class IsEnemyPatch { private static void Postfix(Character a, Character b, ref bool __result) { if (__result && !((Object)(object)a == (Object)null) && !((Object)(object)b == (Object)null) && !Disguise.Probing) { Player val = (Player)(object)((b is Player) ? b : null); if (val != null && !(a is Player) && Disguise.Fools(val, a)) { __result = false; } } } } [HarmonyPatch(typeof(Character), "Damage")] internal static class DamagePatch { private static void Postfix(Character __instance, HitData hit) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && hit != null && !((Object)(object)__instance == (Object)(object)localPlayer) && !((Object)(object)hit.GetAttacker() != (Object)(object)localPlayer)) { Disguise.OnLocalAttack(localPlayer, __instance); } } } [HarmonyPatch(typeof(Player), "Update")] internal static class PlayerUpdatePatch { private unsafe static void Postfix(Player __instance) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } Disguise.LocalUpdate(__instance); if (InputBlocked()) { return; } KeyboardShortcut value = Plugin.RemoveKey.Value; object obj = KeyboardShortcut.Empty; if (!((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).Equals(obj)) { value = Plugin.RemoveKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Disguise.Remove(__instance); } } FitMode.Update(__instance); } internal static bool InputBlocked() { if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !Menu.IsVisible() && !TextInput.IsVisible()) { if ((Object)(object)Minimap.instance != (Object)null) { return Minimap.IsOpen(); } return false; } return true; } } [HarmonyPatch(typeof(InventoryGui), "Update")] internal static class InventoryKeyPatch { private static readonly MethodInfo HoveredMethod = AccessTools.Method(typeof(InventoryGrid), "GetHoveredElement", (Type[])null, (Type[])null); private static InventoryElement GetHovered(InventoryGrid grid) { object? obj = HoveredMethod?.Invoke(grid, null); return (InventoryElement)((obj is InventoryElement) ? obj : null); } private static void Postfix(InventoryGui __instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Invalid comparison between Unknown and I4 Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !InventoryGui.IsVisible()) { return; } KeyboardShortcut value = Plugin.WearKey.Value; if (!((KeyboardShortcut)(ref value)).IsDown() || PlayerUpdatePatch.InputBlocked()) { return; } InventoryGrid playerGrid = __instance.m_playerGrid; if ((Object)(object)playerGrid == (Object)null) { return; } InventoryElement hovered = GetHovered(playerGrid); if (!((Object)(object)hovered == (Object)null)) { Vector2i position = hovered.Position; Inventory inventory = playerGrid.GetInventory(); ItemData val = ((inventory != null) ? inventory.GetItemAt(position.x, position.y) : null); if (val?.m_shared != null && (int)val.m_shared.m_itemType == 13) { Disguise.Wear(localPlayer, val); } } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] internal static class InventoryMarkerPatch { private static readonly FieldInfo ElementsField = AccessTools.Field(typeof(InventoryGrid), "m_elements"); private static readonly FieldInfo Equipped = AccessTools.Field(typeof(InventoryElement), "m_equiped"); private static void Postfix(InventoryGrid __instance, Player player) { //IL_009d: 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 ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || Equipped == null || (Object)(object)InventoryGui.instance == (Object)null || (Object)(object)__instance != (Object)(object)InventoryGui.instance.m_playerGrid) { return; } string worn = Disguise.GetWorn(player); if (worn.Length == 0) { return; } Inventory inventory = __instance.GetInventory(); IList list = ElementsField?.GetValue(__instance) as IList; if (inventory == null || list == null) { return; } foreach (object item in list) { InventoryElement val = (InventoryElement)((item is InventoryElement) ? item : null); if (val == null) { continue; } ItemData itemAt = inventory.GetItemAt(val.Position.x, val.Position.y); if ((Object)(object)itemAt?.m_dropPrefab == (Object)null || ((Object)itemAt.m_dropPrefab).name != worn) { continue; } object value = Equipped.GetValue(val); Behaviour val2 = (Behaviour)((value is Behaviour) ? value : null); if (val2 != null) { val2.enabled = true; continue; } GameObject val3 = (GameObject)((value is GameObject) ? value : null); if (val3 != null) { val3.SetActive(true); } } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] internal static class TooltipPatch { private static void Postfix(ItemData item, ref string __result) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) if (item?.m_shared == null || (int)item.m_shared.m_itemType != 13 || (Object)(object)item.m_dropPrefab == (Object)null) { return; } string name = ((Object)item.m_dropPrefab).name; TrophyInfo trophyInfo = TrophyDatabase.Get(name); StringBuilder stringBuilder = new StringBuilder(__result); stringBuilder.Append("\n\n<color=orange>Master of Disguise</color>"); if (FitStore.IsSkipped(name)) { stringBuilder.Append("\nCan't be worn."); __result = stringBuilder.ToString(); return; } if (!Plugin.Enabled.Value) { bool flag = (Object)(object)Player.m_localPlayer != (Object)null && Disguise.GetWorn(Player.m_localPlayer) == name; stringBuilder.Append("\nCosmetic (disguise power is off)"); stringBuilder.Append($"\n<color=yellow>[{Plugin.WearKey.Value}]</color> ").Append(flag ? "Take off" : "Wear"); __result = stringBuilder.ToString(); return; } if (trophyInfo == null || TrophyDatabase.IsExcluded(name) || (trophyInfo.FromBoss && !Plugin.BossFoolsAll.Value)) { stringBuilder.Append("\nCosmetic only. Nobody is fooled by this one."); } else if (trophyInfo.FromBoss) { stringBuilder.Append("\nFools: every creature in the ").Append(BossBiomes.DisplayName(name)).Append(" (bosses excepted)"); } else if (Plugin.Scope.Value == DisguiseScope.Creature) { stringBuilder.Append("\nFools: ").Append(Disguise.JoinNames(trophyInfo)); } else if (Plugin.Scope.Value == DisguiseScope.Allies) { stringBuilder.Append("\nFools: ").Append(string.Join(", ", Disguise.Fmt(Disguise.AlliesOf(trophyInfo.Factions)))); } else { stringBuilder.Append("\nFools: ").Append(string.Join(", ", Disguise.Fmt(trophyInfo.Factions))); } Player localPlayer = Player.m_localPlayer; bool flag2 = (Object)(object)localPlayer != (Object)null && Disguise.GetWorn(localPlayer) == name; float num = Cost.LifetimeSeconds(name); if (num > 0f) { float num2 = (((Object)(object)localPlayer != (Object)null) ? Cost.UsedSeconds(localPlayer, name) : 0f); stringBuilder.Append("\nDisguise time: ").Append(Cost.FormatTime(num - num2)); if (num2 > 0f) { stringBuilder.Append(" left"); } stringBuilder.Append(" (crumbles when it runs out)"); } stringBuilder.Append($"\n<color=yellow>[{Plugin.WearKey.Value}]</color> ").Append(flag2 ? "Take off" : "Wear as disguise"); __result = stringBuilder.ToString(); } } [HarmonyPatch(typeof(VisEquipment), "UpdateEquipmentVisuals")] internal static class VisualPatch { private static readonly FieldRef<VisEquipment, ZNetView> VisNView = AccessTools.FieldRefAccess<VisEquipment, ZNetView>("m_nview"); private static void Postfix(VisEquipment __instance) { if (TrophyVisual.IsPlayer.Invoke(__instance)) { ZNetView val = VisNView.Invoke(__instance); if ((Object)(object)val == (Object)null || !val.IsValid()) { MenuFitting.Drive(__instance); } else { TrophyVisual.For(__instance).Sync(val.GetZDO()); } } } } [HarmonyPatch(typeof(FejdStartup), "UpdateKeyboard")] internal static class MenuKeyboardPatch { private static bool Prefix() { return !MenuFitting.Active; } } [HarmonyPatch(typeof(FejdStartup), "OnCharacterLeft")] internal static class MenuCharacterLeftPatch { private static bool Prefix() { return !MenuFitting.Active; } } [HarmonyPatch(typeof(FejdStartup), "OnCharacterRight")] internal static class MenuCharacterRightPatch { private static bool Prefix() { return !MenuFitting.Active; } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDBAwakePatch { private static void Postfix(ObjectDB __instance) { Cost.Register(__instance); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class SceneAwakePatch { private static void Postfix() { TrophyDatabase.Invalidate(); } } public enum DisguiseScope { Allies, Faction, Creature } [BepInPlugin("YouDied.MasterOfDisguise", "Master of Disguise", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "YouDied.MasterOfDisguise"; public const string Name = "Master of Disguise"; public const string Version = "1.0.0"; internal static Plugin Instance; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<DisguiseScope> Scope; internal static ConfigEntry<bool> AnimalDisguises; internal static ConfigEntry<string> ExcludedTrophies; internal static ConfigEntry<bool> BossFoolsAll; internal static ConfigEntry<string> BossBiomeMap; internal static ConfigEntry<string> UnlistedBossBiome; internal static ConfigEntry<bool> BreakOnAttack; internal static ConfigEntry<int> BreakSeconds; internal static ConfigEntry<bool> ShowMessages; internal static ConfigEntry<bool> ShowOnHead; internal static ConfigEntry<bool> HideHelmet; internal static ConfigEntry<int> TrophySize; internal static ConfigEntry<int> MaxTrophySize; internal static ConfigEntry<int> Facing; internal static ConfigEntry<int> Tilt; internal static ConfigEntry<int> ForwardOffset; internal static ConfigEntry<int> AutoFitHeight; internal static ConfigEntry<int> Lifetime; internal static ConfigEntry<bool> NeverBreaks; internal static ConfigEntry<int> StaminaRegen; internal static ConfigEntry<int> MoveSpeed; internal static ConfigEntry<bool> ShowStatusIcon; internal static ConfigEntry<KeyboardShortcut> WearKey; internal static ConfigEntry<KeyboardShortcut> RemoveKey; internal static ConfigEntry<KeyboardShortcut> FitModeKey; internal static ConfigEntry<bool> FittingRoom; private Harmony _harmony; private void Awake() { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Expected O, but got Unknown //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Expected O, but got Unknown //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Expected O, but got Unknown //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Expected O, but got Unknown //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Expected O, but got Unknown //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Expected O, but got Unknown //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_034b: Expected O, but got Unknown //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Expected O, but got Unknown //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_044d: Expected O, but got Unknown //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Expected O, but got Unknown //IL_05f0: Unknown result type (might be due to invalid IL or missing references) //IL_05fa: Expected O, but got Unknown Instance = this; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Disguise power", true, "On: wearing a trophy fools creatures. Off: trophies are cosmetic only (you can still wear and fit them, nobody is fooled, and they never wear out)."); Scope = ((BaseUnityPlugin)this).Config.Bind<DisguiseScope>("1 - General", "Disguise mode", DisguiseScope.Allies, "Allies: uses the game's own faction rules. A trophy fools its faction and every creature that wouldn't attack that creature (a Charred trophy fools whatever doesn't fight the Charred; a Skeleton trophy still won't fool Greydwarfs, because they fight skeletons).\nFaction: a trophy only fools its own faction (a Greydwarf trophy fools Greydwarfs, Brutes, Shamans and Trolls).\nCreature: a trophy only fools the creature that drops it (a Troll trophy only fools Trolls)."); AnimalDisguises = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Animal disguises", true, "Deer, boar, wolves-as-animals and other AnimalsVeg creatures stop fleeing from you while you wear their trophy."); ExcludedTrophies = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "Excluded trophies", "", "Comma-separated trophy prefab names that are cosmetic only (example: TrophyTroll,TrophySerpent)."); BossFoolsAll = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Boss trophies fool their biome", true, "Wearing a boss trophy makes every creature in that boss's biome friendly, whatever its faction. It does nothing in other biomes. Bosses themselves are never fooled."); BossBiomeMap = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "Boss trophy biomes", "TrophyEikthyr:Meadows, TrophyTheElder:BlackForest, TrophyBonemass:Swamp, TrophyDragonQueen:Mountain, TrophyGoblinKing:Plains, TrophySeekerQueen:Mistlands, TrophyFader:AshLands", "Which biome each boss trophy rules, as Trophy:Biome pairs. Add the Deep North boss or modded bosses here (the log lists every boss trophy found). Biomes: Meadows, BlackForest, Swamp, Mountain, Plains, Mistlands, AshLands, DeepNorth, Ocean."); UnlistedBossBiome = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "Modded boss trophies", "None", new ConfigDescription("Biome for boss trophies missing from the list above (all 7 vanilla boss trophies are listed; Kall Fimbulbringer drops none). Only matters for modded bosses. None = their trophies are cosmetic only. Better: add them to Boss trophy biomes.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[10] { "DeepNorth", "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands", "Ocean", "None" }), Array.Empty<object>())); BreakOnAttack = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Breaking the disguise", "Break on attack", true, "Hitting a creature your disguise is fooling exposes you, just like the masks in Breath of the Wild."); BreakSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Breaking the disguise", "Exposed seconds", 60, new ConfigDescription("How long the disguise stays broken after you attack.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 600), Array.Empty<object>())); ShowMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Breaking the disguise", "Show messages", true, "Show on-screen messages when your disguise breaks or holds again."); ShowOnHead = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Visuals", "Show trophy on head", true, "Draw the worn trophy on your head. Turn off to keep the disguise effect invisible."); HideHelmet = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Visuals", "Hide helmet while disguised", true, "Hide your real helmet so it doesn't poke through the trophy. Armor stats are unaffected."); TrophySize = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Visuals", "Trophy size (%)", 100, new ConfigDescription("Size of worn trophies. 100 = exactly the size the trophy is on the ground or on an item stand.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(25, 300), Array.Empty<object>())); MaxTrophySize = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Visuals", "Size cap (cm)", 0, new ConfigDescription("0 = trophies are worn at their actual size. Set a number to shrink huge trophies (bosses, Trolls, Lox) so their largest side is no bigger than this.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 500), Array.Empty<object>())); Facing = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Visuals", "Facing (degrees)", 0, new ConfigDescription("Turns every worn trophy around your vertical axis. Only needed if trophies don't face forward.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-180, 180), Array.Empty<object>())); Tilt = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Visuals", "Tilt forward (degrees)", 30, new ConfigDescription("Tips every worn trophy forward. Wall trophies are mounted nose-up, so this levels them out.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-90, 90), Array.Empty<object>())); ForwardOffset = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Visuals", "Forward offset (cm)", -20, new ConfigDescription("Moves every worn trophy forward (+) or back (-) so the skull sits on your head instead of in front of it.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-60, 60), Array.Empty<object>())); AutoFitHeight = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Visuals", "Height (cm)", 28, new ConfigDescription("How far above the head joint the trophy is centered, before your own fit adjustments.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-30, 60), Array.Empty<object>())); WearKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("4 - Keys", "Wear key", new KeyboardShortcut((KeyCode)121, Array.Empty<KeyCode>()), "Press while hovering a trophy in your inventory to wear it. Press on the worn trophy to take it off."); RemoveKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("4 - Keys", "Remove disguise key", KeyboardShortcut.Empty, "Optional key to take off your disguise from anywhere."); FitModeKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("4 - Keys", "Fit mode key", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Toggle fit mode for the worn trophy. Arrows move it, Shift+Up/Down raise/lower, Ctrl+arrows rotate, Alt+Left/Right roll, Alt+Up/Down resize, Backspace resets. Press again to save."); Lifetime = ((BaseUnityPlugin)this).Config.Bind<int>("5 - The cost", "Disguise time (minutes)", 3, new ConfigDescription("How long a trophy can be worn before it crumbles and is used up. Applies to every trophy, bosses included. Time only passes while it's worn and is saved per trophy.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>())); NeverBreaks = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - The cost", "Trophies never break", false, "Turn on to wear trophies forever. They never crumble."); StaminaRegen = ((BaseUnityPlugin)this).Config.Bind<int>("5 - The cost", "Stamina regen while disguised (%)", 100, new ConfigDescription("Hunching around in a trophy is tiring. 100 = no penalty.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 100), Array.Empty<object>())); MoveSpeed = ((BaseUnityPlugin)this).Config.Bind<int>("5 - The cost", "Move speed while disguised (%)", 100, new ConfigDescription("Slows you down while disguised. 100 = no penalty.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 100), Array.Empty<object>())); ShowStatusIcon = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - The cost", "Show Disguised status icon", true, "Show a Disguised status effect with the trophy's icon and a countdown on the HUD."); FittingRoom = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Keys", "Main menu fitting room", false, "On the character select screen, press the fit key to try on and fit every trophy in the game on your preview character."); ShowOnHead.SettingChanged += delegate { TrophyVisual.RefreshAll(); }; TrophySize.SettingChanged += delegate { TrophyVisual.RefreshAll(); }; MaxTrophySize.SettingChanged += delegate { TrophyVisual.RefreshAll(); }; Facing.SettingChanged += delegate { TrophyVisual.RefreshAll(); }; Tilt.SettingChanged += delegate { TrophyVisual.RefreshAll(); }; ForwardOffset.SettingChanged += delegate { TrophyVisual.RefreshAll(); }; AutoFitHeight.SettingChanged += delegate { TrophyVisual.RefreshAll(); }; FitStore.Load(); _harmony = new Harmony("YouDied.MasterOfDisguise"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Master of Disguise 1.0.0 loaded."); } private void Update() { MenuFitting.Update(); } private void OnGUI() { MenuFitting.OnGUI(); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void Log(string msg) { Plugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)msg); } } internal static void Warn(string msg) { Plugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)msg); } } } internal class TrophyInfo { public string TrophyName; public readonly HashSet<Faction> Factions = new HashSet<Faction>(); public readonly HashSet<string> Creatures = new HashSet<string>(); public readonly List<string> CreatureDisplayNames = new List<string>(); public bool FromBoss; } internal static class TrophyDatabase { private static readonly Dictionary<string, TrophyInfo> s_byTrophy = new Dictionary<string, TrophyInfo>(); private static ZNetScene s_builtFor; private static HashSet<string> s_excluded = new HashSet<string>(); private static string s_excludedRaw; public static void Invalidate() { s_builtFor = null; } public static TrophyInfo Get(string trophyName) { if (string.IsNullOrEmpty(trophyName)) { return null; } EnsureBuilt(); if (!s_byTrophy.TryGetValue(trophyName, out var value)) { return null; } return value; } public static bool IsExcluded(string trophyName) { string text = Plugin.ExcludedTrophies.Value ?? ""; if (text != s_excludedRaw) { s_excludedRaw = text; s_excluded = new HashSet<string>(from s in text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim(), StringComparer.OrdinalIgnoreCase); } return s_excluded.Contains(trophyName); } public static bool IsDisguisableFaction(Faction faction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if ((int)faction <= 1) { if ((int)faction == 0) { goto IL_0018; } if ((int)faction == 1) { return Plugin.AnimalDisguises.Value; } } else if ((int)faction == 8 || faction - 11 <= 1) { goto IL_0018; } return true; IL_0018: return false; } private static void EnsureBuilt() { //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Invalid comparison between Unknown and I4 //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Invalid comparison between Unknown and I4 //IL_0165: Unknown result type (might be due to invalid IL or missing references) ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance == (Object)(object)s_builtFor) { return; } s_builtFor = instance; s_byTrophy.Clear(); foreach (GameObject prefab in instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } Character component = prefab.GetComponent<Character>(); if ((Object)(object)component == (Object)null || component is Player) { continue; } CharacterDrop component2 = prefab.GetComponent<CharacterDrop>(); if ((Object)(object)component2 == (Object)null || component2.m_drops == null) { continue; } foreach (Drop drop in component2.m_drops) { if ((Object)(object)drop?.m_prefab == (Object)null) { continue; } ItemDrop component3 = drop.m_prefab.GetComponent<ItemDrop>(); if (!((Object)(object)component3 == (Object)null) && component3.m_itemData?.m_shared != null && (int)component3.m_itemData.m_shared.m_itemType == 13) { string name = ((Object)drop.m_prefab).name; if (!s_byTrophy.TryGetValue(name, out var value)) { value = new TrophyInfo { TrophyName = name }; s_byTrophy[name] = value; } if ((int)component.m_faction == 8) { value.FromBoss = true; } value.Factions.Add(component.m_faction); if (value.Creatures.Add(((Object)prefab).name) && !string.IsNullOrEmpty(component.m_name)) { value.CreatureDisplayNames.Add(component.m_name); } } } } Plugin.Log($"Mapped {s_byTrophy.Count} trophies to creatures."); LogCoverage(); foreach (TrophyInfo value2 in s_byTrophy.Values) { if (!value2.FromBoss) { continue; } if (BossBiomes.TryGet(value2.TrophyName, out var biome)) { if (!BossBiomes.IsListed(value2.TrophyName)) { Plugin.Log($"Modded boss trophy {value2.TrophyName} isn't listed; treating it as {biome} (Modded boss trophies setting)."); } continue; } Plugin.Warn("Modded boss trophy " + value2.TrophyName + " has no biome, so it's cosmetic only. Add \"" + value2.TrophyName + ":Biome\" to 'Boss trophy biomes' to make it work."); } } private static void LogCoverage() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Expected I4, but got Unknown //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) Dictionary<Faction, List<string>> dictionary = new Dictionary<Faction, List<string>>(); Dictionary<Faction, HashSet<string>> dictionary2 = new Dictionary<Faction, HashSet<string>>(); foreach (TrophyInfo value3 in s_byTrophy.Values) { if (value3.FromBoss) { continue; } foreach (Faction faction in value3.Factions) { if (!dictionary.TryGetValue(faction, out var value)) { value = (dictionary[faction] = new List<string>()); } value.Add(value3.TrophyName); if (!dictionary2.TryGetValue(faction, out var value2)) { value2 = (dictionary2[faction] = new HashSet<string>()); } foreach (string creature in value3.Creatures) { value2.Add(creature); } } } foreach (KeyValuePair<Faction, List<string>> kv in dictionary) { if (IsDisguisableFaction(kv.Key)) { List<string> list2 = kv.Value.Where((string t) => !FitStore.IsSkipped(t) && !IsExcluded(t)).ToList(); List<string> list3 = kv.Value.Where((string t) => FitStore.IsSkipped(t)).ToList(); string text = string.Join(", ", from f in Disguise.AlliesOf((IEnumerable<Faction>)(object)new Faction[1] { (Faction)(int)kv.Key }) where f != kv.Key select f); string text2 = string.Format("Faction {0}{1}: worn as {2}", kv.Key, (text.Length > 0) ? (" (also fools " + text + ")") : "", (list2.Count > 0) ? string.Join(", ", list2) : "NOTHING") + ((list3.Count > 0) ? (" | skipped: " + string.Join(", ", list3)) : "") + " | creatures: " + string.Join(", ", dictionary2[kv.Key]); if (list2.Count == 0) { Plugin.Warn(text2 + " <- no wearable trophy fools this faction"); } } } } public unsafe static string FactionDisplayName(Faction faction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected I4, but got Unknown return (faction - 1) switch { 0 => "animals", 1 => "forest creatures", 2 => "the undead", 3 => "demons", 4 => "mountain creatures", 5 => "sea creatures", 6 => "plains creatures", 8 => "Mistlands creatures", 9 => "the Dvergr", 12 => "Deep North creatures", _ => ((object)(*(Faction*)(&faction))/*cast due to .constrained prefix*/).ToString(), }; } } internal class TrophyVisual : MonoBehaviour { internal static readonly FieldRef<VisEquipment, Transform> HelmetJoint = AccessTools.FieldRefAccess<VisEquipment, Transform>("m_helmet"); internal static readonly FieldRef<VisEquipment, GameObject> HelmetInstance = AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_helmetItemInstance"); internal static readonly FieldRef<VisEquipment, bool> IsPlayer = AccessTools.FieldRefAccess<VisEquipment, bool>("m_isPlayer"); private static readonly MethodInfo CleanupInstance = AccessTools.Method(typeof(VisEquipment), "CleanupInstance", (Type[])null, (Type[])null); private VisEquipment _vis; private Transform _pivot; private GameObject _model; private string _trophy = ""; private string _fitRaw; private Fit _parsedFit = Fit.Default; private AttachPoint _bone; private float _autoScale = 1f; private float _groundRatio = 1f; private float _jointScale = 1f; private Quaternion _charToJoint = Quaternion.identity; private GameObject _hiddenHelmet; internal Fit? LiveFit; private static readonly Dictionary<string, Quaternion> s_restCharToJoint = new Dictionary<string, Quaternion>(); public static TrophyVisual For(VisEquipment vis) { TrophyVisual trophyVisual = ((Component)vis).GetComponent<TrophyVisual>(); if ((Object)(object)trophyVisual == (Object)null) { trophyVisual = ((Component)vis).gameObject.AddComponent<TrophyVisual>(); trophyVisual._vis = vis; } return trophyVisual; } public void Sync(ZDO zdo) { string trophy = (Plugin.ShowOnHead.Value ? zdo.GetString(Disguise.ZTrophy, "") : ""); Fit fit; if (LiveFit.HasValue) { fit = LiveFit.Value; } else { string text = zdo.GetString(Disguise.ZFit, ""); if (text != _fitRaw) { _fitRaw = text; _parsedFit = Fit.Parse(text); } fit = _parsedFit; } Show(trophy, fit); } public void ForceRefit() { _fitRaw = null; } public void SyncLocal(string trophy, Fit fit) { Show(Plugin.ShowOnHead.Value ? (trophy ?? "") : "", fit); } private void Show(string trophy, Fit fit) { if (trophy != _trophy || fit.Bone != _bone) { _trophy = trophy; _bone = fit.Bone; Rebuild(); } ApplyHelmetHiding(); if ((Object)(object)_model != (Object)null) { Apply(fit); } } private void Rebuild() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) Clear(); if (_trophy.Length == 0) { return; } Transform val = FindJoint(_bone); GameObject val2 = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(_trophy) : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return; } _pivot = new GameObject("MoD_TrophyPivot").transform; _pivot.SetParent(val, false); _charToJoint = RestCharToJoint(val); _jointScale = Mathf.Max(val.lossyScale.x, 0.0001f); Transform val3 = val2.transform.Find("attach"); if ((Object)(object)val3 != (Object)null) { _model = Object.Instantiate<GameObject>(((Component)val3).gameObject, _pivot, false); _model.transform.localScale = val3.lossyScale; _groundRatio = GroundRatio(val2, val3); } else { _model = MeshCopy(val2); if ((Object)(object)_model == (Object)null) { Plugin.Warn(_trophy + " has nothing to draw; it can still disguise you."); Object.Destroy((Object)(object)((Component)_pivot).gameObject); _pivot = null; return; } _model.transform.SetParent(_pivot, false); _groundRatio = 1f; } ((Object)_model).name = "MoD_Trophy"; _model.transform.localPosition = Vector3.zero; _model.transform.localRotation = Quaternion.identity; _model.layer = ((Component)val).gameObject.layer; Transform[] componentsInChildren = _model.GetComponentsInChildren<Transform>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Component)componentsInChildren[i]).gameObject.layer = ((Component)val).gameObject.layer; } try { CleanupInstance?.Invoke(CleanupInstance.IsStatic ? null : _vis, new object[1] { _model }); } catch (Exception ex) { Plugin.Warn("Trophy cleanup failed: " + ex.Message); } AutoFit(); _fitRaw = null; } private void AutoFit() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) _pivot.localPosition = Vector3.zero; _pivot.localRotation = BaseRotation(Vector3.zero); _pivot.localScale = Vector3.one; if (!WorldMeshBounds(_model.transform, out var bounds)) { _autoScale = 1f; return; } float num = Mathf.Max(_pivot.lossyScale.x, 0.0001f); float num2 = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z)) / num; float num3 = ((Plugin.MaxTrophySize.Value > 0 && num2 > (float)Plugin.MaxTrophySize.Value / 100f) ? ((float)Plugin.MaxTrophySize.Value / 100f / num2) : 1f); float num4 = num2 * _groundRatio; num3 = ((Plugin.MaxTrophySize.Value > 0 && num4 > (float)Plugin.MaxTrophySize.Value / 100f) ? ((float)Plugin.MaxTrophySize.Value / 100f / num4) : 1f); _autoScale = 1f / num * _groundRatio * num3 * ((float)Plugin.TrophySize.Value / 100f); _model.transform.localPosition = -_pivot.InverseTransformPoint(((Bounds)(ref bounds)).center); } private static bool WorldMeshBounds(Transform root, out Bounds bounds) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) bool any = false; bounds = default(Bounds); MeshFilter[] componentsInChildren = ((Component)root).GetComponentsInChildren<MeshFilter>(true); foreach (MeshFilter val in componentsInChildren) { if ((Object)(object)val.sharedMesh != (Object)null) { Add(ref bounds, ref any, ((Component)val).transform.localToWorldMatrix, val.sharedMesh.bounds); } } SkinnedMeshRenderer[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren2) { if ((Object)(object)val2.sharedMesh != (Object)null) { Add(ref bounds, ref any, ((Component)val2).transform.localToWorldMatrix, val2.sharedMesh.bounds); } } return any; } internal static GameObject MeshCopy(GameObject prefab) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) Transform transform = prefab.transform; GameObject val = new GameObject("MoD_MeshCopy"); val.transform.localScale = transform.lossyScale; Matrix4x4 worldToLocalMatrix = transform.worldToLocalMatrix; int num = 0; MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren<MeshFilter>(true); foreach (MeshFilter val2 in componentsInChildren) { MeshRenderer component = ((Component)val2).GetComponent<MeshRenderer>(); if (!((Object)(object)val2.sharedMesh == (Object)null) && !((Object)(object)component == (Object)null) && ((Renderer)component).enabled && ActiveUpTo(((Component)val2).transform, transform)) { AddPart(val.transform, worldToLocalMatrix * ((Component)val2).transform.localToWorldMatrix, val2.sharedMesh, ((Renderer)component).sharedMaterials); num++; } } SkinnedMeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val3 in componentsInChildr