using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExplosiveSprayPaint.Config; using ExplosiveSprayPaint.Networking; using ExplosiveSprayPaint.Patches; using ExplosiveSprayPaint.Utilities; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Collections; 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("ExplosiveSprayPaint")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ExplosiveSprayPaint")] [assembly: AssemblyTitle("ExplosiveSprayPaint")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 ExplosiveSprayPaint { [BepInPlugin("huntedbyacreature.explosivespraypaint", "ExplosiveSprayPaint", "1.1.5")] public sealed class Plugin : BaseUnityPlugin { public const string ModGuid = "huntedbyacreature.explosivespraypaint"; public const string ModName = "ExplosiveSprayPaint"; public const string ModVersion = "1.1.5"; private Harmony? _harmony; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ExplosiveSprayPaintConfig ModConfig { get; private set; } private void Awake() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ModConfig = new ExplosiveSprayPaintConfig(((BaseUnityPlugin)this).Config); _harmony = new Harmony("huntedbyacreature.explosivespraypaint"); SprayPaintItemPatches.Apply(_harmony); _harmony.PatchAll(typeof(Plugin).Assembly); SprayPaintRuntimeWatcher.Register(); SprayCanExplosionNetworking.Register(); Log.LogInfo((object)string.Format("{0} {1} loaded. DebugLogging={2}, TreatSprayUseAsShake={3}, GlowInTheDarkPaint={4}, FunnyExplosionPhysics={5}, ExplosionChance={6:0.##}%.", "ExplosiveSprayPaint", "1.1.5", ModConfig.EnableDebugLogging.Value, ModConfig.TreatSprayUseAsShake.Value, ModConfig.GlowInTheDarkPaint.Value, ModConfig.EnableFunnyExplosionPhysics.Value, ModConfig.ExplosionChancePercent.Value)); } private void Update() { SprayPaintRuntimeWatcher.Tick(); } private void OnDestroy() { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"Plugin component OnDestroy called; leaving runtime hooks active for this session."); } } } } namespace ExplosiveSprayPaint.Utilities { internal static class ExplosionEffectUtility { private const int EnemyCollisionMask = 524288; private const float FunnyNormalPhysicsForce = 35f; private const float FunnyCatastrophicPhysicsForce = 85f; private const float FunnyNormalPlayerKnockback = 13f; private const float FunnyCatastrophicPlayerKnockback = 32f; private const float FunnyNormalVerticalKnockback = 5f; private const float FunnyCatastrophicVerticalKnockback = 12f; internal static Vector3 GetExplosionPosition(SprayPaintItem sprayPaintItem) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_0033: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)sprayPaintItem).transform; PlayerControllerB playerHeldBy = ((GrabbableObject)sprayPaintItem).playerHeldBy; if ((Object)(object)playerHeldBy != (Object)null) { if (!((Object)(object)playerHeldBy.gameplayCamera != (Object)null)) { return ((Component)playerHeldBy).transform.position + Vector3.up * 1.2f + ((Component)playerHeldBy).transform.forward * 0.35f; } return ((Component)playerHeldBy.gameplayCamera).transform.position + ((Component)playerHeldBy.gameplayCamera).transform.forward * 0.35f - Vector3.up * 0.25f; } return transform.position; } internal static void PlayClientSideExplosion(ExplosionMessage message, SprayPaintItem? sprayPaintItem) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (Plugin.ModConfig.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)$"Playing client explosion. catastrophic={message.Catastrophic}, blastRadius={message.BlastRadius:0.00}, paintRadius={message.PaintRadius:0.00}, paintCount={message.PaintCount}, color={ColorUtility.ToHtmlStringRGBA(message.PaintColor)}, hasSprayItem={(Object)(object)sprayPaintItem != (Object)null}."); } TrySpawnVanillaExplosion(message.Position, message.BlastRadius, message.PhysicsForce); PaintDecalUtility.SpawnPaintBurst(sprayPaintItem, message.Position, message.PaintColor, message.PaintRadius, message.PaintCount, message.RandomSeed); ParticleUtility.SpawnPaintParticles(message.Position, message.PaintColor, message.BlastRadius, message.Catastrophic); TryShakeCamera(message.Position, message.BlastRadius, message.Catastrophic); TryShowHudNotification(message); } internal static void ApplyServerSideDamageAndNoise(ExplosionMessage message) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) float blastRadius = message.BlastRadius; int damage = (message.Catastrophic ? Plugin.ModConfig.CatastrophicPlayerDamage.Value : Plugin.ModConfig.NormalPlayerDamage.Value); int damage2 = (message.Catastrophic ? Plugin.ModConfig.CatastrophicEnemyDamage.Value : Plugin.ModConfig.NormalEnemyDamage.Value); DamageNearbyPlayers(message.Position, blastRadius, damage, message.Catastrophic); DamageNearbyEnemies(message.Position, blastRadius, damage2); RoundManager instance = RoundManager.Instance; if (instance != null) { instance.PlayAudibleNoise(message.Position, message.Catastrophic ? (blastRadius * 2.5f) : (blastRadius * 1.6f), message.Catastrophic ? 1f : 0.55f, 0, false, 0); } } private static void TrySpawnVanillaExplosion(Vector3 position, float radius, float physicsForce) { //IL_018b: Unknown result type (might be due to invalid IL or missing references) try { MethodInfo methodInfo = AccessTools.Method(typeof(Landmine), "SpawnExplosion", (Type[])null, (Type[])null); if (methodInfo == null) { return; } ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { string text = parameters[i].Name ?? string.Empty; object[] array2 = array; int num = i; object obj; switch (text) { case "explosionPosition": case "position": obj = position; break; case "spawnExplosionEffect": obj = true; break; case "killRange": obj = 0f; break; case "damageRange": obj = radius; break; case "nonLethalDamage": case "damage": obj = 0; break; case "physicsForce": obj = physicsForce; break; case "overridePrefab": obj = null; break; case "goThroughCar": obj = true; break; default: obj = (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : GetDefaultValue(parameters[i].ParameterType)); break; } array2[num] = obj; } methodInfo.Invoke(null, array); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not spawn vanilla explosion effect: " + ex.Message)); } } private static void DamageNearbyPlayers(Vector3 position, float radius, int damage, bool catastrophic) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) if (damage <= 0 || StartOfRound.Instance?.allPlayerScripts == null) { return; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val == (Object)null || !val.isPlayerControlled || val.isPlayerDead) { continue; } float num = Vector3.Distance(position, ((Component)val).transform.position); if (!(num > radius)) { float num2 = Mathf.Clamp01(1f - num / Mathf.Max(radius, 0.01f)); int damage2 = Mathf.Max(1, Mathf.RoundToInt((float)damage * Mathf.Lerp(0.45f, 1f, num2))); Vector3 val2 = ((Component)val).transform.position - position; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.001f) { val2 = ((Component)val).transform.forward; } float num3 = (catastrophic ? GetCatastrophicPlayerKnockback() : GetNormalPlayerKnockback()); Vector3 val3 = ((Vector3)(ref val2)).normalized * num3; val3.y = GetVerticalPlayerKnockback(catastrophic); try { InvokeDamagePlayer(val, damage2, val3); SprayPaintIntrospection.AddExternalForce(val, Plugin.ModConfig.EnableFunnyExplosionPhysics.Value ? val3 : ClampPlayerForce(val3)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not damage player " + val.playerUsername + ": " + ex.Message)); } } } } private static void DamageNearbyEnemies(Vector3 position, float radius, int damage) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (damage <= 0) { return; } HashSet hashSet = new HashSet(); Collider[] array = Physics.OverlapSphere(position, radius, 524288, (QueryTriggerInteraction)2); for (int i = 0; i < array.Length; i++) { EnemyAI componentInParent = ((Component)array[i]).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && !componentInParent.isEnemyDead && hashSet.Add(componentInParent)) { try { InvokeHitEnemy(componentInParent, damage); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not damage enemy " + componentInParent.enemyType?.enemyName + ": " + ex.Message)); } } } } private static void TryShakeCamera(Vector3 position, float radius, bool catastrophic) { //IL_003a: 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) if (!Plugin.ModConfig.EnableScreenShake.Value || (Object)(object)GameNetworkManager.Instance?.localPlayerController == (Object)null || Vector3.Distance(((Component)GameNetworkManager.Instance.localPlayerController).transform.position, position) > radius * 1.75f) { return; } try { HUDManager instance = HUDManager.Instance; if (instance != null) { instance.ShakeCamera((ScreenShakeType)catastrophic); } } catch { } } private static void TryShowHudNotification(ExplosionMessage message) { if (!Plugin.ModConfig.EnableHudNotification.Value || (Object)(object)GameNetworkManager.Instance?.localPlayerController == (Object)null || GameNetworkManager.Instance.localPlayerController.actualClientId != message.HolderClientId) { return; } try { HUDManager instance = HUDManager.Instance; if (instance != null) { instance.DisplayTip("Explosive Spray Paint", "The can ruptured!", true, false, "ESP_CanRuptured"); } } catch { } } internal static float GetBlastRadius(bool catastrophic) { return Mathf.Clamp(catastrophic ? Plugin.ModConfig.CatastrophicBlastRadius.Value : Plugin.ModConfig.NormalBlastRadius.Value, 0.5f, catastrophic ? 8f : 4.5f); } internal static float GetPhysicsForce(bool catastrophic) { if (Plugin.ModConfig.EnableFunnyExplosionPhysics.Value) { if (!catastrophic) { return 35f; } return 85f; } return Mathf.Clamp(catastrophic ? Plugin.ModConfig.CatastrophicPhysicsForce.Value : Plugin.ModConfig.NormalPhysicsForce.Value, 0f, catastrophic ? 6f : 3f); } internal static float GetPaintRadius(bool catastrophic) { return Mathf.Clamp(catastrophic ? Plugin.ModConfig.CatastrophicPaintSplatterRadius.Value : Plugin.ModConfig.NormalPaintSplatterRadius.Value, 0.5f, catastrophic ? 12f : 7f); } internal static int GetPaintCount(bool catastrophic) { return Mathf.Clamp(catastrophic ? Plugin.ModConfig.CatastrophicPaintSplats.Value : Plugin.ModConfig.NormalPaintSplats.Value, 0, catastrophic ? 240 : 140); } private static Vector3 ClampPlayerForce(Vector3 force) { //IL_0002: 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_0036: 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_0061: 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: 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 = default(Vector3); ((Vector3)(ref val))..ctor(force.x, 0f, force.z); float num = 3f; if (((Vector3)(ref val)).magnitude > num) { val = ((Vector3)(ref val)).normalized * num; } return new Vector3(val.x, Mathf.Clamp(force.y, -0.1f, Plugin.ModConfig.MaxVerticalKnockback.Value), val.z); } private static float GetNormalPlayerKnockback() { if (!Plugin.ModConfig.EnableFunnyExplosionPhysics.Value) { return Plugin.ModConfig.NormalPlayerKnockback.Value; } return 13f; } private static float GetCatastrophicPlayerKnockback() { if (!Plugin.ModConfig.EnableFunnyExplosionPhysics.Value) { return Plugin.ModConfig.CatastrophicPlayerKnockback.Value; } return 32f; } private static float GetVerticalPlayerKnockback(bool catastrophic) { if (Plugin.ModConfig.EnableFunnyExplosionPhysics.Value) { if (!catastrophic) { return 5f; } return 12f; } return Mathf.Min(Plugin.ModConfig.MaxVerticalKnockback.Value, catastrophic ? 0.7f : 0.35f); } private static void InvokeDamagePlayer(PlayerControllerB player, int damage, Vector3 force) { //IL_0180: Unknown result type (might be due to invalid IL or missing references) MethodInfo methodInfo = AccessTools.Method(typeof(PlayerControllerB), "DamagePlayer", (Type[])null, (Type[])null); if (methodInfo == null) { return; } ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { string text = parameters[i].Name ?? string.Empty; object[] array2 = array; int num = i; object obj; switch (text) { case "damageNumber": case "damage": obj = damage; break; case "hasDamageSFX": obj = true; break; case "callRPC": obj = true; break; case "causeOfDeath": obj = (object)(CauseOfDeath)0; break; case "deathAnimation": obj = 0; break; case "fallDamage": obj = false; break; case "force": obj = force; break; default: obj = (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : GetDefaultValue(parameters[i].ParameterType)); break; } array2[num] = obj; } methodInfo.Invoke(player, array); } private static void InvokeHitEnemy(EnemyAI enemy, int damage) { MethodInfo methodInfo = AccessTools.Method(((object)enemy).GetType(), "HitEnemy", (Type[])null, (Type[])null); if (methodInfo == null) { return; } ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { string text = parameters[i].Name ?? string.Empty; object[] array2 = array; int num = i; object obj; switch (text) { case "force": case "damage": obj = damage; break; case "playerWhoHit": obj = null; break; case "playHitSFX": obj = true; break; case "hitID": obj = -1; break; default: obj = (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : GetDefaultValue(parameters[i].ParameterType)); break; } array2[num] = obj; } methodInfo.Invoke(enemy, array); } private static object? GetDefaultValue(Type type) { if (!type.IsValueType) { return null; } return Activator.CreateInstance(type); } } internal static class PaintDecalUtility { private const float SurfaceOffset = 0.018f; internal static void SpawnPaintBurst(SprayPaintItem? sprayPaintItem, Vector3 origin, Color color, float radius, int count, int seed) { //IL_0193: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0095: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) if (count <= 0 || radius <= 0f) { return; } GameObject val = TryGetPaintPrefab(sprayPaintItem); State state = Random.state; Random.InitState(seed); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = count * 5; LogDebug($"Paint burst starting. origin={origin}, radius={radius:0.00}, targetCount={count}, color={ColorUtility.ToHtmlStringRGBA(color)}, hasSprayItem={(Object)(object)sprayPaintItem != (Object)null}, hasVanillaPrefab={(Object)(object)val != (Object)null}."); try { for (int i = 0; i < num6; i++) { if (num >= count) { break; } if (!TryFindPaintSurface(origin, radius, out var hit)) { num3++; continue; } num2++; float size = Random.Range(0.28f, 0.95f) * ((Random.value < 0.12f) ? 1.45f : 1f); if (Plugin.ModConfig.UseVanillaPaintPlacement.Value && (Object)(object)sprayPaintItem != (Object)null && SprayPaintIntrospection.TryAddVanillaPaint(sprayPaintItem, ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal)) { num4++; } SpawnSingleSplat(val, hit, color, size); num5++; num++; } LogDebug($"Paint burst finished. attempts={num6}, raycastHits={num2}, rejectedHits={num3}, visibleSplats={num}/{count}, vanillaPlacements={num4}, fallbackSplats={num5}."); } finally { Random.state = state; } } private static bool TryFindPaintSurface(Vector3 origin, float radius, out RaycastHit hit) { //IL_0006: 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) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0036: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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) float value = Random.value; Vector2 val = Random.insideUnitCircle * radius; if (value < 0.34f) { return TryRaycastPaintSurface(origin + new Vector3(val.x, 2.2f + Random.Range(0f, 0.7f), val.y), Vector3.down, 5.5f, out hit); } if (value < 0.74f) { Vector2 insideUnitCircle = Random.insideUnitCircle; Vector3 val2 = Vector2.op_Implicit(((Vector2)(ref insideUnitCircle)).normalized); if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { val2 = Vector2.op_Implicit(Vector2.right); } Vector3 val3 = new Vector3(val2.x, Random.Range(-0.2f, 0.35f), val2.y); Vector3 normalized = ((Vector3)(ref val3)).normalized; return TryRaycastPaintSurface(origin + Vector3.up * Random.Range(-0.2f, 1.4f), normalized, radius + 2f, out hit); } Vector3 onUnitSphere = Random.onUnitSphere; if (onUnitSphere.y > 0.75f) { onUnitSphere.y *= -1f; } return TryRaycastPaintSurface(origin + Random.insideUnitSphere * 0.35f, ((Vector3)(ref onUnitSphere)).normalized, radius + 2.5f, out hit); } private static bool TryRaycastPaintSurface(Vector3 origin, Vector3 direction, float distance, out RaycastHit hit) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) RaycastHit[] array = Physics.RaycastAll(origin, ((Vector3)(ref direction)).normalized, distance, -1, (QueryTriggerInteraction)1); Array.Sort(array, (RaycastHit left, RaycastHit right) => ((RaycastHit)(ref left)).distance.CompareTo(((RaycastHit)(ref right)).distance)); RaycastHit[] array2 = array; foreach (RaycastHit val in array2) { if (IsValidPaintSurface(val)) { hit = val; return true; } } hit = default(RaycastHit); return false; } private static bool IsValidPaintSurface(RaycastHit hit) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) Collider collider = ((RaycastHit)(ref hit)).collider; if ((Object)(object)collider == (Object)null || !collider.enabled || collider.isTrigger) { return false; } if ((Object)(object)((Component)collider).GetComponentInParent() != (Object)null || (Object)(object)((Component)collider).GetComponentInParent() != (Object)null || (Object)(object)((Component)collider).GetComponentInParent() != (Object)null) { return false; } Renderer val = ((Component)collider).GetComponent() ?? ((Component)collider).GetComponentInParent() ?? ((Component)collider).GetComponentInChildren(); if ((Object)(object)val == (Object)null || !val.enabled) { return false; } Vector3 normal = ((RaycastHit)(ref hit)).normal; return ((Vector3)(ref normal)).sqrMagnitude > 0.8f; } private static GameObject? TryGetPaintPrefab(SprayPaintItem? sprayPaintItem) { if ((Object)(object)sprayPaintItem == (Object)null) { return null; } return SprayPaintIntrospection.GetObjectField(sprayPaintItem, new string[3] { "sprayPaintPrefab", "paintPrefab", "sprayDecalPrefab" }); } private static void SpawnSingleSplat(GameObject? vanillaPaintPrefab, RaycastHit hit, Color color, float size) { //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) GameObject obj = SpawnFallbackSplat(hit, color, size * Random.Range(0.85f, 1.25f)); ((Object)obj).name = "ExplosiveSprayPaint_VisibleSplat"; obj.AddComponent().Initialize(Plugin.ModConfig.PaintLifetimeSeconds.Value, destroyInstancedMaterials: true); } private static GameObject SpawnFallbackSplat(RaycastHit hit, Color color, float size) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_001a: 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_0028: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ExplosiveSprayPaint_FallbackSplat"); Vector3 normal = ((RaycastHit)(ref hit)).normal; Vector3 normalized = ((Vector3)(ref normal)).normalized; val.transform.position = ((RaycastHit)(ref hit)).point + normalized * 0.018f; val.transform.rotation = SurfaceRotationForQuad(normalized); val.transform.Rotate(Vector3.forward, Random.Range(0f, 360f), (Space)1); val.transform.SetParent(((Component)((RaycastHit)(ref hit)).collider).transform, true); GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)obj).name = "PaintQuad"; obj.transform.SetParent(val.transform, false); obj.transform.localPosition = Vector3.zero; obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = new Vector3(size, size * Random.Range(0.55f, 1.25f), 1f); RemoveColliders(obj); obj.GetComponent().material = CreateQuadMaterial(color, Random.Range(0, int.MaxValue)); return val; } private static Material CreateQuadMaterial(Color color, int seed) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_000b: 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) Material val = new Material(FindPaintShader()); Texture2D val3 = (Texture2D)(object)(val.mainTexture = (Texture)(object)CreateSplatTexture(color, seed)); ApplyColor(val, Color.white); DisableEmission(val); val.renderQueue = 3000; if (val.HasProperty("_SurfaceType")) { val.SetFloat("_SurfaceType", 1f); val.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); } if (val.HasProperty("_BlendMode")) { val.SetFloat("_BlendMode", 0f); } if (val.HasProperty("_SrcBlend")) { val.SetFloat("_SrcBlend", 5f); } if (val.HasProperty("_DstBlend")) { val.SetFloat("_DstBlend", 10f); } if (val.HasProperty("_ZWrite")) { val.SetFloat("_ZWrite", 0f); } if (val.HasProperty("_BaseColorMap")) { val.SetTexture("_BaseColorMap", (Texture)(object)val3); } if (val.HasProperty("_UnlitColorMap")) { val.SetTexture("_UnlitColorMap", (Texture)(object)val3); } if (val.HasProperty("_CullMode")) { val.SetFloat("_CullMode", 0f); } if (val.HasProperty("_Cull")) { val.SetFloat("_Cull", 0f); } return val; } private static Shader FindPaintShader() { if (Plugin.ModConfig.GlowInTheDarkPaint.Value) { return Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Transparent") ?? Shader.Find("HDRP/Unlit") ?? Shader.Find("Standard"); } return Shader.Find("HDRP/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Transparent"); } private static Texture2D CreateSplatTexture(Color color, int seed) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //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_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: 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_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false) { name = "ExplosiveSprayPaint_SplatTexture", wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; State state = Random.state; Random.InitState(seed); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(63f * Random.Range(0.43f, 0.57f), 63f * Random.Range(0.43f, 0.57f)); float num = Random.Range(17f, 25f); float num2 = Random.Range(0.8f, 1.25f); float num3 = Random.Range(0.75f, 1.25f); Vector2 val3 = default(Vector2); for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { ((Vector2)(ref val3))..ctor(((float)j - val2.x) / num2, ((float)i - val2.y) / num3); float magnitude = ((Vector2)(ref val3)).magnitude; float num4 = Mathf.PerlinNoise((float)j * 0.16f + (float)seed * 0.001f, (float)i * 0.16f - (float)seed * 0.001f); float num5 = Mathf.Clamp01((num * Mathf.Lerp(0.72f, 1.22f, num4) - magnitude) / 5.5f); for (int k = 0; k < 5; k++) { float num6 = (float)k / 5f * MathF.PI * 2f + (float)seed * 0.0001f; Vector2 val4 = val2 + new Vector2(Mathf.Cos(num6), Mathf.Sin(num6)) * Random.Range(15f, 27f); float num7 = Vector2.Distance(new Vector2((float)j, (float)i), val4); num5 = Mathf.Max(num5, Mathf.Clamp01((Random.Range(3f, 7f) - num7) / 2f)); } Color val5 = color; val5.a = num5 * 0.94f; val.SetPixel(j, i, val5); } } val.Apply(false, false); Random.state = state; return val; } private static void LogDebug(string message) { if (Plugin.ModConfig.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)message); } } private static void ApplyColor(Material material, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) material.color = color; if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", color); } if (material.HasProperty("_Color")) { material.SetColor("_Color", color); } } private static void DisableEmission(Material material) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) material.DisableKeyword("_EMISSION"); material.DisableKeyword("_EMISSIVE_COLOR_MAP"); if (material.HasProperty("_EmissionColor")) { material.SetColor("_EmissionColor", Color.black); } if (material.HasProperty("_EmissiveColor")) { material.SetColor("_EmissiveColor", Color.black); } if (material.HasProperty("_EmissiveIntensity")) { material.SetFloat("_EmissiveIntensity", 0f); } } private static Quaternion SurfaceRotationForQuad(Vector3 normal) { //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) return Quaternion.LookRotation(normal, GetStableUp(normal)); } private static Vector3 GetStableUp(Vector3 normal) { //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_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0033: 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_001a: 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_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) Vector3 val = Vector3.Cross(normal, Vector3.up); if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = Vector3.Cross(normal, Vector3.right); } Vector3 val2 = Vector3.Cross(((Vector3)(ref val)).normalized, normal); return ((Vector3)(ref val2)).normalized; } private static void RemoveColliders(GameObject gameObject) { Collider[] componentsInChildren = gameObject.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { Object.Destroy((Object)(object)componentsInChildren[i]); } } } internal static class ParticleUtility { internal static void SpawnPaintParticles(Vector3 position, Color paintColor, float radius, bool catastrophic) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Expected O, but got Unknown GameObject val = new GameObject("ExplosiveSprayPaint_Particles"); val.transform.position = position; ParticleSystem obj = val.AddComponent(); MainModule main = obj.main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(paintColor); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(catastrophic ? 1.3f : 0.8f); ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(catastrophic ? 12f : 6f); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(catastrophic ? 0.22f : 0.12f); ((MainModule)(ref main)).maxParticles = (catastrophic ? 450 : 180); ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; EmissionModule emission = obj.emission; ((EmissionModule)(ref emission)).enabled = false; ShapeModule shape = obj.shape; ((ShapeModule)(ref shape)).enabled = true; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape)).radius = 0.25f; CollisionModule collision = obj.collision; ((CollisionModule)(ref collision)).enabled = true; ((CollisionModule)(ref collision)).type = (ParticleSystemCollisionType)1; ((CollisionModule)(ref collision)).dampen = MinMaxCurve.op_Implicit(0.55f); ((CollisionModule)(ref collision)).bounce = MinMaxCurve.op_Implicit(0.15f); ((CollisionModule)(ref collision)).lifetimeLoss = MinMaxCurve.op_Implicit(0.35f); ParticleSystemRenderer component = ((Component)obj).GetComponent(); component.renderMode = (ParticleSystemRenderMode)0; ((Renderer)component).material = new Material(Shader.Find("Sprites/Default")); obj.Emit(catastrophic ? 160 : 65); val.AddComponent().Initialize(catastrophic ? 4f : 2.5f, destroyInstancedMaterials: true); } } internal static class SprayPaintIntrospection { private const int TextureSampleSize = 16; private static readonly string[] ColorPropertyNames = new string[4] { "_BaseColor", "_Color", "_TintColor", "_EmissionColor" }; private static readonly string[] TexturePropertyNames = new string[6] { "_BaseColorMap", "_MainTex", "_UnlitColorMap", "_BaseMap", "_DecalColorMap", "_EmissionMap" }; internal static Color GetCurrentSprayColor(SprayPaintItem sprayPaintItem) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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) int valueOrDefault = TryReadInt(sprayPaintItem, "sprayCanMatsIndex", "sprayPaintColorIndex", "colorIndex", "materialIndex").GetValueOrDefault(-1); if (TryGetIndexedMaterialColor(sprayPaintItem, valueOrDefault, "particleMats", new string[4] { "particleMats", "sprayParticleMats", "sprayPaintParticleMaterials", "particleMaterials" }, out Color color, out string source)) { return LogResolvedColor(sprayPaintItem, color, valueOrDefault, source); } Color? val = TryReadColor(sprayPaintItem, "sprayPaintColor", "currentColor", "paintColor", "sprayColor"); if (val.HasValue) { return LogResolvedColor(sprayPaintItem, val.Value, valueOrDefault, "direct color field"); } if (TryGetIndexedMaterialColor(sprayPaintItem, valueOrDefault, "sprayCanMats", new string[3] { "sprayCanMats", "sprayPaintMaterials", "sprayCanMaterials" }, out Color color2, out string source2)) { return LogResolvedColor(sprayPaintItem, color2, valueOrDefault, source2); } if (TryGetRendererColor(sprayPaintItem, out Color color3, out string source3)) { return LogResolvedColor(sprayPaintItem, color3, valueOrDefault, source3); } return LogResolvedColor(sprayPaintItem, Color.magenta, valueOrDefault, "fallback magenta"); } internal static T? GetObjectField(object instance, params string[] names) where T : class { Type type = instance.GetType(); foreach (string text in names) { if (AccessTools.Field(type, text)?.GetValue(instance) is T result) { return result; } PropertyInfo propertyInfo = AccessTools.Property(type, text); if ((object)propertyInfo != null && propertyInfo.CanRead && propertyInfo.GetValue(instance) is T result2) { return result2; } } return null; } internal static float? GetFloatField(object instance, params string[] names) { Type type = instance.GetType(); foreach (string text in names) { object obj = AccessTools.Field(type, text)?.GetValue(instance); if (obj is float) { return (float)obj; } PropertyInfo propertyInfo = AccessTools.Property(type, text); object obj2 = (((object)propertyInfo != null && propertyInfo.CanRead) ? propertyInfo.GetValue(instance) : null); if (obj2 is float) { return (float)obj2; } } return null; } internal static bool? GetBoolField(object instance, params string[] names) { Type type = instance.GetType(); foreach (string text in names) { object obj = AccessTools.Field(type, text)?.GetValue(instance); if (obj is bool) { return (bool)obj; } PropertyInfo propertyInfo = AccessTools.Property(type, text); object obj2 = (((object)propertyInfo != null && propertyInfo.CanRead) ? propertyInfo.GetValue(instance) : null); if (obj2 is bool) { return (bool)obj2; } } return null; } internal static void DestroySprayCanSafely(SprayPaintItem sprayPaintItem) { try { StopSprayingSafely(sprayPaintItem); if ((Object)(object)((GrabbableObject)sprayPaintItem).playerHeldBy != (Object)null) { MethodInfo methodInfo = AccessTools.Method(((object)sprayPaintItem).GetType(), "DestroyObjectInHand", (Type[])null, (Type[])null); if (methodInfo != null) { ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { array[i] = ((i == 0) ? ((GrabbableObject)sprayPaintItem).playerHeldBy : (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : GetDefaultValue(parameters[i].ParameterType))); } methodInfo.Invoke(sprayPaintItem, array); return; } } NetworkObject networkObject = ((NetworkBehaviour)sprayPaintItem).NetworkObject; if ((Object)(object)networkObject != (Object)null && networkObject.IsSpawned) { networkObject.Despawn(true); } else { Object.Destroy((Object)(object)((Component)sprayPaintItem).gameObject); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not destroy ruptured spray can through normal path: " + ex.Message)); try { Object.Destroy((Object)(object)((Component)sprayPaintItem).gameObject); } catch { } } } internal static void StopSprayingSafely(SprayPaintItem sprayPaintItem) { try { AccessTools.Method(((object)sprayPaintItem).GetType(), "StopSpraying", (Type[])null, (Type[])null)?.Invoke(sprayPaintItem, Array.Empty()); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not call StopSpraying before rupture cleanup: " + ex.Message)); } TrySetBoolField(sprayPaintItem, false, "isSpraying", "tryingToUseEmptyCan", "makingAudio"); AudioSource objectField = GetObjectField(sprayPaintItem, new string[1] { "sprayAudio" }); if ((Object)(object)objectField != (Object)null) { objectField.Stop(); } ParticleSystem objectField2 = GetObjectField(sprayPaintItem, new string[2] { "sprayParticle", "sprayCanNeedsShakingParticle" }); if ((Object)(object)objectField2 != (Object)null) { objectField2.Stop(true, (ParticleSystemStopBehavior)0); } } internal static bool TryAddVanillaPaint(SprayPaintItem sprayPaintItem, Vector3 point, Vector3 normal) { //IL_0024: 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_0031: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) try { MethodInfo methodInfo = AccessTools.Method(((object)sprayPaintItem).GetType(), "AddSprayPaintLocal", (Type[])null, (Type[])null); if (methodInfo == null) { return false; } Vector3 val = point + ((Vector3)(ref normal)).normalized * 0.45f; Vector3 val2 = -((Vector3)(ref normal)).normalized; object obj = methodInfo.Invoke(sprayPaintItem, new object[2] { val, val2 }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch (Exception ex) { if (Plugin.ModConfig.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)("Vanilla paint placement failed: " + ex.Message)); } return false; } } internal static void AddExternalForce(PlayerControllerB player, Vector3 force) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) try { FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerControllerB), "externalForces"); if (!(fieldInfo == null) && !(fieldInfo.FieldType != typeof(Vector3))) { Vector3 val = (Vector3)fieldInfo.GetValue(player); fieldInfo.SetValue(player, val + force); } } catch { } } private static Color? TryReadColor(object instance, params string[] names) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00b4: Unknown result type (might be due to invalid IL or missing references) Type type = instance.GetType(); foreach (string text in names) { object obj = AccessTools.Field(type, text)?.GetValue(instance); if (obj is Color) { return (Color)obj; } if (obj is Color32 val) { return Color32.op_Implicit(val); } PropertyInfo propertyInfo = AccessTools.Property(type, text); object obj2 = (((object)propertyInfo != null && propertyInfo.CanRead) ? propertyInfo.GetValue(instance) : null); if (obj2 is Color) { return (Color)obj2; } if (obj2 is Color32 val2) { return Color32.op_Implicit(val2); } } return null; } private static int? TryReadInt(object instance, params string[] names) { Type type = instance.GetType(); foreach (string text in names) { object obj = AccessTools.Field(type, text)?.GetValue(instance); if (obj is int) { return (int)obj; } PropertyInfo propertyInfo = AccessTools.Property(type, text); object obj2 = (((object)propertyInfo != null && propertyInfo.CanRead) ? propertyInfo.GetValue(instance) : null); if (obj2 is int) { return (int)obj2; } } return null; } private static void TrySetBoolField(object instance, bool value, params string[] names) { Type type = instance.GetType(); foreach (string text in names) { FieldInfo fieldInfo = AccessTools.Field(type, text); if (fieldInfo != null && fieldInfo.FieldType == typeof(bool)) { fieldInfo.SetValue(instance, value); } } } private static bool TryGetIndexedMaterialColor(SprayPaintItem sprayPaintItem, int colorIndex, string fieldLabel, string[] fieldNames, out Color color, out string source) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) color = default(Color); source = string.Empty; Material[] objectField = GetObjectField(sprayPaintItem, fieldNames); if (objectField == null || colorIndex < 0 || colorIndex >= objectField.Length || (Object)(object)objectField[colorIndex] == (Object)null) { return false; } Material val = objectField[colorIndex]; if (!TryResolveMaterialPaintColor(val, out color, out string source2)) { return false; } source = $"{fieldLabel}[{colorIndex}] {source2} ({((Object)val).name})"; return true; } private static bool TryGetRendererColor(SprayPaintItem sprayPaintItem, out Color color, out string source) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) color = default(Color); source = string.Empty; Renderer[] componentsInChildren = ((Component)sprayPaintItem).GetComponentsInChildren(); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || val.sharedMaterials == null) { continue; } Material[] sharedMaterials = val.sharedMaterials; foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null) && TryResolveMaterialPaintColor(val2, out color, out string source2)) { source = "renderer material " + source2 + " (" + ((Object)val2).name + ")"; return true; } } } return false; } private static bool TryResolveMaterialPaintColor(Material material, out Color color, out string source) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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) if (TryAverageMaterialTexture(material, out color, out source)) { return true; } string[] colorPropertyNames = ColorPropertyNames; foreach (string text in colorPropertyNames) { if (!material.HasProperty(text)) { continue; } try { color = NormalizePaintColor(material.GetColor(text)); if (IsUsefulPaintColor(color)) { source = text + " color"; return true; } } catch { } } try { color = NormalizePaintColor(material.color); if (IsUsefulPaintColor(color)) { source = "material.color"; return true; } } catch { } color = default(Color); source = string.Empty; return false; } private static bool TryAverageMaterialTexture(Material material, out Color color, out string source) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) color = default(Color); source = string.Empty; string[] texturePropertyNames = TexturePropertyNames; foreach (string text in texturePropertyNames) { if (material.HasProperty(text)) { Texture texture; try { texture = material.GetTexture(text); } catch { continue; } if (!((Object)(object)texture == (Object)null) && TryAverageTexture(texture, out color) && IsUsefulPaintColor(color)) { source = text + " texture average"; return true; } } } return false; } private static bool TryAverageTexture(Texture texture, out Color color) { Texture2D val = (Texture2D)(object)((texture is Texture2D) ? texture : null); if (val != null && TryAverageReadableTexture(val, out color)) { return true; } return TryAverageTextureWithRenderTexture(texture, out color); } private static bool TryAverageReadableTexture(Texture2D texture, out Color color) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) try { return TryAverageReadableTexturePixels(texture, out color); } catch { color = default(Color); return false; } } private static bool TryAverageTextureWithRenderTexture(Texture texture, out Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0029: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) color = default(Color); RenderTexture active = RenderTexture.active; RenderTexture val = null; Texture2D val2 = null; try { val = RenderTexture.GetTemporary(16, 16, 0, (RenderTextureFormat)0); val2 = new Texture2D(16, 16, (TextureFormat)4, false); Graphics.Blit(texture, val); RenderTexture.active = val; val2.ReadPixels(new Rect(0f, 0f, 16f, 16f), 0, 0); val2.Apply(false, false); return TryAverageReadableTexturePixels(val2, out color); } catch { color = default(Color); return false; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { RenderTexture.ReleaseTemporary(val); } if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } } } private static bool TryAverageReadableTexturePixels(Texture2D texture, out Color color) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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_00b2: 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) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) float num = 0f; float num2 = 0f; float num3 = 0f; float num4 = 0f; for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { Color pixelBilinear = texture.GetPixelBilinear(((float)j + 0.5f) / 16f, ((float)i + 0.5f) / 16f); float num5 = Mathf.Clamp01(pixelBilinear.a); if (!(num5 < 0.08f)) { num2 += pixelBilinear.r * num5; num3 += pixelBilinear.g * num5; num4 += pixelBilinear.b * num5; num += num5; } } } if (num <= 0.001f) { color = default(Color); return false; } color = NormalizePaintColor(new Color(num2 / num, num3 / num, num4 / num, 1f)); return true; } private static Color NormalizePaintColor(Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0038: 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) //IL_005c: Unknown result type (might be due to invalid IL or missing references) color.r = Mathf.Clamp01(color.r); color.g = Mathf.Clamp01(color.g); color.b = Mathf.Clamp01(color.b); color.a = ((color.a < 0.2f) ? 1f : Mathf.Clamp01(color.a)); return color; } private static bool IsUsefulPaintColor(Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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) //IL_001d: 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_0029: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(color.r, Mathf.Max(color.g, color.b)); float num2 = Mathf.Min(color.r, Mathf.Min(color.g, color.b)); float num3 = ((num <= 0.001f) ? 0f : ((num - num2) / num)); if (num > 0.05f) { if (num > 0.92f) { return !(num3 < 0.08f); } return true; } return false; } private static Color LogResolvedColor(SprayPaintItem sprayPaintItem, Color color, int colorIndex, string source) { //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_0006: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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) Color val = NormalizePaintColor(color); if (Plugin.ModConfig.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)("Resolved spray paint color " + ColorUtility.ToHtmlStringRGBA(val) + " from " + source + "; " + string.Format("sprayCanMatsIndex={0}, {1}, {2}.", colorIndex, DescribeSelectedMaterial(sprayPaintItem, "particleMats", colorIndex), DescribeSelectedMaterial(sprayPaintItem, "sprayCanMats", colorIndex)))); } return val; } private static string DescribeSelectedMaterial(SprayPaintItem sprayPaintItem, string fieldName, int colorIndex) { Material[] objectField = GetObjectField(sprayPaintItem, new string[1] { fieldName }); if (objectField == null) { return fieldName + "=missing"; } if (colorIndex < 0 || colorIndex >= objectField.Length) { return $"{fieldName}=index {colorIndex} outside {objectField.Length}"; } Material val = objectField[colorIndex]; if (!((Object)(object)val == (Object)null)) { return $"{fieldName}[{colorIndex}]={((Object)val).name}"; } return $"{fieldName}[{colorIndex}]=null"; } private static object? GetDefaultValue(Type type) { if (!type.IsValueType) { return null; } return Activator.CreateInstance(type); } } internal static class SprayPaintRuntimeWatcher { [CompilerGenerated] private static class <>O { public static LogCallback <0>__OnUnityLogMessageReceived; } private static SprayPaintItem? _lastSprayPaintItem; private static int _lastInstanceId; private static float _lastShakeMeter = -1f; private static bool _lastIsSpraying; private static float _nextDebugLogTime; private static float _lastLogFallbackTriggerTime = -10f; private static bool _registered; internal static void Register() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if (!_registered) { object obj = <>O.<0>__OnUnityLogMessageReceived; if (obj == null) { LogCallback val = OnUnityLogMessageReceived; <>O.<0>__OnUnityLogMessageReceived = val; obj = (object)val; } Application.logMessageReceived += (LogCallback)obj; _registered = true; LogDebug("Runtime watcher registered on plugin update loop and Unity log fallback."); } } internal static void Unregister() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if (_registered) { object obj = <>O.<0>__OnUnityLogMessageReceived; if (obj == null) { LogCallback val = OnUnityLogMessageReceived; <>O.<0>__OnUnityLogMessageReceived = val; obj = (object)val; } Application.logMessageReceived -= (LogCallback)obj; _registered = false; LogDebug("Runtime watcher unregistered."); } } internal static void Tick() { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; SprayPaintItem val2 = SprayPaintItemPatches.FindLocalHeldSprayPaint(); if ((Object)(object)val2 == (Object)null) { ClearHeldItem(); return; } int instanceID = ((Object)val2).GetInstanceID(); float valueOrDefault = SprayPaintIntrospection.GetFloatField(val2, "sprayCanShakeMeter").GetValueOrDefault(-1f); bool valueOrDefault2 = SprayPaintIntrospection.GetBoolField(val2, "isSpraying").GetValueOrDefault(); if ((Object)(object)_lastSprayPaintItem != (Object)(object)val2 || _lastInstanceId != instanceID) { _lastSprayPaintItem = val2; _lastInstanceId = instanceID; _lastShakeMeter = valueOrDefault; _lastIsSpraying = valueOrDefault2; object[] obj = new object[4] { instanceID, null, null, null }; NetworkObject networkObject = ((NetworkBehaviour)val2).NetworkObject; obj[1] = ((networkObject != null) ? networkObject.NetworkObjectId.ToString() : null) ?? "none"; obj[2] = valueOrDefault; obj[3] = valueOrDefault2; LogDebug(string.Format("Runtime watcher tracking held SprayPaintItem. instance={0}, objectId={1}, shakeMeter={2:0.00}, isSpraying={3}.", obj)); return; } if (valueOrDefault >= 0f && _lastShakeMeter >= 0f && valueOrDefault - _lastShakeMeter >= 0.03f) { SprayPaintItemPatches.ReportShake(val2, $"runtime watcher shake meter {_lastShakeMeter:0.00}->{valueOrDefault:0.00}"); } if (Plugin.ModConfig.EnableDebugLogging.Value && Time.unscaledTime >= _nextDebugLogTime) { _nextDebugLogTime = Time.unscaledTime + 5f; object[] obj2 = new object[5] { instanceID, null, null, null, null }; NetworkObject networkObject2 = ((NetworkBehaviour)val2).NetworkObject; obj2[1] = ((networkObject2 != null) ? networkObject2.NetworkObjectId.ToString() : null) ?? "none"; obj2[2] = valueOrDefault; obj2[3] = valueOrDefault2; obj2[4] = (Object)(object)((GrabbableObject)val2).playerHeldBy == (Object)(object)val; LogDebug(string.Format("Runtime watcher heartbeat. instance={0}, objectId={1}, shakeMeter={2:0.00}, isSpraying={3}, heldByLocal={4}.", obj2)); } _lastShakeMeter = valueOrDefault; _lastIsSpraying = valueOrDefault2; } private static void OnUnityLogMessageReceived(string condition, string stackTrace, LogType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)type == 3 && (condition.StartsWith("interact False") || condition == "secondary use G") && !(Time.unscaledTime - _lastLogFallbackTriggerTime < 0.25f)) { _lastLogFallbackTriggerTime = Time.unscaledTime; SprayPaintItem val = SprayPaintItemPatches.FindLocalHeldSprayPaint(); if ((Object)(object)val == (Object)null) { LogDebug("Unity log fallback saw '" + condition + "', but could not find a locally held SprayPaintItem."); } else { SprayPaintItemPatches.ReportShake(val, "Unity log fallback '" + condition + "'"); } } } private static void ClearHeldItem() { if ((Object)(object)_lastSprayPaintItem != (Object)null) { LogDebug("Runtime watcher stopped tracking SprayPaintItem because the local player is no longer holding one."); } _lastSprayPaintItem = null; _lastInstanceId = 0; _lastShakeMeter = -1f; _lastIsSpraying = false; } private static void LogDebug(string message) { if (Plugin.ModConfig.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)message); } } } internal sealed class TemporaryObject : MonoBehaviour { private bool _destroyInstancedMaterials; internal void Initialize(float lifetimeSeconds, bool destroyInstancedMaterials) { _destroyInstancedMaterials = destroyInstancedMaterials; ((MonoBehaviour)this).StartCoroutine(DestroyAfterDelay(lifetimeSeconds)); } private IEnumerator DestroyAfterDelay(float lifetimeSeconds) { yield return (object)new WaitForSeconds(lifetimeSeconds); if ((Object)(object)this != (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void OnDestroy() { if (!_destroyInstancedMaterials) { return; } Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val.material != (Object)null) { Texture mainTexture = val.material.mainTexture; if ((Object)(object)mainTexture != (Object)null && ((Object)mainTexture).name.StartsWith("ExplosiveSprayPaint_")) { Object.Destroy((Object)(object)mainTexture); } Object.Destroy((Object)(object)val.material); } } DecalProjector[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(); foreach (DecalProjector val2 in componentsInChildren2) { if ((Object)(object)val2.material != (Object)null) { Object.Destroy((Object)(object)val2.material); } } } } } namespace ExplosiveSprayPaint.Patches { internal static class NetworkLifecyclePatches { [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] private static void RegisterMessagesAfterConnect() { SprayCanExplosionNetworking.Register(); } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] private static void ClearRoundStateOnStart() { ExplosionState.Reset(); } } internal static class SprayPaintItemPatches { internal const float ShakeMeterIncreaseThreshold = 0.03f; internal static void Apply(Harmony harmony) { Patch(harmony, "ItemInteractLeftRight", null, "DetectShake"); Patch(harmony, "ItemActivate", null, "DetectOptionalSprayUse"); Patch(harmony, "LateUpdate", "CaptureShakeMeterBeforeLateUpdate", "DetectShakeMeterIncrease"); Patch(harmony, "Start", null, "LogSprayPaintStart"); Patch(harmony, typeof(PlayerControllerB), "Update", null, "TickRuntimeWatcherFromPlayerUpdate"); } private static void Patch(Harmony harmony, string originalName, string? prefixName = null, string? postfixName = null) { Patch(harmony, typeof(SprayPaintItem), originalName, prefixName, postfixName); } private static void Patch(Harmony harmony, Type originalType, string originalName, string? prefixName = null, string? postfixName = null) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) MethodInfo methodInfo = AccessTools.Method(originalType, originalName, (Type[])null, (Type[])null); if (methodInfo == null) { Plugin.Log.LogError((object)("Could not find " + originalType.Name + "." + originalName + "; this mod cannot detect that action.")); return; } HarmonyMethod val = ((prefixName == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(typeof(SprayPaintItemPatches), prefixName, (Type[])null, (Type[])null))); HarmonyMethod val2 = ((postfixName == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(typeof(SprayPaintItemPatches), postfixName, (Type[])null, (Type[])null))); harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); int num = patchInfo?.Prefixes.Count((Patch patch) => patch.owner == "huntedbyacreature.explosivespraypaint") ?? 0; int num2 = patchInfo?.Postfixes.Count((Patch patch) => patch.owner == "huntedbyacreature.explosivespraypaint") ?? 0; Plugin.Log.LogInfo((object)$"Patch check: {originalType.Name}.{originalName} prefixes={num}, postfixes={num2}."); } private static void DetectShake(SprayPaintItem __instance, bool right) { if (!right) { ReportShake(__instance, "ItemInteractLeftRight(false)"); } } private static void DetectOptionalSprayUse(SprayPaintItem __instance, bool used, bool buttonDown) { LogDebug($"ItemActivate observed. used={used}, buttonDown={buttonDown}; spraying is safe and does not roll explosions."); } private static void CaptureShakeMeterBeforeLateUpdate(SprayPaintItem __instance, out float __state) { __state = SprayPaintIntrospection.GetFloatField(__instance, "sprayCanShakeMeter").GetValueOrDefault(-1f); } private static void DetectShakeMeterIncrease(SprayPaintItem __instance, float __state) { if (!(__state < 0f)) { float valueOrDefault = SprayPaintIntrospection.GetFloatField(__instance, "sprayCanShakeMeter").GetValueOrDefault(__state); if (valueOrDefault - __state >= 0.03f) { ReportShake(__instance, $"sprayCanShakeMeter increased {__state:0.00}->{valueOrDefault:0.00}"); } } } private static void LogSprayPaintStart(SprayPaintItem __instance) { NetworkObject networkObject = ((NetworkBehaviour)__instance).NetworkObject; LogDebug("SprayPaintItem started. objectId=" + (((networkObject != null) ? networkObject.NetworkObjectId.ToString() : null) ?? "none") + ", shakeMeter=" + (SprayPaintIntrospection.GetFloatField(__instance, "sprayCanShakeMeter")?.ToString("0.00") ?? "unknown")); } private static void TickRuntimeWatcherFromPlayerUpdate() { SprayPaintRuntimeWatcher.Tick(); } internal static void ReportShake(SprayPaintItem sprayPaintItem, string source) { if ((Object)(object)sprayPaintItem == (Object)null || (Object)(object)((GrabbableObject)sprayPaintItem).playerHeldBy == (Object)null) { LogDebug("Ignoring " + source + " because the spray can is not held."); return; } if (SprayPaintIntrospection.GetBoolField(sprayPaintItem, "isSpraying").GetValueOrDefault()) { LogDebug("Ignoring " + source + " because the can is actively spraying. Spraying paint is safe; only shaking can rupture it."); return; } if (!IsHeldByLocalPlayer(((GrabbableObject)sprayPaintItem).playerHeldBy)) { object arg = ((GrabbableObject)sprayPaintItem).playerHeldBy.actualClientId; NetworkManager singleton = NetworkManager.Singleton; LogDebug(string.Format("Ignoring {0} because the holder is not the local player. holder={1}, local={2}.", source, arg, ((singleton != null) ? singleton.LocalClientId.ToString() : null) ?? "none")); return; } string[] obj = new string[6] { "Detected local spray can shake via ", source, ". holder=", ((GrabbableObject)sprayPaintItem).playerHeldBy.playerUsername, ", objectId=", null }; NetworkObject networkObject = ((NetworkBehaviour)sprayPaintItem).NetworkObject; obj[5] = ((networkObject != null) ? networkObject.NetworkObjectId.ToString() : null) ?? "none"; LogDebug(string.Concat(obj)); SprayCanExplosionNetworking.ReportLocalShake(sprayPaintItem); } internal static SprayPaintItem? FindLocalHeldSprayPaint() { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return null; } GrabbableObject currentlyHeldObjectServer = val.currentlyHeldObjectServer; SprayPaintItem val2 = (SprayPaintItem)(object)((currentlyHeldObjectServer is SprayPaintItem) ? currentlyHeldObjectServer : null); if (val2 != null) { return val2; } SprayPaintItem[] array = Object.FindObjectsOfType(); foreach (SprayPaintItem val3 in array) { if (!((Object)(object)val3 == (Object)null) && !((Object)(object)((GrabbableObject)val3).playerHeldBy == (Object)null) && ((Object)(object)((GrabbableObject)val3).playerHeldBy == (Object)(object)val || IsHeldByLocalPlayer(((GrabbableObject)val3).playerHeldBy))) { return val3; } } return null; } internal static bool IsHeldByLocalPlayer(PlayerControllerB holder) { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val != (Object)null && (Object)(object)holder == (Object)(object)val) { return true; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.IsListening) { return holder.actualClientId == singleton.LocalClientId; } return ((NetworkBehaviour)holder).IsOwner; } internal static void LogDebug(string message) { if (Plugin.ModConfig.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)message); } } } } namespace ExplosiveSprayPaint.Networking { internal readonly struct ExplosionMessage { internal readonly ulong SprayCanNetworkObjectId; internal readonly ulong HolderClientId; internal readonly Vector3 Position; internal readonly Color PaintColor; internal readonly bool Catastrophic; internal readonly int RandomSeed; internal readonly float BlastRadius; internal readonly float PhysicsForce; internal readonly float PaintRadius; internal readonly int PaintCount; internal ExplosionMessage(ulong sprayCanNetworkObjectId, ulong holderClientId, Vector3 position, Color paintColor, bool catastrophic, int randomSeed, float blastRadius, float physicsForce, float paintRadius, int paintCount) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) SprayCanNetworkObjectId = sprayCanNetworkObjectId; HolderClientId = holderClientId; Position = position; PaintColor = paintColor; Catastrophic = catastrophic; RandomSeed = randomSeed; BlastRadius = blastRadius; PhysicsForce = physicsForce; PaintRadius = paintRadius; PaintCount = paintCount; } internal void Write(FastBufferWriter writer) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0026: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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_00f9: 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) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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_014b: 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_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) ((FastBufferWriter)(ref writer)).WriteValueSafe(ref SprayCanNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref HolderClientId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref Position.x, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref Position.y, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref Position.z, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref PaintColor.r, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref PaintColor.g, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref PaintColor.b, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref PaintColor.a, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref Catastrophic, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref RandomSeed, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref BlastRadius, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref PhysicsForce, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref PaintRadius, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref PaintCount, default(ForPrimitives)); } internal static bool TryRead(FastBufferReader reader, out ExplosionMessage message) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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) //IL_005f: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: 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_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) message = default(ExplosionMessage); try { ulong sprayCanNetworkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref sprayCanNetworkObjectId, default(ForPrimitives)); ulong holderClientId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref holderClientId, default(ForPrimitives)); float num = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); float num2 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num2, default(ForPrimitives)); float num3 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num3, default(ForPrimitives)); float num4 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num4, default(ForPrimitives)); float num5 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num5, default(ForPrimitives)); float num6 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num6, default(ForPrimitives)); float num7 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num7, default(ForPrimitives)); bool catastrophic = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref catastrophic, default(ForPrimitives)); int randomSeed = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref randomSeed, default(ForPrimitives)); float blastRadius = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref blastRadius, default(ForPrimitives)); float physicsForce = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref physicsForce, default(ForPrimitives)); float paintRadius = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref paintRadius, default(ForPrimitives)); int paintCount = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref paintCount, default(ForPrimitives)); message = new ExplosionMessage(sprayCanNetworkObjectId, holderClientId, new Vector3(num, num2, num3), new Color(num4, num5, num6, num7), catastrophic, randomSeed, blastRadius, physicsForce, paintRadius, paintCount); return true; } catch (Exception arg) { Plugin.Log.LogWarning((object)$"Failed to read explosion message: {arg}"); return false; } } } internal static class ExplosionState { private static readonly HashSet ExplodedNetworkObjects = new HashSet(); private static readonly Dictionary LastShakeRequestFrame = new Dictionary(); internal static bool HasExploded(ulong networkObjectId) { lock (ExplodedNetworkObjects) { return ExplodedNetworkObjects.Contains(networkObjectId); } } internal static bool TryMarkExploded(ulong networkObjectId) { lock (ExplodedNetworkObjects) { return ExplodedNetworkObjects.Add(networkObjectId); } } internal static bool TryMarkShakeRequestThisFrame(ulong networkObjectId, int frame) { lock (LastShakeRequestFrame) { if (LastShakeRequestFrame.TryGetValue(networkObjectId, out var value) && value == frame) { return false; } LastShakeRequestFrame[networkObjectId] = frame; return true; } } internal static void Reset() { lock (ExplodedNetworkObjects) { ExplodedNetworkObjects.Clear(); } lock (LastShakeRequestFrame) { LastShakeRequestFrame.Clear(); } } } internal static class SprayCanExplosionNetworking { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnShakeRequestReceived; public static HandleNamedMessageDelegate <1>__OnExplosionReceived; } private const string ShakeRequestMessage = "huntedbyacreature.explosivespraypaint.ShakeRequest"; private const string ExplosionMessageName = "huntedbyacreature.explosivespraypaint.Explosion"; private static bool _registered; internal static void Register() { //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_0042: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if (!_registered && ((singleton != null) ? singleton.CustomMessagingManager : null) != null) { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; object obj = <>O.<0>__OnShakeRequestReceived; if (obj == null) { HandleNamedMessageDelegate val = OnShakeRequestReceived; <>O.<0>__OnShakeRequestReceived = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("huntedbyacreature.explosivespraypaint.ShakeRequest", (HandleNamedMessageDelegate)obj); CustomMessagingManager customMessagingManager2 = singleton.CustomMessagingManager; object obj2 = <>O.<1>__OnExplosionReceived; if (obj2 == null) { HandleNamedMessageDelegate val2 = OnExplosionReceived; <>O.<1>__OnExplosionReceived = val2; obj2 = (object)val2; } customMessagingManager2.RegisterNamedMessageHandler("huntedbyacreature.explosivespraypaint.Explosion", (HandleNamedMessageDelegate)obj2); _registered = true; } } internal static void Unregister() { NetworkManager singleton = NetworkManager.Singleton; if (_registered && ((singleton != null) ? singleton.CustomMessagingManager : null) != null) { singleton.CustomMessagingManager.UnregisterNamedMessageHandler("huntedbyacreature.explosivespraypaint.ShakeRequest"); singleton.CustomMessagingManager.UnregisterNamedMessageHandler("huntedbyacreature.explosivespraypaint.Explosion"); _registered = false; } } internal static void ReportLocalShake(SprayPaintItem sprayPaintItem) { //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) Register(); NetworkObject networkObject = ((NetworkBehaviour)sprayPaintItem).NetworkObject; if ((Object)(object)networkObject == (Object)null || ExplosionState.HasExploded(networkObject.NetworkObjectId)) { LogDebug(((Object)(object)networkObject == (Object)null) ? "Shake ignored because the spray can has no NetworkObject." : $"Shake ignored because spray can {networkObject.NetworkObjectId} already exploded."); return; } if (!ExplosionState.TryMarkShakeRequestThisFrame(networkObject.NetworkObjectId, Time.frameCount)) { LogDebug($"Duplicate shake request ignored for frame {Time.frameCount}, object {networkObject.NetworkObjectId}."); return; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening) { LogDebug("Shake detected, but NetworkManager is not listening yet."); return; } if (singleton.IsServer) { LogDebug($"Processing shake locally on host for object {networkObject.NetworkObjectId}."); TryProcessShakeOnServer(sprayPaintItem, singleton.LocalClientId); return; } LogDebug($"Sending shake request to host for object {networkObject.NetworkObjectId}."); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, -1); try { ulong networkObjectId = networkObject.NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("huntedbyacreature.explosivespraypaint.ShakeRequest", 0uL, val, (NetworkDelivery)2); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private static void OnShakeRequestReceived(ulong senderClientId, FastBufferReader reader) { //IL_001e: 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) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsServer) { ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); LogDebug($"Host received shake request from client {senderClientId} for object {num}."); SprayPaintItem sprayPaintItem = default(SprayPaintItem); if (!singleton.SpawnManager.SpawnedObjects.TryGetValue(num, out var value)) { LogDebug($"Host could not find spawned object {num}."); } else if (!((Component)value).TryGetComponent(ref sprayPaintItem)) { LogDebug($"Host object {num} is not a SprayPaintItem."); } else { TryProcessShakeOnServer(sprayPaintItem, senderClientId); } } } private static void TryProcessShakeOnServer(SprayPaintItem sprayPaintItem, ulong senderClientId) { //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: 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_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) NetworkObject networkObject = ((NetworkBehaviour)sprayPaintItem).NetworkObject; if ((Object)(object)networkObject == (Object)null || ExplosionState.HasExploded(networkObject.NetworkObjectId)) { LogDebug(((Object)(object)networkObject == (Object)null) ? "Host ignored shake because the spray can has no NetworkObject." : $"Host ignored shake because object {networkObject.NetworkObjectId} already exploded."); return; } PlayerControllerB playerHeldBy = ((GrabbableObject)sprayPaintItem).playerHeldBy; if ((Object)(object)playerHeldBy == (Object)null || playerHeldBy.actualClientId != senderClientId) { LogDebug(string.Format("Host rejected shake. holderClient={0}, sender={1}.", playerHeldBy?.actualClientId.ToString() ?? "none", senderClientId)); return; } if (SprayPaintIntrospection.GetBoolField(sprayPaintItem, "isSpraying").GetValueOrDefault()) { LogDebug("Host rejected shake request because the spray can is actively spraying. Spraying is safe."); return; } float num = Random.value * 100f; float num2 = Random.value * 100f; bool flag = num < Plugin.ModConfig.CatastrophicChancePercent.Value; bool flag2 = flag || num2 < Plugin.ModConfig.ExplosionChancePercent.Value; LogDebug($"Host roll for object {networkObject.NetworkObjectId}: catastrophic {num:0.00}/{Plugin.ModConfig.CatastrophicChancePercent.Value:0.##}, normal {num2:0.00}/{Plugin.ModConfig.ExplosionChancePercent.Value:0.##}, explode={flag2}."); if (flag2 && ExplosionState.TryMarkExploded(networkObject.NetworkObjectId)) { SprayPaintIntrospection.StopSprayingSafely(sprayPaintItem); Vector3 explosionPosition = ExplosionEffectUtility.GetExplosionPosition(sprayPaintItem); Color currentSprayColor = SprayPaintIntrospection.GetCurrentSprayColor(sprayPaintItem); int randomSeed = Random.Range(int.MinValue, int.MaxValue); float blastRadius = ExplosionEffectUtility.GetBlastRadius(flag); float physicsForce = ExplosionEffectUtility.GetPhysicsForce(flag); float paintRadius = ExplosionEffectUtility.GetPaintRadius(flag); int paintCount = ExplosionEffectUtility.GetPaintCount(flag); ExplosionMessage message = new ExplosionMessage(networkObject.NetworkObjectId, playerHeldBy.actualClientId, explosionPosition, currentSprayColor, flag, randomSeed, blastRadius, physicsForce, paintRadius, paintCount); NetworkManager singleton = NetworkManager.Singleton; BroadcastExplosion(message, (singleton != null) ? new ulong?(singleton.LocalClientId) : null); LogDebug(string.Format("Broadcasted {0} spray can explosion for object {1}.", flag ? "catastrophic" : "normal", networkObject.NetworkObjectId)); ExplosionEffectUtility.PlayClientSideExplosion(message, sprayPaintItem); ExplosionEffectUtility.ApplyServerSideDamageAndNoise(message); SprayPaintIntrospection.DestroySprayCanSafely(sprayPaintItem); } } private static void BroadcastExplosion(ExplosionMessage message, ulong? excludedClientId) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) == null) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(128, (Allocator)2, -1); try { message.Write(val); foreach (ulong connectedClientsId in singleton.ConnectedClientsIds) { if (!excludedClientId.HasValue || connectedClientsId != excludedClientId.Value) { singleton.CustomMessagingManager.SendNamedMessage("huntedbyacreature.explosivespraypaint.Explosion", connectedClientsId, val, (NetworkDelivery)2); } } } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private static void OnExplosionReceived(ulong senderClientId, FastBufferReader reader) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (ExplosionMessage.TryRead(reader, out var message)) { SprayPaintItem sprayPaintItem = null; NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.SpawnManager.SpawnedObjects.TryGetValue(message.SprayCanNetworkObjectId, out var value)) { ((Component)value).TryGetComponent(ref sprayPaintItem); } ExplosionEffectUtility.PlayClientSideExplosion(message, sprayPaintItem); } } private static void LogDebug(string message) { if (Plugin.ModConfig.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)message); } } } } namespace ExplosiveSprayPaint.Config { internal sealed class ExplosiveSprayPaintConfig { internal ConfigEntry ExplosionChancePercent { get; } internal ConfigEntry CatastrophicChancePercent { get; } internal ConfigEntry EnableScreenShake { get; } internal ConfigEntry EnableHudNotification { get; } internal ConfigEntry GlowInTheDarkPaint { get; } internal ConfigEntry EnableDebugLogging { get; } internal ConfigEntry TreatSprayUseAsShake { get; } internal ConfigEntry NormalPlayerDamage { get; } internal ConfigEntry CatastrophicPlayerDamage { get; } internal ConfigEntry NormalEnemyDamage { get; } internal ConfigEntry CatastrophicEnemyDamage { get; } internal ConfigEntry NormalBlastRadius { get; } internal ConfigEntry CatastrophicBlastRadius { get; } internal ConfigEntry NormalPhysicsForce { get; } internal ConfigEntry CatastrophicPhysicsForce { get; } internal ConfigEntry EnableFunnyExplosionPhysics { get; } internal ConfigEntry NormalPlayerKnockback { get; } internal ConfigEntry CatastrophicPlayerKnockback { get; } internal ConfigEntry MaxVerticalKnockback { get; } internal ConfigEntry NormalPaintSplats { get; } internal ConfigEntry CatastrophicPaintSplats { get; } internal ConfigEntry NormalPaintSplatterRadius { get; } internal ConfigEntry CatastrophicPaintSplatterRadius { get; } internal ConfigEntry PaintLifetimeSeconds { get; } internal ConfigEntry UseVanillaPaintPlacement { get; } internal ExplosiveSprayPaintConfig(ConfigFile config) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Expected O, but got Unknown //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Expected O, but got Unknown //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Expected O, but got Unknown //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Expected O, but got Unknown //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Expected O, but got Unknown //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Expected O, but got Unknown //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Expected O, but got Unknown //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Expected O, but got Unknown //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Expected O, but got Unknown //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Expected O, but got Unknown //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_043d: Expected O, but got Unknown //IL_046c: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Expected O, but got Unknown ExplosionChancePercent = config.Bind("Chance", "ExplosionChancePercent", 5f, new ConfigDescription("Percent chance that a shake ruptures the spray can. Only the host/server rolls this.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CatastrophicChancePercent = config.Bind("Chance", "CatastrophicExplosionChancePercent", 0.5f, new ConfigDescription("Percent chance that a shake causes a catastrophic rupture. This is rolled before the normal explosion chance.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); EnableScreenShake = config.Bind("Client", "EnableScreenShake", true, "Whether local camera shake is played when a can ruptures nearby."); EnableHudNotification = config.Bind("Client", "EnableHudNotification", true, "Whether to show a small HUD tip when your held can ruptures."); GlowInTheDarkPaint = config.Bind("Client", "GlowInTheDarkPaint", true, "If true, generated paint splats use an unlit material so rupture sites stay visible in the dark. If false, splats use lit materials where possible."); EnableDebugLogging = config.Bind("Debug", "EnableDebugLogging", false, "Writes shake detection and host roll details to the BepInEx log. Useful when validating mod compatibility."); TreatSprayUseAsShake = config.Bind("Compatibility", "TreatSprayUseAsShake", false, "If true, pressing/holding the normal spray-use button also rolls for rupture. Leave false for strict shake-only behavior."); NormalPlayerDamage = config.Bind("Damage", "NormalPlayerDamage", 20, new ConfigDescription("Damage dealt to players in a normal rupture radius.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); CatastrophicPlayerDamage = config.Bind("Damage", "CatastrophicPlayerDamage", 45, new ConfigDescription("Damage dealt to players in a catastrophic rupture radius.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); NormalEnemyDamage = config.Bind("Damage", "NormalEnemyDamage", 2, new ConfigDescription("HitEnemy damage dealt to enemies in a normal rupture radius.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20), Array.Empty())); CatastrophicEnemyDamage = config.Bind("Damage", "CatastrophicEnemyDamage", 6, new ConfigDescription("HitEnemy damage dealt to enemies in a catastrophic rupture radius.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 50), Array.Empty())); NormalBlastRadius = config.Bind("Explosion", "NormalBlastRadius", 3f, new ConfigDescription("Radius for a normal spray can rupture.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 20f), Array.Empty())); CatastrophicBlastRadius = config.Bind("Explosion", "CatastrophicBlastRadius", 5.5f, new ConfigDescription("Radius for a catastrophic spray can rupture.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 30f), Array.Empty())); NormalPhysicsForce = config.Bind("Explosion", "NormalPhysicsForce", 1.5f, new ConfigDescription("Vanilla explosion physics force. Keep low; high values launch players violently.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 15f), Array.Empty())); CatastrophicPhysicsForce = config.Bind("Explosion", "CatastrophicPhysicsForce", 3.5f, new ConfigDescription("Vanilla explosion physics force for catastrophic ruptures. Keep low to avoid rocket launches.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 25f), Array.Empty())); EnableFunnyExplosionPhysics = config.Bind("Explosion", "EnableFunnyExplosionPhysics", false, "Restores the high-force v1.0.8 launch behavior. Leave false for balanced spray-can ruptures; set true for silly friend-launching explosions."); NormalPlayerKnockback = config.Bind("Explosion", "NormalPlayerKnockback", 1.2f, new ConfigDescription("Extra horizontal player knockback for a normal rupture.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); CatastrophicPlayerKnockback = config.Bind("Explosion", "CatastrophicPlayerKnockback", 2.5f, new ConfigDescription("Extra horizontal player knockback for a catastrophic rupture.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 15f), Array.Empty())); MaxVerticalKnockback = config.Bind("Explosion", "MaxVerticalKnockback", 0.45f, new ConfigDescription("Maximum upward force added by this mod. Lower values prevent excessive vertical launches.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); NormalPaintSplats = config.Bind("Paint", "NormalPaintSplats", 55, new ConfigDescription("Paint decal count for a normal rupture.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 250), Array.Empty())); CatastrophicPaintSplats = config.Bind("Paint", "CatastrophicPaintSplats", 130, new ConfigDescription("Paint decal count for a catastrophic rupture.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 500), Array.Empty())); NormalPaintSplatterRadius = config.Bind("Paint", "NormalPaintSplatterRadius", 4f, new ConfigDescription("Radius around the rupture where normal paint splats are placed.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 20f), Array.Empty())); CatastrophicPaintSplatterRadius = config.Bind("Paint", "CatastrophicPaintSplatterRadius", 7f, new ConfigDescription("Radius around the rupture where catastrophic paint splats are placed.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 30f), Array.Empty())); PaintLifetimeSeconds = config.Bind("Paint", "PaintLifetimeSeconds", 120f, new ConfigDescription("How long generated fallback paint splats remain before cleanup.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 600f), Array.Empty())); UseVanillaPaintPlacement = config.Bind("Paint", "UseVanillaPaintPlacement", true, "Try Lethal Company's internal spray paint placement method before spawning fallback splats."); } } }