Decompiled source of BetterSprayPaint v2.0.9

BepInEx/plugins/BetterSprayPaint.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterSprayPaint;
using BetterSprayPaint.NetcodePatcher;
using BetterSprayPaint.Ngo;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: AssemblyCompany("BetterSprayPaint")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.9.0")]
[assembly: AssemblyInformationalVersion("2.0.9+67b14332f2c2ee64549a66c724edce78e6201b2c")]
[assembly: AssemblyProduct("BetterSprayPaint")]
[assembly: AssemblyTitle("BetterSprayPaint")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.9.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
		NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedByMemcpy<float>();
		NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable<float>();
		NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedByMemcpy<bool>();
		NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable<bool>();
		NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedByMemcpy<Color>();
		NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable<Color>();
		NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedINetworkSerializable<NetworkObjectReference>();
		NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable<NetworkObjectReference>();
	}
}
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;
		}
	}
}
internal class QuietLogSource : ILogSource, IDisposable
{
	private ManualLogSource innerLog;

	private static readonly TimeSpan baseRecentLogTimeout = TimeSpan.FromMilliseconds(5000.0);

	private Dictionary<string, (DateTime, int)> recentLogs = new Dictionary<string, (DateTime, int)>();

	private int logsSuppressed;

	private int lastReportedLogsSuppressed;

	private bool suppressLogs = true;

	private const int minimumBeforeSuppressal = 5;

	public string SourceName { get; }

	public event EventHandler<LogEventArgs> LogEvent
	{
		add
		{
			innerLog.LogEvent += value;
		}
		remove
		{
			innerLog.LogEvent -= value;
		}
	}

	public QuietLogSource(string sourceName)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		innerLog = new ManualLogSource(sourceName);
		SourceName = sourceName;
	}

	public void Dispose()
	{
		innerLog.Dispose();
	}

	private object AddStackTrace(object data)
	{
		if (data is string arg)
		{
			StackTrace arg2 = new StackTrace(3, fNeedFileInfo: true);
			return $"{arg}\n{arg2}";
		}
		return data;
	}

	public void Log(LogLevel level, object data, bool addStackTrace = false)
	{
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		if (recentLogs.Count > 30)
		{
			KeyValuePair<string, (DateTime, int)>[] array = recentLogs.Where<KeyValuePair<string, (DateTime, int)>>((KeyValuePair<string, (DateTime, int)> kvp) => DateTime.UtcNow - kvp.Value.Item1 > baseRecentLogTimeout).ToArray();
			foreach (KeyValuePair<string, (DateTime, int)> keyValuePair in array)
			{
				recentLogs.Remove(keyValuePair.Key);
			}
		}
		if (data is string key)
		{
			if (recentLogs.TryGetValue(key, out var value))
			{
				TimeSpan timeSpan = ((value.Item2 < 100) ? baseRecentLogTimeout : (baseRecentLogTimeout * 2.0));
				if (DateTime.UtcNow - value.Item1 > timeSpan)
				{
					recentLogs[key] = (DateTime.UtcNow, (value.Item2 > 5) ? 5 : 0);
				}
				else
				{
					recentLogs[key] = (value.Item1, value.Item2 + 1);
					if (value.Item2 >= 5)
					{
						logsSuppressed++;
						if (suppressLogs)
						{
							return;
						}
					}
				}
			}
			else
			{
				recentLogs.Add(key, (DateTime.UtcNow, 0));
			}
		}
		innerLog.Log(level, addStackTrace ? AddStackTrace(data) : data);
		if (suppressLogs && logsSuppressed > lastReportedLogsSuppressed)
		{
			innerLog.LogInfo((object)$"{logsSuppressed - lastReportedLogsSuppressed} duplicate logs suppressed");
			lastReportedLogsSuppressed = logsSuppressed;
		}
	}

	public void LogInfo(object data)
	{
		Log((LogLevel)16, data);
	}

	public void LogError(object data, bool addStackTrace = true)
	{
		Log((LogLevel)2, data, addStackTrace);
	}

	public void LogWarning(object data, bool addStackTrace = true)
	{
		Log((LogLevel)4, data, addStackTrace);
	}

	public void LogLoud(string data)
	{
		for (int i = 0; i < 25; i++)
		{
			Log((LogLevel)16, $"{data} ({i})");
		}
	}
}
internal interface INetVar : IDisposable
{
	void Synchronize();

	static INetVar[] GetAllNetVars(object self)
	{
		object self2 = self;
		return (from field in self2.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
			where typeof(INetVar).IsAssignableFrom(field.FieldType)
			select (INetVar)field.GetValue(self2)).ToArray();
	}
}
internal class NetVar<T> : INetVar, IDisposable where T : IEquatable<T>
{
	public readonly NetworkVariable<T> networkVariable;

	private bool deferPending = true;

	private T deferredValue;

	private T _localValue;

	private readonly bool isGlued;

	private readonly Action<T>? setGlued;

	private readonly Func<T>? getGlued;

	private readonly Func<T, T>? validate;

	private readonly Func<bool> inControl;

	private readonly Action<T> SetOnServer;

	private readonly OnValueChangedDelegate<T>? onChange;

	private T localValue
	{
		get
		{
			return _localValue;
		}
		set
		{
			if (isGlued)
			{
				setGlued(value);
			}
			_localValue = value;
		}
	}

	public T Value
	{
		get
		{
			Synchronize();
			return localValue;
		}
		set
		{
			if (inControl())
			{
				deferPending = false;
				if (validate != null)
				{
					value = validate(value);
				}
				if (!EqualityComparer<T>.Default.Equals(localValue, value))
				{
					T prevValue = localValue;
					localValue = value;
					SetOnServer(value);
					OnChange(prevValue, value);
				}
			}
		}
	}

	public NetVar(out NetworkVariable<T> networkVariable, Action<T> SetOnServer, Func<bool> inControl, T initialValue = default(T), OnValueChangedDelegate<T>? onChange = null, Action<T>? setGlued = null, Func<T>? getGlued = null, Func<T, T>? validate = null)
	{
		isGlued = setGlued != null && getGlued != null;
		this.setGlued = setGlued;
		this.getGlued = getGlued;
		this.validate = validate;
		this.onChange = onChange;
		this.SetOnServer = SetOnServer;
		this.inControl = inControl;
		this.networkVariable = new NetworkVariable<T>(initialValue, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);
		networkVariable = this.networkVariable;
		_localValue = initialValue;
		localValue = initialValue;
		deferredValue = initialValue;
		NetworkVariable<T> obj = networkVariable;
		obj.OnValueChanged = (OnValueChangedDelegate<T>)(object)Delegate.Combine((Delegate?)(object)obj.OnValueChanged, (Delegate?)(object)(OnValueChangedDelegate<T>)delegate(T prevValue, T currentValue)
		{
			if (!EqualityComparer<T>.Default.Equals(localValue, currentValue))
			{
				Synchronize();
				OnChange(prevValue, currentValue);
			}
		});
	}

	public void ServerSet(T value)
	{
		if (validate != null)
		{
			value = validate(value);
		}
		networkVariable.Value = value;
	}

	public void SetDeferred(T value)
	{
		deferredValue = value;
	}

	private void OnChange(T prevValue, T currentValue)
	{
		if (onChange != null)
		{
			onChange.Invoke(prevValue, currentValue);
		}
	}

	public void UpdateDeferred()
	{
		if (inControl() && deferPending)
		{
			Value = deferredValue;
		}
		deferPending = false;
	}

	public void Synchronize()
	{
		if (!inControl())
		{
			localValue = networkVariable.Value;
			deferPending = false;
		}
		else if (isGlued)
		{
			Value = getGlued();
		}
		else
		{
			Value = localValue;
		}
	}

	public void Dispose()
	{
		((NetworkVariableBase)networkVariable).Dispose();
	}
}
public class SprayPaintItemExt : MonoBehaviour
{
	public SprayPaintItem instance;

	public SprayPaintItemNetExt net;

	public DecalProjector previewDecal;

	private List<Action> cleanupActions = new List<Action>();

	private float previewFadeFactor = 1f;

	private Vector3 previewOriginalScale = Vector3.oneVector;

	public bool ItemActive()
	{
		if (net.HeldByLocalPlayer && net.InActiveSlot)
		{
			return Patches.CanUseItem(((GrabbableObject)instance).playerHeldBy);
		}
		return false;
	}

	public void Awake()
	{
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Expected O, but got Unknown
		instance = ((Component)this).GetComponent<SprayPaintItem>();
		net = instance.NetExt();
		GameObject val = Object.Instantiate<GameObject>(instance.sprayPaintPrefab);
		previewDecal = val.GetComponent<DecalProjector>();
		Object.DontDestroyOnLoad((Object)(object)val);
		previewDecal.material = new Material(net.baseDecalMaterial);
		((Behaviour)previewDecal).enabled = true;
		((Object)val).name = "PreviewDecal";
		val.SetActive(true);
		ActionSubscriptionBuilder actionSubscriptionBuilder = new ActionSubscriptionBuilder(cleanupActions, () => ItemActive());
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintEraseModifier, delegate
		{
			if (SessionData.AllowErasing)
			{
				net.IsErasing = true;
			}
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintErase, delegate
		{
			if (SessionData.AllowErasing)
			{
				net.IsErasing = true;
			}
			((GrabbableObject)instance).UseItemOnClient(true);
		}, delegate
		{
			((GrabbableObject)instance).UseItemOnClient(false);
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintNextColor, delegate
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (SessionData.AllowColorChange)
			{
				int num2 = net.ColorPalette.FindIndex((Color color) => color == net.CurrentColor);
				num2 = net.posmod(++num2, net.ColorPalette.Count);
				((MonoBehaviour)this).StartCoroutine(net.ChangeColorCoroutine(net.ColorPalette[num2]));
			}
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintPreviousColor, delegate
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (SessionData.AllowColorChange)
			{
				int num = net.ColorPalette.FindIndex((Color color) => color == net.CurrentColor);
				num = net.posmod(--num, net.ColorPalette.Count);
				((MonoBehaviour)this).StartCoroutine(net.ChangeColorCoroutine(net.ColorPalette[num]));
			}
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintColor1, delegate
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (SessionData.AllowColorChange)
			{
				int index4 = net.posmod(0, net.ColorPalette.Count);
				((MonoBehaviour)this).StartCoroutine(net.ChangeColorCoroutine(net.ColorPalette[index4]));
			}
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintColor2, delegate
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (SessionData.AllowColorChange)
			{
				int index3 = net.posmod(1, net.ColorPalette.Count);
				((MonoBehaviour)this).StartCoroutine(net.ChangeColorCoroutine(net.ColorPalette[index3]));
			}
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintColor3, delegate
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (SessionData.AllowColorChange)
			{
				int index2 = net.posmod(2, net.ColorPalette.Count);
				((MonoBehaviour)this).StartCoroutine(net.ChangeColorCoroutine(net.ColorPalette[index2]));
			}
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintColor4, delegate
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (SessionData.AllowColorChange)
			{
				int index = net.posmod(3, net.ColorPalette.Count);
				((MonoBehaviour)this).StartCoroutine(net.ChangeColorCoroutine(net.ColorPalette[index]));
			}
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintIncreaseSize, (object _, CallbackContext _) => ((MonoBehaviour)this).StartCoroutine(net.ChangeSizeCoroutine()), delegate(object _, CallbackContext _, Coroutine? coroutine)
		{
			((MonoBehaviour)this).StopCoroutine(coroutine);
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintDecreaseSize, (object _, CallbackContext _) => ((MonoBehaviour)this).StartCoroutine(net.ChangeSizeCoroutine()), delegate(object _, CallbackContext _, Coroutine? coroutine)
		{
			((MonoBehaviour)this).StopCoroutine(coroutine);
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintSize01, delegate
		{
			net.PaintSize = 0.1f;
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintSize1, delegate
		{
			net.PaintSize = 1f;
		});
		actionSubscriptionBuilder.Subscribe(Plugin.inputActions.SprayPaintSize2, delegate
		{
			net.PaintSize = 2f;
		});
	}

	public void Update()
	{
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)previewDecal == (Object)null || (Object)(object)((Component)previewDecal).gameObject == (Object)null || (Object)(object)previewDecal.material == (Object)null)
		{
			return;
		}
		bool flag = false;
		if (ItemActive())
		{
			Vector3 position = ((Component)((GrabbableObject)instance).playerHeldBy.gameplayCamera).transform.position;
			Vector3 forward = ((Component)((GrabbableObject)instance).playerHeldBy.gameplayCamera).transform.forward;
			if (Patches.RaycastCustom(new Ray(position, forward), out var sprayHit, SessionData.Range, net.sprayPaintMask, (QueryTriggerInteraction)2, instance))
			{
				Patches.PositionSprayPaint(instance, ((Component)previewDecal).gameObject, sprayHit, setColor: false);
				previewOriginalScale = ((Component)previewDecal).transform.localScale;
				flag = true;
			}
		}
		Color currentColor = net.CurrentColor;
		float num = (Mathf.Sin(Time.timeSinceLevelLoad * 6f) + 1f) * 0.2f + 0.2f;
		previewFadeFactor = Utils.Lexp(previewFadeFactor, flag ? 1f : 0f, 15f * Time.deltaTime);
		previewDecal.material.color = new Color(Mathf.Lerp(currentColor.r, Math.Min(currentColor.r + 0.35f, 1f), num), Mathf.Lerp(currentColor.g, Math.Min(currentColor.g + 0.35f, 1f), num), Mathf.Lerp(currentColor.b, Math.Min(currentColor.b + 0.35f, 1f), num), Mathf.Clamp(Plugin.SprayPreviewOpacity, 0f, 1f) * previewFadeFactor);
		((Component)previewDecal).transform.localScale = previewOriginalScale * previewFadeFactor;
	}

	public void OnDestroy()
	{
		foreach (Action cleanupAction in cleanupActions)
		{
			cleanupAction();
		}
		Object.Destroy((Object)(object)previewDecal);
	}
}
namespace BetterSprayPaint
{
	[HarmonyPatch]
	internal class Patches
	{
		public static HashSet<string> CompanyCruiserColliderBlacklist = new HashSet<string> { "Meshes/DoorLeftContainer/Door/DoorTrigger", "CollisionTriggers/Cube", "PushTrigger", "Triggers/ItemDropRegion", "Triggers/BackPhysicsRegion", "Triggers/LeftShelfPlacementCollider/bounds", "Triggers/RightShelfPlacementCollider/bounds", "VehicleBounds", "InsideTruckNavBounds" };

		private static MethodInfo physicsRaycast = typeof(Physics).GetMethod("Raycast", new Type[5]
		{
			typeof(Ray),
			typeof(RaycastHit).MakeByRefType(),
			typeof(float),
			typeof(int),
			typeof(QueryTriggerInteraction)
		});

		private static MethodInfo raycastCustom = typeof(Patches).GetMethod("RaycastCustom");

		[HarmonyPrefix]
		[HarmonyPatch(typeof(StartOfRound), "EndOfGame")]
		public static void EndOfGame()
		{
			foreach (GameObject sprayPaintDecal in SprayPaintItem.sprayPaintDecals)
			{
				if ((Object)(object)sprayPaintDecal != (Object)null && !sprayPaintDecal.activeInHierarchy)
				{
					Object.Destroy((Object)(object)sprayPaintDecal);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(SprayPaintItem), "LateUpdate")]
		public static void LateUpdate(SprayPaintItem __instance, ref float ___sprayCanTank, ref float ___sprayCanShakeMeter, ref AudioSource ___sprayAudio, bool ___isSpraying)
		{
			//IL_00da: 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_00a2: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.isWeedKillerSprayBottle)
			{
				return;
			}
			__instance.Ext();
			SprayPaintItemNetExt sprayPaintItemNetExt = __instance.NetExt();
			if ((Object)(object)sprayPaintItemNetExt == (Object)null)
			{
				return;
			}
			if (SessionData.InfiniteTank)
			{
				___sprayCanTank = 1f;
			}
			__instance.maxSprayPaintDecals = Plugin.MaxSprayPaintDecals;
			__instance.sprayIntervalSpeed = 0.01f * sprayPaintItemNetExt.PaintSize;
			if (SessionData.ShakingNotNeeded)
			{
				___sprayCanShakeMeter = 1f;
			}
			___sprayAudio.volume = Plugin.Volume;
			if (sprayPaintItemNetExt.HeldByLocalPlayer && sprayPaintItemNetExt.ShakeMeter.Value != ___sprayCanShakeMeter)
			{
				sprayPaintItemNetExt.UpdateShakeMeterServerRpc(___sprayCanShakeMeter);
			}
			else
			{
				___sprayCanShakeMeter = sprayPaintItemNetExt.ShakeMeter.Value;
			}
			NetworkObjectReference value;
			if (sprayPaintItemNetExt.HeldByLocalPlayer)
			{
				value = sprayPaintItemNetExt.PlayerHeldBy.Value;
				if (((NetworkObjectReference)(ref value)).NetworkObjectId != ((NetworkBehaviour)((GrabbableObject)__instance).playerHeldBy).NetworkObjectId)
				{
					sprayPaintItemNetExt.SetPlayerHeldByServerRpc(new NetworkObjectReference(((NetworkBehaviour)((GrabbableObject)__instance).playerHeldBy).NetworkObject));
					goto IL_00f8;
				}
			}
			value = sprayPaintItemNetExt.PlayerHeldBy.Value;
			NetworkObject val = default(NetworkObject);
			if (((NetworkObjectReference)(ref value)).TryGet(ref val, (NetworkManager)null))
			{
				((GrabbableObject)__instance).playerHeldBy = ((Component)val).GetComponent<PlayerControllerB>();
			}
			goto IL_00f8;
			IL_00f8:
			if (sprayPaintItemNetExt.HeldByLocalPlayer)
			{
				sprayPaintItemNetExt.IsErasing = Plugin.inputActions.SprayPaintEraseModifier.IsPressed() || Plugin.inputActions.SprayPaintErase.IsPressed();
			}
			if (___isSpraying && (___sprayCanTank <= 0f || ___sprayCanShakeMeter <= 0f))
			{
				sprayPaintItemNetExt.UpdateParticles();
				__instance.StopSpraying();
				PlayCanEmptyEffect(__instance, ___sprayCanTank <= 0f);
			}
			if (!((Object)(object)((GrabbableObject)__instance).playerHeldBy != (Object)null) || !Plugin.ShorterShakeAnimation)
			{
				return;
			}
			Animator playerBodyAnimator = ((GrabbableObject)__instance).playerHeldBy.playerBodyAnimator;
			AnimatorClipInfo[] currentAnimatorClipInfo = playerBodyAnimator.GetCurrentAnimatorClipInfo(2);
			for (int i = 0; i < currentAnimatorClipInfo.Length; i++)
			{
				AnimatorClipInfo val2 = currentAnimatorClipInfo[i];
				if (((Object)((AnimatorClipInfo)(ref val2)).clip).name == "ShakeItem")
				{
					AnimatorStateInfo currentAnimatorStateInfo = playerBodyAnimator.GetCurrentAnimatorStateInfo(2);
					if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime > 0.1f)
					{
						playerBodyAnimator.Play("HoldOneHandedItem");
					}
				}
			}
		}

		public static void EraseSprayPaintAtPoint(SprayPaintItem __instance, Vector3 pos)
		{
			//IL_0024: 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)
			foreach (GameObject sprayPaintDecal in SprayPaintItem.sprayPaintDecals)
			{
				if ((Object)(object)sprayPaintDecal != (Object)null && Vector3.Distance(sprayPaintDecal.transform.position, pos) < Mathf.Max(0.15f, 0.5f * __instance.NetExt().PaintSize))
				{
					sprayPaintDecal.SetActive(false);
				}
			}
		}

		public static bool EraseSprayPaintLocal(SprayPaintItem __instance, Vector3 sprayPos, Vector3 sprayRot, out RaycastHit sprayHit)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: 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)
			if (RaycastCustom(new Ray(sprayPos, sprayRot), out sprayHit, SessionData.Range, __instance.NetExt().sprayPaintMask, (QueryTriggerInteraction)2, __instance))
			{
				EraseSprayPaintAtPoint(__instance, ((RaycastHit)(ref sprayHit)).point);
				return true;
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(SprayPaintItem), "TrySpraying")]
		public static bool TrySpraying(SprayPaintItem __instance, ref bool __result, ref RaycastHit ___sprayHit, ref float ___sprayCanShakeMeter)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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_0094: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.isWeedKillerSprayBottle)
			{
				return true;
			}
			SprayPaintItemNetExt sprayPaintItemNetExt = __instance.NetExt();
			Vector3 position = ((Component)GameNetworkManager.Instance.localPlayerController.gameplayCamera).transform.position;
			Vector3 forward = ((Component)GameNetworkManager.Instance.localPlayerController.gameplayCamera).transform.forward;
			sprayPaintItemNetExt.UpdateParticles();
			if (SessionData.AllowErasing && sprayPaintItemNetExt.IsErasing)
			{
				if (EraseSprayPaintLocal(__instance, position, forward, out var sprayHit))
				{
					__result = true;
					sprayPaintItemNetExt.EraseServerRpc(((RaycastHit)(ref sprayHit)).point);
				}
				return false;
			}
			if (AddSprayPaintLocal(__instance, position, forward))
			{
				__result = true;
				sprayPaintItemNetExt.SprayServerRpc(position, forward);
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(SprayPaintItem), "ItemActivate")]
		public static void ItemActivate(SprayPaintItem __instance)
		{
			if (!__instance.isWeedKillerSprayBottle)
			{
				__instance.NetExt().UpdateParticles();
			}
		}

		public static bool RaycastCustom(Ray ray, out RaycastHit sprayHit, float _distance, int layerMask, QueryTriggerInteraction queryTriggerInteraction, SprayPaintItem __instance)
		{
			//IL_003e: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: 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_016f: 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)
			PlayerControllerB playerHeldBy = ((GrabbableObject)__instance).playerHeldBy;
			GameObject val = null;
			if ((Object)(object)playerHeldBy != (Object)null && (Object)(object)((Component)playerHeldBy).gameObject != (Object)null)
			{
				val = ((Component)playerHeldBy).gameObject;
			}
			else
			{
				Plugin.log.LogWarning("Player GameObject is null");
			}
			bool result = false;
			RaycastHit val2 = default(RaycastHit);
			float num = SessionData.Range + 1f;
			int num2 = 1073742336;
			RaycastHit[] array = Physics.RaycastAll(ray, SessionData.Range, layerMask | num2, queryTriggerInteraction);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val3 = array[i];
				int num3 = 1 << ((Component)((RaycastHit)(ref val3)).collider).gameObject.layer;
				if ((Object)(object)val != (Object)null && ((RaycastHit)(ref val3)).transform.IsChildOf(val.transform))
				{
					continue;
				}
				if ((num3 & layerMask) == 0)
				{
					if ((num3 & num2) == 0)
					{
						continue;
					}
					Transform val4 = ((Component)((RaycastHit)(ref val3)).collider).gameObject.transform.GetAncestors().FirstOrDefault((Func<Transform, bool>)((Transform go) => ((Object)go).name.StartsWith("CompanyCruiser")));
					if ((Object)(object)val4 == (Object)null)
					{
						continue;
					}
					string path = ((Component)((RaycastHit)(ref val3)).collider).gameObject.transform.GetPath(val4);
					if (CompanyCruiserColliderBlacklist.Contains(path))
					{
						continue;
					}
				}
				if ((!((RaycastHit)(ref val3)).collider.isTrigger || !((Object)((RaycastHit)(ref val3)).collider).name.Contains("Trigger")) && ((RaycastHit)(ref val3)).distance < num)
				{
					num = ((RaycastHit)(ref val3)).distance;
					val2 = val3;
					result = true;
				}
			}
			sprayHit = val2;
			if (!SessionData.ClientsCanPaintShip)
			{
				bool flag = (Object)(object)((GrabbableObject)__instance).playerHeldBy != (Object)null && ((GrabbableObject)__instance).playerHeldBy.isHostPlayerObject;
				if ((((Object)(object)((RaycastHit)(ref sprayHit)).collider != (Object)null && ((Component)((RaycastHit)(ref sprayHit)).collider).transform.IsChildOf(StartOfRound.Instance.elevatorTransform)) || (Object)(object)RoundManager.Instance.mapPropsContainer == (Object)null) && !flag)
				{
					result = false;
				}
			}
			return result;
		}

		[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(typeof(SprayPaintItem), "AddSprayPaintLocal")]
		public static bool original_AddSprayPaintLocal(object instance, Vector3 sprayPos, Vector3 sprayRot)
		{
			throw new NotImplementedException("stub");
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(SprayPaintItem), "AddSprayPaintLocal")]
		private static IEnumerable<CodeInstruction> transpiler_AddSprayPaintLocal(IEnumerable<CodeInstruction> instructions)
		{
			bool foundMinNextDecalDistance = false;
			bool foundRaycastCall = false;
			bool addedWeedKillerSkip = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (!addedWeedKillerSkip)
				{
					addedWeedKillerSkip = true;
					foreach (CodeInstruction item in _transpiler_AddWeedKillerSkip(instruction, typeof(Patches).GetMethod("original_AddSprayPaintLocal")))
					{
						yield return item;
					}
				}
				else if (!foundMinNextDecalDistance && instruction.opcode == OpCodes.Ldc_R4 && (float)instruction.operand == 0.175f)
				{
					foundMinNextDecalDistance = true;
					yield return new CodeInstruction(OpCodes.Ldc_R4, (object)0.001f);
				}
				else if (!foundRaycastCall && instruction.opcode == OpCodes.Call && instruction.operand == physicsRaycast)
				{
					foundRaycastCall = true;
					yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
					yield return new CodeInstruction(OpCodes.Call, (object)raycastCustom);
				}
				else
				{
					yield return instruction;
				}
			}
		}

		public static float TankCapacity()
		{
			if (SessionData.InfiniteTank)
			{
				return 25f;
			}
			return SessionData.TankCapacity;
		}

		private static IEnumerable<CodeInstruction> _transpiler_AddWeedKillerSkip(CodeInstruction instruction, MethodInfo original)
		{
			Label label = default(Label);
			yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
			yield return new CodeInstruction(OpCodes.Ldfld, (object)typeof(SprayPaintItem).GetField("isWeedKillerSprayBottle"));
			yield return new CodeInstruction(OpCodes.Brfalse_S, (object)label);
			yield return new CodeInstruction(OpCodes.Jmp, (object)original);
			yield return CodeInstructionExtensions.WithLabels(instruction, new Label[1] { label });
		}

		[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(typeof(SprayPaintItem), "LateUpdate")]
		public static void original_LateUpdate(object instance)
		{
			throw new NotImplementedException("stub");
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(SprayPaintItem), "LateUpdate")]
		private static IEnumerable<CodeInstruction> transpiler_LateUpdate(IEnumerable<CodeInstruction> instructions)
		{
			bool foundTankCapacityDivisor = false;
			bool addedWeedKillerSkip = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (!addedWeedKillerSkip)
				{
					addedWeedKillerSkip = true;
					foreach (CodeInstruction item in _transpiler_AddWeedKillerSkip(instruction, typeof(Patches).GetMethod("original_LateUpdate")))
					{
						yield return item;
					}
				}
				else if (!foundTankCapacityDivisor && instruction.opcode == OpCodes.Ldc_R4 && (float)instruction.operand == 25f)
				{
					foundTankCapacityDivisor = true;
					yield return new CodeInstruction(OpCodes.Call, (object)typeof(Patches).GetMethod("TankCapacity"));
				}
				else
				{
					yield return instruction;
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyPostfix]
		public static void Player_Update_Postfix(PlayerControllerB __instance)
		{
			if (__instance.IsLocalPlayer())
			{
				Plugin.UpdateSessionData();
			}
		}

		[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(typeof(PlayerControllerB), "CanUseItem")]
		public static bool CanUseItem(object instance)
		{
			throw new NotImplementedException("stub");
		}

		[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(typeof(SprayPaintItem), "AddSprayPaintLocal")]
		public static bool _AddSprayPaintLocal(object instance, Vector3 sprayPos, Vector3 sprayRot)
		{
			Transpiler(null);
			return false;
			static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				bool foundMinNextDecalDistance = false;
				bool foundRaycastCall = false;
				foreach (CodeInstruction instruction in instructions)
				{
					if (!foundMinNextDecalDistance && instruction.opcode == OpCodes.Ldc_R4 && (float)instruction.operand == 0.175f)
					{
						foundMinNextDecalDistance = true;
						yield return new CodeInstruction(OpCodes.Ldc_R4, (object)0.001f);
					}
					else if (!foundRaycastCall && instruction.opcode == OpCodes.Call && instruction.operand == physicsRaycast)
					{
						foundRaycastCall = true;
						yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
						yield return new CodeInstruction(OpCodes.Call, (object)raycastCustom);
					}
					else
					{
						yield return instruction;
					}
				}
			}
		}

		[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(typeof(SprayPaintItem), "PlayCanEmptyEffect")]
		public static void PlayCanEmptyEffect(object instance, bool isEmpty)
		{
			throw new NotImplementedException("stub");
		}

		public static void PositionSprayPaint(SprayPaintItem instance, GameObject gameObject, RaycastHit sprayHit, bool setColor = true)
		{
			//IL_0008: 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_001f: 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)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			gameObject.transform.forward = -((RaycastHit)(ref sprayHit)).normal;
			gameObject.transform.position = ((RaycastHit)(ref sprayHit)).point;
			if (((Component)((RaycastHit)(ref sprayHit)).collider).gameObject.layer == 11 || ((Component)((RaycastHit)(ref sprayHit)).collider).gameObject.layer == 8 || ((Component)((RaycastHit)(ref sprayHit)).collider).gameObject.layer == 0)
			{
				if (((Component)((RaycastHit)(ref sprayHit)).collider).transform.IsChildOf(StartOfRound.Instance.elevatorTransform) || (Object)(object)RoundManager.Instance.mapPropsContainer == (Object)null)
				{
					gameObject.transform.SetParent(StartOfRound.Instance.elevatorTransform, true);
				}
				else
				{
					gameObject.transform.SetParent(RoundManager.Instance.mapPropsContainer.transform, true);
				}
			}
			DecalProjector component = gameObject.GetComponent<DecalProjector>();
			((Behaviour)component).enabled = true;
			SprayPaintItemNetExt sprayPaintItemNetExt = instance.NetExt();
			component.drawDistance = Plugin.DrawDistance;
			if (setColor)
			{
				component.material = sprayPaintItemNetExt.DecalMaterialForColor(sprayPaintItemNetExt.CurrentColor);
			}
			component.scaleMode = (DecalScaleMode)1;
			gameObject.transform.localScale = new Vector3(1f, 1f, 1f);
			Vector3 lossyScale = gameObject.transform.lossyScale;
			gameObject.transform.localScale = new Vector3(1f / lossyScale.x * sprayPaintItemNetExt.PaintSize, 1f / lossyScale.y * sprayPaintItemNetExt.PaintSize, 1f);
		}

		public static bool AddSprayPaintLocal(SprayPaintItem instance, Vector3 sprayPos, Vector3 sprayRot)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (SprayPaintItem.sprayPaintDecalsIndex - SprayPaintItem.sprayPaintDecals.Count > 1)
			{
				SprayPaintItem.sprayPaintDecals.AddRange((IEnumerable<GameObject>)(object)new GameObject[SprayPaintItem.sprayPaintDecalsIndex - 2 - SprayPaintItem.sprayPaintDecals.Count]);
			}
			bool num = _AddSprayPaintLocal(instance, sprayPos, sprayRot);
			if (num && SprayPaintItem.sprayPaintDecals.Count > SprayPaintItem.sprayPaintDecalsIndex)
			{
				GameObject gameObject = SprayPaintItem.sprayPaintDecals[SprayPaintItem.sprayPaintDecalsIndex];
				RaycastHit value = Traverse.Create((object)instance).Field<RaycastHit>("sprayHit").Value;
				PositionSprayPaint(instance, gameObject, value);
			}
			return num;
		}

		[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(typeof(SprayPaintItem), "ItemInteractLeftRight")]
		public static void original_ItemInteractLeftRight(object instance, bool right)
		{
			throw new NotImplementedException("stub");
		}

		public static float _shakeRestoreAmount()
		{
			return SessionData.ShakeEfficiency;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(SprayPaintItem), "ItemInteractLeftRight")]
		private static IEnumerable<CodeInstruction> transpiler_ItemInteractLeftRight(IEnumerable<CodeInstruction> instructions)
		{
			bool foundShakeRestoreAmount = false;
			bool addedWeedKillerSkip = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (!addedWeedKillerSkip)
				{
					addedWeedKillerSkip = true;
					foreach (CodeInstruction item in _transpiler_AddWeedKillerSkip(instruction, typeof(Patches).GetMethod("original_ItemInteractLeftRight")))
					{
						yield return item;
					}
				}
				else if (!foundShakeRestoreAmount && instruction.opcode == OpCodes.Ldc_R4 && (float)instruction.operand == 0.15f)
				{
					foundShakeRestoreAmount = true;
					yield return new CodeInstruction(OpCodes.Call, (object)typeof(Patches).GetMethod("_shakeRestoreAmount"));
				}
				else
				{
					yield return instruction;
				}
			}
		}
	}
	[BepInPlugin("taffyko.BetterSprayPaint", "BetterSprayPaint", "2.0.9")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private delegate bool ParseConfigValue<T>(string input, out T output);

		public const string modGUID = "taffyko.BetterSprayPaint";

		public const string modName = "BetterSprayPaint";

		public const string modVersion = "2.0.9";

		internal static Harmony harmony;

		internal static QuietLogSource log;

		internal static List<Action> cleanupActions;

		internal static List<Action> sceneChangeActions;

		internal static PluginInputActions inputActions;

		public static bool AllowErasing { get; private set; }

		public static bool AllowColorChange { get; private set; }

		public static bool InfiniteTank { get; private set; }

		public static float TankCapacity { get; private set; }

		public static float ShakeEfficiency { get; private set; }

		public static bool ShakingNotNeeded { get; private set; }

		public static float Volume { get; private set; }

		public static float MaxSize { get; private set; }

		public static float Range { get; private set; }

		public static bool ShorterShakeAnimation { get; private set; }

		public static int MaxSprayPaintDecals { get; private set; }

		public static float DrawDistance { get; private set; }

		public static float SprayPreviewOpacity { get; private set; }

		public static bool ClientsCanPaintShip { get; private set; }

		static Plugin()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			harmony = new Harmony("taffyko.BetterSprayPaint");
			cleanupActions = new List<Action>();
			sceneChangeActions = new List<Action>();
			inputActions = new PluginInputActions();
			log = new QuietLogSource("BetterSprayPaint");
			Logger.Sources.Add((ILogSource)(object)log);
		}

		private void Awake()
		{
			log.LogInfo("Loading taffyko.BetterSprayPaint");
			ConfigInit();
			harmony.PatchAll(Assembly.GetExecutingAssembly());
		}

		private void OnDestroy()
		{
		}

		public static void UpdateSessionData()
		{
			SessionData instance = SessionData.instance;
			if ((Object)(object)instance != (Object)null && ((NetworkBehaviour)instance).IsServer)
			{
				instance.allowErasing.Value = AllowErasing;
				instance.allowColorChange.Value = AllowColorChange;
				instance.infiniteTank.Value = InfiniteTank;
				instance.tankCapacity.Value = TankCapacity;
				instance.shakeEfficiency.Value = ShakeEfficiency;
				instance.shakingNotNeeded.Value = ShakingNotNeeded;
				instance.range.Value = Range;
				instance.maxSize.Value = MaxSize;
				instance.clientsCanPaintShip.Value = ClientsCanPaintShip;
			}
		}

		private void ConfigInit()
		{
			((BaseUnityPlugin)this).Config.Bind<string>("README", "README", "", "All config values are text-based, as a workaround to make it possible for default values to change in future updates.\r\n\r\nSee https://github.com/taffyko/LCNiceChat/issues/3 for more information.\r\n\r\nIf you enter an invalid value, it will change back to \"default\" when the game starts.");
			ConfEntry("General", "AllowErasing", defaultValue: true, "When enabled, players can erase spray paint. (Note: With default controls, erasing is done by holding E and LMB at the same time)", bool.TryParse, hostControlled: true);
			ConfEntry("General", "AllowColorChange", defaultValue: true, "When enabled, players can control the color of their spray paint.", bool.TryParse, hostControlled: true);
			ConfEntry("General", "InfiniteTank", defaultValue: true, "When enabled, the spray can has infinite uses.", bool.TryParse, hostControlled: true);
			ConfEntry("General", "TankCapacity", 30f, "Amount of time (in seconds) that each can may spray for before running out (Has no effect when InfiniteTank is enabled.)", float.TryParse, 30f, hostControlled: true);
			ConfEntry("General", "ShakeEfficiency", 0.3f, "The percentage to restore on the \"shake meter\" each time the can is shaken.", float.TryParse, 0.15f, hostControlled: true);
			ConfEntry("General", "ShakingNotNeeded", defaultValue: false, "When enabled, the can never needs to be shaken.", bool.TryParse, hostControlled: true);
			ConfEntry("General", "MaxSize", 2f, "The maximum size of spray paint that players are allowed to create.", float.TryParse, hostControlled: true);
			ConfEntry("General", "Range", 7f, "The maximum distance that players can spray.", float.TryParse, 7f, hostControlled: true);
			ConfEntry("General", "ClientsCanPaintShip", defaultValue: true, "When disabled, only the host can paint on or within the ship.", bool.TryParse, hostControlled: true);
			ConfEntry("Client-side", "Volume", 0.1f, "Volume of spray paint sound effects.", float.TryParse, 1f);
			ConfEntry("Client-side", "ShorterShakeAnimation", defaultValue: true, "Whether to shorten the can-shaking animation.", bool.TryParse);
			ConfEntry("Client-side", "MaxSprayPaintDecals", 4000, "The maximum amount of spray paint decals that can exist at once. When the limit is reached, spray paint decals will start to disappear, starting with the oldest.", int.TryParse, 1000);
			ConfEntry("Client-side", "DrawDistance", 35f, "The maximum distance from which spray paint decals can be seen (Only applies to new spray paint drawn after the setting was changed, if changed mid-game).", float.TryParse, 20f);
			ConfEntry("Client-side", "SprayPreviewOpacity", 0.5f, "Opacity of the preview highlighting where spray paint will land when sprayed. Set to 0 to disable the preview altogether.", float.TryParse);
		}

		private static bool NoopParse(string input, out string output)
		{
			output = input;
			return true;
		}

		private void ConfEntry<T>(string category, string name, T defaultValue, string description, ParseConfigValue<T> tryParse, bool hostControlled = false)
		{
			ConfEntryInternal(category, name, defaultValue, description, tryParse, hostControlled);
		}

		private void ConfEntry<T>(string category, string name, T defaultValue, string description, ParseConfigValue<T> tryParse, T vanillaValue, bool hostControlled = false)
		{
			ConfEntryInternal(category, name, defaultValue, description, tryParse, hostControlled, ConfEntryToString(vanillaValue));
		}

		private void ConfEntryInternal<T>(string category, string name, T defaultValue, string description, ParseConfigValue<T> tryParse, bool hostControlled = false, string? vanillaValueText = null)
		{
			ParseConfigValue<T> tryParse2 = tryParse;
			T defaultValue2 = defaultValue;
			PropertyInfo property = typeof(Plugin).GetProperty(name);
			string text = "[default: " + ConfEntryToString(defaultValue2) + "]\n" + description;
			text += (hostControlled ? "\n(This setting is overridden by the lobby host)" : "\n(This setting's effect applies to you only)");
			if (vanillaValueText != null)
			{
				text = text + "\n(The original value of this setting in the base-game is " + vanillaValueText + ")";
			}
			ConfigEntry<string> config = ((BaseUnityPlugin)this).Config.Bind<string>(category, name, "default", text);
			if (string.IsNullOrEmpty(config.Value))
			{
				config.Value = "default";
			}
			T output;
			bool flag = tryParse2(config.Value, out output) && config.Value != "default";
			property.SetValue(null, flag ? output : defaultValue2);
			if (!flag)
			{
				config.Value = "default";
			}
			EventHandler loadConfig = delegate
			{
				T output2;
				bool flag2 = tryParse2(config.Value, out output2) && config.Value != "default";
				property.SetValue(null, flag2 ? output2 : defaultValue2);
			};
			config.SettingChanged += loadConfig;
			cleanupActions.Add(delegate
			{
				config.SettingChanged -= loadConfig;
				property.SetValue(null, defaultValue2);
			});
		}

		private string ConfEntryToString(object? value)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (value == null)
			{
				return "null";
			}
			Type type = value.GetType();
			if (type == typeof(float))
			{
				return $"{(float)value:0.0#####}";
			}
			if (type == typeof(Color))
			{
				return "#" + ColorUtility.ToHtmlStringRGBA((Color)value);
			}
			return value.ToString();
		}
	}
	public class PluginInputActions : LcInputActions
	{
		[InputAction("<Keyboard>/e", Name = "Spray Paint Erase Modifier", ActionId = "SprayPaintEraseModifier", GamepadPath = "<Gamepad>/dpad/up")]
		public InputAction? SprayPaintEraseModifier { get; set; }

		[InputAction("", Name = "Spray Paint Erase", ActionId = "SprayPaintErase")]
		public InputAction? SprayPaintErase { get; set; }

		[InputAction("<Keyboard>/t", Name = "Spray Paint Next Color", ActionId = "SprayPaintNextColor")]
		public InputAction? SprayPaintNextColor { get; set; }

		[InputAction("", Name = "Spray Paint Previous Color", ActionId = "SprayPaintPreviousColor")]
		public InputAction? SprayPaintPreviousColor { get; set; }

		[InputAction("", Name = "Spray Paint Color 1", ActionId = "SprayPaintColor1")]
		public InputAction? SprayPaintColor1 { get; set; }

		[InputAction("", Name = "Spray Paint Color 2", ActionId = "SprayPaintColor2")]
		public InputAction? SprayPaintColor2 { get; set; }

		[InputAction("", Name = "Spray Paint Color 3", ActionId = "SprayPaintColor3")]
		public InputAction? SprayPaintColor3 { get; set; }

		[InputAction("", Name = "Spray Paint Color 4", ActionId = "SprayPaintColor4")]
		public InputAction? SprayPaintColor4 { get; set; }

		[InputAction("<Keyboard>/equals", Name = "Spray Paint Increase Size", ActionId = "SprayPaintIncreaseSize")]
		public InputAction? SprayPaintIncreaseSize { get; set; }

		[InputAction("<Keyboard>/minus", Name = "Spray Paint Decrease Size", ActionId = "SprayPaintDecreaseSize")]
		public InputAction? SprayPaintDecreaseSize { get; set; }

		[InputAction("", Name = "Spray Paint Set Size 0.1", ActionId = "SprayPaintSize01")]
		public InputAction? SprayPaintSize01 { get; set; }

		[InputAction("", Name = "Spray Paint Set Size 1.0", ActionId = "SprayPaintSize1")]
		public InputAction? SprayPaintSize1 { get; set; }

		[InputAction("", Name = "Spray Paint Set Size 2.0", ActionId = "SprayPaintSize2")]
		public InputAction? SprayPaintSize2 { get; set; }
	}
	public class ActionSubscriptionBuilder
	{
		public List<Action> cleanupActions;

		public Func<bool> active;

		public ActionSubscriptionBuilder(List<Action> cleanupActions, Func<bool> active)
		{
			this.cleanupActions = cleanupActions;
			this.active = active;
			base..ctor();
		}

		public void Subscribe(InputAction? action, EventHandler<CallbackContext> onStart, EventHandler<CallbackContext>? onStop = null)
		{
			EventHandler<CallbackContext> onStart2 = onStart;
			EventHandler<CallbackContext> onStop2 = onStop;
			Subscribe(action, delegate(object sender, CallbackContext e)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				onStart2(sender, e);
				return null;
			}, (onStop2 == null) ? null : ((Action<object, CallbackContext, object>)delegate(object sender, CallbackContext e, object? ret)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				onStop2(sender, e);
			}));
		}

		public void Subscribe<T>(InputAction? action, Func<object, CallbackContext, T> onStart, Action<object, CallbackContext, T?>? onStop = null)
		{
			Func<object, CallbackContext, T> onStart2 = onStart;
			Action<object, CallbackContext, T?> onStop2 = onStop;
			InputAction action2 = action;
			if (action2 == null)
			{
				Plugin.log.LogWarning("Subscribe called with null InputAction");
				return;
			}
			EventInfo startedEvent = typeof(InputAction).GetEvent("started");
			EventInfo canceledEvent = typeof(InputAction).GetEvent("canceled");
			T ret = default(T);
			bool actionHeld = false;
			Action<CallbackContext> startHandler = delegate(CallbackContext e)
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				if (active())
				{
					actionHeld = true;
					ret = onStart2(this, e);
				}
			};
			Action<CallbackContext> cancelHandler = delegate(CallbackContext e)
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				if (actionHeld && onStop2 != null)
				{
					onStop2(this, e, ret);
					actionHeld = false;
				}
			};
			startedEvent.AddEventHandler(action2, startHandler);
			cleanupActions.Add(delegate
			{
				startedEvent.RemoveEventHandler(action2, startHandler);
			});
			canceledEvent.AddEventHandler(action2, cancelHandler);
			cleanupActions.Add(delegate
			{
				canceledEvent.RemoveEventHandler(action2, cancelHandler);
			});
		}
	}
	public static class Utils
	{
		public static string GetPath(this Transform current, Transform? relativeTo = null)
		{
			if ((Object)(object)current == (Object)(object)relativeTo)
			{
				return "";
			}
			if ((Object)(object)current.parent == (Object)null)
			{
				return "/" + ((Object)current).name;
			}
			string path = current.parent.GetPath(relativeTo);
			if (path == "")
			{
				return ((Object)current).name;
			}
			return path + "/" + ((Object)current).name;
		}

		public static IEnumerable<Transform> GetAncestors(this Transform self, bool includeSelf = true)
		{
			Transform current = self;
			if (!includeSelf)
			{
				current = self.parent;
			}
			while ((Object)(object)current != (Object)null)
			{
				yield return current;
				current = current.parent;
			}
		}

		public static bool IsLocalPlayer(this PlayerControllerB? player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return (Object)(object)player == (Object)(object)StartOfRound.Instance?.localPlayerController;
			}
			return false;
		}

		public static SprayPaintItemNetExt NetExt(this SprayPaintItem instance)
		{
			SprayPaintItemNetExt component = ((Component)instance).GetComponent<SprayPaintItemNetExt>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.log.LogError("SprayPaintItem.Ext() is null");
			}
			return component;
		}

		public static SprayPaintItemExt Ext(this SprayPaintItem instance)
		{
			SprayPaintItemExt sprayPaintItemExt = ((Component)instance).GetComponent<SprayPaintItemExt>();
			if ((Object)(object)sprayPaintItemExt == (Object)null)
			{
				sprayPaintItemExt = ((Component)instance).gameObject.AddComponent<SprayPaintItemExt>();
			}
			return sprayPaintItemExt;
		}

		public static PlayerNetExt? NetExt(this PlayerControllerB? instance)
		{
			PlayerNetExt result = default(PlayerNetExt);
			if ((Object)(object)instance != (Object)null && ((Component)instance).TryGetComponent<PlayerNetExt>(ref result))
			{
				return result;
			}
			return null;
		}

		public static void SyncWithNetworkObject(this NetworkBehaviour networkBehaviour, NetworkObject? networkObject)
		{
			networkObject = networkObject ?? networkBehaviour.NetworkObject;
			if (!networkObject.ChildNetworkBehaviours.Contains(networkBehaviour))
			{
				networkObject.ChildNetworkBehaviours.Add(networkBehaviour);
			}
			networkBehaviour.UpdateNetworkProperties();
		}

		public static float Lexp(float a, float b, float t)
		{
			return a + (b - a) * (1f - Mathf.Exp(0f - t));
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "BetterSprayPaint";

		public const string PLUGIN_NAME = "BetterSprayPaint";

		public const string PLUGIN_VERSION = "2.0.9";
	}
}
namespace BetterSprayPaint.Ngo
{
	public class PlayerNetExt : NetworkBehaviour
	{
		internal NetworkVariable<float> paintSize;

		internal NetVar<float> PaintSize;

		private INetVar[] netVars = Array.Empty<INetVar>();

		public PlayerControllerB instance => ((Component)this).GetComponent<PlayerControllerB>();

		[ServerRpc(RequireOwnership = false)]
		private void SetPaintSizeServerRpc(float value)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					ServerRpcParams val = default(ServerRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(58249432u, val, (RpcDelivery)0);
					((FastBufferWriter)(ref val2)).WriteValueSafe<float>(ref value, default(ForPrimitives));
					((NetworkBehaviour)this).__endSendServerRpc(ref val2, 58249432u, val, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					PaintSize.ServerSet(value);
				}
			}
		}

		private PlayerNetExt()
		{
			PaintSize = new NetVar<float>(out paintSize, SetPaintSizeServerRpc, () => instance.IsLocalPlayer(), 1f, null, null, null, (float value) => Mathf.Clamp(value, 0.1f, SessionData.MaxSize));
			netVars = INetVar.GetAllNetVars(this);
		}

		public override void OnNetworkSpawn()
		{
			((NetworkBehaviour)this).OnNetworkSpawn();
		}

		private void Update()
		{
			INetVar[] array = netVars;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].Synchronize();
			}
		}

		public override void OnNetworkDespawn()
		{
			((NetworkBehaviour)this).OnNetworkDespawn();
			INetVar[] array = netVars;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].Dispose();
			}
		}

		protected override void __initializeVariables()
		{
			if (paintSize == null)
			{
				throw new Exception("PlayerNetExt.paintSize cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)paintSize).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)paintSize, "paintSize");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)paintSize);
			((NetworkBehaviour)this).__initializeVariables();
		}

		[RuntimeInitializeOnLoadMethod]
		internal static void InitializeRPCS_PlayerNetExt()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			NetworkManager.__rpc_func_table.Add(58249432u, new RpcReceiveHandler(__rpc_handler_58249432));
		}

		private static void __rpc_handler_58249432(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_002f: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				float paintSizeServerRpc = default(float);
				((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref paintSizeServerRpc, default(ForPrimitives));
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((PlayerNetExt)(object)target).SetPaintSizeServerRpc(paintSizeServerRpc);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		protected internal override string __getTypeName()
		{
			return "PlayerNetExt";
		}
	}
	internal static class NgoHelper
	{
		internal static List<Action> cleanupActions = new List<Action>();

		internal static GameObject? prefabContainer = null;

		private static List<(Type custom, Type native, Type? excluded)> BehaviourBindings { get; } = new List<(Type, Type, Type)>();


		internal static void RegisterPrefab<T>(GameObject prefab, string name) where T : MonoBehaviour
		{
			GameObject prefab2 = prefab;
			prefab2.AddComponent<T>();
			((Object)prefab2).hideFlags = (HideFlags)61;
			prefab2.transform.SetParent(prefabContainer.transform);
			NetworkObject obj = prefab2.AddComponent<NetworkObject>();
			string s = "taffyko.BetterSprayPaint." + name;
			byte[] value = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(s));
			obj.GlobalObjectIdHash = BitConverter.ToUInt32(value, 0);
			NetworkManager.Singleton.AddNetworkPrefab(prefab2);
			cleanupActions.Add(delegate
			{
				MonoBehaviour[] array = (MonoBehaviour[])(object)Resources.FindObjectsOfTypeAll<T>();
				array = array;
				foreach (MonoBehaviour obj2 in array)
				{
					NetworkManager.Singleton.RemoveNetworkPrefab(prefab2);
					Object.Destroy((Object)(object)((Component)obj2).gameObject);
				}
			});
		}

		internal static void AddScriptToInstances<TCustomBehaviour, TNativeBehaviour>(bool updatePrefabs = false, Type? excluded = null) where TCustomBehaviour : NetworkBehaviour where TNativeBehaviour : NetworkBehaviour
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			TNativeBehaviour[] array = Resources.FindObjectsOfTypeAll<TNativeBehaviour>();
			foreach (TNativeBehaviour val in array)
			{
				if ((excluded != null && ((object)val).GetType().IsInstanceOfType(excluded)) || (Object)(object)((Component)(object)val).gameObject.GetComponent<TCustomBehaviour>() != (Object)null)
				{
					continue;
				}
				Scene scene = ((Component)(object)val).gameObject.scene;
				bool flag = !((Scene)(ref scene)).IsValid();
				if (flag && updatePrefabs)
				{
					NetworkPrefabs prefabs = NetworkManager.Singleton.NetworkConfig.Prefabs;
					NetworkObject networkObject = ((Component)(object)val).gameObject.GetComponent<NetworkObject>();
					NetworkPrefab val2 = prefabs.m_Prefabs.Find((NetworkPrefab p) => p.SourcePrefabGlobalObjectIdHash == networkObject.GlobalObjectIdHash);
					foreach (NetworkPrefabsList networkPrefabsList in prefabs.NetworkPrefabsLists)
					{
						networkPrefabsList.Remove(val2);
					}
					NetworkManager.Singleton.RemoveNetworkPrefab(((Component)(object)val).gameObject);
					if (val2 != null)
					{
						_ = val2.SourcePrefabGlobalObjectIdHash;
						prefabs.NetworkPrefabOverrideLinks.Remove(val2.SourcePrefabGlobalObjectIdHash);
					}
					if (val2 != null)
					{
						_ = val2.TargetPrefabGlobalObjectIdHash;
						prefabs.OverrideToNetworkPrefab.Remove(val2.TargetPrefabGlobalObjectIdHash);
					}
				}
				((NetworkBehaviour)(object)((Component)(object)val).gameObject.AddComponent<TCustomBehaviour>()).SyncWithNetworkObject(((Component)(object)val).gameObject.GetComponent<NetworkObject>());
				if (flag && updatePrefabs)
				{
					NetworkManager.Singleton.AddNetworkPrefab(((Component)(object)val).gameObject);
				}
			}
		}

		internal static void RegisterScriptWithExistingPrefab<TCustomBehaviour, TNativeBehaviour>(Type? excluded = null) where TCustomBehaviour : NetworkBehaviour where TNativeBehaviour : NetworkBehaviour
		{
			Type excluded2 = excluded;
			AddScriptToInstances<TCustomBehaviour, TNativeBehaviour>(updatePrefabs: true, excluded2);
			UnityAction<Scene, LoadSceneMode> handler = delegate
			{
				AddScriptToInstances<TCustomBehaviour, TNativeBehaviour>(updatePrefabs: false, excluded2);
			};
			SceneManager.sceneLoaded += handler;
			cleanupActions.Add(delegate
			{
				SceneManager.sceneLoaded -= handler;
				TNativeBehaviour[] array = Resources.FindObjectsOfTypeAll<TNativeBehaviour>();
				for (int i = 0; i < array.Length; i++)
				{
					Object.Destroy((Object)(object)((Component)(object)array[i]).gameObject.GetComponent<TCustomBehaviour>());
				}
			});
			BindToPreExistingObjectByBehaviourPatch<TCustomBehaviour, TNativeBehaviour>(excluded2);
		}

		private static void RegisterCustomScripts()
		{
			NgoHelper.RegisterPrefab<SessionData>(SessionData.prefab, "SessionData");
			NetworkManager.Singleton.OnServerStarted += SessionData.ServerSpawn;
			cleanupActions.Add(delegate
			{
				NetworkManager.Singleton.OnServerStarted -= SessionData.ServerSpawn;
			});
			NetworkManager.Singleton.OnClientStopped += SessionData.Despawn;
			cleanupActions.Add(delegate
			{
				NetworkManager.Singleton.OnClientStopped -= SessionData.Despawn;
			});
			NgoHelper.RegisterScriptWithExistingPrefab<SprayPaintItemNetExt, SprayPaintItem>((Type?)null);
			NgoHelper.RegisterScriptWithExistingPrefab<PlayerNetExt, PlayerControllerB>((Type?)null);
		}

		public static void BindToPreExistingObjectByBehaviourPatch<TCustomBehaviour, TNativeBehaviour>(Type? excluded = null) where TCustomBehaviour : NetworkBehaviour where TNativeBehaviour : NetworkBehaviour
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			Type typeFromHandle = typeof(TCustomBehaviour);
			Type typeFromHandle2 = typeof(TNativeBehaviour);
			BehaviourBindings.Add((typeFromHandle, typeFromHandle2, excluded));
			MethodInfo methodInfo = null;
			try
			{
				methodInfo = typeFromHandle2.GetMethod("Awake", BindingFlags.Instance);
			}
			catch (Exception)
			{
			}
			if (methodInfo != null)
			{
				MethodBase methodBase = AccessTools.Method(typeFromHandle2, "Awake", (Type[])null, (Type[])null);
				HarmonyMethod val = new HarmonyMethod(typeof(NgoHelper), "BindBehaviourOnAwake", (Type[])null);
				Plugin.harmony.Patch(methodBase, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		internal static void BindBehaviourOnAwake(NetworkBehaviour __instance, MethodBase __originalMethod)
		{
			MethodBase __originalMethod2 = __originalMethod;
			Type type = ((object)__instance).GetType();
			Component val = default(Component);
			foreach (var item in BehaviourBindings.Where<(Type, Type, Type)>(((Type custom, Type native, Type excluded) obj) => (obj.native == __originalMethod2.DeclaringType || type == obj.native) && (obj.excluded == null || !type.IsInstanceOfType(obj.excluded))))
			{
				if (!((Component)__instance).gameObject.TryGetComponent(item.Item1, ref val))
				{
					Component obj2 = ((Component)__instance).gameObject.AddComponent(item.Item1);
					((NetworkBehaviour)(object)((obj2 is NetworkBehaviour) ? obj2 : null)).SyncWithNetworkObject(((Component)__instance).gameObject.GetComponent<NetworkObject>());
				}
			}
		}

		internal static void NetcodeInit()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			if ((Object)(object)prefabContainer != (Object)null)
			{
				throw new Exception("Ran NetcodeInit() more than once");
			}
			prefabContainer = new GameObject();
			prefabContainer.SetActive(false);
			((Object)prefabContainer).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)prefabContainer);
			RegisterCustomScripts();
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			for (int i = 0; i < types.Length; i++)
			{
				MethodInfo[] methods = types[i].GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length != 0)
					{
						methodInfo.Invoke(null, null);
					}
				}
			}
		}

		public static GameObject? FindBuiltinPrefabByScript<T>() where T : MonoBehaviour
		{
			//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)
			GameObject result = null;
			T[] array = Resources.FindObjectsOfTypeAll<T>();
			foreach (T val in array)
			{
				Scene scene = ((Component)(object)val).gameObject.scene;
				if (!((Scene)(ref scene)).IsValid())
				{
					result = ((Component)(object)val).gameObject;
					break;
				}
			}
			return result;
		}

		public static void NetcodeUnload()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			Plugin.log.LogInfo("Unloading NGO for BetterSprayPaint");
			NetworkManager singleton = NetworkManager.Singleton;
			if (singleton != null && ((Behaviour)singleton).isActiveAndEnabled && (Object)(object)prefabContainer != (Object)null)
			{
				foreach (Transform item in prefabContainer.transform)
				{
					Transform val = item;
					NetworkManager.Singleton.RemoveNetworkPrefab(((Component)val).gameObject);
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
				Object.Destroy((Object)(object)prefabContainer);
			}
			foreach (Action cleanupAction in cleanupActions)
			{
				cleanupAction();
			}
			cleanupActions.Clear();
		}
	}
	[HarmonyPatch]
	internal class NetcodeInitPatch
	{
		private static bool loaded;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameNetworkManager), "Start")]
		public static void GameNetworkManagerStart(GameNetworkManager __instance)
		{
			if (!loaded && (Object)(object)NetworkManager.Singleton != (Object)null)
			{
				if ((Object)(object)NgoHelper.prefabContainer == (Object)null)
				{
					NgoHelper.NetcodeInit();
				}
				loaded = true;
			}
		}
	}
	public class SessionData : NetworkBehaviour
	{
		internal static GameObject prefab = new GameObject("SessionData");

		internal static SessionData? instance = null;

		internal NetworkVariable<bool> allowColorChange = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		internal NetworkVariable<bool> allowErasing = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		internal NetworkVariable<bool> infiniteTank = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		internal NetworkVariable<float> tankCapacity = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		internal NetworkVariable<float> shakeEfficiency = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		internal NetworkVariable<bool> shakingNotNeeded = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		internal NetworkVariable<float> range = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		internal NetworkVariable<float> maxSize = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		internal NetworkVariable<bool> clientsCanPaintShip = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		public static bool AllowColorChange => instance?.allowColorChange?.Value ?? Plugin.AllowColorChange;

		public static bool AllowErasing => instance?.allowErasing?.Value ?? Plugin.AllowErasing;

		public static bool InfiniteTank => instance?.infiniteTank?.Value ?? Plugin.InfiniteTank;

		public static float TankCapacity => instance?.tankCapacity?.Value ?? Plugin.TankCapacity;

		public static float ShakeEfficiency => instance?.shakeEfficiency?.Value ?? Plugin.ShakeEfficiency;

		public static bool ShakingNotNeeded => instance?.shakingNotNeeded?.Value ?? Plugin.ShakingNotNeeded;

		public static float Range => instance?.range?.Value ?? Plugin.Range;

		public static float MaxSize => instance?.maxSize?.Value ?? Plugin.MaxSize;

		public static bool ClientsCanPaintShip => instance?.clientsCanPaintShip?.Value ?? Plugin.ClientsCanPaintShip;

		public override void OnNetworkSpawn()
		{
			instance = ((Component)this).GetComponent<SessionData>();
		}

		public override void OnDestroy()
		{
			instance = null;
		}

		internal static void ServerSpawn()
		{
			if (NetworkManager.Singleton.IsServer && (Object)(object)instance == (Object)null)
			{
				Object.Instantiate<GameObject>(prefab).GetComponent<NetworkObject>().Spawn(false);
			}
		}

		internal static void Despawn(bool _)
		{
			SessionData? sessionData = instance;
			Object.Destroy((Object)(object)((sessionData != null) ? ((Component)sessionData).gameObject : null));
		}

		protected override void __initializeVariables()
		{
			if (allowColorChange == null)
			{
				throw new Exception("SessionData.allowColorChange cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)allowColorChange).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)allowColorChange, "allowColorChange");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)allowColorChange);
			if (allowErasing == null)
			{
				throw new Exception("SessionData.allowErasing cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)allowErasing).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)allowErasing, "allowErasing");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)allowErasing);
			if (infiniteTank == null)
			{
				throw new Exception("SessionData.infiniteTank cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)infiniteTank).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)infiniteTank, "infiniteTank");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)infiniteTank);
			if (tankCapacity == null)
			{
				throw new Exception("SessionData.tankCapacity cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)tankCapacity).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)tankCapacity, "tankCapacity");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)tankCapacity);
			if (shakeEfficiency == null)
			{
				throw new Exception("SessionData.shakeEfficiency cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)shakeEfficiency).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)shakeEfficiency, "shakeEfficiency");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)shakeEfficiency);
			if (shakingNotNeeded == null)
			{
				throw new Exception("SessionData.shakingNotNeeded cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)shakingNotNeeded).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)shakingNotNeeded, "shakingNotNeeded");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)shakingNotNeeded);
			if (range == null)
			{
				throw new Exception("SessionData.range cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)range).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)range, "range");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)range);
			if (maxSize == null)
			{
				throw new Exception("SessionData.maxSize cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)maxSize).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)maxSize, "maxSize");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)maxSize);
			if (clientsCanPaintShip == null)
			{
				throw new Exception("SessionData.clientsCanPaintShip cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)clientsCanPaintShip).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)clientsCanPaintShip, "clientsCanPaintShip");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)clientsCanPaintShip);
			((NetworkBehaviour)this).__initializeVariables();
		}

		protected internal override string __getTypeName()
		{
			return "SessionData";
		}
	}
	public class SprayPaintItemNetExt : NetworkBehaviour
	{
		private NetworkVariable<bool> _isErasing = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private bool _localIsErasing;

		public NetworkVariable<float> ShakeMeter = new NetworkVariable<float>(1f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		public NetworkVariable<Color> _currentColor = new NetworkVariable<Color>(default(Color), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private Color _localCurrentColor;

		public NetworkVariable<NetworkObjectReference> PlayerHeldBy = new NetworkVariable<NetworkObjectReference>(default(NetworkObjectReference), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		public int sprayPaintMask;

		public Material? baseParticleMaterial;

		public Material? sprayEraseParticleMaterial;

		public Material? baseDecalMaterial;

		public ParticleSystem? sprayCanColorChangeParticle;

		private List<Action> cleanupActions = new List<Action>();

		public static Dictionary<Color, WeakReference<Material>> AllDecalMaterials = new Dictionary<Color, WeakReference<Material>>();

		public static Dictionary<Color, WeakReference<Material>> AllParticleMaterials = new Dictionary<Color, WeakReference<Material>>();

		public List<Color> ColorPalette = new List<Color>();

		private SprayPaintItem instance => ((Component)this).GetComponent<SprayPaintItem>();

		public bool HeldByLocalPlayer
		{
			get
			{
				if (((GrabbableObject)instance).playerHeldBy.IsLocalPlayer())
				{
					return ((GrabbableObject)instance).playerHeldBy.ItemSlots.Any((GrabbableObject item) => (Object)(object)item == (Object)(object)instance);
				}
				return false;
			}
		}

		public bool InActiveSlot
		{
			get
			{
				if ((Object)(object)((GrabbableObject)instance).playerHeldBy != (Object)null)
				{
					return (Object)(object)((GrabbableObject)instance).playerHeldBy.ItemSlots[((GrabbableObject)instance).playerHeldBy.currentItemSlot] == (Object)(object)instance;
				}
				return false;
			}
		}

		private static SessionData sessionData => SessionData.instance;

		public bool IsErasing
		{
			get
			{
				if (!HeldByLocalPlayer)
				{
					return _isErasing.Value;
				}
				return _localIsErasing;
			}
			set
			{
				if (_localIsErasing != value)
				{
					_localIsErasing = value;
					ToggleErasingServerRpc(value);
				}
			}
		}

		public float PaintSize
		{
			get
			{
				PlayerNetExt playerNetExt = null;
				if ((Object)(object)((GrabbableObject)instance).playerHeldBy != (Object)null)
				{
					playerNetExt = ((GrabbableObject)instance).playerHeldBy.NetExt();
				}
				if ((Object)(object)playerNetExt == (Object)null)
				{
					return 1f;
				}
				return playerNetExt.PaintSize.Value;
			}
			set
			{
				if ((Object)(object)((GrabbableObject)instance).playerHeldBy != (Object)null)
				{
					PlayerNetExt playerNetExt = ((GrabbableObject)instance).playerHeldBy.NetExt();
					if ((Object)(object)playerNetExt != (Object)null)
					{
						playerNetExt.PaintSize.Value = value;
					}
					else
					{
						Plugin.log.LogWarning("Tried to set PaintSize but playerHeldBy.NetExt() is null");
					}
				}
				else
				{
					Plugin.log.LogWarning("Tried to set PaintSize but playerHeldBy is null");
				}
			}
		}

		public Color CurrentColor
		{
			get
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				if (!HeldByLocalPlayer)
				{
					return _currentColor.Value;
				}
				return _localCurrentColor;
			}
			set
			{
				//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)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				if (_localCurrentColor != value)
				{
					_localCurrentColor = value;
					SetCurrentColorServerRpc(value);
				}
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void ToggleErasingServerRpc(bool active)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					ServerRpcParams val = default(ServerRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(2165861534u, val, (RpcDelivery)0);
					((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref active, default(ForPrimitives));
					((NetworkBehaviour)this).__endSendServerRpc(ref val2, 2165861534u, val, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					_isErasing.Value = active;
				}
			}
		}

		public void OnChangeErasing(bool previous, bool current)
		{
			if (!HeldByLocalPlayer)
			{
				UpdateParticles();
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void SetCurrentColorServerRpc(Color color)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					ServerRpcParams val = default(ServerRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(3718705491u, val, (RpcDelivery)0);
					((FastBufferWriter)(ref val2)).WriteValueSafe(ref color);
					((NetworkBehaviour)this).__endSendServerRpc(ref val2, 3718705491u, val, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					_currentColor.Value = color;
				}
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void SetPlayerHeldByServerRpc(NetworkObjectReference playerRef)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					ServerRpcParams val = default(ServerRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(1553169032u, val, (RpcDelivery)0);
					((FastBufferWriter)(ref val2)).WriteValueSafe<NetworkObjectReference>(ref playerRef, default(ForNetworkSerializable));
					((NetworkBehaviour)this).__endSendServerRpc(ref val2, 1553169032u, val, (RpcDelivery)0);
				}
				NetworkObject val3 = default(NetworkObject);
				PlayerControllerB val4 = default(PlayerControllerB);
				if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost) && ((NetworkObjectReference)(ref playerRef)).TryGet(ref val3, (NetworkManager)null) && ((Component)val3).TryGetComponent<PlayerControllerB>(ref val4))
				{
					PlayerHeldBy.Value = playerRef;
				}
			}
		}

		public int posmod(int n, int d)
		{
			return (n % d + d) % d;
		}

		public Material DecalMaterialForColor(Color color)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_004a: 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)
			if (AllDecalMaterials.TryGetValue(color, out WeakReference<Material> value) && value.TryGetTarget(out var target) && (Object)(object)target != (Object)null && target.color == color)
			{
				return target;
			}
			target = new Material(baseDecalMaterial)
			{
				color = color
			};
			AllDecalMaterials[color] = new WeakReference<Material>(target);
			return target;
		}

		public Material ParticleMaterialForColor(Color color)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (AllParticleMaterials.TryGetValue(color, out WeakReference<Material> value) && value.TryGetTarget(out var target))
			{
				return target;
			}
			target = new Material(baseParticleMaterial)
			{
				color = color
			};
			AllParticleMaterials[color] = new WeakReference<Material>(target);
			return target;
		}

		public override void OnNetworkSpawn()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00de: 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_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: 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_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			((NetworkBehaviour)this).OnNetworkSpawn();
			if (!instance.isWeedKillerSprayBottle)
			{
				sprayPaintMask = Traverse.Create((object)instance).Field("sprayPaintMask").GetValue<int>();
				int value = Traverse.Create((object)instance).Field<int>("sprayCanMatsIndex").Value;
				baseParticleMaterial = instance.particleMats[value];
				baseDecalMaterial = instance.sprayCanMats[value];
				if (((NetworkBehaviour)this).IsServer)
				{
					Random random = new Random();
					Material val = instance.sprayCanMats[random.Next(instance.sprayCanMats.Length)];
					CurrentColor = val.color;
				}
				sprayEraseParticleMaterial = new Material(baseParticleMaterial);
				sprayEraseParticleMaterial.color = new Color(0.5f, 0.5f, 0.5f, 1f);
				ColorPalette = instance.sprayCanMats.Select((Material mat) => mat.color).ToList();
				Material[] sprayCanMats = instance.sprayCanMats;
				foreach (Material val2 in sprayCanMats)
				{
					AllDecalMaterials[val2.color] = new WeakReference<Material>(val2);
				}
				sprayCanMats = instance.particleMats;
				foreach (Material val3 in sprayCanMats)
				{
					AllParticleMaterials[val3.color] = new WeakReference<Material>(val3);
				}
				GameObject val4 = Object.Instantiate<GameObject>(((Component)instance.sprayCanNeedsShakingParticle).gameObject);
				((Object)val4).name = "ColorChangeParticle";
				sprayCanColorChangeParticle = val4.GetComponent<ParticleSystem>();
				((Component)sprayCanColorChangeParticle).transform.SetParent(((Component)instance).transform, false);
				MainModule main = sprayCanColorChangeParticle.main;
				((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)0;
				((MainModule)(ref main)).startSpeedMultiplier = 2f;
				((MainModule)(ref main)).startLifetimeMultiplier = 0.1f;
				EmissionModule emission = sprayCanColorChangeParticle.emission;
				((EmissionModule)(ref emission)).rateOverTimeMultiplier = 100f;
				ShapeModule shape = sprayCanColorChangeParticle.shape;
				((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0;
				NetworkVariable<bool> isErasing = _isErasing;
				isErasing.OnValueChanged = (OnValueChangedDelegate<bool>)(object)Delegate.Combine((Delegate?)(object)isErasing.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<bool>(OnChangeErasing));
			}
		}

		public IEnumerator ChangeColorCoroutine(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)
			CurrentColor = color;
			UpdateParticles();
			if (Traverse.Create((object)instance).Field("sprayCanTank").GetValue<float>() > 0f)
			{
				sprayCanColorChangeParticle.Play();
				yield return (object)new WaitForSeconds(0.1f);
				sprayCanColorChangeParticle.Stop();
			}
		}

		public IEnumerator ChangeSizeCoroutine()
		{
			bool increase = Plugin.inputActions.SprayPaintIncreaseSize.IsPressed();
			bool decrease = Plugin.inputActions.SprayPaintDecreaseSize.IsPressed();
			PaintSize += (increase ? 0.1f : (-0.1f));
			yield return (object)new WaitForSeconds(0.1f);
			while (HeldByLocalPlayer && (increase || decrease))
			{
				increase = Plugin.inputActions.SprayPaintIncreaseSize.IsPressed();
				decrease = Plugin.inputActions.SprayPaintDecreaseSize.IsPressed();
				PaintSize += (increase ? 0.1f : (-0.1f));
				yield return (object)new WaitForSeconds(0.025f);
			}
		}

		public void UpdateParticles()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			ShapeModule shape = instance.sprayParticle.shape;
			MainModule main = instance.sprayParticle.main;
			float num = Mathf.Min(1.5f, PaintSize);
			((MainModule)(ref main)).startSizeMultiplier = 0.5f * num;
			((ShapeModule)(ref shape)).scale = new Vector3(num, num, num);
			Material material = ParticleMaterialForColor(CurrentColor);
			((Renderer)((Component)sprayCanColorChangeParticle).GetComponent<ParticleSystemRenderer>()).material = material;
			if (SessionData.AllowErasing && IsErasing)
			{
				Material material2 = sprayEraseParticleMaterial;
				((Renderer)((Component)instance.sprayCanNeedsShakingParticle).GetComponent<ParticleSystemRenderer>()).material = material2;
				((Renderer)((Component)instance.sprayParticle).GetComponent<ParticleSystemRenderer>()).material = material2;
				((ShapeModule)(ref shape)).angle = 5f;
				((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(50f);
				((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.1f);
			}
			else
			{
				((Renderer)((Component)instance.sprayCanNeedsShakingParticle).GetComponent<ParticleSystemRenderer>()).material = material;
				((Renderer)((Component)instance.sprayParticle).GetComponent<ParticleSystemRenderer>()).material = material;
				((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(100f);
				((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.05f);
				((ShapeModule)(ref shape)).angle = 0f;
			}
		}

		public override void OnNetworkDespawn()
		{
			((NetworkBehaviour)this).OnNetworkDespawn();
			if (instance.isWeedKillerSprayBottle)
			{
				return;
			}
			NetworkVariable<bool> isErasing = _isErasing;
			isErasing.OnValueChanged = (OnValueChangedDelegate<bool>)(object)Delegate.Remove((Delegate?)(object)isErasing.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<bool>(OnChangeErasing));
			foreach (Action cleanupAction in cleanupActions)
			{
				cleanupAction();
			}
		}

		public void Update()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if (!instance.isWeedKillerSprayBottle)
			{
				if (HeldByLocalPlayer && InActiveSlot)
				{
					UpdateTooltips();
				}
				if (!HeldByLocalPlayer && _localCurrentColor != _currentColor.Value)
				{
					_localCurrentColor = _currentColor.Value;
				}
				if (!HeldByLocalPlayer && (Object)(object)((GrabbableObject)instance).playerHeldBy != (Object)null)
				{
					UpdateParticles();
				}
			}
		}

		public void UpdateTooltips()
		{
			if (HUDManager.Instance.controlTipLines.Length >= 4)
			{
				((TMP_Text)HUDManager.Instance.controlTipLines[3]).text = $"Size : {PaintSize:0.0}";
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void UpdateShakeMeterServerRpc(float shakeMeter)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					ServerRpcParams val = default(ServerRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(1150776642u, val, (RpcDelivery)0);
					((FastBufferWriter)(ref val2)).WriteValueSafe<float>(ref shakeMeter, default(ForPrimitives));
					((NetworkBehaviour)this).__endSendServerRpc(ref val2, 1150776642u, val, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ShakeMeter.Value = shakeMeter;
				}
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void EraseServerRpc(Vector3 sprayPos, ServerRpcParams rpc = default(ServerRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(1724506213u, rpc, (RpcDelivery)0);
					((FastBufferWriter)(ref val)).WriteValueSafe(ref sprayPos);
					((NetworkBehaviour)this).__endSendServerRpc(ref val, 1724506213u, rpc, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost) && SessionData.AllowErasing)
				{
					EraseClientRpc(sprayPos);
				}
			}
		}

		[ClientRpc]
		public void EraseClientRpc(Vector3 sprayPos)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val = default(ClientRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(641093140u, val, (RpcDelivery)0);
					((FastBufferWriter)(ref val2)).WriteValueSafe(ref sprayPos);
					((NetworkBehaviour)this).__endSendClientRpc(ref val2, 641093140u, val, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost) && SessionData.AllowErasing && !HeldByLocalPlayer)
				{
					Patches.EraseSprayPaintAtPoint(instance,