using UnityEngine;
using UnityEngine.Tilemaps;
using UnityEditorInternal;
using System.Collections.Generic;
namespace UnityEditor
{
///
/// The Editor for a RuleOverrideTileEditor.
///
[CustomEditor(typeof(RuleOverrideTile))]
public class RuleOverrideTileEditor : Editor
{
private static class Styles
{
public static readonly GUIContent overrideTile = EditorGUIUtility.TrTextContent("Tile"
, "The Rule Tile to override.");
}
///
/// The RuleOverrideTile being edited
///
public RuleOverrideTile overrideTile => target as RuleOverrideTile;
///
/// The RuleTileEditor for the overridden instance of the RuleTile
///
public RuleTileEditor ruleTileEditor
{
get
{
if (m_RuleTileEditorTarget != overrideTile.m_Tile)
{
DestroyImmediate(m_RuleTileEditor);
m_RuleTileEditor = Editor.CreateEditor(overrideTile.m_InstanceTile) as RuleTileEditor;
m_RuleTileEditorTarget = overrideTile.m_Tile;
}
return m_RuleTileEditor;
}
}
RuleTileEditor m_RuleTileEditor;
RuleTile m_RuleTileEditorTarget;
///
/// List of Sprites and overriding Sprites
///
public List> m_Sprites = new List>();
///
/// List of GameObjects and overriding GameObjects
///
public List> m_GameObjects = new List>();
private ReorderableList m_SpriteList;
private ReorderableList m_GameObjectList;
private int m_MissingOriginalSpriteIndex;
private int m_MissingOriginalGameObjectIndex;
///
/// Height for a Sprite Element
///
public static float k_SpriteElementHeight = 48;
///
/// Height for a GameObject Element
///
public static float k_GameObjectElementHeight = 16;
///
/// Padding between Rule Elements
///
public static float k_PaddingBetweenRules = 4;
///
/// OnEnable for the RuleOverrideTileEditor
///
public virtual void OnEnable()
{
if (m_SpriteList == null)
{
m_SpriteList = new ReorderableList(m_Sprites, typeof(KeyValuePair), false, true, false, false);
m_SpriteList.drawHeaderCallback = DrawSpriteListHeader;
m_SpriteList.drawElementCallback = DrawSpriteElement;
m_SpriteList.elementHeightCallback = GetSpriteElementHeight;
}
if (m_GameObjectList == null)
{
m_GameObjectList = new ReorderableList(m_GameObjects, typeof(KeyValuePair), false, true, false, false);
m_GameObjectList.drawHeaderCallback = DrawGameObjectListHeader;
m_GameObjectList.drawElementCallback = DrawGameObjectElement;
m_GameObjectList.elementHeightCallback = GetGameObjectElementHeight;
}
}
///
/// OnDisable for the RuleOverrideTileEditor
///
public virtual void OnDisable()
{
DestroyImmediate(ruleTileEditor);
m_RuleTileEditorTarget = null;
}
///
/// Draws the Inspector GUI for the RuleOverrideTileEditor
///
public override void OnInspectorGUI()
{
serializedObject.UpdateIfRequiredOrScript();
DrawTileField();
DrawCustomFields();
overrideTile.GetOverrides(m_Sprites, ref m_MissingOriginalSpriteIndex);
overrideTile.GetOverrides(m_GameObjects, ref m_MissingOriginalGameObjectIndex);
EditorGUI.BeginChangeCheck();
m_SpriteList.DoLayoutList();
if (EditorGUI.EndChangeCheck())
{
overrideTile.ApplyOverrides(m_Sprites);
SaveTile();
}
EditorGUI.BeginChangeCheck();
m_GameObjectList.DoLayoutList();
if (EditorGUI.EndChangeCheck())
{
overrideTile.ApplyOverrides(m_GameObjects);
SaveTile();
}
}
///
/// Draws the header for the Sprite list
///
/// GUI Rect to draw the header at
public void DrawSpriteListHeader(Rect rect)
{
float xMax = rect.xMax;
rect.xMax = rect.xMax / 2.0f;
GUI.Label(rect, "Original Sprite", EditorStyles.label);
rect.xMin = rect.xMax;
rect.xMax = xMax;
GUI.Label(rect, "Override Sprite", EditorStyles.label);
}
///
/// Draws the header for the GameObject list
///
/// GUI Rect to draw the header at
public void DrawGameObjectListHeader(Rect rect)
{
float xMax = rect.xMax;
rect.xMax = rect.xMax / 2.0f;
GUI.Label(rect, "Original GameObject", EditorStyles.label);
rect.xMin = rect.xMax;
rect.xMax = xMax;
GUI.Label(rect, "Override GameObject", EditorStyles.label);
}
///
/// Gets the GUI element height for a Sprite element with the given index
///
/// Index of the Sprite element
/// GUI element height for the Sprite element
public float GetSpriteElementHeight(int index)
{
float height = k_SpriteElementHeight + k_PaddingBetweenRules;
bool isMissing = index >= m_MissingOriginalSpriteIndex;
if (isMissing)
height += 16;
return height;
}
///
/// Gets the GUI element height for a GameObject element with the given index
///
/// Index of the GameObject element
/// GUI element height for the GameObject element
public float GetGameObjectElementHeight(int index)
{
float height = k_GameObjectElementHeight + k_PaddingBetweenRules;
bool isMissing = index >= m_MissingOriginalGameObjectIndex;
if (isMissing)
height += 16;
return height;
}
///
/// Draws the Sprite element for the RuleOverride list
///
/// Rect to draw the Sprite Element in
/// Index of the Sprite Element to draw
/// Whether the Sprite Element is active
/// Whether the Sprite Element is focused
public void DrawSpriteElement(Rect rect, int index, bool active, bool focused)
{
bool isMissing = index >= m_MissingOriginalSpriteIndex;
if (isMissing)
{
EditorGUI.HelpBox(new Rect(rect.xMin, rect.yMin, rect.width, 16), "Original Sprite missing", MessageType.Warning);
rect.yMin += 16;
}
Sprite originalSprite = m_Sprites[index].Key;
Sprite overrideSprite = m_Sprites[index].Value;
rect.y += 2;
rect.height -= k_PaddingBetweenRules;
rect.xMax = rect.xMax / 2.0f;
using (new EditorGUI.DisabledScope(true))
EditorGUI.ObjectField(new Rect(rect.xMin, rect.yMin, rect.height, rect.height), originalSprite, typeof(Sprite), false);
rect.xMin = rect.xMax;
rect.xMax *= 2.0f;
EditorGUI.BeginChangeCheck();
overrideSprite = EditorGUI.ObjectField(new Rect(rect.xMin, rect.yMin, rect.height, rect.height), overrideSprite, typeof(Sprite), false) as Sprite;
if (EditorGUI.EndChangeCheck())
m_Sprites[index] = new KeyValuePair(originalSprite, overrideSprite);
}
///
/// Draws the GameObject element for the RuleOverride list
///
/// Rect to draw the GameObject Element in
/// Index of the GameObject Element to draw
/// Whether the GameObject Element is active
/// Whether the GameObject Element is focused
public void DrawGameObjectElement(Rect rect, int index, bool active, bool focused)
{
bool isMissing = index >= m_MissingOriginalGameObjectIndex;
if (isMissing)
{
EditorGUI.HelpBox(new Rect(rect.xMin, rect.yMin, rect.width, 16), "Original GameObject missing", MessageType.Warning);
rect.yMin += 16;
}
GameObject originalGameObject = m_GameObjects[index].Key;
GameObject overrideGameObject = m_GameObjects[index].Value;
rect.y += 2;
rect.height -= k_PaddingBetweenRules;
rect.xMax = rect.xMax / 2.0f;
using (new EditorGUI.DisabledScope(true))
EditorGUI.ObjectField(new Rect(rect.xMin, rect.yMin, rect.width, rect.height), originalGameObject, typeof(GameObject), false);
rect.xMin = rect.xMax;
rect.xMax *= 2.0f;
EditorGUI.BeginChangeCheck();
overrideGameObject = EditorGUI.ObjectField(new Rect(rect.xMin, rect.yMin, rect.width, rect.height), overrideGameObject, typeof(GameObject), false) as GameObject;
if (EditorGUI.EndChangeCheck())
m_GameObjects[index] = new KeyValuePair(originalGameObject, overrideGameObject);
}
///
/// Draws a field for the RuleTile be overridden
///
public void DrawTileField()
{
EditorGUI.BeginChangeCheck();
RuleTile tile = EditorGUILayout.ObjectField(Styles.overrideTile, overrideTile.m_Tile, typeof(RuleTile), false) as RuleTile;
if (EditorGUI.EndChangeCheck())
{
if (!LoopCheck(tile))
{
overrideTile.m_Tile = tile;
SaveTile();
}
else
{
Debug.LogWarning("Circular tile reference");
}
}
bool LoopCheck(RuleTile checkTile)
{
if (!overrideTile.m_InstanceTile)
return false;
HashSet renferenceTils = new HashSet();
Add(overrideTile.m_InstanceTile);
return renferenceTils.Contains(checkTile);
void Add(RuleTile ruleTile)
{
if (renferenceTils.Contains(ruleTile))
return;
renferenceTils.Add(ruleTile);
var overrideTiles = RuleTileEditor.FindAffectedOverrideTiles(ruleTile);
foreach (var overrideTile in overrideTiles)
Add(overrideTile.m_InstanceTile);
}
}
}
///
/// Draw editor fields for custom properties for the RuleOverrideTile
///
public void DrawCustomFields()
{
if (ruleTileEditor)
{
ruleTileEditor.target.hideFlags = HideFlags.None;
ruleTileEditor.DrawCustomFields(true);
ruleTileEditor.target.hideFlags = HideFlags.NotEditable;
}
}
private void SaveInstanceTileAsset()
{
bool assetChanged = false;
if (overrideTile.m_InstanceTile)
{
if (!overrideTile.m_Tile || overrideTile.m_InstanceTile.GetType() != overrideTile.m_Tile.GetType())
{
DestroyImmediate(overrideTile.m_InstanceTile, true);
overrideTile.m_InstanceTile = null;
assetChanged = true;
}
}
if (!overrideTile.m_InstanceTile)
{
if (overrideTile.m_Tile)
{
var t = overrideTile.m_Tile.GetType();
RuleTile instanceTile = ScriptableObject.CreateInstance(t) as RuleTile;
instanceTile.hideFlags = HideFlags.NotEditable;
AssetDatabase.AddObjectToAsset(instanceTile, overrideTile);
overrideTile.m_InstanceTile = instanceTile;
assetChanged = true;
}
}
if (overrideTile.m_InstanceTile)
{
string instanceTileName = overrideTile.m_Tile.name + " (Override)";
if (overrideTile.m_InstanceTile.name != instanceTileName)
{
overrideTile.m_InstanceTile.name = instanceTileName;
assetChanged = true;
}
}
if (assetChanged)
{
EditorUtility.SetDirty(overrideTile.m_InstanceTile);
#if UNITY_2021_1
AssetDatabase.SaveAssets();
#else
AssetDatabase.SaveAssetIfDirty(overrideTile.m_InstanceTile);
#endif
}
}
///
/// Saves any changes to the RuleOverrideTile
///
public void SaveTile()
{
EditorUtility.SetDirty(target);
SceneView.RepaintAll();
SaveInstanceTileAsset();
if (overrideTile.m_InstanceTile)
{
overrideTile.Override();
RuleTileEditor.UpdateAffectedOverrideTiles(overrideTile.m_InstanceTile);
}
if (ruleTileEditor && ruleTileEditor.m_PreviewTilemaps != null)
{
foreach (var tilemap in ruleTileEditor.m_PreviewTilemaps)
tilemap.RefreshAllTiles();
}
}
///
/// Renders a static preview Texture2D for a RuleOverrideTile asset
///
/// Asset path of the RuleOverrideTile
/// Arrays of assets from the given Asset path
/// Width of the static preview
/// Height of the static preview
/// Texture2D containing static preview for the RuleOverrideTile asset
public override Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height)
{
if (ruleTileEditor)
return ruleTileEditor.RenderStaticPreview(assetPath, subAssets, width, height);
return base.RenderStaticPreview(assetPath, subAssets, width, height);
}
///
/// Whether the RuleOverrideTile has a preview GUI
///
/// True if RuleOverrideTile has a preview GUI. False if not.
public override bool HasPreviewGUI()
{
if (ruleTileEditor)
return ruleTileEditor.HasPreviewGUI();
return false;
}
///
/// Updates preview settings for the RuleOverrideTile.
///
public override void OnPreviewSettings()
{
if (ruleTileEditor)
ruleTileEditor.OnPreviewSettings();
}
///
/// Draws the preview GUI for the RuleTile
///
/// Rect to draw the preview GUI
/// The GUIStyle of the background for the preview
public override void OnPreviewGUI(Rect rect, GUIStyle background)
{
if (ruleTileEditor)
ruleTileEditor.OnPreviewGUI(rect, background);
}
}
}