Decompiled source of LDBCustomBloodEffects v1.0.0

Mods/LDBCustomBloodEffects.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using BoneLib;
using BoneLib.BoneMenu;
using CustomBloodEffects;
using HarmonyLib;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(CustomBloodMod), "custombloodeffects", "1.0.0", "LDB", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonOptionalDependencies(new string[] { "LabFusion" })]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CustomBloodEffects")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CustomBloodEffects")]
[assembly: AssemblyTitle("CustomBloodEffects")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CustomBloodEffects
{
	public class CustomBloodMod : MelonMod
	{
		private static MelonPreferences_Category? _prefsCategory;

		private static MelonPreferences_Entry<bool>? _prefDamageEnabled;

		private static MelonPreferences_Entry<string>? _prefDamageBarcode;

		private static MelonPreferences_Entry<float>? _prefDamageMultiplier;

		private static MelonPreferences_Entry<float>? _prefDamageCooldown;

		private static readonly string DamagePresetsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UserData", "CustomBloodEffects_Presets.txt");

		private static List<(string name, string barcode)> _damagePresets = new List<(string, string)>();

		public static float LastDamageTime = -999f;

		private static Page? _rootPage;

		private static Page? _damagePage;

		private static Page? _damagePresetsPage;

		private static Page? _warehousePage;

		private static FunctionElement? _damageBarcodeDisplay;

		public static bool DamageEnabled => _prefDamageEnabled?.Value ?? false;

		public static string DamageBarcode => _prefDamageBarcode?.Value ?? string.Empty;

		public static float DamageMultiplier => _prefDamageMultiplier?.Value ?? 1f;

		public static float DamageCooldown => _prefDamageCooldown?.Value ?? 0.3f;

		public override void OnInitializeMelon()
		{
			_prefsCategory = MelonPreferences.CreateCategory("CustomBloodEffects");
			_prefDamageEnabled = _prefsCategory.CreateEntry<bool>("DamageEnabled", false, "Damage Enabled", (string)null, false, false, (ValueValidator)null, (string)null);
			_prefDamageBarcode = _prefsCategory.CreateEntry<string>("DamageBarcode", string.Empty, "Damage Barcode", (string)null, false, false, (ValueValidator)null, (string)null);
			_prefDamageMultiplier = _prefsCategory.CreateEntry<float>("DamageMultiplier", 1f, "Damage Multiplier", (string)null, false, false, (ValueValidator)null, (string)null);
			_prefDamageCooldown = _prefsCategory.CreateEntry<float>("DamageCooldown", 0.3f, "Damage Cooldown", (string)null, false, false, (ValueValidator)null, (string)null);
			_prefsCategory.SaveToFile(true);
			LoadPresets(DamagePresetsPath, _damagePresets);
			((MelonBase)this).HarmonyInstance.PatchAll();
			SetupMenu();
			MelonLogger.Msg("[custombloodeffects] Initialised.");
		}

		private static void LoadPresets(string path, List<(string, string)> list)
		{
			list.Clear();
			if (!File.Exists(path))
			{
				return;
			}
			string[] array = File.ReadAllLines(path);
			foreach (string text in array)
			{
				int num = text.IndexOf('=');
				if (num >= 1)
				{
					string text2 = text.Substring(0, num).Trim();
					string text3 = text.Substring(num + 1).Trim();
					if (!string.IsNullOrEmpty(text2) && !string.IsNullOrEmpty(text3))
					{
						list.Add((text2, text3));
					}
				}
			}
		}

		public static void SavePresets(string path, List<(string name, string barcode)> list)
		{
			List<string> list2 = new List<string>();
			foreach (var (text, text2) in list)
			{
				list2.Add(text + "=" + text2);
			}
			File.WriteAllLines(path, list2);
		}

		public static string Short(string bc, int max = 28)
		{
			return (bc.Length > max) ? ("..." + bc.Substring(bc.Length - (max - 3))) : bc;
		}

		public static float ClampMult(float v)
		{
			return Mathf.Round(Mathf.Clamp(v, 0f, 3f) * 2f) / 2f;
		}

		public static float ClampCooldown(float v)
		{
			return Mathf.Round(Mathf.Clamp(v, 0.3f, 3f) * 10f) / 10f;
		}

		private void SetupMenu()
		{
			//IL_0011: 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_0047: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			_rootPage = Page.Root.CreatePage("<color=#FF0000>c</color><color=#FF0008>u</color><color=#FF0010>s</color><color=#FF0018>t</color><color=#FF0020>o</color><color=#FF0029>m</color> <color=#FF0039>b</color><color=#FF0041>l</color><color=#FF0049>e</color><color=#FF0052>e</color><color=#FF005A>d</color><color=#FF0062>i</color><color=#FF006A>n</color><color=#FF0072>g</color>", Color.red, 0, true);
			_damagePage = _rootPage.CreatePage("Damage Settings", Color.green, 0, true);
			_damagePage.CreateBool("Damage Spawn Enabled", Color.green, _prefDamageEnabled.Value, (Action<bool>)delegate(bool v)
			{
				_prefDamageEnabled.Value = v;
				_prefsCategory.SaveToFile(true);
			});
			_damageBarcodeDisplay = _damagePage.CreateFunction(DamageLabel(), Color.yellow, (Action)delegate
			{
				MelonLogger.Msg("[custombloodeffects] Barcode: " + DamageBarcode);
			});
			_damagePage.CreateFunction("Reload Barcode", Color.cyan, (Action)delegate
			{
				MelonPreferences.Load();
				((Element)_damageBarcodeDisplay).ElementName = DamageLabel();
			});
			_damagePage.CreateFunction("Clear Barcode", Color.red, (Action)delegate
			{
				_prefDamageBarcode.Value = string.Empty;
				_prefsCategory.SaveToFile(true);
				((Element)_damageBarcodeDisplay).ElementName = DamageLabel();
			});
			FunctionElement multLbl = _damagePage.CreateFunction($"Multiplier: {DamageMultiplier:F1}", Color.white, (Action)delegate
			{
			});
			_damagePage.CreateFunction("Multiplier  +", Color.green, (Action)delegate
			{
				_prefDamageMultiplier.Value = ClampMult(DamageMultiplier + 0.5f);
				_prefsCategory.SaveToFile(true);
				((Element)multLbl).ElementName = $"Multiplier: {DamageMultiplier:F1}";
			});
			_damagePage.CreateFunction("Multiplier  -", Color.red, (Action)delegate
			{
				_prefDamageMultiplier.Value = ClampMult(DamageMultiplier - 0.5f);
				_prefsCategory.SaveToFile(true);
				((Element)multLbl).ElementName = $"Multiplier: {DamageMultiplier:F1}";
			});
			FunctionElement cdLbl = _damagePage.CreateFunction($"Cooldown: {DamageCooldown:F1}s", Color.white, (Action)delegate
			{
			});
			_damagePage.CreateFunction("Cooldown  +", Color.green, (Action)delegate
			{
				_prefDamageCooldown.Value = ClampCooldown(DamageCooldown + 0.1f);
				_prefsCategory.SaveToFile(true);
				((Element)cdLbl).ElementName = $"Cooldown: {DamageCooldown:F1}s";
			});
			_damagePage.CreateFunction("Cooldown  -", Color.red, (Action)delegate
			{
				_prefDamageCooldown.Value = ClampCooldown(DamageCooldown - 0.1f);
				_prefsCategory.SaveToFile(true);
				((Element)cdLbl).ElementName = $"Cooldown: {DamageCooldown:F1}s";
			});
			_damagePresetsPage = _rootPage.CreatePage("Damage Presets", Color.yellow, 0, true);
			SetupPresetsPage(_damagePresetsPage, _damagePresets, DamagePresetsPath, () => DamageBarcode, delegate(string bc)
			{
				_prefDamageBarcode.Value = bc;
				_prefsCategory.SaveToFile(true);
				((Element)_damageBarcodeDisplay).ElementName = "Barcode: " + Short(bc);
			});
			_warehousePage = _rootPage.CreatePage("Asset Warehouse", Color.white, 0, true);
			WarehouseBrowser.SetupWarehousePage(_warehousePage);
			static string DamageLabel()
			{
				return "Barcode: " + (string.IsNullOrEmpty(DamageBarcode) ? "<none>" : Short(DamageBarcode));
			}
		}

		private static void SetupPresetsPage(Page page, List<(string name, string barcode)> list, string filePath, Func<string> getActive, Action<string> applyBarcode)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			Func<string> getActive2 = getActive;
			List<(string name, string barcode)> list2 = list;
			string filePath2 = filePath;
			Page page2 = page;
			Action<string> applyBarcode2 = applyBarcode;
			page2.CreateFunction("Save Current as Preset", Color.green, (Action)delegate
			{
				string text = getActive2();
				if (string.IsNullOrEmpty(text))
				{
					MelonLogger.Warning("[custombloodeffects] No barcode to save.");
				}
				else
				{
					string text2 = text.Split(new char[1] { '.' })[^1];
					int num = 1;
					string final = text2;
					while (list2.Exists(((string name, string barcode) p) => p.name == final))
					{
						final = text2 + "_" + num++;
					}
					list2.Add((final, text));
					SavePresets(filePath2, list2);
					AddPresetButton(page2, list2, filePath2, final, text, applyBarcode2);
					MelonLogger.Msg("[custombloodeffects] Saved preset '" + final + "'.");
				}
			});
			page2.CreateFunction("Delete All Presets", Color.red, (Action)delegate
			{
				list2.Clear();
				SavePresets(filePath2, list2);
				MelonLogger.Msg("[custombloodeffects] All presets deleted. Restart to refresh.");
			});
			page2.CreateFunction("-- Saved Presets --", Color.white, (Action)delegate
			{
			});
			foreach (var (name, bc) in list2)
			{
				AddPresetButton(page2, list2, filePath2, name, bc, applyBarcode2);
			}
		}

		private static void AddPresetButton(Page page, List<(string name, string barcode)> list, string filePath, string name, string bc, Action<string> applyBarcode)
		{
			//IL_0033: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			Action<string> applyBarcode2 = applyBarcode;
			string bc2 = bc;
			string name2 = name;
			List<(string name, string barcode)> list2 = list;
			string filePath2 = filePath;
			Page val = page.CreatePage(name2, Color.yellow, 0, true);
			val.CreateFunction("Apply", Color.green, (Action)delegate
			{
				applyBarcode2(bc2);
				MelonLogger.Msg("[custombloodeffects] Applied '" + name2 + "'.");
			});
			val.CreateFunction("Delete", Color.red, (Action)delegate
			{
				list2.RemoveAll(((string name, string barcode) p) => p.name == name2 && p.barcode == bc2);
				SavePresets(filePath2, list2);
				MelonLogger.Msg("[custombloodeffects] Deleted '" + name2 + "'. Restart to refresh.");
			});
			val.CreateFunction(Short(bc2, 30), Color.white, (Action)delegate
			{
			});
		}

		public static void DoSpawn(string barcode, Vector3 position, Quaternion rotation, int count)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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)
			Barcode val = new Barcode(barcode);
			SpawnableCrate val2 = null;
			AssetWarehouse.Instance.TryGetCrate<SpawnableCrate>(val, ref val2);
			if ((Object)(object)val2 == (Object)null)
			{
				MelonLogger.Error("[custombloodeffects] Crate not found: " + barcode);
				return;
			}
			int num = Math.Max(1, Math.Min(count, 100));
			for (int i = 0; i < num; i++)
			{
				SpawnableCrateReference crateRef = new SpawnableCrateReference(barcode);
				Spawnable val3 = new Spawnable
				{
					crateRef = crateRef
				};
				AssetSpawner.Register(val3);
				if (FusionHelper.FusionInstalled && FusionHelper.IsConnected())
				{
					FusionHelper.NetworkSpawn(barcode, position, rotation);
				}
				else
				{
					AssetSpawner.Spawn(val3, position, rotation, new Nullable<Vector3>(), (Transform)null, false, new Nullable<int>(), (Action<GameObject>)null, (Action<GameObject>)null);
				}
			}
		}

		public static void SetDamageBarcode(string barcode)
		{
			_prefDamageBarcode.Value = barcode;
			_prefsCategory.SaveToFile(true);
			if (_damageBarcodeDisplay != null)
			{
				((Element)_damageBarcodeDisplay).ElementName = "Barcode: " + Short(barcode);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerDamageReceiver), "ReceiveAttack")]
	public static class DamagePatch
	{
		[HarmonyPostfix]
		public static void Postfix(PlayerDamageReceiver __instance, Attack attack)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: 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)
			try
			{
				if (!CustomBloodMod.DamageEnabled || string.IsNullOrEmpty(CustomBloodMod.DamageBarcode))
				{
					return;
				}
				float time = Time.time;
				if (time - CustomBloodMod.LastDamageTime < CustomBloodMod.DamageCooldown)
				{
					return;
				}
				CustomBloodMod.LastDamageTime = time;
				RigManager componentInParent = ((Component)__instance).gameObject.GetComponentInParent<RigManager>();
				if (!((Object)(object)componentInParent == (Object)null))
				{
					RigManager rigManager = Player.RigManager;
					if (!((Object)(object)rigManager == (Object)null) && ((Object)((Component)componentInParent).gameObject).GetInstanceID() == ((Object)((Component)rigManager).gameObject).GetInstanceID())
					{
						Transform transform = ((Component)__instance).gameObject.transform;
						Vector3 position = transform.position;
						Quaternion rotation = transform.rotation;
						int count = Math.Max(1, (int)Mathf.Round(CustomBloodMod.DamageMultiplier));
						CustomBloodMod.DoSpawn(CustomBloodMod.DamageBarcode, position, rotation, count);
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[custombloodeffects] Damage patch: " + ex.Message);
			}
		}
	}
	public static class WarehouseBrowser
	{
		private static string _searchQuery = string.Empty;

		private static Page? _warehouseRootPage;

		private static FunctionElement? _statusLabel;

		private static int _searchSession = 0;

		public static void SetupWarehousePage(Page warehousePage)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			_warehouseRootPage = warehousePage;
			warehousePage.CreateString("Search Query", Color.green, _searchQuery, (Action<string>)delegate(string val)
			{
				_searchQuery = val ?? string.Empty;
			});
			warehousePage.CreateFunction("Refresh / Search", Color.green, (Action)delegate
			{
				PopulateResults();
			});
			warehousePage.CreateFunction("Clear Search", Color.red, (Action)delegate
			{
				_searchQuery = string.Empty;
				PopulateResults();
			});
			_statusLabel = warehousePage.CreateFunction("[ Press Refresh / Search to load ]", Color.yellow, (Action)delegate
			{
			});
		}

		private static void PopulateResults()
		{
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: 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_0301: 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_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_0509: Unknown result type (might be due to invalid IL or missing references)
			if (_warehouseRootPage == null)
			{
				return;
			}
			try
			{
				AssetWarehouse instance = AssetWarehouse.Instance;
				if (instance == null)
				{
					if (_statusLabel != null)
					{
						((Element)_statusLabel).ElementName = "Warehouse not ready — try again.";
					}
					return;
				}
				List<SpawnableCrate> crates = instance.GetCrates<SpawnableCrate>((ICrateFilter<SpawnableCrate>)null);
				if (crates == null || crates.Count == 0)
				{
					if (_statusLabel != null)
					{
						((Element)_statusLabel).ElementName = "No crates found — try again.";
					}
					return;
				}
				string text = _searchQuery.ToLowerInvariant().Trim();
				_searchSession++;
				int searchSession = _searchSession;
				Dictionary<string, List<Tuple<string, string>>> dictionary = new Dictionary<string, List<Tuple<string, string>>>();
				Enumerator<SpawnableCrate> enumerator = crates.GetEnumerator();
				while (enumerator.MoveNext())
				{
					SpawnableCrate current = enumerator.Current;
					if ((Object)(object)current == (Object)null)
					{
						continue;
					}
					try
					{
						string text2 = ((Scannable)current).Barcode.ID ?? string.Empty;
						if (string.IsNullOrEmpty(text2))
						{
							continue;
						}
						string text3 = ((Scannable)current).Title ?? text2;
						Pallet pallet = ((Crate)current).Pallet;
						string text4 = ((pallet != null) ? ((Scannable)pallet).Title : null) ?? "Unknown Pallet";
						if (string.IsNullOrEmpty(text) || text3.ToLowerInvariant().Contains(text) || text4.ToLowerInvariant().Contains(text) || text2.ToLowerInvariant().Contains(text))
						{
							if (!dictionary.ContainsKey(text4))
							{
								dictionary[text4] = new List<Tuple<string, string>>();
							}
							dictionary[text4].Add(Tuple.Create(text3, text2));
						}
					}
					catch
					{
					}
				}
				int num = 0;
				foreach (KeyValuePair<string, List<Tuple<string, string>>> item in dictionary)
				{
					num += item.Value.Count;
				}
				string text5 = (string.IsNullOrEmpty(text) ? $"{dictionary.Count} pallets, {num} crates loaded" : $"{dictionary.Count} pallets, {num} crates matching [{text}]");
				if (_statusLabel != null)
				{
					((Element)_statusLabel).ElementName = text5;
				}
				string text6 = (string.IsNullOrEmpty(text) ? $"Results #{searchSession} (all)" : $"Results #{searchSession} [{text}]");
				Page val = _warehouseRootPage.CreatePage(text6, Color.white, 0, true);
				val.CreateFunction(text5, Color.white, (Action)delegate
				{
				});
				if (dictionary.Count == 0)
				{
					val.CreateFunction("No results found.", Color.red, (Action)delegate
					{
					});
					return;
				}
				Page val2 = val.CreatePage("Pallets", Color.yellow, 0, true);
				val2.CreateFunction($"[ {dictionary.Count} pallet(s) ]", Color.white, (Action)delegate
				{
				});
				foreach (KeyValuePair<string, List<Tuple<string, string>>> item2 in dictionary)
				{
					string key = item2.Key;
					List<Tuple<string, string>> value = item2.Value;
					string text7 = ((key.Length > 26) ? ("..." + key.Substring(key.Length - 23)) : key);
					Page val3 = val2.CreatePage(text7, Color.cyan, 0, true);
					val3.CreateFunction("[ " + text7 + " ]", Color.white, (Action)delegate
					{
					});
					val3.CreateFunction($"{value.Count} spawnable(s)", Color.white, (Action)delegate
					{
					});
					AddCrateButtons(val3, value);
				}
				Page val4 = val.CreatePage("Crates", Color.cyan, 0, true);
				List<Tuple<string, string>> list = new List<Tuple<string, string>>();
				foreach (KeyValuePair<string, List<Tuple<string, string>>> item3 in dictionary)
				{
					list.AddRange(item3.Value);
				}
				val4.CreateFunction($"[ {list.Count} crate(s) ]", Color.white, (Action)delegate
				{
				});
				AddCrateButtons(val4, list);
				MelonLogger.Msg($"[custombloodeffects] Search #{searchSession}: {num} crates, {dictionary.Count} pallets.");
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[custombloodeffects] WarehouseBrowser: " + ex.Message);
				if (_statusLabel != null)
				{
					((Element)_statusLabel).ElementName = "Error: " + ex.Message.Substring(0, Math.Min(30, ex.Message.Length));
				}
			}
		}

		private static void AddCrateButtons(Page parentPage, List<Tuple<string, string>> crates)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			foreach (Tuple<string, string> crate in crates)
			{
				string capTitle = crate.Item1;
				string capBarcode = crate.Item2;
				string text = ((capTitle.Length > 26) ? ("..." + capTitle.Substring(capTitle.Length - 23)) : capTitle);
				Page val = parentPage.CreatePage(text, Color.green, 0, true);
				val.CreateFunction("Send to Damage", Color.green, (Action)delegate
				{
					CustomBloodMod.SetDamageBarcode(capBarcode);
					MelonLogger.Msg("[custombloodeffects] -> Damage: " + capTitle);
				});
				val.CreateFunction((capBarcode.Length > 26) ? ("..." + capBarcode.Substring(capBarcode.Length - 23)) : capBarcode, Color.white, (Action)delegate
				{
				});
			}
		}
	}
	public static class FusionHelper
	{
		public static bool FusionInstalled { get; private set; }

		static FusionHelper()
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (assembly.FullName.Contains("LabFusion"))
					{
						FusionInstalled = true;
						break;
					}
				}
			}
			catch
			{
				FusionInstalled = false;
			}
		}

		public static bool IsConnected()
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (!assembly.FullName.Contains("LabFusion"))
					{
						continue;
					}
					Type[] types = assembly.GetTypes();
					foreach (Type type in types)
					{
						if (!(type.Name != "NetworkInfo"))
						{
							PropertyInfo property = type.GetProperty("HasServer");
							if (property != null)
							{
								return (bool)property.GetValue(null);
							}
						}
					}
				}
				return false;
			}
			catch
			{
				return false;
			}
		}

		public static void NetworkSpawn(string barcode, Vector3 position, Quaternion rotation)
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Type type = null;
				Type type2 = null;
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (!assembly.FullName.Contains("LabFusion"))
					{
						continue;
					}
					Type[] types = assembly.GetTypes();
					foreach (Type type3 in types)
					{
						if (type3.Name == "NetworkAssetSpawner")
						{
							type = type3;
						}
						if (type3.Name == "SpawnRequestInfo")
						{
							type2 = type3;
						}
					}
					if (type != null && type2 != null)
					{
						break;
					}
				}
				if (type == null || type2 == null)
				{
					MelonLogger.Error("[custombloodeffects] Fusion types not found.");
					return;
				}
				SpawnableCrateReference crateRef = new SpawnableCrateReference(barcode);
				Spawnable val = new Spawnable
				{
					crateRef = crateRef
				};
				AssetSpawner.Register(val);
				object uninitializedObject = FormatterServices.GetUninitializedObject(type2);
				type2.GetField("Spawnable")?.SetValue(uninitializedObject, val);
				type2.GetField("Position")?.SetValue(uninitializedObject, position);
				type2.GetField("Rotation")?.SetValue(uninitializedObject, rotation);
				MethodInfo method = type.GetMethod("Spawn");
				if (method == null)
				{
					MelonLogger.Error("[custombloodeffects] Spawn method not found.");
					return;
				}
				method.Invoke(null, new object[1] { uninitializedObject });
			}
			catch (TargetInvocationException ex)
			{
				MelonLogger.Error("[custombloodeffects] Fusion spawn (inner): " + ex.InnerException?.Message);
			}
			catch (Exception ex2)
			{
				MelonLogger.Error("[custombloodeffects] Fusion spawn: " + ex2.Message);
			}
		}
	}
}