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 MonsterDisguise v0.2.0
MonsterDisguise.dll
Decompiled 21 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using REPOLib.Modules; using UnityEngine; using UnityEngine.AI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MonsterDisguise")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0+fae141119a7067697e9814571f6fa2d5faa1fa28")] [assembly: AssemblyProduct("MonsterDisguise")] [assembly: AssemblyTitle("MonsterDisguise")] [assembly: AssemblyVersion("0.2.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 MonsterDisguise { public static class ConfigSettings { public static ConfigEntry<int> Price { get; private set; } public static ConfigEntry<float> DrainPerSecond { get; private set; } public static ConfigEntry<float> PuppetScale { get; private set; } public static ConfigEntry<string> ModelYawOverrides { get; private set; } public static void Bind(ConfigFile config) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown Price = config.Bind<int>("Shop", "Price", 8, new ConfigDescription("Shop price in money units (1 unit = $1k on screen).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); DrainPerSecond = config.Bind<float>("Disguise", "DrainPerSecond", 1.33f, new ConfigDescription("Battery drained per second while disguised (100 battery = ~75s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 50f), Array.Empty<object>())); PuppetScale = config.Bind<float>("Disguise", "PuppetScale", 1f, new ConfigDescription("Model scale of the monster puppet.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 3f), Array.Empty<object>())); ModelYawOverrides = config.Bind<string>("Disguise", "ModelYawOverrides", "", new ConfigDescription("Per-monster model yaw correction in degrees (\"ShortId=deg;...\"). Overrides the automatic facing detection.", (AcceptableValueBase)null, Array.Empty<object>())); } } [DefaultExecutionOrder(32766)] public class DisguiseBehavior : MonoBehaviour { private sealed class RemoteDisguise { public GameObject puppet; public GameObject visuals; public Transform root; public Dictionary<Transform, Vector3> snap; public string steamId; public float yawOffset; } private ItemAttributes activeItem; private string activeMonster; private GameObject puppet; private Transform hiddenRoot; private GameObject hiddenVisuals; private string noVisionId; private Dictionary<Transform, Vector3> snapshot; private Camera localCam; private List<Renderer> hiddenItemRenderers; private float puppetYawOffset; private static readonly string[] BeamObjects = new string[4] { "physGrabBeam", "physGrabPointVisual1", "physGrabPointVisual2", "physGrabPointVisualGridObject" }; private readonly Dictionary<int, RemoteDisguise> remotes = new Dictionary<int, RemoteDisguise>(); private readonly Dictionary<Transform, int> hideRefs = new Dictionary<Transform, int>(); private const float DriftFreeze = 0.05f; private float chargeTick; private string lastFailKey; private readonly HashSet<Transform> spawnedRoots = new HashSet<Transform>(); private static string lastYawSpec; private static Dictionary<string, float> yawOverrides; public static DisguiseBehavior Instance { get; private set; } public static PlayerAvatar LocalAvatar { get; private set; } public bool IsDisguised => (Object)(object)activeItem != (Object)null; public string ActiveMonster => activeMonster; private void Awake() { Instance = this; } private void TickFastCharge(float dt) { chargeTick += dt; if (chargeTick < 0.25f) { return; } float num = chargeTick; chargeTick = 0f; if ((Object)(object)RunManager.instance == (Object)null || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } ItemBattery[] array = Object.FindObjectsOfType<ItemBattery>(); foreach (ItemBattery val in array) { if ((Object)(object)val == (Object)null || val.batteryLife >= 100f) { continue; } IList list = GameAccess.Field<IList>(val, "chargerList"); if (list != null && list.Count != 0) { ItemAttributes component = ((Component)val).GetComponent<ItemAttributes>(); if (!((Object)(object)component == (Object)null) && DisguiseItems.IsOurs(((Object)((Component)component).gameObject).name)) { val.batteryLife = Mathf.Min(100f, val.batteryLife + 20f * num); } } } } private static bool InLevel() { if ((Object)(object)LevelGenerator.Instance == (Object)null || (Object)(object)RunManager.instance == (Object)null || !(bool)AccessTools.Field(typeof(RunManager), "runStarted").GetValue(RunManager.instance)) { return false; } Level levelCurrent = RunManager.instance.levelCurrent; if ((Object)(object)levelCurrent != (Object)null) { return levelCurrent.HasEnemies; } return false; } private void Update() { if ((Object)(object)LocalAvatar == (Object)null) { LocalAvatar = PlayerAvatar.instance; } TickFastCharge(Time.deltaTime); if (!InLevel()) { if ((Object)(object)activeItem != (Object)null) { EndDisguise(); } ClearRemotes(); } else { if ((Object)(object)LocalAvatar == (Object)null) { return; } if ((Object)(object)activeItem == (Object)null) { ItemAttributes val = FindHeldActiveItem(); if ((Object)(object)val != (Object)null) { TryStartDisguise(val); } } else { TickActive(); } } } private void FixedUpdate() { if ((Object)(object)activeItem != (Object)null && (Object)(object)puppet != (Object)null) { PinPuppet(PlayerBodyRoot(), puppet, snapshot, isLocal: true, puppetYawOffset); } foreach (KeyValuePair<int, RemoteDisguise> remote in remotes) { PlayerAvatar val = FindAvatar(remote.Key); if (!((Object)(object)val == (Object)null) && !((Object)(object)remote.Value.puppet == (Object)null)) { PinPuppet(((Component)val).transform, remote.Value.puppet, remote.Value.snap, isLocal: false, remote.Value.yawOffset); } } } private static bool BodyGrounded() { try { object obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); if (obj == null) { return true; } MemberInfo memberInfo = (MemberInfo)(((object)AccessTools.Property(obj.GetType(), "CollisionController")) ?? ((object)AccessTools.Field(obj.GetType(), "CollisionController"))); object obj2 = null; if (memberInfo is PropertyInfo propertyInfo) { obj2 = propertyInfo.GetValue(obj); } else if (memberInfo is FieldInfo fieldInfo) { obj2 = fieldInfo.GetValue(obj); } if (obj2 == null) { return true; } MemberInfo memberInfo2 = (MemberInfo)(((object)AccessTools.Property(obj2.GetType(), "Grounded")) ?? ((object)AccessTools.Field(obj2.GetType(), "Grounded"))); if (memberInfo2 is PropertyInfo propertyInfo2) { return (bool)propertyInfo2.GetValue(obj2); } if (memberInfo2 is FieldInfo fieldInfo2) { return (bool)fieldInfo2.GetValue(obj2); } } catch (Exception) { } return true; } private static PhysGrabber LocalGrabber() { try { if ((Object)(object)LocalAvatar == (Object)null) { return null; } object? obj = AccessTools.Field(typeof(PlayerAvatar), "physGrabber")?.GetValue(LocalAvatar); PhysGrabber val = (PhysGrabber)((obj is PhysGrabber) ? obj : null); if ((Object)(object)val != (Object)null) { return val; } return ((Component)LocalAvatar).GetComponentInChildren<PhysGrabber>(); } catch (Exception) { return null; } } private static void HideBeam() { PhysGrabber val = LocalGrabber(); if ((Object)(object)val == (Object)null) { return; } string[] beamObjects = BeamObjects; foreach (string name in beamObjects) { GameObject val2 = GameAccess.Field<GameObject>(val, name); if ((Object)(object)val2 != (Object)null && val2.activeSelf) { val2.SetActive(false); } } } private static Transform PlayerBodyRoot() { object? obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); PlayerController val = (PlayerController)((obj is PlayerController) ? obj : null); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).transform; } private static bool AvatarDead(PlayerAvatar avatar) { if ((Object)(object)avatar == (Object)null) { return true; } if (!(bool)AccessTools.Field(typeof(PlayerAvatar), "deadSet").GetValue(avatar)) { return (bool)AccessTools.Field(typeof(PlayerAvatar), "isDisabled").GetValue(avatar); } return true; } private static ItemAttributes FindHeldActiveItem() { ItemAttributes[] array = Object.FindObjectsOfType<ItemAttributes>(); foreach (ItemAttributes val in array) { if (!((Object)(object)val == (Object)null) && DisguiseItems.IsOurs(((Object)((Component)val).gameObject).name)) { PhysGrabObject val2 = GameAccess.GrabObject(val); ItemToggle val3 = GameAccess.ToggleOf(val); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null) && val3.toggleState && GameAccess.HeldByLocal(val2)) { return val; } } } return null; } private static List<Renderer> HideItemRenderers(GameObject itemGo) { List<Renderer> list = new List<Renderer>(); if ((Object)(object)itemGo == (Object)null) { return list; } Renderer[] componentsInChildren = itemGo.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val != (Object)null && val.enabled) { val.enabled = false; list.Add(val); } } return list; } private void TickActive() { ItemToggle val = GameAccess.ToggleOf(activeItem); if ((Object)(object)activeItem == (Object)null || (Object)(object)val == (Object)null || !val.toggleState || AvatarDead(LocalAvatar)) { EndDisguise(); return; } HideBeam(); if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } ItemBattery component = ((Component)activeItem).GetComponent<ItemBattery>(); if (!((Object)(object)component == (Object)null)) { component.Drain(ConfigSettings.DrainPerSecond.Value); if (component.batteryLife <= 0f) { val.ToggleItem(false, SemiFunc.PhotonViewIDPlayerAvatarLocal()); EndDisguise(); } } } private void FailOnce(string key, string message) { if (!(lastFailKey == key)) { lastFailKey = key; Plugin.Log(message); } } private void TryStartDisguise(ItemAttributes item) { string setupName = DisguiseItems.SetupFor(((Object)((Component)item).gameObject).name); EnemySetup val = DisguiseItems.FindSetup(setupName); if ((Object)(object)val == (Object)null) { FailOnce(((Object)((Component)item).gameObject).name, "Disguise: no enemy setup for " + ((Object)((Component)item).gameObject).name); ForceToggleOff(item); return; } string text = DisguiseItems.ShortId(setupName); Transform val2 = AcquireSourceRoot(text, val); if ((Object)(object)val2 == (Object)null) { FailOnce(((Object)((Component)item).gameObject).name, "Disguise: no live " + text + " in level (host spawns one, clients need one around)"); ForceToggleOff(item); return; } hiddenRoot = val2; ((Component)val2).gameObject.SetActive(false); Transform val3 = PlayerBodyRoot(); if ((Object)(object)val3 == (Object)null) { ReleaseSourceRoot(hiddenRoot); hiddenRoot = null; ForceToggleOff(item); return; } puppet = BuildPuppet(val2, val3); if ((Object)(object)puppet == (Object)null) { ReleaseSourceRoot(hiddenRoot); hiddenRoot = null; ForceToggleOff(item); return; } snapshot = CaptureSnapshot(puppet); puppetYawOffset = ResolveYawOffset(setupName, puppet); hiddenVisuals = HideVisuals(LocalAvatar); hiddenItemRenderers = HideItemRenderers(((Component)item).gameObject); HideBeam(); noVisionId = AddNoVision(LocalAvatar); noVisionId = AddNoVision(LocalAvatar); activeItem = item; activeMonster = setupName; lastFailKey = null; DisguiseNetworking.Instance?.BroadcastState(DisguiseItems.IndexOfSetup(setupName), on: true); Plugin.Log("Disguise started: " + text); } private void EndDisguise() { if ((Object)(object)activeItem == (Object)null) { return; } string text = activeMonster; if ((Object)(object)puppet != (Object)null) { Object.Destroy((Object)(object)puppet); puppet = null; } snapshot = null; if ((Object)(object)hiddenRoot != (Object)null) { ReleaseSourceRoot(hiddenRoot); hiddenRoot = null; } if ((Object)(object)hiddenVisuals != (Object)null) { hiddenVisuals.SetActive(true); hiddenVisuals = null; } if (hiddenItemRenderers != null) { foreach (Renderer hiddenItemRenderer in hiddenItemRenderers) { if ((Object)(object)hiddenItemRenderer != (Object)null) { hiddenItemRenderer.enabled = true; } } hiddenItemRenderers = null; } if (noVisionId != null) { RemoveNoVision(noVisionId); noVisionId = null; } activeItem = null; activeMonster = null; int setupIdx = ((text != null) ? DisguiseItems.IndexOfSetup(text) : (-1)); DisguiseNetworking.Instance?.BroadcastState(setupIdx, on: false); Plugin.Log("Disguise ended"); } private static void ForceToggleOff(ItemAttributes item) { ItemToggle val = GameAccess.ToggleOf(item); if ((Object)(object)val != (Object)null && val.toggleState) { val.ToggleItem(false, SemiFunc.PhotonViewIDPlayerAvatarLocal()); } } private Transform AcquireSourceRoot(string shortId, EnemySetup setup) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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_0135: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) string text = DisguiseItems.Norm(shortId); Enemy val = null; float num = float.MaxValue; Transform val2 = PlayerBodyRoot(); Vector3 val3 = (((Object)(object)val2 != (Object)null) ? val2.position : Vector3.zero); Enemy[] array = Object.FindObjectsOfType<Enemy>(); foreach (Enemy val4 in array) { if ((Object)(object)val4 == (Object)null) { continue; } string text2 = DisguiseItems.Norm(((object)val4).GetType().Name); if (!text2.Contains(text) && !text.Contains(text2)) { continue; } Transform val5 = RootOf(val4); if (!((Object)(object)val5 == (Object)null)) { float num2 = (((Object)(object)val2 != (Object)null) ? Vector3.Distance(val3, val5.position) : 0f); if (num2 < num) { num = num2; val = val4; } } } if ((Object)(object)val != (Object)null) { Transform val6 = RootOf(val); hideRefs[val6] = ((!hideRefs.TryGetValue(val6, out var value)) ? 1 : (value + 1)); return val6; } if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)setup == (Object)null) { return null; } Vector3 val7 = val3 + Vector3.forward * 3f + Vector3.up * 1.5f; List<EnemyParent> list = null; try { list = Enemies.SpawnEnemy(setup, val7, Quaternion.identity, false); } catch (Exception ex) { Plugin.Log("Disguise spawn failed: " + ex.Message); return null; } Transform val8 = null; if (list != null) { foreach (EnemyParent item in list) { if (!((Object)(object)item == (Object)null)) { if ((Object)(object)val8 == (Object)null) { val8 = ((Component)item).transform; } else { RemoveExtra(item); } } } } if ((Object)(object)val8 == (Object)null) { return null; } hideRefs[val8] = ((!hideRefs.TryGetValue(val8, out var value2)) ? 1 : (value2 + 1)); spawnedRoots.Add(val8); Plugin.Log("Disguise: spawned " + shortId + " (host)"); return val8; } private void ReleaseSourceRoot(Transform root) { if ((Object)(object)root == (Object)null) { return; } if (hideRefs.TryGetValue(root, out var value)) { value--; if (value <= 0) { hideRefs.Remove(root); if (spawnedRoots.Remove(root)) { DespawnRoot(root); } else { ((Component)root).gameObject.SetActive(true); } } else { hideRefs[root] = value; } } else if (spawnedRoots.Remove(root)) { DespawnRoot(root); } else { ((Component)root).gameObject.SetActive(true); } } private static void DespawnRoot(Transform root) { if ((Object)(object)root == (Object)null) { return; } EnemyParent component = ((Component)root).GetComponent<EnemyParent>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)((Component)root).gameObject); return; } try { ((Component)root).gameObject.SetActive(true); component.Despawn(); } catch (Exception ex) { Plugin.Log("Disguise despawn failed: " + ex.Message); RemoveExtra(component); } } private static Transform RootOf(Enemy enemy) { if ((Object)(object)enemy == (Object)null) { return null; } EnemyParent value = Traverse.Create((object)enemy).Field("EnemyParent").GetValue<EnemyParent>(); if (!((Object)(object)value != (Object)null)) { return ((Component)enemy).transform.root; } return ((Component)value).transform; } private static void RemoveExtra(EnemyParent parent) { if (!((Object)(object)parent == (Object)null)) { PhotonView val = ((Component)parent).GetComponent<PhotonView>() ?? ((Component)parent).GetComponentInChildren<PhotonView>(); if ((Object)(object)val != (Object)null && PhotonNetwork.CurrentRoom != null && PhotonNetwork.IsMasterClient) { PhotonNetwork.Destroy(val); } else { Object.Destroy((Object)(object)((Component)parent).gameObject); } } } private GameObject BuildPuppet(Transform source, Transform body) { //IL_0150: 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_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) bool activeInHierarchy = ((Component)source).gameObject.activeInHierarchy; ((Component)source).gameObject.SetActive(true); GameObject val = Object.Instantiate<GameObject>(((Component)source).gameObject); if (!activeInHierarchy) { ((Component)source).gameObject.SetActive(false); } MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null) { ((Behaviour)val2).enabled = false; } } NavMeshAgent[] componentsInChildren2 = val.GetComponentsInChildren<NavMeshAgent>(true); foreach (NavMeshAgent val3 in componentsInChildren2) { if ((Object)(object)val3 != (Object)null) { ((Behaviour)val3).enabled = false; } } EnemyRigidbody[] componentsInChildren3 = val.GetComponentsInChildren<EnemyRigidbody>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.Destroy((Object)(object)componentsInChildren3[i]); } EnemyParent[] componentsInChildren4 = val.GetComponentsInChildren<EnemyParent>(true); for (int i = 0; i < componentsInChildren4.Length; i++) { Object.Destroy((Object)(object)componentsInChildren4[i]); } PhotonView[] componentsInChildren5 = val.GetComponentsInChildren<PhotonView>(true); for (int i = 0; i < componentsInChildren5.Length; i++) { Object.Destroy((Object)(object)componentsInChildren5[i]); } Rigidbody[] componentsInChildren6 = val.GetComponentsInChildren<Rigidbody>(true); for (int i = 0; i < componentsInChildren6.Length; i++) { componentsInChildren6[i].isKinematic = true; } Collider[] componentsInChildren7 = val.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren7.Length; i++) { componentsInChildren7[i].enabled = false; } ((Object)val).name = "DisguisePuppet"; val.transform.SetParent(body, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one * ConfigSettings.PuppetScale.Value; if (!val.activeSelf) { val.SetActive(true); } Plugin.Log("Puppet built under " + ((Object)body).name); return val; } private static float ResolveYawOffset(string setupName, GameObject puppetRoot) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: 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) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) string value = ConfigSettings.ModelYawOverrides.Value; if (value != lastYawSpec) { lastYawSpec = value; yawOverrides = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); string[] array = value.Split(';'); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split('='); if (array2.Length == 2 && float.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { yawOverrides[array2[0].Trim()] = result; } } } string text = DisguiseItems.ShortId(setupName); if (yawOverrides.TryGetValue(text, out var value2) || yawOverrides.TryGetValue(setupName ?? "", out value2)) { Plugin.Log($"Disguise yaw for {text}: {value2} (config)"); return value2; } float num = 0f; try { Bounds val = default(Bounds); ((Bounds)(ref val))..ctor(puppetRoot.transform.position, Vector3.zero); bool flag = false; MeshRenderer[] componentsInChildren = puppetRoot.GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && ((Renderer)val2).enabled) { ((Bounds)(ref val)).Encapsulate(((Renderer)val2).bounds); flag = true; } } SkinnedMeshRenderer[] componentsInChildren2 = puppetRoot.GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val3 in componentsInChildren2) { if ((Object)(object)val3 != (Object)null && ((Renderer)val3).enabled) { ((Bounds)(ref val)).Encapsulate(((Renderer)val3).bounds); flag = true; } } if (flag) { Vector3 val4 = puppetRoot.transform.InverseTransformPoint(((Bounds)(ref val)).center); val4.y = 0f; if (((Vector3)(ref val4)).magnitude >= 0.05f) { num = Mathf.Round(Vector3.SignedAngle(Vector3.forward, ((Vector3)(ref val4)).normalized, Vector3.up) / 90f) * 90f; } } } catch (Exception) { } Plugin.Log($"Disguise yaw for {text}: {num} (auto)"); return num; } private static Dictionary<Transform, Vector3> CaptureSnapshot(GameObject root) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) Dictionary<Transform, Vector3> dictionary = new Dictionary<Transform, Vector3>(); if ((Object)(object)root == (Object)null) { return dictionary; } Transform[] componentsInChildren = root.GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)root.transform)) { dictionary[val] = val.localPosition; } } return dictionary; } private void PinPuppet(Transform body, GameObject target, Dictionary<Transform, Vector3> snap, bool isLocal, float yawOffset) { //IL_0034: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_0075: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: 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) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)body == (Object)null || (Object)(object)target == (Object)null) { return; } if ((Object)(object)target.transform.parent != (Object)(object)body) { target.transform.SetParent(body, false); } float y = body.eulerAngles.y; if (isLocal) { if ((Object)(object)localCam == (Object)null) { localCam = Camera.main; } if ((Object)(object)localCam != (Object)null) { y = ((Component)localCam).transform.eulerAngles.y; } } Quaternion val = Quaternion.Euler(0f, y + yawOffset, 0f); if (Quaternion.Angle(target.transform.rotation, val) > 0.5f) { target.transform.rotation = val; } float num = GroundBelow(body.position, body, target.transform); Vector3 val2 = (Vector3)((isLocal && !BodyGrounded()) ? Vector3.zero : new Vector3(0f, num - body.position.y, 0f)); Vector3 val3 = target.transform.localPosition - val2; if (((Vector3)(ref val3)).sqrMagnitude > 0.0001f) { target.transform.localPosition = val2; } if (snap != null) { float num2 = 0.0025000002f; foreach (KeyValuePair<Transform, Vector3> item in snap) { if (!((Object)(object)item.Key == (Object)null)) { val3 = item.Key.localPosition - item.Value; if (((Vector3)(ref val3)).sqrMagnitude > num2) { item.Key.localPosition = item.Value; } } } } DriveWalkAnim(target, body); } private static void DriveWalkAnim(GameObject target, Transform body) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_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) try { Animator componentInChildren = target.GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren == (Object)null) { return; } bool flag = false; AnimatorControllerParameter[] parameters = componentInChildren.parameters; for (int i = 0; i < parameters.Length; i++) { if (parameters[i].name == "Moving") { flag = true; break; } } if (flag) { Rigidbody componentInParent = ((Component)body).GetComponentInParent<Rigidbody>(); float num = 0f; if ((Object)(object)componentInParent != (Object)null) { Vector3 velocity = componentInParent.velocity; Vector3 val = new Vector3(velocity.x, 0f, velocity.z); num = ((Vector3)(ref val)).magnitude; } componentInChildren.SetBool("Moving", num > 0.2f); } } catch (Exception) { } } private float GroundBelow(Vector3 from, Transform bodyOf, Transform puppet) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_0074: 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) RaycastHit[] array = Physics.RaycastAll(from + Vector3.up * 2f, Vector3.down, 25f); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int num = 0; num < array2.Length; num++) { RaycastHit val = array2[num]; if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && !(((RaycastHit)(ref val)).point.y > from.y + 0.05f) && (!((Object)(object)puppet != (Object)null) || !((Component)((RaycastHit)(ref val)).collider).transform.IsChildOf(puppet)) && (!((Object)(object)bodyOf != (Object)null) || !((Object)(object)((Component)((RaycastHit)(ref val)).collider).transform.root == (Object)(object)bodyOf.root))) { return ((RaycastHit)(ref val)).point.y; } } return from.y; } private static GameObject HideVisuals(PlayerAvatar avatar) { if ((Object)(object)avatar == (Object)null) { return null; } object? obj = AccessTools.Field(typeof(PlayerAvatar), "playerAvatarVisuals")?.GetValue(avatar); PlayerAvatarVisuals val = (PlayerAvatarVisuals)((obj is PlayerAvatarVisuals) ? obj : null); if ((Object)(object)val == (Object)null) { return null; } ((Component)val).gameObject.SetActive(false); return ((Component)val).gameObject; } private static string AddNoVision(PlayerAvatar avatar) { if ((Object)(object)avatar == (Object)null || (Object)(object)EnemyDirector.instance == (Object)null) { return null; } string text = AccessTools.Field(typeof(PlayerAvatar), "steamID")?.GetValue(avatar) as string; if (string.IsNullOrEmpty(text)) { return null; } if (AccessTools.Field(typeof(EnemyDirector), "debugNoVision")?.GetValue(EnemyDirector.instance) is List<string> list && !list.Contains(text)) { list.Add(text); return text; } return null; } private static void RemoveNoVision(string steamId) { if (steamId != null && !((Object)(object)EnemyDirector.instance == (Object)null)) { (AccessTools.Field(typeof(EnemyDirector), "debugNoVision")?.GetValue(EnemyDirector.instance) as List<string>)?.Remove(steamId); } } private static PlayerAvatar FindAvatar(int actorNr) { PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>(true); foreach (PlayerAvatar val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val.photonView != (Object)null && val.photonView.OwnerActorNr == actorNr) { return val; } } return null; } public void ApplyRemote(int actorNr, int setupIdx, bool on) { if (on) { if (remotes.ContainsKey(actorNr)) { return; } string setupName = DisguiseItems.SetupByIndex(setupIdx); if ((Object)(object)DisguiseItems.FindSetup(setupName) == (Object)null) { return; } PlayerAvatar val = FindAvatar(actorNr); if ((Object)(object)val == (Object)null) { return; } Transform val2 = AcquireSourceRoot(DisguiseItems.ShortId(setupName), null); if ((Object)(object)val2 == (Object)null) { Plugin.Log("Remote disguise: no live " + DisguiseItems.ShortId(setupName) + " around"); return; } ((Component)val2).gameObject.SetActive(false); GameObject val3 = BuildPuppet(val2, ((Component)val).transform); if ((Object)(object)val3 == (Object)null) { ReleaseSourceRoot(val2); return; } remotes[actorNr] = new RemoteDisguise { puppet = val3, visuals = HideVisuals(val), root = val2, snap = CaptureSnapshot(val3), steamId = AddNoVision(val), yawOffset = ResolveYawOffset(setupName, val3) }; } else { ClearRemote(actorNr); } } public void ClearRemote(int actorNr) { if (remotes.TryGetValue(actorNr, out var value)) { remotes.Remove(actorNr); if ((Object)(object)value.puppet != (Object)null) { Object.Destroy((Object)(object)value.puppet); } if ((Object)(object)value.root != (Object)null) { ReleaseSourceRoot(value.root); } if ((Object)(object)value.visuals != (Object)null) { value.visuals.SetActive(true); } if (value.steamId != null) { RemoveNoVision(value.steamId); } } } private void ClearRemotes() { foreach (int item in new List<int>(remotes.Keys)) { ClearRemote(item); } } } internal static class DisguiseItems { public const string Prefix = "Item Disguise "; private static bool registered; private static readonly Dictionary<string, string> itemToSetup = new Dictionary<string, string>(); private static readonly List<string> setupNames = new List<string>(); private static GameObject depot; private static readonly string[] prefer = new string[8] { "Tracker", "Baton", "Drone", "Orb", "Gun", "Walkie", "Mine", "Grenade" }; private static FieldInfo itemPrefabField; public static IReadOnlyList<string> SetupNames => setupNames; public static bool IsOurs(string goName) { return goName?.StartsWith("Item Disguise ") ?? false; } public static string SetupFor(string goName) { if (goName == null) { return null; } if (itemToSetup.TryGetValue(goName, out var value)) { return value; } string text = StripClone(goName); if (itemToSetup.TryGetValue(text, out value)) { return value; } if (text.StartsWith("Item Disguise ")) { string text2 = text.Substring("Item Disguise ".Length); foreach (KeyValuePair<string, string> item in itemToSetup) { if (ShortId(item.Value) == text2) { return item.Value; } } } return null; } public static string StripClone(string goName) { if (goName == null || !goName.EndsWith("(Clone)")) { return goName; } return goName.Substring(0, goName.Length - "(Clone)".Length); } public static int IndexOfSetup(string setupName) { return setupNames.IndexOf(setupName); } public static string SetupByIndex(int index) { if (index < 0 || index >= setupNames.Count) { return null; } return setupNames[index]; } public static EnemySetup FindSetup(string setupName) { if (setupName == null) { return null; } foreach (EnemySetup allEnemy in Enemies.AllEnemies) { if ((Object)(object)allEnemy != (Object)null && ((Object)allEnemy).name == setupName) { return allEnemy; } } return null; } public static string ShortId(string setupName) { if (string.IsNullOrEmpty(setupName)) { return "?"; } int num = setupName.LastIndexOf('-'); string text = ((num >= 0) ? setupName.Substring(num + 1) : setupName).Trim(); if (!string.IsNullOrEmpty(text)) { return text; } return setupName; } public static string Norm(string s) { if (string.IsNullOrEmpty(s)) { return ""; } List<char> list = new List<char>(s.Length); string text = s.ToLowerInvariant(); foreach (char c in text) { if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) { list.Add(c); } } return new string(list.ToArray()); } public static void RegisterAll() { if (registered) { return; } StatsManager instance = StatsManager.instance; if ((Object)(object)instance == (Object)null || instance.itemDictionary == null) { return; } ItemAttributes val = PickBase(instance); if ((Object)(object)val == (Object)null) { Plugin.Log("Disguise items: no base toggle+battery item found, retry later"); return; } int num = 0; foreach (EnemySetup allEnemy in Enemies.AllEnemies) { if (!((Object)(object)allEnemy == (Object)null) && !string.IsNullOrEmpty(((Object)allEnemy).name) && RegisterOne(val, allEnemy)) { num++; } } registered = num > 0; Plugin.Log($"Disguise items registered: {num} (base={((Object)((Component)val).gameObject).name})"); } private static void EnsureDepot() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)depot != (Object)null)) { depot = new GameObject("MonsterDisguise Depot"); Object.DontDestroyOnLoad((Object)(object)depot); depot.SetActive(false); } } private static bool RegisterOne(ItemAttributes baseAttr, EnemySetup setup) { string text = ShortId(((Object)setup).name); string text2 = "Item Disguise " + text; if (StatsManager.instance.itemDictionary.ContainsKey(text2)) { itemToSetup[text2] = ((Object)setup).name; if (!setupNames.Contains(((Object)setup).name)) { setupNames.Add(((Object)setup).name); } return true; } GameObject val = Object.Instantiate<GameObject>(((Component)baseAttr).gameObject); ((Object)val).name = text2; Object.DontDestroyOnLoad((Object)(object)val); ItemAttributes component = val.GetComponent<ItemAttributes>(); if ((Object)(object)component == (Object)null || (Object)(object)component.item == (Object)null) { Object.Destroy((Object)(object)val); return false; } component.item = Object.Instantiate<Item>(component.item); ((Object)component.item).name = text2; component.item.itemName = text + " Disguise"; component.item.itemNameLocalized = null; GameAccess.SetItemName(component, text2); GameAccess.SetItemValue(component, ConfigSettings.Price.Value); ItemBattery val2 = val.GetComponent<ItemBattery>(); if ((Object)(object)val2 == (Object)null) { val2 = val.AddComponent<ItemBattery>(); } val2.batteryBars = 4; val2.isUnchargable = false; GameAccess.SetField(val2, "batteryDrainRate", 0f); GameAccess.SetField(val2, "autoDrain", false); ItemToggle val3 = val.GetComponent<ItemToggle>(); if ((Object)(object)val3 == (Object)null) { val3 = val.AddComponent<ItemToggle>(); } GameAccess.SetField(val3, "disabled", false); val3.toggleState = false; EnsureDepot(); val.transform.SetParent(depot.transform, false); val.SetActive(true); try { if (Items.RegisterItem(component) == null) { Object.Destroy((Object)(object)val); return false; } } catch (Exception ex) { Plugin.Log("RegisterItem failed for " + text2 + ": " + ex.Message); Object.Destroy((Object)(object)val); return false; } itemToSetup[text2] = ((Object)setup).name; if (!setupNames.Contains(((Object)setup).name)) { setupNames.Add(((Object)setup).name); } return true; } private static ItemAttributes PickBase(StatsManager stats) { ItemAttributes val = null; ItemAttributes val2 = null; Dictionary<string, ItemAttributes> dictionary = new Dictionary<string, ItemAttributes>(); foreach (Item value2 in stats.itemDictionary.Values) { if ((Object)(object)value2 == (Object)null) { continue; } GameObject val3 = PrefabOf(value2); if ((Object)(object)val3 == (Object)null) { continue; } ItemAttributes component = val3.GetComponent<ItemAttributes>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)((Component)component).GetComponent<PhysGrabObject>() == (Object)null)) { bool flag = (Object)(object)((Component)component).GetComponent<ItemToggle>() != (Object)null; bool flag2 = (Object)(object)((Component)component).GetComponent<ItemBattery>() != (Object)null; if (flag && flag2) { dictionary[((Object)val3).name] = component; val = component; } else if (flag && (Object)(object)val2 == (Object)null) { val2 = component; } } } string[] array = prefer; foreach (string value in array) { foreach (KeyValuePair<string, ItemAttributes> item in dictionary) { if (item.Key.Contains(value)) { return item.Value; } } } return val ?? val2; } private static GameObject PrefabOf(Item item) { try { if (itemPrefabField == null) { itemPrefabField = typeof(Item).GetField("prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } object obj = itemPrefabField?.GetValue(item); if (obj == null) { return null; } Type type = obj.GetType(); object? obj2 = type.GetProperty("Prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj); GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null); if ((Object)(object)val != (Object)null) { return val; } string text = type.GetProperty("ResourcePath", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj) as string; return string.IsNullOrEmpty(text) ? null : Resources.Load<GameObject>(text); } catch (Exception) { return null; } } } public class DisguiseNetworking : MonoBehaviour, IOnEventCallback { private const byte StateEvent = 81; private const byte ConfigEvent = 82; private const float ConfigBroadcastInterval = 10f; private bool registered; private float nextConfigBroadcast; public static DisguiseNetworking Instance { get; private set; } private void Awake() { Instance = this; } private void OnDisable() { Unregister(); } private static bool GameReady() { if ((Object)(object)RunManager.instance != (Object)null && (Object)(object)GameDirector.instance != (Object)null) { return SemiFunc.RunIsLevel(); } return false; } private void EnsureRegistered() { if (!registered && PhotonNetwork.InRoom) { PhotonNetwork.AddCallbackTarget((object)this); registered = true; } } private void Unregister() { if (registered) { PhotonNetwork.RemoveCallbackTarget((object)this); registered = false; } } private void Update() { if (!GameReady()) { Unregister(); return; } EnsureRegistered(); if (PhotonNetwork.IsMasterClient && Time.time >= nextConfigBroadcast) { nextConfigBroadcast = Time.time + 10f; BroadcastConfig(); } } public void BroadcastState(int setupIdx, bool on) { //IL_003e: 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_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) //IL_0054: Expected O, but got Unknown if (PhotonNetwork.InRoom) { int num = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1)); if (num >= 0) { PhotonNetwork.RaiseEvent((byte)81, (object)new int[4] { 81, num, setupIdx, on ? 1 : 0 }, new RaiseEventOptions { Receivers = (ReceiverGroup)1 }, SendOptions.SendReliable); } } } private static void BroadcastConfig() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown if (PhotonNetwork.InRoom) { PhotonNetwork.RaiseEvent((byte)82, (object)new int[1] { Mathf.RoundToInt(ConfigSettings.DrainPerSecond.Value * 100f) }, new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable); } } public void OnEvent(EventData photonEvent) { if (photonEvent != null && photonEvent.Code == 81 && photonEvent.CustomData is int[] array && array.Length >= 4) { int num = array[1]; int num2 = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1)); if (num != num2) { DisguiseBehavior.Instance?.ApplyRemote(num, array[2], array[3] == 1); } } } } internal static class GameAccess { public static T Field<T>(object target, string name) { if (target == null) { return default(T); } return (T)(AccessTools.Field(target.GetType(), name)?.GetValue(target)); } public static void SetField(object target, string name, object value) { if (target != null) { AccessTools.Field(target.GetType(), name)?.SetValue(target, value); } } public static string ItemName(ItemAttributes attr) { return Field<string>(attr, "itemName"); } public static void SetItemName(ItemAttributes attr, string value) { SetField(attr, "itemName", value); } public static int ItemValue(ItemAttributes attr) { return Field<int>(attr, "value"); } public static void SetItemValue(ItemAttributes attr, int value) { SetField(attr, "value", value); } public static PhysGrabObject GrabObject(ItemAttributes attr) { PhysGrabObject obj = Field<PhysGrabObject>(attr, "physGrabObject"); if (obj == null) { if (!((Object)(object)attr != (Object)null)) { return null; } obj = ((Component)attr).GetComponent<PhysGrabObject>(); } return obj; } public static bool HeldByLocal(PhysGrabObject grab) { if ((Object)(object)grab != (Object)null) { return Field<bool>(grab, "heldByLocalPlayer"); } return false; } public static ItemToggle ToggleOf(ItemAttributes attr) { ItemToggle obj = Field<ItemToggle>(attr, "itemToggle"); if (obj == null) { if (!((Object)(object)attr != (Object)null)) { return null; } obj = ((Component)attr).GetComponent<ItemToggle>(); } return obj; } } [BepInPlugin("yo.MonsterDisguise", "MonsterDisguise", "0.2.0")] [BepInProcess("REPO.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private static ManualLogSource logSource; public static Plugin Instance { get; private set; } private void Awake() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) Instance = this; ConfigSettings.Bind(((BaseUnityPlugin)this).Config); logSource = Logger.CreateLogSource("MonsterDisguise"); new Harmony("yo.MonsterDisguise").PatchAll(); GameObject val = new GameObject("MonsterDisguise"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent<DisguiseBehavior>(); val.AddComponent<DisguiseNetworking>(); Log("MonsterDisguise v0.2.0 loaded"); } public static void Log(string message) { logSource.LogInfo((object)message); } } public static class PluginInfo { public const string PLUGIN_GUID = "yo.MonsterDisguise"; public const string PLUGIN_NAME = "MonsterDisguise"; public const string PLUGIN_VERSION = "0.2.0"; } } namespace MonsterDisguise.Patches { [HarmonyPatch(typeof(StatsManager), "LoadItemsFromFolder")] public static class ShopPatch { [HarmonyPostfix] public static void RegisterDisguiseItems() { DisguiseItems.RegisterAll(); } } }