Decompiled source of ProperSmoke v1.0.0

ProperSmoke.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Il2CppInterop.Runtime.Injection;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ProperSmoke")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ProperSmoke")]
[assembly: AssemblyTitle("ProperSmoke")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 ProperSmoke
{
	[BepInPlugin("ekem.propersmoke", "Proper Smoke", "1.0.0")]
	public class Plugin : BasePlugin
	{
		public static ManualLogSource Log { get; private set; }

		public static Settings Cfg { get; private set; }

		public override void Load()
		{
			//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_0030: Expected O, but got Unknown
			//IL_0030: 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_004e: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			Cfg = new Settings(((BasePlugin)this).Config);
			ClassInjector.RegisterTypeInIl2Cpp<Heartbeat>();
			GameObject val = new GameObject("Proper Smoke Heartbeat");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<Heartbeat>();
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(9, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("Proper Smoke");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.0");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded.");
			}
			log.LogInfo(val2);
		}
	}
	public class Heartbeat : MonoBehaviour
	{
		public Heartbeat(IntPtr pointer)
			: base(pointer)
		{
		}

		private void Update()
		{
			SmokeFix.Tick();
		}
	}
	public class Settings
	{
		public readonly ConfigEntry<bool> DebugLogging;

		public Settings(ConfigFile config)
		{
			DebugLogging = config.Bind<bool>("Debug", "DebugLogging", false, "Logs which particle systems were found and what was done with them.");
		}
	}
	public static class PluginInfo
	{
		public const string Guid = "ekem.propersmoke";

		public const string Name = "Proper Smoke";

		public const string Version = "1.0.0";
	}
	public static class SmokeFix
	{
		private sealed class Cigarette
		{
			public ParticleSystem Source;

			public ParticleSystem Emitter;

			public float Size;

			public float Lifetime;

			public float BreathFrom;

			public float Rate = -1f;

			public float EmitSize = -1f;

			public float Speed = -1f;
		}

		private const float ScanEvery = 0.5f;

		private const float SmolderRate = 8f;

		private const float BreathRate = 30f;

		private const float BreathSize = 1.6f;

		private const float BreathSpeed = 0.35f;

		private const float BreathPeriod = 8f;

		private const float InhaleShare = 0.3f;

		private const float ExhaleShare = 0.35f;

		private const float AfterDraw = 3f;

		private const float DrawExhaleRate = 45f;

		private const float DrawExhaleSize = 2.5f;

		private const float DrawExhaleSpeed = 0.5f;

		private const float MaxLifetime = 4f;

		private const int MaxParticles = 400;

		private const float Alpha = 0.25f;

		private const float RiseSpeed = 0.08f;

		private const float ShapeScale = 0.02f;

		private static float _nextScan;

		private static readonly HashSet<int> Seen = new HashSet<int>();

		private static readonly List<Cigarette> Lit = new List<Cigarette>();

		private static bool _toking;

		private static float _scanUntil;

		public static void Tick()
		{
			if (Time.unscaledTime >= _nextScan || Time.time < _scanUntil)
			{
				_nextScan = Time.unscaledTime + 0.5f;
				FirstPersonItemController instance = FirstPersonItemController.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					Scan(((Component)instance).gameObject);
				}
				Camera main = Camera.main;
				if ((Object)(object)main != (Object)null)
				{
					Scan(((Component)main).gameObject);
				}
			}
			for (int num = Lit.Count - 1; num >= 0; num--)
			{
				if (!Smoke(Lit[num]))
				{
					Lit.RemoveAt(num);
				}
			}
		}

		private static void Scan(GameObject root)
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			bool flag = default(bool);
			foreach (ParticleSystem componentsInChild in root.GetComponentsInChildren<ParticleSystem>(true))
			{
				if ((Object)(object)componentsInChild == (Object)null || !Seen.Add(((Object)componentsInChild).GetInstanceID()))
				{
					continue;
				}
				string name = ((Object)((Component)componentsInChild).gameObject).name;
				string text = name.ToLowerInvariant();
				if (text.Contains("cigar"))
				{
					Replace(componentsInChild);
				}
				else if (text.Contains("smok"))
				{
					componentsInChild.emission.enabled = false;
					componentsInChild.Stop(true, (ParticleSystemStopBehavior)0);
					if (Plugin.Cfg.DebugLogging.Value)
					{
						ManualLogSource log = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("smoke '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' silenced");
						}
						log.LogInfo(val);
					}
				}
				else if (Plugin.Cfg.DebugLogging.Value)
				{
					ManualLogSource log2 = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(26, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("particles '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ParticleSystemSimulationSpace>(componentsInChild.main.simulationSpace);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") left as is");
					}
					log2.LogInfo(val);
				}
			}
		}

		private static void Replace(ParticleSystem source)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			MainModule main = source.main;
			MinMaxCurve startLifetime = main.startLifetime;
			float num = Mathf.Max(new float[3] { startLifetime.m_ConstantMax, startLifetime.m_ConstantMin, 1f }) * Mathf.Max(main.startLifetimeMultiplier, 0.01f);
			if (Plugin.Cfg.DebugLogging.Value)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(61, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("cigarette smoke: was rate ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(source.emission.rateOverTimeMultiplier, "0.##");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/s, ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("size x");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(main.startSizeMultiplier, "0.###");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", lifetime ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num, "0.##");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("s, ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("lossyScale ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(((Component)source).transform.lossyScale.x, "0.###");
				}
				log.LogInfo(val);
			}
			ParticleSystem val2 = NewEmitter(source);
			if (!((Object)(object)val2 == (Object)null))
			{
				source.emission.enabled = false;
				Lit.Add(new Cigarette
				{
					Source = source,
					Emitter = val2,
					Size = Mathf.Max(main.startSizeMultiplier, 0.03f),
					Lifetime = Mathf.Min(num, 4f),
					BreathFrom = Time.time
				});
			}
		}

		private static ParticleSystem? NewEmitter(ParticleSystem source)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			Step("create");
			GameObject val = new GameObject("Proper SmokeCigaretteSmoke");
			Object.DontDestroyOnLoad((Object)(object)val);
			val.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
			val.transform.rotation = Quaternion.FromToRotation(Vector3.forward, Vector3.up);
			val.transform.localScale = Vector3.one * 0.02f;
			ParticleSystem val2 = val.AddComponent<ParticleSystem>();
			val2.emission.rateOverTime = new MinMaxCurve(0f);
			MainModule main = val2.main;
			main.simulationSpace = (ParticleSystemSimulationSpace)1;
			main.scalingMode = (ParticleSystemScalingMode)2;
			main.maxParticles = 400;
			main.startSpeedMultiplier = 0.08f;
			main.startLifetimeMultiplier = Mathf.Min(source.main.startLifetimeMultiplier, 4f);
			main.startSizeMultiplier = Mathf.Max(source.main.startSizeMultiplier, 0.03f);
			main.startColor = new MinMaxGradient(new Color(1f, 1f, 1f, 0.25f));
			Step("material");
			ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>();
			ParticleSystemRenderer component2 = ((Component)source).GetComponent<ParticleSystemRenderer>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)((Renderer)component2).sharedMaterial == (Object)null)
			{
				Plugin.Log.LogWarning((object)"no smoke material to borrow, leaving the game's smoke alone");
				Object.Destroy((Object)(object)val);
				return null;
			}
			((Renderer)component).sharedMaterial = ((Renderer)component2).sharedMaterial;
			val2.Play();
			Step("ready");
			return val2;
		}

		private static void Step(string what)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			if (Plugin.Cfg.DebugLogging.Value)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("smoke emitter: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(what);
				}
				log.LogInfo(val);
			}
		}

		private static bool Smoke(Cigarette c)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Expected O, but got Unknown
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)c.Emitter == (Object)null)
			{
				return false;
			}
			if ((Object)(object)c.Source == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)c.Emitter).gameObject, c.Lifetime + 1f);
				return false;
			}
			if (!((Component)c.Source).gameObject.activeInHierarchy)
			{
				if (c.Rate != 0f)
				{
					c.Rate = 0f;
					c.Emitter.emission.rateOverTime = new MinMaxCurve(0f);
				}
				return true;
			}
			float num = 0f;
			FirstPersonItemController instance = FirstPersonItemController.Instance;
			bool flag = (Object)(object)instance != (Object)null && instance.smokingTokeActive;
			if (flag != _toking)
			{
				_toking = flag;
				if (Plugin.Cfg.DebugLogging.Value)
				{
					ManualLogSource log = Plugin.Log;
					bool flag2 = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(11, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("cigarette: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(flag ? "drawing" : "not drawing");
					}
					log.LogInfo(val);
				}
			}
			float num2 = 0f;
			float num3;
			if (flag)
			{
				num3 = 0f;
				c.BreathFrom = Time.time + 3f;
				_scanUntil = c.BreathFrom;
			}
			else if (Time.time < c.BreathFrom)
			{
				float num4 = 1f - (c.BreathFrom - Time.time) / 3f;
				num2 = Mathf.Sin((float)Math.PI * Mathf.Clamp01(num4));
				num = num2;
				num3 = Mathf.Lerp(8f, 45f, num2);
			}
			else
			{
				float num5 = (Time.time - c.BreathFrom) % 8f / 8f;
				if (num5 < 0.3f)
				{
					num3 = 0f;
				}
				else
				{
					float num6 = num5 - 0.3f;
					if (num6 < 0.35f)
					{
						num = Mathf.Sin((float)Math.PI * num6 / 0.35f);
					}
					num3 = Mathf.Lerp(8f, 30f, num);
				}
			}
			float num7 = c.Size * ((num2 > 0f) ? Mathf.Lerp(1f, 2.5f, num2) : Mathf.Lerp(1f, 1.6f, num));
			float num8 = ((num2 > 0f) ? Mathf.Lerp(0.08f, 0.5f, num2) : Mathf.Lerp(0.08f, 0.35f, num));
			if (Mathf.Abs(num3 - c.Rate) > 0.5f)
			{
				c.Rate = num3;
				c.Emitter.emission.rateOverTime = new MinMaxCurve(num3);
			}
			if (Mathf.Abs(num7 - c.EmitSize) > 0.005f || Mathf.Abs(num8 - c.Speed) > 0.01f)
			{
				c.EmitSize = num7;
				c.Speed = num8;
				MainModule main = c.Emitter.main;
				main.startSizeMultiplier = num7;
				main.startSpeedMultiplier = num8;
			}
			Camera main2 = Camera.main;
			Vector3 val2 = Vector3.up;
			if ((Object)(object)main2 != (Object)null && num > 0f)
			{
				Vector3 up = Vector3.up;
				Vector3 val3 = ((Component)main2).transform.forward + Vector3.up * 0.2f;
				val2 = Vector3.Slerp(up, ((Vector3)(ref val3)).normalized, num);
			}
			((Component)c.Emitter).transform.rotation = Quaternion.FromToRotation(Vector3.forward, val2);
			((Component)c.Emitter).transform.position = ((Component)c.Source).transform.position;
			return true;
		}
	}
}