using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using PWCommon5; namespace GeNa.Core { public static class EditorUtilsExtensions { #region Methods public static void Fractal(this EditorUtils editorUtils, Fractal maskFractal, bool helpSwitch, bool showFalloff = true) { maskFractal.Enabled = editorUtils.Toggle("Noise Enabled", maskFractal.Enabled, helpSwitch); if (maskFractal.Enabled) { EditorGUI.indentLevel++; if (showFalloff) maskFractal.NoiseFalloff = editorUtils.CurveField("Noise Falloff", maskFractal.NoiseFalloff, helpSwitch); maskFractal.NoiseType = (Constants.NoiseType)editorUtils.EnumPopup("Mask Type", maskFractal.NoiseType, helpSwitch); maskFractal.Strength = editorUtils.Slider("Strength", maskFractal.Strength, -2f, 2f, helpSwitch); maskFractal.Seed = editorUtils.Slider("Seed", maskFractal.Seed, 1f, 65000f, helpSwitch); maskFractal.Octaves = editorUtils.IntSlider("Octaves", maskFractal.Octaves, 1, 15, helpSwitch); maskFractal.Frequency = editorUtils.Slider("Frequency", maskFractal.Frequency, 0.0001f, 1f, helpSwitch); maskFractal.Persistence = editorUtils.Slider("Persistence", maskFractal.Persistence, 0f, 1f, helpSwitch); maskFractal.Lacunarity = editorUtils.Slider("Lacunarity", maskFractal.Lacunarity, 1.5f, 3f, helpSwitch); maskFractal.Amplitude = editorUtils.Slider("Amplitude", maskFractal.Amplitude, 0.00001f, 1f, helpSwitch); switch (maskFractal.NoiseType) { case Constants.NoiseType.Perlin: case Constants.NoiseType.Billow: break; case Constants.NoiseType.Ridged: maskFractal.RidgedOffset = editorUtils.Slider("Ridge Offset", maskFractal.RidgedOffset, 0f, 3f, helpSwitch); break; case Constants.NoiseType.IQ: break; case Constants.NoiseType.Swiss: maskFractal.RidgedOffset = editorUtils.Slider("Ridge Offset", maskFractal.RidgedOffset, 0f, 3f, helpSwitch); maskFractal.Warp = editorUtils.Slider("Warp", maskFractal.Warp, 0f, 5f, helpSwitch); break; case Constants.NoiseType.Jordan: maskFractal.Warp = editorUtils.Slider("Warp", maskFractal.Warp, 0f, 5f, helpSwitch); maskFractal.Warp0 = editorUtils.Slider("Warp0", maskFractal.Warp0, 0f, 15f, helpSwitch); maskFractal.Damp = editorUtils.Slider("Damp", maskFractal.Damp, 0f, 5f, helpSwitch); maskFractal.Damp0 = editorUtils.Slider("Damp0", maskFractal.Damp0, 0f, 5f, helpSwitch); maskFractal.DampScale = editorUtils.Slider("Damp Scale", maskFractal.DampScale, -5, 20f, helpSwitch); break; /* * * CELL NOISE noiseCellType = EditorGUILayout.IntSlider(GetLabel("Cell Type"), noiseCellType, 1, 9); noiseCellDistanceFunction = EditorGUILayout.IntSlider(GetLabel("Cell Dist"), noiseCellDistanceFunction, 1, 7); */ default: throw new ArgumentOutOfRangeException(); } var offset = maskFractal.Offset; offset.x = editorUtils.FloatField("Offset X", offset.x, helpSwitch); offset.y = editorUtils.FloatField("Offset Y", offset.y, helpSwitch); maskFractal.Offset = offset; // Filters //maskFractal.Displacement = editorUtils.Slider("Displacement", maskFractal.Displacement, -1f, 1f); EditorGUI.indentLevel--; } } public static void ObjectField(this EditorUtils editorUtils, string key, SerializedProperty property, System.Type objType, bool allowSceneObjects, params GUILayoutOption[] options) { property.objectReferenceValue = EditorGUILayout.ObjectField(editorUtils.GetContent(key), property.objectReferenceValue, objType, allowSceneObjects, options); Rect rect = GUILayoutUtility.GetLastRect(); EditorGUI.BeginProperty(rect, editorUtils.GetContent(key), property); EditorGUI.EndProperty(); } public static void Popup(this EditorUtils editorUtils, string key, SerializedProperty intProperty, GUIContent[] optionKeys, bool helpSwitch) { Rect rect = EditorGUILayout.GetControlRect(); GUIContent label = EditorGUI.BeginProperty(rect, editorUtils.GetContent(key), intProperty); int selectedIndex = intProperty.intValue; intProperty.intValue = EditorGUI.Popup(rect, label, selectedIndex, optionKeys); EditorGUI.EndProperty(); editorUtils.InlineHelp(key, helpSwitch); } public static void MinMaxSliderWithFields(this EditorUtils editorUtils, SerializedProperty minValueProperty, SerializedProperty maxValueProperty, ref float minValue, ref float maxValue, float minLimit, float maxLimit, string key, bool helpSwitch) { Rect rect = EditorGUILayout.GetControlRect(); GUIContent label = EditorGUI.BeginProperty(rect, editorUtils.GetContent(key), minValueProperty); label = EditorGUI.BeginProperty(rect, label, maxValueProperty); rect = EditorGUI.PrefixLabel(rect, label); int indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; float min = minValue; float max = maxValue; Rect pos = new Rect(rect.x, rect.y, EditorGUIUtility.fieldWidth, rect.height); float value = EditorGUI.DelayedFloatField(pos, min); min = Mathf.Clamp(value, minLimit, maxLimit); if (!Mathf.Approximately(min, minValue) && max < min) max = min; pos = new Rect(rect.x + EditorGUIUtility.fieldWidth + 5f, rect.y, rect.width - 10f - 2 * EditorGUIUtility.fieldWidth, rect.height); EditorGUI.MinMaxSlider(pos, ref min, ref max, minLimit, maxLimit); pos = new Rect(rect.xMax - EditorGUIUtility.fieldWidth, rect.y, EditorGUIUtility.fieldWidth, rect.height); value = EditorGUI.DelayedFloatField(pos, max); max = Mathf.Clamp(value, minLimit, maxLimit); if (!Mathf.Approximately(max, maxValue) && max < min) min = max; minValue = min; maxValue = max; EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); EditorGUI.EndProperty(); editorUtils.InlineHelp(key, helpSwitch); } /// /// Handy layer mask interface /// /// /// /// /// /// public static LayerMask LayerMaskField(this EditorUtils editorUtils, string key, LayerMask layerMask, bool helpSwitch) { List layers = new List(); List layerNumbers = new List(); for (int i = 0; i < 32; i++) { string layerName = LayerMask.LayerToName(i); if (layerName != "") { layers.Add(layerName); layerNumbers.Add(i); } } int maskWithoutEmpty = 0; for (int i = 0; i < layerNumbers.Count; i++) { if (((1 << layerNumbers[i]) & layerMask.value) > 0) maskWithoutEmpty |= (1 << i); } maskWithoutEmpty = editorUtils.MaskField(key, maskWithoutEmpty, layers.ToArray(), helpSwitch); int mask = 0; for (int i = 0; i < layerNumbers.Count; i++) { if ((maskWithoutEmpty & (1 << i)) > 0) mask |= (1 << layerNumbers[i]); } layerMask.value = mask; return layerMask; } /// /// Handy layer mask interface /// /// /// /// /// /// public static void LayerMaskField(this EditorUtils editorUtils, string key, SerializedProperty property, bool helpSwitch) { Rect rect = EditorGUILayout.GetControlRect(); GUIContent label = EditorGUI.BeginProperty(rect, editorUtils.GetContent(key), property); List layers = new List(); List layerNumbers = new List(); for (int i = 0; i < 32; i++) { string layerName = LayerMask.LayerToName(i); if (layerName != "") { layers.Add(layerName); layerNumbers.Add(i); } } int maskWithoutEmpty = 0; for (int i = 0; i < layerNumbers.Count; i++) { if (((1 << layerNumbers[i]) & property.intValue) > 0) maskWithoutEmpty |= (1 << i); } maskWithoutEmpty = EditorGUI.MaskField(rect, label, maskWithoutEmpty, layers.ToArray()); int mask = 0; for (int i = 0; i < layerNumbers.Count; i++) { if ((maskWithoutEmpty & (1 << i)) > 0) mask |= (1 << layerNumbers[i]); } property.intValue = mask; EditorGUI.EndProperty(); editorUtils.InlineHelp(key, helpSwitch); } public static bool BeginOverrideToggle(bool @override, EditorApplication.CallbackFunction toggleCallback, EditorApplication.CallbackFunction guiCallback) { if (BeginControlToggle(@override, out bool enabled)) toggleCallback(); @override = enabled; if (GUI.enabled == false) enabled = false; GUI.enabled = enabled; guiCallback(); GUI.enabled = false; EndControlToggle(); return @override; } /// /// Create toggle to enable/disable a control and returns true if the value of the toggle changes. /// /// /// public static bool BeginControlToggle(bool current, out bool enabled) { GUILayout.BeginHorizontal(); EditorGUI.BeginChangeCheck(); enabled = EditorGUILayout.Toggle(current, GUILayout.Width(60f), GUILayout.ExpandWidth(false)); bool changed = EditorGUI.EndChangeCheck(); // Toggle works arkwardly with the clickable area shifting out to the left. It becomes non-clickable with smaller width, so using this trick. GUILayout.Space(-48f); EditorGUI.BeginDisabledGroup(!enabled); return changed; } /// /// Create toggle to enable/disable a control. /// public static void EndControlToggle() { EditorGUI.EndDisabledGroup(); GUILayout.EndHorizontal(); } public static void TerrainModifier(this EditorUtils editorUtils, TerrainModifier terrainModifier, bool helpSwitch, Action addBrushTexture = null, Action removeBrushTexture = null, Action clearBrushTexture = null) { if (terrainModifier == null) return; // Shape terrainModifier.Enabled = editorUtils.Toggle("Enabled", terrainModifier.Enabled, helpSwitch); GUI.enabled = terrainModifier.Enabled; EditorGUI.indentLevel++; terrainModifier.BrushIndex = editorUtils.BrushSelectionGrid("TxBrush Shape", terrainModifier.BrushIndex, out _, terrainModifier.BrushTextures.ToArray(), addBrushTexture ?? terrainModifier.AddBrushTexture, removeBrushTexture ?? terrainModifier.RemoveBrushTexture, clearBrushTexture ?? terrainModifier.ClearBrushTextures, helpSwitch); terrainModifier.EffectType = (EffectType)editorUtils.EnumPopup("Effect Type", terrainModifier.EffectType, helpSwitch); EffectType effectType = terrainModifier.EffectType; Terrain terrain = Terrain.activeTerrain; if (terrain != null) { TerrainData terrainData = terrain.terrainData; switch (effectType) { case EffectType.Texture: int alphamapLayers = terrainData.alphamapLayers; TerrainLayer[] terrainLayers = terrainData.terrainLayers; GUIContent[] textureChoices = new GUIContent[alphamapLayers]; for (int assetIdx = 0; assetIdx < textureChoices.Length; assetIdx++) textureChoices[assetIdx] = new GUIContent(terrainLayers[assetIdx].diffuseTexture.name); terrainModifier.TextureProtoIndex = editorUtils.Popup("Texture", terrainModifier.TextureProtoIndex, textureChoices, helpSwitch); break; case EffectType.Detail: DetailPrototype[] detailPrototypes = terrainData.detailPrototypes; GUIContent[] detailChoices = new GUIContent[detailPrototypes.Length]; for (int assetIdx = 0; assetIdx < detailChoices.Length; assetIdx++) { DetailPrototype detailProto = detailPrototypes[assetIdx]; string name = "Unknown asset"; if (detailProto.prototype != null) name = detailProto.prototype.name; else if (detailProto.prototypeTexture != null) name = detailProto.prototypeTexture.name; detailChoices[assetIdx] = new GUIContent(name); } terrainModifier.DetailProtoIndex = editorUtils.Popup("Details", terrainModifier.DetailProtoIndex, detailChoices, helpSwitch); break; } } switch (effectType) { case EffectType.Raise: case EffectType.Lower: terrainModifier.Strength = editorUtils.FloatField("Strength", terrainModifier.Strength, helpSwitch); break; default: terrainModifier.Strength = editorUtils.Slider("Strength", terrainModifier.Strength, 0f, 50f, helpSwitch); break; } terrainModifier.InvertAlpha = editorUtils.Toggle("Invert Alpha", terrainModifier.InvertAlpha, helpSwitch); terrainModifier.AreaOfEffect = editorUtils.IntField("Area Of Effect", terrainModifier.AreaOfEffect, helpSwitch); editorUtils.Fractal(terrainModifier.NoiseFractal, helpSwitch); if (editorUtils.Button("Apply to Terrain")) { //if (EditorUtility.DisplayDialog("Warning", // "You are about to apply the current changes to the terrain. This cannot be undone.", // "Okay", // "Cancel")) //{ terrainModifier.ApplyToTerrain(); //} } EditorGUI.indentLevel--; GUI.enabled = true; } public static void BoundsModifier(this EditorUtils editorUtils, BoundsModifier boundsModifier, bool helpSwitch) { if (boundsModifier == null) return; boundsModifier.Ignore = editorUtils.Toggle("Bounds Ignore", boundsModifier.Ignore, helpSwitch); GUI.enabled = !boundsModifier.Ignore; boundsModifier.ShapeType = (SdfShape.Type)editorUtils.EnumPopup("Shape Type", boundsModifier.ShapeType, helpSwitch); boundsModifier.Center = editorUtils.Vector3Field("Bounds Center", boundsModifier.Center, helpSwitch); switch (boundsModifier.ShapeType) { case SdfShape.Type.Box: boundsModifier.Size = editorUtils.Vector3Field("Bounds Size", boundsModifier.Size, helpSwitch); break; case SdfShape.Type.Sphere: boundsModifier.Radius = editorUtils.FloatField("Bounds Radius", boundsModifier.Radius, helpSwitch); break; case SdfShape.Type.Capsule: case SdfShape.Type.Cylinder: boundsModifier.Radius = editorUtils.FloatField("Bounds Radius", boundsModifier.Radius, helpSwitch); boundsModifier.Height = editorUtils.FloatField("Bounds Height", boundsModifier.Height, helpSwitch); break; } GUI.enabled = true; } /// /// Options to Edit the Spawn Criteria Overrides of a prototype /// /// /// /// /// /// public static SpawnCriteria SpawnCriteriaOverrides(this EditorUtils editorUtils, SpawnCriteria crit, SpawnCriteria @override, bool helpSwitch, bool useLargeRanges = false) { if (@override == null) @override = crit; crit.OverrideChildren = EditorGUILayout.Toggle("Override Children", crit.OverrideChildren); //crit.ForceSpawn = editorUtils.Toggle("Force Spawn", crit.ForceSpawn); //crit.OverrideForceSpawn = crit.ForceSpawn; //GUI.enabled = !crit.ForceSpawn; crit.OverrideVirginCheckType = BeginOverrideToggle(crit.OverrideVirginCheckType, () => crit.CheckCollisionType = @override.CheckCollisionType, () => crit.CheckCollisionType = (Constants.VirginCheckType)editorUtils.EnumPopup("Check Collisions", crit.CheckCollisionType)); editorUtils.InlineHelp("Check Collisions", helpSwitch); //crit.ForceSpawn = EditorGUILayout.Toggle(crit.ForceSpawn, "Force Spawn"); if (crit.CheckCollisionType != Constants.VirginCheckType.None) // && proto.ResourceType < Constants.ResourceType.TerrainGrass) { if (crit.CheckCollisionType == Constants.VirginCheckType.Bounds) { EditorGUI.indentLevel += 1; crit.OverrideSpawnCollisionLayers = BeginOverrideToggle(crit.OverrideSpawnCollisionLayers, () => crit.SpawnCollisionLayers = @override.SpawnCollisionLayers, () => crit.SpawnCollisionLayers = editorUtils.LayerMaskField("Collision Layers", crit.SpawnCollisionLayers, helpSwitch)); editorUtils.InlineHelp("Collision Layers", helpSwitch); // Modify Bounds crit.OverrideBoundsBorder = BeginOverrideToggle(crit.OverrideBoundsBorder, () => crit.BlendAmount = @override.BlendAmount, () => crit.BlendAmount = editorUtils.Slider("Blend Amount", crit.BlendAmount, 0.001f, 10f)); editorUtils.InlineHelp("Blend Amount", helpSwitch); crit.OverrideRayExtents = BeginOverrideToggle(crit.OverrideRayExtents, () => crit.BoundsExtents = @override.BoundsExtents, () => crit.BoundsExtents = editorUtils.Slider("Bounds Extents", crit.BoundsExtents, 0.0f, 100f)); editorUtils.InlineHelp("Bounds Extents", helpSwitch); EditorGUI.indentLevel -= 1; } } // Check Height crit.OverrideCheckHeight = BeginOverrideToggle(crit.OverrideCheckHeight, () => crit.CheckHeightType = @override.CheckHeightType, () => crit.CheckHeightType = (Constants.CriteriaRangeType)editorUtils.EnumPopup("Check Height Type", crit.CheckHeightType)); editorUtils.InlineHelp("Check Height Type", helpSwitch); if (crit.CheckHeightType != Constants.CriteriaRangeType.None) { EditorGUI.indentLevel++; if (crit.CheckHeightType >= Constants.CriteriaRangeType.MinMax) { // Min Spawn Slope crit.OverrideMinMaxHeight = BeginOverrideToggle(crit.OverrideMinMaxHeight, () => { crit.MinHeight = @override.MinHeight; crit.MaxHeight = @override.MaxHeight; }, () => { float minValue = crit.MinHeight; float maxValue = crit.MaxHeight; float minLimit = crit.BottomBoundary; float maxLimit = crit.TopBoundary; bool oldState = GUI.enabled; GUI.enabled = crit.OverrideMinMaxHeight && crit.CheckHeightType >= Constants.CriteriaRangeType.MinMax; editorUtils.MinMaxSliderWithFields("Min Max Height", ref minValue, ref maxValue, minLimit, maxLimit); GUI.enabled = oldState; crit.MinHeight = minValue; crit.MaxHeight = maxValue; }); editorUtils.InlineHelp("Min Max Height", helpSwitch); } if (crit.CheckHeightType != Constants.CriteriaRangeType.MinMax) { bool oldState = GUI.enabled; GUI.enabled = false; // Min Spawn Slope crit.OverrideMinMaxSpawnHeight = BeginOverrideToggle(crit.OverrideMinMaxSpawnHeight, () => { crit.MinSpawnHeight = @override.MinSpawnHeight; crit.MaxSpawnHeight = @override.MaxSpawnHeight; }, () => { float minValue = crit.MinHeight; float maxValue = crit.MaxHeight; float minSpawnValue = crit.MinSpawnHeight; float maxSpawnValue = crit.MaxSpawnHeight; float minLimit = crit.BottomBoundary; float maxLimit = crit.TopBoundary; Color oldColor = GUI.color; if (crit.CheckHeightType == Constants.CriteriaRangeType.Mixed) if (maxSpawnValue <= minValue || minSpawnValue >= maxValue) GUI.color = Color.red; editorUtils.MinMaxSliderWithFields("Min Max Spawn Height", ref minSpawnValue, ref maxSpawnValue, minLimit, maxLimit); GUI.color = oldColor; crit.MinSpawnHeight = minSpawnValue; crit.MaxSpawnHeight = maxSpawnValue; }); editorUtils.InlineHelp("Min Max Spawn Height", helpSwitch); GUI.enabled = oldState; } switch (crit.CheckHeightType) { case Constants.CriteriaRangeType.Range: case Constants.CriteriaRangeType.Mixed: // Height Variance crit.OverrideHeightVariance = BeginOverrideToggle(crit.OverrideHeightVariance, () => crit.HeightRange = @override.HeightRange, () => crit.HeightRange = editorUtils.Slider("Height Range", crit.HeightRange, 0.1f, 200f)); editorUtils.InlineHelp("Height Range", helpSwitch); break; } EditorGUI.indentLevel--; } // Check Slope crit.OverrideCheckSlope = BeginOverrideToggle(crit.OverrideCheckSlope, () => crit.CheckSlopeType = @override.CheckSlopeType, () => crit.CheckSlopeType = (Constants.CriteriaRangeType)editorUtils.EnumPopup("Check Slope Type", crit.CheckSlopeType)); editorUtils.InlineHelp("Check Slope Type", helpSwitch); if (crit.CheckSlopeType != Constants.CriteriaRangeType.None) { EditorGUI.indentLevel++; if (crit.CheckSlopeType >= Constants.CriteriaRangeType.MinMax) { // Min Spawn Slope crit.OverrideMinMaxSlope = BeginOverrideToggle(crit.OverrideMinMaxSlope, () => { crit.MinSlope = @override.MinSlope; crit.MaxSlope = @override.MaxSlope; }, () => { float minValue = crit.MinSlope; float maxValue = crit.MaxSlope; float minLimit = 0f; float maxLimit = 90f; bool oldState = GUI.enabled; GUI.enabled = crit.OverrideMinMaxSlope && crit.CheckSlopeType >= Constants.CriteriaRangeType.MinMax; editorUtils.MinMaxSliderWithFields("Min Max Slope", ref minValue, ref maxValue, minLimit, maxLimit); GUI.enabled = oldState; crit.MinSlope = minValue; crit.MaxSlope = maxValue; }); editorUtils.InlineHelp("Min Max Slope", helpSwitch); } if (crit.CheckSlopeType != Constants.CriteriaRangeType.MinMax) { bool oldState = GUI.enabled; GUI.enabled = false; // Min Spawn Slope crit.OverrideMinMaxSpawnSlope = BeginOverrideToggle(crit.OverrideMinMaxSpawnSlope, () => { crit.MinSpawnSlope = @override.MinSpawnSlope; crit.MaxSpawnSlope = @override.MaxSpawnSlope; }, () => { float minValue = crit.MinSlope; float maxValue = crit.MaxSlope; float minSpawnValue = crit.MinSpawnSlope; float maxSpawnValue = crit.MaxSpawnSlope; float minLimit = 0f; float maxLimit = 90f; Color oldColor = GUI.color; if (crit.CheckSlopeType == Constants.CriteriaRangeType.Mixed) if (maxSpawnValue <= minValue || minSpawnValue >= maxValue) GUI.color = Color.red; editorUtils.MinMaxSliderWithFields("Min Max Spawn Slope", ref minSpawnValue, ref maxSpawnValue, minLimit, maxLimit); GUI.color = oldColor; crit.MinSpawnSlope = minSpawnValue; crit.MaxSpawnSlope = maxSpawnValue; }); editorUtils.InlineHelp("Min Max Spawn Slope", helpSwitch); GUI.enabled = oldState; } switch (crit.CheckSlopeType) { case Constants.CriteriaRangeType.Range: case Constants.CriteriaRangeType.Mixed: // Slope Range (Variance) crit.OverrideSlopeVariance = BeginOverrideToggle(crit.OverrideSlopeVariance, () => crit.SlopeRange = @override.SlopeRange, () => crit.SlopeRange = editorUtils.Slider("Slope Range", crit.SlopeRange, 0.1f, 180f)); editorUtils.InlineHelp("Slope Range", helpSwitch); break; } EditorGUI.indentLevel--; } // Check Textures crit.OverrideCheckTextures = BeginOverrideToggle(crit.OverrideCheckTextures, () => crit.CheckTextures = @override.CheckTextures, () => { EditorGUILayout.LabelField("Check Textures"); }); editorUtils.InlineHelp("Check Textures", helpSwitch); if (crit.OverrideCheckTextures) { EditorGUI.indentLevel++; crit.CheckTextures = EditorGUILayout.ToggleLeft("Enabled", crit.CheckTextures); GUI.enabled = crit.CheckTextures; Terrain terrain = Terrain.activeTerrain; if (terrain != null) { var terrainData = terrain.terrainData; var terrainLayers = terrainData.terrainLayers; var alphamapLayers = terrainData.alphamapLayers; GUIContent[] assetChoices = new GUIContent[alphamapLayers]; for (int assetIdx = 0; assetIdx < assetChoices.Length; assetIdx++) { assetChoices[assetIdx] = new GUIContent(terrainLayers[assetIdx].diffuseTexture.name); } if (assetChoices.Length == 0) { EditorGUILayout.LabelField("There are no Textures on Terrain"); } else { int oldIdx = crit.SelectedTextureIdx; crit.OverrideSelectedTextureIdx = BeginOverrideToggle(crit.OverrideSelectedTextureIdx, () => { crit.SelectedTextureIdx = @override.SelectedTextureIdx; string name = "No Textures on Terrain"; if (crit.SelectedTextureIdx >= 0 && crit.SelectedTextureIdx < terrainLayers.Length) name = terrainLayers[crit.SelectedTextureIdx].diffuseTexture.name; crit.SelectedTextureName = name; }, () => { crit.SelectedTextureIdx = EditorGUILayout.Popup(crit.SelectedTextureIdx, assetChoices); }); editorUtils.InlineHelp("Texture Selection", helpSwitch); if (crit.SelectedTextureIdx != oldIdx) { string name = terrainLayers[crit.SelectedTextureIdx].diffuseTexture.name; crit.SelectedTextureName = name; } } } // Texture Strength crit.OverrideTextureStrength = BeginOverrideToggle(crit.OverrideTextureStrength, () => crit.TextureStrength = @override.TextureStrength, () => crit.TextureStrength = editorUtils.Slider("Texture Strength", crit.TextureStrength, 0.0f, 1f)); editorUtils.InlineHelp("Texture Strength", helpSwitch); // Texture Range (Variance) crit.OverrideTextureVariance = BeginOverrideToggle(crit.OverrideTextureVariance, () => crit.TextureRange = @override.TextureRange, () => crit.TextureRange = editorUtils.Slider("Texture Range", crit.TextureRange, 0.0f, 1f)); editorUtils.InlineHelp("Texture Range", helpSwitch); EditorGUI.indentLevel--; GUI.enabled = true; } // Check Mask crit.OverrideCheckMask = BeginOverrideToggle(crit.OverrideCheckMask, () => crit.CheckMask = @override.CheckMask, () => EditorGUILayout.LabelField("Check Mask")); editorUtils.InlineHelp("Check Mask", helpSwitch); if (crit.OverrideCheckMask) { EditorGUI.indentLevel++; crit.CheckMask = EditorGUILayout.ToggleLeft("Enabled", crit.CheckMask); GUI.enabled = crit.CheckMask; // Check Mask Type crit.OverrideCheckMaskType = BeginOverrideToggle(crit.OverrideCheckMaskType, () => crit.CheckMaskType = @override.CheckMaskType, () => crit.CheckMaskType = (Constants.MaskType)editorUtils.EnumPopup("Check Mask", crit.CheckMaskType)); editorUtils.InlineHelp("Check Mask", helpSwitch); if (crit.CheckMaskType != Constants.MaskType.Image) { // Mask Fractal Fractal maskFractal = crit.MaskFractal; Fractal overrideMaskFractal = @override.MaskFractal; // Seed crit.OverrideMaskFractalSeed = BeginOverrideToggle(crit.OverrideMaskFractalSeed, () => maskFractal.Seed = overrideMaskFractal.Seed, () => maskFractal.Seed = editorUtils.Slider("Seed", maskFractal.Seed, 0f, 65000f)); editorUtils.InlineHelp("Seed", helpSwitch); // Octaves crit.OverrideMaskFractalOctaves = BeginOverrideToggle(crit.OverrideMaskFractalOctaves, () => maskFractal.Octaves = overrideMaskFractal.Octaves, () => maskFractal.Octaves = editorUtils.IntSlider("Octaves", maskFractal.Octaves, 1, 12)); editorUtils.InlineHelp("Octaves", helpSwitch); // Frequency crit.OverrideMaskFractalFrequency = BeginOverrideToggle(crit.OverrideMaskFractalFrequency, () => maskFractal.Frequency = overrideMaskFractal.Frequency, () => maskFractal.Frequency = editorUtils.Slider("Frequency", maskFractal.Frequency, 0f, useLargeRanges ? 1f : 0.3f)); editorUtils.InlineHelp("Frequency", helpSwitch); // Persistence crit.OverrideMaskFractalPersistence = BeginOverrideToggle(crit.OverrideMaskFractalPersistence, () => maskFractal.Persistence = overrideMaskFractal.Persistence, () => maskFractal.Persistence = editorUtils.Slider("Persistence", maskFractal.Persistence, 0f, 1f)); editorUtils.InlineHelp("Persistence", helpSwitch); // Lacunarity crit.OverrideMaskFractalLacunarity = BeginOverrideToggle(crit.OverrideMaskFractalLacunarity, () => maskFractal.Lacunarity = overrideMaskFractal.Lacunarity, () => maskFractal.Lacunarity = editorUtils.Slider("Lacunarity", maskFractal.Persistence, 1.5f, 3.5f)); editorUtils.InlineHelp("Lacunarity", helpSwitch); // Midpoint crit.OverrideMidMaskFractal = BeginOverrideToggle(crit.OverrideMidMaskFractal, () => crit.MidMaskFractal = @override.MidMaskFractal, () => crit.MidMaskFractal = editorUtils.Slider("Midpoint", crit.MidMaskFractal, 0f, 1f)); editorUtils.InlineHelp("Midpoint", helpSwitch); // Range crit.OverrideMaskFractalRange = BeginOverrideToggle(crit.OverrideMaskFractalRange, () => crit.MaskFractalRange = @override.MaskFractalRange, () => crit.MaskFractalRange = editorUtils.Slider("Range", crit.MaskFractalRange, 0f, 1f)); editorUtils.InlineHelp("Range", helpSwitch); // Invert Mask crit.OverrideMaskInvert = BeginOverrideToggle(crit.OverrideMaskInvert, () => crit.MaskInvert = @override.MaskInvert, () => crit.MaskInvert = editorUtils.Toggle("Invert Mask", crit.MaskInvert)); editorUtils.InlineHelp("Invert Mask", helpSwitch); } else { // Mask Image crit.OverrideMaskImage = BeginOverrideToggle(crit.OverrideMaskImage, () => crit.MaskImage = @override.MaskImage, () => crit.MaskImage = (Texture2D)editorUtils.ObjectField("Image Mask", crit.MaskImage, typeof(Texture2D), false)); editorUtils.InlineHelp("Image Mask", helpSwitch); // Image Filter Color crit.OverrideImageFilterColor = BeginOverrideToggle(crit.OverrideImageFilterColor, () => crit.ImageFilterColor = @override.ImageFilterColor, () => crit.ImageFilterColor = editorUtils.ColorField("Selection Color", crit.ImageFilterColor)); editorUtils.InlineHelp("Selection Color", helpSwitch); // Image Filter Fuzzy Match crit.OverrideImageFilterFuzzyMatch = BeginOverrideToggle(crit.OverrideImageFilterFuzzyMatch, () => crit.ImageFilterFuzzyMatch = @override.ImageFilterFuzzyMatch, () => crit.ImageFilterFuzzyMatch = editorUtils.Slider("Selection Accuracy", crit.ImageFilterFuzzyMatch, 0f, 1f)); editorUtils.InlineHelp("Selection Accuracy", helpSwitch); // Constrain Within Masked Bounds crit.OverrideConstrainWithinMaskedBounds = BeginOverrideToggle(crit.OverrideConstrainWithinMaskedBounds, () => crit.ConstrainWithinMaskedBounds = @override.ConstrainWithinMaskedBounds, () => crit.ConstrainWithinMaskedBounds = editorUtils.Toggle("Fit Within Mask", crit.ConstrainWithinMaskedBounds)); editorUtils.InlineHelp("Fit Within Mask", helpSwitch); // Invert Masked Alpha crit.OverrideInvertMaskedAlpha = BeginOverrideToggle(crit.OverrideInvertMaskedAlpha, () => crit.InvertMaskedAlpha = @override.InvertMaskedAlpha, () => crit.InvertMaskedAlpha = editorUtils.Toggle("Invert Alpha", crit.InvertMaskedAlpha)); editorUtils.InlineHelp("Invert Alpha", helpSwitch); // Success On Masked Alpha crit.OverrideSuccessOnMaskedAlpha = BeginOverrideToggle(crit.OverrideSuccessOnMaskedAlpha, () => crit.SuccessOnMaskedAlpha = @override.SuccessOnMaskedAlpha, () => crit.SuccessOnMaskedAlpha = editorUtils.Toggle("Success By Alpha", crit.SuccessOnMaskedAlpha)); editorUtils.InlineHelp("Success By Alpha", helpSwitch); // Scale On Masked Alpha crit.OverrideScaleOnMaskedAlpha = BeginOverrideToggle(crit.OverrideScaleOnMaskedAlpha, () => crit.ScaleOnMaskedAlpha = @override.ScaleOnMaskedAlpha, () => crit.ScaleOnMaskedAlpha = editorUtils.Toggle("Scale By Alpha", crit.ScaleOnMaskedAlpha)); editorUtils.InlineHelp("Scale By Alpha", helpSwitch); if (crit.ScaleOnMaskedAlpha) { EditorGUI.indentLevel++; // Min Scale On Masked Alpha crit.OverrideMinScaleOnMaskedAlpha = BeginOverrideToggle(crit.OverrideMinScaleOnMaskedAlpha, () => crit.MinScaleOnMaskedAlpha = @override.MinScaleOnMaskedAlpha, () => crit.MinScaleOnMaskedAlpha = editorUtils.Slider("Mask Alpha Min Scale", crit.MinScaleOnMaskedAlpha, 0f, 10f)); editorUtils.InlineHelp("Mask Alpha Min Scale", helpSwitch); // Max Scale On Masked Alpha crit.OverrideMaxScaleOnMaskedAlpha = BeginOverrideToggle(crit.OverrideMaxScaleOnMaskedAlpha, () => crit.MaxScaleOnMaskedAlpha = @override.MaxScaleOnMaskedAlpha, () => crit.MaxScaleOnMaskedAlpha = editorUtils.Slider("Mask Alpha Max Scale", crit.MaxScaleOnMaskedAlpha, 0f, 10f)); editorUtils.InlineHelp("Mask Alpha Max Scale", helpSwitch); EditorGUI.indentLevel--; } } EditorGUI.indentLevel--; } GUI.enabled = true; return crit; } public static void SpawnFlags(this EditorUtils editorUtils, SpawnFlags spawnFlags, bool canUseColliders, bool helpEnabled) { GUIStyle spawnFlagsPanel = new GUIStyle(GUI.skin.window) { normal = { textColor = GUI.skin.label.normal.textColor }, alignment = TextAnchor.UpperCenter, margin = new RectOffset(0, 0, 5, 7), padding = new RectOffset(10, 10, 3, 3), stretchWidth = true, stretchHeight = false }; //resFlagsPanel.fontStyle = FontStyle.Bold; // Need a bunch of weird stuff here int indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; float labelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth -= 5f + 10f * indent; float fieldsWidth = EditorGUIUtility.labelWidth; float indentWidth = 12f * indent; GUILayoutOption fieldOption = GUILayout.Width(fieldsWidth + 15f); spawnFlags.ApplyToChildren = editorUtils.Toggle("ApplyToChildren", spawnFlags.ApplyToChildren, helpEnabled); GUILayout.BeginHorizontal(); { GUILayout.Space(indentWidth + 12f); GUILayout.BeginVertical(spawnFlagsPanel, fieldOption); { spawnFlags.FlagBatchingStatic = editorUtils.Toggle("Static Batching", spawnFlags.FlagBatchingStatic, helpEnabled, fieldOption); spawnFlags.FlagLightmapStatic = editorUtils.Toggle("Static Lightmap", spawnFlags.FlagLightmapStatic, helpEnabled, fieldOption); spawnFlags.FlagOccludeeStatic = editorUtils.Toggle("Static Occludee", spawnFlags.FlagOccludeeStatic, helpEnabled, fieldOption); spawnFlags.FlagOccluderStatic = editorUtils.Toggle("Static Occluder", spawnFlags.FlagOccluderStatic, helpEnabled, fieldOption); #if !UNITY_2022_2_OR_NEWER spawnFlags.FlagNavigationStatic = editorUtils.Toggle("Static Navigation", spawnFlags.FlagNavigationStatic, helpEnabled, fieldOption); //spawnFlags.FlagOffMeshLinkGeneration = editorUtils.Toggle("Offmesh Link Gen", spawnFlags.FlagOffMeshLinkGeneration, helpEnabled, fieldOption); #endif } GUILayout.EndVertical(); GUILayout.Space(20f); GUILayout.BeginVertical(spawnFlagsPanel, fieldOption); { spawnFlags.FlagReflectionProbeStatic = editorUtils.Toggle("Static Ref Probe", spawnFlags.FlagReflectionProbeStatic, helpEnabled, fieldOption); //spawnFlags.FlagMovingObject = editorUtils.Toggle("Moving Object", spawnFlags.FlagMovingObject, helpEnabled, fieldOption); spawnFlags.FlagIsOutdoorObject = editorUtils.Toggle("Outdoor Object", spawnFlags.FlagIsOutdoorObject, helpEnabled, fieldOption); spawnFlags.FlagForceOptimise = editorUtils.Toggle("Force Optimise", spawnFlags.FlagForceOptimise, helpEnabled, fieldOption); spawnFlags.FlagCanBeOptimised = editorUtils.Toggle("Can Optimise", spawnFlags.FlagCanBeOptimised, helpEnabled, fieldOption); EditorGUI.BeginDisabledGroup(!canUseColliders); spawnFlags.UseColliderBounds = editorUtils.Toggle("Use Collider Bounds", spawnFlags.UseColliderBounds, helpEnabled, fieldOption); EditorGUI.EndDisabledGroup(); if (spawnFlags.FlagForceOptimise) spawnFlags.FlagCanBeOptimised = true; } GUILayout.EndVertical(); GUILayout.Space(-40f); } GUILayout.EndHorizontal(); EditorGUIUtility.labelWidth = labelWidth; EditorGUI.indentLevel = indent; } #endregion } }