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 SmokeGrenade v1.1.1
SmokeGrenade.dll
Decompiled 5 hours agousing 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<AudioSource>(); 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<SmokeCloud> ActiveClouds = new List<SmokeCloud>(); 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>(); 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<LocalVolumetricFog>(); 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<StunGrenadeItem>()).itemProperties; Prefab = NetworkPrefabs.CloneNetworkPrefab(val, "SmokeGrenade"); Definition = Object.Instantiate<Item>(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<GrabbableObject>().itemProperties = Definition; StunGrenadeItem component = Prefab.GetComponent<StunGrenadeItem>(); component.TimeToExplode = 2.25f; component.throwString = "Throw smoke: [RMB]"; component.stunGrenadeExplosion = null; component.explodeSFX = null; Prefab.AddComponent<SmokeGrenadeBehaviour>(); 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<GameObject> list = new List<GameObject>(); 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<StunGrenadeItem>(); 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<StunGrenadeItem>()).itemProperties.itemName == "Stun grenade") { return item; } } if (list.Count <= 0) { return null; } return list[0]; } private static void Consider(GameObject candidate, List<GameObject> candidates) { StunGrenadeItem component = candidate.GetComponent<StunGrenadeItem>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)((GrabbableObject)component).itemProperties == (Object)null) && !((Object)(object)((Component)component).GetComponent<NetworkObject>() == (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<Renderer>(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<PlayerControllerB> 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<PlayerControllerB>(__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<SmokeGrenadeBehaviour>(); 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; } } }