Decompiled source of balrond flower painter v0.1.0

plugins/BalrondFlowerPainter.dll

Decompiled 16 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using FlowerPainter.Components;
using FlowerPainter.Data;
using FlowerPainter.Managers;
using FlowerPainter.Runtime;
using FlowerPainter.Utils;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace FlowerPainter
{
	[BepInPlugin("balrond.astafaraios.BalrondFlowerPainter", "Balrond Flower Painter", "0.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "balrond.astafaraios.BalrondFlowerPainter";

		public const string ModName = "Balrond Flower Painter";

		public const string ModVersion = "0.1.0";

		internal static Plugin Instance;

		internal static Harmony Harmony;

		internal static ConfigEntry<float> DefaultBrushRadius;

		internal static ConfigEntry<float> DefaultDensityMultiplier;

		private void Awake()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			Instance = this;
			DefaultBrushRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Painting", "DefaultBrushRadius", 4f, "Default FlowerPainter brush radius in metres. Ctrl + mouse wheel changes it at runtime (0.5-20 m). Larger radius automatically paints proportionally more instances.");
			DefaultDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Painting", "DefaultBrushDensity", 2f, "Default painted clutter density multiplier. 1.0 follows the ClutterSystem density basis; values above 1 are denser. Shift + mouse wheel changes it at runtime (0.25-8x).");
			Harmony = new Harmony("balrond.astafaraios.BalrondFlowerPainter");
			Harmony.PatchAll();
			((Component)this).gameObject.AddComponent<FlowerPaintSystem>();
			Debug.Log((object)"Balrond Flower Painter 0.1.0 loaded");
		}

		private void OnDestroy()
		{
			if (Harmony != null)
			{
				Harmony.UnpatchSelf();
			}
		}
	}
}
namespace FlowerPainter.Utils
{
	public static class DisplayNameUtils
	{
		public static string FromPrefabName(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return "Unknown";
			}
			string value = prefabName;
			value = RemoveSuffix(value, "_bal");
			value = value.Replace("_", " ");
			value = SplitCamelCaseAndDigits(value);
			value = NormalizeSpaces(value);
			return ToTitleLike(value);
		}

		private static string RemoveSuffix(string value, string suffix)
		{
			if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(suffix))
			{
				return value;
			}
			if (value.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
			{
				return value.Substring(0, value.Length - suffix.Length);
			}
			return value;
		}

		private static string SplitCamelCaseAndDigits(string value)
		{
			StringBuilder stringBuilder = new StringBuilder(value.Length + 8);
			for (int i = 0; i < value.Length; i++)
			{
				char c = value[i];
				char c2 = ((i > 0) ? value[i - 1] : '\0');
				char c3 = ((i < value.Length - 1) ? value[i + 1] : '\0');
				if (i > 0 && ((char.IsLower(c2) && char.IsUpper(c)) || (char.IsLetter(c2) && char.IsDigit(c)) || (char.IsDigit(c2) && char.IsLetter(c)) || (char.IsUpper(c2) && char.IsUpper(c) && char.IsLower(c3))))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(c);
			}
			return stringBuilder.ToString();
		}

		private static string NormalizeSpaces(string value)
		{
			StringBuilder stringBuilder = new StringBuilder(value.Length);
			bool flag = false;
			foreach (char c in value)
			{
				if (char.IsWhiteSpace(c))
				{
					if (!flag)
					{
						stringBuilder.Append(' ');
						flag = true;
					}
				}
				else
				{
					stringBuilder.Append(c);
					flag = false;
				}
			}
			return stringBuilder.ToString().Trim();
		}

		private static string ToTitleLike(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return value;
			}
			StringBuilder stringBuilder = new StringBuilder(value.Length);
			bool flag = true;
			foreach (char c in value)
			{
				if (c == ' ')
				{
					stringBuilder.Append(c);
					flag = true;
				}
				else if (flag)
				{
					stringBuilder.Append(char.ToUpperInvariant(c));
					flag = false;
				}
				else
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}
	}
	public static class PrefabPreviewRenderer
	{
		private const int PreviewLayer = 31;

		public static Sprite CreatePreviewSprite(DiscoveredClutter entry, int size = 128)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = CreatePreviewTexture(entry, size);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}

		public static Sprite CreatePreviewSprite(GameObject sourcePrefab, int size = 128)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = CreatePreviewTexture(sourcePrefab, size);
			if (!IsUsablePreview(val))
			{
				DestroyTexture(val);
				return null;
			}
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}

		public static Texture2D CreatePreviewTexture(DiscoveredClutter entry, int size = 128)
		{
			if (entry == null || (Object)(object)entry.Prefab == (Object)null)
			{
				return null;
			}
			InstanceRenderer[] componentsInChildren = entry.Prefab.GetComponentsInChildren<InstanceRenderer>(true);
			if (componentsInChildren != null && componentsInChildren.Length != 0)
			{
				Texture2D val = RenderInstancedDefinition(componentsInChildren, RepresentativeScale(entry), size);
				if (IsUsablePreview(val))
				{
					return val;
				}
				DestroyTexture(val);
			}
			Texture2D val2 = CreatePreviewTexture(entry.Prefab, size);
			if (IsUsablePreview(val2))
			{
				return val2;
			}
			DestroyTexture(val2);
			return null;
		}

		public static Texture2D CreatePreviewTexture(GameObject sourcePrefab, int size = 128)
		{
			if ((Object)(object)sourcePrefab == (Object)null)
			{
				return null;
			}
			GameObject val = null;
			GameObject val2 = null;
			try
			{
				val = CreatePreviewRoot();
				val2 = Object.Instantiate<GameObject>(sourcePrefab, val.transform);
				((Object)val2).hideFlags = (HideFlags)61;
				Behaviour[] componentsInChildren = val2.GetComponentsInChildren<Behaviour>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					if ((Object)(object)componentsInChildren[i] != (Object)null)
					{
						componentsInChildren[i].enabled = false;
					}
				}
				SetPreviewHierarchyActive(val2.transform);
				SetLayerRecursively(val2, 31);
				Renderer[] componentsInChildren2 = val2.GetComponentsInChildren<Renderer>(true);
				if (componentsInChildren2 == null || componentsInChildren2.Length == 0)
				{
					return null;
				}
				for (int j = 0; j < componentsInChildren2.Length; j++)
				{
					if ((Object)(object)componentsInChildren2[j] != (Object)null)
					{
						componentsInChildren2[j].enabled = true;
					}
				}
				return RenderRoot(val, componentsInChildren2, size);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("FlowerPainter standard icon preview failed for '" + ((Object)sourcePrefab).name + "': " + ex.Message));
				return null;
			}
			finally
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
		}

		private static Texture2D RenderInstancedDefinition(InstanceRenderer[] sources, float scaleMultiplier, int size)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = null;
			try
			{
				val = CreatePreviewRoot();
				List<Renderer> list = new List<Renderer>();
				for (int i = 0; i < sources.Length; i++)
				{
					InstanceRenderer val2 = sources[i];
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.m_mesh == (Object)null) && !((Object)(object)val2.m_material == (Object)null))
					{
						GameObject val3 = new GameObject("FP_InstancedPreview_" + i);
						((Object)val3).hideFlags = (HideFlags)61;
						val3.layer = 31;
						val3.transform.SetParent(val.transform, false);
						val3.transform.localPosition = Vector3.zero;
						val3.transform.localRotation = Quaternion.identity;
						val3.transform.localScale = val2.m_scale * scaleMultiplier;
						MeshFilter val4 = val3.AddComponent<MeshFilter>();
						val4.sharedMesh = val2.m_mesh;
						MeshRenderer val5 = val3.AddComponent<MeshRenderer>();
						((Renderer)val5).sharedMaterial = val2.m_material;
						((Renderer)val5).shadowCastingMode = val2.m_shadowCasting;
						((Renderer)val5).receiveShadows = true;
						list.Add((Renderer)(object)val5);
					}
				}
				if (list.Count == 0)
				{
					return null;
				}
				return RenderRoot(val, list.ToArray(), size);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("FlowerPainter InstanceRenderer icon preview failed: " + ex.Message));
				return null;
			}
			finally
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
		}

		private static GameObject CreatePreviewRoot()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("FP_PreviewRoot");
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		private static Texture2D RenderRoot(GameObject root, Renderer[] renderers, int size)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_014a: 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_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: 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_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Expected O, but got Unknown
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Expected O, but got Unknown
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			Camera val = null;
			RenderTexture val2 = null;
			RenderTexture active = RenderTexture.active;
			try
			{
				Bounds combinedBounds = GetCombinedBounds(renderers);
				val = new GameObject("FP_PreviewCamera").AddComponent<Camera>();
				((Object)((Component)val).gameObject).hideFlags = (HideFlags)61;
				((Component)val).transform.SetParent(root.transform, false);
				val.clearFlags = (CameraClearFlags)2;
				val.backgroundColor = new Color(0f, 0f, 0f, 0f);
				val.nearClipPlane = 0.01f;
				val.farClipPlane = 1000f;
				val.cullingMask = int.MinValue;
				val.allowHDR = false;
				val.allowMSAA = false;
				CreateLight(root.transform, new Vector3(35f, -35f, 0f), 1.05f);
				CreateLight(root.transform, new Vector3(340f, 35f, 0f), 0.65f);
				Vector3 center = ((Bounds)(ref combinedBounds)).center;
				float num = Mathf.Max(new float[3]
				{
					((Bounds)(ref combinedBounds)).extents.x,
					((Bounds)(ref combinedBounds)).extents.y,
					((Bounds)(ref combinedBounds)).extents.z
				});
				num = Mathf.Max(num, 0.05f);
				Vector3 val3 = new Vector3(-0.9f, 0.55f, -0.9f);
				Vector3 normalized = ((Vector3)(ref val3)).normalized;
				float num2 = val.fieldOfView * ((float)Math.PI / 180f);
				float num3 = Mathf.Max(num * 2.8f, num / Mathf.Tan(num2 * 0.5f) * 1.25f);
				((Component)val).transform.position = center - normalized * num3;
				((Component)val).transform.LookAt(center);
				val2 = new RenderTexture(size, size, 24, (RenderTextureFormat)0);
				((Object)val2).hideFlags = (HideFlags)61;
				val.targetTexture = val2;
				RenderTexture.active = val2;
				val.Render();
				Texture2D val4 = new Texture2D(size, size, (TextureFormat)5, false, false);
				val4.ReadPixels(new Rect(0f, 0f, (float)size, (float)size), 0, 0);
				val4.Apply(false, false);
				return val4;
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					val.targetTexture = null;
				}
				if ((Object)(object)val2 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
				if ((Object)(object)val != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)((Component)val).gameObject);
				}
			}
		}

		private static float RepresentativeScale(DiscoveredClutter entry)
		{
			float num = entry.ScaleMin;
			float num2 = entry.ScaleMax;
			if (num <= 0f && num2 <= 0f)
			{
				return 1f;
			}
			if (num2 <= 0f)
			{
				num2 = num;
			}
			if (num <= 0f)
			{
				num = num2;
			}
			if (num2 < num)
			{
				float num3 = num;
				num = num2;
				num2 = num3;
			}
			return (num + num2) * 0.5f;
		}

		private static Light CreateLight(Transform parent, Vector3 euler, float intensity)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0029: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("FP_PreviewLight");
			((Object)val).hideFlags = (HideFlags)61;
			val.transform.SetParent(parent, false);
			val.transform.rotation = Quaternion.Euler(euler);
			Light val2 = val.AddComponent<Light>();
			val2.type = (LightType)1;
			val2.color = Color.white;
			val2.intensity = intensity;
			val2.shadows = (LightShadows)0;
			return val2;
		}

		private static Bounds GetCombinedBounds(Renderer[] renderers)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			Bounds bounds = default(Bounds);
			((Bounds)(ref bounds))..ctor(Vector3.zero, Vector3.one * 0.1f);
			foreach (Renderer val in renderers)
			{
				if (!((Object)(object)val == (Object)null))
				{
					if (!flag)
					{
						bounds = val.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(val.bounds);
					}
				}
			}
			return bounds;
		}

		private static void SetPreviewHierarchyActive(Transform root)
		{
			if (!((Object)(object)root == (Object)null))
			{
				((Component)root).gameObject.SetActive(true);
				for (int i = 0; i < root.childCount; i++)
				{
					SetPreviewHierarchyActive(root.GetChild(i));
				}
			}
		}

		private static void SetLayerRecursively(GameObject go, int layer)
		{
			if (!((Object)(object)go == (Object)null))
			{
				go.layer = layer;
				for (int i = 0; i < go.transform.childCount; i++)
				{
					SetLayerRecursively(((Component)go.transform.GetChild(i)).gameObject, layer);
				}
			}
		}

		private static bool IsUsablePreview(Texture2D texture)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)texture == (Object)null)
			{
				return false;
			}
			try
			{
				Color32[] pixels = texture.GetPixels32();
				if (pixels == null || pixels.Length == 0)
				{
					return false;
				}
				int num = 0;
				int num2 = Mathf.Max(12, pixels.Length / 1024);
				foreach (Color32 val in pixels)
				{
					if (val.a > 8)
					{
						num++;
						if (num >= num2)
						{
							return true;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("FlowerPainter icon visibility check failed: " + ex.Message));
			}
			return false;
		}

		private static void DestroyTexture(Texture2D texture)
		{
			if ((Object)(object)texture != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)texture);
			}
		}
	}
	public static class ReflectionUtils
	{
		private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		public static object GetFieldValue(object target, string name)
		{
			if (target == null || string.IsNullOrEmpty(name))
			{
				return null;
			}
			FieldInfo field = target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			return (field != null) ? field.GetValue(target) : null;
		}

		public static T GetFieldValue<T>(object target, string name, T fallback)
		{
			object fieldValue = GetFieldValue(target, name);
			return (fieldValue is T) ? ((T)fieldValue) : fallback;
		}

		public static IEnumerable EnumerateFieldCandidates(object target, params string[] names)
		{
			if (target == null)
			{
				yield break;
			}
			Type type = target.GetType();
			int i = 0;
			while (i < names.Length)
			{
				FieldInfo field = type.GetField(names[i], BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(field == null) && field.GetValue(target) is IEnumerable enumerable)
				{
					yield return enumerable;
				}
				int num = i + 1;
				i = num;
			}
		}

		public static MethodInfo FindMethod(Type type, string name, int parameterCount)
		{
			MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!(methodInfo.Name != name) && methodInfo.GetParameters().Length == parameterCount)
				{
					return methodInfo;
				}
			}
			return null;
		}

		public static string SafeName(string raw)
		{
			if (string.IsNullOrEmpty(raw))
			{
				return "Unnamed";
			}
			char[] array = raw.ToCharArray();
			for (int i = 0; i < array.Length; i++)
			{
				if (!char.IsLetterOrDigit(array[i]) && array[i] != '_')
				{
					array[i] = '_';
				}
			}
			return new string(array);
		}

		public static bool LooksLikeVegetationName(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return false;
			}
			string text = prefabName.ToLowerInvariant();
			string[] array = new string[14]
			{
				"grass", "flower", "fern", "reed", "heath", "heather", "bush", "shrub", "plant", "herb",
				"weed", "thistle", "mush", "sapling"
			};
			for (int i = 0; i < array.Length; i++)
			{
				if (text.Contains(array[i]))
				{
					return true;
				}
			}
			return false;
		}
	}
	public static class TextureMaker
	{
		public static Sprite CreateBrushIcon(string text, int seed)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0039: 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_00a7: 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_00da: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(64, 64, (TextureFormat)5, false);
			((Texture)val).filterMode = (FilterMode)0;
			Random random = new Random(seed);
			Color val2 = Color.HSVToRGB((float)random.NextDouble(), 0.55f, 0.9f);
			Color black = Color.black;
			Color white = Color.white;
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					bool flag = j < 4 || i < 4 || j > 59 || i > 59;
					val.SetPixel(j, i, flag ? black : val2);
				}
			}
			DrawBlockLetter(val, MakeTag(text), white);
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f);
		}

		public static Sprite CreateFlowerGlyphIcon(int size = 64)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			size = Mathf.Max(32, size);
			Texture2D val = new Texture2D(size, size, (TextureFormat)5, false);
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0f, 0f, 0f, 0f);
			Color color = default(Color);
			((Color)(ref color))..ctor(0.95f, 0.95f, 0.95f, 1f);
			Color color2 = default(Color);
			((Color)(ref color2))..ctor(1f, 0.72f, 0.12f, 1f);
			Color color3 = default(Color);
			((Color)(ref color3))..ctor(0.28f, 0.72f, 0.28f, 1f);
			Color[] array = (Color[])(object)new Color[size * size];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = val2;
			}
			val.SetPixels(array);
			float num = (float)size * 0.5f;
			float num2 = (float)size * 0.6f;
			float num3 = (float)size * 0.14f;
			float radius = (float)size * 0.115f;
			for (int j = 0; j < 6; j++)
			{
				float num4 = (float)j * (float)Math.PI * 2f / 6f;
				DrawDisc(val, num + Mathf.Cos(num4) * num3, num2 + Mathf.Sin(num4) * num3, radius, color);
			}
			DrawDisc(val, num, num2, (float)size * 0.105f, color2);
			DrawThickLine(val, num, num2 - (float)size * 0.1f, num, (float)size * 0.17f, Mathf.Max(2f, (float)size * 0.045f), color3);
			DrawLeaf(val, num - (float)size * 0.03f, (float)size * 0.34f, -1f, color3);
			DrawLeaf(val, num + (float)size * 0.03f, (float)size * 0.27f, 1f, color3);
			val.Apply(false, false);
			return Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), (float)size);
		}

		private static void DrawDisc(Texture2D texture, float cx, float cy, float radius, Color color)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Max(0, Mathf.FloorToInt(cx - radius));
			int num2 = Mathf.Min(((Texture)texture).width - 1, Mathf.CeilToInt(cx + radius));
			int num3 = Mathf.Max(0, Mathf.FloorToInt(cy - radius));
			int num4 = Mathf.Min(((Texture)texture).height - 1, Mathf.CeilToInt(cy + radius));
			float num5 = radius * radius;
			for (int i = num3; i <= num4; i++)
			{
				for (int j = num; j <= num2; j++)
				{
					float num6 = (float)j - cx;
					float num7 = (float)i - cy;
					if (num6 * num6 + num7 * num7 <= num5)
					{
						texture.SetPixel(j, i, color);
					}
				}
			}
		}

		private static void DrawThickLine(Texture2D texture, float x0, float y0, float x1, float y1, float width, Color color)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Max(1, Mathf.CeilToInt(Vector2.Distance(new Vector2(x0, y0), new Vector2(x1, y1))));
			for (int i = 0; i <= num; i++)
			{
				float num2 = (float)i / (float)num;
				DrawDisc(texture, Mathf.Lerp(x0, x1, num2), Mathf.Lerp(y0, y1, num2), width * 0.5f, color);
			}
		}

		private static void DrawLeaf(Texture2D texture, float x, float y, float direction, Color color)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)((Texture)texture).width * 0.15f;
			float width = (float)((Texture)texture).width * 0.065f;
			float x2 = x + direction * num;
			float y2 = y + num * 0.45f;
			DrawThickLine(texture, x, y, x2, y2, width, color);
		}

		private static string MakeTag(string source)
		{
			if (string.IsNullOrEmpty(source))
			{
				return "FP";
			}
			string[] array = source.Replace("_", " ").Replace("-", " ").Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 1)
			{
				string text = array[0];
				return (text.Length >= 2) ? text.Substring(0, 2).ToUpperInvariant() : text.ToUpperInvariant();
			}
			return (array[0][0].ToString() + array[1][0]).ToUpperInvariant();
		}

		private static void DrawBlockLetter(Texture2D texture, string tag, Color color)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			int num = 14;
			int y = 16;
			int num2 = 14;
			for (int i = 0; i < tag.Length && i < 2; i++)
			{
				DrawGlyph(texture, tag[i], num + i * num2, y, color);
			}
		}

		private static void DrawGlyph(Texture2D texture, char c, int x, int y, Color color)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			bool[,] array = GlyphFor(c);
			int length = array.GetLength(0);
			int length2 = array.GetLength(1);
			for (int i = 0; i < length; i++)
			{
				for (int j = 0; j < length2; j++)
				{
					if (!array[i, j])
					{
						continue;
					}
					for (int k = 0; k < 3; k++)
					{
						for (int l = 0; l < 3; l++)
						{
							texture.SetPixel(x + i * 3 + k, y + (length2 - 1 - j) * 3 + l, color);
						}
					}
				}
			}
		}

		private static bool[,] GlyphFor(char c)
		{
			string[] array = char.ToUpperInvariant(c) switch
			{
				'A' => new string[5] { "01110", "10001", "11111", "10001", "10001" }, 
				'B' => new string[5] { "11110", "10001", "11110", "10001", "11110" }, 
				'C' => new string[5] { "01111", "10000", "10000", "10000", "01111" }, 
				'D' => new string[5] { "11110", "10001", "10001", "10001", "11110" }, 
				'E' => new string[5] { "11111", "10000", "11110", "10000", "11111" }, 
				'F' => new string[5] { "11111", "10000", "11110", "10000", "10000" }, 
				'G' => new string[5] { "01111", "10000", "10011", "10001", "01111" }, 
				'H' => new string[5] { "10001", "10001", "11111", "10001", "10001" }, 
				'I' => new string[5] { "11111", "00100", "00100", "00100", "11111" }, 
				'J' => new string[5] { "00111", "00010", "00010", "10010", "01100" }, 
				'K' => new string[5] { "10001", "10010", "11100", "10010", "10001" }, 
				'L' => new string[5] { "10000", "10000", "10000", "10000", "11111" }, 
				'M' => new string[5] { "10001", "11011", "10101", "10001", "10001" }, 
				'N' => new string[5] { "10001", "11001", "10101", "10011", "10001" }, 
				'O' => new string[5] { "01110", "10001", "10001", "10001", "01110" }, 
				'P' => new string[5] { "11110", "10001", "11110", "10000", "10000" }, 
				'Q' => new string[5] { "01110", "10001", "10001", "10011", "01111" }, 
				'R' => new string[5] { "11110", "10001", "11110", "10010", "10001" }, 
				'S' => new string[5] { "01111", "10000", "01110", "00001", "11110" }, 
				'T' => new string[5] { "11111", "00100", "00100", "00100", "00100" }, 
				'U' => new string[5] { "10001", "10001", "10001", "10001", "01110" }, 
				'V' => new string[5] { "10001", "10001", "10001", "01010", "00100" }, 
				'W' => new string[5] { "10001", "10001", "10101", "11011", "10001" }, 
				'X' => new string[5] { "10001", "01010", "00100", "01010", "10001" }, 
				'Y' => new string[5] { "10001", "01010", "00100", "00100", "00100" }, 
				'Z' => new string[5] { "11111", "00010", "00100", "01000", "11111" }, 
				_ => new string[5] { "11111", "10001", "00110", "00000", "00100" }, 
			};
			bool[,] array2 = new bool[5, 5];
			for (int i = 0; i < 5; i++)
			{
				for (int j = 0; j < 5; j++)
				{
					array2[j, i] = array[i][j] == '1';
				}
			}
			return array2;
		}
	}
}
namespace FlowerPainter.Patches
{
	[HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")]
	public static class FlowerPainterMouseWheelCapturePatch
	{
		private static void Postfix(ref float __result)
		{
			if (!(Mathf.Abs(__result) < 0.001f) && FlowerPaintPlacementGhost.ShouldConsumeMouseWheel())
			{
				__result = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "PlacePiece", new Type[]
	{
		typeof(Piece),
		typeof(Vector3),
		typeof(Quaternion),
		typeof(bool)
	})]
	public static class PlayerPlacePiecePatch
	{
		private static bool Prefix(Piece piece, Vector3 pos)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)piece == (Object)null)
			{
				return true;
			}
			FlowerPaintBrush component = ((Component)piece).GetComponent<FlowerPaintBrush>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			if (!component.RemoveMode)
			{
				return true;
			}
			FlowerPaintBrushSettings.EnsureInitialized();
			ErasePaintedClutter(pos, FlowerPaintBrushSettings.Radius);
			return false;
		}

		private static void ErasePaintedClutter(Vector3 position, float radius)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			radius = Mathf.Max(0.25f, radius);
			for (int num = FlowerPaintRegistry.All.Count - 1; num >= 0; num--)
			{
				FlowerPaintMarker flowerPaintMarker = FlowerPaintRegistry.All[num];
				if (!((Object)(object)flowerPaintMarker == (Object)null) && flowerPaintMarker.OverlapsHorizontalCircle(position, radius))
				{
					if (flowerPaintMarker.IsFullyInsideHorizontalCircle(position, radius))
					{
						flowerPaintMarker.DestroyNetworked();
					}
					else
					{
						flowerPaintMarker.ApplyEraseCircle(position, radius);
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	public static class ZNetScenePatch
	{
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			RuntimeBootstrap.TryRegisterScenePrefabs();
			RuntimeBootstrap.TryRegisterPieces();
		}
	}
	[HarmonyPatch(typeof(ClutterSystem), "Awake")]
	public static class ClutterSystemPatch
	{
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			ClutterCatalog.Invalidate();
			RuntimeBootstrap.TryRegisterPieces();
		}
	}
}
namespace FlowerPainter.Runtime
{
	public sealed class FlowerPaintSystem : MonoBehaviour
	{
		private void Update()
		{
			RuntimeBootstrap.Tick();
		}

		public static void RequestImmediateRefresh()
		{
		}

		public static bool TryGetTerrainPoint(Vector3 input, out Vector3 point, out Vector3 normal)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			point = input;
			normal = Vector3.up;
			int num = LayerMask.NameToLayer("terrain");
			int num2 = ((num >= 0) ? (1 << num) : 0);
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(input.x, input.y + 2000f, input.z);
			RaycastHit val2 = default(RaycastHit);
			if (num2 != 0 && Physics.Raycast(val, Vector3.down, ref val2, 5000f, num2, (QueryTriggerInteraction)1))
			{
				point = ((RaycastHit)(ref val2)).point;
				normal = ((RaycastHit)(ref val2)).normal;
				return true;
			}
			float num3 = default(float);
			if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(input, ref num3))
			{
				point = new Vector3(input.x, num3, input.z);
				normal = Vector3.up;
				return true;
			}
			return false;
		}
	}
	public static class ClutterCatalog
	{
		private const bool IncludeAllClutterEntries = false;

		private static readonly List<DiscoveredClutter> Cached = new List<DiscoveredClutter>();

		private static readonly Dictionary<string, DiscoveredClutter> ById = new Dictionary<string, DiscoveredClutter>(StringComparer.Ordinal);

		private static int _signature;

		public static IList<DiscoveredClutter> Entries => Cached;

		public static void Invalidate()
		{
			_signature = 0;
		}

		public static bool EnsureDiscovered()
		{
			ClutterSystem val = (((Object)(object)ClutterSystem.instance != (Object)null) ? ClutterSystem.instance : Object.FindFirstObjectByType<ClutterSystem>());
			if ((Object)(object)val == (Object)null || val.m_clutter == null)
			{
				return false;
			}
			int num = ComputeSignature(val.m_clutter);
			if (num == _signature && Cached.Count > 0)
			{
				return true;
			}
			Rebuild(val.m_clutter, num);
			return Cached.Count > 0;
		}

		public static bool TryGet(string clutterId, string fallbackPrefabName, out DiscoveredClutter entry)
		{
			EnsureDiscovered();
			if (!string.IsNullOrEmpty(clutterId) && ById.TryGetValue(clutterId, out entry))
			{
				return true;
			}
			if (!string.IsNullOrEmpty(fallbackPrefabName))
			{
				for (int i = 0; i < Cached.Count; i++)
				{
					DiscoveredClutter discoveredClutter = Cached[i];
					if (discoveredClutter != null && string.Equals(discoveredClutter.PrefabName, fallbackPrefabName, StringComparison.Ordinal))
					{
						entry = discoveredClutter;
						return true;
					}
				}
			}
			entry = null;
			return false;
		}

		private static void Rebuild(List<Clutter> source, int signature)
		{
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			Cached.Clear();
			ById.Clear();
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.Ordinal);
			for (int i = 0; i < source.Count; i++)
			{
				Clutter val = source[i];
				if (val == null || (Object)(object)val.m_prefab == (Object)null || !val.m_enabled)
				{
					continue;
				}
				string text = ((Object)val.m_prefab).name ?? string.Empty;
				if (!string.IsNullOrEmpty(text))
				{
					bool flag = ReflectionUtils.LooksLikeVegetationName(text);
					InstanceRenderer[] componentsInChildren = val.m_prefab.GetComponentsInChildren<InstanceRenderer>(true);
					bool flag2 = componentsInChildren != null && componentsInChildren.Length != 0;
					if (flag || flag2)
					{
						dictionary.TryGetValue(text, out var value);
						dictionary[text] = value + 1;
						string text2 = ((!string.IsNullOrEmpty(val.m_name)) ? val.m_name : text);
						dictionary2.TryGetValue(text2, out var value2);
						dictionary2[text2] = value2 + 1;
						string text3 = ((value2 == 0) ? text2 : (text2 + "#" + value2));
						string stableId = ReflectionUtils.SafeName(text2) + "_" + StableHash(text3 + "|" + text).ToString("X8");
						DiscoveredClutter discoveredClutter = new DiscoveredClutter
						{
							ClutterId = text3,
							StableId = stableId,
							ClutterName = (val.m_name ?? string.Empty),
							PrefabName = text,
							CatalogIndex = i,
							PrefabOccurrence = value,
							Prefab = val.m_prefab,
							Source = val,
							Amount = val.m_amount,
							Biome = val.m_biome,
							VegetationLike = flag,
							Instanced = val.m_instanced,
							ScaleMin = val.m_scaleMin,
							ScaleMax = val.m_scaleMax,
							MinTilt = val.m_minTilt,
							MaxTilt = val.m_maxTilt,
							RandomOffset = val.m_randomOffset,
							TerrainTilt = val.m_terrainTilt,
							SnapToWater = val.m_snapToWater,
							OnCleared = val.m_onCleared,
							OnUncleared = val.m_onUncleared,
							HasInstanceRenderer = flag2
						};
						Cached.Add(discoveredClutter);
						ById[discoveredClutter.ClutterId] = discoveredClutter;
					}
				}
			}
			Cached.Sort(delegate(DiscoveredClutter a, DiscoveredClutter b)
			{
				int num = string.Compare(a.PrefabName, b.PrefabName, StringComparison.OrdinalIgnoreCase);
				return (num != 0) ? num : string.Compare(a.ClutterId, b.ClutterId, StringComparison.OrdinalIgnoreCase);
			});
			_signature = signature;
		}

		private static int ComputeSignature(List<Clutter> source)
		{
			int num = 17;
			num = num * 31 + source.Count;
			for (int i = 0; i < source.Count; i++)
			{
				Clutter val = source[i];
				if (val == null)
				{
					num *= 31;
					continue;
				}
				num = num * 31 + StableHash(val.m_name);
				num = num * 31 + StableHash(((Object)(object)val.m_prefab != (Object)null) ? ((Object)val.m_prefab).name : string.Empty);
				num = num * 31 + val.m_amount;
				num = num * 31 + val.m_scaleMin.GetHashCode();
				num = num * 31 + val.m_scaleMax.GetHashCode();
				num = num * 31 + (val.m_instanced ? 1 : 0);
			}
			return num;
		}

		internal static int StableHash(string value)
		{
			int num = 23;
			if (value == null)
			{
				return num;
			}
			for (int i = 0; i < value.Length; i++)
			{
				num = num * 31 + value[i];
			}
			return num;
		}
	}
	public static class PrefabFactory
	{
		private const float FlowerPainterPieceHealth = 20f;

		public const string LegacyMarkerPrefabName = "FlowerPainter_MarkerV2";

		public const string PiecePrefix = "FlowerPainter_Piece_";

		public static GameObject CreateLegacyMarkerPrefab()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("FlowerPainter_MarkerV2");
			ParentToRuntimeRoot(val);
			val.layer = GetPieceLayer();
			val.SetActive(true);
			ZNetView val2 = val.AddComponent<ZNetView>();
			val2.m_persistent = true;
			val.AddComponent<FlowerPaintMarker>();
			return val;
		}

		public static GameObject CreatePaintPiecePrefab(DiscoveredClutter entry)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			if (entry == null || (Object)(object)entry.Prefab == (Object)null)
			{
				return null;
			}
			string text = "FlowerPainter_Piece_" + entry.StableId;
			string text2 = DisplayNameUtils.FromPrefabName(entry.PrefabName);
			if (!string.IsNullOrEmpty(entry.ClutterName) && entry.ClutterName != entry.PrefabName)
			{
				text2 = text2 + " [" + entry.ClutterName + "]";
			}
			GameObject val = new GameObject(text);
			ParentToRuntimeRoot(val);
			val.layer = GetPieceLayer();
			val.SetActive(true);
			ZNetView val2 = val.AddComponent<ZNetView>();
			val2.m_persistent = true;
			Piece piece = val.AddComponent<Piece>();
			ConfigurePiece(piece, entry, text2);
			WearNTear wear = val.AddComponent<WearNTear>();
			ConfigureWearNTear(wear);
			SphereCollider val3 = val.AddComponent<SphereCollider>();
			((Collider)val3).isTrigger = false;
			val3.radius = 0.65f;
			val3.center = new Vector3(0f, 0.35f, 0f);
			FlowerPaintBrush flowerPaintBrush = val.AddComponent<FlowerPaintBrush>();
			flowerPaintBrush.BrushId = entry.StableId;
			flowerPaintBrush.ClutterId = entry.ClutterId;
			flowerPaintBrush.ClutterPrefabName = entry.PrefabName;
			flowerPaintBrush.Radius = ((Plugin.DefaultBrushRadius != null) ? Mathf.Max(0.25f, Plugin.DefaultBrushRadius.Value) : 4f);
			flowerPaintBrush.DensityMultiplier = ((Plugin.DefaultDensityMultiplier != null) ? Mathf.Max(0.01f, Plugin.DefaultDensityMultiplier.Value) : 1f);
			flowerPaintBrush.RemoveMode = false;
			val.AddComponent<FlowerPaintMarker>();
			GameObject val4 = CreateClutterVisualTemplate(entry.Prefab, val.transform);
			if ((Object)(object)val4 != (Object)null)
			{
				((Object)val4).name = "_FP_ClutterTemplate";
			}
			AttachVanillaGhost(val);
			FlowerPaintGhostScaler flowerPaintGhostScaler = val.AddComponent<FlowerPaintGhostScaler>();
			flowerPaintGhostScaler.Radius = flowerPaintBrush.Radius;
			val.AddComponent<FlowerPaintPlacementGhost>();
			return val;
		}

		public static GameObject CreateClearBrushPrefab()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("FlowerPainter_Clear");
			ParentToRuntimeRoot(val);
			val.layer = GetPieceLayer();
			val.SetActive(true);
			Piece val2 = val.AddComponent<Piece>();
			val2.m_name = "Clear Flower Paint";
			val2.m_description = "Erase FlowerPainter clutter inside the brush radius. Ctrl + mouse wheel changes eraser radius.";
			val2.m_enabled = true;
			val2.m_category = (PieceCategory)0;
			val2.m_groundPiece = true;
			val2.m_groundOnly = true;
			val2.m_allowAltGroundPlacement = true;
			val2.m_canRotate = false;
			val2.m_canBeRemoved = false;
			val2.m_resources = (Requirement[])(object)new Requirement[0];
			if (!IsDedicatedServer())
			{
				val2.m_icon = GetCultivatorIcon();
				if ((Object)(object)val2.m_icon == (Object)null)
				{
					val2.m_icon = TextureMaker.CreateFlowerGlyphIcon();
				}
			}
			FlowerPaintBrush flowerPaintBrush = val.AddComponent<FlowerPaintBrush>();
			flowerPaintBrush.BrushId = "CLEAR";
			flowerPaintBrush.Radius = ((Plugin.DefaultBrushRadius != null) ? Mathf.Max(0.25f, Plugin.DefaultBrushRadius.Value) : 4f);
			flowerPaintBrush.DensityMultiplier = 1f;
			flowerPaintBrush.RemoveMode = true;
			AttachVanillaGhost(val);
			FlowerPaintGhostScaler flowerPaintGhostScaler = val.AddComponent<FlowerPaintGhostScaler>();
			flowerPaintGhostScaler.Radius = flowerPaintBrush.Radius;
			val.AddComponent<FlowerPaintPlacementGhost>();
			return val;
		}

		private static void ConfigurePiece(Piece piece, DiscoveredClutter entry, string displayName)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (!IsDedicatedServer())
			{
				piece.m_icon = PrefabPreviewRenderer.CreatePreviewSprite(entry);
				if ((Object)(object)piece.m_icon == (Object)null)
				{
					piece.m_icon = TextureMaker.CreateFlowerGlyphIcon();
				}
			}
			piece.m_name = displayName;
			piece.m_description = "Paint ClutterSystem entry '" + entry.ClutterId + "'. Ctrl + mouse wheel: radius. Shift + mouse wheel: density.";
			piece.m_enabled = true;
			piece.m_category = (PieceCategory)0;
			piece.m_isUpgrade = false;
			piece.m_groundPiece = true;
			piece.m_groundOnly = true;
			piece.m_allowAltGroundPlacement = true;
			piece.m_cultivatedGroundOnly = false;
			piece.m_waterPiece = false;
			piece.m_noInWater = false;
			piece.m_notOnWood = false;
			piece.m_notOnTiltingSurface = false;
			piece.m_noClipping = false;
			piece.m_allowedInDungeons = false;
			piece.m_spaceRequirement = 0f;
			piece.m_canRotate = false;
			piece.m_randomInitBuildRotation = false;
			piece.m_canBeRemoved = true;
			piece.m_resources = (Requirement[])(object)new Requirement[0];
		}

		private static void ConfigureWearNTear(WearNTear wear)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			wear.m_health = 20f;
			wear.m_noRoofWear = true;
			wear.m_noSupportWear = true;
			wear.m_supports = true;
			wear.m_staticPosition = true;
			wear.m_burnable = false;
			wear.m_ashDamageImmune = true;
			wear.m_triggerPrivateArea = true;
			wear.m_autoCreateFragments = false;
			wear.m_materialType = (MaterialType)0;
		}

		public static GameObject CreateClutterVisualTemplate(GameObject sourcePrefab, Transform parent)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sourcePrefab == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(sourcePrefab, parent, false);
			((Object)val).name = "_FP_ClutterTemplate";
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.SetActive(false);
			SanitizeClutterVisual(val.transform);
			return val;
		}

		public static void SanitizeClutterVisual(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			Component[] components = ((Component)root).GetComponents<Component>();
			foreach (Component val in components)
			{
				if (!((Object)(object)val == (Object)null) && !(val is Transform) && (val is ZNetView || val is ZSyncTransform || val is Piece || val is WearNTear || val is ItemDrop || val is Pickable || val is Plant || val is Collider || val is Rigidbody || val is IDestructible))
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
			for (int j = 0; j < root.childCount; j++)
			{
				SanitizeClutterVisual(root.GetChild(j));
			}
		}

		private static void ParentToRuntimeRoot(GameObject go)
		{
			if (!((Object)(object)go == (Object)null))
			{
				Transform runtimePrefabRoot = RuntimeBootstrap.RuntimePrefabRoot;
				if ((Object)(object)runtimePrefabRoot != (Object)null)
				{
					go.transform.SetParent(runtimePrefabRoot, false);
				}
			}
		}

		public static bool RegisterPrefabToZNetScene(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return false;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
			if (ZNetScene.instance.m_namedPrefabs.TryGetValue(stableHashCode, out var value))
			{
				if ((Object)(object)value == (Object)(object)prefab)
				{
					return true;
				}
				Debug.LogError((object)("FlowerPainter prefab hash/name collision: " + ((Object)prefab).name));
				return false;
			}
			if (!ZNetScene.instance.m_prefabs.Contains(prefab))
			{
				ZNetScene.instance.m_prefabs.Add(prefab);
			}
			ZNetScene.instance.m_namedPrefabs.Add(stableHashCode, prefab);
			return true;
		}

		private static bool IsDedicatedServer()
		{
			return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated();
		}

		private static Sprite GetCultivatorIcon()
		{
			GameObject val = null;
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				val = ObjectDB.instance.GetItemPrefab("Cultivator");
			}
			if ((Object)(object)val == (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
			{
				val = ZNetScene.instance.GetPrefab("Cultivator");
			}
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			ItemDrop component = val.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null || component.m_itemData == null)
			{
				return null;
			}
			return component.m_itemData.GetIcon();
		}

		private static int GetPieceLayer()
		{
			int num = LayerMask.NameToLayer("piece_nonsolid");
			if (num < 0)
			{
				num = LayerMask.NameToLayer("piece");
			}
			return (num >= 0) ? num : 0;
		}

		private static void AttachVanillaGhost(GameObject target)
		{
			if ((Object)(object)target == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Cultivator");
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return;
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
			{
				return;
			}
			PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces;
			if ((Object)(object)buildPieces == (Object)null || buildPieces.m_pieces == null)
			{
				return;
			}
			GameObject val = FindGhostSource(buildPieces);
			if (!((Object)(object)val == (Object)null))
			{
				Transform val2 = val.transform.Find("_GhostOnly");
				if (!((Object)(object)val2 == (Object)null))
				{
					GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, target.transform, false);
					((Object)val3).name = "_GhostOnly";
					val3.SetActive(true);
				}
			}
		}

		private static GameObject FindGhostSource(PieceTable table)
		{
			for (int i = 0; i < table.m_pieces.Count; i++)
			{
				GameObject val = table.m_pieces[i];
				if (!((Object)(object)val == (Object)null))
				{
					Transform val2 = val.transform.Find("_GhostOnly");
					if ((Object)(object)val2 != (Object)null)
					{
						return val;
					}
				}
			}
			return null;
		}
	}
	public static class RuntimeBootstrap
	{
		private const string RuntimeRootName = "BalrondFlowerPainter_RuntimePrefabs";

		private static GameObject _runtimeRoot;

		private static GameObject _legacyMarkerPrefab;

		private static GameObject _clearBrushPrefab;

		private static readonly Dictionary<string, GameObject> PiecePrefabs = new Dictionary<string, GameObject>(StringComparer.Ordinal);

		private static float _nextRetry;

		private static int _lastLoggedPieceCount = -1;

		public static Transform RuntimePrefabRoot
		{
			get
			{
				EnsureRuntimeRoot();
				return ((Object)(object)_runtimeRoot != (Object)null) ? _runtimeRoot.transform : null;
			}
		}

		public static void Tick()
		{
			if (!(Time.time < _nextRetry))
			{
				_nextRetry = Time.time + 2f;
				if (IsWorldRuntimeReady())
				{
					TryRegisterScenePrefabs();
					TryRegisterPieces();
				}
			}
		}

		public static bool IsWorldRuntimeReady()
		{
			return (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ClutterSystem.instance != (Object)null;
		}

		public static void TryRegisterScenePrefabs()
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			EnsureRuntimeRoot();
			if ((Object)(object)ZNetScene.instance.GetPrefab("FlowerPainter_MarkerV2") == (Object)null)
			{
				if ((Object)(object)_legacyMarkerPrefab == (Object)null)
				{
					_legacyMarkerPrefab = PrefabFactory.CreateLegacyMarkerPrefab();
				}
				PrefabFactory.RegisterPrefabToZNetScene(_legacyMarkerPrefab);
			}
		}

		public static void TryRegisterPieces()
		{
			if (!IsWorldRuntimeReady() || !ClutterCatalog.EnsureDiscovered())
			{
				return;
			}
			TryRegisterScenePrefabs();
			RemoveFlowerPainterPiecesFromHoe();
			IList<DiscoveredClutter> entries = ClutterCatalog.Entries;
			List<PieceTable> list = CollectTargetTables();
			if (list.Count == 0)
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				SanitizePieceTable(list[i]);
			}
			if ((Object)(object)_clearBrushPrefab == (Object)null)
			{
				_clearBrushPrefab = PrefabFactory.CreateClearBrushPrefab();
			}
			if ((Object)(object)_clearBrushPrefab != (Object)null)
			{
				for (int j = 0; j < list.Count; j++)
				{
					AddPieceIfMissing(list[j], _clearBrushPrefab);
					MoveClearBeforeFlowerPainterPieces(list[j]);
				}
			}
			for (int k = 0; k < entries.Count; k++)
			{
				DiscoveredClutter discoveredClutter = entries[k];
				if (discoveredClutter == null || (Object)(object)discoveredClutter.Prefab == (Object)null)
				{
					continue;
				}
				string key = "FlowerPainter_Piece_" + discoveredClutter.StableId;
				if (!PiecePrefabs.TryGetValue(key, out var value) || (Object)(object)value == (Object)null)
				{
					value = PrefabFactory.CreatePaintPiecePrefab(discoveredClutter);
					if ((Object)(object)value == (Object)null)
					{
						continue;
					}
					PiecePrefabs[key] = value;
				}
				if (PrefabFactory.RegisterPrefabToZNetScene(value))
				{
					for (int l = 0; l < list.Count; l++)
					{
						AddPieceIfMissing(list[l], value);
					}
				}
			}
			int num = entries.Count + 1;
			if (_lastLoggedPieceCount != num)
			{
				_lastLoggedPieceCount = num;
				Debug.Log((object)("FlowerPainter registered " + entries.Count + " full Piece prefabs + clear tool into " + list.Count + " PieceTable(s). Every clutter Piece is ZNetScene-registered and uses vanilla Player.PlacePiece."));
			}
		}

		public static void SanitizePieceTable(PieceTable table)
		{
			if (!((Object)(object)table == (Object)null) && table.m_pieces != null)
			{
				int num = table.m_pieces.RemoveAll((GameObject piece) => (Object)(object)piece == (Object)null);
				if (num > 0)
				{
					Debug.LogWarning((object)("Removed " + num + " null/destroyed prefab reference(s) from PieceTable '" + ((Object)table).name + "'."));
				}
			}
		}

		private static List<PieceTable> CollectTargetTables()
		{
			List<PieceTable> result = new List<PieceTable>();
			AddTableFromTool(result, "Cultivator", includeObjectDb: true);
			return result;
		}

		private static void RemoveFlowerPainterPiecesFromHoe()
		{
			List<PieceTable> list = new List<PieceTable>();
			AddTableFromTool(list, "Hoe", includeObjectDb: true);
			for (int i = 0; i < list.Count; i++)
			{
				PieceTable val = list[i];
				if (!((Object)(object)val == (Object)null) && val.m_pieces != null)
				{
					int num = val.m_pieces.RemoveAll((GameObject piece) => !((Object)(object)piece == (Object)null) && (((Object)piece).name.StartsWith("FlowerPainter_Piece_", StringComparison.Ordinal) || ((Object)piece).name == "FlowerPainter_Clear"));
					if (num > 0)
					{
						Debug.Log((object)("Removed " + num + " FlowerPainter Piece(s) from Hoe PieceTable. FlowerPainter is Cultivator-only."));
					}
				}
			}
		}

		private static void AddTableFromTool(List<PieceTable> result, string toolName, bool includeObjectDb)
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				AddToolPrefabTable(result, ZNetScene.instance.GetPrefab(toolName));
			}
			if (includeObjectDb && (Object)(object)ObjectDB.instance != (Object)null)
			{
				AddToolPrefabTable(result, ObjectDB.instance.GetItemPrefab(toolName));
			}
		}

		private static void AddToolPrefabTable(List<PieceTable> result, GameObject tool)
		{
			if ((Object)(object)tool == (Object)null)
			{
				return;
			}
			ItemDrop component = tool.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
			{
				return;
			}
			PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces;
			if ((Object)(object)buildPieces == (Object)null || buildPieces.m_pieces == null)
			{
				return;
			}
			for (int i = 0; i < result.Count; i++)
			{
				if (result[i] == buildPieces)
				{
					return;
				}
			}
			result.Add(buildPieces);
		}

		private static void AddPieceIfMissing(PieceTable table, GameObject piecePrefab)
		{
			if ((Object)(object)table == (Object)null || table.m_pieces == null || (Object)(object)piecePrefab == (Object)null)
			{
				return;
			}
			Piece component = piecePrefab.GetComponent<Piece>();
			if ((Object)(object)component == (Object)null)
			{
				Debug.LogError((object)("Refusing to add non-Piece FlowerPainter prefab to PieceTable: " + ((Object)piecePrefab).name));
				return;
			}
			for (int i = 0; i < table.m_pieces.Count; i++)
			{
				GameObject val = table.m_pieces[i];
				if ((Object)(object)val != (Object)null && ((Object)val).name == ((Object)piecePrefab).name)
				{
					return;
				}
			}
			table.m_pieces.Add(piecePrefab);
		}

		private static void MoveClearBeforeFlowerPainterPieces(PieceTable table)
		{
			if ((Object)(object)table == (Object)null || table.m_pieces == null)
			{
				return;
			}
			int num = -1;
			int num2 = -1;
			for (int i = 0; i < table.m_pieces.Count; i++)
			{
				GameObject val = table.m_pieces[i];
				if (!((Object)(object)val == (Object)null))
				{
					if (((Object)val).name == "FlowerPainter_Clear")
					{
						num = i;
					}
					else if (num2 < 0 && ((Object)val).name.StartsWith("FlowerPainter_Piece_", StringComparison.Ordinal))
					{
						num2 = i;
					}
				}
			}
			if (num >= 0 && num2 >= 0 && num >= num2)
			{
				GameObject item = table.m_pieces[num];
				table.m_pieces.RemoveAt(num);
				table.m_pieces.Insert(num2, item);
			}
		}

		private static void EnsureRuntimeRoot()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			if (!((Object)(object)_runtimeRoot != (Object)null))
			{
				_runtimeRoot = new GameObject("BalrondFlowerPainter_RuntimePrefabs");
				((Object)_runtimeRoot).hideFlags = (HideFlags)1;
				Object.DontDestroyOnLoad((Object)(object)_runtimeRoot);
				_runtimeRoot.SetActive(false);
			}
		}
	}
}
namespace FlowerPainter.Managers
{
	public static class FlowerPaintRegistry
	{
		public static readonly List<FlowerPaintMarker> All = new List<FlowerPaintMarker>();

		private static int _revision;

		public static int Revision => _revision;

		public static void Register(FlowerPaintMarker marker)
		{
			if (!((Object)(object)marker == (Object)null) && !All.Contains(marker))
			{
				All.Add(marker);
				_revision++;
			}
		}

		public static void Unregister(FlowerPaintMarker marker)
		{
			if (!((Object)(object)marker == (Object)null) && All.Remove(marker))
			{
				_revision++;
			}
		}

		public static void MarkDirty()
		{
			_revision++;
		}
	}
}
namespace FlowerPainter.Data
{
	public sealed class DiscoveredClutter
	{
		public string ClutterId;

		public string StableId;

		public string ClutterName;

		public string PrefabName;

		public int CatalogIndex;

		public int PrefabOccurrence;

		public GameObject Prefab;

		public Clutter Source;

		public int Amount;

		public Biome Biome;

		public bool VegetationLike;

		public bool Instanced;

		public float ScaleMin;

		public float ScaleMax;

		public float MinTilt;

		public float MaxTilt;

		public float RandomOffset;

		public bool TerrainTilt;

		public bool SnapToWater;

		public bool OnCleared;

		public bool OnUncleared;

		public bool HasInstanceRenderer;
	}
}
namespace FlowerPainter.Components
{
	public sealed class FlowerPaintBrush : MonoBehaviour
	{
		public string BrushId;

		public string ClutterId;

		public string ClutterPrefabName;

		public float Radius;

		public float DensityMultiplier = 1f;

		public bool RemoveMode;
	}
	public static class FlowerPaintBrushSettings
	{
		public const float MinRadius = 0.5f;

		public const float MaxRadius = 20f;

		public const float RadiusStep = 0.5f;

		public const float MinDensity = 0.25f;

		public const float MaxDensity = 8f;

		public const float DensityStep = 0.25f;

		private static bool _initialized;

		private static float _radius;

		private static float _density;

		public static float Radius
		{
			get
			{
				EnsureInitialized();
				return _radius;
			}
		}

		public static float DensityMultiplier
		{
			get
			{
				EnsureInitialized();
				return _density;
			}
		}

		public static void EnsureInitialized()
		{
			if (!_initialized)
			{
				float num = ((Plugin.DefaultBrushRadius != null) ? Plugin.DefaultBrushRadius.Value : 4f);
				float num2 = ((Plugin.DefaultDensityMultiplier != null) ? Plugin.DefaultDensityMultiplier.Value : 2f);
				_radius = Mathf.Clamp(num, 0.5f, 20f);
				_density = Mathf.Clamp(num2, 0.25f, 8f);
				_initialized = true;
			}
		}

		public static bool AdjustRadius(float direction)
		{
			EnsureInitialized();
			if (Mathf.Abs(direction) < 0.001f)
			{
				return false;
			}
			float num = Mathf.Clamp(_radius + Mathf.Sign(direction) * 0.5f, 0.5f, 20f);
			if (Mathf.Approximately(num, _radius))
			{
				return false;
			}
			_radius = num;
			return true;
		}

		public static bool AdjustDensity(float direction)
		{
			EnsureInitialized();
			if (Mathf.Abs(direction) < 0.001f)
			{
				return false;
			}
			float num = Mathf.Clamp(_density + Mathf.Sign(direction) * 0.25f, 0.25f, 8f);
			if (Mathf.Approximately(num, _density))
			{
				return false;
			}
			_density = num;
			return true;
		}
	}
	public class FlowerPaintGhostScaler : MonoBehaviour
	{
		public float Radius;

		private void OnEnable()
		{
			Apply();
		}

		public void Apply()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			Transform val = ((Component)this).transform.Find("_GhostOnly");
			if (!((Object)(object)val == (Object)null))
			{
				float num = ((Radius > 0f) ? Radius : Plugin.DefaultBrushRadius.Value);
				float num2 = num * 2f;
				val.localScale = new Vector3(num2, 1f, num2);
			}
		}
	}
	public sealed class FlowerPaintMarker : MonoBehaviour, IPlaced
	{
		private struct Placement
		{
			public Vector3 Position;

			public Quaternion Rotation;

			public float Scale;
		}

		private struct EraseCircle
		{
			public Vector2 LocalCenter;

			public float Radius;
		}

		public const string VisualTemplateName = "_FP_ClutterTemplate";

		private const string ExtraVisualRootName = "_FP_ExtraVisuals";

		private const int DataVersion = 7;

		private const int MaxPerInstanceRenderer = 1023;

		private const int MaxFallbackGameObjects = 512;

		private const int MaxInstancesPerPiece = 8192;

		private ZNetView _znv;

		private FlowerPaintBrush _definition;

		private bool _registered;

		private bool _visualBuilt;

		private float _nextBuildAttempt;

		private float _nextDataSyncCheck;

		private Transform _extraVisualRoot;

		private readonly List<EraseCircle> _eraseCircles = new List<EraseCircle>();

		private string _eraseDataCache = string.Empty;

		public string ClutterId { get; private set; }

		public string ClutterPrefabName { get; private set; }

		public float Radius { get; private set; }

		public float DensityMultiplier { get; private set; }

		public int Seed { get; private set; }

		public int TargetCount { get; private set; }

		private void Awake()
		{
			_znv = ((Component)this).GetComponent<ZNetView>();
			_definition = ((Component)this).GetComponent<FlowerPaintBrush>();
			TryLoadAndRegister();
		}

		private void Start()
		{
			TryLoadAndRegister();
			HidePlacementGhostVisuals();
			TryBuildVisuals();
		}

		private void Update()
		{
			if ((Object)(object)_znv != (Object)null && _znv.IsValid() && Time.time >= _nextDataSyncCheck)
			{
				_nextDataSyncCheck = Time.time + 0.5f;
				if (RefreshEraseDataFromZDO())
				{
					_visualBuilt = false;
					ClearGeneratedVisuals();
				}
			}
			if (!_visualBuilt && !(Time.time < _nextBuildAttempt))
			{
				_nextBuildAttempt = Time.time + 1f;
				TryLoadAndRegister();
				TryBuildVisuals();
			}
		}

		private void OnDestroy()
		{
			if (_registered)
			{
				FlowerPaintRegistry.Unregister(this);
			}
		}

		public void OnPlaced()
		{
			if ((Object)(object)_definition != (Object)null && !_definition.RemoveMode)
			{
				FlowerPaintBrushSettings.EnsureInitialized();
				Initialize(_definition.ClutterId, _definition.ClutterPrefabName, FlowerPaintBrushSettings.Radius, FlowerPaintBrushSettings.DensityMultiplier, CreateUniquePlacementSeed());
			}
			TryLoadAndRegister();
			HidePlacementGhostVisuals();
			RebuildVisuals();
		}

		public void Initialize(string clutterId, string clutterPrefabName, float radius, float densityMultiplier, int seed)
		{
			if ((Object)(object)_znv == (Object)null || !_znv.IsValid())
			{
				return;
			}
			if (!_znv.IsOwner())
			{
				_znv.ClaimOwnership();
			}
			if (!_znv.IsOwner())
			{
				return;
			}
			ZDO zDO = _znv.GetZDO();
			if (zDO != null)
			{
				if (seed == 0)
				{
					seed = 1;
				}
				ClutterId = clutterId ?? string.Empty;
				ClutterPrefabName = clutterPrefabName ?? string.Empty;
				Radius = Mathf.Max(0.25f, radius);
				DensityMultiplier = Mathf.Max(0.01f, densityMultiplier);
				Seed = seed;
				TargetCount = ((ClutterCatalog.TryGet(ClutterId, ClutterPrefabName, out var entry) && entry != null) ? ComputeTargetCount(entry) : 0);
				zDO.Set("fp_version", 7);
				zDO.Set("fp_clutter_id", ClutterId);
				zDO.Set("fp_clutter", ClutterPrefabName);
				zDO.Set("fp_radius", Radius);
				zDO.Set("fp_density", DensityMultiplier);
				zDO.Set("fp_seed", Seed);
				zDO.Set("fp_count", TargetCount);
				zDO.Set("fp_erase", string.Empty);
				_eraseCircles.Clear();
				_eraseDataCache = string.Empty;
				RegisterIfNetworked();
				FlowerPaintRegistry.MarkDirty();
			}
		}

		public void DestroyNetworked()
		{
			if ((Object)(object)_znv != (Object)null && _znv.IsValid() && !_znv.IsOwner())
			{
				_znv.ClaimOwnership();
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				ZNetScene.instance.Destroy(((Component)this).gameObject);
			}
			else
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		public void SetPlacementColliderEnabled(bool enabledState)
		{
			Collider[] components = ((Component)this).GetComponents<Collider>();
			foreach (Collider val in components)
			{
				if ((Object)(object)val != (Object)null && val.enabled != enabledState)
				{
					val.enabled = enabledState;
				}
			}
		}

		public bool OverlapsHorizontalCircle(Vector3 worldCenter, float radius)
		{
			//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)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(0.25f, Radius);
			float num2 = Mathf.Max(0f, radius);
			Vector3 val = ((Component)this).transform.position - worldCenter;
			val.y = 0f;
			float num3 = num + num2;
			return ((Vector3)(ref val)).sqrMagnitude <= num3 * num3;
		}

		public bool IsFullyInsideHorizontalCircle(Vector3 worldCenter, float radius)
		{
			//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)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(0.25f, Radius);
			float num2 = Mathf.Max(0f, radius);
			Vector3 val = ((Component)this).transform.position - worldCenter;
			val.y = 0f;
			return ((Vector3)(ref val)).magnitude + num <= num2;
		}

		public bool ApplyEraseCircle(Vector3 worldCenter, float radius)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			radius = Mathf.Max(0.25f, radius);
			if ((Object)(object)_znv == (Object)null || !_znv.IsValid())
			{
				return false;
			}
			if (!_znv.IsOwner())
			{
				_znv.ClaimOwnership();
			}
			if (!_znv.IsOwner())
			{
				return false;
			}
			ZDO zDO = _znv.GetZDO();
			if (zDO == null)
			{
				return false;
			}
			RefreshEraseDataFromZDO();
			Vector3 val = worldCenter - ((Component)this).transform.position;
			Vector2 localCenter = default(Vector2);
			((Vector2)(ref localCenter))..ctor(val.x, val.z);
			if (!AddEraseCircle(localCenter, radius))
			{
				return false;
			}
			string text = SerializeEraseCircles();
			zDO.Set("fp_erase", text);
			_eraseDataCache = text;
			FlowerPaintRegistry.MarkDirty();
			if (ClutterCatalog.TryGet(ClutterId, ClutterPrefabName, out var entry) && entry != null && (Object)(object)entry.Prefab != (Object)null && GeneratePlacements(entry).Count == 0)
			{
				DestroyNetworked();
				return true;
			}
			RebuildVisuals();
			return true;
		}

		public void RebuildVisuals()
		{
			_visualBuilt = false;
			ClearGeneratedVisuals();
			TryBuildVisuals();
		}

		private void TryLoadAndRegister()
		{
			if ((Object)(object)_znv == (Object)null)
			{
				_znv = ((Component)this).GetComponent<ZNetView>();
			}
			if (!((Object)(object)_znv == (Object)null) && _znv.IsValid())
			{
				LoadFromZDO();
				RegisterIfNetworked();
			}
		}

		private void RegisterIfNetworked()
		{
			if (!_registered && !((Object)(object)_znv == (Object)null) && _znv.IsValid())
			{
				FlowerPaintRegistry.Register(this);
				_registered = true;
			}
		}

		private void LoadFromZDO()
		{
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_znv == (Object)null || !_znv.IsValid())
			{
				return;
			}
			ZDO zDO = _znv.GetZDO();
			if (zDO == null)
			{
				return;
			}
			string text = zDO.GetString("fp_clutter_id", string.Empty);
			string clutterPrefabName = zDO.GetString("fp_clutter", string.Empty);
			if (string.IsNullOrEmpty(text) && (Object)(object)_definition != (Object)null && !_definition.RemoveMode)
			{
				ClutterId = _definition.ClutterId ?? string.Empty;
				ClutterPrefabName = _definition.ClutterPrefabName ?? string.Empty;
				Radius = Mathf.Max(0.25f, _definition.Radius);
				DensityMultiplier = Mathf.Max(0.01f, _definition.DensityMultiplier);
				TargetCount = 0;
				_eraseCircles.Clear();
				_eraseDataCache = string.Empty;
				return;
			}
			ClutterId = text;
			ClutterPrefabName = clutterPrefabName;
			Radius = Mathf.Max(0.25f, zDO.GetFloat("fp_radius", (Plugin.DefaultBrushRadius != null) ? Plugin.DefaultBrushRadius.Value : 4f));
			DensityMultiplier = Mathf.Max(0.01f, zDO.GetFloat("fp_density", 1f));
			Seed = zDO.GetInt("fp_seed", 0);
			TargetCount = Mathf.Max(0, zDO.GetInt("fp_count", 0));
			LoadEraseData(zDO.GetString("fp_erase", string.Empty));
			if (Seed == 0 && (!string.IsNullOrEmpty(ClutterId) || !string.IsNullOrEmpty(ClutterPrefabName)))
			{
				Seed = StablePositionSeed((!string.IsNullOrEmpty(ClutterId)) ? ClutterId : ClutterPrefabName, ((Component)this).transform.position);
			}
		}

		private void TryBuildVisuals()
		{
			if (_visualBuilt || (Object)(object)_znv == (Object)null || !_znv.IsValid())
			{
				return;
			}
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated())
			{
				_visualBuilt = true;
				return;
			}
			if (string.IsNullOrEmpty(ClutterId) && string.IsNullOrEmpty(ClutterPrefabName))
			{
				LoadFromZDO();
				if (string.IsNullOrEmpty(ClutterId) && string.IsNullOrEmpty(ClutterPrefabName))
				{
					return;
				}
			}
			if (!ClutterCatalog.TryGet(ClutterId, ClutterPrefabName, out var entry) || entry == null || (Object)(object)entry.Prefab == (Object)null)
			{
				return;
			}
			List<Placement> list = GeneratePlacements(entry);
			if (list.Count == 0)
			{
				_visualBuilt = true;
				return;
			}
			ClearGeneratedVisuals();
			if (entry.Instanced && entry.HasInstanceRenderer)
			{
				BuildNativeInstanceRendererVisuals(entry, list);
			}
			else
			{
				BuildFallbackVisuals(entry, list);
			}
			_visualBuilt = true;
		}

		private List<Placement> GeneratePlacements(DiscoveredClutter entry)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: 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_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			int num = ResolveTargetCount(entry);
			List<Placement> list = new List<Placement>(num);
			if (num <= 0)
			{
				return list;
			}
			int num2 = ((Seed != 0) ? Seed : StablePositionSeed(ClutterId, ((Component)this).transform.position));
			Random random = new Random(num2);
			double num3 = random.NextDouble();
			double num4 = random.NextDouble();
			Random random2 = new Random((num2 * 397) ^ 0x51ED270B);
			float num5 = Mathf.Max(0.25f, Radius);
			int num6 = Mathf.Max(num * 6, num + 64);
			float min = entry.ScaleMin;
			float max = entry.ScaleMax;
			NormalizeScaleRange(ref min, ref max);
			int num7 = 0;
			for (int i = 0; i < num6; i++)
			{
				if (num7 >= num)
				{
					break;
				}
				double d = Frac(num3 + (double)(i + 1) * 0.7548776662466927);
				double num8 = Frac(num4 + (double)(i + 1) * 0.5698402909980532);
				double num9 = num8 * Math.PI * 2.0;
				double num10 = Math.Sqrt(d) * (double)num5;
				Vector3 input = ((Component)this).transform.position + new Vector3((float)(Math.Cos(num9) * num10), 0f, (float)(Math.Sin(num9) * num10));
				if (FlowerPaintSystem.TryGetTerrainPoint(input, out var point, out var normal))
				{
					if (entry.SnapToWater)
					{
						float y = (((Object)(object)ZoneSystem.instance != (Object)null) ? ReflectionUtils.GetFieldValue(ZoneSystem.instance, "m_waterLevel", point.y) : point.y);
						point.y = y;
					}
					float num11 = (float)(random2.NextDouble() * 360.0);
					Quaternion val = Quaternion.Euler(0f, num11, 0f);
					if (entry.TerrainTilt)
					{
						val = Quaternion.FromToRotation(Vector3.up, normal) * val;
					}
					float scale = Mathf.Lerp(min, max, (float)random2.NextDouble());
					num7++;
					if (!IsErased(point))
					{
						list.Add(new Placement
						{
							Position = point,
							Rotation = val,
							Scale = scale
						});
					}
				}
			}
			return list;
		}

		private int CreateUniquePlacementSeed()
		{
			//IL_0091: 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)
			int num = 17;
			ZDO val = (((Object)(object)_znv != (Object)null && _znv.IsValid()) ? _znv.GetZDO() : null);
			num = ((val == null) ? (num * 31 + Environment.TickCount) : (num * 31 + ((object)Unsafe.As<ZDOID, ZDOID>(ref val.m_uid)/*cast due to .constrained prefix*/).GetHashCode()));
			num = num * 31 + ClutterCatalog.StableHash(((Object)(object)_definition != (Object)null) ? _definition.ClutterId : ClutterId);
			num = num * 31 + Mathf.RoundToInt(((Component)this).transform.position.x * 100f);
			num = num * 31 + Mathf.RoundToInt(((Component)this).transform.position.z * 100f);
			if (num == 0)
			{
				num = 1;
			}
			return num;
		}

		private static double Frac(double value)
		{
			return value - Math.Floor(value);
		}

		private int ResolveTargetCount(DiscoveredClutter entry)
		{
			if (TargetCount > 0)
			{
				return Mathf.Min(TargetCount, 8192);
			}
			TargetCount = ComputeTargetCount(entry);
			if ((Object)(object)_znv != (Object)null && _znv.IsValid() && _znv.IsOwner())
			{
				ZDO zDO = _znv.GetZDO();
				if (zDO != null)
				{
					zDO.Set("fp_count", TargetCount);
					zDO.Set("fp_version", 7);
				}
			}
			return TargetCount;
		}

		private int ComputeTargetCount(DiscoveredClutter entry)
		{
			float num = (((Object)(object)ClutterSystem.instance != (Object)null) ? ReflectionUtils.GetFieldValue(ClutterSystem.instance, "m_amountScale", 1f) : 1f);
			if (num <= 0f)
			{
				num = 1f;
			}
			float num2 = (((Object)(object)ClutterSystem.instance != (Object)null) ? ReflectionUtils.GetFieldValue(ClutterSystem.instance, "m_grassPatchSize", Radius * 2f) : (Radius * 2f));
			num2 = Mathf.Max(0.5f, num2);
			float num3 = (float)Math.PI * Radius * Radius;
			float num4 = num2 * num2;
			float num5 = ((num4 > 0.001f) ? (num3 / num4) : 1f);
			float num6 = (float)Mathf.Max(1, entry.Amount) * num * Mathf.Max(0.01f, DensityMultiplier) * num5;
			int num7 = Mathf.Max(1, Mathf.RoundToInt(num6));
			return Mathf.Min(num7, 8192);
		}

		private void BuildNativeInstanceRendererVisuals(DiscoveredClutter entry, List<Placement> placements)
		{
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = FindOrCreateVisualTemplate(entry);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			val.SetActive(false);
			int num = 0;
			int num2 = 0;
			while (num < placements.Count)
			{
				int num3 = Mathf.Min(1023, placements.Count - num);
				GameObject val2;
				if (num2 == 0)
				{
					val2 = val;
				}
				else
				{
					val2 = PrefabFactory.CreateClutterVisualTemplate(entry.Prefab, GetExtraVisualRoot());
					if ((Object)(object)val2 == (Object)null)
					{
						break;
					}
					((Object)val2).name = "FP_IR_Batch_" + num2;
				}
				val2.SetActive(false);
				InstanceRenderer[] componentsInChildren = val2.GetComponentsInChildren<InstanceRenderer>(true);
				if (componentsInChildren == null || componentsInChildren.Length == 0)
				{
					if (num2 > 0)
					{
						Object.Destroy((Object)(object)val2);
					}
					break;
				}
				foreach (InstanceRenderer val3 in componentsInChildren)
				{
					if (!((Object)(object)val3 == (Object)null))
					{
						val3.Clear();
						if ((Object)(object)val3.m_material != (Object)null)
						{
							val3.m_material.enableInstancing = true;
						}
						for (int j = 0; j < num3; j++)
						{
							Placement placement = placements[num + j];
							val3.AddInstance(placement.Position, placement.Rotation, placement.Scale);
						}
					}
				}
				val2.SetActive(true);
				num += num3;
				num2++;
			}
		}

		private void BuildFallbackVisuals(DiscoveredClutter entry, List<Placement> placements)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = FindOrCreateVisualTemplate(entry);
			if ((Object)(object)val != (Object)null)
			{
				val.SetActive(false);
			}
			Transform extraVisualRoot = GetExtraVisualRoot();
			int num = Mathf.Min(placements.Count, 512);
			for (int i = 0; i < num; i++)
			{
				Placement placement = placements[i];
				GameObject val2 = Object.Instantiate<GameObject>(entry.Prefab, placement.Position, placement.Rotation, extraVisualRoot);
				((Object)val2).name = "FP_Fallback_" + i;
				PrefabFactory.SanitizeClutterVisual(val2.transform);
				val2.transform.localScale = val2.transform.localScale * placement.Scale;
				val2.SetActive(true);
			}
		}

		private GameObject FindOrCreateVisualTemplate(DiscoveredClutter entry)
		{
			Transform val = ((Component)this).transform.Find("_FP_ClutterTemplate");
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).gameObject;
			}
			return PrefabFactory.CreateClutterVisualTemplate(entry.Prefab, ((Component)this).transform);
		}

		private Transform GetExtraVisualRoot()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			if ((Object)(object)_extraVisualRoot != (Object)null)
			{
				return _extraVisualRoot;
			}
			Transform val = ((Component)this).transform.Find("_FP_ExtraVisuals");
			if ((Object)(object)val != (Object)null)
			{
				_extraVisualRoot = val;
				return _extraVisualRoot;
			}
			GameObject val2 = new GameObject("_FP_ExtraVisuals");
			val2.transform.SetParent(((Component)this).transform, false);
			_extraVisualRoot = val2.transform;
			return _extraVisualRoot;
		}

		private void ClearGeneratedVisuals()
		{
			Transform val = ((Component)this).transform.Find("_FP_ClutterTemplate");
			if ((Object)(object)val != (Object)null)
			{
				InstanceRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<InstanceRenderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					if ((Object)(object)componentsInChildren[i] != (Object)null)
					{
						componentsInChildren[i].Clear();
					}
				}
				((Component)val).gameObject.SetActive(false);
			}
			Transform val2 = ((Component)this).transform.Find("_FP_ExtraVisuals");
			if ((Object)(object)val2 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val2).gameObject);
				_extraVisualRoot = null;
			}
		}

		private void HidePlacementGhostVisuals()
		{
			Transform val = ((Component)this).transform.Find("_GhostOnly");
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(false);
			}
		}

		private bool RefreshEraseDataFromZDO()
		{
			if ((Object)(object)_znv == (Object)null || !_znv.IsValid())
			{
				return false;
			}
			ZDO zDO = _znv.GetZDO();
			if (zDO == null)
			{
				return false;
			}
			string text = zDO.GetString("fp_erase", string.Empty);
			if (text == _eraseDataCache)
			{
				return false;
			}
			LoadEraseData(text);
			return true;
		}

		private void LoadEraseData(string data)
		{
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			_eraseDataCache = data ?? string.Empty;
			_eraseCircles.Clear();
			if (string.IsNullOrEmpty(_eraseDataCache))
			{
				return;
			}
			string[] array = _eraseDataCache.Split(new char[1] { ';' });
			for (int i = 0; i < array.Length; i++)
			{
				if (!string.IsNullOrEmpty(array[i]))
				{
					string[] array2 = array[i].Split(new char[1] { ',' });
					if (array2.Length == 3 && float.TryParse(array2[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) && !(result3 <= 0f))
					{
						_eraseCircles.Add(new EraseCircle
						{
							LocalCenter = new Vector2(result, result2),
							Radius = result3
						});
					}
				}
			}
		}

		private bool AddEraseCircle(Vector2 localCenter, float radius)
		{
			//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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			radius = Mathf.Max(0.25f, radius);
			for (int i = 0; i < _eraseCircles.Count; i++)
			{
				EraseCircle eraseCircle = _eraseCircles[i];
				float num = Vector2.Distance(eraseCircle.LocalCenter, localCenter);
				if (num + radius <= eraseCircle.Radius)
				{
					return false;
				}
			}
			for (int num2 = _eraseCircles.Count - 1; num2 >= 0; num2--)
			{
				EraseCircle eraseCircle2 = _eraseCircles[num2];
				float num3 = Vector2.Distance(eraseCircle2.LocalCenter, localCenter);
				if (num3 + eraseCircle2.Radius <= radius)
				{
					_eraseCircles.RemoveAt(num2);
				}
			}
			_eraseCircles.Add(new EraseCircle
			{
				LocalCenter = localCenter,
				Radius = radius
			});
			if (_eraseCircles.Count > 128)
			{
				_eraseCircles.RemoveRange(0, _eraseCircles.Count - 128);
			}
			return true;
		}

		private string SerializeEraseCircles()
		{
			if (_eraseCircles.Count == 0)
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(_eraseCircles.Count * 24);
			for (int i = 0; i < _eraseCircles.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(';');
				}
				EraseCircle eraseCircle = _eraseCircles[i];
				stringBuilder.Append(eraseCircle.LocalCenter.x.ToString("R", CultureInfo.InvariantCulture));
				stringBuilder.Append(',');
				stringBuilder.Append(eraseCircle.LocalCenter.y.ToString("R", CultureInfo.InvariantCulture));
				stringBuilder.Append(',');
				stringBuilder.Append(eraseCircle.Radius.ToString("R", CultureInfo.InvariantCulture));
			}
			return stringBuilder.ToString();
		}

		private bool IsErased(Vector3 worldPoint)
		{
			//IL_001a: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if (_eraseCircles.Count == 0)
			{
				return false;
			}
			Vector3 val = worldPoint - ((Component)this).transform.position;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(val.x, val.z);
			for (int i = 0; i < _eraseCircles.Count; i++)
			{
				EraseCircle eraseCircle = _eraseCircles[i];
				Vector2 val3 = val2 - eraseCircle.LocalCenter;
				if (((Vector2)(ref val3)).sqrMagnitude <= eraseCircle.Radius * eraseCircle.Radius)
				{
					return true;
				}
			}
			return false;
		}

		private static void NormalizeScaleRange(ref float min, ref float max)
		{
			if (min <= 0f && max <= 0f)
			{
				min = 1f;
				max = 1f;
				return;
			}
			if (min <= 0f)
			{
				min = max;
			}
			if (max <= 0f)
			{
				max = min;
			}
			if (max < min)
			{
				float num = min;
				min = max;
				max = num;
			}
		}

		private static int StablePositionSeed(string id, Vector3 position)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			int num = 17;
			num = num * 31 + ClutterCatalog.StableHash(id);
			num = num * 31 + Mathf.RoundToInt(position.x * 100f);
			num = num * 31 + Mathf.RoundToInt(position.y * 100f);
			num = num * 31 + Mathf.RoundToInt(position.z * 100f);
			return (num == 0) ? 1 : num;
		}
	}
	[RequireComponent(typeof(FlowerPaintBrush))]
	public sealed class FlowerPaintPlacementGhost : MonoBehaviour
	{
		private FlowerPaintBrush _brush;

		private FlowerPaintGhostScaler _scaler;

		private ZNetView _znv;

		private LineRenderer _ring;

		private readonly List<LineRenderer> _removeLines = new List<LineRenderer>();

		private Material _lineMaterial;

		private float _lastAppliedRadius = -1f;

		private bool _registeredAsActivePlacementGhost;

		private static int _activePlacementGhostCount;

		private void Awake()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			_brush = ((Component)this).GetComponent<FlowerPaintBrush>();
			_scaler = ((Component)this).GetComponent<FlowerPaintGhostScaler>();
			_znv = ((Component)this).GetComponent<ZNetView>();
			if ((Object)(object)_znv != (Object)null && _znv.IsValid())
			{
				((Behaviour)this).enabled = false;
				return;
			}
			FlowerPaintBrushSettings.EnsureInitialized();
			ApplyRuntimeBrushSettings(forceScale: true);
			Shader val = Shader.Find("Sprites/Default");
			if (!((Object)(object)val == (Object)null))
			{
				_lineMaterial = new Material(val);
				GameObject val2 = new GameObject("FP_RangeRing");
				val2.transform.SetParent(((Component)this).transform, false);
				_ring = val2.AddComponent<LineRenderer>();
				_ring.loop = true;
				_ring.useWorldSpace = true;
				_ring.widthMultiplier = 0.05f;
				((Renderer)_ring).material = _lineMaterial;
				_ring.positionCount = 48;
				((Renderer)_ring).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)_ring).receiveShadows = false;
				Color val3 = (((Object)(object)_brush != (Object)null && _brush.RemoveMode) ? new Color(1f, 0.2f, 0.2f, 0.9f) : new Color(0.2f, 1f, 0.2f, 0.9f));
				_ring.startColor = val3;
				_ring.endColor = val3;
			}
		}

		private void OnEnable()
		{
			if ((Object)(object)_znv == (Object)null || !_znv.IsValid())
			{
				RegisterActivePlacementGhost();
				SetPlacedMarkerColliders(enabledState: false);
			}
		}

		private void OnDisable()
		{
			UnregisterActivePlacementGhost();
			if ((Object)(object)_znv == (Object)null || !_znv.IsValid())
			{
				SetPlacedMarkerColliders(enabledState: true);
			}
		}

		private void OnDestroy()
		{
			UnregisterActivePlacementGhost();
			if ((Object)(object)_znv == (Object)null || !_znv.IsValid())
			{
				SetPlacedMarkerColliders(enabledState: true);
			}
			if ((Object)(object)_lineMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_lineMaterial);
			}
		}

		private void Update()
		{
			if ((Object)(object)_brush == (Object)null || (Object)(object)_ring == (Object)null)
			{
				return;
			}
			if ((Object)(object)_znv != (Object)null && _znv.IsValid())
			{
				((Renderer)_ring).enabled = false;
				ClearRemovePreview();
				((Behaviour)this).enabled = false;
				return;
			}
			SetPlacedMarkerColliders(enabledState: false);
			HandleBrushInput();
			ApplyRuntimeBrushSettings(forceScale: false);
			DrawRing();
			if (_brush.RemoveMode)
			{
				DrawRemovePreview();
			}
			else
			{
				ClearRemovePreview();
			}
		}

		private void HandleBrushInput()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (Console.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()))
			{
				return;
			}
			float y = Input.mouseScrollDelta.y;
			if (Mathf.Abs(y) < 0.001f)
			{
				return;
			}
			bool flag = IsCtrlHeld();
			bool flag2 = IsShiftHeld();
			if (flag)
			{
				if (FlowerPaintBrushSettings.AdjustRadius(y))
				{
					ApplyRuntimeBrushSettings(forceScale: true);
					ShowSettingMessage("FlowerPainter radius: " + FlowerPaintBrushSettings.Radius.ToString("0.0") + " m");
				}
			}
			else if (flag2 && !_brush.RemoveMode && FlowerPaintBrushSettings.AdjustDensity(y))
			{
				ApplyRuntimeBrushSettings(forceScale: false);
				ShowSettingMessage("FlowerPainter density: x" + FlowerPaintBrushSettings.DensityMultiplier.ToString("0.00"));
			}
		}

		internal static bool ShouldConsumeMouseWheel()
		{
			if (_activePlacementGhostCount <= 0)
			{
				return false;
			}
			if (Hud.IsPieceSelectionVisible())
			{
				return false;
			}
			if (Console.IsVisible())
			{
				return false;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return false;
			}
			return IsCtrlHeld() || IsShiftHeld();
		}

		private static bool IsCtrlHeld()
		{
			return ZInput.GetKey((KeyCode)306, true) || ZInput.GetKey((KeyCode)305, true);
		}

		private static bool IsShiftHeld()
		{
			return ZInput.GetKey((KeyCode)304, true) || ZInput.GetKey((KeyCode)303, true);
		}

		private void RegisterActivePlacementGhost()
		{
			if (!_registeredAsActivePlacementGhost)
			{
				_registeredAsActivePlacementGhost = true;
				_activePlacementGhostCount++;
			}
		}

		private void UnregisterActivePlacementGhost()
		{
			if (_registeredAsActivePlacementGhost)
			{
				_registeredAsActivePlacementGhost = false;
				_activePlacementGhostCount = Mathf.Max(0, _activePlacementGhostCount - 1);
			}
		}

		private void ApplyRuntimeBrushSettings(bool forceScale)
		{
			if (!((Object)(object)_brush == (Object)null))
			{
				_brush.Radius = FlowerPaintBrushSettings.Radius;
				if (!_brush.RemoveMode)
				{
					_brush.DensityMultiplier = FlowerPaintBrushSettings.DensityMultiplier;
				}
				if (!((Object)(object)_scaler == (Object)null) && (forceScale || !Mathf.Approximately(_lastAppliedRadius, _brush.Radius)))
				{
					_lastAppliedRadius = _brush.Radius;
					_scaler.Radius = _brush.Radius;
					_scaler.Apply();
				}
			}
		}

		private static void ShowSettingMessage(string text)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null);
			}
		}

		private static void SetPlacedMarkerColliders(bool enabledState)
		{
			for (int i = 0; i < FlowerPaintRegistry.All.Count; i++)
			{
				FlowerPaintMarker flowerPaintMarker = FlowerPaintRegistry.All[i];
				if ((Object)(object)flowerPaintMarker != (Object)null)
				{
					flowerPaintMarker.SetPlacementColliderEnabled(enabledState);
				}
			}
		}

		private void DrawRing()
		{
			//IL_0046: 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_0067: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			int positionCount = _ring.positionCount;
			float num = Mathf.Max(0.5f, _brush.Radius);
			for (int i = 0; i < positionCount; i++)
			{
				float num2 = (float)i / (float)positionCount;
				float num3 = num2 * (float)Math.PI * 2f;
				Vector3 val = ((Component)this).transform.position + new Vector3(Mathf.Cos(num3) * num, 0f, Mathf.Sin(num3) * num);
				if (FlowerPaintSystem.TryGetTerrainPoint(val, out var point, out var normal))
				{
					_ring.SetPosition(i, point + normal * 0.05f);
				}
				else
				{
					_ring.SetPosition(i, val + Vector3.up * 0.05f);
				}
			}
		}

		private void DrawRemovePreview()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0083: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing referen