using System; using System.Collections.Generic; using System.Linq; namespace UnityEngine.Tilemaps { [Serializable] internal enum GridInformationType { Integer, String, Float, Double, UnityObject, Color } /// /// A simple MonoBehaviour that stores and provides information based on Grid positions and keywords. /// [Serializable] [HelpURL( "https://docs.unity3d.com/Packages/com.unity.2d.tilemap.extras@latest/index.html?subfolder=/manual/GridInformation.html")] [AddComponentMenu("Tilemap/Grid Information")] public class GridInformation : MonoBehaviour, ISerializationCallbackReceiver { [SerializeField] [HideInInspector] private List m_PositionIntKeys = new(); [SerializeField] [HideInInspector] private List m_PositionIntValues = new(); [SerializeField] [HideInInspector] private List m_PositionStringKeys = new(); [SerializeField] [HideInInspector] private List m_PositionStringValues = new(); [SerializeField] [HideInInspector] private List m_PositionFloatKeys = new(); [SerializeField] [HideInInspector] private List m_PositionFloatValues = new(); [SerializeField] [HideInInspector] private List m_PositionDoubleKeys = new(); [SerializeField] [HideInInspector] private List m_PositionDoubleValues = new(); [SerializeField] [HideInInspector] private List m_PositionObjectKeys = new(); [SerializeField] [HideInInspector] private List m_PositionObjectValues = new(); [SerializeField] [HideInInspector] private List m_PositionColorKeys = new(); [SerializeField] [HideInInspector] private List m_PositionColorValues = new(); internal Dictionary PositionProperties { get; } = new(); /// /// Clears all information stored /// public virtual void Reset() { PositionProperties.Clear(); } /// /// Callback before serializing this GridInformation /// void ISerializationCallbackReceiver.OnBeforeSerialize() { m_PositionIntKeys.Clear(); m_PositionIntValues.Clear(); m_PositionStringKeys.Clear(); m_PositionStringValues.Clear(); m_PositionFloatKeys.Clear(); m_PositionFloatValues.Clear(); m_PositionDoubleKeys.Clear(); m_PositionDoubleValues.Clear(); m_PositionObjectKeys.Clear(); m_PositionObjectValues.Clear(); m_PositionColorKeys.Clear(); m_PositionColorValues.Clear(); foreach (var kvp in PositionProperties) switch (kvp.Value.type) { case GridInformationType.Integer: m_PositionIntKeys.Add(kvp.Key); m_PositionIntValues.Add((int)kvp.Value.data); break; case GridInformationType.String: m_PositionStringKeys.Add(kvp.Key); m_PositionStringValues.Add(kvp.Value.data as string); break; case GridInformationType.Float: m_PositionFloatKeys.Add(kvp.Key); m_PositionFloatValues.Add((float)kvp.Value.data); break; case GridInformationType.Double: m_PositionDoubleKeys.Add(kvp.Key); m_PositionDoubleValues.Add((double)kvp.Value.data); break; case GridInformationType.Color: m_PositionColorKeys.Add(kvp.Key); m_PositionColorValues.Add((Color)kvp.Value.data); break; default: m_PositionObjectKeys.Add(kvp.Key); m_PositionObjectValues.Add(kvp.Value.data as Object); break; } } /// /// Callback after deserializing this GridInformation /// void ISerializationCallbackReceiver.OnAfterDeserialize() { PositionProperties.Clear(); for (var i = 0; i != Math.Min(m_PositionIntKeys.Count, m_PositionIntValues.Count); i++) { GridInformationValue positionValue; positionValue.type = GridInformationType.Integer; positionValue.data = m_PositionIntValues[i]; PositionProperties.Add(m_PositionIntKeys[i], positionValue); } for (var i = 0; i != Math.Min(m_PositionStringKeys.Count, m_PositionStringValues.Count); i++) { GridInformationValue positionValue; positionValue.type = GridInformationType.String; positionValue.data = m_PositionStringValues[i]; PositionProperties.Add(m_PositionStringKeys[i], positionValue); } for (var i = 0; i != Math.Min(m_PositionFloatKeys.Count, m_PositionFloatValues.Count); i++) { GridInformationValue positionValue; positionValue.type = GridInformationType.Float; positionValue.data = m_PositionFloatValues[i]; PositionProperties.Add(m_PositionFloatKeys[i], positionValue); } for (var i = 0; i != Math.Min(m_PositionDoubleKeys.Count, m_PositionDoubleValues.Count); i++) { GridInformationValue positionValue; positionValue.type = GridInformationType.Double; positionValue.data = m_PositionDoubleValues[i]; PositionProperties.Add(m_PositionDoubleKeys[i], positionValue); } for (var i = 0; i != Math.Min(m_PositionObjectKeys.Count, m_PositionObjectValues.Count); i++) { GridInformationValue positionValue; positionValue.type = GridInformationType.UnityObject; positionValue.data = m_PositionObjectValues[i]; PositionProperties.Add(m_PositionObjectKeys[i], positionValue); } for (var i = 0; i != Math.Min(m_PositionColorKeys.Count, m_PositionColorValues.Count); i++) { GridInformationValue positionValue; positionValue.type = GridInformationType.Color; positionValue.data = m_PositionColorValues[i]; PositionProperties.Add(m_PositionColorKeys[i], positionValue); } } /// /// This is not supported. /// /// Position to store information for /// Property name to store information for /// The information to be stored at the position /// Type of the information to set /// Whether the information was set /// This is not implemented as only concrete Types are supported public bool SetPositionProperty(Vector3Int position, string name, T positionProperty) { throw new NotImplementedException("Storing this type is not accepted in GridInformation"); } /// /// Stores int information at the given position with the given property name /// /// Position to store information for /// Property name to store information for /// The information to be stored at the position /// Whether the information was set public bool SetPositionProperty(Vector3Int position, string name, int positionProperty) { return SetPositionProperty(position, name, GridInformationType.Integer, positionProperty); } /// /// Stores string information at the given position with the given property name /// /// Position to store information for /// Property name to store information for /// The information to be stored at the position /// Whether the information was set public bool SetPositionProperty(Vector3Int position, string name, string positionProperty) { return SetPositionProperty(position, name, GridInformationType.String, positionProperty); } /// /// Stores float information at the given position with the given property name /// /// Position to store information for /// Property name to store information for /// The information to be stored at the position /// Whether the information was set public bool SetPositionProperty(Vector3Int position, string name, float positionProperty) { return SetPositionProperty(position, name, GridInformationType.Float, positionProperty); } /// /// Stores double information at the given position with the given property name /// /// Position to store information for /// Property name to store information for /// The information to be stored at the position /// Whether the information was set public bool SetPositionProperty(Vector3Int position, string name, double positionProperty) { return SetPositionProperty(position, name, GridInformationType.Double, positionProperty); } /// /// Stores UnityEngine.Object information at the given position with the given property name /// /// Position to store information for /// Property name to store information for /// The information to be stored at the position /// Whether the information was set public bool SetPositionProperty(Vector3Int position, string name, Object positionProperty) { return SetPositionProperty(position, name, GridInformationType.UnityObject, positionProperty); } /// /// Stores color information at the given position with the given property name /// /// Position to store information for /// Property name to store information for /// The information to be stored at the position /// Whether the information was set public bool SetPositionProperty(Vector3Int position, string name, Color positionProperty) { return SetPositionProperty(position, name, GridInformationType.Color, positionProperty); } private bool SetPositionProperty(Vector3Int position, string name, GridInformationType dataType, object positionProperty) { var grid = GetComponentInParent(); if (grid != null && positionProperty != null) { GridInformationKey positionKey; positionKey.position = position; positionKey.name = name; GridInformationValue positionValue; positionValue.type = dataType; positionValue.data = positionProperty; PositionProperties[positionKey] = positionValue; return true; } return false; } /// /// Retrieves information stored at the given position with the given property name as the given Type /// /// Position to retrieve information for /// Property name to retrieve information for /// Default value if property does not exist at the given position /// Type of the information to retrieve /// The information stored at the position /// Thrown when information to be retrieved is not the given Type public T GetPositionProperty(Vector3Int position, string name, T defaultValue) where T : Object { GridInformationKey positionKey; positionKey.position = position; positionKey.name = name; GridInformationValue positionValue; if (PositionProperties.TryGetValue(positionKey, out positionValue)) { if (positionValue.type != GridInformationType.UnityObject) throw new InvalidCastException("Value stored in GridInformation is not of the right type"); return positionValue.data as T; } return defaultValue; } /// /// Retrieves int information stored at the given position with the given property name /// /// Position to retrieve information for /// Property name to retrieve information for /// Default int if property does not exist at the given position /// The int stored at the position /// Thrown when information to be retrieved is not a int public int GetPositionProperty(Vector3Int position, string name, int defaultValue) { GridInformationKey positionKey; positionKey.position = position; positionKey.name = name; GridInformationValue positionValue; if (PositionProperties.TryGetValue(positionKey, out positionValue)) { if (positionValue.type != GridInformationType.Integer) throw new InvalidCastException("Value stored in GridInformation is not of the right type"); return (int)positionValue.data; } return defaultValue; } /// /// Retrieves string information stored at the given position with the given property name /// /// Position to retrieve information for /// Property name to retrieve information for /// Default string if property does not exist at the given position /// The string stored at the position /// Thrown when information to be retrieved is not a string public string GetPositionProperty(Vector3Int position, string name, string defaultValue) { GridInformationKey positionKey; positionKey.position = position; positionKey.name = name; GridInformationValue positionValue; if (PositionProperties.TryGetValue(positionKey, out positionValue)) { if (positionValue.type != GridInformationType.String) throw new InvalidCastException("Value stored in GridInformation is not of the right type"); return (string)positionValue.data; } return defaultValue; } /// /// Retrieves float information stored at the given position with the given property name /// /// Position to retrieve information for /// Property name to retrieve information for /// Default float if property does not exist at the given position /// The float stored at the position /// Thrown when information to be retrieved is not a float public float GetPositionProperty(Vector3Int position, string name, float defaultValue) { GridInformationKey positionKey; positionKey.position = position; positionKey.name = name; GridInformationValue positionValue; if (PositionProperties.TryGetValue(positionKey, out positionValue)) { if (positionValue.type != GridInformationType.Float) throw new InvalidCastException("Value stored in GridInformation is not of the right type"); return (float)positionValue.data; } return defaultValue; } /// /// Retrieves double information stored at the given position with the given property name /// /// Position to retrieve information for /// Property name to retrieve information for /// Default double if property does not exist at the given position /// The double stored at the position /// Thrown when information to be retrieved is not a double public double GetPositionProperty(Vector3Int position, string name, double defaultValue) { GridInformationKey positionKey; positionKey.position = position; positionKey.name = name; GridInformationValue positionValue; if (PositionProperties.TryGetValue(positionKey, out positionValue)) { if (positionValue.type != GridInformationType.Double) throw new InvalidCastException("Value stored in GridInformation is not of the right type"); return (double)positionValue.data; } return defaultValue; } /// /// Retrieves Color information stored at the given position with the given property name /// /// Position to retrieve information for /// Property name to retrieve information for /// Default color if property does not exist at the given position /// The color stored at the position /// Thrown when information to be retrieved is not a Color public Color GetPositionProperty(Vector3Int position, string name, Color defaultValue) { GridInformationKey positionKey; positionKey.position = position; positionKey.name = name; GridInformationValue positionValue; if (PositionProperties.TryGetValue(positionKey, out positionValue)) { if (positionValue.type != GridInformationType.Color) throw new InvalidCastException("Value stored in GridInformation is not of the right type"); return (Color)positionValue.data; } return defaultValue; } /// /// Erases information stored at the given position with the given property name /// /// Position to erase /// Property name to erase /// Whether the information was erased public bool ErasePositionProperty(Vector3Int position, string name) { GridInformationKey positionKey; positionKey.position = position; positionKey.name = name; return PositionProperties.Remove(positionKey); } /// /// Gets all positions with information with the given property name /// /// Property name to search for /// An array of all positions with the property name public Vector3Int[] GetAllPositions(string propertyName) { return PositionProperties.Keys.ToList().FindAll(x => x.name == propertyName).Select(x => x.position) .ToArray(); } [Serializable] internal struct GridInformationValue { public GridInformationType type; public object data; } [Serializable] internal struct GridInformationKey : IEquatable { public Vector3Int position; public string name; public bool Equals(GridInformationKey key) { return position == key.position && name == key.name; } public override int GetHashCode() { return HashCode.Combine(position.GetHashCode(), name.GetHashCode()); } } } }