using System; using System.Linq; using System.Text.RegularExpressions; using UnityEngine; using UnityEngine.Scripting.APIUpdating; using UnityEngine.Tilemaps; namespace UnityEditor.Tilemaps { /// /// Wizard for populating RuleOverrideTile from a SpriteSheet /// [MovedFrom(true, "UnityEditor")] public class PopulateRuleOverideTileWizard : ScriptableWizard { /// /// The Texture2D containing the Sprites to override with /// public Texture2D m_spriteSet; private RuleOverrideTile m_tileset; private void OnWizardCreate() { try { Populate(); } catch (Exception ex) { EditorUtility.DisplayDialog("Auto-populate failed!", ex.Message, "Ok"); CloneWizard(this); } } private void OnWizardUpdate() { isValid = m_tileset != null && m_spriteSet != null; } [MenuItem("CONTEXT/RuleOverrideTile/Populate From Sprite Sheet")] private static void MenuOption(MenuCommand menuCommand) { CreateWizard(menuCommand.context as RuleOverrideTile); } [MenuItem("CONTEXT/RuleOverrideTile/Populate From Sprite Sheet", true)] private static bool MenuOptionValidation(MenuCommand menuCommand) { var tile = menuCommand.context as RuleOverrideTile; return tile.m_Tile; } /// /// Creates a wizard for the target RuleOverrideTIle /// /// The RuleOverrideTile to be edited by the wizard public static void CreateWizard(RuleOverrideTile target) { var wizard = DisplayWizard("Populate Override", "Populate"); wizard.m_tileset = target; } /// /// Creates a new PopulateRuleOverideTileWizard and copies the settings from an existing PopulateRuleOverideTileWizard /// /// The wizard to copy settings from public static void CloneWizard(PopulateRuleOverideTileWizard oldWizard) { var wizard = DisplayWizard("Populate Override", "Populate"); wizard.m_tileset = oldWizard.m_tileset; wizard.m_spriteSet = oldWizard.m_spriteSet; } /// /// Attempts to populate the selected override tile using the chosen sprite. /// The assumption here is that the sprite set selected by the user has the same /// naming scheme as the original sprite. That is to say, they should both have the same number /// of sprites, each sprite ends in an underscore followed by a number, and that they are /// intended to be equivalent in function. /// private void Populate() { var spriteSheet = AssetDatabase.GetAssetPath(m_spriteSet); var overrideSprites = AssetDatabase.LoadAllAssetsAtPath(spriteSheet).OfType().ToArray(); var finished = false; try { Undo.RecordObject(m_tileset, "Auto-populate " + m_tileset.name); foreach (var rule in m_tileset.m_Tile.m_TilingRules) foreach (var originalSprite in rule.m_Sprites) { var spriteName = originalSprite.name; var spriteNumber = Regex.Match(spriteName, @"_\d+$").Value; var matchingOverrideSprite = overrideSprites.First(sprite => sprite.name.EndsWith(spriteNumber)); m_tileset[originalSprite] = matchingOverrideSprite; } finished = true; } catch (InvalidOperationException ex) { throw new ArgumentOutOfRangeException("Sprite sheet mismatch", ex); } finally { // We handle the undo like this in case we end up catching more exceptions. // We want this to ALWAYS happen unless we complete the population. if (!finished) Undo.PerformUndo(); } } } }