using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Scripting.APIUpdating;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.Tilemaps
{
///
/// Rule Override Tiles are Tiles which can override a subset of Rules for a given Rule Tile to provide specialised behaviour while keeping most of the Rules originally set in the Rule Tile.
///
[MovedFrom(true, "UnityEngine")]
[Serializable]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.tilemap.extras@latest/index.html?subfolder=/manual/RuleOverrideTile.html")]
public class RuleOverrideTile : TileBase
{
///
/// A data structure storing the Sprite overriding the original RuleTile Sprite
///
[Serializable]
public class TileSpritePair
{
///
/// Original Sprite from the original RuleTile.
///
public Sprite m_OriginalSprite;
///
/// Overriding Sprite for the Original Sprite.
///
public Sprite m_OverrideSprite;
}
///
/// A data structure storing the GameObject overriding the original RuleTile GameObject
///
[Serializable]
public class TileGameObjectPair
{
///
/// Original GameObject from the original RuleTile.
///
public GameObject m_OriginalGameObject;
///
/// Overriding GameObject for the Original Sprite.
///
public GameObject m_OverrideGameObject;
}
///
/// Gets the overriding Sprite of a given Sprite.
///
/// The original Sprite that is overridden
public Sprite this[Sprite originalSprite]
{
get
{
foreach (TileSpritePair spritePair in m_Sprites)
{
if (spritePair.m_OriginalSprite == originalSprite)
{
return spritePair.m_OverrideSprite;
}
}
return null;
}
set
{
if (value == null)
{
m_Sprites = m_Sprites.Where(spritePair => spritePair.m_OriginalSprite != originalSprite).ToList();
}
else
{
foreach (TileSpritePair spritePair in m_Sprites)
{
if (spritePair.m_OriginalSprite == originalSprite)
{
spritePair.m_OverrideSprite = value;
return;
}
}
m_Sprites.Add(new TileSpritePair()
{
m_OriginalSprite = originalSprite,
m_OverrideSprite = value,
});
}
}
}
///
/// Gets the overriding GameObject of a given GameObject.
///
/// The original GameObject that is overridden
public GameObject this[GameObject originalGameObject]
{
get
{
foreach (TileGameObjectPair gameObjectPair in m_GameObjects)
{
if (gameObjectPair.m_OriginalGameObject == originalGameObject)
{
return gameObjectPair.m_OverrideGameObject;
}
}
return null;
}
set
{
if (value == null)
{
m_GameObjects = m_GameObjects.Where(gameObjectPair => gameObjectPair.m_OriginalGameObject != originalGameObject).ToList();
}
else
{
foreach (TileGameObjectPair gameObjectPair in m_GameObjects)
{
if (gameObjectPair.m_OriginalGameObject == originalGameObject)
{
gameObjectPair.m_OverrideGameObject = value;
return;
}
}
m_GameObjects.Add(new TileGameObjectPair()
{
m_OriginalGameObject = originalGameObject,
m_OverrideGameObject = value,
});
}
}
}
///
/// The RuleTile to override
///
public RuleTile m_Tile;
///
/// A list of Sprite Overrides
///
public List m_Sprites = new List();
///
/// A list of GameObject Overrides
///
public List m_GameObjects = new List();
///
/// Returns the Rule Tile for retrieving TileData
///
[HideInInspector] public RuleTile m_InstanceTile;
private void CreateInstanceTile()
{
var t = m_Tile.GetType();
RuleTile instanceTile = CreateInstance(t) as RuleTile;
instanceTile.hideFlags = HideFlags.NotEditable;
instanceTile.name = m_Tile.name + " (Override)";
m_InstanceTile = instanceTile;
#if UNITY_EDITOR
if(AssetDatabase.Contains(this))
AssetDatabase.AddObjectToAsset(instanceTile, this);
EditorUtility.SetDirty(this);
#endif
}
///
/// Applies overrides to this
///
/// A list of overrides to apply
/// The input overrides list is not valid
public void ApplyOverrides(IList> overrides)
{
if (overrides == null)
throw new ArgumentNullException("overrides");
for (int i = 0; i < overrides.Count; i++)
this[overrides[i].Key] = overrides[i].Value;
}
///
/// Applies overrides to this
///
/// A list of overrides to apply
/// The input overrides list is not valid
public void ApplyOverrides(IList> overrides)
{
if (overrides == null)
throw new ArgumentNullException("overrides");
for (int i = 0; i < overrides.Count; i++)
this[overrides[i].Key] = overrides[i].Value;
}
///
/// Gets overrides for this
///
/// A list of overrides to fill
/// Returns the number of valid overrides for Sprites
/// The input overrides list is not valid
public void GetOverrides(List> overrides, ref int validCount)
{
if (overrides == null)
throw new ArgumentNullException("overrides");
overrides.Clear();
List originalSprites = new List();
if (m_Tile)
{
if (m_Tile.m_DefaultSprite)
originalSprites.Add(m_Tile.m_DefaultSprite);
foreach (RuleTile.TilingRule rule in m_Tile.m_TilingRules)
foreach (Sprite sprite in rule.m_Sprites)
if (sprite && !originalSprites.Contains(sprite))
originalSprites.Add(sprite);
}
validCount = originalSprites.Count;
foreach (var pair in m_Sprites)
if (!originalSprites.Contains(pair.m_OriginalSprite))
originalSprites.Add(pair.m_OriginalSprite);
foreach (Sprite sprite in originalSprites)
overrides.Add(new KeyValuePair(sprite, this[sprite]));
}
///
/// Gets overrides for this
///
/// A list of overrides to fill
/// Returns the number of valid overrides for GameObjects
/// The input overrides list is not valid
public void GetOverrides(List> overrides, ref int validCount)
{
if (overrides == null)
throw new ArgumentNullException("overrides");
overrides.Clear();
List originalGameObjects = new List();
if (m_Tile)
{
if (m_Tile.m_DefaultGameObject)
originalGameObjects.Add(m_Tile.m_DefaultGameObject);
foreach (RuleTile.TilingRule rule in m_Tile.m_TilingRules)
if (rule.m_GameObject && !originalGameObjects.Contains(rule.m_GameObject))
originalGameObjects.Add(rule.m_GameObject);
}
validCount = originalGameObjects.Count;
foreach (var pair in m_GameObjects)
if (!originalGameObjects.Contains(pair.m_OriginalGameObject))
originalGameObjects.Add(pair.m_OriginalGameObject);
foreach (GameObject gameObject in originalGameObjects)
overrides.Add(new KeyValuePair(gameObject, this[gameObject]));
}
///
/// Updates the Rules with the Overrides set for this RuleOverrideTile
///
public virtual void Override()
{
if (!m_Tile)
return;
if (!m_InstanceTile)
CreateInstanceTile();
PrepareOverride();
var tile = m_InstanceTile;
tile.m_DefaultSprite = this[tile.m_DefaultSprite] ?? tile.m_DefaultSprite;
tile.m_DefaultGameObject = this[tile.m_DefaultGameObject] ?? tile.m_DefaultGameObject;
foreach (var rule in tile.m_TilingRules)
{
for (int i = 0; i < rule.m_Sprites.Length; i++)
{
Sprite sprite = rule.m_Sprites[i];
rule.m_Sprites[i] = this[sprite] ?? sprite;
}
rule.m_GameObject = this[rule.m_GameObject] ?? rule.m_GameObject;
}
}
///
/// Prepares the Overrides set for this RuleOverrideTile
///
public void PrepareOverride()
{
// Create clone of instanceTile to keep data from collections being overridden by JsonUtility
var tempTile = Instantiate(m_InstanceTile);
var customData = m_InstanceTile.GetCustomFields(true)
.ToDictionary(field => field, field => field.GetValue(tempTile));
JsonUtility.FromJsonOverwrite(JsonUtility.ToJson(m_Tile), m_InstanceTile);
foreach (var kvp in customData)
kvp.Key.SetValue(m_InstanceTile, kvp.Value);
}
///
/// Retrieves any tile animation data from the scripted tile.
///
/// Position of the Tile on the Tilemap.
/// The Tilemap the tile is present on.
/// Data to run an animation on the tile.
/// Whether the call was successful.
public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData)
{
if (!m_InstanceTile)
return false;
return m_InstanceTile.GetTileAnimationData(position, tilemap, ref tileAnimationData);
}
///
/// Retrieves any tile rendering data from the scripted tile.
///
/// Position of the Tile on the Tilemap.
/// The Tilemap the tile is present on.
/// Data to render the tile.
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
{
if (!m_InstanceTile)
return;
m_InstanceTile.GetTileData(position, tilemap, ref tileData);
}
///
/// This method is called when the tile is refreshed.
///
/// Position of the Tile on the Tilemap.
/// The Tilemap the tile is present on.
public override void RefreshTile(Vector3Int position, ITilemap tilemap)
{
if (!m_InstanceTile)
return;
m_InstanceTile.RefreshTile(position, tilemap);
}
///
/// StartUp is called on the first frame of the running Scene.
///
/// Position of the Tile on the Tilemap.
/// The Tilemap the tile is present on.
/// The GameObject instantiated for the Tile.
/// Whether StartUp was successful
public override bool StartUp(Vector3Int position, ITilemap tilemap, GameObject go)
{
if (!m_InstanceTile)
return true;
return m_InstanceTile.StartUp(position, tilemap, go);
}
///
/// Callback when the tile is enabled
///
public void OnEnable()
{
if (m_Tile == null)
return;
if (m_InstanceTile == null)
Override();
}
}
}