Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CrimsonBlood v0.7.6
CrimsonBlood.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.0.0")] namespace CrimsonBlood; [BepInPlugin("marc.valheim.crimsonblood", "Crimson Blood", "0.7.6.2")] [BepInProcess("valheim.exe")] public sealed class CrimsonBloodPlugin : BaseUnityPlugin { public const string PluginGuid = "marc.valheim.crimsonblood"; public const string PluginName = "Crimson Blood"; public const string PluginVersion = "0.7.6.2"; private const string YoureInjuredGuid = "com.marccunningham.youreinjured"; private const float MinimumMeaningfulHealthLoss = 0.01f; private const float MinimumDirectionMagnitude = 0.0001f; private const int MinimumPoolSize = 4; private const int MaximumPoolSize = 240; private const float MinimumVisualDistance = 5f; private const float MaximumVisualDistance = 150f; private const float MinimumImpactCooldown = 0.03f; private const float MaximumImpactCooldown = 0.75f; internal static CrimsonBloodPlugin Instance; private ConfigEntry<bool> enabledConfig; private ConfigEntry<KeyCode> diagnosticKey; private ConfigEntry<KeyCode> clearDiagnosticsKey; private ConfigEntry<float> visualDistance; private ConfigEntry<float> dynamicEffectRenderDistance; private ConfigEntry<float> surfaceSplatRenderDistance; private ConfigEntry<float> minimumHealthLossForVisual; private ConfigEntry<float> perTargetCooldown; private ConfigEntry<bool> useExternalAssetTextures; private ConfigEntry<string> assetRootFolder; private ConfigEntry<bool> useHighDefinitionGroundSplats; private ConfigEntry<int> maximumBurstTextures; private ConfigEntry<int> maximumTrailTextures; private ConfigEntry<int> maximumGroundSplatTextures; private ConfigEntry<int> burstPoolSize; private ConfigEntry<int> streakPoolSize; private ConfigEntry<int> dropletPoolSize; private ConfigEntry<int> splatPoolSize; private ConfigEntry<int> maximumDropletsPerHit; private ConfigEntry<int> maximumStreaksPerHeavyHit; private ConfigEntry<int> maximumBurstsPerHeavyHit; private ConfigEntry<float> dropletGravity; private ConfigEntry<float> dropletLifetime; private ConfigEntry<float> streakLifetime; private ConfigEntry<float> burstLifetime; private ConfigEntry<float> splatLifetime; private ConfigEntry<float> minimumSplatHealthLoss; private ConfigEntry<bool> createImmediateImpactSplats; private ConfigEntry<bool> allowWallMarks; private ConfigEntry<bool> groundOnlySurfaceMarks; private ConfigEntry<bool> createFallbackSplatsWhenAirborne; private ConfigEntry<float> surfaceOffset; private ConfigEntry<float> splatSettleSeconds; private ConfigEntry<bool> allowPlayerImpactVisuals; private ConfigEntry<bool> suppressPlayerImpactsWhenYoureInjuredLoaded; private ConfigEntry<bool> disableVanillaBloodEffects; private ConfigEntry<string> vanillaBloodEffectTokens; private ConfigEntry<bool> recordVanillaEffectRoots; private ConfigEntry<float> vanillaEffectWindowSeconds; private ConfigEntry<float> immediateWallProbeDistance; private ConfigEntry<bool> useGroundedLethalFinish; private ConfigEntry<bool> logVisualEvents; private ConfigEntry<float> bluntBloodMultiplier; private ConfigEntry<int> bluntMaximumDropletsPerHit; private ConfigEntry<float> bluntBurstSizeMultiplier; private ConfigEntry<float> bluntSplatSizeMultiplier; private ConfigEntry<float> bluntLifetimeMultiplier; private Harmony harmony; private Transform visualRoot; private string pluginDirectory; private string activeAssetDirectory; private Material quadMaterial; private Texture2D fallbackDropletTexture; private Texture2D fallbackBurstTexture; private Texture2D fallbackSplatTexture; private Texture2D fallbackTrailTexture; private readonly List<Texture2D> burstTextures = new List<Texture2D>(); private readonly List<Texture2D> dropletTextures = new List<Texture2D>(); private readonly List<Texture2D> splatTextures = new List<Texture2D>(); private readonly List<Texture2D> trailTextures = new List<Texture2D>(); private readonly List<Texture2D> ownedTextures = new List<Texture2D>(); private readonly List<Material> ownedMaterials = new List<Material>(); private readonly List<CrimsonBloodBurst> burstPool = new List<CrimsonBloodBurst>(); private readonly List<CrimsonBloodStreak> streakPool = new List<CrimsonBloodStreak>(); private readonly List<CrimsonBloodDroplet> dropletPool = new List<CrimsonBloodDroplet>(); private readonly List<CrimsonBloodSplat> splatPool = new List<CrimsonBloodSplat>(); private readonly Dictionary<int, float> nextAllowedImpactTime = new Dictionary<int, float>(); private readonly Dictionary<Type, FieldInfo[]> damageFieldCache = new Dictionary<Type, FieldInfo[]>(); private readonly Queue<string> recentEvents = new Queue<string>(); private readonly Queue<string> recentVanillaEffectRoots = new Queue<string>(); private readonly RaycastHit[] immediateSurfaceHits = (RaycastHit[])(object)new RaycastHit[16]; private Camera cachedMainCamera; private float nextCameraSearchTime; private float nextCooldownTrimTime; private int applyDamageHookCalls; private int observedDamageCalls; private int realHealthLossEvents; private int zeroHealthLossEvents; private int visualEvents; private int burstsSpawned; private int streaksSpawned; private int dropletsSpawned; private int splatsSpawned; private int recycledBursts; private int recycledStreaks; private int recycledDroplets; private int recycledSplats; private int suppressedPlayerImpactEvents; private int cooldownSkippedEvents; private int distanceSkippedEvents; private int surfaceLandingEvents; private int fallbackLandingEvents; private int fallbackSplatsDiscarded; private int characterSurfaceSkips; private int rigidbodySurfaceSkips; private int invalidSurfaceSkips; private int suppressedVanillaBloodEffects; private int observedVanillaEffectRoots; private int unmatchedVanillaEffectRoots; private int mutedVanillaRenderers; private int groundedLethalFinishes; private int destroyedPoolEntriesRecovered; private float vanillaEffectWindowUntil; private Vector3 vanillaEffectWindowCenter; private bool externalAssetsLoaded; private string assetLoadSummary = "Not loaded yet"; private string lastEvent = "none"; internal float DropletGravityMultiplier { get { if (dropletGravity != null) { return Mathf.Clamp(dropletGravity.Value, 0.1f, 6f); } return 1f; } } internal float SurfaceOffset { get { if (surfaceOffset != null) { return Mathf.Clamp(surfaceOffset.Value, 0.001f, 0.05f); } return 0.006f; } } internal float SplatSettleSeconds { get { if (splatSettleSeconds != null) { return Mathf.Clamp(splatSettleSeconds.Value, 0.05f, 0.5f); } return 0.14f; } } internal float DynamicEffectRenderDistance { get { if (dynamicEffectRenderDistance != null) { return Mathf.Clamp(dynamicEffectRenderDistance.Value, 6f, 60f); } return 24f; } } internal float SurfaceSplatRenderDistance { get { if (surfaceSplatRenderDistance != null) { return Mathf.Clamp(surfaceSplatRenderDistance.Value, 4f, 50f); } return 18f; } } internal bool DisableVanillaBloodEffects { get { if (disableVanillaBloodEffects != null) { return disableVanillaBloodEffects.Value; } return false; } } internal bool UseGroundedLethalFinish { get { if (useGroundedLethalFinish != null) { return useGroundedLethalFinish.Value; } return true; } } internal bool CreateFallbackSplatsWhenAirborne { get { if (createFallbackSplatsWhenAirborne != null) { return createFallbackSplatsWhenAirborne.Value; } return false; } } internal bool AllowWallMarks { get { if (allowWallMarks != null) { return allowWallMarks.Value; } return false; } } internal Camera RenderCamera { get { if ((Object)(object)cachedMainCamera != (Object)null && ((Behaviour)cachedMainCamera).isActiveAndEnabled) { return cachedMainCamera; } if (Time.unscaledTime >= nextCameraSearchTime) { nextCameraSearchTime = Time.unscaledTime + 0.5f; cachedMainCamera = Camera.main; } return cachedMainCamera; } } internal bool IsCharacterSurface(Collider collider) { if ((Object)(object)collider != (Object)null) { return (Object)(object)((Component)collider).GetComponentInParent<Character>() != (Object)null; } return false; } internal bool IsRejectedBloodSurface(Collider collider) { if ((Object)(object)collider == (Object)null) { return true; } if (IsCharacterSurface(collider)) { characterSurfaceSkips++; return true; } if ((Object)(object)collider.attachedRigidbody != (Object)null) { rigidbodySurfaceSkips++; return true; } Transform val = ((Component)collider).transform; int num = 0; while ((Object)(object)val != (Object)null && num < 8) { string text = ((Object)val).name ?? string.Empty; if (text.IndexOf("ragdoll", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("corpse", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("character", StringComparison.OrdinalIgnoreCase) >= 0) { invalidSurfaceSkips++; return true; } num++; val = val.parent; } return false; } internal bool IsValidBloodSurfaceNormal(Vector3 normal) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (!AllowWallMarks) { return normal.y >= 0.55f; } return normal.y >= -0.35f; } internal void RecordCharacterSurfaceSkip() { characterSurfaceSkips++; } internal void RecordAirborneFallbackDiscarded() { fallbackSplatsDiscarded++; } internal void BeginVanillaEffectWindow(Character target) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (DisableVanillaBloodEffects && !((Object)(object)target == (Object)null)) { vanillaEffectWindowCenter = target.GetCenterPoint(); float num = ((vanillaEffectWindowSeconds == null) ? 1.25f : Mathf.Clamp(vanillaEffectWindowSeconds.Value, 0.25f, 3f)); vanillaEffectWindowUntil = Mathf.Max(vanillaEffectWindowUntil, Time.time + num); } } internal void OnVanillaEffectsCreated(GameObject[] createdEffects) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (!DisableVanillaBloodEffects || createdEffects == null || createdEffects.Length == 0 || Time.time > vanillaEffectWindowUntil) { return; } foreach (GameObject val in createdEffects) { if ((Object)(object)val == (Object)null) { continue; } Vector3 val2 = val.transform.position - vanillaEffectWindowCenter; if (((Vector3)(ref val2)).sqrMagnitude > 625f) { continue; } string text = BuildVanillaEffectSignature(val); observedVanillaEffectRoots++; if (EffectSignatureMatchesVanillaBlood(text)) { MuteVanillaBloodVisuals(val); suppressedVanillaBloodEffects++; RememberVanillaEffectRoot("MUTED " + text); continue; } unmatchedVanillaEffectRoots++; if (recordVanillaEffectRoots != null && recordVanillaEffectRoots.Value) { RememberVanillaEffectRoot("OBSERVED " + text); } } } private void MuteVanillaBloodVisuals(GameObject root) { if ((Object)(object)root == (Object)null) { return; } Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { try { val.enabled = false; mutedVanillaRenderers++; } catch { } } } } private bool EffectSignatureMatchesVanillaBlood(string signature) { if (string.IsNullOrEmpty(signature)) { return false; } string[] array = ((vanillaBloodEffectTokens != null) ? vanillaBloodEffectTokens.Value : "blood,bleed,gore,splatter").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); string text = signature.ToLowerInvariant(); for (int i = 0; i < array.Length; i++) { string value = array[i].Trim().ToLowerInvariant(); if (!string.IsNullOrEmpty(value) && text.Contains(value)) { return true; } } return false; } private static string BuildVanillaEffectSignature(GameObject root) { if ((Object)(object)root == (Object)null) { return "<destroyed>"; } string text = ((Object)root).name ?? "unnamed"; Transform transform = root.transform; for (int i = 0; i < transform.childCount && i < 24; i++) { Transform child = transform.GetChild(i); if ((Object)(object)child == (Object)null) { continue; } text = text + " / " + ((Object)child).name; for (int j = 0; j < child.childCount && j < 6; j++) { Transform child2 = child.GetChild(j); if ((Object)(object)child2 != (Object)null) { text = text + " / " + ((Object)child2).name; } } } return text; } private void RememberVanillaEffectRoot(string line) { while (recentVanillaEffectRoots.Count >= 24) { recentVanillaEffectRoots.Dequeue(); } recentVanillaEffectRoots.Enqueue(line); } internal bool ShouldRenderEffectAt(Vector3 worldPosition, bool isSurfaceMark) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0053: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) Camera renderCamera = RenderCamera; Vector3 val = (((Object)(object)renderCamera != (Object)null) ? ((Component)renderCamera).transform.position : (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero)); float num = (isSurfaceMark ? SurfaceSplatRenderDistance : DynamicEffectRenderDistance); Vector3 val2 = worldPosition - val; return ((Vector3)(ref val2)).sqrMagnitude <= num * num; } 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; pluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); BindConfig(); harmony = new Harmony("marc.valheim.crimsonblood"); harmony.PatchAll(typeof(CrimsonBloodPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Crimson Blood 0.7.6.2 loaded. F11 writes diagnostics; F12 clears recent events."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Asset-driven mode expects an assets folder beside CrimsonBlood.dll. If it is missing, safe procedural fallback textures are used."); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); harmony = null; } DestroyVisualSystem(); nextAllowedImpactTime.Clear(); damageFieldCache.Clear(); recentEvents.Clear(); recentVanillaEffectRoots.Clear(); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(diagnosticKey.Value)) { WriteDiagnostics(); } if (Input.GetKeyDown(clearDiagnosticsKey.Value)) { recentEvents.Clear(); recentVanillaEffectRoots.Clear(); lastEvent = "none"; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Crimson Blood: cleared recent event diagnostics."); } if ((Object)(object)Player.m_localPlayer != (Object)null) { EnsureVisualSystem(); } if (Time.time >= nextCooldownTrimTime) { nextCooldownTrimTime = Time.time + 20f; TrimExpiredCooldowns(); } } private void BindConfig() { enabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Master", "Enabled", true, "Turns Crimson Blood's local visual layer on or off. It never changes combat balance."); diagnosticKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("0 - Master", "DiagnosticKey", (KeyCode)292, "Writes Crimson Blood diagnostic information to BepInEx/LogOutput.log."); clearDiagnosticsKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("0 - Master", "ClearDiagnosticsKey", (KeyCode)293, "Clears Crimson Blood's recent diagnostic event list."); visualDistance = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Safety", "VisualDistanceMetres", 80f, "Maximum distance from the local player at which combat blood visuals are created."); dynamicEffectRenderDistance = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Safety", "DynamicEffectRenderDistanceMetres", 24f, "Maximum distance from the camera at which airborne bursts, streaks, and droplets remain visible."); surfaceSplatRenderDistance = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Safety", "SurfaceSplatRenderDistanceMetres", 18f, "Maximum distance from the camera at which surface blood marks remain visible."); minimumHealthLossForVisual = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Safety", "MinimumActualHealthLoss", 0.1f, "Actual health lost after armour, blocking and resistances required before a visual may spawn."); perTargetCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Safety", "PerTargetImpactCooldownSeconds", 0.06f, "Stops rapid repeated damage ticks from producing excessive visual bursts."); useExternalAssetTextures = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Asset Loading", "UseExternalAssetTextures", true, "Loads supplied transparent PNG effects from the assets folder beside CrimsonBlood.dll."); assetRootFolder = ((BaseUnityPlugin)this).Config.Bind<string>("2 - Asset Loading", "AssetRootFolder", "assets", "Folder beside CrimsonBlood.dll that contains sprays, trails, and ground_splats."); useHighDefinitionGroundSplats = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Asset Loading", "UseHighDefinitionGroundSplats", false, "Uses assets/ground_splats/kenney_512 if you copied it beside the DLL. This uses more video memory than the default 256px set."); maximumBurstTextures = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Asset Loading", "MaximumBurstTextures", 6, "Maximum number of splash-frame textures loaded from assets/sprays/blood_splash_frames."); maximumTrailTextures = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Asset Loading", "MaximumTrailTextures", 8, "Maximum number of trail/droplet textures loaded from assets/trails."); maximumGroundSplatTextures = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Asset Loading", "MaximumGroundSplatTextures", 36, "Maximum number of ground-splat textures loaded. 36 default 256px textures are safe for this first asset build."); burstPoolSize = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Safety Pools", "ImpactBurstPoolSize", 20, "Pre-warmed maximum number of animated impact burst sprites."); streakPoolSize = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Safety Pools", "PressureStreakPoolSize", 22, "Pre-warmed maximum number of pressure spray streaks."); dropletPoolSize = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Safety Pools", "DropletPoolSize", 112, "Pre-warmed maximum number of moving droplets."); splatPoolSize = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Safety Pools", "SurfaceSplatPoolSize", 112, "Pre-warmed maximum number of temporary blood splats."); maximumDropletsPerHit = ((BaseUnityPlugin)this).Config.Bind<int>("4 - Look", "MaximumDropletsPerHit", 18, "Upper safety cap for liquid droplets created by one strong hit."); maximumStreaksPerHeavyHit = ((BaseUnityPlugin)this).Config.Bind<int>("4 - Look", "MaximumPressureStreaksPerHeavyHit", 4, "Upper safety cap for streaks on stronger hits."); maximumBurstsPerHeavyHit = ((BaseUnityPlugin)this).Config.Bind<int>("4 - Look", "MaximumAnimatedBurstsPerHeavyHit", 2, "Upper safety cap for animated splash bursts on stronger hits."); dropletGravity = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "DropletGravityMultiplier", 1.85f, "Gravity multiplier for airborne droplets. Higher values make them fall and hit surfaces sooner."); dropletLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "DropletLifetimeSeconds", 1.2f, "Maximum airborne lifetime before a droplet fades or tries a final nearby splat."); streakLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "PressureStreakLifetimeSeconds", 0.18f, "Lifetime of directional pressure spray streaks."); burstLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "ImpactBurstLifetimeSeconds", 0.16f, "Lifetime of animated impact burst sprites."); splatLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "SurfaceSplatLifetimeSeconds", 120f, "How long temporary ground/structure blood remains before fading."); minimumSplatHealthLoss = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "MinimumHealthLossForImmediateImpactSplat", 0.85f, "Health loss required before an immediate blood mark may appear below/near the impact."); createImmediateImpactSplats = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Look", "CreateImmediateImpactSplats", true, "Places one small wet mark near a meaningful hit where a suitable surface exists."); allowWallMarks = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Look", "AllowWallAndSteepSurfaceBloodMarks", true, "Allows blood marks on static walls, wooden structures, steep rocks, floors, and terrain."); groundOnlySurfaceMarks = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Look", "GroundOnlySurfaceMarks", false, "Legacy compatibility setting. v0.7.5 ignores this value so wall and steep-surface marks work when AllowWallAndSteepSurfaceBloodMarks is true."); immediateWallProbeDistance = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "ImmediateWallProbeDistanceMetres", 1.35f, "How far a fresh hit checks behind and around the wound for a nearby static wall or steep rock to receive blood."); createFallbackSplatsWhenAirborne = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Look", "CreateFallbackSplatsWhenAirborne", false, "When false, droplets that never reach a valid ground surface simply fade instead of creating a late fallback blood mark in the air."); surfaceOffset = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "SurfaceOffset", 0.006f, "Small offset that keeps a blood mark just above its surface and avoids flickering."); splatSettleSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "SurfaceSplatSettleSeconds", 0.14f, "Real-time seconds a new blood mark takes to spread to its final size. This is independent of splat lifetime."); bluntBloodMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "BluntHeavyHitBloodMultiplier", 1.85f, "Extra amount of blood created by strong blunt hits such as maces and clubs. Affects heavy hits only."); bluntMaximumDropletsPerHit = ((BaseUnityPlugin)this).Config.Bind<int>("4 - Look", "MaximumDropletsPerHeavyBluntHit", 30, "Safety cap used only for strong blunt hits. Lets mace and club impacts be fuller without raising every weapon type."); bluntBurstSizeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "BluntHeavyHitBurstSizeMultiplier", 1.6f, "Size multiplier for animated impact bursts created by strong blunt hits."); bluntSplatSizeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "BluntHeavyHitSplatSizeMultiplier", 1.45f, "Size multiplier for blood marks created by strong blunt hits."); bluntLifetimeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Look", "BluntHeavyHitLifetimeMultiplier", 1.38f, "Makes blunt-hit bursts, droplets, and streaks stay visible slightly longer."); allowPlayerImpactVisuals = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Player Compatibility", "AllowPlayerImpactVisuals", true, "Allows Crimson Blood to create impact visuals when the local player takes real damage."); suppressPlayerImpactsWhenYoureInjuredLoaded = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Player Compatibility", "PreventDuplicatePlayerHitBloodWhenYoureInjuredLoaded", true, "Prevents a duplicate Crimson Blood player-hit burst while You're Injured is installed. Creature blood remains enabled."); disableVanillaBloodEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Player Compatibility", "DisableVanillaBloodEffects", true, "Suppresses Valheim's default blood effect when Crimson Blood is handling damage visuals. This reduces visual clashing."); vanillaBloodEffectTokens = ((BaseUnityPlugin)this).Config.Bind<string>("5 - Player Compatibility", "VanillaBloodEffectTokens", "blood,bleed,gore,splatter", "Name fragments used to identify actual vanilla effect GameObjects created during a hit. Unmatched roots appear in F11 diagnostics."); recordVanillaEffectRoots = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Player Compatibility", "RecordVanillaEffectRootsAroundHits", true, "Records EffectList-created root names near a real hit. Use F11 results to identify any remaining vanilla blood effect exactly."); vanillaEffectWindowSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("5 - Player Compatibility", "VanillaEffectWindowSeconds", 1.25f, "Seconds after a damage event that newly created EffectList roots are inspected for vanilla blood suppression."); useGroundedLethalFinish = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Player Compatibility", "UseGroundedLethalFinish", true, "On a lethal hit, replaces the hanging animated impact burst with a grounded death spill and falling droplets."); logVisualEvents = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Debug", "LogVisualEvents", false, "Writes every spawned visual event to LogOutput.log. Leave false outside testing."); } internal void RecordHookCall() { applyDamageHookCalls++; } internal bool ShouldObserve(Character target) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (!enabledConfig.Value || (Object)(object)target == (Object)null) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)target == (Object)(object)localPlayer) { return true; } if ((Object)(object)localPlayer == (Object)null) { return false; } float num = Mathf.Clamp(visualDistance.Value, 5f, 150f); Vector3 val = ((Component)target).transform.position - ((Component)localPlayer).transform.position; return ((Vector3)(ref val)).sqrMagnitude <= num * num; } internal void RecordDamage(Character target, HitData hit, float healthBefore) { //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) if (!enabledConfig.Value || (Object)(object)target == (Object)null) { return; } observedDamageCalls++; float health = target.GetHealth(); float num = Mathf.Max(0f, healthBefore - health); if (num < 0.01f) { zeroHealthLossEvents++; return; } realHealthLossEvents++; if (num < Mathf.Max(0.01f, minimumHealthLossForVisual.Value)) { RememberEvent("SKIP threshold target=" + GetTargetName(target) + " loss=" + num.ToString("0.##")); return; } if (!IsWithinVisualRange(target)) { distanceSkippedEvents++; return; } if ((Object)(object)target == (Object)(object)Player.m_localPlayer && !CanSpawnLocalPlayerImpact()) { suppressedPlayerImpactEvents++; RememberEvent("SKIP player-compatibility loss=" + num.ToString("0.##")); return; } int instanceID = ((Object)target).GetInstanceID(); if (nextAllowedImpactTime.TryGetValue(instanceID, out var value) && Time.time < value) { cooldownSkippedEvents++; return; } nextAllowedImpactTime[instanceID] = Time.time + Mathf.Clamp(perTargetCooldown.Value, 0.03f, 0.75f); EnsureVisualSystem(); if ((Object)(object)visualRoot == (Object)null) { RememberEvent("SKIP visual-root-unavailable target=" + GetTargetName(target)); return; } DamageCategory category = ResolveDamageCategory(hit); Vector3 impactPoint = ResolveImpactPoint(target, hit); Vector3 sprayDirection = ResolveOutwardSprayDirection(target, hit, impactPoint); Color bloodColor = ResolveBloodColor(target, category); float severity = Mathf.Clamp01((num - 0.35f) / 14f); bool lethalHit = health <= 0.01f; SpawnImpact(target, impactPoint, sprayDirection, num, severity, category, bloodColor, lethalHit); } private bool IsWithinVisualRange(Character target) { //IL_0032: 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_0047: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } float num = Mathf.Clamp(visualDistance.Value, 5f, 150f); Vector3 val = ((Component)target).transform.position - ((Component)localPlayer).transform.position; return ((Vector3)(ref val)).sqrMagnitude <= num * num; } private bool CanSpawnLocalPlayerImpact() { if (!allowPlayerImpactVisuals.Value) { return false; } if (suppressPlayerImpactsWhenYoureInjuredLoaded.Value) { return !IsYoureInjuredLoaded(); } return true; } private static bool IsYoureInjuredLoaded() { try { return Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("com.marccunningham.youreinjured"); } catch { return false; } } private void EnsureVisualSystem() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)visualRoot != (Object)null)) { visualRoot = new GameObject("CrimsonBlood_LocalVisuals").transform; visualRoot.SetParent(((Component)this).transform, false); ((Object)((Component)visualRoot).gameObject).hideFlags = (HideFlags)61; PrepareTexturesAndMaterials(); PrewarmPools(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Crimson Blood: " + assetLoadSummary)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Crimson Blood: visual pools ready: bursts=" + burstPool.Count + ", streaks=" + streakPool.Count + ", droplets=" + dropletPool.Count + ", splats=" + splatPool.Count + ".")); } } private void PrepareTexturesAndMaterials() { ClearLoadedAssetLists(); externalAssetsLoaded = false; activeAssetDirectory = string.Empty; bool flag = false; if (useExternalAssetTextures.Value) { string path = (string.IsNullOrWhiteSpace(assetRootFolder.Value) ? "assets" : assetRootFolder.Value.Trim()); activeAssetDirectory = Path.Combine(pluginDirectory ?? string.Empty, path); flag = TryLoadExternalTextureSet(activeAssetDirectory); } int count = burstTextures.Count; int count2 = trailTextures.Count; int count3 = splatTextures.Count; externalAssetsLoaded = count > 0 || count2 > 0 || count3 > 0; CreateFallbackTexturesIfNeeded(); if (burstTextures.Count == 0) { burstTextures.Add(fallbackBurstTexture); } if (dropletTextures.Count == 0) { dropletTextures.Add(fallbackDropletTexture); } if (splatTextures.Count == 0) { splatTextures.Add(fallbackSplatTexture); } quadMaterial = CreateTransparentMaterial("CrimsonBlood_AssetQuadMaterial", fallbackSplatTexture); ownedMaterials.Add(quadMaterial); if (trailTextures.Count == 0) { trailTextures.Add(fallbackTrailTexture); } string text = (flag ? "EXTERNAL" : (externalAssetsLoaded ? "PARTIAL" : "FALLBACK")); assetLoadSummary = "assetMode=" + text + " | root=" + (string.IsNullOrEmpty(activeAssetDirectory) ? "not-requested" : activeAssetDirectory) + " | externalBurst=" + count + " | externalTrail=" + count2 + " | externalSplat=" + count3 + " | activeBurst=" + burstTextures.Count + " | activeTrail=" + trailTextures.Count + " | activeSplat=" + splatTextures.Count; } private bool TryLoadExternalTextureSet(string assetRoot) { if (string.IsNullOrEmpty(assetRoot) || !Directory.Exists(assetRoot)) { assetLoadSummary = "assets folder missing: " + assetRoot; return false; } string folder = Path.Combine(assetRoot, "sprays", "blood_splash_frames"); string folder2 = Path.Combine(assetRoot, "trails"); string folder3 = (useHighDefinitionGroundSplats.Value ? Path.Combine(assetRoot, "ground_splats", "kenney_512") : Path.Combine(assetRoot, "ground_splats", "kenney_256")); int num = LoadPngFolder(folder, Mathf.Clamp(maximumBurstTextures.Value, 1, 16), burstTextures, "burst"); int num2 = LoadPngFolder(folder2, Mathf.Clamp(maximumTrailTextures.Value, 1, 16), trailTextures, "trail"); int num3 = LoadPngFolder(folder3, Mathf.Clamp(maximumGroundSplatTextures.Value, 1, 48), splatTextures, "splat"); for (int i = 0; i < trailTextures.Count; i++) { if ((Object)(object)trailTextures[i] != (Object)null) { dropletTextures.Add(trailTextures[i]); } } int num4; if (num > 0 && num2 > 0) { num4 = ((num3 > 0) ? 1 : 0); if (num4 != 0) { goto IL_014f; } } else { num4 = 0; } ((BaseUnityPlugin)this).Logger.LogWarning((object)"Crimson Blood: asset folders were found but one or more required texture groups were empty. Falling back only for missing groups."); goto IL_014f; IL_014f: return (byte)num4 != 0; } private int LoadPngFolder(string folder, int maximumTextures, List<Texture2D> destination, string groupName) { if (!Directory.Exists(folder)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Crimson Blood: missing " + groupName + " asset folder: " + folder)); return 0; } string[] files; try { files = Directory.GetFiles(folder, "*.png", SearchOption.TopDirectoryOnly); Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Crimson Blood: could not enumerate " + groupName + " textures. " + ex.Message)); return 0; } int num = 0; for (int i = 0; i < files.Length; i++) { if (num >= maximumTextures) { break; } if (!CrimsonAssetLoader.TryLoadAlphaMaskPng(files[i], out var texture, out var error)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Crimson Blood: skipped " + groupName + " texture '" + Path.GetFileName(files[i]) + "'. " + error)); } else { ((Object)texture).name = "CrimsonBlood_" + groupName + "_" + Path.GetFileNameWithoutExtension(files[i]); destination.Add(texture); ownedTextures.Add(texture); num++; } } return num; } private void CreateFallbackTexturesIfNeeded() { if ((Object)(object)fallbackDropletTexture == (Object)null) { fallbackDropletTexture = CrimsonAssetLoader.CreateSoftCircleTexture("CrimsonBlood_FallbackDroplet", 64, 0.88f); ownedTextures.Add(fallbackDropletTexture); } if ((Object)(object)fallbackBurstTexture == (Object)null) { fallbackBurstTexture = CrimsonAssetLoader.CreateBurstTexture("CrimsonBlood_FallbackBurst", 128); ownedTextures.Add(fallbackBurstTexture); } if ((Object)(object)fallbackSplatTexture == (Object)null) { fallbackSplatTexture = CrimsonAssetLoader.CreateIrregularSplatTexture("CrimsonBlood_FallbackSplat", 128); ownedTextures.Add(fallbackSplatTexture); } if ((Object)(object)fallbackTrailTexture == (Object)null) { fallbackTrailTexture = CrimsonAssetLoader.CreateTrailTexture("CrimsonBlood_FallbackTrail", 32, 128); ownedTextures.Add(fallbackTrailTexture); } } private Material CreateTransparentMaterial(string materialName, Texture2D texture) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Standard"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Legacy Shaders/Transparent/Specular"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Particles/Alpha Blended"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Unlit/Transparent"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Sprites/Default"); } Material val2 = new Material(val); ((Object)val2).name = materialName; ((Object)val2).hideFlags = (HideFlags)61; val2.color = Color.white; val2.renderQueue = 3000; if ((Object)(object)texture != (Object)null) { if (val2.HasProperty("_MainTex")) { val2.SetTexture("_MainTex", (Texture)(object)texture); } if (val2.HasProperty("_BaseMap")) { val2.SetTexture("_BaseMap", (Texture)(object)texture); } } if (val2.HasProperty("_Mode")) { val2.SetFloat("_Mode", 3f); } if (val2.HasProperty("_Surface")) { val2.SetFloat("_Surface", 1f); } if (val2.HasProperty("_Blend")) { val2.SetFloat("_Blend", 0f); } if (val2.HasProperty("_SrcBlend")) { val2.SetInt("_SrcBlend", 5); } if (val2.HasProperty("_DstBlend")) { val2.SetInt("_DstBlend", 10); } if (val2.HasProperty("_ZWrite")) { val2.SetInt("_ZWrite", 0); } if (val2.HasProperty("_Cull")) { val2.SetInt("_Cull", 0); } if (val2.HasProperty("_Glossiness")) { val2.SetFloat("_Glossiness", 0.82f); } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", 0.82f); } if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", 0f); } if (val2.HasProperty("_SpecColor")) { val2.SetColor("_SpecColor", new Color(0.22f, 0.08f, 0.08f, 1f)); } if (val2.HasProperty("_Color")) { val2.SetColor("_Color", Color.white); } if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", Color.white); } val2.SetOverrideTag("RenderType", "Transparent"); val2.DisableKeyword("_ALPHATEST_ON"); val2.EnableKeyword("_ALPHABLEND_ON"); val2.DisableKeyword("_ALPHAPREMULTIPLY_ON"); return val2; } private void PrewarmPools() { int num = Mathf.Clamp(burstPoolSize.Value, 4, 48); int num2 = Mathf.Clamp(streakPoolSize.Value, 4, 48); int num3 = Mathf.Clamp(dropletPoolSize.Value, 4, 240); int num4 = Mathf.Clamp(splatPoolSize.Value, 4, 240); for (int i = 0; i < num; i++) { CreateBurstPoolObject(i); } for (int j = 0; j < num2; j++) { CreateStreakPoolObject(j); } for (int k = 0; k < num3; k++) { CreateDropletPoolObject(k); } for (int l = 0; l < num4; l++) { CreateSplatPoolObject(l); } } private void CreateBurstPoolObject(int index) { GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)obj).name = "CrimsonBlood_ImpactBurst_" + index; obj.transform.SetParent(visualRoot, false); ((Object)obj).hideFlags = (HideFlags)61; RemoveCollider(obj); Renderer component = obj.GetComponent<Renderer>(); ConfigureRenderer(component, quadMaterial); CrimsonBloodBurst crimsonBloodBurst = obj.AddComponent<CrimsonBloodBurst>(); crimsonBloodBurst.Initialize(this, component); obj.SetActive(false); burstPool.Add(crimsonBloodBurst); } private void CreateDropletPoolObject(int index) { GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)obj).name = "CrimsonBlood_Droplet_" + index; obj.transform.SetParent(visualRoot, false); ((Object)obj).hideFlags = (HideFlags)61; RemoveCollider(obj); Renderer component = obj.GetComponent<Renderer>(); ConfigureRenderer(component, quadMaterial); CrimsonBloodDroplet crimsonBloodDroplet = obj.AddComponent<CrimsonBloodDroplet>(); crimsonBloodDroplet.Initialize(this, component); obj.SetActive(false); dropletPool.Add(crimsonBloodDroplet); } private void CreateStreakPoolObject(int index) { GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)obj).name = "CrimsonBlood_Streak_" + index; obj.transform.SetParent(visualRoot, false); ((Object)obj).hideFlags = (HideFlags)61; RemoveCollider(obj); Renderer component = obj.GetComponent<Renderer>(); ConfigureRenderer(component, quadMaterial); CrimsonBloodStreak crimsonBloodStreak = obj.AddComponent<CrimsonBloodStreak>(); crimsonBloodStreak.Initialize(this, component); obj.SetActive(false); streakPool.Add(crimsonBloodStreak); } private void CreateSplatPoolObject(int index) { GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)obj).name = "CrimsonBlood_Splat_" + index; obj.transform.SetParent(visualRoot, false); ((Object)obj).hideFlags = (HideFlags)61; RemoveCollider(obj); MeshRenderer component = obj.GetComponent<MeshRenderer>(); ConfigureRenderer((Renderer)(object)component, quadMaterial); CrimsonBloodSplat crimsonBloodSplat = obj.AddComponent<CrimsonBloodSplat>(); crimsonBloodSplat.Initialize(this, component); obj.SetActive(false); splatPool.Add(crimsonBloodSplat); } private static void RemoveCollider(GameObject gameObject) { Collider component = gameObject.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } } private static void ConfigureRenderer(Renderer renderer, Material material) { if (!((Object)(object)renderer == (Object)null)) { renderer.sharedMaterial = material; renderer.shadowCastingMode = (ShadowCastingMode)0; renderer.receiveShadows = false; } } private void SpawnImpact(Character target, Vector3 impactPoint, Vector3 sprayDirection, float healthLoss, float severity, DamageCategory category, Color bloodColor, bool lethalHit) { //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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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) //IL_007d: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = impactPoint + sprayDirection * 0.035f + Vector3.up * 0.035f; bool flag = healthLoss >= 2.5f || severity >= 0.15f; bool flag2 = healthLoss >= 5.5f || severity >= 0.38f; bool flag3 = healthLoss >= 10f || severity >= 0.68f; if (category == DamageCategory.Fall) { TryCreateImmediateImpactSplat(((Component)target).transform, val, Mathf.Lerp(0.2f, 0.7f, severity), bloodColor, Vector3.zero); visualEvents++; RememberEvent("SPAWN target=" + GetTargetName(target) + " loss=" + healthLoss.ToString("0.##") + " category=Fall splat-only"); return; } int num = Mathf.Clamp(maximumDropletsPerHit.Value, 2, 30); if (category == DamageCategory.Blunt && flag2) { num = Mathf.Clamp(bluntMaximumDropletsPerHit.Value, 4, 30); } int num2 = Mathf.Clamp(3 + Mathf.RoundToInt(Mathf.Lerp(2f, (float)num - 3f, severity)), 2, num); int num3 = (flag ? Mathf.Clamp(1 + Mathf.RoundToInt(Mathf.Lerp(0f, (float)maximumStreaksPerHeavyHit.Value - 1f, severity)), 1, Mathf.Max(1, maximumStreaksPerHeavyHit.Value)) : 0); int num4 = (flag ? 1 : 0); if (flag2) { num4 = Mathf.Clamp(maximumBurstsPerHeavyHit.Value, 1, 3); } switch (category) { case DamageCategory.Slash: case DamageCategory.Chop: num2 += 2; break; case DamageCategory.Pierce: num2++; num3 = Mathf.Max(num3, 1); break; case DamageCategory.Blunt: if (flag2) { float num5 = Mathf.Clamp(bluntBloodMultiplier.Value, 1f, 3f); num2 = Mathf.RoundToInt((float)num2 * num5) + 2; num3 = Mathf.Max(num3, 4); num4 = Mathf.Max(num4, 3); } else { num2++; } break; case DamageCategory.Fire: num2 = Mathf.Max(1, num2 - 6); num3 = 0; num4 = 0; break; case DamageCategory.Poison: num2 = Mathf.Max(1, num2 - 7); num3 = 0; num4 = 0; break; case DamageCategory.BiteOrMonsterHit: num2 += 2; break; } num2 = Mathf.Clamp(num2, 1, num); if (category != DamageCategory.Fire && category != DamageCategory.Poison && !(category == DamageCategory.Blunt && flag2)) { num2 = Mathf.Min(num + 2, num2 + 2); } num3 = Mathf.Clamp(num3, 0, Mathf.Clamp(maximumStreaksPerHeavyHit.Value, 0, 8)); num4 = Mathf.Clamp(num4, 0, Mathf.Clamp(maximumBurstsPerHeavyHit.Value + 1, 0, 4)); if (createImmediateImpactSplats.Value && healthLoss >= Mathf.Max(0f, minimumSplatHealthLoss.Value)) { float num6 = Mathf.Lerp(0.15f, flag3 ? 0.58f : 0.42f, severity); if (category == DamageCategory.Blunt && flag2) { num6 *= Mathf.Clamp(bluntSplatSizeMultiplier.Value, 1f, 2.5f); } TryCreateImmediateImpactSplat(((Component)target).transform, val + sprayDirection * 0.15f, num6, bloodColor, sprayDirection); } bool flag4 = lethalHit && UseGroundedLethalFinish; if (flag4) { groundedLethalFinishes++; num4 = 0; num3 = 0; num2 = Mathf.Min(num2, 12); TryCreateImmediateImpactSplat(((Component)target).transform, impactPoint, Mathf.Clamp(0.34f + severity * 0.48f, 0.34f, 0.78f), bloodColor, sprayDirection); } if (!flag4) { SpawnAnimatedBursts(((Component)target).transform, val, sprayDirection, num4, severity, category, bloodColor); } SpawnPressureStreaks(((Component)target).transform, val, sprayDirection, num3, severity, category, bloodColor); SpawnBallisticDroplets(((Component)target).transform, val, sprayDirection, num2, severity, category, bloodColor, flag2, flag4); visualEvents++; string text = "SPAWN target=" + GetTargetName(target) + " loss=" + healthLoss.ToString("0.##") + " category=" + category.ToString() + " lethal=" + lethalHit + " burst=" + num4 + " streaks=" + num3 + " droplets=" + num2 + " direction=" + FormatVector(sprayDirection); RememberEvent(text); if (logVisualEvents.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Crimson Blood " + text)); } } private void SpawnAnimatedBursts(Transform owner, Vector3 source, Vector3 sprayDirection, int burstCount, float severity, DamageCategory category, Color color) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_0096: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) if (burstCount <= 0 || burstPool.Count == 0) { return; } Vector3 val = Vector3.Cross(Vector3.up, sprayDirection); if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = Vector3.right; } ((Vector3)(ref val)).Normalize(); float num = Mathf.Lerp(0.52f, 1.2f, severity); for (int i = 0; i < burstCount; i++) { float num2 = Random.Range(-0.2f, 0.2f); float num3 = Random.Range(-0.06f, 0.16f); Vector3 val2 = sprayDirection + val * num2 + Vector3.up * num3; Vector3 normalized = ((Vector3)(ref val2)).normalized; float num4 = num * Random.Range(0.85f, 1.18f); float num5 = Mathf.Max(0.06f, burstLifetime.Value) * Random.Range(0.9f, 1.12f); Vector3 val3 = normalized * Random.Range(0.45f, 1.35f) + Vector3.up * Random.Range(0.05f, 0.45f); switch (category) { case DamageCategory.Pierce: num4 *= 0.82f; val3 *= 1.3f; break; case DamageCategory.Blunt: { float num6 = Mathf.Clamp(bluntBurstSizeMultiplier.Value, 1f, 2.5f); num4 *= num6; num5 *= Mathf.Clamp(bluntLifetimeMultiplier.Value, 1f, 2.5f); val3 *= 1.1f; break; } } GetBurst().Activate(owner, source + normalized * 0.02f, val3, num4, num5, color, burstTextures, Random.Range(0f, 360f)); burstsSpawned++; } } private void SpawnPressureStreaks(Transform owner, Vector3 source, Vector3 sprayDirection, int streakCount, float severity, DamageCategory category, Color color) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00b4: 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_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013f: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: 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_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) if (streakCount <= 0 || streakPool.Count == 0) { return; } Vector3 val = Vector3.Cross(Vector3.up, sprayDirection); if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = Vector3.right; } ((Vector3)(ref val)).Normalize(); float num = Mathf.Lerp(5.5f, 12f, severity); float num2 = Mathf.Lerp(0.75f, 2.25f, severity); for (int i = 0; i < streakCount; i++) { float num3 = ((category == DamageCategory.Blunt) ? 0.78f : 0.44f); float num4 = Random.Range(0f - num3, num3); float num5 = Random.Range(-0.06f, 0.3f); Vector3 val2 = sprayDirection + val * num4 + Vector3.up * num5; Vector3 normalized = ((Vector3)(ref val2)).normalized; float num6 = num * Random.Range(0.84f, 1.24f); float num7 = Mathf.Lerp(0.028f, 0.078f, severity) * Random.Range(0.85f, 1.18f); float num8 = Mathf.Max(0.06f, streakLifetime.Value) * Random.Range(0.88f, 1.15f); Vector3 val3 = normalized * num6 + Vector3.up * num2; switch (category) { case DamageCategory.Pierce: val3 *= 1.16f; num7 *= 0.84f; break; case DamageCategory.Blunt: val3 *= 1.05f; num7 *= 1.65f; num8 *= Mathf.Clamp(bluntLifetimeMultiplier.Value, 1f, 2.5f); break; case DamageCategory.BiteOrMonsterHit: val3 += val * Random.Range(-1f, 1f); break; } GetStreak().Activate(owner, source, val3, num7, num8, color, GetRandomTrailTexture(), Random.Range(0f, 360f)); streaksSpawned++; } } private void SpawnBallisticDroplets(Transform owner, Vector3 source, Vector3 sprayDirection, int dropletCount, float severity, DamageCategory category, Color color, bool heavyImpact, bool groundedLethal) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_010b: 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_0126: 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_0130: 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) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //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_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.Cross(Vector3.up, sprayDirection); if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = Vector3.right; } ((Vector3)(ref val)).Normalize(); float num = Mathf.Lerp(3f, 9.8f, severity); float num2 = (heavyImpact ? 1.65f : 1.05f); if (groundedLethal) { num *= 0.68f; num2 = 0.15f; } for (int i = 0; i < dropletCount; i++) { float num3 = ((category == DamageCategory.Blunt) ? 1.55f : 1.1f); float num4 = Random.Range(0f - num3, num3); float num5 = Random.Range(-0.12f, 0.7f); Vector3 val2 = Random.insideUnitSphere * 0.13f; val2.y = Mathf.Abs(val2.y) * 0.35f; Vector3 val3 = sprayDirection + val * num4 * 0.5f + Vector3.up * num5 + val2; Vector3 normalized = ((Vector3)(ref val3)).normalized; float num6 = num * Random.Range(0.6f, 1.3f); Vector3 val4 = normalized * num6 + Vector3.up * (num2 * Random.Range(0.28f, 1.25f)); if (groundedLethal) { val4.y = Mathf.Min(val4.y, 0.32f); } switch (category) { case DamageCategory.Pierce: val4 *= 1.15f; break; case DamageCategory.Blunt: val4 *= 1.1f; break; case DamageCategory.Fire: case DamageCategory.Poison: val4 *= 0.72f; break; } float num7 = Mathf.Lerp(0.03f, 0.105f, severity) * Random.Range(0.7f, 1.3f) * 1.12f; float num8 = Mathf.Max(0.22f, dropletLifetime.Value) * Random.Range(0.74f, 1.18f) * 1.1f; if (groundedLethal) { num8 = Mathf.Min(num8, 0.62f); } float num9 = Mathf.Lerp(0.75f, heavyImpact ? 1.55f : 1.18f, severity) * Random.Range(0.82f, 1.2f); if (category == DamageCategory.Blunt && heavyImpact) { float num10 = Mathf.Clamp(bluntBurstSizeMultiplier.Value, 1f, 2.5f); float num11 = Mathf.Clamp(bluntSplatSizeMultiplier.Value, 1f, 2.5f); num7 *= Mathf.Lerp(1.05f, num10, 0.52f); num8 *= Mathf.Clamp(bluntLifetimeMultiplier.Value, 1f, 2.5f); num9 *= num11; } GetDroplet().Activate(owner, source, val4, num7, num8, num9, color, GetRandomDropletTexture(), Random.Range(0f, 360f)); dropletsSpawned++; } } private void TryCreateImmediateImpactSplat(Transform owner, Vector3 sourcePosition, float size, Color color, Vector3 preferredWallDirection) { //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_000b: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0042: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_00f0: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: 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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0168: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) Vector3 origin = sourcePosition + Vector3.up * 1.15f; if (TryFindSurface(owner, origin, Vector3.down, 3.2f, out var bestHit) && ((RaycastHit)(ref bestHit)).normal.y >= 0.55f) { CreateSurfaceSplat(((RaycastHit)(ref bestHit)).point, ((RaycastHit)(ref bestHit)).normal, size, color, null); } if (!AllowWallMarks) { return; } float distance = ((immediateWallProbeDistance == null) ? 1.35f : Mathf.Clamp(immediateWallProbeDistance.Value, 0.25f, 3f)); Vector3 val = preferredWallDirection; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = (((Object)(object)owner != (Object)null) ? owner.forward : Vector3.forward); val.y = 0f; } ((Vector3)(ref val)).Normalize(); Vector3 val2 = Vector3.Cross(Vector3.up, val); Vector3 normalized = ((Vector3)(ref val2)).normalized; Vector3[] obj = new Vector3[4] { val, default(Vector3), default(Vector3), default(Vector3) }; val2 = val + normalized * 0.38f; obj[1] = ((Vector3)(ref val2)).normalized; val2 = val - normalized * 0.38f; obj[2] = ((Vector3)(ref val2)).normalized; obj[3] = -val; Vector3[] array = (Vector3[])(object)obj; for (int i = 0; i < array.Length; i++) { if (TryFindSurface(owner, sourcePosition + Vector3.up * 0.06f, array[i], distance, out var bestHit2) && !(((RaycastHit)(ref bestHit2)).normal.y > 0.54f)) { CreateSurfaceSplat(((RaycastHit)(ref bestHit2)).point, ((RaycastHit)(ref bestHit2)).normal, size * 0.82f, color, null); break; } } } internal void LandDropletOnSurface(Transform owner, Vector3 point, Vector3 normal, Transform parent, float dropletScale, float landingScale, Color color) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) surfaceLandingEvents++; float size = Mathf.Clamp(dropletScale * 4.2f * landingScale, 0.07f, 0.64f); CreateSurfaceSplat(point, normal, size, color, parent); } internal void LandDropletFallback(Transform owner, Vector3 position, float dropletScale, float landingScale, Color color) { //IL_001f: 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_003b: Unknown result type (might be due to invalid IL or missing references) fallbackLandingEvents++; if (!CreateFallbackSplatsWhenAirborne) { RecordAirborneFallbackDiscarded(); } else { TryCreateImmediateImpactSplat(owner, position, Mathf.Clamp(dropletScale * 3.5f * landingScale, 0.07f, 0.46f), color, Vector3.zero); } } private void CreateSurfaceSplat(Vector3 worldPosition, Vector3 normal, float size, Color color, Transform surfaceParent) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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) if (!((Object)(object)visualRoot == (Object)null) && IsValidBloodSurfaceNormal(normal)) { size = Mathf.Clamp(size, 0.04f, 0.58f); CrimsonBloodSplat splat = GetSplat(); if (!((Object)(object)splat == (Object)null)) { float lifetime = Mathf.Max(8f, splatLifetime.Value) * Random.Range(0.84f, 1.12f); splat.Activate(visualRoot, worldPosition, normal, size, lifetime, color, GetRandomSplatTexture(), Random.Range(0f, 360f)); splatsSpawned++; } } } private bool TryFindSurface(Transform owner, Vector3 origin, Vector3 direction, float distance, out RaycastHit bestHit) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_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) bestHit = default(RaycastHit); int num = Physics.RaycastNonAlloc(origin, direction, immediateSurfaceHits, distance, -1, (QueryTriggerInteraction)1); float num2 = float.MaxValue; bool result = false; for (int i = 0; i < num; i++) { Collider collider = ((RaycastHit)(ref immediateSurfaceHits[i])).collider; if (!((Object)(object)collider == (Object)null) && (!((Object)(object)owner != (Object)null) || !((Component)collider).transform.IsChildOf(owner)) && !IsRejectedBloodSurface(collider) && IsValidBloodSurfaceNormal(((RaycastHit)(ref immediateSurfaceHits[i])).normal) && !(((RaycastHit)(ref immediateSurfaceHits[i])).distance >= num2)) { num2 = ((RaycastHit)(ref immediateSurfaceHits[i])).distance; bestHit = immediateSurfaceHits[i]; result = true; } } return result; } private CrimsonBloodBurst GetBurst() { RemoveDestroyedPoolEntries(burstPool); if (burstPool.Count == 0) { CreateBurstPoolObject(0); } for (int i = 0; i < burstPool.Count; i++) { CrimsonBloodBurst crimsonBloodBurst = burstPool[i]; if ((Object)(object)crimsonBloodBurst != (Object)null && !((Component)crimsonBloodBurst).gameObject.activeSelf) { return crimsonBloodBurst; } } CrimsonBloodBurst crimsonBloodBurst2 = burstPool[0]; for (int j = 1; j < burstPool.Count; j++) { if ((Object)(object)burstPool[j] != (Object)null && burstPool[j].ActivatedAt < crimsonBloodBurst2.ActivatedAt) { crimsonBloodBurst2 = burstPool[j]; } } recycledBursts++; crimsonBloodBurst2.Deactivate(); return crimsonBloodBurst2; } private CrimsonBloodStreak GetStreak() { RemoveDestroyedPoolEntries(streakPool); if (streakPool.Count == 0) { CreateStreakPoolObject(0); } for (int i = 0; i < streakPool.Count; i++) { CrimsonBloodStreak crimsonBloodStreak = streakPool[i]; if ((Object)(object)crimsonBloodStreak != (Object)null && !((Component)crimsonBloodStreak).gameObject.activeSelf) { return crimsonBloodStreak; } } CrimsonBloodStreak crimsonBloodStreak2 = streakPool[0]; for (int j = 1; j < streakPool.Count; j++) { if ((Object)(object)streakPool[j] != (Object)null && streakPool[j].ActivatedAt < crimsonBloodStreak2.ActivatedAt) { crimsonBloodStreak2 = streakPool[j]; } } recycledStreaks++; crimsonBloodStreak2.Deactivate(); return crimsonBloodStreak2; } private CrimsonBloodDroplet GetDroplet() { RemoveDestroyedPoolEntries(dropletPool); if (dropletPool.Count == 0) { CreateDropletPoolObject(0); } for (int i = 0; i < dropletPool.Count; i++) { CrimsonBloodDroplet crimsonBloodDroplet = dropletPool[i]; if ((Object)(object)crimsonBloodDroplet != (Object)null && !((Component)crimsonBloodDroplet).gameObject.activeSelf) { return crimsonBloodDroplet; } } CrimsonBloodDroplet crimsonBloodDroplet2 = dropletPool[0]; for (int j = 1; j < dropletPool.Count; j++) { if ((Object)(object)dropletPool[j] != (Object)null && dropletPool[j].ActivatedAt < crimsonBloodDroplet2.ActivatedAt) { crimsonBloodDroplet2 = dropletPool[j]; } } recycledDroplets++; crimsonBloodDroplet2.Deactivate(); return crimsonBloodDroplet2; } private CrimsonBloodSplat GetSplat() { RemoveDestroyedPoolEntries(splatPool); if (splatPool.Count == 0) { CreateSplatPoolObject(0); } for (int i = 0; i < splatPool.Count; i++) { CrimsonBloodSplat crimsonBloodSplat = splatPool[i]; if ((Object)(object)crimsonBloodSplat != (Object)null && !((Component)crimsonBloodSplat).gameObject.activeSelf) { return crimsonBloodSplat; } } CrimsonBloodSplat crimsonBloodSplat2 = splatPool[0]; for (int j = 1; j < splatPool.Count; j++) { if ((Object)(object)splatPool[j] != (Object)null && splatPool[j].ActivatedAt < crimsonBloodSplat2.ActivatedAt) { crimsonBloodSplat2 = splatPool[j]; } } recycledSplats++; crimsonBloodSplat2.Deactivate(); return crimsonBloodSplat2; } private void RemoveDestroyedPoolEntries<T>(List<T> pool) where T : MonoBehaviour { for (int num = pool.Count - 1; num >= 0; num--) { if (!((Object)(object)pool[num] != (Object)null)) { pool.RemoveAt(num); destroyedPoolEntriesRecovered++; } } } private Texture2D GetRandomDropletTexture() { if (dropletTextures.Count != 0) { return dropletTextures[Random.Range(0, dropletTextures.Count)]; } return fallbackDropletTexture; } private Texture2D GetRandomSplatTexture() { if (splatTextures.Count != 0) { return splatTextures[Random.Range(0, splatTextures.Count)]; } return fallbackSplatTexture; } private Texture2D GetRandomTrailTexture() { if (trailTextures.Count != 0) { return trailTextures[Random.Range(0, trailTextures.Count)]; } return fallbackTrailTexture; } private DamageCategory ResolveDamageCategory(HitData hit) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (hit == null) { return DamageCategory.Unknown; } if (string.Equals(((object)Unsafe.As<HitType, HitType>(ref hit.m_hitType)/*cast due to .constrained prefix*/).ToString(), "Fall", StringComparison.OrdinalIgnoreCase)) { return DamageCategory.Fall; } object obj = hit.m_damage; if (obj == null) { return DamageCategory.Unknown; } float damageValue = GetDamageValue(obj, "m_fire"); float damageValue2 = GetDamageValue(obj, "m_poison"); float damageValue3 = GetDamageValue(obj, "m_slash"); float damageValue4 = GetDamageValue(obj, "m_pierce"); float damageValue5 = GetDamageValue(obj, "m_chop"); float damageValue6 = GetDamageValue(obj, "m_blunt"); if (damageValue > 0.001f && damageValue >= damageValue2 && damageValue >= damageValue3 && damageValue >= damageValue4 && damageValue >= damageValue5 && damageValue >= damageValue6) { return DamageCategory.Fire; } if (damageValue2 > 0.001f && damageValue2 >= damageValue3 && damageValue2 >= damageValue4 && damageValue2 >= damageValue5 && damageValue2 >= damageValue6) { return DamageCategory.Poison; } if (damageValue4 > 0.001f && damageValue4 >= damageValue3 && damageValue4 >= damageValue5 && damageValue4 >= damageValue6) { return DamageCategory.Pierce; } if (damageValue3 > 0.001f && damageValue3 >= damageValue5 && damageValue3 >= damageValue6) { return DamageCategory.Slash; } if (damageValue5 > 0.001f && damageValue5 >= damageValue6) { return DamageCategory.Chop; } if (damageValue6 > 0.001f) { if (!string.Equals(((object)Unsafe.As<HitType, HitType>(ref hit.m_hitType)/*cast due to .constrained prefix*/).ToString(), "EnemyHit", StringComparison.OrdinalIgnoreCase)) { return DamageCategory.Blunt; } return DamageCategory.BiteOrMonsterHit; } return DamageCategory.Unknown; } private float GetDamageValue(object damage, string fieldName) { if (damage == null || string.IsNullOrEmpty(fieldName)) { return 0f; } Type type = damage.GetType(); if (!damageFieldCache.TryGetValue(type, out var value)) { value = type.GetFields(BindingFlags.Instance | BindingFlags.Public); damageFieldCache[type] = value; } for (int i = 0; i < value.Length; i++) { if (string.Equals(value[i].Name, fieldName, StringComparison.Ordinal)) { try { object value2 = value[i].GetValue(damage); return (value2 is float) ? Mathf.Max(0f, (float)value2) : 0f; } catch { return 0f; } } } return 0f; } private static Vector3 ResolveImpactPoint(Character target, HitData hit) { //IL_000b: 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_0010: 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_0017: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) Vector3 val = hit?.m_point ?? Vector3.zero; Vector3 centerPoint = target.GetCenterPoint(); if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f)) { Vector3 val2 = val - centerPoint; if (!(((Vector3)(ref val2)).sqrMagnitude > 36f)) { goto IL_003e; } } val = centerPoint; goto IL_003e; IL_003e: return val; } private static Vector3 ResolveOutwardSprayDirection(Character target, HitData hit, Vector3 impactPoint) { //IL_000b: 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_0010: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_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_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_006b: 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_0060: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_009b: 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_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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_00de: 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_00bf: Unknown result type (might be due to invalid IL or missing references) Vector3 val = hit?.m_dir ?? Vector3.zero; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = ((Component)target).transform.forward; } val = ((Vector3)(ref val)).normalized; Vector3 centerPoint = target.GetCenterPoint(); Vector3 val2 = impactPoint - centerPoint; val2.y *= 0.55f; if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f) { val2 = val; } else { ((Vector3)(ref val2)).Normalize(); if (Vector3.Dot(val2, val) < 0f) { val2 = -val2; } } Vector3 val3 = val * 0.78f + val2 * 0.32f + Vector3.up * 0.06f; if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f) { val3 = val; } val3.y = Mathf.Clamp(val3.y, -0.12f, 0.42f); return ((Vector3)(ref val3)).normalized; } private static Color ResolveBloodColor(Character target, DamageCategory category) { //IL_003a: 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) string text = GetTargetName(target).ToLowerInvariant(); if (text.Contains("skeleton") || text.Contains("ghost")) { return new Color(0.075f, 0.012f, 0.016f, 0.8f); } return new Color(0.34f, 0.02f, 0.025f, 0.88f); } private static string GetTargetName(Character target) { if ((Object)(object)target == (Object)null) { return "unknown"; } try { string text = (((Object)(object)((Component)target).gameObject != (Object)null) ? ((Object)((Component)target).gameObject).name : string.Empty); if (!string.IsNullOrEmpty(text)) { return text.Replace("(Clone)", string.Empty).Trim(); } } catch { } return ((object)target).GetType().Name; } private void RememberEvent(string eventText) { lastEvent = eventText; while (recentEvents.Count >= 20) { recentEvents.Dequeue(); } recentEvents.Enqueue(eventText); } private void TrimExpiredCooldowns() { if (nextAllowedImpactTime.Count == 0) { return; } List<int> list = null; foreach (KeyValuePair<int, float> item in nextAllowedImpactTime) { if (!(item.Value >= Time.time)) { if (list == null) { list = new List<int>(); } list.Add(item.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { nextAllowedImpactTime.Remove(list[i]); } } } private void ClearLoadedAssetLists() { burstTextures.Clear(); dropletTextures.Clear(); splatTextures.Clear(); trailTextures.Clear(); } private void DestroyVisualSystem() { if ((Object)(object)visualRoot != (Object)null) { Object.Destroy((Object)(object)((Component)visualRoot).gameObject); visualRoot = null; } for (int i = 0; i < ownedMaterials.Count; i++) { if ((Object)(object)ownedMaterials[i] != (Object)null) { Object.Destroy((Object)(object)ownedMaterials[i]); } } for (int j = 0; j < ownedTextures.Count; j++) { if ((Object)(object)ownedTextures[j] != (Object)null) { Object.Destroy((Object)(object)ownedTextures[j]); } } ownedMaterials.Clear(); ownedTextures.Clear(); burstPool.Clear(); streakPool.Clear(); dropletPool.Clear(); splatPool.Clear(); ClearLoadedAssetLists(); quadMaterial = null; fallbackDropletTexture = null; fallbackBurstTexture = null; fallbackSplatTexture = null; fallbackTrailTexture = null; } private void WriteDiagnostics() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Crimson Blood 0.7.6.2 Safe Vanilla Mute / Falling Blood status:"); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" Enabled=" + enabledConfig.Value + " | Local-only visuals | YoureInjuredLoaded=" + IsYoureInjuredLoaded())); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" AssetLoad=" + assetLoadSummary)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" ApplyDamageHookCalls=" + applyDamageHookCalls + " | ObservedDamageCalls=" + observedDamageCalls)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" RealHealthLossEvents=" + realHealthLossEvents + " | ZeroHealthLossEvents=" + zeroHealthLossEvents)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" VisualEvents=" + visualEvents + " | Bursts=" + burstsSpawned + " | Streaks=" + streaksSpawned + " | Droplets=" + dropletsSpawned + " | Splats=" + splatsSpawned)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" Recycled: bursts=" + recycledBursts + ", streaks=" + recycledStreaks + ", droplets=" + recycledDroplets + ", splats=" + recycledSplats + ", destroyedPoolEntriesRecovered=" + destroyedPoolEntriesRecovered)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" Skipped: playerCompatibility=" + suppressedPlayerImpactEvents + ", cooldown=" + cooldownSkippedEvents + ", distance=" + distanceSkippedEvents)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" RenderDistance: dynamic=" + DynamicEffectRenderDistance.ToString("0.##") + "m, splat=" + SurfaceSplatRenderDistance.ToString("0.##") + "m")); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" Landings: surfaceHit=" + surfaceLandingEvents + ", fallback=" + fallbackLandingEvents + ", discardedFallback=" + fallbackSplatsDiscarded + ", characterSurfaceSkipped=" + characterSurfaceSkips + ", rigidbodySurfaceSkipped=" + rigidbodySurfaceSkips + ", invalidSurfaceSkipped=" + invalidSurfaceSkips + ", groundedLethalFinishes=" + groundedLethalFinishes)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" StaticSurfaceMarks: wallsAndSteep=" + AllowWallMarks + ", immediateWallProbe=" + ((immediateWallProbeDistance == null) ? 1.35f : immediateWallProbeDistance.Value).ToString("0.##") + "m, airborneFallbackSplats=" + CreateFallbackSplatsWhenAirborne)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" VanillaEffects: observed=" + observedVanillaEffectRoots + ", muted=" + suppressedVanillaBloodEffects + ", unmatched=" + unmatchedVanillaEffectRoots + ", mutedRenderers=" + mutedVanillaRenderers + ", particleRenderersIncluded=true, tokens=" + ((vanillaBloodEffectTokens == null) ? "blood,bleed,gore,splatter" : vanillaBloodEffectTokens.Value))); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" Pool: bursts=" + burstPool.Count + ", streaks=" + streakPool.Count + ", droplets=" + dropletPool.Count + ", splats=" + splatPool.Count)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" HeavyBlunt: bloodMultiplier=" + bluntBloodMultiplier.Value.ToString("0.##") + ", maxDroplets=" + bluntMaximumDropletsPerHit.Value + ", burstSize=" + bluntBurstSizeMultiplier.Value.ToString("0.##") + ", splatSize=" + bluntSplatSizeMultiplier.Value.ToString("0.##") + ", lifetime=" + bluntLifetimeMultiplier.Value.ToString("0.##"))); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" LastEvent=" + lastEvent)); ((BaseUnityPlugin)this).Logger.LogInfo((object)(" RecentEvents=" + recentEvents.Count)); foreach (string recentEvent in recentEvents) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(" " + recentEvent)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)(" RecentVanillaEffectRoots=" + recentVanillaEffectRoots.Count)); foreach (string recentVanillaEffectRoot in recentVanillaEffectRoots) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(" " + recentVanillaEffectRoot)); } } private static string FormatVector(Vector3 value) { return "(" + value.x.ToString("0.##") + "," + value.y.ToString("0.##") + "," + value.z.ToString("0.##") + ")"; } } internal enum DamageCategory { Unknown, Slash, Pierce, Blunt, Chop, Fire, Poison, Fall, BiteOrMonsterHit } internal sealed class CrimsonDamageSnapshot { public bool Observe; public float HealthBefore; } [HarmonyPatch(typeof(Character), "ApplyDamage")] internal static class CharacterApplyDamageCrimsonPatch { [HarmonyPrefix] private static void Prefix(Character __instance, out CrimsonDamageSnapshot __state) { __state = new CrimsonDamageSnapshot(); CrimsonBloodPlugin instance = CrimsonBloodPlugin.Instance; if (!((Object)(object)instance == (Object)null)) { instance.BeginVanillaEffectWindow(__instance); instance.RecordHookCall(); if (instance.ShouldObserve(__instance)) { __state.Observe = true; __state.HealthBefore = (((Object)(object)__instance != (Object)null) ? __instance.GetHealth() : 0f); } } } [HarmonyPostfix] private static void Postfix(Character __instance, HitData __0, CrimsonDamageSnapshot __state) { if (__state != null && __state.Observe && !((Object)(object)__instance == (Object)null)) { CrimsonBloodPlugin instance = CrimsonBloodPlugin.Instance; if ((Object)(object)instance != (Object)null) { instance.RecordDamage(__instance, __0, __state.HealthBefore); } } } } [HarmonyPatch(typeof(EffectList), "Create", new Type[] { typeof(Vector3), typeof(Quaternion), typeof(Transform), typeof(float), typeof(int) })] internal static class EffectListCreateCrimsonPatch { [HarmonyPostfix] private static void Postfix(GameObject[] __result) { CrimsonBloodPlugin instance = CrimsonBloodPlugin.Instance; if ((Object)(object)instance != (Object)null) { instance.OnVanillaEffectsCreated(__result); } } } internal sealed class CrimsonBloodBurst : MonoBehaviour { private CrimsonBloodPlugin plugin; private Renderer cachedRenderer; private MaterialPropertyBlock propertyBlock; private List<Texture2D> frames; private Vector3 velocity; private float remainingLifetime; private float startLifetime; private float baseSize; private float rotationDegrees; private Color color; private int lastFrameIndex; internal float ActivatedAt { get; private set; } internal void Initialize(CrimsonBloodPlugin sourcePlugin, Renderer renderer) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown plugin = sourcePlugin; cachedRenderer = renderer; propertyBlock = new MaterialPropertyBlock(); } internal void Activate(Transform owner, Vector3 position, Vector3 startVelocity, float size, float lifetime, Color startColor, List<Texture2D> sourceFrames, float randomRotation) { //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_0040: 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_0078: 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) velocity = startVelocity; remainingLifetime = Mathf.Max(0.05f, lifetime); startLifetime = remainingLifetime; baseSize = Mathf.Max(0.05f, size); rotationDegrees = randomRotation; color = startColor; frames = ((sourceFrames != null && sourceFrames.Count > 0) ? sourceFrames : null); lastFrameIndex = -1; ActivatedAt = Time.time; ((Component)this).transform.position = position; if ((Object)(object)cachedRenderer != (Object)null) { cachedRenderer.enabled = true; } ApplyFrame(0, color); UpdateBillboardAndScale(0f); ((Component)this).gameObject.SetActive(true); } internal void Deactivate() { frames = null; if ((Object)(object)cachedRenderer != (Object)null) { cachedRenderer.enabled = true; } ((Component)this).gameObject.SetActive(false); } private void Update() { //IL_002b: 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_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_0051: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_00df: 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_0117: 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) if ((Object)(object)plugin == (Object)null) { Deactivate(); return; } float deltaTime = Time.deltaTime; remainingLifetime -= deltaTime; velocity += Physics.gravity * (plugin.DropletGravityMultiplier * 0.12f) * deltaTime; Transform transform = ((Component)this).transform; transform.position += velocity * deltaTime; float num = 1f - Mathf.Clamp01(remainingLifetime / Mathf.Max(0.01f, startLifetime)); int frameIndex = ((frames != null && frames.Count != 0) ? Mathf.Min(frames.Count - 1, Mathf.FloorToInt(num * (float)frames.Count)) : 0); Color targetColor = color; float num2 = ((num > 0.55f) ? Mathf.Clamp01((1f - num) / 0.45f) : 1f); targetColor.a *= num2; ApplyFrame(frameIndex, targetColor); UpdateBillboardAndScale(num); if ((Object)(object)cachedRenderer != (Object)null) { cachedRenderer.enabled = plugin.ShouldRenderEffectAt(((Component)this).transform.position, isSurfaceMark: false); } if (remainingLifetime <= 0f) { Deactivate(); } } private void UpdateBillboardAndScale(float age) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) Camera val = (((Object)(object)plugin != (Object)null) ? plugin.RenderCamera : null); if ((Object)(object)val != (Object)null) { Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val2)).sqrMagnitude > 0.001f) { ((Component)this).transform.rotation = Quaternion.LookRotation(((Vector3)(ref val2)).normalized, ((Component)val).transform.up) * Quaternion.Euler(0f, 0f, rotationDegrees); } } Texture2D val3 = ((frames != null && frames.Count > 0) ? frames[Mathf.Clamp(lastFrameIndex, 0, frames.Count - 1)] : null); float num = (((Object)(object)val3 != (Object)null && ((Texture)val3).height > 0) ? ((float)((Texture)val3).width / (float)((Texture)val3).height) : 1f); float num2 = Mathf.Lerp(0.38f, 1.18f, Mathf.Clamp01(age / 0.68f)); ((Component)this).transform.localScale = new Vector3(baseSize * num * num2, baseSize * num2, 1f); } private void ApplyFrame(int frameIndex, Color targetColor) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)cachedRenderer == (Object)null)) { if (frames != null && frames.Count > 0) { frameIndex = Mathf.Clamp(frameIndex, 0, frames.Count - 1); lastFrameIndex = frameIndex; Texture2D val = frames[frameIndex]; propertyBlock.SetTexture("_MainTex", (Texture)(object)val); propertyBlock.SetTexture("_BaseMap", (Texture)(object)val); } propertyBlock.SetColor("_Color", targetColor); propertyBlock.SetColor("_BaseColor", targetColor); cachedRenderer.SetPropertyBlock(propertyBlock); } } } internal sealed class CrimsonBloodStreak : MonoBehaviour { private CrimsonBloodPlugin plugin; private Renderer cachedRenderer; private MaterialPropertyBlock propertyBlock; private Vector3 velocity; private float remainingLifetime; private float startLifetime; private float width; private float rotationDegrees; private Color color; private Texture2D texture; internal float ActivatedAt { get; private set; } internal void Initialize(CrimsonBloodPlugin sourcePlugin, Renderer renderer) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown plugin = sourcePlugin; cachedRenderer = renderer; propertyBlock = new MaterialPropertyBlock(); } internal void Activate(Transform owner, Vector3 position, Vector3 startVelocity, float startWidth, float lifetime, Color startColor, Texture2D startTexture, float randomRotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to in