Decompiled source of MarkerMod v1.5.1

MarkerMod.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using Bifrost.Cooked;
using HarmonyLib;
using MarkerMod;
using MarkerMod.Config;
using MarkerMod.Managers;
using MarkerMod.Services;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using Mimic.Actors;
using MimicAPI.GameAPI;
using ReluProtocol;
using UnityEngine;
using UnityEngine.InputSystem;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "MarkerMod", "1.5.0", "DooDesch", null)]
[assembly: MelonGame("ReLUGames", "MIMESIS")]
[assembly: MelonOptionalDependencies(new string[] { "MimicAPI" })]
[assembly: HarmonyDontPatchAll]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MarkerMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.1.0")]
[assembly: AssemblyInformationalVersion("1.5.1+d767ae756357bdd6238e050e86f285db51679be2")]
[assembly: AssemblyProduct("MarkerMod")]
[assembly: AssemblyTitle("MarkerMod")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 MarkerMod
{
	public class Core : MelonMod
	{
		public override void OnInitializeMelon()
		{
			MarkerPreferences.Initialize();
			((MelonBase)this).HarmonyInstance.PatchAll();
			((MelonBase)this).LoggerInstance.Msg($"MarkerMod initialized. Lifespan={MarkerPreferences.PermanentLifetimeSeconds:F0}s, Footprints={MarkerPreferences.KeepFootprints}, Puddles={MarkerPreferences.KeepPuddles}, InfinitePaintballs={MarkerPreferences.InfinitePaintballs}");
		}
	}
}
namespace MarkerMod.Patches
{
	[HarmonyPatch(typeof(FieldSkillActor), "Spawn")]
	internal static class FieldSkillActorSpawnPatch
	{
		private static readonly MethodInfo Destroy2Arg = AccessTools.Method(typeof(Object), "Destroy", new Type[2]
		{
			typeof(Object),
			typeof(float)
		}, (Type[])null);

		private static readonly MethodInfo DestroyOverride = AccessTools.Method(typeof(PaintPersistenceManager), "DestroyWithOverride", (Type[])null, (Type[])null);

		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, Destroy2Arg))
				{
					yield return new CodeInstruction(OpCodes.Ldarg_1, (object)null);
					instruction.operand = DestroyOverride;
				}
				yield return instruction;
			}
		}

		[HarmonyPostfix]
		public static void Postfix(FieldSkillActor __instance, FieldSkillObjectInfo fieldSkillObjectInfo, ref float __result)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			PaintPersistenceManager.TrackDecal(fieldSkillObjectInfo);
			__result = PaintPersistenceManager.OverrideLifetime(fieldSkillObjectInfo, __result);
			if (!MarkerPreferences.EnablePaintballColorChange || fieldSkillObjectInfo == null)
			{
				return;
			}
			try
			{
				if (PaintBallColorManager.IsPaintball(fieldSkillObjectInfo.fieldSkillMasterID) && PaintBallColorManager.HasColorBeenSelected() && (Object)(object)__instance != (Object)null)
				{
					((MonoBehaviour)__instance).StartCoroutine(ApplyColorToProjectileCoroutine(__instance, PaintBallColorManager.GetCurrentColor()));
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[PaintballProjectileColor] Error: " + ex.Message + "\n" + ex.StackTrace);
			}
		}

		private static IEnumerator ApplyColorToProjectileCoroutine(FieldSkillActor actor, Color color)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			yield return null;
			yield return null;
			if ((Object)(object)actor != (Object)null && (Object)(object)((Component)actor).transform != (Object)null)
			{
				MaterialColorService.ApplyColorToTransform(((Component)actor).transform, color, useDefaultMaterial: false);
			}
		}
	}
	[HarmonyPatch(typeof(GameMainBase), "SpawnFieldSkill")]
	internal static class GameMainBaseSpawnFieldSkillPatch
	{
		private static readonly MethodInfo Destroy2Arg = AccessTools.Method(typeof(Object), "Destroy", new Type[2]
		{
			typeof(Object),
			typeof(float)
		}, (Type[])null);

		private static readonly MethodInfo DestroyOverride = AccessTools.Method(typeof(PaintPersistenceManager), "DestroyWithOverride", (Type[])null, (Type[])null);

		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, Destroy2Arg))
				{
					yield return new CodeInstruction(OpCodes.Ldarg_1, (object)null);
					instruction.operand = DestroyOverride;
				}
				yield return instruction;
			}
		}
	}
	[HarmonyPatch(typeof(WorldDecal), "Activate")]
	internal static class WorldDecalActivatePatch
	{
		[HarmonyPrefix]
		public static void Prefix(WorldDecal __instance)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if (PaintPersistenceManager.IsPermanentDecal(__instance.decalId))
			{
				__instance.lifetimeMSec = PaintPersistenceManager.PermanentLifetimeMilliseconds;
				__instance.fadeoutMSec = 0L;
			}
			if (MarkerPreferences.EnablePaintballColorChange && PaintBallColorManager.HasColorBeenSelected() && PaintBallColorManager.GetCurrentColorIndex() != -1 && PaintPersistenceManager.IsPaintDecal(__instance.decalId))
			{
				__instance.decalColor = PaintBallColorManager.GetCurrentColor();
			}
		}
	}
	[HarmonyPatch(typeof(DecalData), "CreateDecalData")]
	internal static class DecalDataCreatePatch
	{
		[HarmonyPrefix]
		public static void Prefix(string pathWithSocket, ref long lifetimeMSec, ref long fadeoutMSec, Transform spawnBase)
		{
			bool flag = !string.IsNullOrEmpty(pathWithSocket) && pathWithSocket.IndexOf("paint", StringComparison.OrdinalIgnoreCase) >= 0;
			bool flag2 = (Object)(object)spawnBase != (Object)null;
			bool flag3 = false;
			if (MarkerPreferences.KeepFootprints && flag2 && flag)
			{
				flag3 = true;
			}
			if (MarkerPreferences.KeepPuddles && !flag2 && flag)
			{
				flag3 = true;
			}
			if (flag3)
			{
				lifetimeMSec = PaintPersistenceManager.PermanentLifetimeMilliseconds;
				fadeoutMSec = 0L;
			}
		}

		[HarmonyPostfix]
		public static void Postfix(DecalData __result, string pathWithSocket, Transform spawnBase)
		{
			bool flag = !string.IsNullOrEmpty(pathWithSocket) && pathWithSocket.IndexOf("paint", StringComparison.OrdinalIgnoreCase) >= 0;
			bool flag2 = (Object)(object)spawnBase != (Object)null;
			if (MarkerPreferences.KeepFootprints && flag2 && flag && __result != null)
			{
				PaintPersistenceManager.TrackDecalIfNeeded(__result);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryController), "OnUseSkill_SpawnProjectile", new Type[]
	{
		typeof(int),
		typeof(VProjectileObject)
	})]
	internal static class OnUseSkillSpawnProjectilePatch
	{
		[HarmonyPrefix]
		public static bool Prefix(VProjectileObject projectile)
		{
			if (!MarkerPreferences.InfinitePaintballs || projectile == null)
			{
				return true;
			}
			try
			{
				object fieldValue = ReflectionHelper.GetFieldValue((object)projectile, "_projectileInfo");
				if (fieldValue == null)
				{
					return true;
				}
				if (PaintBallColorManager.IsPaintball(ReflectionHelper.GetFieldValue<int>(fieldValue, "SpawnItemMasterIDonCollision")))
				{
					return false;
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[InfinitePaintballs] OnUseSkill_SpawnProjectile patch error: " + ex.Message);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(EquipmentItemElement), "SetDurability")]
	internal static class EquipmentItemElementSetDurabilityPatch
	{
		[HarmonyPrefix]
		public static bool Prefix(EquipmentItemElement __instance, int durability)
		{
			if (!MarkerPreferences.InfinitePaintballs)
			{
				return true;
			}
			try
			{
				if (PaintBallColorManager.IsPaintball(ReflectionHelper.GetFieldValue<int>((object)__instance, "ItemMasterID")))
				{
					int propertyValue = ReflectionHelper.GetPropertyValue<int>((object)__instance, "RemainDurability");
					if (durability < propertyValue)
					{
						return false;
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[InfinitePaintballs] Error in SetDurability patch: " + ex.Message);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ProtoActor), "Update")]
	internal static class PaintBallColorUpdatePatch
	{
		private static long lastSelectedItemID = -1L;

		private static bool wasRightMouseButtonPressedLastFrame = false;

		[HarmonyPostfix]
		public static void Postfix(ProtoActor __instance)
		{
			if (!MarkerPreferences.EnablePaintballColorChange)
			{
				return;
			}
			try
			{
				if (!__instance.AmIAvatar())
				{
					return;
				}
				if ((Object)(object)PlayerAPI.GetLocalPlayer() == (Object)null)
				{
					lastSelectedItemID = -1L;
					return;
				}
				object localInventory = PlayerAPI.GetLocalInventory();
				if (localInventory == null)
				{
					lastSelectedItemID = -1L;
					return;
				}
				object propertyValue = ReflectionHelper.GetPropertyValue(localInventory, "SelectedItem");
				if (propertyValue == null)
				{
					if (lastSelectedItemID != -1)
					{
						MelonLogger.Msg("[PaintBallColor] No item selected");
						lastSelectedItemID = -1L;
					}
					return;
				}
				object propertyValue2 = ReflectionHelper.GetPropertyValue(propertyValue, "ItemID");
				object propertyValue3 = ReflectionHelper.GetPropertyValue(propertyValue, "ItemMasterID");
				if (propertyValue2 == null || propertyValue3 == null)
				{
					return;
				}
				long num = Convert.ToInt64(propertyValue2);
				bool flag = PaintBallColorManager.IsPaintball(Convert.ToInt32(propertyValue3));
				if (flag && num != lastSelectedItemID)
				{
					PaintBallColorManager.ResetColorSelection();
					PaintBallColorManager.ApplyColorToPaintball(propertyValue);
					lastSelectedItemID = num;
				}
				else if (!flag && lastSelectedItemID != -1)
				{
					lastSelectedItemID = -1L;
					PaintBallColorManager.ResetColorSelection();
				}
				if (flag)
				{
					Mouse current = Mouse.current;
					if (current != null)
					{
						bool isPressed = current.rightButton.isPressed;
						bool num2 = isPressed && !wasRightMouseButtonPressedLastFrame;
						wasRightMouseButtonPressedLastFrame = isPressed;
						if (num2)
						{
							PaintBallColorManager.CycleColor();
							PaintBallColorManager.ApplyColorToPaintball(propertyValue);
							string currentColorName = PaintBallColorManager.GetCurrentColorName();
							MelonLogger.Msg("[PaintBallColor] Farbe geändert zu: " + currentColorName);
						}
					}
				}
				else
				{
					wasRightMouseButtonPressedLastFrame = false;
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[PaintBallColor] Error: " + ex.Message + "\n" + ex.StackTrace);
			}
		}
	}
	[HarmonyPatch(typeof(VProjectileObject), "HandlePhysicsProj")]
	internal static class VProjectileSelfHitGracePatch
	{
		private const float HugeGraceDistance = 1E+09f;

		[HarmonyPrepare]
		public static bool Prepare()
		{
			try
			{
				return MarkerPreferences.PreventPaintballSelfDamage;
			}
			catch
			{
				return false;
			}
		}

		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ldfld && instruction.operand is FieldInfo { Name: "SelfHitGraceDistance" })
				{
					yield return new CodeInstruction(OpCodes.Pop, (object)null);
					yield return new CodeInstruction(OpCodes.Ldc_R4, (object)1E+09f);
				}
				else
				{
					yield return instruction;
				}
			}
		}
	}
	[HarmonyPatch(typeof(VProjectileObject), "OnHit")]
	internal static class VProjectileSelfHitPatch
	{
		[HarmonyPrefix]
		public static void Prefix(VProjectileObject __instance, List<int> hitTargetActorIDs)
		{
			if (!MarkerPreferences.PreventPaintballSelfDamage || hitTargetActorIDs == null || hitTargetActorIDs.Count == 0)
			{
				return;
			}
			try
			{
				object fieldValue = ReflectionHelper.GetFieldValue((object)__instance, "_parentActor");
				if (fieldValue == null)
				{
					return;
				}
				int parentActorID = ReflectionHelper.GetPropertyValue<int>(fieldValue, "ObjectID");
				if (parentActorID != 0)
				{
					hitTargetActorIDs.RemoveAll((int id) => id == parentActorID);
					_ = 0;
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PaintballSelfDamage] Projectile OnHit patch error: " + ex.Message);
			}
		}
	}
	[HarmonyPatch(typeof(FieldSkillObject), "OnHit")]
	internal static class FieldSkillSelfHitPatch
	{
		[HarmonyPrefix]
		public static void Prefix(FieldSkillObject __instance, FieldSkillHitInputData hitInfo)
		{
			if (!MarkerPreferences.PreventPaintballSelfDamage || ((hitInfo != null) ? hitInfo.Targets : null) == null || hitInfo.Targets.Count == 0)
			{
				return;
			}
			try
			{
				object fieldValue = ReflectionHelper.GetFieldValue((object)__instance, "_parentSkillContext");
				object obj = ((fieldValue != null) ? ReflectionHelper.GetPropertyValue(fieldValue, "ContextInfo") : null);
				object obj2 = ((obj != null) ? ReflectionHelper.GetFieldValue(obj, "Creature") : null);
				int casterID = ((obj2 != null) ? ReflectionHelper.GetPropertyValue<int>(obj2, "ObjectID") : 0);
				if (casterID != 0)
				{
					hitInfo.Targets.RemoveAll((TargetInfo t) => t.targetObjectID == casterID);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PaintballSelfDamage] FieldSkill OnHit patch error: " + ex.Message);
			}
		}
	}
	[HarmonyPatch(typeof(VProjectileObject), "HandlePhysicsProj")]
	internal static class VProjectileNavmeshPatch
	{
		private const float WidenedSnapRadius = 25f;

		[HarmonyPrepare]
		public static bool Prepare()
		{
			try
			{
				return MarkerPreferences.AllowLongPaintballThrows;
			}
			catch
			{
				return false;
			}
		}

		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			for (int i = 1; i < list.Count; i++)
			{
				CodeInstruction val = list[i];
				if ((val.opcode == OpCodes.Call || val.opcode == OpCodes.Callvirt) && val.operand is MethodInfo { Name: "GetNearestPointOnNavMesh" } && list[i - 1].opcode == OpCodes.Ldc_R4)
				{
					list[i - 1].operand = 25f;
				}
			}
			return list;
		}
	}
}
namespace MarkerMod.Services
{
	internal static class MaterialColorService
	{
		private static readonly Dictionary<string, Material> originalMaterialsCache = new Dictionary<string, Material>();

		internal static void ApplyColorToRenderer(Renderer renderer, Color color, bool useDefaultMaterial)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0062: 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_0058: Expected O, but got Unknown
			if ((Object)(object)renderer == (Object)null)
			{
				return;
			}
			Material[] materials = renderer.materials;
			if (materials == null || materials.Length == 0)
			{
				return;
			}
			for (int i = 0; i < materials.Length; i++)
			{
				if ((Object)(object)materials[i] != (Object)null)
				{
					Material orCacheOriginalMaterial = GetOrCacheOriginalMaterial($"{((Object)renderer).GetInstanceID()}_{i}", materials[i]);
					if (useDefaultMaterial)
					{
						materials[i] = new Material(orCacheOriginalMaterial);
						continue;
					}
					Material val = new Material(orCacheOriginalMaterial);
					ApplyColorToMaterial(val, color);
					materials[i] = val;
				}
			}
			renderer.materials = materials;
		}

		internal static void ApplyColorToTransform(Transform transform, Color color, bool useDefaultMaterial)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)transform == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = ((Component)transform).GetComponentsInChildren<Renderer>(true);
			if (componentsInChildren != null && componentsInChildren.Length != 0)
			{
				Renderer[] array = componentsInChildren;
				for (int i = 0; i < array.Length; i++)
				{
					ApplyColorToRenderer(array[i], color, useDefaultMaterial);
				}
			}
		}

		private static Material GetOrCacheOriginalMaterial(string materialKey, Material currentMaterial)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			if (!originalMaterialsCache.ContainsKey(materialKey))
			{
				Material val = new Material(currentMaterial);
				if (val.HasProperty("_MainTex") && (Object)(object)val.GetTexture("_MainTex") == (Object)(object)Texture2D.whiteTexture)
				{
					val.SetTexture("_MainTex", (Texture)null);
				}
				if (val.HasProperty("_BaseMap") && (Object)(object)val.GetTexture("_BaseMap") == (Object)(object)Texture2D.whiteTexture)
				{
					val.SetTexture("_BaseMap", (Texture)null);
				}
				originalMaterialsCache[materialKey] = val;
				return val;
			}
			return originalMaterialsCache[materialKey];
		}

		private static void ApplyColorToMaterial(Material material, Color color)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			if (material.HasProperty("_Color"))
			{
				ReplaceTextureWithWhite(material);
				if (IsBlackColor(color))
				{
					material.SetColor("_Color", new Color(0.15f, 0.15f, 0.15f, 1f));
				}
				else
				{
					material.SetColor("_Color", color);
				}
			}
			else if (material.HasProperty("_BaseColor"))
			{
				ReplaceTextureWithWhite(material);
				if (IsBlackColor(color))
				{
					material.SetColor("_BaseColor", new Color(0.15f, 0.15f, 0.15f, 1f));
				}
				else
				{
					material.SetColor("_BaseColor", color);
				}
			}
			else if (material.HasProperty("_TintColor"))
			{
				ReplaceTextureWithWhite(material);
				if (IsBlackColor(color))
				{
					material.SetColor("_TintColor", new Color(0.15f, 0.15f, 0.15f, 1f));
				}
				else
				{
					material.SetColor("_TintColor", color);
				}
			}
		}

		private static void ReplaceTextureWithWhite(Material material)
		{
			if (material.HasProperty("_MainTex"))
			{
				material.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture);
			}
			if (material.HasProperty("_BaseMap"))
			{
				material.SetTexture("_BaseMap", (Texture)(object)Texture2D.whiteTexture);
			}
		}

		private static bool IsBlackColor(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (color.r < 0.1f && color.g < 0.1f)
			{
				return color.b < 0.1f;
			}
			return false;
		}
	}
}
namespace MarkerMod.Managers
{
	internal static class PaintPersistenceManager
	{
		private const int PaintspotMasterId = 71001;

		private static readonly HashSet<int> PaintballMasterIds = new HashSet<int> { 70010, 70011, 70012, 70013, 70014, 70015, 70016, 70017, 70018 };

		private static readonly HashSet<string> PermanentDecalIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly object DecalLock = new object();

		private static readonly Func<Hub, DataManager> DataManagerGetter = CreateDataManagerGetter();

		internal static long PermanentLifetimeMilliseconds
		{
			get
			{
				double num = (double)MarkerPreferences.PermanentLifetimeSeconds * 1000.0;
				if (!(num >= 9.223372036854776E+18))
				{
					return (long)Math.Max(1.0, num);
				}
				return long.MaxValue;
			}
		}

		internal static bool ShouldKeep(FieldSkillObjectInfo info)
		{
			if (info == null)
			{
				return false;
			}
			if (MarkerPreferences.KeepFootprints && info.fieldSkillMasterID == 71001)
			{
				return true;
			}
			if (MarkerPreferences.KeepPuddles && PaintballMasterIds.Contains(info.fieldSkillMasterID))
			{
				return true;
			}
			return false;
		}

		internal static float OverrideLifetime(FieldSkillObjectInfo info, float originalSeconds)
		{
			if (!ShouldKeep(info))
			{
				return originalSeconds;
			}
			return MathF.Max(originalSeconds, MarkerPreferences.PermanentLifetimeSeconds);
		}

		internal static void DestroyWithOverride(Object target, float originalSeconds, FieldSkillObjectInfo info)
		{
			Object.Destroy(target, OverrideLifetime(info, originalSeconds));
		}

		internal static void TrackDecal(FieldSkillObjectInfo info)
		{
			if (!MarkerPreferences.KeepFootprints || info == null || info.fieldSkillMasterID != 71001)
			{
				return;
			}
			FieldSkillMemberInfo val = ResolveMemberInfo(info);
			if (val == null || string.IsNullOrEmpty(val.DecalId))
			{
				return;
			}
			lock (DecalLock)
			{
				PermanentDecalIds.Add(val.DecalId);
			}
		}

		internal static bool IsPermanentDecal(string decalId)
		{
			if (string.IsNullOrWhiteSpace(decalId))
			{
				return false;
			}
			lock (DecalLock)
			{
				return PermanentDecalIds.Contains(decalId);
			}
		}

		internal static void EnsureDecalLifetime(DecalData decalData)
		{
		}

		internal static void TrackDecalIfNeeded(DecalData decalData)
		{
			if (decalData == null || !MarkerPreferences.KeepFootprints || string.IsNullOrEmpty(decalData.DecalId) || !((Object)(object)decalData.SpawnBase != (Object)null) || (!ContainsPaintKeyword(decalData.DecalId) && !ContainsPaintKeyword(decalData.Socket)))
			{
				return;
			}
			lock (DecalLock)
			{
				PermanentDecalIds.Add(decalData.DecalId);
			}
		}

		private static bool ContainsPaintKeyword(string value)
		{
			if (!string.IsNullOrEmpty(value))
			{
				return value.IndexOf("paint", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		internal static bool IsPaintDecal(string decalId)
		{
			if (!ContainsPaintKeyword(decalId))
			{
				return IsPermanentDecal(decalId);
			}
			return true;
		}

		internal static bool IsPaintFieldSkill(int fieldSkillMasterID)
		{
			if (fieldSkillMasterID != 71001)
			{
				return PaintballMasterIds.Contains(fieldSkillMasterID);
			}
			return true;
		}

		private static FieldSkillMemberInfo ResolveMemberInfo(FieldSkillObjectInfo info)
		{
			Hub s = Hub.s;
			if ((Object)(object)s == (Object)null)
			{
				return null;
			}
			DataManager val = DataManagerGetter(s);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			FieldSkillInfo fieldSkillData = val.ExcelDataManager.GetFieldSkillData(info.fieldSkillMasterID);
			if (fieldSkillData == null)
			{
				return null;
			}
			if (!fieldSkillData.FieldSkillMemberInfos.TryGetValue(info.fieldSkillIndex, out var value))
			{
				return null;
			}
			return value;
		}

		private static Func<Hub, DataManager> CreateDataManagerGetter()
		{
			return (Hub hub) => (!((Object)(object)hub != (Object)null)) ? null : ReflectionHelper.GetPropertyValue<DataManager>((object)hub, "dataman");
		}
	}
	internal static class PaintBallColorManager
	{
		private static readonly List<Color> ColorPalette = new List<Color>
		{
			new Color(1f, 0f, 0f, 1f),
			new Color(1f, 1f, 0f, 1f),
			new Color(0f, 1f, 0f, 1f),
			new Color(0f, 0f, 1f, 1f),
			new Color(1f, 0.5f, 0f, 1f),
			new Color(0.5f, 0f, 1f, 1f),
			new Color(1f, 1f, 1f, 1f),
			new Color(0f, 0f, 0f, 1f)
		};

		private static int currentColorIndex = -1;

		private static bool hasColorBeenSelected = false;

		private static readonly HashSet<int> PaintballMasterIDs = new HashSet<int> { 2030, 70010, 70011, 70012, 70013, 70014, 70015, 70016, 70017, 70018 };

		internal static void CycleColor()
		{
			hasColorBeenSelected = true;
			if (currentColorIndex == -1)
			{
				currentColorIndex = 0;
			}
			else if (currentColorIndex == ColorPalette.Count - 1)
			{
				currentColorIndex = -1;
			}
			else
			{
				currentColorIndex++;
			}
		}

		internal static void ResetColorSelection()
		{
			hasColorBeenSelected = false;
			currentColorIndex = -1;
		}

		internal static Color GetCurrentColor()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (currentColorIndex == -1)
			{
				return Color.white;
			}
			return ColorPalette[currentColorIndex];
		}

		internal static string GetCurrentColorName()
		{
			return currentColorIndex switch
			{
				-1 => "Default", 
				0 => "Rot", 
				1 => "Gelb", 
				2 => "Grün", 
				3 => "Blau", 
				4 => "Orange", 
				5 => "Lila", 
				6 => "Weiß", 
				7 => "Schwarz", 
				_ => "Unbekannt", 
			};
		}

		internal static bool IsPaintball(int itemMasterID)
		{
			return PaintballMasterIDs.Contains(itemMasterID);
		}

		internal static void ApplyColorToPaintball(object inventoryItem)
		{
			//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_0053: Unknown result type (might be due to invalid IL or missing references)
			if (inventoryItem == null)
			{
				return;
			}
			try
			{
				Transform propertyValue = ReflectionHelper.GetPropertyValue<Transform>(inventoryItem, "Transform");
				if ((Object)(object)propertyValue == (Object)null)
				{
					return;
				}
				bool useDefaultMaterial = !hasColorBeenSelected || currentColorIndex == -1;
				Color currentColor = GetCurrentColor();
				Renderer[] componentsInChildren = ((Component)propertyValue).GetComponentsInChildren<Renderer>(true);
				if (componentsInChildren != null && componentsInChildren.Length != 0)
				{
					Renderer[] array = componentsInChildren;
					for (int i = 0; i < array.Length; i++)
					{
						MaterialColorService.ApplyColorToRenderer(array[i], currentColor, useDefaultMaterial);
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[PaintBallColorManager] Error: " + ex.Message + "\n" + ex.StackTrace);
			}
		}

		internal static bool HasColorBeenSelected()
		{
			return hasColorBeenSelected;
		}

		internal static int GetCurrentColorIndex()
		{
			return currentColorIndex;
		}
	}
}
namespace MarkerMod.Config
{
	internal static class MarkerPreferences
	{
		private const string CategoryId = "MarkerMod";

		private static MelonPreferences_Category _category;

		private static MelonPreferences_Entry<bool> _keepFootprints;

		private static MelonPreferences_Entry<bool> _keepPuddles;

		private static MelonPreferences_Entry<float> _lifetimeSeconds;

		private static MelonPreferences_Entry<bool> _infinitePaintballs;

		private static MelonPreferences_Entry<bool> _enablePaintballColorChange;

		private static MelonPreferences_Entry<bool> _preventPaintballSelfDamage;

		private static MelonPreferences_Entry<bool> _allowLongPaintballThrows;

		internal static bool KeepFootprints => _keepFootprints?.Value ?? true;

		internal static bool KeepPuddles => _keepPuddles?.Value ?? false;

		internal static float PermanentLifetimeSeconds => Mathf.Max(1f, _lifetimeSeconds?.Value ?? 86400f);

		internal static bool InfinitePaintballs => _infinitePaintballs?.Value ?? false;

		internal static bool EnablePaintballColorChange => _enablePaintballColorChange?.Value ?? true;

		internal static bool PreventPaintballSelfDamage => _preventPaintballSelfDamage?.Value ?? true;

		internal static bool AllowLongPaintballThrows => _allowLongPaintballThrows?.Value ?? false;

		internal static void Initialize()
		{
			if (_category == null)
			{
				_category = MelonPreferences.CreateCategory("MarkerMod", "Marker Mod");
				_keepFootprints = CreateEntry("keepFootprints", defaultValue: true, "Keep Footprints", "Keep paint footprints after puddles dry. When enabled, paint footprints will persist even after the paint puddles have dried up. Default: true");
				_keepPuddles = CreateEntry("keepPuddles", defaultValue: false, "Keep Puddles", "Keep spawned paint puddles as well. When enabled, both paint footprints and paint puddles will persist. Default: false");
				_lifetimeSeconds = CreateEntry("permanentLifetimeSeconds", 86400f, "Lifetime", "Lifetime in seconds for persistent paint. This determines how long paint marks will remain visible. Default: 86400 (24 hours)");
				_infinitePaintballs = CreateEntry("infinitePaintballs", defaultValue: false, "Infinite Paintballs", "Paintballs are not consumed when thrown. When enabled, you can throw paintballs infinitely without them being removed from your inventory. Default: false");
				_enablePaintballColorChange = CreateEntry("enablePaintballColorChange", defaultValue: true, "Enable Paintball Color Change", "Allow changing paintball color by right-clicking. When enabled, you can cycle through colors (Red, Yellow, Green, Blue, Orange, Purple, White, Black) by right-clicking while holding a paintball. Default: true");
				_preventPaintballSelfDamage = CreateEntry("preventPaintballSelfDamage", defaultValue: true, "Prevent Paintball Self Damage", "Stop your own thrown paintball from hitting and damaging you. In game 0.3.0 projectiles can hit their thrower after a short distance; this excludes you from your own paintball hits. Default: true");
				_allowLongPaintballThrows = CreateEntry("allowLongPaintballThrows", defaultValue: false, "Allow Long Paintball Throws (experimental)", "Reduce the navmesh clamp that makes thrown paintballs stop early at an 'invisible wall'. Experimental and server-authoritative (host only) - verify in-game before relying on it. Default: false");
			}
		}

		private static MelonPreferences_Entry<T> CreateEntry<T>(string identifier, T defaultValue, string displayName, string description = null)
		{
			if (_category == null)
			{
				throw new InvalidOperationException("Preference category not initialized.");
			}
			return _category.CreateEntry<T>(identifier, defaultValue, displayName, description, false, false, (ValueValidator)null, (string)null);
		}
	}
}