using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace InfiniteWorld.Editor { public class WorldGeneratorEditorWindow : EditorWindow { private static readonly AutoTileShape[] WallShapeOrder = { AutoTileShape.OuterTopLeft, AutoTileShape.Top, AutoTileShape.OuterTopRight, AutoTileShape.Left, AutoTileShape.Center, AutoTileShape.Right, AutoTileShape.OuterBottomLeft, AutoTileShape.Bottom, AutoTileShape.OuterBottomRight, AutoTileShape.InnerTopLeft, AutoTileShape.InnerTopRight, AutoTileShape.InnerBottomLeft, AutoTileShape.InnerBottomRight }; private WorldAutotileProfile profile; private SerializedObject serializedProfile; private Vector2 scroll; [MenuItem("Tools/Infinite World/World Builder")] public static void Open() { GetWindow("World Builder"); } private void OnGUI() { DrawToolbar(); EditorGUILayout.Space(6f); if (profile == null) { EditorGUILayout.HelpBox("Assign or create a WorldAutotileProfile. The workflow is: create the authoring layout prefab, edit tiles inside that grid, then build the final profile back from the layout.", MessageType.Info); return; } if (serializedProfile == null || serializedProfile.targetObject != profile) { serializedProfile = new SerializedObject(profile); } serializedProfile.Update(); scroll = EditorGUILayout.BeginScrollView(scroll); DrawPaletteTools(); EditorGUILayout.Space(8f); DrawValidation(); EditorGUILayout.Space(8f); DrawProfileFields(); EditorGUILayout.EndScrollView(); serializedProfile.ApplyModifiedProperties(); if (GUI.changed) { EditorUtility.SetDirty(profile); WorldAutotileProfilePipeline.QueueProfileRefresh(profile); } } private void DrawToolbar() { EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); profile = (WorldAutotileProfile)EditorGUILayout.ObjectField(profile, typeof(WorldAutotileProfile), false, GUILayout.Width(position.width * 0.55f)); if (GUILayout.Button("New Profile", EditorStyles.toolbarButton, GUILayout.Width(90f))) { CreateProfileAsset(); } using (new EditorGUI.DisabledScope(profile == null)) { if (GUILayout.Button("Create Authoring Layout", EditorStyles.toolbarButton, GUILayout.Width(155f))) { WorldAutotileProfilePipeline.GenerateAuthoringLayout(profile); } } EditorGUILayout.EndHorizontal(); } private void DrawPaletteTools() { EditorGUILayout.LabelField("Palette Tools", EditorStyles.boldLabel); EditorGUILayout.BeginVertical("box"); EditorGUILayout.HelpBox("Create Authoring Layout builds a temporary editor-only prefab with marked grid sections. Edit tiles there, then use Build Profile From Layout to write the final WorldAutotileProfile.", MessageType.None); EditorGUILayout.PropertyField(serializedProfile.FindProperty("autoUpdatePaletteLayout"), new GUIContent("Auto Update Authoring Layout")); EditorGUILayout.PropertyField(serializedProfile.FindProperty("autoRefreshGeneratedWorld"), new GUIContent("Auto Refresh Generated World")); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Create / Update Layout")) { WorldAutotileProfilePipeline.GenerateAuthoringLayout(profile); } using (new EditorGUI.DisabledScope(WorldAutotileProfilePipeline.LoadAuthoringLayoutAsset(profile) == null)) { if (GUILayout.Button("Build Profile From Layout")) { WorldAutotileProfilePipeline.BuildProfileFromAuthoringLayout(profile); } if (GUILayout.Button("Open Layout Prefab")) { GameObject layout = WorldAutotileProfilePipeline.LoadAuthoringLayoutAsset(profile); if (layout != null) { AssetDatabase.OpenAsset(layout); } } } EditorGUILayout.EndHorizontal(); using (new EditorGUI.DisabledScope(WorldAutotileProfilePipeline.LoadAuthoringLayoutAsset(profile) == null)) { if (GUILayout.Button("Ping Layout Prefab")) { GameObject layout = WorldAutotileProfilePipeline.LoadAuthoringLayoutAsset(profile); if (layout != null) { EditorGUIUtility.PingObject(layout); Selection.activeObject = layout; } } } EditorGUILayout.LabelField("Layout Path", WorldAutotileProfilePipeline.GetAuthoringLayoutPath(profile)); EditorGUILayout.EndVertical(); } private void DrawValidation() { EditorGUILayout.LabelField("Profile Check", EditorStyles.boldLabel); EditorGUILayout.BeginVertical("box"); List missingShapes = GetMissingWallShapes(); if (missingShapes.Count == 0) { EditorGUILayout.HelpBox("All wall variants are assigned. The generated palette layout will include every corner, side, and center tile.", MessageType.Info); } else { EditorGUILayout.HelpBox("Missing wall variants: " + string.Join(", ", missingShapes), MessageType.Warning); } int environmentCount = CountAssignedEnvironmentTiles(); int prefabCount = CountAssignedRandomPrefabs(); EditorGUILayout.LabelField("Background", profile.baseGroundTile != null ? profile.baseGroundTile.name : "Not assigned"); EditorGUILayout.LabelField("Environment Tiles", environmentCount.ToString()); EditorGUILayout.LabelField("Random Prefabs", prefabCount.ToString()); EditorGUILayout.EndVertical(); } private void DrawProfileFields() { EditorGUILayout.LabelField("Profile Assets", EditorStyles.boldLabel); EditorGUILayout.PropertyField(serializedProfile.FindProperty("baseGroundTile"), new GUIContent("Background Tile")); EditorGUILayout.Space(6f); EditorGUILayout.LabelField("Wall Variants", EditorStyles.miniBoldLabel); SerializedProperty walls = serializedProfile.FindProperty("wallTiles"); DrawWallGrid(walls); EditorGUILayout.Space(6f); EditorGUILayout.PropertyField(serializedProfile.FindProperty("environmentTiles"), true); EditorGUILayout.Space(6f); EditorGUILayout.PropertyField(serializedProfile.FindProperty("randomPrefabs"), true); } private void DrawWallGrid(SerializedProperty walls) { DrawLabeledRow(walls, AutoTileShape.OuterTopLeft, AutoTileShape.Top, AutoTileShape.OuterTopRight); DrawLabeledRow(walls, AutoTileShape.Left, AutoTileShape.Center, AutoTileShape.Right); DrawLabeledRow(walls, AutoTileShape.OuterBottomLeft, AutoTileShape.Bottom, AutoTileShape.OuterBottomRight); DrawLabeledRow(walls, AutoTileShape.InnerTopLeft, AutoTileShape.InnerTopRight); DrawLabeledRow(walls, AutoTileShape.InnerBottomLeft, AutoTileShape.InnerBottomRight); } private static void DrawLabeledRow(SerializedProperty root, params AutoTileShape[] shapes) { EditorGUILayout.BeginHorizontal(); for (int i = 0; i < shapes.Length; i++) { DrawLabeledCell(root, shapes[i]); } EditorGUILayout.EndHorizontal(); } private static void DrawLabeledCell(SerializedProperty root, AutoTileShape shape) { SerializedProperty property = root.FindPropertyRelative(WorldAutotileEditorLabels.GetPropertyName(shape)); EditorGUILayout.BeginVertical(GUILayout.MaxWidth(150f)); EditorGUILayout.LabelField(WorldAutotileEditorLabels.GetShapeLabel(shape), EditorStyles.miniLabel); EditorGUILayout.PropertyField(property, GUIContent.none); EditorGUILayout.EndVertical(); } private List GetMissingWallShapes() { List missing = new List(); for (int i = 0; i < WallShapeOrder.Length; i++) { AutoTileShape shape = WallShapeOrder[i]; if (profile.wallTiles == null || profile.wallTiles.GetAssignedTile(shape) == null) { missing.Add(shape.ToString()); } } return missing; } private int CountAssignedEnvironmentTiles() { if (profile.environmentTiles == null) { return 0; } int count = 0; for (int i = 0; i < profile.environmentTiles.Count; i++) { if (profile.environmentTiles[i] != null && profile.environmentTiles[i].tile != null) { count++; } } return count; } private int CountAssignedRandomPrefabs() { if (profile.randomPrefabs == null) { return 0; } int count = 0; for (int i = 0; i < profile.randomPrefabs.Count; i++) { if (profile.randomPrefabs[i] != null && profile.randomPrefabs[i].prefab != null) { count++; } } return count; } private void CreateProfileAsset() { string path = EditorUtility.SaveFilePanelInProject("Create World Profile", "WorldAutotileProfile", "asset", "Choose where to save the tile profile."); if (string.IsNullOrEmpty(path)) { return; } WorldAutotileProfile asset = CreateInstance(); AssetDatabase.CreateAsset(asset, path); AssetDatabase.SaveAssets(); profile = asset; serializedProfile = new SerializedObject(profile); Selection.activeObject = asset; } } }