Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of balrond flower painter v0.1.0
plugins/BalrondFlowerPainter.dll
Decompiled 16 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using FlowerPainter.Components; using FlowerPainter.Data; using FlowerPainter.Managers; using FlowerPainter.Runtime; using FlowerPainter.Utils; using HarmonyLib; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace FlowerPainter { [BepInPlugin("balrond.astafaraios.BalrondFlowerPainter", "Balrond Flower Painter", "0.1.0")] public sealed class Plugin : BaseUnityPlugin { public const string ModGuid = "balrond.astafaraios.BalrondFlowerPainter"; public const string ModName = "Balrond Flower Painter"; public const string ModVersion = "0.1.0"; internal static Plugin Instance; internal static Harmony Harmony; internal static ConfigEntry<float> DefaultBrushRadius; internal static ConfigEntry<float> DefaultDensityMultiplier; private void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown Instance = this; DefaultBrushRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Painting", "DefaultBrushRadius", 4f, "Default FlowerPainter brush radius in metres. Ctrl + mouse wheel changes it at runtime (0.5-20 m). Larger radius automatically paints proportionally more instances."); DefaultDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Painting", "DefaultBrushDensity", 2f, "Default painted clutter density multiplier. 1.0 follows the ClutterSystem density basis; values above 1 are denser. Shift + mouse wheel changes it at runtime (0.25-8x)."); Harmony = new Harmony("balrond.astafaraios.BalrondFlowerPainter"); Harmony.PatchAll(); ((Component)this).gameObject.AddComponent<FlowerPaintSystem>(); Debug.Log((object)"Balrond Flower Painter 0.1.0 loaded"); } private void OnDestroy() { if (Harmony != null) { Harmony.UnpatchSelf(); } } } } namespace FlowerPainter.Utils { public static class DisplayNameUtils { public static string FromPrefabName(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return "Unknown"; } string value = prefabName; value = RemoveSuffix(value, "_bal"); value = value.Replace("_", " "); value = SplitCamelCaseAndDigits(value); value = NormalizeSpaces(value); return ToTitleLike(value); } private static string RemoveSuffix(string value, string suffix) { if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(suffix)) { return value; } if (value.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)) { return value.Substring(0, value.Length - suffix.Length); } return value; } private static string SplitCamelCaseAndDigits(string value) { StringBuilder stringBuilder = new StringBuilder(value.Length + 8); for (int i = 0; i < value.Length; i++) { char c = value[i]; char c2 = ((i > 0) ? value[i - 1] : '\0'); char c3 = ((i < value.Length - 1) ? value[i + 1] : '\0'); if (i > 0 && ((char.IsLower(c2) && char.IsUpper(c)) || (char.IsLetter(c2) && char.IsDigit(c)) || (char.IsDigit(c2) && char.IsLetter(c)) || (char.IsUpper(c2) && char.IsUpper(c) && char.IsLower(c3)))) { stringBuilder.Append(' '); } stringBuilder.Append(c); } return stringBuilder.ToString(); } private static string NormalizeSpaces(string value) { StringBuilder stringBuilder = new StringBuilder(value.Length); bool flag = false; foreach (char c in value) { if (char.IsWhiteSpace(c)) { if (!flag) { stringBuilder.Append(' '); flag = true; } } else { stringBuilder.Append(c); flag = false; } } return stringBuilder.ToString().Trim(); } private static string ToTitleLike(string value) { if (string.IsNullOrEmpty(value)) { return value; } StringBuilder stringBuilder = new StringBuilder(value.Length); bool flag = true; foreach (char c in value) { if (c == ' ') { stringBuilder.Append(c); flag = true; } else if (flag) { stringBuilder.Append(char.ToUpperInvariant(c)); flag = false; } else { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } } public static class PrefabPreviewRenderer { private const int PreviewLayer = 31; public static Sprite CreatePreviewSprite(DiscoveredClutter entry, int size = 128) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) Texture2D val = CreatePreviewTexture(entry, size); if ((Object)(object)val == (Object)null) { return null; } return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } public static Sprite CreatePreviewSprite(GameObject sourcePrefab, int size = 128) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) Texture2D val = CreatePreviewTexture(sourcePrefab, size); if (!IsUsablePreview(val)) { DestroyTexture(val); return null; } return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } public static Texture2D CreatePreviewTexture(DiscoveredClutter entry, int size = 128) { if (entry == null || (Object)(object)entry.Prefab == (Object)null) { return null; } InstanceRenderer[] componentsInChildren = entry.Prefab.GetComponentsInChildren<InstanceRenderer>(true); if (componentsInChildren != null && componentsInChildren.Length != 0) { Texture2D val = RenderInstancedDefinition(componentsInChildren, RepresentativeScale(entry), size); if (IsUsablePreview(val)) { return val; } DestroyTexture(val); } Texture2D val2 = CreatePreviewTexture(entry.Prefab, size); if (IsUsablePreview(val2)) { return val2; } DestroyTexture(val2); return null; } public static Texture2D CreatePreviewTexture(GameObject sourcePrefab, int size = 128) { if ((Object)(object)sourcePrefab == (Object)null) { return null; } GameObject val = null; GameObject val2 = null; try { val = CreatePreviewRoot(); val2 = Object.Instantiate<GameObject>(sourcePrefab, val.transform); ((Object)val2).hideFlags = (HideFlags)61; Behaviour[] componentsInChildren = val2.GetComponentsInChildren<Behaviour>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { componentsInChildren[i].enabled = false; } } SetPreviewHierarchyActive(val2.transform); SetLayerRecursively(val2, 31); Renderer[] componentsInChildren2 = val2.GetComponentsInChildren<Renderer>(true); if (componentsInChildren2 == null || componentsInChildren2.Length == 0) { return null; } for (int j = 0; j < componentsInChildren2.Length; j++) { if ((Object)(object)componentsInChildren2[j] != (Object)null) { componentsInChildren2[j].enabled = true; } } return RenderRoot(val, componentsInChildren2, size); } catch (Exception ex) { Debug.LogWarning((object)("FlowerPainter standard icon preview failed for '" + ((Object)sourcePrefab).name + "': " + ex.Message)); return null; } finally { if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } } } private static Texture2D RenderInstancedDefinition(InstanceRenderer[] sources, float scaleMultiplier, int size) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; try { val = CreatePreviewRoot(); List<Renderer> list = new List<Renderer>(); for (int i = 0; i < sources.Length; i++) { InstanceRenderer val2 = sources[i]; if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.m_mesh == (Object)null) && !((Object)(object)val2.m_material == (Object)null)) { GameObject val3 = new GameObject("FP_InstancedPreview_" + i); ((Object)val3).hideFlags = (HideFlags)61; val3.layer = 31; val3.transform.SetParent(val.transform, false); val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; val3.transform.localScale = val2.m_scale * scaleMultiplier; MeshFilter val4 = val3.AddComponent<MeshFilter>(); val4.sharedMesh = val2.m_mesh; MeshRenderer val5 = val3.AddComponent<MeshRenderer>(); ((Renderer)val5).sharedMaterial = val2.m_material; ((Renderer)val5).shadowCastingMode = val2.m_shadowCasting; ((Renderer)val5).receiveShadows = true; list.Add((Renderer)(object)val5); } } if (list.Count == 0) { return null; } return RenderRoot(val, list.ToArray(), size); } catch (Exception ex) { Debug.LogWarning((object)("FlowerPainter InstanceRenderer icon preview failed: " + ex.Message)); return null; } finally { if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } } } private static GameObject CreatePreviewRoot() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown GameObject val = new GameObject("FP_PreviewRoot"); ((Object)val).hideFlags = (HideFlags)61; return val; } private static Texture2D RenderRoot(GameObject root, Renderer[] renderers, int size) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Expected O, but got Unknown //IL_01fd: Unknown result type (might be due to invalid IL or missing references) Camera val = null; RenderTexture val2 = null; RenderTexture active = RenderTexture.active; try { Bounds combinedBounds = GetCombinedBounds(renderers); val = new GameObject("FP_PreviewCamera").AddComponent<Camera>(); ((Object)((Component)val).gameObject).hideFlags = (HideFlags)61; ((Component)val).transform.SetParent(root.transform, false); val.clearFlags = (CameraClearFlags)2; val.backgroundColor = new Color(0f, 0f, 0f, 0f); val.nearClipPlane = 0.01f; val.farClipPlane = 1000f; val.cullingMask = int.MinValue; val.allowHDR = false; val.allowMSAA = false; CreateLight(root.transform, new Vector3(35f, -35f, 0f), 1.05f); CreateLight(root.transform, new Vector3(340f, 35f, 0f), 0.65f); Vector3 center = ((Bounds)(ref combinedBounds)).center; float num = Mathf.Max(new float[3] { ((Bounds)(ref combinedBounds)).extents.x, ((Bounds)(ref combinedBounds)).extents.y, ((Bounds)(ref combinedBounds)).extents.z }); num = Mathf.Max(num, 0.05f); Vector3 val3 = new Vector3(-0.9f, 0.55f, -0.9f); Vector3 normalized = ((Vector3)(ref val3)).normalized; float num2 = val.fieldOfView * ((float)Math.PI / 180f); float num3 = Mathf.Max(num * 2.8f, num / Mathf.Tan(num2 * 0.5f) * 1.25f); ((Component)val).transform.position = center - normalized * num3; ((Component)val).transform.LookAt(center); val2 = new RenderTexture(size, size, 24, (RenderTextureFormat)0); ((Object)val2).hideFlags = (HideFlags)61; val.targetTexture = val2; RenderTexture.active = val2; val.Render(); Texture2D val4 = new Texture2D(size, size, (TextureFormat)5, false, false); val4.ReadPixels(new Rect(0f, 0f, (float)size, (float)size), 0, 0); val4.Apply(false, false); return val4; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { val.targetTexture = null; } if ((Object)(object)val2 != (Object)null) { Object.DestroyImmediate((Object)(object)val2); } if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } } private static float RepresentativeScale(DiscoveredClutter entry) { float num = entry.ScaleMin; float num2 = entry.ScaleMax; if (num <= 0f && num2 <= 0f) { return 1f; } if (num2 <= 0f) { num2 = num; } if (num <= 0f) { num = num2; } if (num2 < num) { float num3 = num; num = num2; num2 = num3; } return (num + num2) * 0.5f; } private static Light CreateLight(Transform parent, Vector3 euler, float intensity) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("FP_PreviewLight"); ((Object)val).hideFlags = (HideFlags)61; val.transform.SetParent(parent, false); val.transform.rotation = Quaternion.Euler(euler); Light val2 = val.AddComponent<Light>(); val2.type = (LightType)1; val2.color = Color.white; val2.intensity = intensity; val2.shadows = (LightShadows)0; return val2; } private static Bounds GetCombinedBounds(Renderer[] renderers) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) bool flag = false; Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(Vector3.zero, Vector3.one * 0.1f); foreach (Renderer val in renderers) { if (!((Object)(object)val == (Object)null)) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } return bounds; } private static void SetPreviewHierarchyActive(Transform root) { if (!((Object)(object)root == (Object)null)) { ((Component)root).gameObject.SetActive(true); for (int i = 0; i < root.childCount; i++) { SetPreviewHierarchyActive(root.GetChild(i)); } } } private static void SetLayerRecursively(GameObject go, int layer) { if (!((Object)(object)go == (Object)null)) { go.layer = layer; for (int i = 0; i < go.transform.childCount; i++) { SetLayerRecursively(((Component)go.transform.GetChild(i)).gameObject, layer); } } } private static bool IsUsablePreview(Texture2D texture) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)texture == (Object)null) { return false; } try { Color32[] pixels = texture.GetPixels32(); if (pixels == null || pixels.Length == 0) { return false; } int num = 0; int num2 = Mathf.Max(12, pixels.Length / 1024); foreach (Color32 val in pixels) { if (val.a > 8) { num++; if (num >= num2) { return true; } } } } catch (Exception ex) { Debug.LogWarning((object)("FlowerPainter icon visibility check failed: " + ex.Message)); } return false; } private static void DestroyTexture(Texture2D texture) { if ((Object)(object)texture != (Object)null) { Object.DestroyImmediate((Object)(object)texture); } } } public static class ReflectionUtils { private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; public static object GetFieldValue(object target, string name) { if (target == null || string.IsNullOrEmpty(name)) { return null; } FieldInfo field = target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); return (field != null) ? field.GetValue(target) : null; } public static T GetFieldValue<T>(object target, string name, T fallback) { object fieldValue = GetFieldValue(target, name); return (fieldValue is T) ? ((T)fieldValue) : fallback; } public static IEnumerable EnumerateFieldCandidates(object target, params string[] names) { if (target == null) { yield break; } Type type = target.GetType(); int i = 0; while (i < names.Length) { FieldInfo field = type.GetField(names[i], BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null) && field.GetValue(target) is IEnumerable enumerable) { yield return enumerable; } int num = i + 1; i = num; } } public static MethodInfo FindMethod(Type type, string name, int parameterCount) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != name) && methodInfo.GetParameters().Length == parameterCount) { return methodInfo; } } return null; } public static string SafeName(string raw) { if (string.IsNullOrEmpty(raw)) { return "Unnamed"; } char[] array = raw.ToCharArray(); for (int i = 0; i < array.Length; i++) { if (!char.IsLetterOrDigit(array[i]) && array[i] != '_') { array[i] = '_'; } } return new string(array); } public static bool LooksLikeVegetationName(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return false; } string text = prefabName.ToLowerInvariant(); string[] array = new string[14] { "grass", "flower", "fern", "reed", "heath", "heather", "bush", "shrub", "plant", "herb", "weed", "thistle", "mush", "sapling" }; for (int i = 0; i < array.Length; i++) { if (text.Contains(array[i])) { return true; } } return false; } } public static class TextureMaker { public static Sprite CreateBrushIcon(string text, int seed) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)5, false); ((Texture)val).filterMode = (FilterMode)0; Random random = new Random(seed); Color val2 = Color.HSVToRGB((float)random.NextDouble(), 0.55f, 0.9f); Color black = Color.black; Color white = Color.white; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { bool flag = j < 4 || i < 4 || j > 59 || i > 59; val.SetPixel(j, i, flag ? black : val2); } } DrawBlockLetter(val, MakeTag(text), white); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f); } public static Sprite CreateFlowerGlyphIcon(int size = 64) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) size = Mathf.Max(32, size); Texture2D val = new Texture2D(size, size, (TextureFormat)5, false); ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; Color val2 = default(Color); ((Color)(ref val2))..ctor(0f, 0f, 0f, 0f); Color color = default(Color); ((Color)(ref color))..ctor(0.95f, 0.95f, 0.95f, 1f); Color color2 = default(Color); ((Color)(ref color2))..ctor(1f, 0.72f, 0.12f, 1f); Color color3 = default(Color); ((Color)(ref color3))..ctor(0.28f, 0.72f, 0.28f, 1f); Color[] array = (Color[])(object)new Color[size * size]; for (int i = 0; i < array.Length; i++) { array[i] = val2; } val.SetPixels(array); float num = (float)size * 0.5f; float num2 = (float)size * 0.6f; float num3 = (float)size * 0.14f; float radius = (float)size * 0.115f; for (int j = 0; j < 6; j++) { float num4 = (float)j * (float)Math.PI * 2f / 6f; DrawDisc(val, num + Mathf.Cos(num4) * num3, num2 + Mathf.Sin(num4) * num3, radius, color); } DrawDisc(val, num, num2, (float)size * 0.105f, color2); DrawThickLine(val, num, num2 - (float)size * 0.1f, num, (float)size * 0.17f, Mathf.Max(2f, (float)size * 0.045f), color3); DrawLeaf(val, num - (float)size * 0.03f, (float)size * 0.34f, -1f, color3); DrawLeaf(val, num + (float)size * 0.03f, (float)size * 0.27f, 1f, color3); val.Apply(false, false); return Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), (float)size); } private static void DrawDisc(Texture2D texture, float cx, float cy, float radius, Color color) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Max(0, Mathf.FloorToInt(cx - radius)); int num2 = Mathf.Min(((Texture)texture).width - 1, Mathf.CeilToInt(cx + radius)); int num3 = Mathf.Max(0, Mathf.FloorToInt(cy - radius)); int num4 = Mathf.Min(((Texture)texture).height - 1, Mathf.CeilToInt(cy + radius)); float num5 = radius * radius; for (int i = num3; i <= num4; i++) { for (int j = num; j <= num2; j++) { float num6 = (float)j - cx; float num7 = (float)i - cy; if (num6 * num6 + num7 * num7 <= num5) { texture.SetPixel(j, i, color); } } } } private static void DrawThickLine(Texture2D texture, float x0, float y0, float x1, float y1, float width, Color color) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Max(1, Mathf.CeilToInt(Vector2.Distance(new Vector2(x0, y0), new Vector2(x1, y1)))); for (int i = 0; i <= num; i++) { float num2 = (float)i / (float)num; DrawDisc(texture, Mathf.Lerp(x0, x1, num2), Mathf.Lerp(y0, y1, num2), width * 0.5f, color); } } private static void DrawLeaf(Texture2D texture, float x, float y, float direction, Color color) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) float num = (float)((Texture)texture).width * 0.15f; float width = (float)((Texture)texture).width * 0.065f; float x2 = x + direction * num; float y2 = y + num * 0.45f; DrawThickLine(texture, x, y, x2, y2, width, color); } private static string MakeTag(string source) { if (string.IsNullOrEmpty(source)) { return "FP"; } string[] array = source.Replace("_", " ").Replace("-", " ").Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 1) { string text = array[0]; return (text.Length >= 2) ? text.Substring(0, 2).ToUpperInvariant() : text.ToUpperInvariant(); } return (array[0][0].ToString() + array[1][0]).ToUpperInvariant(); } private static void DrawBlockLetter(Texture2D texture, string tag, Color color) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) int num = 14; int y = 16; int num2 = 14; for (int i = 0; i < tag.Length && i < 2; i++) { DrawGlyph(texture, tag[i], num + i * num2, y, color); } } private static void DrawGlyph(Texture2D texture, char c, int x, int y, Color color) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) bool[,] array = GlyphFor(c); int length = array.GetLength(0); int length2 = array.GetLength(1); for (int i = 0; i < length; i++) { for (int j = 0; j < length2; j++) { if (!array[i, j]) { continue; } for (int k = 0; k < 3; k++) { for (int l = 0; l < 3; l++) { texture.SetPixel(x + i * 3 + k, y + (length2 - 1 - j) * 3 + l, color); } } } } } private static bool[,] GlyphFor(char c) { string[] array = char.ToUpperInvariant(c) switch { 'A' => new string[5] { "01110", "10001", "11111", "10001", "10001" }, 'B' => new string[5] { "11110", "10001", "11110", "10001", "11110" }, 'C' => new string[5] { "01111", "10000", "10000", "10000", "01111" }, 'D' => new string[5] { "11110", "10001", "10001", "10001", "11110" }, 'E' => new string[5] { "11111", "10000", "11110", "10000", "11111" }, 'F' => new string[5] { "11111", "10000", "11110", "10000", "10000" }, 'G' => new string[5] { "01111", "10000", "10011", "10001", "01111" }, 'H' => new string[5] { "10001", "10001", "11111", "10001", "10001" }, 'I' => new string[5] { "11111", "00100", "00100", "00100", "11111" }, 'J' => new string[5] { "00111", "00010", "00010", "10010", "01100" }, 'K' => new string[5] { "10001", "10010", "11100", "10010", "10001" }, 'L' => new string[5] { "10000", "10000", "10000", "10000", "11111" }, 'M' => new string[5] { "10001", "11011", "10101", "10001", "10001" }, 'N' => new string[5] { "10001", "11001", "10101", "10011", "10001" }, 'O' => new string[5] { "01110", "10001", "10001", "10001", "01110" }, 'P' => new string[5] { "11110", "10001", "11110", "10000", "10000" }, 'Q' => new string[5] { "01110", "10001", "10001", "10011", "01111" }, 'R' => new string[5] { "11110", "10001", "11110", "10010", "10001" }, 'S' => new string[5] { "01111", "10000", "01110", "00001", "11110" }, 'T' => new string[5] { "11111", "00100", "00100", "00100", "00100" }, 'U' => new string[5] { "10001", "10001", "10001", "10001", "01110" }, 'V' => new string[5] { "10001", "10001", "10001", "01010", "00100" }, 'W' => new string[5] { "10001", "10001", "10101", "11011", "10001" }, 'X' => new string[5] { "10001", "01010", "00100", "01010", "10001" }, 'Y' => new string[5] { "10001", "01010", "00100", "00100", "00100" }, 'Z' => new string[5] { "11111", "00010", "00100", "01000", "11111" }, _ => new string[5] { "11111", "10001", "00110", "00000", "00100" }, }; bool[,] array2 = new bool[5, 5]; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { array2[j, i] = array[i][j] == '1'; } } return array2; } } } namespace FlowerPainter.Patches { [HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")] public static class FlowerPainterMouseWheelCapturePatch { private static void Postfix(ref float __result) { if (!(Mathf.Abs(__result) < 0.001f) && FlowerPaintPlacementGhost.ShouldConsumeMouseWheel()) { __result = 0f; } } } [HarmonyPatch(typeof(Player), "PlacePiece", new Type[] { typeof(Piece), typeof(Vector3), typeof(Quaternion), typeof(bool) })] public static class PlayerPlacePiecePatch { private static bool Prefix(Piece piece, Vector3 pos) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)piece == (Object)null) { return true; } FlowerPaintBrush component = ((Component)piece).GetComponent<FlowerPaintBrush>(); if ((Object)(object)component == (Object)null) { return true; } if (!component.RemoveMode) { return true; } FlowerPaintBrushSettings.EnsureInitialized(); ErasePaintedClutter(pos, FlowerPaintBrushSettings.Radius); return false; } private static void ErasePaintedClutter(Vector3 position, float radius) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) radius = Mathf.Max(0.25f, radius); for (int num = FlowerPaintRegistry.All.Count - 1; num >= 0; num--) { FlowerPaintMarker flowerPaintMarker = FlowerPaintRegistry.All[num]; if (!((Object)(object)flowerPaintMarker == (Object)null) && flowerPaintMarker.OverlapsHorizontalCircle(position, radius)) { if (flowerPaintMarker.IsFullyInsideHorizontalCircle(position, radius)) { flowerPaintMarker.DestroyNetworked(); } else { flowerPaintMarker.ApplyEraseCircle(position, radius); } } } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class ZNetScenePatch { [HarmonyPriority(0)] private static void Postfix() { RuntimeBootstrap.TryRegisterScenePrefabs(); RuntimeBootstrap.TryRegisterPieces(); } } [HarmonyPatch(typeof(ClutterSystem), "Awake")] public static class ClutterSystemPatch { [HarmonyPriority(0)] private static void Postfix() { ClutterCatalog.Invalidate(); RuntimeBootstrap.TryRegisterPieces(); } } } namespace FlowerPainter.Runtime { public sealed class FlowerPaintSystem : MonoBehaviour { private void Update() { RuntimeBootstrap.Tick(); } public static void RequestImmediateRefresh() { } public static bool TryGetTerrainPoint(Vector3 input, out Vector3 point, out Vector3 normal) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) point = input; normal = Vector3.up; int num = LayerMask.NameToLayer("terrain"); int num2 = ((num >= 0) ? (1 << num) : 0); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(input.x, input.y + 2000f, input.z); RaycastHit val2 = default(RaycastHit); if (num2 != 0 && Physics.Raycast(val, Vector3.down, ref val2, 5000f, num2, (QueryTriggerInteraction)1)) { point = ((RaycastHit)(ref val2)).point; normal = ((RaycastHit)(ref val2)).normal; return true; } float num3 = default(float); if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(input, ref num3)) { point = new Vector3(input.x, num3, input.z); normal = Vector3.up; return true; } return false; } } public static class ClutterCatalog { private const bool IncludeAllClutterEntries = false; private static readonly List<DiscoveredClutter> Cached = new List<DiscoveredClutter>(); private static readonly Dictionary<string, DiscoveredClutter> ById = new Dictionary<string, DiscoveredClutter>(StringComparer.Ordinal); private static int _signature; public static IList<DiscoveredClutter> Entries => Cached; public static void Invalidate() { _signature = 0; } public static bool EnsureDiscovered() { ClutterSystem val = (((Object)(object)ClutterSystem.instance != (Object)null) ? ClutterSystem.instance : Object.FindFirstObjectByType<ClutterSystem>()); if ((Object)(object)val == (Object)null || val.m_clutter == null) { return false; } int num = ComputeSignature(val.m_clutter); if (num == _signature && Cached.Count > 0) { return true; } Rebuild(val.m_clutter, num); return Cached.Count > 0; } public static bool TryGet(string clutterId, string fallbackPrefabName, out DiscoveredClutter entry) { EnsureDiscovered(); if (!string.IsNullOrEmpty(clutterId) && ById.TryGetValue(clutterId, out entry)) { return true; } if (!string.IsNullOrEmpty(fallbackPrefabName)) { for (int i = 0; i < Cached.Count; i++) { DiscoveredClutter discoveredClutter = Cached[i]; if (discoveredClutter != null && string.Equals(discoveredClutter.PrefabName, fallbackPrefabName, StringComparison.Ordinal)) { entry = discoveredClutter; return true; } } } entry = null; return false; } private static void Rebuild(List<Clutter> source, int signature) { //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) Cached.Clear(); ById.Clear(); Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.Ordinal); for (int i = 0; i < source.Count; i++) { Clutter val = source[i]; if (val == null || (Object)(object)val.m_prefab == (Object)null || !val.m_enabled) { continue; } string text = ((Object)val.m_prefab).name ?? string.Empty; if (!string.IsNullOrEmpty(text)) { bool flag = ReflectionUtils.LooksLikeVegetationName(text); InstanceRenderer[] componentsInChildren = val.m_prefab.GetComponentsInChildren<InstanceRenderer>(true); bool flag2 = componentsInChildren != null && componentsInChildren.Length != 0; if (flag || flag2) { dictionary.TryGetValue(text, out var value); dictionary[text] = value + 1; string text2 = ((!string.IsNullOrEmpty(val.m_name)) ? val.m_name : text); dictionary2.TryGetValue(text2, out var value2); dictionary2[text2] = value2 + 1; string text3 = ((value2 == 0) ? text2 : (text2 + "#" + value2)); string stableId = ReflectionUtils.SafeName(text2) + "_" + StableHash(text3 + "|" + text).ToString("X8"); DiscoveredClutter discoveredClutter = new DiscoveredClutter { ClutterId = text3, StableId = stableId, ClutterName = (val.m_name ?? string.Empty), PrefabName = text, CatalogIndex = i, PrefabOccurrence = value, Prefab = val.m_prefab, Source = val, Amount = val.m_amount, Biome = val.m_biome, VegetationLike = flag, Instanced = val.m_instanced, ScaleMin = val.m_scaleMin, ScaleMax = val.m_scaleMax, MinTilt = val.m_minTilt, MaxTilt = val.m_maxTilt, RandomOffset = val.m_randomOffset, TerrainTilt = val.m_terrainTilt, SnapToWater = val.m_snapToWater, OnCleared = val.m_onCleared, OnUncleared = val.m_onUncleared, HasInstanceRenderer = flag2 }; Cached.Add(discoveredClutter); ById[discoveredClutter.ClutterId] = discoveredClutter; } } } Cached.Sort(delegate(DiscoveredClutter a, DiscoveredClutter b) { int num = string.Compare(a.PrefabName, b.PrefabName, StringComparison.OrdinalIgnoreCase); return (num != 0) ? num : string.Compare(a.ClutterId, b.ClutterId, StringComparison.OrdinalIgnoreCase); }); _signature = signature; } private static int ComputeSignature(List<Clutter> source) { int num = 17; num = num * 31 + source.Count; for (int i = 0; i < source.Count; i++) { Clutter val = source[i]; if (val == null) { num *= 31; continue; } num = num * 31 + StableHash(val.m_name); num = num * 31 + StableHash(((Object)(object)val.m_prefab != (Object)null) ? ((Object)val.m_prefab).name : string.Empty); num = num * 31 + val.m_amount; num = num * 31 + val.m_scaleMin.GetHashCode(); num = num * 31 + val.m_scaleMax.GetHashCode(); num = num * 31 + (val.m_instanced ? 1 : 0); } return num; } internal static int StableHash(string value) { int num = 23; if (value == null) { return num; } for (int i = 0; i < value.Length; i++) { num = num * 31 + value[i]; } return num; } } public static class PrefabFactory { private const float FlowerPainterPieceHealth = 20f; public const string LegacyMarkerPrefabName = "FlowerPainter_MarkerV2"; public const string PiecePrefix = "FlowerPainter_Piece_"; public static GameObject CreateLegacyMarkerPrefab() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown GameObject val = new GameObject("FlowerPainter_MarkerV2"); ParentToRuntimeRoot(val); val.layer = GetPieceLayer(); val.SetActive(true); ZNetView val2 = val.AddComponent<ZNetView>(); val2.m_persistent = true; val.AddComponent<FlowerPaintMarker>(); return val; } public static GameObject CreatePaintPiecePrefab(DiscoveredClutter entry) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) if (entry == null || (Object)(object)entry.Prefab == (Object)null) { return null; } string text = "FlowerPainter_Piece_" + entry.StableId; string text2 = DisplayNameUtils.FromPrefabName(entry.PrefabName); if (!string.IsNullOrEmpty(entry.ClutterName) && entry.ClutterName != entry.PrefabName) { text2 = text2 + " [" + entry.ClutterName + "]"; } GameObject val = new GameObject(text); ParentToRuntimeRoot(val); val.layer = GetPieceLayer(); val.SetActive(true); ZNetView val2 = val.AddComponent<ZNetView>(); val2.m_persistent = true; Piece piece = val.AddComponent<Piece>(); ConfigurePiece(piece, entry, text2); WearNTear wear = val.AddComponent<WearNTear>(); ConfigureWearNTear(wear); SphereCollider val3 = val.AddComponent<SphereCollider>(); ((Collider)val3).isTrigger = false; val3.radius = 0.65f; val3.center = new Vector3(0f, 0.35f, 0f); FlowerPaintBrush flowerPaintBrush = val.AddComponent<FlowerPaintBrush>(); flowerPaintBrush.BrushId = entry.StableId; flowerPaintBrush.ClutterId = entry.ClutterId; flowerPaintBrush.ClutterPrefabName = entry.PrefabName; flowerPaintBrush.Radius = ((Plugin.DefaultBrushRadius != null) ? Mathf.Max(0.25f, Plugin.DefaultBrushRadius.Value) : 4f); flowerPaintBrush.DensityMultiplier = ((Plugin.DefaultDensityMultiplier != null) ? Mathf.Max(0.01f, Plugin.DefaultDensityMultiplier.Value) : 1f); flowerPaintBrush.RemoveMode = false; val.AddComponent<FlowerPaintMarker>(); GameObject val4 = CreateClutterVisualTemplate(entry.Prefab, val.transform); if ((Object)(object)val4 != (Object)null) { ((Object)val4).name = "_FP_ClutterTemplate"; } AttachVanillaGhost(val); FlowerPaintGhostScaler flowerPaintGhostScaler = val.AddComponent<FlowerPaintGhostScaler>(); flowerPaintGhostScaler.Radius = flowerPaintBrush.Radius; val.AddComponent<FlowerPaintPlacementGhost>(); return val; } public static GameObject CreateClearBrushPrefab() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("FlowerPainter_Clear"); ParentToRuntimeRoot(val); val.layer = GetPieceLayer(); val.SetActive(true); Piece val2 = val.AddComponent<Piece>(); val2.m_name = "Clear Flower Paint"; val2.m_description = "Erase FlowerPainter clutter inside the brush radius. Ctrl + mouse wheel changes eraser radius."; val2.m_enabled = true; val2.m_category = (PieceCategory)0; val2.m_groundPiece = true; val2.m_groundOnly = true; val2.m_allowAltGroundPlacement = true; val2.m_canRotate = false; val2.m_canBeRemoved = false; val2.m_resources = (Requirement[])(object)new Requirement[0]; if (!IsDedicatedServer()) { val2.m_icon = GetCultivatorIcon(); if ((Object)(object)val2.m_icon == (Object)null) { val2.m_icon = TextureMaker.CreateFlowerGlyphIcon(); } } FlowerPaintBrush flowerPaintBrush = val.AddComponent<FlowerPaintBrush>(); flowerPaintBrush.BrushId = "CLEAR"; flowerPaintBrush.Radius = ((Plugin.DefaultBrushRadius != null) ? Mathf.Max(0.25f, Plugin.DefaultBrushRadius.Value) : 4f); flowerPaintBrush.DensityMultiplier = 1f; flowerPaintBrush.RemoveMode = true; AttachVanillaGhost(val); FlowerPaintGhostScaler flowerPaintGhostScaler = val.AddComponent<FlowerPaintGhostScaler>(); flowerPaintGhostScaler.Radius = flowerPaintBrush.Radius; val.AddComponent<FlowerPaintPlacementGhost>(); return val; } private static void ConfigurePiece(Piece piece, DiscoveredClutter entry, string displayName) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (!IsDedicatedServer()) { piece.m_icon = PrefabPreviewRenderer.CreatePreviewSprite(entry); if ((Object)(object)piece.m_icon == (Object)null) { piece.m_icon = TextureMaker.CreateFlowerGlyphIcon(); } } piece.m_name = displayName; piece.m_description = "Paint ClutterSystem entry '" + entry.ClutterId + "'. Ctrl + mouse wheel: radius. Shift + mouse wheel: density."; piece.m_enabled = true; piece.m_category = (PieceCategory)0; piece.m_isUpgrade = false; piece.m_groundPiece = true; piece.m_groundOnly = true; piece.m_allowAltGroundPlacement = true; piece.m_cultivatedGroundOnly = false; piece.m_waterPiece = false; piece.m_noInWater = false; piece.m_notOnWood = false; piece.m_notOnTiltingSurface = false; piece.m_noClipping = false; piece.m_allowedInDungeons = false; piece.m_spaceRequirement = 0f; piece.m_canRotate = false; piece.m_randomInitBuildRotation = false; piece.m_canBeRemoved = true; piece.m_resources = (Requirement[])(object)new Requirement[0]; } private static void ConfigureWearNTear(WearNTear wear) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) wear.m_health = 20f; wear.m_noRoofWear = true; wear.m_noSupportWear = true; wear.m_supports = true; wear.m_staticPosition = true; wear.m_burnable = false; wear.m_ashDamageImmune = true; wear.m_triggerPrivateArea = true; wear.m_autoCreateFragments = false; wear.m_materialType = (MaterialType)0; } public static GameObject CreateClutterVisualTemplate(GameObject sourcePrefab, Transform parent) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sourcePrefab == (Object)null) { return null; } GameObject val = Object.Instantiate<GameObject>(sourcePrefab, parent, false); ((Object)val).name = "_FP_ClutterTemplate"; val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.SetActive(false); SanitizeClutterVisual(val.transform); return val; } public static void SanitizeClutterVisual(Transform root) { if ((Object)(object)root == (Object)null) { return; } Component[] components = ((Component)root).GetComponents<Component>(); foreach (Component val in components) { if (!((Object)(object)val == (Object)null) && !(val is Transform) && (val is ZNetView || val is ZSyncTransform || val is Piece || val is WearNTear || val is ItemDrop || val is Pickable || val is Plant || val is Collider || val is Rigidbody || val is IDestructible)) { Object.DestroyImmediate((Object)(object)val); } } for (int j = 0; j < root.childCount; j++) { SanitizeClutterVisual(root.GetChild(j)); } } private static void ParentToRuntimeRoot(GameObject go) { if (!((Object)(object)go == (Object)null)) { Transform runtimePrefabRoot = RuntimeBootstrap.RuntimePrefabRoot; if ((Object)(object)runtimePrefabRoot != (Object)null) { go.transform.SetParent(runtimePrefabRoot, false); } } } public static bool RegisterPrefabToZNetScene(GameObject prefab) { if ((Object)(object)prefab == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return false; } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); if (ZNetScene.instance.m_namedPrefabs.TryGetValue(stableHashCode, out var value)) { if ((Object)(object)value == (Object)(object)prefab) { return true; } Debug.LogError((object)("FlowerPainter prefab hash/name collision: " + ((Object)prefab).name)); return false; } if (!ZNetScene.instance.m_prefabs.Contains(prefab)) { ZNetScene.instance.m_prefabs.Add(prefab); } ZNetScene.instance.m_namedPrefabs.Add(stableHashCode, prefab); return true; } private static bool IsDedicatedServer() { return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated(); } private static Sprite GetCultivatorIcon() { GameObject val = null; if ((Object)(object)ObjectDB.instance != (Object)null) { val = ObjectDB.instance.GetItemPrefab("Cultivator"); } if ((Object)(object)val == (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { val = ZNetScene.instance.GetPrefab("Cultivator"); } if ((Object)(object)val == (Object)null) { return null; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null) { return null; } return component.m_itemData.GetIcon(); } private static int GetPieceLayer() { int num = LayerMask.NameToLayer("piece_nonsolid"); if (num < 0) { num = LayerMask.NameToLayer("piece"); } return (num >= 0) ? num : 0; } private static void AttachVanillaGhost(GameObject target) { if ((Object)(object)target == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Cultivator"); if ((Object)(object)itemPrefab == (Object)null) { return; } ItemDrop component = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { return; } PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces; if ((Object)(object)buildPieces == (Object)null || buildPieces.m_pieces == null) { return; } GameObject val = FindGhostSource(buildPieces); if (!((Object)(object)val == (Object)null)) { Transform val2 = val.transform.Find("_GhostOnly"); if (!((Object)(object)val2 == (Object)null)) { GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, target.transform, false); ((Object)val3).name = "_GhostOnly"; val3.SetActive(true); } } } private static GameObject FindGhostSource(PieceTable table) { for (int i = 0; i < table.m_pieces.Count; i++) { GameObject val = table.m_pieces[i]; if (!((Object)(object)val == (Object)null)) { Transform val2 = val.transform.Find("_GhostOnly"); if ((Object)(object)val2 != (Object)null) { return val; } } } return null; } } public static class RuntimeBootstrap { private const string RuntimeRootName = "BalrondFlowerPainter_RuntimePrefabs"; private static GameObject _runtimeRoot; private static GameObject _legacyMarkerPrefab; private static GameObject _clearBrushPrefab; private static readonly Dictionary<string, GameObject> PiecePrefabs = new Dictionary<string, GameObject>(StringComparer.Ordinal); private static float _nextRetry; private static int _lastLoggedPieceCount = -1; public static Transform RuntimePrefabRoot { get { EnsureRuntimeRoot(); return ((Object)(object)_runtimeRoot != (Object)null) ? _runtimeRoot.transform : null; } } public static void Tick() { if (!(Time.time < _nextRetry)) { _nextRetry = Time.time + 2f; if (IsWorldRuntimeReady()) { TryRegisterScenePrefabs(); TryRegisterPieces(); } } } public static bool IsWorldRuntimeReady() { return (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ClutterSystem.instance != (Object)null; } public static void TryRegisterScenePrefabs() { if ((Object)(object)ZNetScene.instance == (Object)null) { return; } EnsureRuntimeRoot(); if ((Object)(object)ZNetScene.instance.GetPrefab("FlowerPainter_MarkerV2") == (Object)null) { if ((Object)(object)_legacyMarkerPrefab == (Object)null) { _legacyMarkerPrefab = PrefabFactory.CreateLegacyMarkerPrefab(); } PrefabFactory.RegisterPrefabToZNetScene(_legacyMarkerPrefab); } } public static void TryRegisterPieces() { if (!IsWorldRuntimeReady() || !ClutterCatalog.EnsureDiscovered()) { return; } TryRegisterScenePrefabs(); RemoveFlowerPainterPiecesFromHoe(); IList<DiscoveredClutter> entries = ClutterCatalog.Entries; List<PieceTable> list = CollectTargetTables(); if (list.Count == 0) { return; } for (int i = 0; i < list.Count; i++) { SanitizePieceTable(list[i]); } if ((Object)(object)_clearBrushPrefab == (Object)null) { _clearBrushPrefab = PrefabFactory.CreateClearBrushPrefab(); } if ((Object)(object)_clearBrushPrefab != (Object)null) { for (int j = 0; j < list.Count; j++) { AddPieceIfMissing(list[j], _clearBrushPrefab); MoveClearBeforeFlowerPainterPieces(list[j]); } } for (int k = 0; k < entries.Count; k++) { DiscoveredClutter discoveredClutter = entries[k]; if (discoveredClutter == null || (Object)(object)discoveredClutter.Prefab == (Object)null) { continue; } string key = "FlowerPainter_Piece_" + discoveredClutter.StableId; if (!PiecePrefabs.TryGetValue(key, out var value) || (Object)(object)value == (Object)null) { value = PrefabFactory.CreatePaintPiecePrefab(discoveredClutter); if ((Object)(object)value == (Object)null) { continue; } PiecePrefabs[key] = value; } if (PrefabFactory.RegisterPrefabToZNetScene(value)) { for (int l = 0; l < list.Count; l++) { AddPieceIfMissing(list[l], value); } } } int num = entries.Count + 1; if (_lastLoggedPieceCount != num) { _lastLoggedPieceCount = num; Debug.Log((object)("FlowerPainter registered " + entries.Count + " full Piece prefabs + clear tool into " + list.Count + " PieceTable(s). Every clutter Piece is ZNetScene-registered and uses vanilla Player.PlacePiece.")); } } public static void SanitizePieceTable(PieceTable table) { if (!((Object)(object)table == (Object)null) && table.m_pieces != null) { int num = table.m_pieces.RemoveAll((GameObject piece) => (Object)(object)piece == (Object)null); if (num > 0) { Debug.LogWarning((object)("Removed " + num + " null/destroyed prefab reference(s) from PieceTable '" + ((Object)table).name + "'.")); } } } private static List<PieceTable> CollectTargetTables() { List<PieceTable> result = new List<PieceTable>(); AddTableFromTool(result, "Cultivator", includeObjectDb: true); return result; } private static void RemoveFlowerPainterPiecesFromHoe() { List<PieceTable> list = new List<PieceTable>(); AddTableFromTool(list, "Hoe", includeObjectDb: true); for (int i = 0; i < list.Count; i++) { PieceTable val = list[i]; if (!((Object)(object)val == (Object)null) && val.m_pieces != null) { int num = val.m_pieces.RemoveAll((GameObject piece) => !((Object)(object)piece == (Object)null) && (((Object)piece).name.StartsWith("FlowerPainter_Piece_", StringComparison.Ordinal) || ((Object)piece).name == "FlowerPainter_Clear")); if (num > 0) { Debug.Log((object)("Removed " + num + " FlowerPainter Piece(s) from Hoe PieceTable. FlowerPainter is Cultivator-only.")); } } } } private static void AddTableFromTool(List<PieceTable> result, string toolName, bool includeObjectDb) { if ((Object)(object)ZNetScene.instance != (Object)null) { AddToolPrefabTable(result, ZNetScene.instance.GetPrefab(toolName)); } if (includeObjectDb && (Object)(object)ObjectDB.instance != (Object)null) { AddToolPrefabTable(result, ObjectDB.instance.GetItemPrefab(toolName)); } } private static void AddToolPrefabTable(List<PieceTable> result, GameObject tool) { if ((Object)(object)tool == (Object)null) { return; } ItemDrop component = tool.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { return; } PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces; if ((Object)(object)buildPieces == (Object)null || buildPieces.m_pieces == null) { return; } for (int i = 0; i < result.Count; i++) { if (result[i] == buildPieces) { return; } } result.Add(buildPieces); } private static void AddPieceIfMissing(PieceTable table, GameObject piecePrefab) { if ((Object)(object)table == (Object)null || table.m_pieces == null || (Object)(object)piecePrefab == (Object)null) { return; } Piece component = piecePrefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { Debug.LogError((object)("Refusing to add non-Piece FlowerPainter prefab to PieceTable: " + ((Object)piecePrefab).name)); return; } for (int i = 0; i < table.m_pieces.Count; i++) { GameObject val = table.m_pieces[i]; if ((Object)(object)val != (Object)null && ((Object)val).name == ((Object)piecePrefab).name) { return; } } table.m_pieces.Add(piecePrefab); } private static void MoveClearBeforeFlowerPainterPieces(PieceTable table) { if ((Object)(object)table == (Object)null || table.m_pieces == null) { return; } int num = -1; int num2 = -1; for (int i = 0; i < table.m_pieces.Count; i++) { GameObject val = table.m_pieces[i]; if (!((Object)(object)val == (Object)null)) { if (((Object)val).name == "FlowerPainter_Clear") { num = i; } else if (num2 < 0 && ((Object)val).name.StartsWith("FlowerPainter_Piece_", StringComparison.Ordinal)) { num2 = i; } } } if (num >= 0 && num2 >= 0 && num >= num2) { GameObject item = table.m_pieces[num]; table.m_pieces.RemoveAt(num); table.m_pieces.Insert(num2, item); } } private static void EnsureRuntimeRoot() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (!((Object)(object)_runtimeRoot != (Object)null)) { _runtimeRoot = new GameObject("BalrondFlowerPainter_RuntimePrefabs"); ((Object)_runtimeRoot).hideFlags = (HideFlags)1; Object.DontDestroyOnLoad((Object)(object)_runtimeRoot); _runtimeRoot.SetActive(false); } } } } namespace FlowerPainter.Managers { public static class FlowerPaintRegistry { public static readonly List<FlowerPaintMarker> All = new List<FlowerPaintMarker>(); private static int _revision; public static int Revision => _revision; public static void Register(FlowerPaintMarker marker) { if (!((Object)(object)marker == (Object)null) && !All.Contains(marker)) { All.Add(marker); _revision++; } } public static void Unregister(FlowerPaintMarker marker) { if (!((Object)(object)marker == (Object)null) && All.Remove(marker)) { _revision++; } } public static void MarkDirty() { _revision++; } } } namespace FlowerPainter.Data { public sealed class DiscoveredClutter { public string ClutterId; public string StableId; public string ClutterName; public string PrefabName; public int CatalogIndex; public int PrefabOccurrence; public GameObject Prefab; public Clutter Source; public int Amount; public Biome Biome; public bool VegetationLike; public bool Instanced; public float ScaleMin; public float ScaleMax; public float MinTilt; public float MaxTilt; public float RandomOffset; public bool TerrainTilt; public bool SnapToWater; public bool OnCleared; public bool OnUncleared; public bool HasInstanceRenderer; } } namespace FlowerPainter.Components { public sealed class FlowerPaintBrush : MonoBehaviour { public string BrushId; public string ClutterId; public string ClutterPrefabName; public float Radius; public float DensityMultiplier = 1f; public bool RemoveMode; } public static class FlowerPaintBrushSettings { public const float MinRadius = 0.5f; public const float MaxRadius = 20f; public const float RadiusStep = 0.5f; public const float MinDensity = 0.25f; public const float MaxDensity = 8f; public const float DensityStep = 0.25f; private static bool _initialized; private static float _radius; private static float _density; public static float Radius { get { EnsureInitialized(); return _radius; } } public static float DensityMultiplier { get { EnsureInitialized(); return _density; } } public static void EnsureInitialized() { if (!_initialized) { float num = ((Plugin.DefaultBrushRadius != null) ? Plugin.DefaultBrushRadius.Value : 4f); float num2 = ((Plugin.DefaultDensityMultiplier != null) ? Plugin.DefaultDensityMultiplier.Value : 2f); _radius = Mathf.Clamp(num, 0.5f, 20f); _density = Mathf.Clamp(num2, 0.25f, 8f); _initialized = true; } } public static bool AdjustRadius(float direction) { EnsureInitialized(); if (Mathf.Abs(direction) < 0.001f) { return false; } float num = Mathf.Clamp(_radius + Mathf.Sign(direction) * 0.5f, 0.5f, 20f); if (Mathf.Approximately(num, _radius)) { return false; } _radius = num; return true; } public static bool AdjustDensity(float direction) { EnsureInitialized(); if (Mathf.Abs(direction) < 0.001f) { return false; } float num = Mathf.Clamp(_density + Mathf.Sign(direction) * 0.25f, 0.25f, 8f); if (Mathf.Approximately(num, _density)) { return false; } _density = num; return true; } } public class FlowerPaintGhostScaler : MonoBehaviour { public float Radius; private void OnEnable() { Apply(); } public void Apply() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)this).transform.Find("_GhostOnly"); if (!((Object)(object)val == (Object)null)) { float num = ((Radius > 0f) ? Radius : Plugin.DefaultBrushRadius.Value); float num2 = num * 2f; val.localScale = new Vector3(num2, 1f, num2); } } } public sealed class FlowerPaintMarker : MonoBehaviour, IPlaced { private struct Placement { public Vector3 Position; public Quaternion Rotation; public float Scale; } private struct EraseCircle { public Vector2 LocalCenter; public float Radius; } public const string VisualTemplateName = "_FP_ClutterTemplate"; private const string ExtraVisualRootName = "_FP_ExtraVisuals"; private const int DataVersion = 7; private const int MaxPerInstanceRenderer = 1023; private const int MaxFallbackGameObjects = 512; private const int MaxInstancesPerPiece = 8192; private ZNetView _znv; private FlowerPaintBrush _definition; private bool _registered; private bool _visualBuilt; private float _nextBuildAttempt; private float _nextDataSyncCheck; private Transform _extraVisualRoot; private readonly List<EraseCircle> _eraseCircles = new List<EraseCircle>(); private string _eraseDataCache = string.Empty; public string ClutterId { get; private set; } public string ClutterPrefabName { get; private set; } public float Radius { get; private set; } public float DensityMultiplier { get; private set; } public int Seed { get; private set; } public int TargetCount { get; private set; } private void Awake() { _znv = ((Component)this).GetComponent<ZNetView>(); _definition = ((Component)this).GetComponent<FlowerPaintBrush>(); TryLoadAndRegister(); } private void Start() { TryLoadAndRegister(); HidePlacementGhostVisuals(); TryBuildVisuals(); } private void Update() { if ((Object)(object)_znv != (Object)null && _znv.IsValid() && Time.time >= _nextDataSyncCheck) { _nextDataSyncCheck = Time.time + 0.5f; if (RefreshEraseDataFromZDO()) { _visualBuilt = false; ClearGeneratedVisuals(); } } if (!_visualBuilt && !(Time.time < _nextBuildAttempt)) { _nextBuildAttempt = Time.time + 1f; TryLoadAndRegister(); TryBuildVisuals(); } } private void OnDestroy() { if (_registered) { FlowerPaintRegistry.Unregister(this); } } public void OnPlaced() { if ((Object)(object)_definition != (Object)null && !_definition.RemoveMode) { FlowerPaintBrushSettings.EnsureInitialized(); Initialize(_definition.ClutterId, _definition.ClutterPrefabName, FlowerPaintBrushSettings.Radius, FlowerPaintBrushSettings.DensityMultiplier, CreateUniquePlacementSeed()); } TryLoadAndRegister(); HidePlacementGhostVisuals(); RebuildVisuals(); } public void Initialize(string clutterId, string clutterPrefabName, float radius, float densityMultiplier, int seed) { if ((Object)(object)_znv == (Object)null || !_znv.IsValid()) { return; } if (!_znv.IsOwner()) { _znv.ClaimOwnership(); } if (!_znv.IsOwner()) { return; } ZDO zDO = _znv.GetZDO(); if (zDO != null) { if (seed == 0) { seed = 1; } ClutterId = clutterId ?? string.Empty; ClutterPrefabName = clutterPrefabName ?? string.Empty; Radius = Mathf.Max(0.25f, radius); DensityMultiplier = Mathf.Max(0.01f, densityMultiplier); Seed = seed; TargetCount = ((ClutterCatalog.TryGet(ClutterId, ClutterPrefabName, out var entry) && entry != null) ? ComputeTargetCount(entry) : 0); zDO.Set("fp_version", 7); zDO.Set("fp_clutter_id", ClutterId); zDO.Set("fp_clutter", ClutterPrefabName); zDO.Set("fp_radius", Radius); zDO.Set("fp_density", DensityMultiplier); zDO.Set("fp_seed", Seed); zDO.Set("fp_count", TargetCount); zDO.Set("fp_erase", string.Empty); _eraseCircles.Clear(); _eraseDataCache = string.Empty; RegisterIfNetworked(); FlowerPaintRegistry.MarkDirty(); } } public void DestroyNetworked() { if ((Object)(object)_znv != (Object)null && _znv.IsValid() && !_znv.IsOwner()) { _znv.ClaimOwnership(); } if ((Object)(object)ZNetScene.instance != (Object)null) { ZNetScene.instance.Destroy(((Component)this).gameObject); } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } public void SetPlacementColliderEnabled(bool enabledState) { Collider[] components = ((Component)this).GetComponents<Collider>(); foreach (Collider val in components) { if ((Object)(object)val != (Object)null && val.enabled != enabledState) { val.enabled = enabledState; } } } public bool OverlapsHorizontalCircle(Vector3 worldCenter, float radius) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0.25f, Radius); float num2 = Mathf.Max(0f, radius); Vector3 val = ((Component)this).transform.position - worldCenter; val.y = 0f; float num3 = num + num2; return ((Vector3)(ref val)).sqrMagnitude <= num3 * num3; } public bool IsFullyInsideHorizontalCircle(Vector3 worldCenter, float radius) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0.25f, Radius); float num2 = Mathf.Max(0f, radius); Vector3 val = ((Component)this).transform.position - worldCenter; val.y = 0f; return ((Vector3)(ref val)).magnitude + num <= num2; } public bool ApplyEraseCircle(Vector3 worldCenter, float radius) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) radius = Mathf.Max(0.25f, radius); if ((Object)(object)_znv == (Object)null || !_znv.IsValid()) { return false; } if (!_znv.IsOwner()) { _znv.ClaimOwnership(); } if (!_znv.IsOwner()) { return false; } ZDO zDO = _znv.GetZDO(); if (zDO == null) { return false; } RefreshEraseDataFromZDO(); Vector3 val = worldCenter - ((Component)this).transform.position; Vector2 localCenter = default(Vector2); ((Vector2)(ref localCenter))..ctor(val.x, val.z); if (!AddEraseCircle(localCenter, radius)) { return false; } string text = SerializeEraseCircles(); zDO.Set("fp_erase", text); _eraseDataCache = text; FlowerPaintRegistry.MarkDirty(); if (ClutterCatalog.TryGet(ClutterId, ClutterPrefabName, out var entry) && entry != null && (Object)(object)entry.Prefab != (Object)null && GeneratePlacements(entry).Count == 0) { DestroyNetworked(); return true; } RebuildVisuals(); return true; } public void RebuildVisuals() { _visualBuilt = false; ClearGeneratedVisuals(); TryBuildVisuals(); } private void TryLoadAndRegister() { if ((Object)(object)_znv == (Object)null) { _znv = ((Component)this).GetComponent<ZNetView>(); } if (!((Object)(object)_znv == (Object)null) && _znv.IsValid()) { LoadFromZDO(); RegisterIfNetworked(); } } private void RegisterIfNetworked() { if (!_registered && !((Object)(object)_znv == (Object)null) && _znv.IsValid()) { FlowerPaintRegistry.Register(this); _registered = true; } } private void LoadFromZDO() { //IL_0222: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_znv == (Object)null || !_znv.IsValid()) { return; } ZDO zDO = _znv.GetZDO(); if (zDO == null) { return; } string text = zDO.GetString("fp_clutter_id", string.Empty); string clutterPrefabName = zDO.GetString("fp_clutter", string.Empty); if (string.IsNullOrEmpty(text) && (Object)(object)_definition != (Object)null && !_definition.RemoveMode) { ClutterId = _definition.ClutterId ?? string.Empty; ClutterPrefabName = _definition.ClutterPrefabName ?? string.Empty; Radius = Mathf.Max(0.25f, _definition.Radius); DensityMultiplier = Mathf.Max(0.01f, _definition.DensityMultiplier); TargetCount = 0; _eraseCircles.Clear(); _eraseDataCache = string.Empty; return; } ClutterId = text; ClutterPrefabName = clutterPrefabName; Radius = Mathf.Max(0.25f, zDO.GetFloat("fp_radius", (Plugin.DefaultBrushRadius != null) ? Plugin.DefaultBrushRadius.Value : 4f)); DensityMultiplier = Mathf.Max(0.01f, zDO.GetFloat("fp_density", 1f)); Seed = zDO.GetInt("fp_seed", 0); TargetCount = Mathf.Max(0, zDO.GetInt("fp_count", 0)); LoadEraseData(zDO.GetString("fp_erase", string.Empty)); if (Seed == 0 && (!string.IsNullOrEmpty(ClutterId) || !string.IsNullOrEmpty(ClutterPrefabName))) { Seed = StablePositionSeed((!string.IsNullOrEmpty(ClutterId)) ? ClutterId : ClutterPrefabName, ((Component)this).transform.position); } } private void TryBuildVisuals() { if (_visualBuilt || (Object)(object)_znv == (Object)null || !_znv.IsValid()) { return; } if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) { _visualBuilt = true; return; } if (string.IsNullOrEmpty(ClutterId) && string.IsNullOrEmpty(ClutterPrefabName)) { LoadFromZDO(); if (string.IsNullOrEmpty(ClutterId) && string.IsNullOrEmpty(ClutterPrefabName)) { return; } } if (!ClutterCatalog.TryGet(ClutterId, ClutterPrefabName, out var entry) || entry == null || (Object)(object)entry.Prefab == (Object)null) { return; } List<Placement> list = GeneratePlacements(entry); if (list.Count == 0) { _visualBuilt = true; return; } ClearGeneratedVisuals(); if (entry.Instanced && entry.HasInstanceRenderer) { BuildNativeInstanceRendererVisuals(entry, list); } else { BuildFallbackVisuals(entry, list); } _visualBuilt = true; } private List<Placement> GeneratePlacements(DiscoveredClutter entry) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) int num = ResolveTargetCount(entry); List<Placement> list = new List<Placement>(num); if (num <= 0) { return list; } int num2 = ((Seed != 0) ? Seed : StablePositionSeed(ClutterId, ((Component)this).transform.position)); Random random = new Random(num2); double num3 = random.NextDouble(); double num4 = random.NextDouble(); Random random2 = new Random((num2 * 397) ^ 0x51ED270B); float num5 = Mathf.Max(0.25f, Radius); int num6 = Mathf.Max(num * 6, num + 64); float min = entry.ScaleMin; float max = entry.ScaleMax; NormalizeScaleRange(ref min, ref max); int num7 = 0; for (int i = 0; i < num6; i++) { if (num7 >= num) { break; } double d = Frac(num3 + (double)(i + 1) * 0.7548776662466927); double num8 = Frac(num4 + (double)(i + 1) * 0.5698402909980532); double num9 = num8 * Math.PI * 2.0; double num10 = Math.Sqrt(d) * (double)num5; Vector3 input = ((Component)this).transform.position + new Vector3((float)(Math.Cos(num9) * num10), 0f, (float)(Math.Sin(num9) * num10)); if (FlowerPaintSystem.TryGetTerrainPoint(input, out var point, out var normal)) { if (entry.SnapToWater) { float y = (((Object)(object)ZoneSystem.instance != (Object)null) ? ReflectionUtils.GetFieldValue(ZoneSystem.instance, "m_waterLevel", point.y) : point.y); point.y = y; } float num11 = (float)(random2.NextDouble() * 360.0); Quaternion val = Quaternion.Euler(0f, num11, 0f); if (entry.TerrainTilt) { val = Quaternion.FromToRotation(Vector3.up, normal) * val; } float scale = Mathf.Lerp(min, max, (float)random2.NextDouble()); num7++; if (!IsErased(point)) { list.Add(new Placement { Position = point, Rotation = val, Scale = scale }); } } } return list; } private int CreateUniquePlacementSeed() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) int num = 17; ZDO val = (((Object)(object)_znv != (Object)null && _znv.IsValid()) ? _znv.GetZDO() : null); num = ((val == null) ? (num * 31 + Environment.TickCount) : (num * 31 + ((object)Unsafe.As<ZDOID, ZDOID>(ref val.m_uid)/*cast due to .constrained prefix*/).GetHashCode())); num = num * 31 + ClutterCatalog.StableHash(((Object)(object)_definition != (Object)null) ? _definition.ClutterId : ClutterId); num = num * 31 + Mathf.RoundToInt(((Component)this).transform.position.x * 100f); num = num * 31 + Mathf.RoundToInt(((Component)this).transform.position.z * 100f); if (num == 0) { num = 1; } return num; } private static double Frac(double value) { return value - Math.Floor(value); } private int ResolveTargetCount(DiscoveredClutter entry) { if (TargetCount > 0) { return Mathf.Min(TargetCount, 8192); } TargetCount = ComputeTargetCount(entry); if ((Object)(object)_znv != (Object)null && _znv.IsValid() && _znv.IsOwner()) { ZDO zDO = _znv.GetZDO(); if (zDO != null) { zDO.Set("fp_count", TargetCount); zDO.Set("fp_version", 7); } } return TargetCount; } private int ComputeTargetCount(DiscoveredClutter entry) { float num = (((Object)(object)ClutterSystem.instance != (Object)null) ? ReflectionUtils.GetFieldValue(ClutterSystem.instance, "m_amountScale", 1f) : 1f); if (num <= 0f) { num = 1f; } float num2 = (((Object)(object)ClutterSystem.instance != (Object)null) ? ReflectionUtils.GetFieldValue(ClutterSystem.instance, "m_grassPatchSize", Radius * 2f) : (Radius * 2f)); num2 = Mathf.Max(0.5f, num2); float num3 = (float)Math.PI * Radius * Radius; float num4 = num2 * num2; float num5 = ((num4 > 0.001f) ? (num3 / num4) : 1f); float num6 = (float)Mathf.Max(1, entry.Amount) * num * Mathf.Max(0.01f, DensityMultiplier) * num5; int num7 = Mathf.Max(1, Mathf.RoundToInt(num6)); return Mathf.Min(num7, 8192); } private void BuildNativeInstanceRendererVisuals(DiscoveredClutter entry, List<Placement> placements) { //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindOrCreateVisualTemplate(entry); if ((Object)(object)val == (Object)null) { return; } val.SetActive(false); int num = 0; int num2 = 0; while (num < placements.Count) { int num3 = Mathf.Min(1023, placements.Count - num); GameObject val2; if (num2 == 0) { val2 = val; } else { val2 = PrefabFactory.CreateClutterVisualTemplate(entry.Prefab, GetExtraVisualRoot()); if ((Object)(object)val2 == (Object)null) { break; } ((Object)val2).name = "FP_IR_Batch_" + num2; } val2.SetActive(false); InstanceRenderer[] componentsInChildren = val2.GetComponentsInChildren<InstanceRenderer>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { if (num2 > 0) { Object.Destroy((Object)(object)val2); } break; } foreach (InstanceRenderer val3 in componentsInChildren) { if (!((Object)(object)val3 == (Object)null)) { val3.Clear(); if ((Object)(object)val3.m_material != (Object)null) { val3.m_material.enableInstancing = true; } for (int j = 0; j < num3; j++) { Placement placement = placements[num + j]; val3.AddInstance(placement.Position, placement.Rotation, placement.Scale); } } } val2.SetActive(true); num += num3; num2++; } } private void BuildFallbackVisuals(DiscoveredClutter entry, List<Placement> placements) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindOrCreateVisualTemplate(entry); if ((Object)(object)val != (Object)null) { val.SetActive(false); } Transform extraVisualRoot = GetExtraVisualRoot(); int num = Mathf.Min(placements.Count, 512); for (int i = 0; i < num; i++) { Placement placement = placements[i]; GameObject val2 = Object.Instantiate<GameObject>(entry.Prefab, placement.Position, placement.Rotation, extraVisualRoot); ((Object)val2).name = "FP_Fallback_" + i; PrefabFactory.SanitizeClutterVisual(val2.transform); val2.transform.localScale = val2.transform.localScale * placement.Scale; val2.SetActive(true); } } private GameObject FindOrCreateVisualTemplate(DiscoveredClutter entry) { Transform val = ((Component)this).transform.Find("_FP_ClutterTemplate"); if ((Object)(object)val != (Object)null) { return ((Component)val).gameObject; } return PrefabFactory.CreateClutterVisualTemplate(entry.Prefab, ((Component)this).transform); } private Transform GetExtraVisualRoot() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown if ((Object)(object)_extraVisualRoot != (Object)null) { return _extraVisualRoot; } Transform val = ((Component)this).transform.Find("_FP_ExtraVisuals"); if ((Object)(object)val != (Object)null) { _extraVisualRoot = val; return _extraVisualRoot; } GameObject val2 = new GameObject("_FP_ExtraVisuals"); val2.transform.SetParent(((Component)this).transform, false); _extraVisualRoot = val2.transform; return _extraVisualRoot; } private void ClearGeneratedVisuals() { Transform val = ((Component)this).transform.Find("_FP_ClutterTemplate"); if ((Object)(object)val != (Object)null) { InstanceRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<InstanceRenderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { componentsInChildren[i].Clear(); } } ((Component)val).gameObject.SetActive(false); } Transform val2 = ((Component)this).transform.Find("_FP_ExtraVisuals"); if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)((Component)val2).gameObject); _extraVisualRoot = null; } } private void HidePlacementGhostVisuals() { Transform val = ((Component)this).transform.Find("_GhostOnly"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } } private bool RefreshEraseDataFromZDO() { if ((Object)(object)_znv == (Object)null || !_znv.IsValid()) { return false; } ZDO zDO = _znv.GetZDO(); if (zDO == null) { return false; } string text = zDO.GetString("fp_erase", string.Empty); if (text == _eraseDataCache) { return false; } LoadEraseData(text); return true; } private void LoadEraseData(string data) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) _eraseDataCache = data ?? string.Empty; _eraseCircles.Clear(); if (string.IsNullOrEmpty(_eraseDataCache)) { return; } string[] array = _eraseDataCache.Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { if (!string.IsNullOrEmpty(array[i])) { string[] array2 = array[i].Split(new char[1] { ',' }); if (array2.Length == 3 && float.TryParse(array2[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) && !(result3 <= 0f)) { _eraseCircles.Add(new EraseCircle { LocalCenter = new Vector2(result, result2), Radius = result3 }); } } } } private bool AddEraseCircle(Vector2 localCenter, float radius) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) radius = Mathf.Max(0.25f, radius); for (int i = 0; i < _eraseCircles.Count; i++) { EraseCircle eraseCircle = _eraseCircles[i]; float num = Vector2.Distance(eraseCircle.LocalCenter, localCenter); if (num + radius <= eraseCircle.Radius) { return false; } } for (int num2 = _eraseCircles.Count - 1; num2 >= 0; num2--) { EraseCircle eraseCircle2 = _eraseCircles[num2]; float num3 = Vector2.Distance(eraseCircle2.LocalCenter, localCenter); if (num3 + eraseCircle2.Radius <= radius) { _eraseCircles.RemoveAt(num2); } } _eraseCircles.Add(new EraseCircle { LocalCenter = localCenter, Radius = radius }); if (_eraseCircles.Count > 128) { _eraseCircles.RemoveRange(0, _eraseCircles.Count - 128); } return true; } private string SerializeEraseCircles() { if (_eraseCircles.Count == 0) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(_eraseCircles.Count * 24); for (int i = 0; i < _eraseCircles.Count; i++) { if (i > 0) { stringBuilder.Append(';'); } EraseCircle eraseCircle = _eraseCircles[i]; stringBuilder.Append(eraseCircle.LocalCenter.x.ToString("R", CultureInfo.InvariantCulture)); stringBuilder.Append(','); stringBuilder.Append(eraseCircle.LocalCenter.y.ToString("R", CultureInfo.InvariantCulture)); stringBuilder.Append(','); stringBuilder.Append(eraseCircle.Radius.ToString("R", CultureInfo.InvariantCulture)); } return stringBuilder.ToString(); } private bool IsErased(Vector3 worldPoint) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) if (_eraseCircles.Count == 0) { return false; } Vector3 val = worldPoint - ((Component)this).transform.position; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(val.x, val.z); for (int i = 0; i < _eraseCircles.Count; i++) { EraseCircle eraseCircle = _eraseCircles[i]; Vector2 val3 = val2 - eraseCircle.LocalCenter; if (((Vector2)(ref val3)).sqrMagnitude <= eraseCircle.Radius * eraseCircle.Radius) { return true; } } return false; } private static void NormalizeScaleRange(ref float min, ref float max) { if (min <= 0f && max <= 0f) { min = 1f; max = 1f; return; } if (min <= 0f) { min = max; } if (max <= 0f) { max = min; } if (max < min) { float num = min; min = max; max = num; } } private static int StablePositionSeed(string id, Vector3 position) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) int num = 17; num = num * 31 + ClutterCatalog.StableHash(id); num = num * 31 + Mathf.RoundToInt(position.x * 100f); num = num * 31 + Mathf.RoundToInt(position.y * 100f); num = num * 31 + Mathf.RoundToInt(position.z * 100f); return (num == 0) ? 1 : num; } } [RequireComponent(typeof(FlowerPaintBrush))] public sealed class FlowerPaintPlacementGhost : MonoBehaviour { private FlowerPaintBrush _brush; private FlowerPaintGhostScaler _scaler; private ZNetView _znv; private LineRenderer _ring; private readonly List<LineRenderer> _removeLines = new List<LineRenderer>(); private Material _lineMaterial; private float _lastAppliedRadius = -1f; private bool _registeredAsActivePlacementGhost; private static int _activePlacementGhostCount; private void Awake() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) _brush = ((Component)this).GetComponent<FlowerPaintBrush>(); _scaler = ((Component)this).GetComponent<FlowerPaintGhostScaler>(); _znv = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)_znv != (Object)null && _znv.IsValid()) { ((Behaviour)this).enabled = false; return; } FlowerPaintBrushSettings.EnsureInitialized(); ApplyRuntimeBrushSettings(forceScale: true); Shader val = Shader.Find("Sprites/Default"); if (!((Object)(object)val == (Object)null)) { _lineMaterial = new Material(val); GameObject val2 = new GameObject("FP_RangeRing"); val2.transform.SetParent(((Component)this).transform, false); _ring = val2.AddComponent<LineRenderer>(); _ring.loop = true; _ring.useWorldSpace = true; _ring.widthMultiplier = 0.05f; ((Renderer)_ring).material = _lineMaterial; _ring.positionCount = 48; ((Renderer)_ring).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)_ring).receiveShadows = false; Color val3 = (((Object)(object)_brush != (Object)null && _brush.RemoveMode) ? new Color(1f, 0.2f, 0.2f, 0.9f) : new Color(0.2f, 1f, 0.2f, 0.9f)); _ring.startColor = val3; _ring.endColor = val3; } } private void OnEnable() { if ((Object)(object)_znv == (Object)null || !_znv.IsValid()) { RegisterActivePlacementGhost(); SetPlacedMarkerColliders(enabledState: false); } } private void OnDisable() { UnregisterActivePlacementGhost(); if ((Object)(object)_znv == (Object)null || !_znv.IsValid()) { SetPlacedMarkerColliders(enabledState: true); } } private void OnDestroy() { UnregisterActivePlacementGhost(); if ((Object)(object)_znv == (Object)null || !_znv.IsValid()) { SetPlacedMarkerColliders(enabledState: true); } if ((Object)(object)_lineMaterial != (Object)null) { Object.Destroy((Object)(object)_lineMaterial); } } private void Update() { if ((Object)(object)_brush == (Object)null || (Object)(object)_ring == (Object)null) { return; } if ((Object)(object)_znv != (Object)null && _znv.IsValid()) { ((Renderer)_ring).enabled = false; ClearRemovePreview(); ((Behaviour)this).enabled = false; return; } SetPlacedMarkerColliders(enabledState: false); HandleBrushInput(); ApplyRuntimeBrushSettings(forceScale: false); DrawRing(); if (_brush.RemoveMode) { DrawRemovePreview(); } else { ClearRemovePreview(); } } private void HandleBrushInput() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (Console.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())) { return; } float y = Input.mouseScrollDelta.y; if (Mathf.Abs(y) < 0.001f) { return; } bool flag = IsCtrlHeld(); bool flag2 = IsShiftHeld(); if (flag) { if (FlowerPaintBrushSettings.AdjustRadius(y)) { ApplyRuntimeBrushSettings(forceScale: true); ShowSettingMessage("FlowerPainter radius: " + FlowerPaintBrushSettings.Radius.ToString("0.0") + " m"); } } else if (flag2 && !_brush.RemoveMode && FlowerPaintBrushSettings.AdjustDensity(y)) { ApplyRuntimeBrushSettings(forceScale: false); ShowSettingMessage("FlowerPainter density: x" + FlowerPaintBrushSettings.DensityMultiplier.ToString("0.00")); } } internal static bool ShouldConsumeMouseWheel() { if (_activePlacementGhostCount <= 0) { return false; } if (Hud.IsPieceSelectionVisible()) { return false; } if (Console.IsVisible()) { return false; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return false; } return IsCtrlHeld() || IsShiftHeld(); } private static bool IsCtrlHeld() { return ZInput.GetKey((KeyCode)306, true) || ZInput.GetKey((KeyCode)305, true); } private static bool IsShiftHeld() { return ZInput.GetKey((KeyCode)304, true) || ZInput.GetKey((KeyCode)303, true); } private void RegisterActivePlacementGhost() { if (!_registeredAsActivePlacementGhost) { _registeredAsActivePlacementGhost = true; _activePlacementGhostCount++; } } private void UnregisterActivePlacementGhost() { if (_registeredAsActivePlacementGhost) { _registeredAsActivePlacementGhost = false; _activePlacementGhostCount = Mathf.Max(0, _activePlacementGhostCount - 1); } } private void ApplyRuntimeBrushSettings(bool forceScale) { if (!((Object)(object)_brush == (Object)null)) { _brush.Radius = FlowerPaintBrushSettings.Radius; if (!_brush.RemoveMode) { _brush.DensityMultiplier = FlowerPaintBrushSettings.DensityMultiplier; } if (!((Object)(object)_scaler == (Object)null) && (forceScale || !Mathf.Approximately(_lastAppliedRadius, _brush.Radius))) { _lastAppliedRadius = _brush.Radius; _scaler.Radius = _brush.Radius; _scaler.Apply(); } } } private static void ShowSettingMessage(string text) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null); } } private static void SetPlacedMarkerColliders(bool enabledState) { for (int i = 0; i < FlowerPaintRegistry.All.Count; i++) { FlowerPaintMarker flowerPaintMarker = FlowerPaintRegistry.All[i]; if ((Object)(object)flowerPaintMarker != (Object)null) { flowerPaintMarker.SetPlacementColliderEnabled(enabledState); } } } private void DrawRing() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) int positionCount = _ring.positionCount; float num = Mathf.Max(0.5f, _brush.Radius); for (int i = 0; i < positionCount; i++) { float num2 = (float)i / (float)positionCount; float num3 = num2 * (float)Math.PI * 2f; Vector3 val = ((Component)this).transform.position + new Vector3(Mathf.Cos(num3) * num, 0f, Mathf.Sin(num3) * num); if (FlowerPaintSystem.TryGetTerrainPoint(val, out var point, out var normal)) { _ring.SetPosition(i, point + normal * 0.05f); } else { _ring.SetPosition(i, val + Vector3.up * 0.05f); } } } private void DrawRemovePreview() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing referen