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 enabledConfig; private ConfigEntry diagnosticKey; private ConfigEntry clearDiagnosticsKey; private ConfigEntry visualDistance; private ConfigEntry dynamicEffectRenderDistance; private ConfigEntry surfaceSplatRenderDistance; private ConfigEntry minimumHealthLossForVisual; private ConfigEntry perTargetCooldown; private ConfigEntry useExternalAssetTextures; private ConfigEntry assetRootFolder; private ConfigEntry useHighDefinitionGroundSplats; private ConfigEntry maximumBurstTextures; private ConfigEntry maximumTrailTextures; private ConfigEntry maximumGroundSplatTextures; private ConfigEntry burstPoolSize; private ConfigEntry streakPoolSize; private ConfigEntry dropletPoolSize; private ConfigEntry splatPoolSize; private ConfigEntry maximumDropletsPerHit; private ConfigEntry maximumStreaksPerHeavyHit; private ConfigEntry maximumBurstsPerHeavyHit; private ConfigEntry dropletGravity; private ConfigEntry dropletLifetime; private ConfigEntry streakLifetime; private ConfigEntry burstLifetime; private ConfigEntry splatLifetime; private ConfigEntry minimumSplatHealthLoss; private ConfigEntry createImmediateImpactSplats; private ConfigEntry allowWallMarks; private ConfigEntry groundOnlySurfaceMarks; private ConfigEntry createFallbackSplatsWhenAirborne; private ConfigEntry surfaceOffset; private ConfigEntry splatSettleSeconds; private ConfigEntry allowPlayerImpactVisuals; private ConfigEntry suppressPlayerImpactsWhenYoureInjuredLoaded; private ConfigEntry disableVanillaBloodEffects; private ConfigEntry vanillaBloodEffectTokens; private ConfigEntry recordVanillaEffectRoots; private ConfigEntry vanillaEffectWindowSeconds; private ConfigEntry immediateWallProbeDistance; private ConfigEntry useGroundedLethalFinish; private ConfigEntry logVisualEvents; private ConfigEntry bluntBloodMultiplier; private ConfigEntry bluntMaximumDropletsPerHit; private ConfigEntry bluntBurstSizeMultiplier; private ConfigEntry bluntSplatSizeMultiplier; private ConfigEntry 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 burstTextures = new List(); private readonly List dropletTextures = new List(); private readonly List splatTextures = new List(); private readonly List trailTextures = new List(); private readonly List ownedTextures = new List(); private readonly List ownedMaterials = new List(); private readonly List burstPool = new List(); private readonly List streakPool = new List(); private readonly List dropletPool = new List(); private readonly List splatPool = new List(); private readonly Dictionary nextAllowedImpactTime = new Dictionary(); private readonly Dictionary damageFieldCache = new Dictionary(); private readonly Queue recentEvents = new Queue(); private readonly Queue recentVanillaEffectRoots = new Queue(); 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() != (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(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 ""; } 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("0 - Master", "Enabled", true, "Turns Crimson Blood's local visual layer on or off. It never changes combat balance."); diagnosticKey = ((BaseUnityPlugin)this).Config.Bind("0 - Master", "DiagnosticKey", (KeyCode)292, "Writes Crimson Blood diagnostic information to BepInEx/LogOutput.log."); clearDiagnosticsKey = ((BaseUnityPlugin)this).Config.Bind("0 - Master", "ClearDiagnosticsKey", (KeyCode)293, "Clears Crimson Blood's recent diagnostic event list."); visualDistance = ((BaseUnityPlugin)this).Config.Bind("1 - Safety", "VisualDistanceMetres", 80f, "Maximum distance from the local player at which combat blood visuals are created."); dynamicEffectRenderDistance = ((BaseUnityPlugin)this).Config.Bind("1 - Safety", "DynamicEffectRenderDistanceMetres", 24f, "Maximum distance from the camera at which airborne bursts, streaks, and droplets remain visible."); surfaceSplatRenderDistance = ((BaseUnityPlugin)this).Config.Bind("1 - Safety", "SurfaceSplatRenderDistanceMetres", 18f, "Maximum distance from the camera at which surface blood marks remain visible."); minimumHealthLossForVisual = ((BaseUnityPlugin)this).Config.Bind("1 - Safety", "MinimumActualHealthLoss", 0.1f, "Actual health lost after armour, blocking and resistances required before a visual may spawn."); perTargetCooldown = ((BaseUnityPlugin)this).Config.Bind("1 - Safety", "PerTargetImpactCooldownSeconds", 0.06f, "Stops rapid repeated damage ticks from producing excessive visual bursts."); useExternalAssetTextures = ((BaseUnityPlugin)this).Config.Bind("2 - Asset Loading", "UseExternalAssetTextures", true, "Loads supplied transparent PNG effects from the assets folder beside CrimsonBlood.dll."); assetRootFolder = ((BaseUnityPlugin)this).Config.Bind("2 - Asset Loading", "AssetRootFolder", "assets", "Folder beside CrimsonBlood.dll that contains sprays, trails, and ground_splats."); useHighDefinitionGroundSplats = ((BaseUnityPlugin)this).Config.Bind("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("2 - Asset Loading", "MaximumBurstTextures", 6, "Maximum number of splash-frame textures loaded from assets/sprays/blood_splash_frames."); maximumTrailTextures = ((BaseUnityPlugin)this).Config.Bind("2 - Asset Loading", "MaximumTrailTextures", 8, "Maximum number of trail/droplet textures loaded from assets/trails."); maximumGroundSplatTextures = ((BaseUnityPlugin)this).Config.Bind("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("3 - Safety Pools", "ImpactBurstPoolSize", 20, "Pre-warmed maximum number of animated impact burst sprites."); streakPoolSize = ((BaseUnityPlugin)this).Config.Bind("3 - Safety Pools", "PressureStreakPoolSize", 22, "Pre-warmed maximum number of pressure spray streaks."); dropletPoolSize = ((BaseUnityPlugin)this).Config.Bind("3 - Safety Pools", "DropletPoolSize", 112, "Pre-warmed maximum number of moving droplets."); splatPoolSize = ((BaseUnityPlugin)this).Config.Bind("3 - Safety Pools", "SurfaceSplatPoolSize", 112, "Pre-warmed maximum number of temporary blood splats."); maximumDropletsPerHit = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "MaximumDropletsPerHit", 18, "Upper safety cap for liquid droplets created by one strong hit."); maximumStreaksPerHeavyHit = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "MaximumPressureStreaksPerHeavyHit", 4, "Upper safety cap for streaks on stronger hits."); maximumBurstsPerHeavyHit = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "MaximumAnimatedBurstsPerHeavyHit", 2, "Upper safety cap for animated splash bursts on stronger hits."); dropletGravity = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "DropletGravityMultiplier", 1.85f, "Gravity multiplier for airborne droplets. Higher values make them fall and hit surfaces sooner."); dropletLifetime = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "DropletLifetimeSeconds", 1.2f, "Maximum airborne lifetime before a droplet fades or tries a final nearby splat."); streakLifetime = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "PressureStreakLifetimeSeconds", 0.18f, "Lifetime of directional pressure spray streaks."); burstLifetime = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "ImpactBurstLifetimeSeconds", 0.16f, "Lifetime of animated impact burst sprites."); splatLifetime = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "SurfaceSplatLifetimeSeconds", 120f, "How long temporary ground/structure blood remains before fading."); minimumSplatHealthLoss = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "MinimumHealthLossForImmediateImpactSplat", 0.85f, "Health loss required before an immediate blood mark may appear below/near the impact."); createImmediateImpactSplats = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "CreateImmediateImpactSplats", true, "Places one small wet mark near a meaningful hit where a suitable surface exists."); allowWallMarks = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "AllowWallAndSteepSurfaceBloodMarks", true, "Allows blood marks on static walls, wooden structures, steep rocks, floors, and terrain."); groundOnlySurfaceMarks = ((BaseUnityPlugin)this).Config.Bind("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("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("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("4 - Look", "SurfaceOffset", 0.006f, "Small offset that keeps a blood mark just above its surface and avoids flickering."); splatSettleSeconds = ((BaseUnityPlugin)this).Config.Bind("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("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("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("4 - Look", "BluntHeavyHitBurstSizeMultiplier", 1.6f, "Size multiplier for animated impact bursts created by strong blunt hits."); bluntSplatSizeMultiplier = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "BluntHeavyHitSplatSizeMultiplier", 1.45f, "Size multiplier for blood marks created by strong blunt hits."); bluntLifetimeMultiplier = ((BaseUnityPlugin)this).Config.Bind("4 - Look", "BluntHeavyHitLifetimeMultiplier", 1.38f, "Makes blunt-hit bursts, droplets, and streaks stay visible slightly longer."); allowPlayerImpactVisuals = ((BaseUnityPlugin)this).Config.Bind("5 - Player Compatibility", "AllowPlayerImpactVisuals", true, "Allows Crimson Blood to create impact visuals when the local player takes real damage."); suppressPlayerImpactsWhenYoureInjuredLoaded = ((BaseUnityPlugin)this).Config.Bind("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("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("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("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("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("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("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 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?)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(); ConfigureRenderer(component, quadMaterial); CrimsonBloodBurst crimsonBloodBurst = obj.AddComponent(); 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(); ConfigureRenderer(component, quadMaterial); CrimsonBloodDroplet crimsonBloodDroplet = obj.AddComponent(); 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(); ConfigureRenderer(component, quadMaterial); CrimsonBloodStreak crimsonBloodStreak = obj.AddComponent(); 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(); ConfigureRenderer((Renderer)(object)component, quadMaterial); CrimsonBloodSplat crimsonBloodSplat = obj.AddComponent(); crimsonBloodSplat.Initialize(this, component); obj.SetActive(false); splatPool.Add(crimsonBloodSplat); } private static void RemoveCollider(GameObject gameObject) { Collider component = gameObject.GetComponent(); 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(List 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(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(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 list = null; foreach (KeyValuePair item in nextAllowedImpactTime) { if (!(item.Value >= Time.time)) { if (list == null) { list = new List(); } 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 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 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 invalid IL or missing references) //IL_0038: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) velocity = startVelocity; remainingLifetime = Mathf.Max(0.05f, lifetime); startLifetime = remainingLifetime; width = Mathf.Max(0.008f, startWidth); color = startColor; texture = startTexture; rotationDegrees = randomRotation; ActivatedAt = Time.time; ((Component)this).transform.position = position; if ((Object)(object)cachedRenderer != (Object)null) { cachedRenderer.enabled = true; } ApplyTextureAndColor(color); UpdateBillboardAndScale(); ((Component)this).gameObject.SetActive(true); } internal void Deactivate() { texture = 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_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_00b2: 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) if ((Object)(object)plugin == (Object)null) { Deactivate(); return; } float deltaTime = Time.deltaTime; remainingLifetime -= deltaTime; velocity += Physics.gravity * (plugin.DropletGravityMultiplier * 0.34f) * deltaTime; Transform transform = ((Component)this).transform; transform.position += velocity * deltaTime; Color targetColor = color; targetColor.a *= Mathf.Clamp01(remainingLifetime / Mathf.Max(0.04f, startLifetime * 0.38f)); ApplyTextureAndColor(targetColor); UpdateBillboardAndScale(); if ((Object)(object)cachedRenderer != (Object)null) { cachedRenderer.enabled = plugin.ShouldRenderEffectAt(((Component)this).transform.position, isSurfaceMark: false); } if (remainingLifetime <= 0f) { Deactivate(); } } private void UpdateBillboardAndScale() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0084: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) Camera val = (((Object)(object)plugin != (Object)null) ? plugin.RenderCamera : null); float magnitude = ((Vector3)(ref velocity)).magnitude; float num = rotationDegrees; Quaternion val2 = Quaternion.identity; if ((Object)(object)val != (Object)null) { Vector3 val3 = ((Component)val).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val3)).sqrMagnitude > 0.001f) { val2 = Quaternion.LookRotation(((Vector3)(ref val3)).normalized, ((Component)val).transform.up); } if (magnitude > 0.001f) { Vector3 val4 = velocity / magnitude; float num2 = Vector3.Dot(val4, ((Component)val).transform.right); float num3 = Vector3.Dot(val4, ((Component)val).transform.up); num += Mathf.Atan2(num3, num2) * 57.29578f - 90f; } } ((Component)this).transform.rotation = val2 * Quaternion.Euler(0f, 0f, num); float num4 = 1f - Mathf.Clamp01(remainingLifetime / Mathf.Max(0.01f, startLifetime)); float num5 = Mathf.Lerp(width * 2.2f, width * 8.5f, Mathf.Clamp01(1f - num4 * 0.45f)); float num6 = (((Object)(object)texture != (Object)null && ((Texture)texture).height > 0) ? ((float)((Texture)texture).width / (float)((Texture)texture).height) : 1f); ((Component)this).transform.localScale = new Vector3(width * num6, num5, 1f); } private void ApplyTextureAndColor(Color targetColor) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)cachedRenderer == (Object)null)) { propertyBlock.SetTexture("_MainTex", (Texture)(object)texture); propertyBlock.SetTexture("_BaseMap", (Texture)(object)texture); propertyBlock.SetColor("_Color", targetColor); propertyBlock.SetColor("_BaseColor", targetColor); cachedRenderer.SetPropertyBlock(propertyBlock); } } } internal sealed class CrimsonBloodDroplet : MonoBehaviour { private static readonly RaycastHit[] SurfaceHits = (RaycastHit[])(object)new RaycastHit[16]; private CrimsonBloodPlugin plugin; private Renderer cachedRenderer; private MaterialPropertyBlock propertyBlock; private Transform owner; private Vector3 velocity; private float remainingLifetime; private float startLifetime; private float dropletScale; private float landingScale; private float randomRotation; 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 sourceOwner, Vector3 position, Vector3 startVelocity, float startScale, float lifetime, float startLandingScale, Color startColor, Texture2D startTexture, float startRotation) { //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_0051: 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_0079: 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) owner = sourceOwner; velocity = startVelocity; dropletScale = Mathf.Max(0.012f, startScale); landingScale = Mathf.Max(0.2f, startLandingScale); remainingLifetime = Mathf.Max(0.08f, lifetime); startLifetime = remainingLifetime; color = startColor; texture = startTexture; randomRotation = startRotation; ActivatedAt = Time.time; ((Component)this).transform.position = position; if ((Object)(object)cachedRenderer != (Object)null) { cachedRenderer.enabled = true; } ApplyTextureAndColor(color); UpdateBillboardAndScale(); ((Component)this).gameObject.SetActive(true); } internal void Deactivate() { owner = null; texture = null; if ((Object)(object)cachedRenderer != (Object)null) { cachedRenderer.enabled = true; } ((Component)this).gameObject.SetActive(false); } private void Update() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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; Vector3 position = ((Component)this).transform.position; velocity += Physics.gravity * plugin.DropletGravityMultiplier * deltaTime; Vector3 val = position + velocity * deltaTime; if (TryFindSurface(position, val, out var bestHit)) { Transform parent = (((Object)(object)((RaycastHit)(ref bestHit)).collider != (Object)null) ? ((Component)((RaycastHit)(ref bestHit)).collider).transform : null); plugin.LandDropletOnSurface(owner, ((RaycastHit)(ref bestHit)).point, ((RaycastHit)(ref bestHit)).normal, parent, dropletScale, landingScale, color); Deactivate(); return; } ((Component)this).transform.position = val; UpdateBillboardAndScale(); Color targetColor = color; targetColor.a *= Mathf.Clamp01(remainingLifetime / Mathf.Max(0.08f, startLifetime * 0.3f)); ApplyTextureAndColor(targetColor); if ((Object)(object)cachedRenderer != (Object)null) { cachedRenderer.enabled = plugin.ShouldRenderEffectAt(((Component)this).transform.position, isSurfaceMark: false); } if (remainingLifetime <= 0f) { plugin.LandDropletFallback(owner, ((Component)this).transform.position, dropletScale, landingScale, color); Deactivate(); } } private bool TryFindSurface(Vector3 from, Vector3 to, out RaycastHit bestHit) { //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_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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_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_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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) bestHit = default(RaycastHit); Vector3 val = to - from; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.0001f) { return false; } val /= magnitude; float num = Mathf.Max(0.003f, dropletScale * 0.22f); int num2 = Physics.SphereCastNonAlloc(from, num, val, SurfaceHits, magnitude + 0.018f, -1, (QueryTriggerInteraction)1); float num3 = float.MaxValue; bool result = false; for (int i = 0; i < num2; i++) { Collider collider = ((RaycastHit)(ref SurfaceHits[i])).collider; if (!((Object)(object)collider == (Object)null) && (!((Object)(object)owner != (Object)null) || !((Component)collider).transform.IsChildOf(owner)) && !plugin.IsRejectedBloodSurface(collider) && plugin.IsValidBloodSurfaceNormal(((RaycastHit)(ref SurfaceHits[i])).normal) && !(((RaycastHit)(ref SurfaceHits[i])).distance >= num3)) { num3 = ((RaycastHit)(ref SurfaceHits[i])).distance; bestHit = SurfaceHits[i]; result = true; } } return result; } private void UpdateBillboardAndScale() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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) Camera val = (((Object)(object)plugin != (Object)null) ? plugin.RenderCamera : null); float magnitude = ((Vector3)(ref velocity)).magnitude; float num = Mathf.Clamp(0.7f + magnitude * 0.075f, 0.7f, 2.25f); float num2 = randomRotation; Quaternion val2 = Quaternion.identity; if ((Object)(object)val != (Object)null) { Vector3 val3 = ((Component)val).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val3)).sqrMagnitude > 0.001f) { val2 = Quaternion.LookRotation(((Vector3)(ref val3)).normalized, ((Component)val).transform.up); } if (magnitude > 0.001f) { Vector3 val4 = velocity / magnitude; float num3 = Vector3.Dot(val4, ((Component)val).transform.right); float num4 = Vector3.Dot(val4, ((Component)val).transform.up); num2 += Mathf.Atan2(num4, num3) * 57.29578f - 90f; } } ((Component)this).transform.rotation = val2 * Quaternion.Euler(0f, 0f, num2); float num5 = (((Object)(object)texture != (Object)null && ((Texture)texture).height > 0) ? ((float)((Texture)texture).width / (float)((Texture)texture).height) : 1f); float num6 = dropletScale * Mathf.Lerp(0.92f, 0.58f, Mathf.Clamp01((num - 0.7f) / 1.55f)); float num7 = dropletScale * num; ((Component)this).transform.localScale = new Vector3(num6 * num5, num7, 1f); } private void ApplyTextureAndColor(Color targetColor) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)cachedRenderer == (Object)null)) { propertyBlock.SetTexture("_MainTex", (Texture)(object)texture); propertyBlock.SetTexture("_BaseMap", (Texture)(object)texture); propertyBlock.SetColor("_Color", targetColor); propertyBlock.SetColor("_BaseColor", targetColor); cachedRenderer.SetPropertyBlock(propertyBlock); } } } internal sealed class CrimsonBloodSplat : MonoBehaviour { private CrimsonBloodPlugin plugin; private MeshRenderer meshRenderer; private MaterialPropertyBlock propertyBlock; private float remainingLifetime; private float startLifetime; private float settledSize; private Color color; private Texture2D texture; internal float ActivatedAt { get; private set; } internal void Initialize(CrimsonBloodPlugin sourcePlugin, MeshRenderer renderer) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown plugin = sourcePlugin; meshRenderer = renderer; propertyBlock = new MaterialPropertyBlock(); } internal void Activate(Transform parent, Vector3 worldPosition, Vector3 normal, float size, float lifetime, Color startColor, Texture2D startTexture, float rotationDegrees) { //IL_003e: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) ((Component)this).transform.SetParent(parent, true); remainingLifetime = Mathf.Max(1f, lifetime); startLifetime = remainingLifetime; settledSize = Mathf.Max(0.03f, size); color = startColor; texture = startTexture; ActivatedAt = Time.time; ((Component)this).transform.position = worldPosition + normal * plugin.SurfaceOffset; ((Component)this).transform.rotation = Quaternion.FromToRotation(Vector3.forward, normal) * Quaternion.Euler(0f, 0f, rotationDegrees); ((Component)this).transform.localScale = Vector3.one * settledSize * 0.2f; if ((Object)(object)meshRenderer != (Object)null) { ((Renderer)meshRenderer).enabled = true; } ApplyTextureAndColor(color); ((Component)this).gameObject.SetActive(true); } internal void Deactivate() { if ((Object)(object)plugin != (Object)null && (Object)(object)((Component)plugin).transform != (Object)null) { ((Component)this).transform.SetParent(((Component)plugin).transform, false); } texture = null; if ((Object)(object)meshRenderer != (Object)null) { ((Renderer)meshRenderer).enabled = true; } ((Component)this).gameObject.SetActive(false); } private void Update() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)plugin == (Object)null) { Deactivate(); return; } remainingLifetime -= Time.deltaTime; float num = Mathf.Clamp01(Mathf.Max(0f, Time.time - ActivatedAt) / plugin.SplatSettleSeconds); num = num * num * (3f - 2f * num); ((Component)this).transform.localScale = Vector3.one * settledSize * Mathf.Lerp(0.2f, 1f, num); float num2 = Mathf.Max(12f, startLifetime * 0.16f); float num3 = ((remainingLifetime < num2) ? Mathf.Clamp01(remainingLifetime / num2) : 1f); Color targetColor = color; targetColor.a *= num3; ApplyTextureAndColor(targetColor); if ((Object)(object)meshRenderer != (Object)null) { ((Renderer)meshRenderer).enabled = plugin.ShouldRenderEffectAt(((Component)this).transform.position, isSurfaceMark: true); } if (remainingLifetime <= 0f) { Deactivate(); } } private void ApplyTextureAndColor(Color targetColor) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)meshRenderer == (Object)null)) { propertyBlock.SetTexture("_MainTex", (Texture)(object)texture); propertyBlock.SetTexture("_BaseMap", (Texture)(object)texture); propertyBlock.SetColor("_Color", targetColor); propertyBlock.SetColor("_BaseColor", targetColor); ((Renderer)meshRenderer).SetPropertyBlock(propertyBlock); } } } internal static class CrimsonAssetLoader { private static MethodInfo textureLoadImageMethod; private static MethodInfo imageConversionLoadImageMethod; private static bool searchedImageLoadMethods; internal static bool TryLoadAlphaMaskPng(string path, out Texture2D texture, out string error) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) texture = null; error = string.Empty; if (string.IsNullOrEmpty(path) || !File.Exists(path)) { error = "File does not exist."; return false; } Texture2D val = null; try { byte[] array = File.ReadAllBytes(path); if (array == null || array.Length == 0) { error = "File was empty."; return false; } ResolveImageLoadMethods(); val = new Texture2D(2, 2, (TextureFormat)4, false); bool flag = false; if (imageConversionLoadImageMethod != null) { object obj = imageConversionLoadImageMethod.Invoke(null, new object[3] { val, array, false }); flag = obj is bool && (bool)obj; } if (!flag && textureLoadImageMethod != null) { object obj2 = textureLoadImageMethod.Invoke(val, new object[2] { array, false }); flag = obj2 is bool && (bool)obj2; } if (!flag) { Object.Destroy((Object)(object)val); val = null; error = ((imageConversionLoadImageMethod == null && textureLoadImageMethod == null) ? "No Unity PNG decoder was found. Expected ImageConversion.LoadImage or Texture2D.LoadImage." : "Unity rejected this PNG."); return false; } Color32[] pixels = val.GetPixels32(); for (int i = 0; i < pixels.Length; i++) { byte a = pixels[i].a; pixels[i] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, a); } val.SetPixels32(pixels); ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; val.Apply(false, true); texture = val; return true; } catch (TargetInvocationException ex) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } error = ((ex.InnerException != null) ? ex.InnerException.Message : ex.Message); return false; } catch (Exception ex2) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } error = ex2.Message; return false; } } private static void ResolveImageLoadMethods() { if (searchedImageLoadMethods) { return; } searchedImageLoadMethods = true; try { textureLoadImageMethod = typeof(Texture2D).GetMethod("LoadImage", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(byte[]), typeof(bool) }, null); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { if (!(imageConversionLoadImageMethod == null)) { break; } Type type = assemblies[i].GetType("UnityEngine.ImageConversion", throwOnError: false); if (!(type == null)) { imageConversionLoadImageMethod = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, null); } } } catch { } } internal static Texture2D CreateSoftCircleTexture(string name, int size, float alpha) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false); ((Object)val).name = name; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; float num = (float)(size - 1) * 0.5f; float num2 = num * 0.94f; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num3 = ((float)j - num) / num2; float num4 = ((float)i - num) / num2; float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4); float num6 = Mathf.Clamp01(1f - num5); num6 = num6 * num6 * (3f - 2f * num6) * alpha; val.SetPixel(j, i, new Color(1f, 1f, 1f, num6)); } } val.Apply(false, true); return val; } internal static Texture2D CreateTrailTexture(string name, int width, int height) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(width, height, (TextureFormat)4, false); ((Object)val).name = name; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; float num = (float)(width - 1) * 0.5f; for (int i = 0; i < height; i++) { float num2 = (float)i / (float)(height - 1); float num3 = Mathf.Lerp(0.95f, 0.1f, num2); for (int j = 0; j < width; j++) { float num4 = Mathf.Abs(((float)j - num) / Mathf.Max(1f, num)); float num5 = Mathf.Clamp01(1f - num4 / Mathf.Max(0.08f, num3)); num5 *= Mathf.Lerp(0.82f, 0.2f, num2); num5 *= num5; val.SetPixel(j, i, new Color(1f, 1f, 1f, num5)); } } val.Apply(false, true); return val; } internal static Texture2D CreateBurstTexture(string name, int size) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false); ((Object)val).name = name; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; float num = (float)(size - 1) * 0.5f; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num2 = ((float)j - num) / num; float num3 = ((float)i - num) / num; float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3); float num5 = Mathf.Atan2(num3, num2); float num6 = 0.72f + 0.28f * Mathf.Abs(Mathf.Sin(num5 * 5.5f)); float num7 = Mathf.Clamp01(1f - num4 / num6); num7 = num7 * num7 * (3f - 2f * num7); val.SetPixel(j, i, new Color(1f, 1f, 1f, num7)); } } val.Apply(false, true); return val; } internal static Texture2D CreateIrregularSplatTexture(string name, int size) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false); ((Object)val).name = name; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; float num = (float)(size - 1) * 0.5f; float num2 = num * 0.95f; float num3 = Random.Range(0f, 100f); float num4 = Random.Range(100f, 200f); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num5 = ((float)j - num) / num2; float num6 = ((float)i - num) / num2; float num7 = Mathf.Sqrt(num5 * num5 + num6 * num6); float num8 = Mathf.PerlinNoise(num3 + num5 * 2.2f, num3 + num6 * 2.2f); float num9 = Mathf.PerlinNoise(num4 + num5 * 5.4f, num4 + num6 * 5.4f); float num10 = Mathf.Lerp(0.75f, 1.18f, num8 * 0.7f + num9 * 0.3f); float num11 = Mathf.Clamp01(1f - num7 / Mathf.Max(0.01f, num10)); num11 = num11 * num11 * (3f - 2f * num11); val.SetPixel(j, i, new Color(1f, 1f, 1f, num11)); } } val.Apply(false, true); return val; } }