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 MaskedPlus v1.0.0
MaskedPlus.dll
Decompiled 5 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [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("MaskedPlus")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MaskedPlus")] [assembly: AssemblyTitle("MaskedPlus")] [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 MaskedPlus { internal static class MaskedPatches { private static readonly FieldRef<MaskedPlayerEnemy, PlayerControllerB> lastPlayerKilled = AccessTools.FieldRefAccess<MaskedPlayerEnemy, PlayerControllerB>("lastPlayerKilled"); private static readonly HashSet<int> handled = new HashSet<int>(); private static Item comedyItem; private static Item tragedyItem; [HarmonyPatch(typeof(MaskedPlayerEnemy), "KillEnemy")] [HarmonyPostfix] private static void OnKilled(MaskedPlayerEnemy __instance, bool destroy) { if (destroy || (Object)(object)__instance == (Object)null || !handled.Add(((Object)__instance).GetInstanceID())) { return; } try { bool flag = WoreComedy(__instance); HideMask(__instance); bool flag2 = ReturnBody(__instance); if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer) { DropMask(__instance, flag); } Plugin.Log.LogInfo((object)("Masked died: dropped a " + (flag ? "Comedy" : "Tragedy") + " mask" + (flag2 ? ", player body returned" : "") + ".")); } catch (Exception ex) { Plugin.Log.LogError((object)("Masked death: " + ex)); } } private static bool WoreComedy(MaskedPlayerEnemy m) { GameObject[] maskTypes = m.maskTypes; if (maskTypes != null && maskTypes.Length > 1) { if ((Object)(object)maskTypes[0] != (Object)null && maskTypes[0].activeSelf) { return true; } if ((Object)(object)maskTypes[1] != (Object)null && maskTypes[1].activeSelf) { return false; } } return m.maskTypeIndex == 0; } private static void HideMask(MaskedPlayerEnemy m) { if (m.maskTypes != null) { GameObject[] maskTypes = m.maskTypes; foreach (GameObject val in maskTypes) { if ((Object)(object)val != (Object)null) { val.SetActive(false); } } } if (m.maskEyesGlow != null) { MeshRenderer[] maskEyesGlow = m.maskEyesGlow; foreach (MeshRenderer val2 in maskEyesGlow) { if ((Object)(object)val2 != (Object)null) { ((Renderer)val2).enabled = false; } } } if ((Object)(object)m.maskEyesGlowLight != (Object)null) { ((Behaviour)m.maskEyesGlowLight).enabled = false; } } private static void DropMask(MaskedPlayerEnemy m, bool comedy) { //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_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_004d: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) Item val = FindMask(comedy); if ((Object)(object)val == (Object)null || (Object)(object)val.spawnPrefab == (Object)null) { Plugin.Log.LogWarning((object)"Mask item not found, nothing dropped."); return; } Vector3 val2 = ((Component)m).transform.position + Vector3.up * 1.8f; Transform val3 = (((Object)(object)RoundManager.Instance != (Object)null) ? RoundManager.Instance.spawnedScrapContainer : null); GameObject obj = Object.Instantiate<GameObject>(val.spawnPrefab, val2, Quaternion.identity, val3); GrabbableObject component = obj.GetComponent<GrabbableObject>(); component.fallTime = 0f; component.isInFactory = !((EnemyAI)m).isOutside; int num = Value(val); component.SetScrapValue(num); NetworkObject component2 = obj.GetComponent<NetworkObject>(); component2.Spawn(false); RoundManager.Instance.SyncScrapValuesClientRpc((NetworkObjectReference[])(object)new NetworkObjectReference[1] { NetworkObjectReference.op_Implicit(component2) }, new int[1] { num }); } private static int Value(Item item) { if (Plugin.ValueMode.Value == MaskValue.Custom) { return Mathf.Max(0, Plugin.CustomValue.Value); } float num = (((Object)(object)RoundManager.Instance != (Object)null) ? RoundManager.Instance.scrapValueMultiplier : 0.4f); int num2 = Mathf.Min(item.minValue, item.maxValue); int num3 = Mathf.Max(item.minValue, item.maxValue); return Mathf.Max(1, (int)((float)Random.Range(num2, num3) * num)); } private static Item FindMask(bool comedy) { if (comedy && (Object)(object)comedyItem != (Object)null) { return comedyItem; } if (!comedy && (Object)(object)tragedyItem != (Object)null) { return tragedyItem; } List<Item> itemsList = StartOfRound.Instance.allItemsList.itemsList; string key = (comedy ? "Comedy" : "Tragedy"); Item result = ((IEnumerable<Item>)itemsList).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((Object)i).name == key + "Mask")) ?? ((IEnumerable<Item>)itemsList).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && i.itemName != null && i.itemName.IndexOf(key, StringComparison.OrdinalIgnoreCase) >= 0)); if (comedy) { comedyItem = result; } else { tragedyItem = result; } return result; } private static bool ReturnBody(MaskedPlayerEnemy m) { //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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB mimickingPlayer = m.mimickingPlayer; if ((Object)(object)mimickingPlayer == (Object)null || !mimickingPlayer.isPlayerDead || (Object)(object)mimickingPlayer.deadBody == (Object)null || !mimickingPlayer.deadBody.deactivated) { return false; } DeadBodyInfo deadBody = mimickingPlayer.deadBody; if ((Object)(object)RoundManager.Instance != (Object)null) { foreach (EnemyAI spawnedEnemy in RoundManager.Instance.SpawnedEnemies) { MaskedPlayerEnemy val = (MaskedPlayerEnemy)(object)((spawnedEnemy is MaskedPlayerEnemy) ? spawnedEnemy : null); if (val != null && (Object)(object)lastPlayerKilled.Invoke(val) == (Object)(object)mimickingPlayer) { lastPlayerKilled.Invoke(val) = null; } } } ((Component)deadBody).gameObject.SetActive(true); deadBody.deactivated = false; deadBody.attachedTo = null; deadBody.attachedLimb = null; deadBody.secondaryAttachedTo = null; deadBody.secondaryAttachedLimb = null; deadBody.matchPositionExactly = false; deadBody.SetBodyPartsKinematic(false); deadBody.SetRagdollPositionSafely(((Component)m).transform.position + Vector3.up * 0.5f, true); Transform[] componentsInChildren = ((Component)deadBody).GetComponentsInChildren<Transform>(true); foreach (Transform val2 in componentsInChildren) { if (((Object)val2).name.StartsWith("HeadMask")) { ((Component)val2).gameObject.SetActive(false); } } Renderer[] componentsInChildren2 = ((Component)m).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].enabled = false; } Collider[] componentsInChildren3 = ((Component)m).GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { componentsInChildren3[i].enabled = false; } ScanNodeProperties[] componentsInChildren4 = ((Component)m).GetComponentsInChildren<ScanNodeProperties>(true); foreach (ScanNodeProperties val3 in componentsInChildren4) { if ((Object)(object)((Component)val3).gameObject != (Object)(object)((Component)m).gameObject) { ((Component)val3).gameObject.SetActive(false); } } return true; } } internal static class MaskHide { private static readonly FieldRef<HauntedMaskItem, bool> maskOn = AccessTools.FieldRefAccess<HauntedMaskItem, bool>("maskOn"); private static readonly FieldRef<HauntedMaskItem, bool> finishedAttaching = AccessTools.FieldRefAccess<HauntedMaskItem, bool>("finishedAttaching"); private static readonly Dictionary<(EnemyAI, PlayerControllerB), float> revealed = new Dictionary<(EnemyAI, PlayerControllerB), float>(); private static bool MaskUp(PlayerControllerB p) { if ((Object)(object)p != (Object)null && !p.isPlayerDead) { GrabbableObject currentlyHeldObjectServer = p.currentlyHeldObjectServer; HauntedMaskItem val = (HauntedMaskItem)(object)((currentlyHeldObjectServer is HauntedMaskItem) ? currentlyHeldObjectServer : null); if (val != null && maskOn.Invoke(val)) { return !finishedAttaching.Invoke(val); } } return false; } internal static bool Hidden(EnemyAI enemy, PlayerControllerB p) { if (!Plugin.HideEnabled.Value || (Object)(object)enemy == (Object)null || !MaskUp(p)) { return false; } if (revealed.TryGetValue((enemy, p), out var value)) { if (Time.time < value) { return false; } revealed.Remove((enemy, p)); } return true; } [HarmonyPatch(typeof(EnemyAICollisionDetect), "OnTriggerStay")] [HarmonyPrefix] private static void Touch(EnemyAICollisionDetect __instance, Collider other) { if (!Plugin.HideEnabled.Value || (Object)(object)other == (Object)null || (Object)(object)__instance.mainScript == (Object)null || !((Component)other).CompareTag("Player")) { return; } PlayerControllerB component = ((Component)other).GetComponent<PlayerControllerB>(); if (MaskUp(component)) { if (revealed.Count > 64) { revealed.Clear(); } revealed[(__instance.mainScript, component)] = Time.time + Mathf.Max(0f, Plugin.RevealSeconds.Value); } } [HarmonyPatch(typeof(EnemyAI), "PlayerIsTargetable")] [HarmonyPostfix] private static void Targetable(EnemyAI __instance, PlayerControllerB playerScript, ref bool __result) { if (__result && Hidden(__instance, playerScript)) { __result = false; } } [HarmonyPatch(typeof(EnemyAI), "CheckLineOfSightForPlayer")] [HarmonyPostfix] private static void Sight(EnemyAI __instance, ref PlayerControllerB __result) { if (Hidden(__instance, __result)) { __result = null; } } [HarmonyPatch(typeof(EnemyAI), "CheckLineOfSightForClosestPlayer")] [HarmonyPostfix] private static void ClosestSight(EnemyAI __instance, ref PlayerControllerB __result) { if (Hidden(__instance, __result)) { __result = null; } } [HarmonyPatch(typeof(EnemyAI), "GetClosestPlayer")] [HarmonyPostfix] private static void Closest(EnemyAI __instance, ref PlayerControllerB __result) { if (Hidden(__instance, __result)) { __result = null; } } [HarmonyPatch(typeof(EnemyAI), "GetAllPlayersInLineOfSight")] [HarmonyPostfix] private static void AllInSight(EnemyAI __instance, ref PlayerControllerB[] __result) { if (__result == null || __result.Length == 0) { return; } int num = 0; for (int i = 0; i < __result.Length; i++) { if (Hidden(__instance, __result[i])) { num++; } } if (num == 0) { return; } if (num == __result.Length) { __result = null; return; } PlayerControllerB[] array = (PlayerControllerB[])(object)new PlayerControllerB[__result.Length - num]; int j = 0; int num2 = 0; for (; j < __result.Length; j++) { if (!Hidden(__instance, __result[j])) { array[num2++] = __result[j]; } } __result = array; } } public enum MaskValue { Vanilla, Custom } [BepInPlugin("Miles.MaskedPlus", "MaskedPlus", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "Miles.MaskedPlus"; public const string Name = "MaskedPlus"; public const string Version = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry<MaskValue> ValueMode; internal static ConfigEntry<int> CustomValue; internal static ConfigEntry<bool> HideEnabled; internal static ConfigEntry<float> RevealSeconds; private void Awake() { //IL_0095: 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) Log = ((BaseUnityPlugin)this).Logger; ValueMode = ((BaseUnityPlugin)this).Config.Bind<MaskValue>("Mask", "ValueMode", MaskValue.Vanilla, "How much a dropped mask is worth. Vanilla = the same random value a Comedy/Tragedy mask found as scrap gets (its normal range times the game's scrap value multiplier, so mods that change scrap value per moon apply too). Custom = always CustomValue. Only the host's setting counts."); CustomValue = ((BaseUnityPlugin)this).Config.Bind<int>("Mask", "CustomValue", 52, "Value of a dropped mask when ValueMode is Custom."); HideEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Hide behind a mask", "Enabled", true, "Holding a Comedy or Tragedy mask up to your face makes enemies ignore you, even up close. Touching one gives you away and it attacks (a Nutcracker kicks, a Forest Keeper grabs you). Holding the mask up too long still does what masks do. Everyone in the lobby should use the same setting."); RevealSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Hide behind a mask", "RevealSeconds", 10f, "After you touch an enemy with the mask up, it sees you for this many seconds (it keeps seeing you while you touch it)."); Harmony val = new Harmony("Miles.MaskedPlus"); val.PatchAll(typeof(MaskedPatches)); val.PatchAll(typeof(MaskHide)); Log.LogInfo((object)"MaskedPlus 1.0.0 loaded."); } } }