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 DefaultBrushRadius; internal static ConfigEntry 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("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("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(); 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(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(sourcePrefab, val.transform); ((Object)val2).hideFlags = (HideFlags)61; Behaviour[] componentsInChildren = val2.GetComponentsInChildren(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(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 list = new List(); 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(); val4.sharedMesh = val2.m_mesh; MeshRenderer val5 = val3.AddComponent(); ((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(); ((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(); 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(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(); 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 Cached = new List(); private static readonly Dictionary ById = new Dictionary(StringComparer.Ordinal); private static int _signature; public static IList Entries => Cached; public static void Invalidate() { _signature = 0; } public static bool EnsureDiscovered() { ClutterSystem val = (((Object)(object)ClutterSystem.instance != (Object)null) ? ClutterSystem.instance : Object.FindFirstObjectByType()); 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 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 dictionary = new Dictionary(StringComparer.Ordinal); Dictionary dictionary2 = new Dictionary(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(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 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(); val2.m_persistent = true; val.AddComponent(); 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(); val2.m_persistent = true; Piece piece = val.AddComponent(); ConfigurePiece(piece, entry, text2); WearNTear wear = val.AddComponent(); ConfigureWearNTear(wear); SphereCollider val3 = val.AddComponent(); ((Collider)val3).isTrigger = false; val3.radius = 0.65f; val3.center = new Vector3(0f, 0.35f, 0f); FlowerPaintBrush flowerPaintBrush = val.AddComponent(); 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(); 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.Radius = flowerPaintBrush.Radius; val.AddComponent(); 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(); 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.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.Radius = flowerPaintBrush.Radius; val.AddComponent(); 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(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(); 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(); 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(); 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(((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 PiecePrefabs = new Dictionary(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 entries = ClutterCatalog.Entries; List 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 CollectTargetTables() { List result = new List(); AddTableFromTool(result, "Cultivator", includeObjectDb: true); return result; } private static void RemoveFlowerPainterPiecesFromHoe() { List list = new List(); 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 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 result, GameObject tool) { if ((Object)(object)tool == (Object)null) { return; } ItemDrop component = tool.GetComponent(); 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(); 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 All = new List(); 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 _eraseCircles = new List(); 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(); _definition = ((Component)this).GetComponent(); 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(); 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(); } 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 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 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 list = new List(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(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 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(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 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(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(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 _removeLines = new List(); 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(); _scaler = ((Component)this).GetComponent(); _znv = ((Component)this).GetComponent(); 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(); _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 references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) List list = new List(); float radius = _brush.Radius; Vector3 position = ((Component)this).transform.position; for (int i = 0; i < FlowerPaintRegistry.All.Count; i++) { FlowerPaintMarker flowerPaintMarker = FlowerPaintRegistry.All[i]; if (!((Object)(object)flowerPaintMarker == (Object)null) && flowerPaintMarker.OverlapsHorizontalCircle(position, radius)) { list.Add(flowerPaintMarker); } } while (_removeLines.Count < list.Count) { GameObject val = new GameObject("FP_RemovePreview"); val.transform.SetParent(((Component)this).transform, false); LineRenderer val2 = val.AddComponent(); val2.useWorldSpace = true; val2.positionCount = 2; val2.widthMultiplier = 0.03f; ((Renderer)val2).material = _lineMaterial; ((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val2).receiveShadows = false; val2.startColor = new Color(1f, 0.25f, 0.25f, 0.9f); val2.endColor = new Color(1f, 0.25f, 0.25f, 0.1f); _removeLines.Add(val2); } for (int j = 0; j < _removeLines.Count; j++) { if (j >= list.Count) { ((Renderer)_removeLines[j]).enabled = false; continue; } FlowerPaintMarker flowerPaintMarker2 = list[j]; if (!FlowerPaintSystem.TryGetTerrainPoint(((Component)flowerPaintMarker2).transform.position, out var point, out var _)) { point = ((Component)flowerPaintMarker2).transform.position; } ((Renderer)_removeLines[j]).enabled = true; _removeLines[j].SetPosition(0, point + Vector3.up * 0.05f); _removeLines[j].SetPosition(1, point + Vector3.up * 1.2f); } } private void ClearRemovePreview() { for (int i = 0; i < _removeLines.Count; i++) { if ((Object)(object)_removeLines[i] != (Object)null) { ((Renderer)_removeLines[i]).enabled = false; } } } } }