using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalLib.Modules; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.Rendering.HighDefinition; [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("SmokeGrenade")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SmokeGrenade")] [assembly: AssemblyTitle("SmokeGrenade")] [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 SmokeGrenade { public static class EmbeddedAssets { public const string IconResource = "SmokeGrenade.smoke_grenade_icon.png"; public const string ReleaseSoundResource = "SmokeGrenade.gas_grenade_hiss.wav"; private static byte[] ReadBytes(string resourceName) { using Stream stream = typeof(EmbeddedAssets).Assembly.GetManifestResourceStream(resourceName); if (stream == null) { Plugin.Log.LogError((object)("Embedded asset '" + resourceName + "' is missing from the build.")); return null; } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } return array; } public static Sprite LoadSprite(string resourceName, string spriteName) { //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_001c: 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_002b: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) byte[] array = ReadBytes(resourceName); if (array == null) { return null; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false) { name = spriteName, filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; if (!ImageConversion.LoadImage(val, array)) { Plugin.Log.LogError((object)("Embedded image '" + resourceName + "' could not be decoded.")); return null; } Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); ((Object)obj).name = spriteName; return obj; } public static AudioClip LoadWav(string resourceName, string clipName) { byte[] array = ReadBytes(resourceName); if (array == null) { return null; } if (array.Length < 12 || BitConverter.ToUInt32(array, 0) != 1179011410 || BitConverter.ToUInt32(array, 8) != 1163280727) { Plugin.Log.LogError((object)"Embedded sound is not a RIFF/WAVE file."); return null; } int num = 0; int num2 = 0; int num3 = 0; int num4 = -1; int num5 = 0; int num6 = 12; while (num6 + 8 <= array.Length) { uint num7 = BitConverter.ToUInt32(array, num6); int num8 = BitConverter.ToInt32(array, num6 + 4); int num9 = num6 + 8; if (num7 == 544501094 && num9 + 16 <= array.Length) { num = BitConverter.ToInt16(array, num9 + 2); num2 = BitConverter.ToInt32(array, num9 + 4); num3 = BitConverter.ToInt16(array, num9 + 14); } else if (num7 == 1635017060) { num4 = num9; num5 = Mathf.Min(num8, array.Length - num9); } num6 = num9 + num8 + (num8 & 1); } if (num4 < 0 || num <= 0 || num2 <= 0) { Plugin.Log.LogError((object)"Embedded sound has no usable fmt/data chunks."); return null; } if (num3 != 16) { Plugin.Log.LogError((object)$"Embedded sound is {num3}-bit; only 16-bit PCM is supported."); return null; } int num10 = num5 / 2; float[] array2 = new float[num10]; for (int i = 0; i < num10; i++) { array2[i] = (float)BitConverter.ToInt16(array, num4 + i * 2) / 32768f; } int num11 = num10 / num; if (num11 <= 0) { Plugin.Log.LogError((object)"Embedded sound decoded to zero frames."); return null; } AudioClip obj = AudioClip.Create(clipName, num11, num, num2, false); obj.SetData(array2, 0); return obj; } } public static class ModInfo { public const string Guid = "SmokeGrenade"; public const string Name = "SmokeGrenade"; public const string Version = "1.0.0"; } [BepInPlugin("SmokeGrenade", "SmokeGrenade", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private Harmony _harmony; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("SmokeGrenade"); _harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"SmokeGrenade v1.0.0 loaded."); } } public static class SmokeAudio { private static AudioClip _bundled; private static bool _bundledLoaded; private static AudioClip _generated; private static AudioClip Generated { get { if ((Object)(object)_generated != (Object)null) { return _generated; } float num = 6f; int num2 = Mathf.Max(1024, Mathf.RoundToInt(44100f * num)); float[] array = new float[num2]; Random random = new Random(381134); float num3 = 1f - Mathf.Exp(-0.12822828f); float num4 = 0f; float num5 = 0f; float num6 = 0f; float num7 = 0.0001f; for (int i = 0; i < num2; i++) { float num8 = (float)(random.NextDouble() * 2.0 - 1.0); num4 += num3 * (num8 - num4); num5 += num3 * (num4 - num5); num6 = (array[i] = num6 + num3 * (num5 - num6)); float num9 = Mathf.Abs(num6); if (num9 > num7) { num7 = num9; } } float num10 = 0.9f / num7; for (int j = 0; j < num2; j++) { float num11 = (float)j / 44100f; float num12 = 0.82f + 0.18f * Mathf.Sin(num11 * 3.1f) * Mathf.Sin(num11 * 1.37f + 0.9f); array[j] = Mathf.Clamp(array[j] * num10 * num12, -1f, 1f); } _generated = AudioClip.Create("SmokeGrenadeHiss", num2, 1, 44100, false); _generated.SetData(array, 0); return _generated; } } public static AudioClip GetReleaseClip() { if (!_bundledLoaded) { _bundledLoaded = true; _bundled = EmbeddedAssets.LoadWav("SmokeGrenade.gas_grenade_hiss.wav", "SmokeGrenadeRelease"); if ((Object)(object)_bundled != (Object)null) { Plugin.Log.LogInfo((object)$"Loaded the release sound ({_bundled.length:0.0}s)."); } else { Plugin.Log.LogWarning((object)"Falling back to a generated hiss for the smoke release."); } } return _bundled ?? Generated; } public static AudioSource CreateSource(GameObject host, AudioSource template) { //IL_0058: 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_00a2: Invalid comparison between Unknown and I4 AudioSource val = host.AddComponent(); val.playOnAwake = false; val.spatialBlend = 1f; val.dopplerLevel = 0f; val.rolloffMode = (AudioRolloffMode)1; val.minDistance = 2f; val.maxDistance = 24f; if ((Object)(object)template != (Object)null) { val.outputAudioMixerGroup = template.outputAudioMixerGroup; val.rolloffMode = template.rolloffMode; val.minDistance = template.minDistance; val.maxDistance = Mathf.Max(template.maxDistance, val.maxDistance); val.spatialBlend = Mathf.Max(template.spatialBlend, 0.9f); if ((int)template.rolloffMode == 2) { val.SetCustomCurve((AudioSourceCurveType)0, template.GetCustomCurve((AudioSourceCurveType)0)); } } return val; } } public class SmokeCloud : MonoBehaviour { public static readonly List ActiveClouds = new List(); private const float SeedRadius = 0.4f; private const float InvisibleMeanFreePath = 60f; private const float MaxCreep = 1.35f; private float _age; private float _maxRise; private Vector3 _localOrigin; private LocalVolumetricFog _fog; private AudioSource _audio; public float Radius { get; private set; } public float Density { get; private set; } public static bool AnyActive => ActiveClouds.Count > 0; public static SmokeCloud Spawn(Vector3 position, Transform parent, AudioSource audioTemplate) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SmokeGrenadeCloud"); if ((Object)(object)parent != (Object)null) { val.transform.SetParent(parent); } val.transform.position = position; val.transform.rotation = Quaternion.identity; SmokeCloud smokeCloud = val.AddComponent(); smokeCloud.Setup(audioTemplate); return smokeCloud; } private void Setup(AudioSource audioTemplate) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) _localOrigin = ((Component)this).transform.localPosition; _maxRise = ResolveRiseCeiling(); Radius = 0.4f; Density = 0f; CreateFog(); CreateAudio(audioTemplate); } private float ResolveRiseCeiling() { //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) int num = LayerMask.GetMask(new string[3] { "Room", "Terrain", "MiscLevelGeometry" }); if (num == 0) { num = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-1)); } RaycastHit val = default(RaycastHit); if (Physics.Raycast(((Component)this).transform.position, Vector3.up, ref val, 6f, num, (QueryTriggerInteraction)1)) { return Mathf.Clamp(((RaycastHit)(ref val)).distance - 0.6f, 0f, 5f); } return 5f; } private void CreateFog() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_008e: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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) try { GameObject val = new GameObject("Fog"); val.transform.SetParent(((Component)this).transform, false); _fog = val.AddComponent(); LocalVolumetricFogArtistParameters p = _fog.parameters; p.albedo = SmokeSettings.FogColor; p.meanFreePath = 60f; p.anisotropy = 0f; p.size = Vector3.one * (Radius * 2f); p.positiveFade = Vector3.one * 0.5f; p.negativeFade = Vector3.one * 0.5f; p.distanceFadeStart = 5000f; p.distanceFadeEnd = 5000f; ApplyNoise(ref p); _fog.parameters = p; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not create the volumetric smoke, falling back to an invisible cloud: " + ex.Message)); _fog = null; } } private static void ApplyNoise(ref LocalVolumetricFogArtistParameters p) { //IL_0013: 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_002a: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) try { Texture3D val = SmokeNoise.Mask(); if (!((Object)(object)val == (Object)null)) { p.maskMode = (LocalVolumetricFogMaskMode)0; p.volumeMask = (Texture)(object)val; p.textureTiling = Vector3.one * 2.2f; p.textureScrollingSpeed = new Vector3(0.01f, 0.04f, 0.016f); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not apply the smoke noise mask: " + ex.Message)); } } private void CreateAudio(AudioSource audioTemplate) { try { AudioClip releaseClip = SmokeAudio.GetReleaseClip(); if (!((Object)(object)releaseClip == (Object)null)) { _audio = SmokeAudio.CreateSource(((Component)this).gameObject, audioTemplate); _audio.clip = releaseClip; _audio.loop = true; _audio.pitch = 0.37800002f; _audio.volume = Mathf.Min(1f, 0.047250003f); _audio.Play(); if ((Object)(object)audioTemplate != (Object)null) { WalkieTalkie.TransmitOneShotAudio(audioTemplate, releaseClip, _audio.volume); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not play the smoke release: " + ex.Message)); } } private void OnEnable() { if (!ActiveClouds.Contains(this)) { ActiveClouds.Add(this); } } private void OnDisable() { ActiveClouds.Remove(this); } private void Update() { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: 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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: 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) _age += Time.deltaTime; if (_age >= 38.3f) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Radius = Mathf.Min(RadiusAt(_age), 24.300001f); float num = Mathf.Clamp01(_age / 1.2f); float num2 = 1f - (1f - num) * (1f - num); if (_age > 30.3f) { num2 *= Mathf.Clamp01(1f - (_age - 30.3f) / 8f); } Density = Mathf.Clamp01(num2); if (_maxRise > 0f) { ((Component)this).transform.localPosition = _localOrigin + Vector3.up * Mathf.Min(0.35f * _age, _maxRise); } if ((Object)(object)_fog != (Object)null) { LocalVolumetricFogArtistParameters parameters = _fog.parameters; parameters.size = Vector3.one * (Radius * 2f); parameters.meanFreePath = Mathf.Lerp(60f, 1f, Density); _fog.parameters = parameters; } DriveRelease(); if (Density > 0.25f) { FogUpLocalVisor(); } } private static float RadiusAt(float age) { if (age < 0.3f) { float num = age / 0.3f; return Mathf.Lerp(0.4f, 3.5f, 1f - (1f - num) * (1f - num)); } float num2 = Mathf.Clamp01((age - 0.3f) / 10f); float num3 = num2 * num2 * (3f - 2f * num2); return Mathf.Lerp(3.5f, 18f, num3) + 0.15f * Mathf.Max(0f, age - 0.3f - 10f); } private void DriveRelease() { if ((Object)(object)_audio == (Object)null || !_audio.isPlaying) { return; } float num = 6f - _age; if (num <= 0f) { _audio.Stop(); return; } float num2 = 0.28f; float num3 = 0.035f; if (_age < 0.7f) { float num4 = _age / 0.7f; num4 = 1f - (1f - num4) * (1f - num4); num2 = Mathf.Lerp(num2 * 1.35f, num2, num4); num3 = Mathf.Lerp(Mathf.Min(1f, num3 * 1.35f), num3, num4); } if (num < 2.5f) { float num5 = 1f - num / 2.5f; num2 = Mathf.Lerp(num2, 0.126f, num5 * num5); num3 *= 1f - num5; } _audio.pitch = num2; _audio.volume = num3; } private void FogUpLocalVisor() { //IL_006e: 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) GameNetworkManager instance = GameNetworkManager.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)HUDManager.Instance == (Object)null) { return; } PlayerControllerB val = instance.localPlayerController; if (!((Object)(object)val == (Object)null)) { if (val.isPlayerDead && (Object)(object)val.spectatedPlayerScript != (Object)null) { val = val.spectatedPlayerScript; } if (!((Object)(object)val == (Object)null) && !((Object)(object)val.gameplayCamera == (Object)null) && Vector3.Distance(((Component)val.gameplayCamera).transform.position, ((Component)this).transform.position) < Radius) { HUDManager.Instance.increaseHelmetCondensation = true; } } } public static bool BlocksSight(Vector3 from, Vector3 to) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < ActiveClouds.Count; i++) { SmokeCloud smokeCloud = ActiveClouds[i]; if (!((Object)(object)smokeCloud == (Object)null) && !(smokeCloud.Density < 0.25f)) { float num = PathThroughSphere(from, to, ((Component)smokeCloud).transform.position, smokeCloud.Radius); if (!(num <= 0f) && num >= 2.5f / Mathf.Max(0.05f, smokeCloud.Density)) { return true; } } } return false; } public static float PathThroughSphere(Vector3 a, Vector3 b, Vector3 centre, float radius) { //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_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0027: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Vector3 val = b - a; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.0001f) { return 0f; } Vector3 val2 = val / magnitude; Vector3 val3 = a - centre; float num = Vector3.Dot(val3, val2); float num2 = Vector3.Dot(val3, val3) - radius * radius; float num3 = num * num - num2; if (num3 <= 0f) { return 0f; } float num4 = Mathf.Sqrt(num3); float num5 = Mathf.Max(0f - num - num4, 0f); return Mathf.Max(Mathf.Min(0f - num + num4, magnitude) - num5, 0f); } } public class SmokeGrenadeBehaviour : MonoBehaviour { private bool _released; public void Release(StunGrenadeItem grenade) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!_released) { _released = true; Vector3 position = ((Component)this).transform.position + Vector3.up * 0.2f; SmokeCloud.Spawn(position, ResolveParent(grenade), grenade.itemAudio); AlertMonsters(grenade, position); } } private static Transform ResolveParent(StunGrenadeItem grenade) { if (((GrabbableObject)grenade).isInElevator && (Object)(object)StartOfRound.Instance != (Object)null) { return StartOfRound.Instance.elevatorTransform; } if ((Object)(object)RoundManager.Instance != (Object)null && (Object)(object)RoundManager.Instance.mapPropsContainer != (Object)null) { return RoundManager.Instance.mapPropsContainer.transform; } return null; } private static void AlertMonsters(StunGrenadeItem grenade, Vector3 position) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)RoundManager.Instance == (Object)null)) { bool flag = ((GrabbableObject)grenade).isInElevator && (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.hangarDoorsClosed; RoundManager.Instance.PlayAudibleNoise(position, 12f, 0.2f, 0, flag, 195301); } } } public static class SmokeGrenadeItem { public const string ItemName = "Smoke grenade"; private static bool _built; public static Item Definition { get; private set; } public static GameObject Prefab { get; private set; } public static void Build() { if (_built) { return; } _built = true; GameObject val = FindStunGrenadePrefab(); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)"Could not find the vanilla stun grenade prefab; the smoke grenade will not be available."); return; } Item itemProperties = ((GrabbableObject)val.GetComponent()).itemProperties; Prefab = NetworkPrefabs.CloneNetworkPrefab(val, "SmokeGrenade"); Definition = Object.Instantiate(itemProperties); ((Object)Definition).name = "SmokeGrenadeItem"; Definition.itemName = "Smoke grenade"; Definition.itemId = 195301; Definition.isScrap = false; Definition.creditsWorth = 50; Definition.spawnPrefab = Prefab; Definition.toolTips = new string[2] { "Pull pin: [RMB]", "Throw smoke: [RMB]" }; Sprite val2 = EmbeddedAssets.LoadSprite("SmokeGrenade.smoke_grenade_icon.png", "SmokeGrenadeIcon"); if ((Object)(object)val2 != (Object)null) { Definition.itemIcon = val2; } Prefab.GetComponent().itemProperties = Definition; StunGrenadeItem component = Prefab.GetComponent(); component.TimeToExplode = 2.25f; component.throwString = "Throw smoke: [RMB]"; component.stunGrenadeExplosion = null; component.explodeSFX = null; Prefab.AddComponent(); Recolour(Prefab); RegisterNetworkPrefab(Prefab); Items.RegisterShopItem(Definition, 50); Plugin.Log.LogInfo((object)string.Format("Registered '{0}' for {1} credits.", "Smoke grenade", 50)); } private static GameObject FindStunGrenadePrefab() { List list = new List(); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.NetworkConfig != null && singleton.NetworkConfig.Prefabs != null) { foreach (NetworkPrefabsList networkPrefabsList in singleton.NetworkConfig.Prefabs.NetworkPrefabsLists) { if ((Object)(object)networkPrefabsList == (Object)null) { continue; } foreach (NetworkPrefab prefab in networkPrefabsList.PrefabList) { if ((Object)(object)prefab?.Prefab != (Object)null) { Consider(prefab.Prefab, list); } } } } if (list.Count == 0) { StunGrenadeItem[] array = Resources.FindObjectsOfTypeAll(); foreach (StunGrenadeItem val in array) { if ((Object)(object)val != (Object)null) { Consider(((Component)val).gameObject, list); } } } foreach (GameObject item in list) { if (((GrabbableObject)item.GetComponent()).itemProperties.itemName == "Stun grenade") { return item; } } if (list.Count <= 0) { return null; } return list[0]; } private static void Consider(GameObject candidate, List candidates) { StunGrenadeItem component = candidate.GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)((GrabbableObject)component).itemProperties == (Object)null) && !((Object)(object)((Component)component).GetComponent() == (Object)null) && !component.explodeOnCollision && !component.DestroyGrenade && !component.dontRequirePullingPin && !(component.chanceToExplode < 100f) && !candidates.Contains(candidate)) { candidates.Add(candidate); } } private static void RegisterNetworkPrefab(GameObject prefab) { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.NetworkConfig != null && !singleton.NetworkConfig.Prefabs.Contains(prefab)) { singleton.AddNetworkPrefab(prefab); } } private static void Recolour(GameObject prefab) { //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_004f: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { Material[] sharedMaterials = val.sharedMaterials; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null)) { Material val2 = new Material(sharedMaterials[j]) { name = ((Object)sharedMaterials[j]).name + " (Smoke)" }; Tint(val2, SmokeSettings.ItemTint); sharedMaterials[j] = val2; flag = true; } } if (flag) { val.sharedMaterials = sharedMaterials; } } } private static void Tint(Material material, Color tint) { //IL_0013: 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_0045: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", tint); } if (material.HasProperty("_Color")) { material.SetColor("_Color", tint); } if (material.HasProperty("_UnlitColor")) { material.SetColor("_UnlitColor", tint); } } } public static class SmokeNoise { private const int Size = 32; private static Texture3D _mask; public static Texture3D Mask() { if ((Object)(object)_mask == (Object)null) { _mask = Build(0.6f); } return _mask; } private static Texture3D Build(float strength) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0027: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) Texture3D val = new Texture3D(32, 32, 32, (TextureFormat)1, false) { name = "SmokeGrenadeNoise", wrapMode = (TextureWrapMode)0, filterMode = (FilterMode)1 }; Color32[] array = (Color32[])(object)new Color32[32768]; int num = 0; for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { for (int k = 0; k < 32; k++) { float x = (float)k / 32f; float y = (float)j / 32f; float z = (float)i / 32f; float num2 = Fbm(x, y, z); num2 = Mathf.Clamp01((num2 - 0.5f) * 1.6f + 0.5f); float num3 = Mathf.Lerp(1f, num2, strength); array[num++] = new Color32((byte)0, (byte)0, (byte)0, (byte)(Mathf.Clamp01(num3) * 255f)); } } } val.SetPixels32(array); val.Apply(false, false); return val; } private static float Fbm(float x, float y, float z) { return ValueNoise(x, y, z, 4, 1) * 0.55f + ValueNoise(x, y, z, 8, 2) * 0.3f + ValueNoise(x, y, z, 16, 3) * 0.15f; } private static float ValueNoise(float x, float y, float z, int period, int seed) { x *= (float)period; y *= (float)period; z *= (float)period; int num = Mathf.FloorToInt(x); int num2 = Mathf.FloorToInt(y); int num3 = Mathf.FloorToInt(z); float num4 = Smooth(x - (float)num); float num5 = Smooth(y - (float)num2); float num6 = Smooth(z - (float)num3); float num7 = Corner(num, num2, num3, period, seed); float num8 = Corner(num + 1, num2, num3, period, seed); float num9 = Corner(num, num2 + 1, num3, period, seed); float num10 = Corner(num + 1, num2 + 1, num3, period, seed); float num11 = Corner(num, num2, num3 + 1, period, seed); float num12 = Corner(num + 1, num2, num3 + 1, period, seed); float num13 = Corner(num, num2 + 1, num3 + 1, period, seed); float num14 = Corner(num + 1, num2 + 1, num3 + 1, period, seed); float num15 = Mathf.Lerp(num7, num8, num4); float num16 = Mathf.Lerp(num9, num10, num4); float num17 = Mathf.Lerp(num11, num12, num4); float num18 = Mathf.Lerp(num13, num14, num4); return Mathf.Lerp(Mathf.Lerp(num15, num16, num5), Mathf.Lerp(num17, num18, num5), num6); } private static float Smooth(float t) { return t * t * (3f - 2f * t); } private static float Corner(int x, int y, int z, int period, int seed) { x = Wrap(x, period); y = Wrap(y, period); z = Wrap(z, period); int num = x * 374761393 + y * 668265263 + z * 1274126177 + seed * 144665123; int num2 = (num ^ (num >>> 13)) * 1274126177; return (float)(uint)((num2 ^ (num2 >>> 16)) & 0xFFFFFF) / 16777215f; } private static int Wrap(int value, int period) { int num = value % period; if (num >= 0) { return num; } return num + period; } } internal static class SmokeSettings { public const int Price = 50; public const float FuseTime = 2.25f; public static readonly Color ItemTint = new Color(0.644f, 0.9775f, 1.0695f, 1f); public const float BurstRadius = 3.5f; public const float BurstTime = 0.3f; public const float Radius = 18f; public const float ExpandTime = 10f; public const float LingerGrowth = 0.15f; public const float RiseSpeed = 0.35f; public const float MaxRise = 5f; public const float ThickenTime = 1.2f; public const float Duration = 20f; public const float FadeTime = 8f; public static readonly Color FogColor = Color32.op_Implicit(new Color32((byte)88, (byte)92, (byte)96, byte.MaxValue)); public const float FogThickness = 1f; public const float NoiseStrength = 0.6f; public const float NoiseScale = 2.2f; public const float NoiseSpeed = 0.04f; public const float SightBlockDepth = 2.5f; public const float MinBlockingDensity = 0.25f; public const float ReleaseVolume = 0.035f; public const float ReleasePitch = 0.28f; public const float StartBoost = 1.35f; public const float AttackTime = 0.7f; public const float SpinDownTime = 2.5f; public const float SpinDownPitch = 0.45f; public const float ReleaseLength = 6f; public const float NoiseRange = 12f; public const float NoiseLoudness = 0.2f; public const int NoiseId = 195301; } } namespace SmokeGrenade.Patches { [HarmonyPatch(typeof(EnemyAI))] internal static class EnemyVisionPatches { private static bool CanBeBlinded(EnemyAI enemy) { if (!SmokeCloud.AnyActive) { return false; } if ((Object)(object)enemy == (Object)null) { return false; } EnemyType enemyType = enemy.enemyType; if (!((Object)(object)enemyType == (Object)null)) { return !enemyType.canSeeThroughFog; } return true; } private static Vector3 EyePosition(EnemyAI enemy, Transform overrideEye = null) { //IL_000a: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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) if ((Object)(object)overrideEye != (Object)null) { return overrideEye.position; } if ((Object)(object)enemy.eye != (Object)null) { return enemy.eye.position; } return ((Component)enemy).transform.position + Vector3.up * 0.5f; } private static bool Obscured(EnemyAI enemy, Vector3 target, Transform overrideEye = null) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return SmokeCloud.BlocksSight(EyePosition(enemy, overrideEye), target); } private static Vector3 HeadOf(PlayerControllerB player) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0019: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player.gameplayCamera != (Object)null) { return ((Component)player.gameplayCamera).transform.position; } return ((Component)player).transform.position + Vector3.up * 1.5f; } [HarmonyPatch("CheckLineOfSightForPlayer")] [HarmonyPostfix] private static void HideFromLineOfSight(EnemyAI __instance, ref PlayerControllerB __result) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__result == (Object)null) && CanBeBlinded(__instance) && Obscured(__instance, HeadOf(__result))) { __result = null; } } [HarmonyPatch("CheckLineOfSightForClosestPlayer")] [HarmonyPostfix] private static void HideFromClosestLineOfSight(EnemyAI __instance, ref PlayerControllerB __result) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__result == (Object)null) && CanBeBlinded(__instance) && Obscured(__instance, HeadOf(__result))) { __result = null; } } [HarmonyPatch("CheckLineOfSightForPosition")] [HarmonyPostfix] private static void HidePosition(EnemyAI __instance, ref bool __result, Vector3 objectPosition, Transform overrideEye) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (__result && CanBeBlinded(__instance) && Obscured(__instance, objectPosition, overrideEye)) { __result = false; } } [HarmonyPatch("CheckLineOfSight")] [HarmonyPostfix] private static void HideObject(EnemyAI __instance, ref GameObject __result, Transform useEye) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__result == (Object)null) && CanBeBlinded(__instance) && Obscured(__instance, __result.transform.position, useEye)) { __result = null; } } [HarmonyPatch("GetAllPlayersInLineOfSightNonAlloc", new Type[] { typeof(PlayerControllerB[]), typeof(float), typeof(int), typeof(Transform), typeof(float), typeof(int) })] [HarmonyPostfix] private static void FilterProvidedArray(EnemyAI __instance, ref int __result, PlayerControllerB[] playersArray, Transform eyeObject) { if (__result > 0 && CanBeBlinded(__instance)) { __result = Compact(__instance, playersArray, __result, eyeObject); } } [HarmonyPatch("GetAllPlayersInLineOfSightNonAlloc", new Type[] { typeof(float), typeof(int), typeof(Transform), typeof(float), typeof(int) })] [HarmonyPostfix] private static void FilterSharedArray(EnemyAI __instance, ref int __result, Transform eyeObject) { if (__result > 0 && CanBeBlinded(__instance) && !((Object)(object)RoundManager.Instance == (Object)null) && RoundManager.Instance.tempPlayersArray != null) { __result = Compact(__instance, RoundManager.Instance.tempPlayersArray, __result, eyeObject); } } [HarmonyPatch("GetAllPlayersInLineOfSight")] [HarmonyPostfix] private static void FilterResultArray(EnemyAI __instance, ref PlayerControllerB[] __result, Transform eyeObject) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (__result == null || __result.Length == 0 || !CanBeBlinded(__instance)) { return; } List list = null; for (int i = 0; i < __result.Length; i++) { PlayerControllerB val = __result[i]; bool flag = (Object)(object)val == (Object)null || Obscured(__instance, HeadOf(val), eyeObject); if (flag && list == null) { list = new List(__result.Length); for (int j = 0; j < i; j++) { list.Add(__result[j]); } } else if (!flag) { list?.Add(val); } } if (list != null) { __result = ((list.Count > 0) ? list.ToArray() : null); } } private static int Compact(EnemyAI enemy, PlayerControllerB[] players, int count, Transform eyeObject) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) count = Mathf.Min(count, players.Length); int num = 0; for (int i = 0; i < count; i++) { PlayerControllerB val = players[i]; if (!((Object)(object)val == (Object)null) && !Obscured(enemy, HeadOf(val), eyeObject)) { players[num++] = val; } } for (int j = num; j < count; j++) { players[j] = null; } return num; } } [HarmonyPatch(typeof(GameNetworkManager))] internal static class GameNetworkManagerPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void BuildSmokeGrenade() { SmokeGrenadeItem.Build(); } } [HarmonyPatch(typeof(StartOfRound))] internal static class StartOfRoundPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void ClearClouds() { SmokeCloud.ActiveClouds.RemoveAll((SmokeCloud cloud) => (Object)(object)cloud == (Object)null); } } [HarmonyPatch(typeof(StunGrenadeItem))] internal static class StunGrenadePatches { [HarmonyPatch("ExplodeStunGrenade")] [HarmonyPrefix] private static bool ReleaseSmokeInstead(StunGrenadeItem __instance) { SmokeGrenadeBehaviour component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } if (__instance.hasExploded) { return false; } __instance.hasExploded = true; try { component.Release(__instance); } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to release smoke: {arg}"); } return false; } } }