using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; using BepInEx; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: AssemblyProduct("Pixel Smoke Fx")] [assembly: AssemblyDescription("Low-poly 3D smoke for Ravenfield bullet hits - zero assets, zero particles. Player-fire exemption, distance/frustum culling, pooled.")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyTitle("Pixel Smoke Fx")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("1.1.0.0")] namespace PixelSmokeFx; [BepInPlugin("com.local.pixelsmokefx", "Pixel Smoke Fx", "1.1.0")] public class FxPlugin : BaseUnityPlugin { public static class SpawnDecal_Patch { private static void Prefix(Projectile __instance, RaycastHit hitInfo) { //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) try { if (!EnabledCfg) { return; } if ((Object)(object)TemplatePlugin == (Object)null) { if (++_hitNoTemplate % 500 == 0 && Log != null) { Log.LogWarning((object)("PixelSmokeFx: " + _hitNoTemplate + " hits arrived while template missing")); } } else { if (__instance is ExplodingProjectile) { return; } string text = (((Object)(object)__instance.sourceWeapon != (Object)null) ? ((Object)__instance.sourceWeapon).name : null); if (TargetWeapon.Length > 0 && (string.IsNullOrEmpty(text) || text.IndexOf(TargetWeapon, StringComparison.OrdinalIgnoreCase) < 0)) { return; } Vector3 point = ((RaycastHit)(ref hitInfo)).point; Vector3 normal = ((RaycastHit)(ref hitInfo)).normal; bool flag = AlwaysRenderPlayer && IsPlayerFire(__instance); Camera val = MainCam(); float num = (((Object)(object)val != (Object)null) ? Vector3.Distance(((Component)val).transform.position, point) : 0f); if ((!flag && num >= HalfDist) || (!flag && !IsOnScreen(point))) { return; } float time = Time.time; string key = ((text != null) ? text : ""); if (!_lastGunTime.TryGetValue(key, out var value) || !(time - value < BurstWindow)) { if (time - _lastGlobalTime < GlobalCooldown || (_lastGunTime.TryGetValue(key, out value) && time - value < GunCooldown)) { return; } _lastGlobalTime = time; } _lastGunTime[key] = time; float caliber = 800f; float num2 = -1f; try { if (__instance.configuration != null) { Type type = ((object)__instance.configuration).GetType(); num2 = ReadDamage(__instance.configuration); if (num2 < 0f) { num2 = ReadDamage(__instance); } if (_speedProp == null || _speedPropType != type) { _speedPropType = type; _speedProp = type.GetProperty("speed"); } if (_speedProp != null) { object value2 = _speedProp.GetValue(__instance.configuration, null); if (value2 != null && value2 is float && (float)value2 > 50f) { caliber = (float)value2; } } } } catch (Exception) { } Transform transform = ((Component)__instance).transform; Vector3 flight = (((Object)(object)transform != (Object)null) ? transform.forward : Vector3.up); SpawnEffect(key, point, normal, flight, num, caliber, num2); } } catch (Exception ex2) { if (Log != null) { Log.LogWarning((object)("PixelSmokeFx: spawn: " + ex2)); } } } } private const int TEMPLATE_ATTEMPT_LIMIT = 10; internal static FxPlugin Instance; internal static ManualLogSource Log; internal static string TargetWeapon = ""; internal static int PoolSize = 120; internal static float GlobalCooldown = 0.005f; internal static float GunCooldown = 0.02f; internal static float BurstWindow = 0.08f; internal static float FullDist = 60f; internal static float HalfDist = 200f; internal static float Lifetime = 1.5f; internal static float ExpandTime = 0.15f; internal static float DecayRate = 2.2f; internal static float BaseScale = 0.7f; internal static float DamageRef = 40f; internal static float MinSizeFactor = 0.5f; internal static float MaxSizeFactor = 1.5f; internal static float ShotgunFactor = 0.25f; internal static bool EnabledCfg = true; internal static bool AlwaysRenderPlayer = true; internal static bool AutoTestCfg; private static bool _autoTestStarted; internal static GameObject TemplatePlugin; private static float _nextTemplateAttempt = -100f; private static int _templateAttempts; private static bool _templateFailedPermanent; private static Plane[] _planes; private static int _planeFrame = -1; private static PropertyInfo _speedProp; private static Type _speedPropType; private static MemberInfo _dmgMember; private static Type _dmgMemberType; private static float _lastGlobalTime = -1f; private static readonly Dictionary _lastGunTime = new Dictionary(); internal static int SpawnCount; private static int _spawnLogThrottle; internal static int _hitNoTemplate; private static Camera _cachedMain; private static int _cachedMainFrame = -1; private static FieldInfo _firedByPlayerField; private static bool _firedByPlayerResolved; private static MethodInfo _userIsPlayerMethod; private static bool _userIsPlayerResolved; private static bool _playerFireLogged; private readonly List _pool = new List(); private readonly Dictionary _slotBlobs = new Dictionary(); private bool _toppingUp; internal static float ReadDamage(object target) { if (target == null) { return -1f; } Type type = target.GetType(); if (_dmgMember == null || _dmgMemberType != type) { _dmgMemberType = type; _dmgMember = FindDamageMember(type); } if (_dmgMember == null) { return -1f; } try { object obj = ((_dmgMember is PropertyInfo) ? ((PropertyInfo)_dmgMember).GetValue(target, null) : ((FieldInfo)_dmgMember).GetValue(target)); if (obj == null) { return -1f; } float num = Convert.ToSingle(obj); return (num > 0f) ? num : (-1f); } catch (Exception) { return -1f; } } private static MemberInfo FindDamageMember(Type t) { string[] array = new string[5] { "damage", "damageMax", "maxDamage", "damagePerProjectile", "baseDamage" }; try { string[] array2 = array; foreach (string name in array2) { PropertyInfo property = t.GetProperty(name); if (property != null && (property.PropertyType == typeof(float) || property.PropertyType == typeof(int))) { return property; } } string[] array3 = array; foreach (string name2 in array3) { FieldInfo field = t.GetField(name2); if (field != null && (field.FieldType == typeof(float) || field.FieldType == typeof(int))) { return field; } } } catch (Exception) { } return null; } internal static bool IsPlayerFire(Projectile proj) { try { if (!_firedByPlayerResolved) { _firedByPlayerResolved = true; _firedByPlayerField = AccessTools.Field(typeof(Projectile), "firedByPlayer"); if (Log != null && !_playerFireLogged) { _playerFireLogged = true; Log.LogInfo((object)("PixelSmokeFx: player-fire resolver uses " + ((_firedByPlayerField != null) ? "Projectile.firedByPlayer" : "Weapon.UserIsPlayer() fallback"))); } } if (_firedByPlayerField != null) { object value = _firedByPlayerField.GetValue(proj); if (value != null && value is bool result) { return result; } } if ((Object)(object)proj.sourceWeapon != (Object)null) { if (!_userIsPlayerResolved) { _userIsPlayerResolved = true; _userIsPlayerMethod = AccessTools.Method(typeof(Weapon), "UserIsPlayer", (Type[])null, (Type[])null); } if (_userIsPlayerMethod != null) { object obj = _userIsPlayerMethod.Invoke(proj.sourceWeapon, null); if (obj != null && obj is bool result2) { return result2; } } } } catch (Exception) { } return false; } private static float SafeFloat(string key, float value, float min, float max, float fallback) { if (float.IsNaN(value) || float.IsInfinity(value)) { Log.LogWarning((object)("PixelSmokeFx: cfg " + key + " is not a number (" + value + "), using " + fallback)); return fallback; } if (value < min || value > max) { Log.LogWarning((object)("PixelSmokeFx: cfg " + key + "=" + value + " out of range [" + min + "," + max + "], clamped")); return Mathf.Clamp(value, min, max); } return value; } private static int SafeInt(string key, int value, int min, int max, int fallback) { if (value < min || value > max) { Log.LogWarning((object)("PixelSmokeFx: cfg " + key + "=" + value + " out of range [" + min + "," + max + "], clamped")); return Math.Max(min, Math.Min(max, value)); } return value; } private void Awake() { //IL_05ce: Unknown result type (might be due to invalid IL or missing references) //IL_05d4: Expected O, but got Unknown //IL_063f: Unknown result type (might be due to invalid IL or missing references) //IL_064d: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; try { EnabledCfg = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Master switch.").Value; TargetWeapon = ((BaseUnityPlugin)this).Config.Bind("General", "TargetWeapon", "", "Weapon-name substring that sourceWeapon.name must contain; empty = all non-explosive guns.").Value; AlwaysRenderPlayer = ((BaseUnityPlugin)this).Config.Bind("General", "AlwaysRenderPlayer", true, "Effects from shots FIRED BY THE PLAYER render regardless of distance and viewport; other shots keep distance + frustum culling.").Value; PoolSize = SafeInt("PoolSize", ((BaseUnityPlugin)this).Config.Bind("Performance", "PoolSize", 120, "Pool slots (= concurrent alive blob cap).").Value, 1, 400, 120); GlobalCooldown = SafeFloat("GlobalCooldown", ((BaseUnityPlugin)this).Config.Bind("Performance", "GlobalCooldown", 0.005f, "Min seconds between any two bursts (same-burst hits bypass this).").Value, 0f, 10f, 0.005f); GunCooldown = SafeFloat("GunCooldown", ((BaseUnityPlugin)this).Config.Bind("Performance", "GunCooldown", 0.02f, "Min seconds between bursts of the same weapon (auto-fire pacifier).").Value, 0f, 10f, 0.02f); BurstWindow = SafeFloat("BurstWindow", ((BaseUnityPlugin)this).Config.Bind("Performance", "BurstWindow", 0.08f, "Hits from one weapon within this many seconds count as ONE shot (shotgun pellets land on different frames when angled) and all render.").Value, 0f, 10f, 0.08f); FullDist = SafeFloat("FullDist", ((BaseUnityPlugin)this).Config.Bind("Performance", "FullDist", 60f, "Blobs closer than this are full size.").Value, 1f, 10000f, 60f); HalfDist = Math.Max(FullDist, SafeFloat("HalfDist", ((BaseUnityPlugin)this).Config.Bind("Performance", "HalfDist", 200f, "Blobs closer than this are half size; further = skipped.").Value, 1f, 20000f, 200f)); Lifetime = SafeFloat("Lifetime", ((BaseUnityPlugin)this).Config.Bind("Performance", "Lifetime", 1.5f, "Seconds a blob lives (alpha fades 1 -> 0 linearly across this).").Value, 0.1f, 60f, 1.5f); ExpandTime = SafeFloat("ExpandTime", ((BaseUnityPlugin)this).Config.Bind("Fx", "ExpandTime", 0.15f, "Rapid-expansion window: scale 0.04 -> 1.0 over this many seconds.").Value, 0.01f, 30f, 0.15f); DecayRate = SafeFloat("DecayRate", ((BaseUnityPlugin)this).Config.Bind("Fx", "DecayRate", 2.2f, "Exponential shrink rate after ExpandTime (higher = snappier).").Value, 0.05f, 100f, 2.2f); BaseScale = SafeFloat("BaseScale", ((BaseUnityPlugin)this).Config.Bind("Fx", "BaseScale", 0.7f, "Master blob size multiplier (damage/speed + distance LOD still scale it).").Value, 0.01f, 100f, 0.7f); DamageRef = SafeFloat("DamageRef", ((BaseUnityPlugin)this).Config.Bind("Fx", "DamageRef", 40f, "Projectile damage that maps to size factor 1.0 (rifle-size smoke).").Value, 1f, 10000f, 40f); MinSizeFactor = SafeFloat("MinSizeFactor", ((BaseUnityPlugin)this).Config.Bind("Fx", "MinSizeFactor", 0.5f, "Smallest damage size factor (shotgun pellets - many hits per shot - can shrink to 0.25).").Value, 0.05f, 1f, 0.5f); MaxSizeFactor = SafeFloat("MaxSizeFactor", ((BaseUnityPlugin)this).Config.Bind("Fx", "MaxSizeFactor", 1.5f, "Largest damage size factor (sniper hits billow big).").Value, 0.1f, 10f, 1.5f); ShotgunFactor = SafeFloat("ShotgunFactor", ((BaseUnityPlugin)this).Config.Bind("Fx", "ShotgunFactor", 0.25f, "Size floor for low-damage pellets (shotguns fire many; each pellet stays tiny).").Value, 0.05f, 1f, 0.25f); AutoTestCfg = ((BaseUnityPlugin)this).Config.Bind("Testing", "AutoTest", false, "True = run built-in AutoTest once at boot (spawns blobs at several distances/angles in front of the camera, captures screenshots).").Value; Log.LogInfo((object)("PixelSmokeFx: cfg Target='" + TargetWeapon + "' Pool=" + PoolSize + " cd=" + GlobalCooldown + "/" + GunCooldown + " burst=" + BurstWindow + " dist=" + FullDist + "/" + HalfDist + " expand=" + ExpandTime + " decay=" + DecayRate + " base=" + BaseScale + " dmgRef=" + DamageRef + " size=" + MinSizeFactor + "/" + MaxSizeFactor + " pellet=" + ShotgunFactor)); } catch (Exception ex) { Log.LogError((object)("PixelSmokeFx cfg: " + ex)); } try { Harmony val = new Harmony("com.local.pixelsmokefx"); MethodInfo methodInfo = AccessTools.Method(typeof(Projectile), "SpawnDecal", (Type[])null, (Type[])null); MethodInfo method = typeof(SpawnDecal_Patch).GetMethod("Prefix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (methodInfo == null) { Log.LogError((object)"PixelSmokeFx: target Projectile::SpawnDecal not found"); return; } if (method == null) { Log.LogError((object)"PixelSmokeFx: prefix method not found"); return; } val.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); bool flag = false; foreach (MethodBase patchedMethod in val.GetPatchedMethods()) { if (patchedMethod != null && patchedMethod.DeclaringType == typeof(Projectile) && patchedMethod.Name == "SpawnDecal") { flag = true; break; } } if (flag) { Log.LogInfo((object)"PixelSmokeFx: harmony hook CONFIRMED on Projectile::SpawnDecal"); } else { Log.LogError((object)"PixelSmokeFx: harmony hook NOT registered (SpawnDecal missing from patched list)"); } } catch (Exception ex2) { Log.LogError((object)("PixelSmokeFx: harmony patch failed: " + ex2)); } } private void Update() { if ((Object)(object)TemplatePlugin == (Object)null && !_templateFailedPermanent && Time.time >= _nextTemplateAttempt) { _templateAttempts++; _nextTemplateAttempt = Time.time + ((_templateAttempts <= 5) ? 3f : 30f); if (_templateAttempts > 10) { _templateFailedPermanent = true; try { if (Log != null) { Log.LogWarning((object)("PixelSmokeFx: mesh template failed " + 10 + " times - disabled. Delete BepInEx/config/com.local.pixelsmokefx.cfg and check the log.")); } return; } catch (Exception) { return; } } LoadTemplate(); } if (AutoTestCfg && !_autoTestStarted) { _autoTestStarted = true; ((MonoBehaviour)this).StartCoroutine(AutoTestRoutine()); } } private IEnumerator AutoTestRoutine() { Camera cam = null; bool textOnly = true; float deadline = Time.time + 60f; float lastDiag = 0f; while (Time.time < deadline) { cam = MainCam(); if ((Object)(object)cam == (Object)null) { cam = FallbackTestCam(); if ((Object)(object)cam != (Object)null) { textOnly = ((Object)cam).name != null && ((Object)cam).name.IndexOf("Text", StringComparison.OrdinalIgnoreCase) >= 0; if (!textOnly) { break; } cam = null; } } else { textOnly = ((Object)cam).name != null && ((Object)cam).name.IndexOf("Text", StringComparison.OrdinalIgnoreCase) >= 0; if (!textOnly) { break; } } if (Time.time - lastDiag > 10f) { lastDiag = Time.time; try { Camera[] array = Object.FindObjectsOfType(); string[] array2 = new string[array.Length]; for (int i = 0; i < array.Length; i++) { array2[i] = ((Object)array[i]).name + "[" + (((Component)array[i]).tag ?? "?") + "," + (((Behaviour)array[i]).enabled ? "on" : "off") + "]"; } Log.LogInfo((object)("PixelSmokeFx: AutoTest waiting for camera, found: " + string.Join(", ", array2))); } catch (Exception ex) { Log.LogWarning((object)("PixelSmokeFx AutoTest cam diag: " + ex)); } } yield return null; } if ((Object)(object)cam == (Object)null) { Log.LogWarning((object)"PixelSmokeFx: AutoTest aborted - no camera within 60s"); _autoTestStarted = true; yield break; } if (textOnly) { Log.LogWarning((object)"PixelSmokeFx: AutoTest proceeding with text/loading camera - shots may be blank"); } Log.LogInfo((object)("PixelSmokeFx: AutoTest start, camera=" + ((Object)cam).name)); string dir = Path.Combine(Paths.BepInExRootPath, "PixelSmokeFxTest", DateTime.Now.ToString("yyyyMMdd_HHmmss")); try { Directory.CreateDirectory(dir); } catch (Exception ex2) { Log.LogError((object)("PixelSmokeFx: AutoTest dir: " + ex2)); dir = null; } float[] dists = new float[3] { 8f, 24f, 60f }; try { bool built; try { built = SmokeMeshFactory.BuildMainTemplate(); } catch (Exception ex3) { Log.LogError((object)("PixelSmokeFx: AutoTest template build: " + ex3)); built = false; } if (!built) { Log.LogWarning((object)"PixelSmokeFx: AutoTest template build failed, skipped"); yield break; } TemplatePlugin = SmokeMeshFactory.TemplateRoot; RebuildPoolForTemplate(); Log.LogInfo((object)"PixelSmokeFx: AutoTest evaluating mesh template"); Vector3 fwd = ((Component)cam).transform.forward; Vector3 right = ((Component)cam).transform.right; for (int d = 0; d < dists.Length; d++) { Vector3 basePos = ((Component)cam).transform.position + fwd * dists[d]; Vector3[] burstPts = (Vector3[])(object)new Vector3[3]; Vector3[] burstNs = (Vector3[])(object)new Vector3[3]; float[] offsets = new float[3] { -2.2f, 0f, 2.2f }; float[] yOff = new float[3] { -0.4f, 0f, 0.4f }; for (int j = 0; j < 3; j++) { Vector3 val = basePos + right * offsets[j] + Vector3.up * yOff[j]; Vector3 val2 = ((Component)cam).transform.position - val; Vector3 normalized = ((Vector3)(ref val2)).normalized; Vector3 val3; switch (j) { default: { Vector3 val4 = Vector3.up + normalized; val3 = ((Vector3)(ref val4)).normalized; break; } case 1: val3 = normalized; break; case 0: val3 = Vector3.up; break; } Vector3 val5 = val3; burstPts[j] = val; burstNs[j] = val5; SpawnEffect("autotest", val, val5, fwd, dists[d], 800f, 40f); } yield return (object)new WaitForSeconds(0.4f); if (dir == null) { continue; } string file = Path.Combine(dir, "d" + dists[d] + "m.png"); float content = -1f; for (int attempt = 0; attempt < 8; attempt++) { for (int k = 0; k < 3; k++) { SpawnEffect("autotest", burstPts[k], burstNs[k], fwd, dists[d], 800f, 40f); } yield return (object)new WaitForSeconds(0.4f); TakeScreenshot(file); yield return (object)new WaitForEndOfFrame(); Thread.Sleep(120); content = ScreenshotContent(file); if (content >= 0.25f) { break; } Log.LogInfo((object)("PixelSmokeFx: AutoTest re-shoot " + (attempt + 1) + " for " + file + " (content=" + content + ")")); try { if (File.Exists(file)) { File.Delete(file); } } catch (Exception) { } } Log.LogInfo((object)("PixelSmokeFx: AutoTest shot -> " + file + " (content=" + content + ")")); } yield return (object)new WaitForSeconds(0.8f); } finally { for (int array = _pool.Count - 1; array >= 0; array--) { GameObject array2 = _pool[array]; if ((Object)(object)array2 != (Object)null) { DropSlot(array2); Object.Destroy((Object)(object)array2); } } _pool.Clear(); Instance._slotBlobs.Clear(); TemplatePlugin = null; SmokeMeshFactory.ReleaseTemplate(); _nextTemplateAttempt = 0f; _templateAttempts = 0; _templateFailedPermanent = false; if (dir != null) { Log.LogInfo((object)("PixelSmokeFx: AutoTest done - screenshots in " + dir)); } else { Log.LogInfo((object)"PixelSmokeFx: AutoTest done (no screenshots taken)"); } } } private void RebuildPoolForTemplate() { for (int num = _pool.Count - 1; num >= 0; num--) { GameObject val = _pool[num]; if ((Object)(object)val != (Object)null) { DropSlot(val); Object.Destroy((Object)(object)val); } } _pool.Clear(); _slotBlobs.Clear(); if (!((Object)(object)TemplatePlugin == (Object)null)) { int num2 = Math.Min(PoolSize, 12); for (int i = 0; i < num2; i++) { GameObject val2 = Object.Instantiate(TemplatePlugin); Object.DontDestroyOnLoad((Object)(object)val2); val2.SetActive(false); _pool.Add(val2); } Log.LogInfo((object)("PixelSmokeFx: AutoTest pool rebuilt (" + num2 + ")")); } } private static float ScreenshotContent(string path) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) try { if (!File.Exists(path)) { return -1f; } Texture2D val = new Texture2D(2, 2); if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path))) { Object.Destroy((Object)(object)val); return -1f; } Color32[] pixels = val.GetPixels32(); int num = 0; int num2 = 0; for (int i = 0; i < pixels.Length; i += 5) { Color32 val2 = pixels[i]; if (val2.r < 70 && val2.g < 70 && val2.b < 70) { num++; } if (val2.r > 110 && val2.g > 110 && val2.b > 110) { num2++; } } Object.Destroy((Object)(object)val); int num3 = (pixels.Length + 4) / 5; float num4 = (float)num / (float)num3; float num5 = (float)num2 / (float)num3; return Mathf.Min(1f, num4 * 2.5f) + ((num5 > 0.15f) ? 0.5f : 0f); } catch (Exception ex) { if (Log != null) { Log.LogWarning((object)("PixelSmokeFx: content check " + path + ": " + ex)); } return -1f; } } private static void TakeScreenshot(string path) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Type type = null; for (int i = 0; i < assemblies.Length; i++) { if (!(type == null)) { break; } if (assemblies[i].FullName.StartsWith("UnityEngine.ScreenCaptureModule", StringComparison.Ordinal)) { type = assemblies[i].GetType("UnityEngine.ScreenCapture"); } } if (type == null) { Log.LogWarning((object)"PixelSmokeFx: ScreenCapture type not found, no shot"); return; } MethodInfo method = type.GetMethod("CaptureScreenshot", new Type[2] { typeof(string), typeof(int) }); if (method == null) { method = type.GetMethod("CaptureScreenshot", new Type[1] { typeof(string) }); } if (method == null) { Log.LogWarning((object)"PixelSmokeFx: CaptureScreenshot not found, no shot"); return; } object[] parameters = ((method.GetParameters().Length == 2) ? new object[2] { path, 1 } : new object[1] { path }); method.Invoke(null, parameters); } catch (Exception ex) { Log.LogWarning((object)("PixelSmokeFx: screenshot " + path + ": " + ex)); } } private void LoadTemplate() { try { if (SmokeMeshFactory.BuildMainTemplate()) { TemplatePlugin = SmokeMeshFactory.TemplateRoot; Log.LogInfo((object)"PixelSmokeFx: mesh template ready"); ((MonoBehaviour)this).StartCoroutine(WarmPool()); } else { Log.LogError((object)"PixelSmokeFx: mesh template build failed, retrying in 3s"); } } catch (Exception ex) { Log.LogError((object)("PixelSmokeFx: template load failed: " + ex)); } } private IEnumerator WarmPool() { while (_pool.Count < PoolSize && (Object)(object)TemplatePlugin != (Object)null) { GameObject go = Object.Instantiate(TemplatePlugin); Object.DontDestroyOnLoad((Object)(object)go); go.SetActive(false); _pool.Add(go); if (_pool.Count % 10 == 0) { yield return null; } } Log.LogInfo((object)("PixelSmokeFx: pool warmed to " + _pool.Count)); } internal static SmokeBlob BlobOf(GameObject go) { if (Instance._slotBlobs.TryGetValue(go, out var value)) { return value; } value = go.GetComponent(); if ((Object)(object)value == (Object)null) { value = go.AddComponent(); } Instance._slotBlobs[go] = value; return value; } private static void DropSlot(GameObject go) { if ((Object)(object)Instance != (Object)null && go != null) { Instance._slotBlobs.Remove(go); } } internal static GameObject GetFromPool() { List pool = Instance._pool; for (int num = pool.Count - 1; num >= 0; num--) { if ((Object)(object)pool[num] == (Object)null) { DropSlot(pool[num]); pool.RemoveAt(num); } else if (!pool[num].activeSelf) { return pool[num]; } } return null; } private IEnumerator TopUpPool() { while (_pool.Count < PoolSize && (Object)(object)TemplatePlugin != (Object)null) { GameObject go = Object.Instantiate(TemplatePlugin); Object.DontDestroyOnLoad((Object)(object)go); go.SetActive(false); _pool.Add(go); yield return null; } } internal static void RequestTopUp() { if (!Instance._toppingUp) { Instance._toppingUp = true; ((MonoBehaviour)Instance).StartCoroutine(Instance.TopUpPoolAndUnset()); } } private IEnumerator TopUpPoolAndUnset() { yield return TopUpPool(); _toppingUp = false; } internal static void SpawnEffect(string key, Vector3 point, Vector3 normal, Vector3 flight, float dist, float caliber, float damage) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)TemplatePlugin == (Object)null) { return; } float num = ((dist < FullDist) ? 1f : 0.5f); float num4; if (damage > 0f) { float num2 = ((damage * 2f < DamageRef) ? ShotgunFactor : MinSizeFactor); float num3 = Mathf.Clamp(damage / DamageRef, num2, MaxSizeFactor); num4 = num3 * 0.7f * num * BaseScale; } else { num4 = Mathf.Clamp((float)Math.Sqrt(caliber / 800f) * 0.7f, 0.45f, 1.6f) * num * BaseScale; } num4 = Mathf.Clamp(num4, 0.001f, 3f); GameObject fromPool = GetFromPool(); if ((Object)(object)fromPool == (Object)null) { RequestTopUp(); return; } fromPool.transform.position = point + normal * 0.3f; fromPool.transform.rotation = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f); SmokeBlob smokeBlob = BlobOf(fromPool); smokeBlob.Launch(num4, Lifetime); fromPool.SetActive(true); SpawnCount++; if (++_spawnLogThrottle % 200 == 0 && Log != null) { Log.LogInfo((object)("PixelSmokeFx: spawned " + SpawnCount + " total, key=" + key + " dist=" + dist.ToString("F0") + " cal=" + caliber.ToString("F0") + " scale=" + num4.ToString("F2"))); } } catch (Exception ex) { if (Log != null) { Log.LogWarning((object)("PixelSmokeFx: spawn: " + ex)); } } } internal static Camera MainCam() { if ((Object)(object)_cachedMain == (Object)null || _cachedMainFrame != Time.frameCount) { _cachedMain = Camera.main; _cachedMainFrame = Time.frameCount; } return _cachedMain; } private static Camera FallbackTestCam() { Camera val = null; try { Camera[] array = Object.FindObjectsOfType(); foreach (Camera val2 in array) { if ((Object)(object)val2 == (Object)null || !((Behaviour)val2).enabled) { continue; } string name = ((Object)val2).name; if (name == null || (name.IndexOf("Text", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Icon", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Post-process", StringComparison.OrdinalIgnoreCase) < 0)) { if ((Object)(object)val == (Object)null) { val = val2; } if (name != null && name.IndexOf("Main", StringComparison.OrdinalIgnoreCase) >= 0) { return val2; } } } } catch (Exception) { } return val; } internal static bool IsOnScreen(Vector3 point) { //IL_003e: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) Camera val = MainCam(); if ((Object)(object)val == (Object)null) { return false; } if (_planes == null || _planeFrame != Time.frameCount) { _planes = GeometryUtility.CalculateFrustumPlanes(val); _planeFrame = Time.frameCount; } return GeometryUtility.TestPlanesAABB(_planes, new Bounds(point, Vector3.one * 0.4f)); } } public static class SmokeMeshFactory { public static GameObject TemplateRoot; private static Material _sharedMat; private static readonly Dictionary _cache = new Dictionary(); private static readonly int[] PUFF_SEEDS = new int[3] { 20260808, 20260809, 20260810 }; internal static readonly float[] PUFF_BASE_SCALE = new float[3] { 1f, 0.62f, 0.45f }; internal static readonly float[] PUFF_DELAY = new float[3] { 0f, 0.1f, 0.16f }; public static bool BuildMainTemplate() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0049: 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_00a3: Unknown result type (might be due to invalid IL or missing references) try { Material val = MakeBlobMaterial(); if ((Object)(object)val == (Object)null) { return false; } _sharedMat = val; GameObject val2 = new GameObject("PixelSmokeFxBlobExplosion"); val2.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val2); MakePuff(val2, "SmokePuff0", new Vector3(0f, 0f, 0f), GetOrBuild(PUFF_SEEDS[0], 3)); MakePuff(val2, "SmokePuff1", new Vector3(0.26f, -0.1f, 0.14f), GetOrBuild(PUFF_SEEDS[1], 3)); MakePuff(val2, "SmokePuff2", new Vector3(-0.24f, 0.07f, 0.12f), GetOrBuild(PUFF_SEEDS[2], 3)); val2.AddComponent(); TemplateRoot = val2; return true; } catch (Exception ex) { if (FxPlugin.Log != null) { FxPlugin.Log.LogWarning((object)("PixelSmokeFx: mesh template build: " + ex)); } return false; } } private static GameObject MakePuff(GameObject parent, string name, Vector3 localPos, Mesh mesh) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent.transform, false); val.transform.localPosition = localPos; val.transform.localRotation = Quaternion.identity; MeshFilter val2 = val.AddComponent(); val2.sharedMesh = mesh; MeshRenderer val3 = val.AddComponent(); ((Renderer)val3).sharedMaterial = _sharedMat; return val; } public static void ReleaseTemplate() { if ((Object)(object)TemplateRoot != (Object)null) { Object.Destroy((Object)(object)TemplateRoot); } TemplateRoot = null; if ((Object)(object)_sharedMat != (Object)null) { Object.Destroy((Object)(object)_sharedMat); } _sharedMat = null; } private static Mesh GetOrBuild(int seed, int subdiv) { if (_cache.TryGetValue(seed, out var value) && (Object)(object)value != (Object)null) { return value; } value = BuildIcosphere(seed, subdiv); _cache[seed] = value; return value; } private static Mesh BuildIcosphere(int seed, int subdiv) { //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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: 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_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_043a: Unknown result type (might be due to invalid IL or missing references) //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_0485: Unknown result type (might be due to invalid IL or missing references) //IL_0487: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_0499: Unknown result type (might be due to invalid IL or missing references) //IL_04a9: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04bb: Unknown result type (might be due to invalid IL or missing references) //IL_04bd: Unknown result type (might be due to invalid IL or missing references) //IL_0504: Unknown result type (might be due to invalid IL or missing references) //IL_0509: Unknown result type (might be due to invalid IL or missing references) //IL_0600: Unknown result type (might be due to invalid IL or missing references) //IL_0607: Expected O, but got Unknown //IL_05c4: Unknown result type (might be due to invalid IL or missing references) //IL_05c6: Unknown result type (might be due to invalid IL or missing references) //IL_05d6: Unknown result type (might be due to invalid IL or missing references) //IL_05d8: Unknown result type (might be due to invalid IL or missing references) //IL_05e8: Unknown result type (might be due to invalid IL or missing references) //IL_05ea: Unknown result type (might be due to invalid IL or missing references) Random random = new Random(seed); List list = new List(); List list2 = new List(); float num = (1f + Mathf.Sqrt(5f)) * 0.5f; Vector3 val = new Vector3(-1f, num, 0f); list.Add(((Vector3)(ref val)).normalized); Vector3 val2 = new Vector3(1f, num, 0f); list.Add(((Vector3)(ref val2)).normalized); Vector3 val3 = new Vector3(-1f, 0f - num, 0f); list.Add(((Vector3)(ref val3)).normalized); Vector3 val4 = new Vector3(1f, 0f - num, 0f); list.Add(((Vector3)(ref val4)).normalized); Vector3 val5 = new Vector3(0f, -1f, num); list.Add(((Vector3)(ref val5)).normalized); Vector3 val6 = new Vector3(0f, 1f, num); list.Add(((Vector3)(ref val6)).normalized); Vector3 val7 = new Vector3(0f, -1f, 0f - num); list.Add(((Vector3)(ref val7)).normalized); Vector3 val8 = new Vector3(0f, 1f, 0f - num); list.Add(((Vector3)(ref val8)).normalized); Vector3 val9 = new Vector3(num, 0f, -1f); list.Add(((Vector3)(ref val9)).normalized); Vector3 val10 = new Vector3(num, 0f, 1f); list.Add(((Vector3)(ref val10)).normalized); Vector3 val11 = new Vector3(0f - num, 0f, -1f); list.Add(((Vector3)(ref val11)).normalized); Vector3 val12 = new Vector3(0f - num, 0f, 1f); list.Add(((Vector3)(ref val12)).normalized); int[] array = new int[60] { 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 }; for (int i = 0; i < array.Length; i++) { list2.Add(array[i]); } for (int j = 0; j < subdiv; j++) { SubdivideOnce(list, list2); } Vector3[] array2 = (Vector3[])(object)new Vector3[8] { new Vector3(1f, 0.35f, 0.1f), new Vector3(-0.72f, 0.5f, 0.42f), new Vector3(0.2f, -0.9f, 0.3f), new Vector3(-0.4f, -0.5f, -0.85f), new Vector3(0.5f, 0.62f, -0.6f), new Vector3(-0.82f, 0.2f, -0.45f), new Vector3(0.3f, 0.8f, 0.5f), new Vector3(0.75f, -0.45f, -0.5f) }; float[] array3 = new float[8] { 0.17f, 0.15f, 0.14f, 0.16f, 0.13f, 0.14f, 0.12f, 0.11f }; Quaternion val13 = Quaternion.Euler((float)(seed % 360), (float)(seed / 7 % 360), (float)(seed / 13 % 360)); for (int k = 0; k < list.Count; k++) { Vector3 val14 = list[k]; Vector3 val15 = val13 * ((Vector3)(ref val14)).normalized; float num2 = 1f; for (int l = 0; l < array2.Length; l++) { float num3 = Vector3.Dot(val15, ((Vector3)(ref array2[l])).normalized); float num4 = Mathf.Clamp01((num3 - 0.3f) / 0.7f); num4 = num4 * num4 * (3f - 2f * num4); num2 += array3[l] * num4; } list[k] = val15 * num2; } int[] array4 = list2.ToArray(); Vector3[] array5 = (Vector3[])(object)new Vector3[array4.Length]; Vector3[] array6 = (Vector3[])(object)new Vector3[array4.Length]; for (int m = 0; m < array4.Length; m += 3) { Vector3 val16 = list[array4[m]]; Vector3 val17 = list[array4[m + 1]]; Vector3 val18 = list[array4[m + 2]]; Vector3 val19 = Vector3.Cross(val17 - val16, val18 - val16); Vector3 normalized = ((Vector3)(ref val19)).normalized; array5[m] = val16; array6[m] = normalized; array5[m + 1] = val17; array6[m + 1] = normalized; array5[m + 2] = val18; array6[m + 2] = normalized; } int[] array7 = new int[array4.Length]; for (int n = 0; n < array7.Length; n++) { array7[n] = n; } Color[] array8 = (Color[])(object)new Color[array5.Length]; Color val20 = BaseTintFor(seed); Color val21 = default(Color); for (int num5 = 0; num5 < array5.Length; num5 += 3) { float num6 = array6[num5].y * 0.5f + 0.5f; float num7 = ((num6 < 0.3f) ? 0.14f : ((num6 < 0.62f) ? 0.26f : 0.44f)); float num8 = (float)(random.NextDouble() * 0.1 - 0.05); float num9 = Mathf.Clamp01(num7 + num8); ((Color)(ref val21))..ctor(val20.r * num9 * 0.5f, val20.g * num9 * 0.5f, val20.b * num9 * 0.5f, 1f); array8[num5] = val21; array8[num5 + 1] = val21; array8[num5 + 2] = val21; } Mesh val22 = new Mesh(); ((Object)val22).name = "SmokeBlob_" + seed; val22.vertices = array5; val22.normals = array6; val22.colors = array8; val22.triangles = array7; val22.RecalculateBounds(); return val22; } private static Color BaseTintFor(int seed) { //IL_0027: 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_0051: Unknown result type (might be due to invalid IL or missing references) return (Color)(seed switch { 20260809 => new Color(0.42f, 0.4f, 0.37f), 20260810 => new Color(0.38f, 0.38f, 0.4f), _ => new Color(0.34f, 0.34f, 0.36f), }); } private static void SubdivideOnce(List verts, List tris) { Dictionary midMap = new Dictionary(); int count = tris.Count; List list = new List(count * 4); for (int i = 0; i < count; i += 3) { int num = tris[i]; int num2 = tris[i + 1]; int num3 = tris[i + 2]; int item = MidPoint(verts, midMap, num, num2); int item2 = MidPoint(verts, midMap, num2, num3); int item3 = MidPoint(verts, midMap, num3, num); list.Add(num); list.Add(item); list.Add(item3); list.Add(num2); list.Add(item2); list.Add(item); list.Add(num3); list.Add(item3); list.Add(item2); list.Add(item); list.Add(item2); list.Add(item3); } tris.Clear(); tris.AddRange(list); } private static int MidPoint(List verts, Dictionary midMap, int i1, int i2) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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 key = ((i1 < i2) ? ((i1 << 16) | i2) : ((i2 << 16) | i1)); if (midMap.TryGetValue(key, out var value)) { return value; } Vector3 item = (verts[i1] + verts[i2]) * 0.5f; ((Vector3)(ref item)).Normalize(); int count = verts.Count; verts.Add(item); midMap[key] = count; return count; } private static Material MakeBlobMaterial() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[3] { "Particles/Alpha Blended", "Legacy Shaders/Particles/Alpha Blended", "Sprites/Default" }; Shader val = null; for (int i = 0; i < array.Length; i++) { if (!((Object)(object)val == (Object)null)) { break; } val = Shader.Find(array[i]); } if ((Object)(object)val == (Object)null) { return null; } Material val2 = new Material(val); if (val2.HasProperty("_TintColor")) { val2.SetColor("_TintColor", new Color(1f, 1f, 1f, 0.5f)); } else if (val2.HasProperty("_Color")) { val2.SetColor("_Color", new Color(1f, 1f, 1f, 1f)); } return val2; } } public class SmokeBlob : MonoBehaviour { private static readonly int TINT_ID = Shader.PropertyToID("_TintColor"); private static readonly int COLOR_ID = Shader.PropertyToID("_Color"); private Transform[] _puffs; private Renderer[] _renderers; private MaterialPropertyBlock[] _blocks; private int _intPropId = TINT_ID; private bool _live; private float _t0; private float _life; private float _scale; public void Launch(float scale, float life) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) _scale = Mathf.Max(0.001f, scale); _life = Mathf.Max(0.2f, life); _t0 = Time.time; _live = true; if (_puffs == null) { return; } for (int i = 0; i < _puffs.Length; i++) { if ((Object)(object)_puffs[i] != (Object)null) { _puffs[i].localScale = Vector3.one * 0.001f; } } } private void Awake() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown int childCount = ((Component)this).transform.childCount; _puffs = (Transform[])(object)new Transform[childCount]; _renderers = (Renderer[])(object)new Renderer[childCount]; _blocks = (MaterialPropertyBlock[])(object)new MaterialPropertyBlock[childCount]; for (int i = 0; i < childCount; i++) { Transform child = ((Component)this).transform.GetChild(i); _puffs[i] = child; _renderers[i] = (((Object)(object)child != (Object)null) ? ((Component)child).GetComponent() : null); _blocks[i] = new MaterialPropertyBlock(); } Renderer val = ((_renderers.Length > 0) ? _renderers[0] : null); if ((Object)(object)val != (Object)null && (Object)(object)val.sharedMaterial != (Object)null) { if (val.sharedMaterial.HasProperty("_Color") && !val.sharedMaterial.HasProperty("_TintColor")) { _intPropId = COLOR_ID; } else { _intPropId = TINT_ID; } } } private void Update() { //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) if (!_live || _puffs == null || _puffs.Length == 0) { return; } float num = Time.time - _t0; if (num >= _life) { _live = false; ((Component)this).gameObject.SetActive(false); return; } float expandTime = FxPlugin.ExpandTime; float num3; if (num < expandTime) { float num2 = Mathf.Clamp01(num / expandTime); num3 = 0.04f + 0.96f * num2; } else { num3 = Mathf.Exp((0f - FxPlugin.DecayRate) * (num - expandTime)); } float num4 = Mathf.Clamp01(1f - num / _life); for (int i = 0; i < _puffs.Length; i++) { Transform val = _puffs[i]; if ((Object)(object)val == (Object)null) { continue; } float num5 = num - ((i < SmokeMeshFactory.PUFF_DELAY.Length) ? SmokeMeshFactory.PUFF_DELAY[i] : 0f); float num6; float num7; if (num5 <= 0f) { num6 = 0.001f; num7 = 0f; } else { float num8 = num3; float num9 = expandTime; if (num5 < num9) { float num10 = Mathf.Clamp01(num5 / num9); num8 = 0.04f + 0.96f * num10; } else { num8 = Mathf.Exp((0f - FxPlugin.DecayRate) * (num5 - num9)); } num6 = num8 * ((i < SmokeMeshFactory.PUFF_BASE_SCALE.Length) ? SmokeMeshFactory.PUFF_BASE_SCALE[i] : 1f) * _scale; num7 = num4; } val.localScale = new Vector3(num6, num6, num6); Renderer val2 = _renderers[i]; if (!((Object)(object)val2 == (Object)null) && val2.isVisible) { MaterialPropertyBlock val3 = _blocks[i]; val3.SetColor(_intPropId, new Color(1f, 1f, 1f, num7 * 0.5f)); val2.SetPropertyBlock(val3); } } } }