Decompiled source of Blood System v3.4.1

BloodSystem.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")]
[assembly: AssemblyCompany("BloodSystem")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+449acb6bb3a2ebf7106d764eb3f17bfa0ecf1d98")]
[assembly: AssemblyProduct("BloodSystem")]
[assembly: AssemblyTitle("BloodSystem")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BloodSystem;

internal static class BloodThermal
{
	private struct MatRef
	{
		public Material Mat;

		public MatKey Key;

		public bool Drip;

		public MatRef(Material mat, MatKey key, bool drip)
		{
			Mat = mat;
			Key = key;
			Drip = drip;
		}
	}

	private class Cohort
	{
		public int Id;

		public int CurveClass;

		public float StartTime;

		public float RetireTime;

		public int Step;

		public float NextEvent;

		public float AmbIntensity;

		public bool AmbSampled;

		public readonly List<MatRef> Mats = new List<MatRef>();

		public readonly List<Renderer> Renderers = new List<Renderer>();
	}

	private const int MAX_CLASSES = 20;

	private const string P_INTENSITY = "_ThermalIntensity";

	private const string P_TRANSVIS = "_ThermalTransparentVisibility";

	private const string P_NOALPHA = "_ThermalDisableAlphaBlend";

	private const string P_HEATMAP = "_ThermalHeatMap";

	private const string P_HEATMAPSCL = "_ThermalHeatMapScale";

	private const string P_DISABLE = "_ThermalDisable";

	private const string P_COLORALPHA = "_ThermalUseColorAlpha";

	private const string P_VERTEXCOLOR = "_ThermalUseVertexColor";

	internal static ConfigEntry<bool> CfgAnimate;

	private const float COOL_SECONDS = 8f;

	private const int STEPS = 80;

	private const float COHORT_WINDOW = 0.5f;

	private const int CLASSES = 4;

	private const float FRAGMENT_WEIGHT = 1f;

	private const bool STAGGER = true;

	private const bool STAGGER_OUTWARD = false;

	private const float DENSE_LINEARITY = 0.75f;

	private const float TAIL_LINEARITY = 0.3f;

	private const float SPARSE_COOL_MULT = 1.6f;

	private const float FRESH_INTENSITY = 27f;

	private const float START_TEMP_C = 36f;

	private const float AMBIENT_TEMP_C = 20f;

	private const bool USE_VOLUMES = true;

	private const int DENSITY_BLUR = 4;

	private const float DENSITY_BLUR_FRACTION = 0.03f;

	private const bool OPAQUE_IN_THERMAL = false;

	private const float HEATMAP_STRENGTH = 1f;

	private const bool SHAPE_VIA_HEATMAP = true;

	private const bool USE_PROPERTY_BLOCK = false;

	private const bool DEBUG_LOG = false;

	private const float DEBUG_FORCE = -1f;

	private const float AMBIENT_OVERRIDE = -1f;

	private static float[][] _stepTime;

	private static float[][] _heatFrac;

	private static int _classes = 1;

	private static int _steps = 1;

	private static float _quantum = 2.5f;

	private static float _hotOffset;

	private static bool _usePropertyBlock;

	private static bool _shapeViaHeatMap;

	private static bool _forced;

	private static float _forcedValue;

	private static bool _enabled;

	private static bool _keepWarm;

	internal const bool NormalizeDensity = true;

	internal const float FragmentWeight = 1f;

	internal const int DensityBlur = 4;

	internal const float DensityBlurFraction = 0.03f;

	private static readonly Dictionary<int, Cohort> _cohorts = new Dictionary<int, Cohort>();

	private static readonly List<Cohort> _live = new List<Cohort>();

	private static readonly List<Cohort> _done = new List<Cohort>();

	private static readonly List<Cohort> _retire = new List<Cohort>();

	private static float _nextEvent = float.MaxValue;

	private static bool _armed;

	private static MaterialPropertyBlock _mpb;

	private static readonly HashSet<string> _diagLoggedScenes = new HashSet<string>();

	private static int _dbgSteps;

	private static int _dbgWrites;

	private static readonly Dictionary<Texture, Texture> _heatMasks = new Dictionary<Texture, Texture>();

	internal static int Classes => _classes;

	internal static int ActiveClasses
	{
		get
		{
			if (!_armed)
			{
				return 1;
			}
			return _classes;
		}
	}

	internal static bool Enabled => _enabled;

	internal static void BindConfig(ConfigFile cfg)
	{
		CfgAnimate = cfg.Bind<bool>("Thermal", "Animate Cooldown", true, "Whether blood cools down on thermal optics. On: blood leaves the body hot and fades to the temperature of its surroundings over about eight seconds, thicker pooled areas holding their heat longer than scattered spray. Off: blood still shows up on thermal at body temperature but stays there for as long as the decal lasts, and none of the cooling machinery runs at all.");
	}

	internal static void Init()
	{
		_enabled = true;
		_keepWarm = !CfgAnimate.Value;
		_usePropertyBlock = false;
		_shapeViaHeatMap = true;
		_forcedValue = -1f;
		_forced = _forcedValue >= 0f;
		_classes = (_keepWarm ? 1 : Mathf.Clamp(4, 1, 20));
		_steps = Mathf.Clamp(80, 2, 160);
		_hotOffset = 27f;
		float num = 16f;
		float num2 = 16f;
		_hotOffset = ((Mathf.Abs(num) < 0.01f) ? 27f : (27f * (num2 / num)));
		BuildStepTables();
		_quantum = Mathf.Max(0.25f, 0.5f);
		_cohorts.Clear();
		_live.Clear();
		_done.Clear();
		_nextEvent = float.MaxValue;
		_armed = false;
		BloodSystemPlugin.Log.LogInfo((object)("[BloodSystem] Thermal: enabled=" + _enabled + " classes=" + _classes + " steps=" + _steps + " quantum=" + _quantum.ToString("F2") + "s hotOffset=" + _hotOffset.ToString("F1") + " mode=" + (_usePropertyBlock ? "PropertyBlock" : "Material") + (_keepWarm ? " KEEP-WARM" : "") + (_forced ? (" FORCED=" + _forcedValue.ToString("F1")) : "")));
	}

	internal static void LogThermalDiagnostics(Camera cam)
	{
		//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_0108: 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_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			Material decalSourceMat = BloodSystemPlugin._decalSourceMat;
			string item = name + "|" + ((decalSourceMat == null) ? "none" : ((Object)decalSourceMat.shader).name);
			if (_diagLoggedScenes.Add(item))
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("[BloodSystem] THERMAL DIAG scene='").Append(name).Append("'");
				FXM instance = ManagerSingleton<FXM>.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					stringBuilder.Append(" | FXM=MISSING (no thermal shader available)");
				}
				else
				{
					Shader thermalShader = instance.ThermalShader;
					stringBuilder.Append(" | FXM=ok ThermalShader=").Append((thermalShader == null) ? "NULL" : ((Object)thermalShader).name).Append((thermalShader == null) ? "" : (thermalShader.isSupported ? " (supported)" : " (NOT SUPPORTED)"));
				}
				if (cam != null)
				{
					stringBuilder.Append(" | cam='").Append(((Object)cam).name).Append("'")
						.Append(" clear=")
						.Append(cam.clearFlags)
						.Append(" bg=")
						.Append(cam.backgroundColor)
						.Append(" path=")
						.Append(cam.actualRenderingPath);
				}
				stringBuilder.Append(" | ObjectTemperatures=").Append((ObjectTemperature.allTemperatureObjects == null) ? (-1) : ObjectTemperature.allTemperatureObjects.Count);
				stringBuilder.Append(" TemperatureVolumes=").Append((TemperatureVolume.volumes == null) ? (-1) : TemperatureVolume.volumes.Count);
				Material decalSourceMat2 = BloodSystemPlugin._decalSourceMat;
				stringBuilder.Append(" | decalSrc=").Append((decalSourceMat2 == null) ? "none" : (((Object)decalSourceMat2.shader).name + " RenderType=" + decalSourceMat2.GetTag("RenderType", false, "<none>")));
				stringBuilder.Append(" | ambientLight=").Append(RenderSettings.ambientLight).Append(" ambientIntensity=")
					.Append(RenderSettings.ambientIntensity.ToString("F2"));
				BloodSystemPlugin.Log.LogInfo((object)stringBuilder.ToString());
			}
		}
		catch (Exception ex)
		{
			BloodSystemPlugin.Log.LogWarning((object)("[BloodSystem] THERMAL DIAG failed: " + ex.Message));
		}
	}

	internal static void DebugNoteChunks(int chunkCount, int dotCount)
	{
	}

	private static void BuildStepTables()
	{
		_stepTime = new float[_classes][];
		_heatFrac = new float[_classes][];
		float num = Mathf.Max(0.25f, 8f);
		for (int i = 0; i < _classes; i++)
		{
			float num2 = ((_classes == 1) ? 0f : ((float)i / (float)(_classes - 1)));
			float num3 = Mathf.Clamp01(0.75f);
			float num4 = Mathf.Clamp01(0.3f);
			float linearity = Mathf.Lerp(num4, Mathf.Max(num3, num4), 1f - num2);
			float num5 = num / Mathf.Lerp(1f, Mathf.Max(0.05f, 1.6f), num2);
			float k = 4f / num5;
			float num6 = 0f;
			if (_classes > 1)
			{
				int num7 = i;
				num6 = num5 / (float)(_steps - 1) * (float)num7 / (float)_classes;
			}
			_stepTime[i] = new float[_steps];
			_heatFrac[i] = new float[_steps];
			for (int j = 0; j < _steps; j++)
			{
				float num8 = 1f - (float)j / (float)(_steps - 1);
				_heatFrac[i][j] = num8;
				_stepTime[i][j] = ((j == 0) ? 0f : (SolveTime(num8, k, num5, linearity) + num6));
			}
		}
	}

	private static float CoolCurve(float t, float k, float tau, float linearity)
	{
		if (t >= tau)
		{
			return 0f;
		}
		float num = Mathf.Lerp(Mathf.Exp((0f - k) * t), Mathf.Max(0f, 1f - t / tau), linearity);
		float num2 = Mathf.Lerp(Mathf.Exp((0f - k) * tau), 0f, linearity);
		return Mathf.Clamp01((num - num2) / Mathf.Max(0.0001f, 1f - num2));
	}

	private static float SolveTime(float targetFrac, float k, float tau, float linearity)
	{
		if (targetFrac <= 0f)
		{
			return tau;
		}
		float num = 0f;
		float num2 = tau;
		for (int i = 0; i < 40; i++)
		{
			float num3 = (num + num2) * 0.5f;
			if (CoolCurve(num3, k, tau, linearity) > targetFrac)
			{
				num = num3;
			}
			else
			{
				num2 = num3;
			}
		}
		return (num + num2) * 0.5f;
	}

	internal static int CurrentCohort(int curveClass)
	{
		if (!_enabled)
		{
			return 0;
		}
		if (curveClass < 0)
		{
			curveClass = 0;
		}
		if (curveClass >= _classes)
		{
			curveClass = _classes - 1;
		}
		int num = Mathf.FloorToInt(Time.time / _quantum);
		int num2 = num * 20 + curveClass;
		if (!_cohorts.TryGetValue(num2, out var value))
		{
			value = new Cohort
			{
				Id = num2,
				CurveClass = curveClass,
				StartTime = (float)num * _quantum,
				Step = 0,
				AmbSampled = false
			};
			value.RetireTime = value.StartTime + _quantum + BloodSystemPlugin.CfgLifetime.Value + 1f;
			value.NextEvent = ((_keepWarm || _forced) ? value.RetireTime : (value.StartTime + _stepTime[curveClass][1]));
			_cohorts[num2] = value;
			_live.Add(value);
			if (value.NextEvent < _nextEvent)
			{
				_nextEvent = value.NextEvent;
			}
		}
		return num2;
	}

	internal static void RegisterMaterial(Material m, MatKey key, bool drip)
	{
		if (!_enabled || m == null)
		{
			return;
		}
		ApplyShapeProps(m);
		if (_cohorts.TryGetValue(key.Cohort, out var value))
		{
			value.Mats.Add(new MatRef(m, key, drip));
			if (_forced)
			{
				WriteHeat(m, _forcedValue, value.AmbIntensity);
			}
			else if (_armed || _keepWarm)
			{
				WriteHeat(m, IntensityAt(value, value.Step), value.AmbIntensity);
			}
		}
	}

	internal static void MarkAlwaysHot(Material m)
	{
		if (_enabled && m != null)
		{
			ApplyShapeProps(m);
			WriteHeat(m, _forced ? _forcedValue : _hotOffset, 0f);
		}
	}

	internal static void RegisterHeatMask(Texture visible, Texture heat)
	{
		if (visible != null && heat != null)
		{
			_heatMasks[visible] = heat;
		}
	}

	private static Texture HeatMaskFor(Texture visible)
	{
		if (visible == null)
		{
			return null;
		}
		if (!_heatMasks.TryGetValue(visible, out var value))
		{
			return visible;
		}
		return value;
	}

	private static void ApplyShapeProps(Material m)
	{
		Texture val = HeatMaskFor(m.mainTexture);
		bool flag = val != null;
		m.SetFloat("_ThermalTransparentVisibility", 1f);
		m.SetFloat("_ThermalDisableAlphaBlend", 0f);
		m.SetFloat("_ThermalDisable", 0f);
		m.SetFloat("_ThermalUseColorAlpha", 0f);
		m.SetFloat("_ThermalUseVertexColor", 0f);
		m.SetTexture("_ThermalHeatMap", (Texture)(flag ? ((object)val) : ((object)Texture2D.whiteTexture)));
		if (!_shapeViaHeatMap)
		{
			m.SetFloat("_ThermalHeatMapScale", flag ? Mathf.Max(0f, 1f) : 0f);
		}
	}

	private static void WriteHeat(Material m, float v, float amb)
	{
		if (_shapeViaHeatMap)
		{
			m.SetFloat("_ThermalIntensity", amb);
			m.SetFloat("_ThermalHeatMapScale", (v - amb) * Mathf.Max(0f, 1f));
		}
		else
		{
			m.SetFloat("_ThermalIntensity", v);
		}
	}

	internal static void RegisterRenderer(Renderer r, int cohortId, Vector3 worldPos)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		if (!_enabled || r == null)
		{
			return;
		}
		NoteSpawnPosition(cohortId, worldPos);
		if (_usePropertyBlock && _cohorts.TryGetValue(cohortId, out var value))
		{
			value.Renderers.Add(r);
			if (_forced)
			{
				ApplyToRenderer(r, _forcedValue, value.AmbIntensity);
			}
			else if (_armed || _keepWarm)
			{
				ApplyToRenderer(r, IntensityAt(value, value.Step), value.AmbIntensity);
			}
		}
	}

	internal static void NoteSpawnPosition(int cohortId, Vector3 worldPos)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		if (_enabled && _cohorts.TryGetValue(cohortId, out var value) && !value.AmbSampled)
		{
			SampleAmbient(value, worldPos);
		}
	}

	private static void SampleAmbient(Cohort co, Vector3 worldPos)
	{
		//IL_003f: 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_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		co.AmbSampled = true;
		co.AmbIntensity = 0f;
		List<TemperatureVolume> volumes = TemperatureVolume.volumes;
		if (volumes == null || volumes.Count == 0)
		{
			return;
		}
		float num = 0f;
		for (int i = 0; i < volumes.Count; i++)
		{
			TemperatureVolume val = volumes[i];
			if (val != null)
			{
				Vector3 val2 = worldPos - ((Component)val).transform.position;
				bool flag;
				if (val.spherical)
				{
					float num2 = Mathf.Max(val.size.x, Mathf.Max(val.size.y, val.size.z)) + val.blendDistance;
					flag = ((Vector3)(ref val2)).sqrMagnitude <= num2 * num2;
				}
				else
				{
					flag = Mathf.Abs(val2.x) <= val.size.x + val.blendDistance && Mathf.Abs(val2.y) <= val.size.y + val.blendDistance && Mathf.Abs(val2.z) <= val.size.z + val.blendDistance;
				}
				if (flag && Mathf.Abs(val.thermalIntensity) > Mathf.Abs(num))
				{
					num = val.thermalIntensity;
				}
			}
		}
		co.AmbIntensity = num;
	}

	private static float IntensityAt(Cohort co, int step)
	{
		if (step >= _steps)
		{
			step = _steps - 1;
		}
		return co.AmbIntensity + _hotOffset * _heatFrac[co.CurveClass][step];
	}

	internal static void OnSceneChanged()
	{
		_armed = false;
		for (int num = _live.Count - 1; num >= 0; num--)
		{
			Retire(_live[num]);
		}
		for (int num2 = _done.Count - 1; num2 >= 0; num2--)
		{
			Retire(_done[num2]);
		}
		_live.Clear();
		_done.Clear();
		_cohorts.Clear();
		_nextEvent = float.MaxValue;
	}

	internal static void Arm()
	{
		if (!_armed && _enabled)
		{
			_armed = true;
			BloodSystemPlugin.Log.LogInfo((object)"[BloodSystem] Thermal armed - a thermal camera rendered in this scene, blood heat is now being applied.");
			for (int i = 0; i < _live.Count; i++)
			{
				ApplyCohort(_live[i]);
			}
			for (int j = 0; j < _done.Count; j++)
			{
				ApplyCohort(_done[j]);
			}
		}
	}

	internal static void Tick()
	{
		if (!_enabled)
		{
			return;
		}
		float time = Time.time;
		if (time < _nextEvent)
		{
			return;
		}
		float num = float.MaxValue;
		_retire.Clear();
		for (int num2 = _live.Count - 1; num2 >= 0; num2--)
		{
			Cohort cohort = _live[num2];
			if (time >= cohort.RetireTime)
			{
				_live.RemoveAt(num2);
				_retire.Add(cohort);
			}
			else
			{
				bool flag = false;
				while (cohort.Step < _steps - 1 && time >= cohort.NextEvent)
				{
					cohort.Step++;
					flag = true;
					cohort.NextEvent = ((cohort.Step < _steps - 1) ? (cohort.StartTime + _stepTime[cohort.CurveClass][cohort.Step + 1]) : cohort.RetireTime);
				}
				if (flag && _armed)
				{
					ApplyCohort(cohort);
				}
				if (cohort.Step >= _steps - 1)
				{
					_live.RemoveAt(num2);
					_done.Add(cohort);
					if (cohort.RetireTime < num)
					{
						num = cohort.RetireTime;
					}
				}
				else if (cohort.NextEvent < num)
				{
					num = cohort.NextEvent;
				}
			}
		}
		while (_done.Count > 0 && time >= _done[0].RetireTime)
		{
			_retire.Add(_done[0]);
			_done.RemoveAt(0);
		}
		if (_done.Count > 0 && _done[0].RetireTime < num)
		{
			num = _done[0].RetireTime;
		}
		for (int i = 0; i < _retire.Count; i++)
		{
			Retire(_retire[i]);
		}
		_retire.Clear();
		_nextEvent = num;
	}

	private static void ApplyCohort(Cohort co)
	{
		float v = (_forced ? _forcedValue : IntensityAt(co, co.Step));
		if (_usePropertyBlock)
		{
			for (int num = co.Renderers.Count - 1; num >= 0; num--)
			{
				Renderer val = co.Renderers[num];
				if ((Object)(object)val == (Object)null)
				{
					co.Renderers.RemoveAt(num);
				}
				else
				{
					ApplyToRenderer(val, v, co.AmbIntensity);
					_dbgWrites++;
				}
			}
			return;
		}
		for (int i = 0; i < co.Mats.Count; i++)
		{
			Material mat = co.Mats[i].Mat;
			if (mat != null)
			{
				WriteHeat(mat, v, co.AmbIntensity);
				_dbgWrites++;
			}
		}
	}

	private static void ApplyToRenderer(Renderer r, float v, float amb)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected O, but got Unknown
		Material sharedMaterial = r.sharedMaterial;
		Texture val = ((sharedMaterial == null) ? null : HeatMaskFor(sharedMaterial.mainTexture));
		bool flag = val != null;
		if (_mpb == null)
		{
			_mpb = new MaterialPropertyBlock();
		}
		_mpb.Clear();
		r.GetPropertyBlock(_mpb);
		_mpb.SetFloat("_ThermalTransparentVisibility", 1f);
		_mpb.SetFloat("_ThermalDisableAlphaBlend", 0f);
		_mpb.SetFloat("_ThermalDisable", 0f);
		_mpb.SetFloat("_ThermalUseColorAlpha", 0f);
		_mpb.SetFloat("_ThermalUseVertexColor", 0f);
		_mpb.SetTexture("_ThermalHeatMap", (Texture)(flag ? ((object)val) : ((object)Texture2D.whiteTexture)));
		if (_shapeViaHeatMap && flag)
		{
			_mpb.SetFloat("_ThermalIntensity", amb);
			_mpb.SetFloat("_ThermalHeatMapScale", (v - amb) * Mathf.Max(0f, 1f));
		}
		else
		{
			_mpb.SetFloat("_ThermalIntensity", v);
			_mpb.SetFloat("_ThermalHeatMapScale", flag ? Mathf.Max(0f, 1f) : 0f);
		}
		r.SetPropertyBlock(_mpb);
	}

	private static void Retire(Cohort co)
	{
		for (int i = 0; i < co.Mats.Count; i++)
		{
			MatRef matRef = co.Mats[i];
			if (matRef.Drip)
			{
				BloodSystemPlugin._dripMatCache.Remove(matRef.Key);
			}
			else
			{
				BloodSystemPlugin._matCache.Remove(matRef.Key);
			}
			if (matRef.Mat != null)
			{
				Object.Destroy((Object)(object)matRef.Mat);
			}
		}
		co.Mats.Clear();
		co.Renderers.Clear();
		_cohorts.Remove(co.Id);
		_live.Remove(co);
		_done.Remove(co);
	}
}
internal struct MatKey : IEquatable<MatKey>
{
	public readonly Color Col;

	public readonly int Cohort;

	public MatKey(Color col, int cohort)
	{
		//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)
		Col = col;
		Cohort = cohort;
	}

	public bool Equals(MatKey o)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		if (Cohort == o.Cohort)
		{
			return ((object)Col/*cast due to .constrained prefix*/).Equals((object?)o.Col);
		}
		return false;
	}

	public override bool Equals(object o)
	{
		if (o is MatKey)
		{
			return Equals((MatKey)o);
		}
		return false;
	}

	public override int GetHashCode()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		return (((object)Col/*cast due to .constrained prefix*/).GetHashCode() * 397) ^ Cohort;
	}
}
internal struct DotData
{
	public Vector3 Pos;

	public Vector3 Norm;

	public float R;

	public float Dark;

	public float Bright;

	public Vector3 TanNorm;

	public Vector3 ElongDir;

	public float Elongation;

	public float Dist;

	public byte CurveClass;

	public DotData(Vector3 pos, Vector3 norm, float r, float dark, float bright, Vector3 tanNorm, Vector3 elongDir, float elongation, float dist, byte curveClass)
	{
		//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_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_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		Pos = pos;
		Norm = norm;
		R = r;
		Dark = dark;
		Bright = bright;
		TanNorm = tanNorm;
		ElongDir = elongDir;
		Elongation = elongation;
		Dist = dist;
		CurveClass = curveClass;
	}
}
[BepInPlugin("h3vr.invent60.bloodsystem", "Blood System", "3.4.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class BloodSystemPlugin : BaseUnityPlugin
{
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	internal struct RhByDist : IComparer<RaycastHit>
	{
		public int Compare(RaycastHit a, RaycastHit b)
		{
			return ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance);
		}
	}

	internal static ManualLogSource Log;

	internal static BloodSystemPlugin _instance;

	internal static ConfigEntry<bool> CfgEnabled;

	internal static ConfigEntry<float> CfgLifetime;

	internal static ConfigEntry<int> CfgRayCount;

	internal static ConfigEntry<float> CfgConeAngle;

	internal static ConfigEntry<float> CfgDotSize;

	internal static ConfigEntry<float> CfgRange;

	internal static ConfigEntry<string> CfgProjectionMode;

	internal static ConfigEntry<float> CfgSpeedRatio;

	internal static ConfigEntry<float> CfgSpeedBias;

	internal static ConfigEntry<float> CfgDotScaleMax;

	internal static ConfigEntry<float> CfgDotScaleRange;

	internal static ConfigEntry<int> CfgGibRayCount;

	internal static ConfigEntry<string> CfgColorOverride;

	internal static ConfigEntry<string> CfgColorOverrideMode;

	internal static ConfigEntry<bool> CfgSplashOnHumans;

	public static float ExternalBloodScale = 1f;

	internal static ConfigEntry<bool> CfgSplatterEnabled;

	internal static ConfigEntry<bool> CfgSprayEnabled;

	internal static ConfigEntry<bool> CfgVanillaStainEnabled;

	internal static ConfigEntry<bool> CfgDripStainsEnabled;

	internal static readonly Color _mustardFallback = new Color(0.9f, 0.8f, 0f, 1f);

	internal static readonly Dictionary<MatKey, Material> _matCache = new Dictionary<MatKey, Material>();

	internal static readonly Dictionary<MatKey, Material> _dripMatCache = new Dictionary<MatKey, Material>();

	private static int _nextShotId;

	private static readonly Dictionary<int, List<GameObject>> _shotGroups = new Dictionary<int, List<GameObject>>();

	private static readonly Queue<int> _shotQueue = new Queue<int>();

	private static readonly Queue<GameObject> _dripQueue = new Queue<GameObject>();

	internal static ConfigEntry<int> CfgMaxShots;

	internal static ConfigEntry<int> CfgMaxDrips;

	private static Shader _bloodShader;

	private static bool _bloodShaderSearched;

	internal static Material _decalSourceMat;

	internal static bool _decalSourceSearched;

	internal static bool _dbgDotLogged;

	internal static bool _dbgDecalLogged;

	private static Texture2D _decalTex;

	private static Texture2D _hardCircleTex;

	private static Texture2D _firstBloodTex;

	private static Texture2D _normalMapTex;

	private static Texture2D _noiseMapTex;

	private static readonly Dictionary<Color, Texture2D> _coloredTexCache = new Dictionary<Color, Texture2D>();

	private static Vector2[] _splatterUVs;

	private static float[] _cumWeights;

	private static float[] _splatterDarks;

	private static float[] _splatterBrights;

	private static Vector3[] _splatterNormals;

	private static byte[] _splatterClasses;

	private static readonly Vector3 _tanLight;

	internal static readonly float[] BRIGHT_LEVELS;

	private static readonly float[] _brightLevels;

	private static ParticleSystem _pelletPS;

	private static ParticleSystem _fogPS;

	private static ParticleSystem _jetPS;

	private static Material _fogMat;

	private static Material _pelletMat;

	private static Material _dotBaseMat;

	private static Mesh _dotQuadMesh;

	private static ParticleSystem _flyingDotPS;

	private static Particle[] _flyBuf;

	private static Particle[] _flyMergeBuf;

	internal static readonly RaycastHit[] _rayBuf;

	internal static readonly RhByDist _rhCompare;

	private static bool _ngaChecked;

	private static bool _ngaKetchup;

	private static Color _ngaColor;

	internal static bool _alloyGrabPending;

	private static Shader _fallbackDecalShader;

	private static bool _fallbackDecalShaderSearched;

	private const int GIB_BATCH = 50;

	private static bool _dbgDropLogged;

	private static bool _growingStainLoggedOnce;

	private static string AlloyMatCachePath => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "alloy_mat.cache");

	private static Color BrightTint(Color col)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: 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)
		float num = _brightLevels[Random.Range(0, _brightLevels.Length)];
		return new Color(col.r * num, col.g * num, col.b * num, col.a);
	}

	private void Awake()
	{
		//IL_038b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0395: Expected O, but got Unknown
		//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b6: 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_03d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_0402: Unknown result type (might be due to invalid IL or missing references)
		//IL_0407: Unknown result type (might be due to invalid IL or missing references)
		//IL_0428: Unknown result type (might be due to invalid IL or missing references)
		//IL_042d: Unknown result type (might be due to invalid IL or missing references)
		//IL_043e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0443: Unknown result type (might be due to invalid IL or missing references)
		//IL_0454: Unknown result type (might be due to invalid IL or missing references)
		//IL_0459: Unknown result type (might be due to invalid IL or missing references)
		//IL_046a: Unknown result type (might be due to invalid IL or missing references)
		//IL_046f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0486: Unknown result type (might be due to invalid IL or missing references)
		//IL_048b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_049e: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_04af: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ee: Expected O, but got Unknown
		//IL_04fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0502: Unknown result type (might be due to invalid IL or missing references)
		//IL_050a: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0561: Unknown result type (might be due to invalid IL or missing references)
		//IL_0570: Unknown result type (might be due to invalid IL or missing references)
		//IL_0575: Unknown result type (might be due to invalid IL or missing references)
		//IL_0585: Unknown result type (might be due to invalid IL or missing references)
		//IL_0372: Unknown result type (might be due to invalid IL or missing references)
		//IL_037c: Expected O, but got Unknown
		//IL_0676: Unknown result type (might be due to invalid IL or missing references)
		//IL_067b: Unknown result type (might be due to invalid IL or missing references)
		//IL_068b: Unknown result type (might be due to invalid IL or missing references)
		//IL_069b: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		_instance = this;
		CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Blood", "Enabled", true, "Toggle all blood effects.");
		CfgLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Blood", "Lifetime seconds", 60f, "How long splash and drip stains last before despawning. Long enough that blood is still around to look at on thermal well after it has finished cooling.");
		CfgRayCount = ((BaseUnityPlugin)this).Config.Bind<int>("Blood", "Max rays per shot", 3000, "Maximum splash ray count. Capped to the actual number of image pixels if fewer.");
		CfgConeAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Blood", "Cone half-angle", 10f, "Half-angle in degrees of the splash cone.");
		CfgDotSize = ((BaseUnityPlugin)this).Config.Bind<float>("Blood", "Dot base radius", 0.008f, "Base radius of each splash dot in metres. Scales to Dot Max Scale at Dot Scale Range distance.");
		CfgRange = ((BaseUnityPlugin)this).Config.Bind<float>("Blood", "Range metres", 40f, "Maximum splash distance in metres.");
		CfgProjectionMode = ((BaseUnityPlugin)this).Config.Bind<string>("Blood", "Projection Mode", "Animated", "How splash dots appear. Animated: dots fly from wound to wall in real-time (best visuals, most FPS cost). Delayed: dots appear all at once after a timed delay with no animation (moderate). Immediate: dots appear instantly with no delay and no animation (cheapest, best for low-end systems).");
		CfgSpeedRatio = ((BaseUnityPlugin)this).Config.Bind<float>("Blood", "Projection Speed Ratio", 2f, "Multiplies bullet exit speed to calculate how fast splash dots travel toward the wall. Higher = faster animation, less time spread between near and far dots. Default 2.");
		CfgSpeedBias = ((BaseUnityPlugin)this).Config.Bind<float>("Blood", "Projection Speed Bias", 10f, "Flat metres-per-second added to projection speed after the ratio multiply. Prevents dots from moving too slowly for low-velocity bullets. Default 10.");
		CfgDotScaleMax = ((BaseUnityPlugin)this).Config.Bind<float>("Blood", "Dot Max Scale", 5f, "Maximum size multiplier applied to splash dots at Dot Scale Range distance. 5 means dots at full range are 5x the base radius. Default 5.");
		CfgDotScaleRange = ((BaseUnityPlugin)this).Config.Bind<float>("Blood", "Dot Scale Range metres", 50f, "Distance in metres at which splash dots reach their maximum size (Dot Max Scale). Dots near the wound start at Dot Base Radius and grow linearly to this range. Default 30.");
		CfgGibRayCount = ((BaseUnityPlugin)this).Config.Bind<int>("Blood", "Gib Ray Count", 200, "Number of rays fired in random 360-degree directions when a segment explodes. Lower values improve FPS in gib-heavy fights. Capped by image pixel count. Default 200.");
		CfgMaxShots = ((BaseUnityPlugin)this).Config.Bind<int>("Blood", "Max shot groups", 20, "Maximum number of shots whose splash and drip decals stay visible. When exceeded, the oldest shot's decals are all deleted together.");
		CfgMaxDrips = ((BaseUnityPlugin)this).Config.Bind<int>("Blood", "Max drip stains", 400, "Maximum drip stains from particle detection (VanillaDripStainer). Oldest deleted when exceeded.");
		CfgColorOverride = ((BaseUnityPlugin)this).Config.Bind<string>("Blood", "Color Override", "#8C1A1A", "Hex color (e.g. #8C1A1A) used for blood when Color Override Mode is set to Soft or Hard. Ignored when mode is Unset.");
		CfgSplashOnHumans = ((BaseUnityPlugin)this).Config.Bind<bool>("Blood", "Splash On Human-mod Humans", false, "Whether the LinkExplodes splash/spray/gib burst plays on Sosigs controlled by the Human mod (invent60's puppeteer AI). Default off - that mod calls LinkExplodes on every ordinary kill, not just real grenade/gib bursts.");
		CfgColorOverrideMode = ((BaseUnityPlugin)this).Config.Bind<string>("Blood", "Color Override Mode", "0", "Type 1 for Soft Override: replaces normal blood color, but sosigs with a color specifically set via NGA SosigIntegrityConfigs (e.g. zombies) keep their own color. Type 2 for Hard Override: replaces blood color for every sosig, no exceptions. Any other value = Unset: no override, vanilla per-sosig color behavior.");
		CfgSplatterEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Blood", "Splatter Enabled", true, "Projected blood splash dots on walls/floor/props from the bullet wound. The main splatter effect.");
		CfgSprayEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Blood", "Spray Enabled", true, "Blood particles that scatter outward from the wound in a wide cone/sphere, not just along the bullet path. Off by default - many players found this looked like an unintended splatter-sphere.");
		CfgVanillaStainEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Blood", "Vanilla Particle Staining Enabled", true, "Whether vanilla sosig bleed-out particles get intercepted and made to leave a stain when they land. When off, vanilla bleed particles behave as in unmodded H3VR (fall/bounce, no stain).");
		CfgDripStainsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Blood", "Blood Drip Stains Enabled", true, "Our own dripping-wound blood drops that fall from the wound over time and stain the floor.");
		BloodThermal.BindConfig(((BaseUnityPlugin)this).Config);
		BloodThermal.Init();
		SceneManager.sceneLoaded += delegate
		{
			BloodThermal.OnSceneChanged();
		};
		_decalTex = MakeSoftCircle(96);
		_hardCircleTex = MakeHardCircle(64);
		BloodThermal.RegisterHeatMask((Texture)(object)_decalTex, (Texture)(object)MakeHeatMask(_decalTex));
		BloodThermal.RegisterHeatMask((Texture)(object)_hardCircleTex, (Texture)(object)MakeHeatMask(_hardCircleTex));
		TryLoadFromBundle();
		Shader val = Shader.Find("Sprites/Default");
		if (val != null)
		{
			_dotBaseMat = new Material(val);
			_dotBaseMat.mainTexture = (Texture)(object)_decalTex;
		}
		_dotQuadMesh = new Mesh();
		_dotQuadMesh.vertices = (Vector3[])(object)new Vector3[4]
		{
			new Vector3(-0.5f, -0.5f, 0f),
			new Vector3(0.5f, -0.5f, 0f),
			new Vector3(0.5f, 0.5f, 0f),
			new Vector3(-0.5f, 0.5f, 0f)
		};
		_dotQuadMesh.uv = (Vector2[])(object)new Vector2[4]
		{
			new Vector2(0f, 0f),
			new Vector2(1f, 0f),
			new Vector2(1f, 1f),
			new Vector2(0f, 1f)
		};
		_dotQuadMesh.normals = (Vector3[])(object)new Vector3[4]
		{
			Vector3.forward,
			Vector3.forward,
			Vector3.forward,
			Vector3.forward
		};
		_dotQuadMesh.triangles = new int[6] { 0, 2, 3, 0, 1, 2 };
		_dotQuadMesh.RecalculateBounds();
		GameObject val2 = new GameObject("FlyingDotPS");
		Object.DontDestroyOnLoad((Object)val2);
		_flyingDotPS = val2.AddComponent<ParticleSystem>();
		MainModule main = _flyingDotPS.main;
		((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.5f);
		((MainModule)(ref main)).startSpeed = new MinMaxCurve(0f);
		((MainModule)(ref main)).startSize = new MinMaxCurve(0.02f);
		((MainModule)(ref main)).loop = false;
		((MainModule)(ref main)).playOnAwake = false;
		((MainModule)(ref main)).maxParticles = 8000;
		((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
		((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0f);
		EmissionModule emission = _flyingDotPS.emission;
		((EmissionModule)(ref emission)).enabled = false;
		((EmissionModule)(ref emission)).rateOverTime = new MinMaxCurve(0f);
		((Component)_flyingDotPS).GetComponent<ParticleSystemRenderer>().renderMode = (ParticleSystemRenderMode)0;
		List<Texture2D> list = LoadAllPngs();
		if (list.Count > 0)
		{
			_firstBloodTex = list[0];
			BuildSampleDataFromAll(list);
			Log.LogInfo((object)("[BloodSystem] " + list.Count + " PNG(s) loaded. CDF points=" + ((_splatterUVs != null) ? _splatterUVs.Length.ToString() : "0")));
		}
		else
		{
			BuildFallbackGrid(200);
			Log.LogWarning((object)"[BloodSystem] No PNG found in plugin folder — using uniform fallback grid.");
		}
		_fogMat = BuildSprayMaterial();
		_pelletMat = BuildSprayMaterial();
		BloodThermal.MarkAlwaysHot(_fogMat);
		BloodThermal.MarkAlwaysHot(_pelletMat);
		if (_flyingDotPS != null && _pelletMat != null)
		{
			((Renderer)((Component)_flyingDotPS).GetComponent<ParticleSystemRenderer>()).material = _pelletMat;
		}
		BuildSprayPSes();
		Harmony val3 = new Harmony("h3vr.invent60.bloodsystem");
		val3.PatchAll(typeof(BloodSystemPatches));
		val3.PatchAll(typeof(ThermalArmHook));
		val3.PatchAll(typeof(BloodSystemPatches.WfxDecalMaterialGrab));
		val3.PatchAll(typeof(BloodSystemPatches.OnslaughtNaturalDeathPatch));
		Log.LogInfo((object)("[BloodSystem] 3.4.1 loaded. FieldsOK=" + BloodSystemPatches.Ok));
		if (Chainloader.PluginInfos.ContainsKey("Aiyke.code_mod"))
		{
			Log.LogInfo((object)"[BloodSystem] Aiyke code mod pack detected - overriding its MoveBullet penetration patches so this mod's own splatter detection works.");
			TryOverrideAiykePenetration();
		}
	}

	private void Update()
	{
		BloodThermal.Tick();
	}

	private static void TryOverrideAiykePenetration()
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Expected O, but got Unknown
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(BallisticProjectile), "MoveBullet", new Type[1] { typeof(float) }, (Type[])null);
			if ((object)methodInfo == null)
			{
				return;
			}
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo == null || patchInfo.Prefixes == null)
			{
				return;
			}
			Harmony val = new Harmony("h3vr.invent60.bloodsystem");
			int num = 0;
			foreach (Patch prefix in patchInfo.Prefixes)
			{
				if ((object)prefix.PatchMethod != null && (object)prefix.PatchMethod.DeclaringType != null && prefix.PatchMethod.DeclaringType.FullName == "plugin.code_mod")
				{
					val.Unpatch((MethodBase)methodInfo, prefix.PatchMethod);
					num++;
				}
			}
			Log.LogInfo((object)("[BloodSystem] Aiyke Compat Override: removed " + num + " Aiyke prefix patch(es) from BallisticProjectile.MoveBullet."));
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("[BloodSystem] TryOverrideAiykePenetration: " + ex.Message));
		}
	}

	internal static Material GetDripMat(Color col)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		return GetDripMat(col, BloodThermal.CurrentCohort(BloodThermal.Classes - 1));
	}

	internal static Material GetDripMat(Color col, int cohortId)
	{
		//IL_0002: 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_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Expected O, but got Unknown
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		MatKey key = new MatKey(col, cohortId);
		if (_dripMatCache.TryGetValue(key, out var value) && value != null)
		{
			return value;
		}
		Material bloodMat = GetBloodMat(col, cohortId);
		if (bloodMat == null)
		{
			if (_pelletMat == null)
			{
				return null;
			}
			value = new Material(_pelletMat);
			value.color = col;
		}
		else
		{
			value = new Material(bloodMat);
		}
		if (_hardCircleTex != null)
		{
			value.mainTexture = (Texture)(object)_hardCircleTex;
		}
		else if (_decalTex != null)
		{
			value.mainTexture = (Texture)(object)_decalTex;
		}
		value.SetOverrideTag("RenderType", "Transparent");
		_dripMatCache[key] = value;
		BloodThermal.RegisterMaterial(value, key, drip: true);
		return value;
	}

	internal static List<GameObject> StartShotGroup()
	{
		int num = _nextShotId++;
		List<GameObject> list = new List<GameObject>();
		_shotGroups[num] = list;
		_shotQueue.Enqueue(num);
		EvictOldShots();
		return list;
	}

	private static void EvictOldShots()
	{
		while (_shotQueue.Count > CfgMaxShots.Value)
		{
			int key = _shotQueue.Dequeue();
			if (!_shotGroups.TryGetValue(key, out var value))
			{
				continue;
			}
			foreach (GameObject item in value)
			{
				if (item != null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
			_shotGroups.Remove(key);
		}
	}

	internal static void TrackGO(GameObject go, List<GameObject> shotList)
	{
		if (shotList != null)
		{
			shotList.Add(go);
			return;
		}
		_dripQueue.Enqueue(go);
		while (_dripQueue.Count > CfgMaxDrips.Value)
		{
			GameObject val = _dripQueue.Dequeue();
			if (val != null)
			{
				Object.Destroy((Object)(object)val);
			}
		}
	}

	private static List<Texture2D> LoadAllPngs()
	{
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Expected O, but got Unknown
		List<Texture2D> list = new List<Texture2D>();
		try
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			List<string> list2 = new List<string>(Directory.GetFiles(directoryName, "*.png"));
			list2.AddRange(Directory.GetFiles(directoryName, "*.jpg"));
			list2.AddRange(Directory.GetFiles(directoryName, "*.jpeg"));
			foreach (string item in list2)
			{
				string text = Path.GetFileNameWithoutExtension(item).ToLower();
				if (text == "icon")
				{
					continue;
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (val.LoadImage(File.ReadAllBytes(item)))
				{
					((Texture)val).filterMode = (FilterMode)2;
					if (text.Contains("normal") || text.Contains("norm"))
					{
						_normalMapTex = val;
						Log.LogInfo((object)("[BloodSystem] NormalMap=" + Path.GetFileName(item)));
					}
					else if (text.Contains("noise"))
					{
						_noiseMapTex = NormalizeLumTex(val);
						Log.LogInfo((object)("[BloodSystem] NoiseTex=" + Path.GetFileName(item)));
					}
					else
					{
						list.Add(NormalizeLumTex(val, keepAlpha: true));
					}
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("[BloodSystem] LoadAllPngs: " + ex.Message));
		}
		return list;
	}

	private static Texture2D NormalizeLumTex(Texture2D src, bool keepAlpha = false)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		Color[] pixels = src.GetPixels();
		float num = float.MaxValue;
		float num2 = float.MinValue;
		Color[] array = pixels;
		foreach (Color val in array)
		{
			if (!keepAlpha || !(val.a < 0.02f))
			{
				float num3 = val.r * 0.299f + val.g * 0.587f + val.b * 0.114f;
				if (num3 < num)
				{
					num = num3;
				}
				if (num3 > num2)
				{
					num2 = num3;
				}
			}
		}
		float num4 = num2 - num;
		Texture2D val2 = new Texture2D(((Texture)src).width, ((Texture)src).height, (TextureFormat)4, false);
		bool flag = num4 < 0.001f;
		for (int j = 0; j < pixels.Length; j++)
		{
			float num5 = ((!flag) ? ((pixels[j].r * 0.299f + pixels[j].g * 0.587f + pixels[j].b * 0.114f - num) / num4) : 1f);
			pixels[j] = new Color(num5, num5, num5, keepAlpha ? pixels[j].a : 1f);
		}
		val2.SetPixels(pixels);
		val2.Apply();
		((Texture)val2).filterMode = (FilterMode)2;
		return val2;
	}

	private static float LookupNoiseBright(Vector2 uv)
	{
		//IL_000d: 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_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)
		if (_noiseMapTex == null)
		{
			return 1f;
		}
		float num = uv.x * 0.5f + 0.5f;
		float num2 = uv.y * 0.5f + 0.5f;
		int num3 = Mathf.Clamp(Mathf.RoundToInt(num * (float)(((Texture)_noiseMapTex).width - 1)), 0, ((Texture)_noiseMapTex).width - 1);
		int num4 = Mathf.Clamp(Mathf.RoundToInt(num2 * (float)(((Texture)_noiseMapTex).height - 1)), 0, ((Texture)_noiseMapTex).height - 1);
		Color pixel = _noiseMapTex.GetPixel(num3, num4);
		float grayscale = ((Color)(ref pixel)).grayscale;
		return Mathf.Lerp(0.3f, 1f, grayscale);
	}

	private static Vector3 LookupNormal(Vector2 uv)
	{
		//IL_001c: 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_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: 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_00bf: 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_00db: 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_0016: Unknown result type (might be due to invalid IL or missing references)
		if (_normalMapTex == null)
		{
			return new Vector3(0f, 0f, 1f);
		}
		float num = uv.x * 0.5f + 0.5f;
		float num2 = uv.y * 0.5f + 0.5f;
		int num3 = Mathf.Clamp(Mathf.RoundToInt(num * (float)(((Texture)_normalMapTex).width - 1)), 0, ((Texture)_normalMapTex).width - 1);
		int num4 = Mathf.Clamp(Mathf.RoundToInt(num2 * (float)(((Texture)_normalMapTex).height - 1)), 0, ((Texture)_normalMapTex).height - 1);
		Color pixel = _normalMapTex.GetPixel(num3, num4);
		Vector3 val = new Vector3(pixel.r * 2f - 1f, pixel.g * 2f - 1f, Mathf.Abs(pixel.b * 2f - 1f));
		return ((Vector3)(ref val)).normalized;
	}

	private static Texture2D MakeHeatMask(Texture2D src)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		//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)
		if (src == null)
		{
			return null;
		}
		int width = ((Texture)src).width;
		int height = ((Texture)src).height;
		Texture2D val = new Texture2D(width, height, (TextureFormat)4, false);
		Color[] pixels = src.GetPixels();
		Color[] array = (Color[])(object)new Color[pixels.Length];
		for (int i = 0; i < pixels.Length; i++)
		{
			float a = pixels[i].a;
			array[i] = new Color(a, a, a, 1f);
		}
		val.SetPixels(array);
		val.Apply();
		return val;
	}

	private static Texture2D MakeSoftCircle(int size)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		//IL_007d: 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)
		Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
		float num = (float)(size - 1) * 0.5f;
		Color[] array = (Color[])(object)new Color[size * size];
		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 = num2 * num2 + num3 * num3;
				float num5 = ((num4 > 1f) ? 0f : Mathf.Clamp01(Mathf.Exp((0f - num4) * 15f)));
				array[i * size + j] = new Color(1f, 1f, 1f, num5);
			}
		}
		val.SetPixels(array);
		val.Apply();
		return val;
	}

	private static Texture2D MakeHardCircle(int size)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
		float num = (float)(size - 1) * 0.5f;
		Color[] array = (Color[])(object)new Color[size * size];
		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.Clamp01((num4 - 0.6f) / 0.4f);
				float num6 = ((num4 > 1f) ? 0f : (1f - num5 * num5 * (3f - 2f * num5)));
				array[i * size + j] = new Color(1f, 1f, 1f, num6);
			}
		}
		val.SetPixels(array);
		val.Apply();
		return val;
	}

	private static Texture2D MakeHemisphereNormalMap(int size)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		//IL_0075: 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)
		//IL_006e: 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_0083: 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_00a9: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
		float num = (float)(size - 1) * 0.5f;
		Color[] array = (Color[])(object)new Color[size * size];
		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 = num2 * num2 + num3 * num3;
				Vector3 val3;
				if (!(num4 > 1f))
				{
					Vector3 val2 = new Vector3(num2, num3, Mathf.Sqrt(1f - num4));
					val3 = ((Vector3)(ref val2)).normalized;
				}
				else
				{
					val3 = Vector3.forward;
				}
				Vector3 val4 = val3;
				array[i * size + j] = new Color(val4.x * 0.5f + 0.5f, val4.y * 0.5f + 0.5f, val4.z * 0.5f + 0.5f, 1f);
			}
		}
		val.SetPixels(array);
		val.Apply();
		return val;
	}

	private static Texture2D GetColoredTex(Color col)
	{
		//IL_0005: 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_0021: Expected O, but got Unknown
		//IL_00d3: 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_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		if (_coloredTexCache.TryGetValue(col, out var value) && value != null)
		{
			return value;
		}
		int num = 96;
		value = new Texture2D(num, num, (TextureFormat)4, false);
		float num2 = (float)(num - 1) * 0.5f;
		Color[] array = (Color[])(object)new Color[num * num];
		for (int i = 0; i < num; i++)
		{
			for (int j = 0; j < num; j++)
			{
				float num3 = ((float)j - num2) / num2;
				float num4 = ((float)i - num2) / num2;
				float num5 = num3 * num3 + num4 * num4;
				float num6 = ((num5 > 1f) ? 0f : Mathf.Clamp01(Mathf.Exp((0f - num5) * 8f)));
				array[i * num + j] = new Color(col.r, col.g, col.b, num6);
			}
		}
		value.SetPixels(array);
		value.Apply();
		((Texture)value).filterMode = (FilterMode)2;
		_coloredTexCache[col] = value;
		return value;
	}

	private static void BuildSampleDataFromAll(List<Texture2D> textures)
	{
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: 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_00ef: 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_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
		List<Vector2> list = new List<Vector2>();
		List<float> list2 = new List<float>();
		List<float> list3 = new List<float>();
		List<Vector3> list4 = new List<Vector3>();
		List<float> list5 = new List<float>();
		List<float> list6 = new List<float>();
		float num = 0f;
		foreach (Texture2D texture in textures)
		{
			int width = ((Texture)texture).width;
			int height = ((Texture)texture).height;
			Color[] pixels = texture.GetPixels();
			float num2 = (float)width / (float)height;
			float[] array = BuildDensityMap(pixels, width, height);
			List<Vector2> list7 = new List<Vector2>(width * height / 4);
			List<float> list8 = new List<float>(width * height / 4);
			List<float> list9 = new List<float>(width * height / 4);
			List<float> list10 = new List<float>(width * height / 4);
			float num3 = 0f;
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					Color val = pixels[i * width + j];
					float num4 = val.r * 0.299f + val.g * 0.587f + val.b * 0.114f;
					float a = val.a;
					if (!(a < 0.02f))
					{
						float num5;
						float num6;
						if (num2 >= 1f)
						{
							num5 = (float)j / (float)(width - 1) * 2f - 1f;
							num6 = ((float)i / (float)(height - 1) * 2f - 1f) / num2;
						}
						else
						{
							num5 = ((float)j / (float)(width - 1) * 2f - 1f) * num2;
							num6 = (float)i / (float)(height - 1) * 2f - 1f;
						}
						list7.Add(new Vector2(num5, num6));
						list8.Add(1f - num4);
						list9.Add(a);
						list10.Add(array[i * width + j]);
						num3 += a;
					}
				}
			}
			if (!(num3 < 0.001f) && list7.Count != 0)
			{
				LogDensityStats(((Object)texture).name, list10);
				float[] array2 = list10.ToArray();
				Array.Sort(array2);
				float num7 = array2[Mathf.Clamp((int)((float)array2.Length * 0.02f), 0, array2.Length - 1)];
				float num8 = array2[Mathf.Clamp((int)((float)array2.Length * 0.98f), 0, array2.Length - 1)] - num7;
				for (int k = 0; k < list10.Count; k++)
				{
					list10[k] = ((num8 > 1E-05f) ? Mathf.Clamp01((list10[k] - num7) / num8) : 0f);
				}
				float num9 = 1f / num3;
				for (int l = 0; l < list7.Count; l++)
				{
					num += list9[l] * num9;
					list.Add(list7[l]);
					list2.Add(list8[l]);
					list3.Add(LookupNoiseBright(list7[l]));
					list4.Add(LookupNormal(list7[l]));
					list6.Add(list10[l]);
					list5.Add(num);
				}
			}
		}
		_splatterUVs = list.ToArray();
		_splatterDarks = list2.ToArray();
		_splatterBrights = list3.ToArray();
		_splatterNormals = list4.ToArray();
		_cumWeights = list5.ToArray();
		_splatterClasses = BuildCurveClasses(list6);
		LogClassDistribution(list6);
	}

	private static void LogDensityStats(string name, List<float> dens)
	{
		try
		{
			if (dens.Count != 0)
			{
				float[] array = dens.ToArray();
				Array.Sort(array);
				int num = array.Length;
				Log.LogInfo((object)("[BloodSystem] Density '" + name + "' n=" + num + " min=" + array[0].ToString("F3") + " p05=" + array[num * 5 / 100].ToString("F3") + " p25=" + array[num * 25 / 100].ToString("F3") + " p50=" + array[num / 2].ToString("F3") + " p75=" + array[num * 75 / 100].ToString("F3") + " p95=" + array[num * 95 / 100].ToString("F3") + " max=" + array[num - 1].ToString("F3")));
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("[BloodSystem] LogDensityStats: " + ex.Message));
		}
	}

	private static void LogClassDistribution(List<float> densities)
	{
		try
		{
			int classes = BloodThermal.Classes;
			if (_splatterClasses == null || _splatterClasses.Length == 0)
			{
				return;
			}
			int[] array = new int[classes];
			double[] array2 = new double[classes];
			double[] array3 = new double[classes];
			for (int i = 0; i < _splatterClasses.Length; i++)
			{
				int num = _splatterClasses[i];
				if (num >= classes)
				{
					num = classes - 1;
				}
				array[num]++;
				array2[num] += ((Vector2)(ref _splatterUVs[i])).magnitude;
				array3[num] += densities[i];
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("[BloodSystem] Density classes (0=densest, cools slowest):");
			for (int j = 0; j < classes; j++)
			{
				stringBuilder.Append("\n  class ").Append(j).Append(": ")
					.Append(array[j])
					.Append(" samples (")
					.Append((100f * (float)array[j] / (float)_splatterClasses.Length).ToString("F1"))
					.Append("%)");
				if (array[j] > 0)
				{
					stringBuilder.Append("  meanDensity=").Append((array3[j] / (double)array[j]).ToString("F3")).Append("  meanRadius=")
						.Append((array2[j] / (double)array[j]).ToString("F3"));
				}
			}
			stringBuilder.Append("\n  meanRadius should RISE with class index if the packed middle is class 0.");
			Log.LogInfo((object)stringBuilder.ToString());
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("[BloodSystem] LogClassDistribution: " + ex.Message));
		}
	}

	private static int AnimStepsForDistance(float dist)
	{
		if (dist <= 3f)
		{
			return 1;
		}
		if (dist <= 10f)
		{
			return Mathf.RoundToInt(Mathf.Lerp(1f, 2f, (dist - 3f) / 7f));
		}
		if (dist <= 40f)
		{
			return Mathf.RoundToInt(Mathf.Lerp(2f, 5f, (dist - 10f) / 30f));
		}
		return 5;
	}

	private static float[] BoxBlur(float[] src, int w, int h, int r)
	{
		float[] array = new float[w * h];
		for (int i = 0; i < h; i++)
		{
			int num = i * w;
			float num2 = 0f;
			int num3 = 0;
			int num4 = Mathf.Min(w - 1, r);
			for (int j = 0; j <= num4; j++)
			{
				num2 += src[num + j];
				num3++;
			}
			for (int k = 0; k < w; k++)
			{
				array[num + k] = num2 / (float)num3;
				int num5 = k + r + 1;
				int num6 = k - r;
				if (num5 < w)
				{
					num2 += src[num + num5];
					num3++;
				}
				if (num6 >= 0)
				{
					num2 -= src[num + num6];
					num3--;
				}
			}
		}
		float[] array2 = new float[w * h];
		for (int l = 0; l < w; l++)
		{
			float num7 = 0f;
			int num8 = 0;
			int num9 = Mathf.Min(h - 1, r);
			for (int m = 0; m <= num9; m++)
			{
				num7 += array[m * w + l];
				num8++;
			}
			for (int n = 0; n < h; n++)
			{
				array2[n * w + l] = num7 / (float)num8;
				int num10 = n + r + 1;
				int num11 = n - r;
				if (num10 < h)
				{
					num7 += array[num10 * w + l];
					num8++;
				}
				if (num11 >= 0)
				{
					num7 -= array[num11 * w + l];
					num8--;
				}
			}
		}
		return array2;
	}

	private static float[] BuildDensityMap(Color[] pixels, int w, int h)
	{
		int r = Mathf.Max(4, Mathf.RoundToInt((float)Mathf.Min(w, h) * 0.03f));
		float num = Mathf.Clamp01(1f);
		float[] array = new float[w * h];
		float[] array2 = new float[w * h];
		for (int i = 0; i < array.Length; i++)
		{
			float num2 = (array[i] = pixels[i].a);
			array2[i] = num2 * num2;
		}
		float[] array3 = BoxBlur(array, w, h, r);
		float[] array4 = BoxBlur(array2, w, h, r);
		float[] array5 = new float[w * h];
		for (int j = 0; j < array5.Length; j++)
		{
			float num3 = array3[j];
			float num4 = Mathf.Max(0f, array4[j] - num3 * num3);
			float num5 = num3 * (1f - num3);
			float num6 = ((num5 > 1E-05f) ? Mathf.Clamp01(num4 / num5) : 0f);
			array5[j] = num3 * (1f - num * num6 * (1f - num3));
		}
		return array5;
	}

	private static byte[] BuildCurveClasses(List<float> densities)
	{
		int count = densities.Count;
		byte[] array = new byte[count];
		int classes = BloodThermal.Classes;
		if (classes <= 1 || count == 0)
		{
			return array;
		}
		int[] array2 = new int[classes];
		for (int i = 0; i < count; i++)
		{
			float num = Mathf.Clamp01((densities[i] - 0f) / 1f);
			int num2 = Mathf.Clamp((int)((1f - num) * (float)classes * 0.9999f), 0, classes - 1);
			array[i] = (byte)num2;
			array2[num2]++;
		}
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("[BloodSystem] Class bands over normalized density:");
		for (int j = 0; j < classes; j++)
		{
			float num3 = 1f - 1f * (float)j / (float)classes;
			float num4 = 1f - 1f * (float)(j + 1) / (float)classes;
			stringBuilder.Append("\n  class ").Append(j).Append(" density ")
				.Append(num4.ToString("F2"))
				.Append("-")
				.Append(num3.ToString("F2"))
				.Append(" -> ")
				.Append(array2[j])
				.Append(" samples (")
				.Append((100f * (float)array2[j] / (float)count).ToString("F1"))
				.Append("%)");
		}
		Log.LogInfo((object)stringBuilder.ToString());
		return array;
	}

	private static void BuildFallbackGrid(int side)
	{
		//IL_005e: 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_007e: 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)
		List<Vector2> list = new List<Vector2>(side * side);
		List<float> list2 = new List<float>(side * side);
		List<float> list3 = new List<float>(side * side);
		List<Vector3> list4 = new List<Vector3>(side * side);
		Vector2 val = default(Vector2);
		for (int i = 0; i < side; i++)
		{
			for (int j = 0; j < side; j++)
			{
				((Vector2)(ref val))..ctor((float)j / (float)(side - 1) * 2f - 1f, (float)i / (float)(side - 1) * 2f - 1f);
				list.Add(val);
				list2.Add(0.8f);
				list3.Add(LookupNoiseBright(val));
				list4.Add(LookupNormal(val));
			}
		}
		_splatterUVs = list.ToArray();
		_splatterDarks = list2.ToArray();
		_splatterBrights = list3.ToArray();
		_splatterNormals = list4.ToArray();
		_cumWeights = new float[0];
		_splatterClasses = new byte[list.Count];
	}

	private static void SampleSplatter(out Vector2 uv, out float dark, out float bright, out Vector3 tanNorm, out byte curveClass)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: 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_00c6: 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_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: 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)
		if (_splatterUVs == null || _splatterUVs.Length == 0)
		{
			uv = new Vector2(Random.Range(-1f, 1f), Random.Range(-1f, 1f));
			dark = 0.8f;
			bright = 1f;
			tanNorm = Vector3.forward;
			curveClass = 0;
			return;
		}
		int num;
		if (_cumWeights == null || _cumWeights.Length == 0)
		{
			num = Random.Range(0, _splatterUVs.Length);
		}
		else
		{
			float num2 = Random.Range(0f, _cumWeights[_cumWeights.Length - 1]);
			int num3 = 0;
			int num4 = _cumWeights.Length - 1;
			while (num3 < num4)
			{
				int num5 = num3 + num4 >> 1;
				if (_cumWeights[num5] < num2)
				{
					num3 = num5 + 1;
				}
				else
				{
					num4 = num5;
				}
			}
			num = num3;
		}
		uv = _splatterUVs[num];
		dark = ((_splatterDarks != null && num < _splatterDarks.Length) ? _splatterDarks[num] : 0.8f);
		bright = ((_splatterBrights != null && num < _splatterBrights.Length) ? _splatterBrights[num] : 1f);
		tanNorm = ((_splatterNormals != null && num < _splatterNormals.Length) ? _splatterNormals[num] : Vector3.forward);
		curveClass = (byte)((_splatterClasses != null && num < _splatterClasses.Length) ? _splatterClasses[num] : 0);
	}

	private static void TryLoadFromBundle()
	{
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Expected O, but got Unknown
		try
		{
			string alloyMatCachePath = AlloyMatCachePath;
			if (!File.Exists(alloyMatCachePath))
			{
				return;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string[] array = File.ReadAllLines(alloyMatCachePath);
			foreach (string text in array)
			{
				int num = text.IndexOf('=');
				if (num >= 0)
				{
					dictionary[text.Substring(0, num).Trim()] = text.Substring(num + 1).Trim();
				}
			}
			if (!dictionary.TryGetValue("shaderName", out var value))
			{
				return;
			}
			Shader val = Shader.Find(value);
			if (val == null)
			{
				Log.LogWarning((object)("[BloodSystem] Cache shader not found: " + value));
				return;
			}
			Material val2 = new Material(val);
			if (dictionary.TryGetValue("renderQueue", out var value2))
			{
				val2.renderQueue = int.Parse(value2);
			}
			if (dictionary.TryGetValue("_SrcBlend", out value2) && val2.HasProperty("_SrcBlend"))
			{
				val2.SetInt("_SrcBlend", int.Parse(value2));
			}
			if (dictionary.TryGetValue("_DstBlend", out value2) && val2.HasProperty("_DstBlend"))
			{
				val2.SetInt("_DstBlend", int.Parse(value2));
			}
			if (dictionary.TryGetValue("_ZWrite", out value2) && val2.HasProperty("_ZWrite"))
			{
				val2.SetInt("_ZWrite", int.Parse(value2));
			}
			if (dictionary.TryGetValue("_Mode", out value2) && val2.HasProperty("_Mode"))
			{
				val2.SetFloat("_Mode", float.Parse(value2));
			}
			if (dictionary.TryGetValue("keywords", out value2) && !string.IsNullOrEmpty(value2))
			{
				array = value2.Split(new char[1] { ',' });
				foreach (string text2 in array)
				{
					if (!string.IsNullOrEmpty(text2.Trim()))
					{
						val2.EnableKeyword(text2.Trim());
					}
				}
			}
			val2.SetInt("_Cull", 0);
			_decalSourceMat = val2;
			_decalSourceSearched = true;
			Log.LogInfo((object)("[BloodSystem] Cache loaded: " + value + " rq=" + val2.renderQueue));
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("[BloodSystem] TryLoadFromCache: " + ex.Message));
		}
	}

	internal static void SaveAlloyCacheToFile(Material mat)
	{
		try
		{
			List<string> list = new List<string>
			{
				"shaderName=" + ((Object)mat.shader).name,
				"renderQueue=" + mat.renderQueue,
				"keywords=" + string.Join(",", mat.shaderKeywords)
			};
			string[] array = new string[3] { "_SrcBlend", "_DstBlend", "_ZWrite" };
			foreach (string text in array)
			{
				if (mat.HasProperty(text))
				{
					list.Add(text + "=" + mat.GetInt(text));
				}
			}
			array = new string[2] { "_Mode", "_Cutoff" };
			foreach (string text2 in array)
			{
				if (mat.HasProperty(text2))
				{
					list.Add(text2 + "=" + mat.GetFloat(text2).ToString("F3"));
				}
			}
			File.WriteAllLines(AlloyMatCachePath, list.ToArray());
			Log.LogInfo((object)("[BloodSystem] Cache saved: " + ((Object)mat.shader).name + " kws=" + string.Join(",", mat.shaderKeywords)));
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("[BloodSystem] SaveAlloyCache: " + ex.Message));
		}
	}

	internal static IEnumerator TryGrabAlloyFromScene()
	{
		_alloyGrabPending = true;
		yield return null;
		if (_decalSourceMat != null)
		{
			_alloyGrabPending = false;
			yield break;
		}
		Renderer val = null;
		int num = -1;
		int num2 = 0;
		try
		{
			Renderer[] array = Object.FindObjectsOfType<Renderer>();
			foreach (Renderer val2 in array)
			{
				if (val2 == null)
				{
					continue;
				}
				Material sharedMaterial = val2.sharedMaterial;
				if (sharedMaterial == null || sharedMaterial.shader == null)
				{
					continue;
				}
				string name = ((Object)sharedMaterial.shader).name;
				if (name.IndexOf("Alloy", StringComparison.OrdinalIgnoreCase) >= 0 && name.IndexOf("Additive", StringComparison.OrdinalIgnoreCase) < 0)
				{
					num2++;
					int num3 = 0;
					if (name == "Alloy/Core")
					{
						num3 += 100;
					}
					if (sharedMaterial.renderQueue > 2000)
					{
						num3 += 50;
					}
					Log.LogInfo((object)("[BloodSystem] Alloy candidate: shader=" + name + " rq=" + sharedMaterial.renderQueue + " score=" + num3 + " obj=" + ((Object)((Component)val2).gameObject).name));
					if (num3 > num)
					{
						num = num3;
						val = val2;
					}
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("[BloodSystem] TryGrabAlloyFromScene: " + ex.Message));
		}
		Log.LogInfo((object)("[BloodSystem] AlloyGrab: candidates=" + num2 + " bestScore=" + num));
		if (val != null)
		{
			_decalSourceMat = new Material(val.sharedMaterial);
			_decalSourceMat.SetInt("_Cull", 0);
			_decalSourceSearched = true;
			_matCache.Clear();
			_dripMatCache.Clear();
			Log.LogInfo((object)("[BloodSystem] Alloy mat GRABBED: " + ((Object)_decalSourceMat.shader).name + " rq=" + _decalSourceMat.renderQueue));
			SaveAlloyCacheToFile(_decalSourceMat);
		}
		else
		{
			Log.LogWarning((object)"[BloodSystem] No Alloy renderer found — shoot a wall, then a sosig.");
		}
		_alloyGrabPending = false;
	}

	internal static Material GetBloodMat(Color col)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		return GetBloodMat(col, BloodThermal.CurrentCohort(BloodThermal.Classes - 1));
	}

	internal static Material GetBloodMat(Color col, int cohortId)
	{
		//IL_0002: 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_009c: Expected O, but got Unknown
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Expected O, but got Unknown
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		MatKey key = new MatKey(col, cohortId);
		if (_matCache.TryGetValue(key, out var value) && value != null)
		{
			return value;
		}
		Material decalSourceMat = _decalSourceMat;
		if (decalSourceMat == null)
		{
			if (!_fallbackDecalShaderSearched)
			{
				_fallbackDecalShaderSearched = true;
				_fallbackDecalShader = Shader.Find("Legacy Shaders/Transparent/Diffuse");
			}
			if (_fallbackDecalShader == null)
			{
				return null;
			}
			value = new Material(_fallbackDecalShader);
			if (_decalTex != null)
			{
				value.mainTexture = (Texture)(object)_decalTex;
			}
			value.color = col;
			value.SetOverrideTag("RenderType", "Transparent");
			_matCache[key] = value;
			BloodThermal.RegisterMaterial(value, key, drip: false);
			return value;
		}
		value = new Material(decalSourceMat);
		if (_decalTex != null)
		{
			value.mainTexture = (Texture)(object)_decalTex;
		}
		ApplyBloodProps(value, col);
		_matCache[key] = value;
		BloodThermal.RegisterMaterial(value, key, drip: false);
		return value;
	}

	private static void ApplyBloodProps(Material m, Color col)
	{
		//IL_0013: 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_0150: Unknown result type (might be due to invalid IL or missing references)
		if (m.HasProperty("_Color"))
		{
			m.SetColor("_Color", col);
		}
		if (m.HasProperty("_Metal"))
		{
			m.SetFloat("_Metal", 0f);
		}
		if (m.HasProperty("_Specularity"))
		{
			m.SetFloat("_Specularity", 0f);
		}
		if (m.HasProperty("_Roughness"))
		{
			m.SetFloat("_Roughness", 0.8f);
		}
		m.DisableKeyword("_RIM_ON");
		if (m.HasProperty("_EmissionColor"))
		{
			m.SetColor("_EmissionColor", Color.black);
		}
		m.DisableKeyword("_EMISSION");
		m.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)4;
		if (m.HasProperty("_SrcBlend"))
		{
			m.SetInt("_SrcBlend", 5);
		}
		if (m.HasProperty("_DstBlend"))
		{
			m.SetInt("_DstBlend", 10);
		}
		m.DisableKeyword("_ALPHAPREMULTIPLY_ON");
		m.EnableKeyword("_ALPHABLEND_ON");
		m.SetOverrideTag("RenderType", "Transparent");
		if (m.HasProperty("_Metallic"))
		{
			m.SetFloat("_Metallic", 0f);
		}
		if (m.HasProperty("_Smoothness"))
		{
			m.SetFloat("_Smoothness", 0.1f);
		}
		if (m.HasProperty("_SpecColor"))
		{
			m.SetColor("_SpecColor", Color.black);
		}
		if (m.HasProperty("_Shininess"))
		{
			m.SetFloat("_Shininess", 0.05f);
		}
	}

	private static Material BuildSprayMaterial()
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		Shader val = Shader.Find("Sprites/Default");
		if (val == null)
		{
			val = Shader.Find("Particles/Additive");
		}
		if (val == null)
		{
			return null;
		}
		Material val2 = new Material(val);
		if (_firstBloodTex != null)
		{
			val2.mainTexture = (Texture)(object)_firstBloodTex;
		}
		return val2;
	}

	private static void SetParticleFadeMode(Material mat)
	{
		mat.SetFloat("_Mode", 2f);
		mat.EnableKeyword("_ALPHABLEND_ON");
		mat.DisableKeyword("_ALPHATEST_ON");
		mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
		mat.SetInt("_SrcBlend", 5);
		mat.SetInt("_DstBlend", 10);
		mat.SetInt("_ZWrite", 0);
		mat.renderQueue = 3000;
	}

	private void BuildSprayPSes()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		//IL_000f: 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_0025: Unknown result type (might be due to invalid IL or missing references)
		//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_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: 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_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		//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_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: 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_00ec: 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_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Expected O, but got Unknown
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Expected O, but got Unknown
		//IL_0279: Unknown result type (might be due to invalid IL or missing references)
		//IL_027e: Unknown result type (might be due to invalid IL or missing references)
		//IL_028c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0320: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0334: Unknown result type (might be due to invalid IL or missing references)
		//IL_0345: Unknown result type (might be due to invalid IL or missing references)
		//IL_0354: Unknown result type (might be due to invalid IL or missing references)
		//IL_0359: Unknown result type (might be due to invalid IL or missing references)
		//IL_0388: Unknown result type (might be due to invalid IL or missing references)
		//IL_038d: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03da: Expected O, but got Unknown
		//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0436: Unknown result type (might be due to invalid IL or missing references)
		//IL_043b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0441: Expected O, but got Unknown
		//IL_0441: Unknown result type (might be due to invalid IL or missing references)
		//IL_0448: Unknown result type (might be due to invalid IL or missing references)
		//IL_0458: Unknown result type (might be due to invalid IL or missing references)
		//IL_045d: Unknown result type (might be due to invalid IL or missing references)
		//IL_046b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0481: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_04fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_050e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0513: Unknown result type (might be due to invalid IL or missing references)
		//IL_0524: Unknown result type (might be due to invalid IL or missing references)
		//IL_0533: Unknown result type (might be due to invalid IL or missing references)
		//IL_0538: Unknown result type (might be due to invalid IL or missing references)
		//IL_0567: Unknown result type (might be due to invalid IL or missing references)
		//IL_056c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0579: Unknown result type (might be due to invalid IL or missing references)
		Gradient val = new Gradient();
		val.SetKeys((GradientColorKey[])(object)new GradientColorKey[2]
		{
			new GradientColorKey(Color.white, 0f),
			new GradientColorKey(Color.white, 1f)
		}, (GradientAlphaKey[])(object)new GradientAlphaKey[2]
		{
			new GradientAlphaKey(1f, 0f),
			new GradientAlphaKey(0f, 1f)
		});
		GameObject val2 = new GameObject("BSFog");
		Object.DontDestroyOnLoad((Object)(object)val2);
		val2.SetActive(false);
		_fogPS = val2.AddComponent<ParticleSystem>();
		MainModule main = _fogPS.main;
		((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.25f, 0.4f);
		((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.3f, 1.2f);
		((MainModule)(ref main)).startSize = new MinMaxCurve(0.01f, 0.03f);
		((MainModule)(ref main)).startRotation = new MinMaxCurve(0f, (float)Math.PI * 2f);
		((MainModule)(ref main)).maxParticles = 2000;
		((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0.05f);
		((MainModule)(ref main)).loop = false;
		((MainModule)(ref main)).playOnAwake = false;
		((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
		((MainModule)(ref main)).duration = 0.5f;
		((MainModule)(ref main)).startColor = new MinMaxGradient(_mustardFallback);
		EmissionModule emission = _fogPS.emission;
		((EmissionModule)(ref emission)).enabled = true;
		((EmissionModule)(ref emission)).rateOverTime = new MinMaxCurve(0f);
		ShapeModule shape = _fogPS.shape;
		((ShapeModule)(ref shape)).enabled = true;
		((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)7;
		((ShapeModule)(ref shape)).angle = 85f;
		((ShapeModule)(ref shape)).radius = 0.02f;
		SizeOverLifetimeModule sizeOverLifetime = _fogPS.sizeOverLifetime;
		((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true;
		((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, new AnimationCurve((Keyframe[])(object)new Keyframe[2]
		{
			new Keyframe(0f, 0.5f),
			new Keyframe(1f, 2.5f)
		}));
		ColorOverLifetimeModule colorOverLifetime = _fogPS.colorOverLifetime;
		((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true;
		((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val);
		ParticleSystemRenderer component = ((Component)_fogPS).GetComponent<ParticleSystemRenderer>();
		if ((Object)(object)component != (Object)null && _fogMat != null)
		{
			((Renderer)component).material = _fogMat;
		}
		val2.SetActive(true);
		GameObject val3 = new GameObject("BSPellet");
		Object.DontDestroyOnLoad((Object)(object)val3);
		val3.SetActive(false);
		_pelletPS = val3.AddComponent<ParticleSystem>();
		MainModule main2 = _pelletPS.main;
		((MainModule)(ref main2)).startLifetime = new MinMaxCurve(0.3f, 0.5f);
		((MainModule)(ref main2)).startSpeed = new MinMaxCurve(1.5f, 4f);
		((MainModule)(ref main2)).startSize = new MinMaxCurve(0.04f, 0.12f);
		((MainModule)(ref main2)).startRotation = new MinMaxCurve(0f, (float)Math.PI * 2f);
		((MainModule)(ref main2)).maxParticles = 2000;
		((MainModule)(ref main2)).gravityModifier = MinMaxCurve.op_Implicit(0.35f);
		((MainModule)(ref main2)).loop = false;
		((MainModule)(ref main2)).playOnAwake = false;
		((MainModule)(ref main2)).simulationSpace = (ParticleSystemSimulationSpace)1;
		((MainModule)(ref main2)).duration = 0.5f;
		((MainModule)(ref main2)).startColor = new MinMaxGradient(_mustardFallback);
		EmissionModule emission2 = _pelletPS.emission;
		((EmissionModule)(ref emission2)).enabled = true;
		((EmissionModule)(ref emission2)).rateOverTime = new MinMaxCurve(0f);
		ShapeModule shape2 = _pelletPS.shape;
		((ShapeModule)(ref shape2)).enabled = true;
		((ShapeModule)(ref shape2)).shapeType = (ParticleSystemShapeType)4;
		((ShapeModule)(ref shape2)).angle = 20f;
		((ShapeModule)(ref shape2)).radius = 0.02f;
		SizeOverLifetimeModule sizeOverLifetime2 = _pelletPS.sizeOverLifetime;
		((SizeOverLifetimeModule)(ref sizeOverLifetime2)).enabled = true;
		((SizeOverLifetimeModule)(ref sizeOverLifetime2)).size = new MinMaxCurve(1f, new AnimationCurve((Keyframe[])(object)new Keyframe[2]
		{
			new Keyframe(0f, 0.4f),
			new Keyframe(1f, 1.6f)
		}));
		ColorOverLifetimeModule colorOverLifetime2 = _pelletPS.colorOverLifetime;
		((ColorOverLifetimeModule)(ref colorOverLifetime2)).enabled = true;
		((ColorOverLifetimeModule)(ref colorOverLifetime2)).color = new MinMaxGradient(val);
		ParticleSystemRenderer component2 = ((Component)_pelletPS).GetComponent<ParticleSystemRenderer>();
		if ((Object)(object)component2 != (Object)null && _pelletMat != null)
		{
			((Renderer)component2).material = _pelletMat;
		}
		val3.SetActive(true);
		GameObject val4 = new GameObject("BSJet");
		Object.DontDestroyOnLoad((Object)val4);
		val4.SetActive(false);
		_jetPS = val4.AddComponent<ParticleSystem>();
		MainModule main3 = _jetPS.main;
		((MainModule)(ref main3)).startLifetime = new MinMaxCurve(0.3f, 0.5f);
		((MainModule)(ref main3)).startSpeed = new MinMaxCurve(8f, 18f);
		((MainModule)(ref main3)).startSize = new MinMaxCurve(0.012f, 0.03f);
		((MainModule)(ref main3)).startRotation = new MinMaxCurve(0f, (float)Math.PI * 2f);
		((MainModule)(ref main3)).maxParticles = 1000;
		((MainModule)(ref main3)).gravityModifier = MinMaxCurve.op_Implicit(1.2f);
		((MainModule)(ref main3)).loop = false;
		((MainModule)(ref main3)).playOnAwake = false;
		((MainModule)(ref main3)).simulationSpace = (ParticleSystemSimulationSpace)1;
		((MainModule)(ref main3)).duration = 0.5f;
		((MainModule)(ref main3)).startColor = new MinMaxGradient(_mustardFallback);
		EmissionModule emission3 = _jetPS.emission;
		((EmissionModule)(ref emission3)).enabled = true;
		((EmissionModule)(ref emission3)).rateOverTime = new MinMaxCurve(0f);
		ShapeModule shape3 = _jetPS.shape;
		((ShapeModule)(ref shape3)).enabled = true;
		((ShapeModule)(ref shape3)).shapeType = (ParticleSystemShapeType)4;
		((ShapeModule)(ref shape3)).angle = 5f;
		((ShapeModule)(ref shape3)).radius = 0.005f;
		ColorOverLifetimeModule colorOverLifetime3 = _jetPS.colorOverLifetime;
		((ColorOverLifetimeModule)(ref colorOverLifetime3)).enabled = true;
		((ColorOverLifetimeModule)(ref colorOverLifetime3)).color = new MinMaxGradient(val);
		ParticleSystemRenderer component3 = ((Component)_jetPS).GetComponent<ParticleSystemRenderer>();
		if ((Object)(object)component3 != (Object)null && _pelletMat != null)
		{
			((Renderer)component3).material = _pelletMat;
		}
		val4.SetActive(true);
	}

	internal static void SpawnProjection(Vector3 exitPt, Vector3 projDir, Sosig srcSosig, float bulletSpeed, bool gib = false, List<GameObject> shotList = null, float rayCountScale = 1f)
	{
		//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_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_0073: 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_0091: 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_0096: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00ec: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: 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_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0356: Unknown result type (might be due to invalid IL or missing references)
		//IL_0318: Unknown result type (might be due to invalid IL or missing references)
		//IL_0319: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0322: Unknown result type (might be due to invalid IL or missing references)
		//IL_0328: Unknown result type (might be due to invalid IL or missing references)
		//IL_032d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0332: Unknown result type (might be due to invalid IL or missing references)
		//IL_0334: Unknown result type (might be due to invalid IL or missing references)
		//IL_033b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0341: Unknown result type (might be due to invalid IL or missing references)
		//IL_0346: Unknown result type (might be due to invalid IL or missing references)
		//IL_034b: Unknown result type (might be due to invalid IL or missing references)
		//IL_034f: Unknown result type (might be due to invalid IL or missing references)
		//IL_035b: Unknown result type (might be due to invalid IL or missing references)
		//IL_035d: Unknown result type (might be due to invalid IL or missing references)
		//IL_035e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0364: Unknown result type (might be due to invalid IL or missing references)
		//IL_0369: Unknown result type (might be due to invalid IL or missing references)
		//IL_036e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0396: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_042e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0432: Unknown result type (might be due to invalid IL or missing references)
		//IL_0466: Unknown result type (might be due to invalid IL or missing references)
		//IL_0468: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0478: Unknown result type (might be due to invalid IL or missing references)
		//IL_047d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0482: Unknown result type (might be due to invalid IL or missing references)
		//IL_0487: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0931: Unknown result type (might be due to invalid IL or missing references)
		//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04de: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_053b: Unknown result type (might be due to invalid IL or missing references)
		//IL_054d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0551: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_081f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0907: Unknown result type (might be due to invalid IL or missing references)
		if (!CfgEnabled.Value || !CfgSplatterEnabled.Value)
		{
			return;
		}
		try
		{
			Color sosigBloodColor = GetSosigBloodColor(srcSosig);
			Vector3 normalized = ((Vector3)(ref projDir)).normalized;
			float num = Mathf.Tan(CfgConeAngle.Value * ((float)Math.PI / 180f)) * 0.8f;
			float value = CfgRange.Value;
			float num2 = Mathf.Max(1f, bulletSpeed * CfgSpeedRatio.Value) + CfgSpeedBias.Value;
			Vector3 val = Vector3.Cross((Mathf.Abs(Vector3.Dot(normalized, Vector3.up)) > 0.99f) ? Vector3.forward : Vector3.up, normalized);
			Vector3 normalized2 = ((Vector3)(ref val)).normalized;
			Vector3 val2 = Vector3.Cross(normalized, normalized2);
			float num3 = Random.Range(0f, (float)Math.PI * 2f);
			float num4 = Mathf.Cos(num3);
			float num5 = Mathf.Sin(num3);
			Vector3 val3 = normalized2 * num4 + val2 * num5;
			Vector3 val4 = val2 * num4 - normalized2 * num5;
			normalized2 = val3;
			val2 = val4;
			bool flag = string.Equals(CfgProjectionMode.Value, "Animated", StringComparison.OrdinalIgnoreCase);
			bool flag2 = string.Equals(CfgProjectionMode.Value, "Immediate", StringComparison.OrdinalIgnoreCase);
			float value2 = CfgDotScaleMax.Value;
			float num6 = (value2 - 1f) / Mathf.Max(0.1f, CfgDotScaleRange.Value);
			int num7 = ((_splatterUVs != null && _splatterUVs.Length != 0) ? _splatterUVs.Length : int.MaxValue);
			int num8 = (gib ? Mathf.Min(Mathf.Max(1, CfgGibRayCount.Value), num7) : Mathf.Min(Mathf.Max(1, CfgRayCount.Value), num7));
			if (rayCountScale < 0.999f)
			{
				num8 = Mathf.Max(1, Mathf.RoundToInt((float)num8 * rayCountScale));
			}
			if (gib)
			{
				((MonoBehaviour)_instance).StartCoroutine(SpawnGibGradual(exitPt, num8, value, value2, num6, sosigBloodColor, srcSosig, shotList));
				return;
			}
			int num9 = Physics.RaycastNonAlloc(exitPt + Vector3.up * 0.5f, Vector3.down, _rayBuf, 0.6f);
			Array.Sort(_rayBuf, 0, num9, _rhCompare);
			for (int i = 0; i < num9; i++)
			{
				RaycastHit val5 = _rayBuf[i];
				if (!((Object)(object)((RaycastHit)(ref val5)).collider.attachedRigidbody != (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val5)).collider).GetComponentInParent<SosigLink>() != (Object)null) && !(((RaycastHit)(ref val5)).normal.y < 0.5f))
				{
					exitPt = ((RaycastHit)(ref val5)).point + ((RaycastHit)(ref val5)).normal * 0.05f;
					break;
				}
			}
			Dictionary<int, List<DotData>> dictionary = new Dictionary<int, List<DotData>>();
			Dictionary<int, Dictionary<Transform, List<DotData>>> dictionary2 = new Dictionary<int, Dictionary<Transform, List<DotData>>>();
			List<DotData> list = new List<DotData>();
			List<Transform> list2 = new List<Transform>();
			float num10 = 0f;
			if (_flyBuf == null || _flyBuf.Length < num8)
			{
				_flyBuf = (Particle[])(object)new Particle[num8];
			}
			int num11 = 0;
			Color32 startColor = Color32.op_Implicit(sosigBloodColor);
			for (int j = 0; j < num8; j++)
			{
				SampleSplatter(out var uv, out var dark, out var bright, out var tanNorm, out var curveClass);
				Vector3 val6;
				if (!gib)
				{
					val = normalized + normalized2 * uv.x * num + val2 * uv.y * num;
					val6 = ((Vector3)(ref val)).normalized;
				}
				else
				{
					val6 = Random.onUnitSphere;
				}
				Vector3 val7 = val6;
				int num12 = Physics.RaycastNonAlloc(exitPt - normalized * 0.15f, val7, _rayBu