282 lines
11 KiB
C#
282 lines
11 KiB
C#
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<WorldGeneratorEditorWindow>("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<string> 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<string> GetMissingWallShapes()
|
|
{
|
|
List<string> missing = new List<string>();
|
|
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<WorldAutotileProfile>();
|
|
AssetDatabase.CreateAsset(asset, path);
|
|
AssetDatabase.SaveAssets();
|
|
profile = asset;
|
|
serializedProfile = new SerializedObject(profile);
|
|
Selection.activeObject = asset;
|
|
}
|
|
}
|
|
}
|