using System; using System.Collections.Generic; #if UNITY_EDITOR using System.Linq; #endif using Rive.Utils; using UnityEngine; namespace Rive { [Serializable] internal class FileMetadata { #if UNITY_EDITOR private const int CURRENT_VERSION = 1; // Increment this whenever the structure changes [SerializeField] private int m_Version = 1; //And also update this so we can check for changes in the future [Serializable] public class InputMetadata { public string Name; public string Type; } [Serializable] public class StateMachineMetadata { public string Name; public List Inputs = new List(); } [Serializable] public class ViewModelPropertyMetadata { public string Name; public ViewModelDataType Type; /// /// The name of the nested view model if the property is a view model. /// public string NestedViewModelName; /// /// The name of the enum type if the property is an enum. /// public string EnumTypeName; public static ViewModelPropertyMetadata FromPropertyData(ViewModelPropertyData propertyData, ViewModel viewModel) { if (propertyData.Type == ViewModelDataType.ViewModel) { // Get the view model name by loading a view model instance and getting the name of the view model var instance = viewModel.CreateInstance(); ViewModelInstance nestedInstance = instance.GetProperty(propertyData.Name); if (nestedInstance == null) { DebugLogger.Instance.LogWarning("Could not find nested view model instance for property " + propertyData.Name); return new ViewModelPropertyMetadata { Name = propertyData.Name, Type = propertyData.Type }; } string nestedViewModelName = nestedInstance.ViewModelName; nestedInstance.Dispose(); // We don't need the instance anymore return new ViewModelPropertyMetadata { Name = propertyData.Name, Type = propertyData.Type, NestedViewModelName = nestedViewModelName }; } else if (propertyData.Type == ViewModelDataType.Enum) { // Get the enum name by loading a view model instance and getting the associated enum type. // Unfortunately, we need to do it this way because the native API doesn't expose the enum type name directly from the property data. var instance = viewModel.CreateInstance(); var enumType = ViewModelInstancePropertyHandlersFactory.GetEnumForPropertyAtPath(instance, propertyData.Name); instance.Dispose(); // We don't need the instance anymore return new ViewModelPropertyMetadata { Name = propertyData.Name, Type = propertyData.Type, EnumTypeName = enumType?.Name }; } return new ViewModelPropertyMetadata { Name = propertyData.Name, Type = propertyData.Type }; } } [Serializable] public class ArtboardMetadata { [SerializeField] private string m_Name; [SerializeField] private float m_Width; [SerializeField] private float m_Height; [SerializeField] private List m_StateMachines; [SerializeField] private ViewModelMetadata m_DefaultViewModel; public string Name { get { return m_Name; } } public float Width { get { return m_Width; } } public float Height { get { return m_Height; } } public List StateMachines { get { return m_StateMachines; } } public ViewModelMetadata DefaultViewModel { get { return m_DefaultViewModel; } } public ArtboardMetadata(string name, float width, float height, List stateMachines, ViewModelMetadata defaultViewModel) { m_Name = name; m_Width = width; m_Height = height; m_StateMachines = stateMachines == null ? new List() : stateMachines; m_DefaultViewModel = defaultViewModel; } } [Serializable] public class ViewModelMetadata { /// /// The name of the view model. /// public string Name; /// /// The properties of the view model. /// public List Properties = new List(); /// /// The names of the instances of this view model within the Rive file. /// public List InstanceNames = new List(); public static ViewModelMetadata FromViewModel(ViewModel viewModel) { var viewModelMeta = new ViewModelMetadata { Name = viewModel.Name }; IReadOnlyList properties = viewModel.Properties; foreach (var property in properties) { viewModelMeta.Properties.Add(ViewModelPropertyMetadata.FromPropertyData(property, viewModel)); } viewModelMeta.InstanceNames.AddRange(viewModel.InstanceNames); return viewModelMeta; } } [Serializable] public class ViewModelEnumMetadata { [SerializeField] private string m_Name; [SerializeField] private string[] m_Values; public string Name { get { return m_Name; } } public IReadOnlyList Values { get { return m_Values; } } public ViewModelEnumMetadata(string name, IReadOnlyList values) { m_Name = name; m_Values = values.ToArray(); } } public List Artboards = new List(); public List ViewModels = new List(); public List Enums = new List(); public string[] GetArtboardNames() { return Artboards.Select(a => a.Name).ToArray(); } public string[] GetStateMachineNames(string artboardName) { var artboard = Artboards.FirstOrDefault(a => a.Name == artboardName); return artboard?.StateMachines.Select(sm => sm.Name).ToArray() ?? new string[0]; } public ArtboardMetadata GetArtboard(string name) { return Artboards.FirstOrDefault(a => a.Name == name); } public bool NeedsReload() { // Force reload for unversioned (0) or outdated data return m_Version != CURRENT_VERSION; } #endif } /// /// Represents a Rive asset (.riv) /// public class Asset : ScriptableObject { [HideInInspector] [SerializeField] private byte[] m_Bytes; /// /// The raw bytes of the Rive asset /// public byte[] Bytes { get { return m_Bytes; } } [HideInInspector] [SerializeField] private EmbeddedAssetData[] m_EmbeddedAssets; /// /// An array of all the embedded asset data in this Rive asset /// public IReadOnlyList EmbeddedAssets { get { return m_EmbeddedAssets; } } /// /// The number of embedded asset data in this Rive asset /// public int EmbeddedAssetCount { get { return m_EmbeddedAssets == null ? 0 : m_EmbeddedAssets.Length; } } #if UNITY_EDITOR [SerializeField] private FileMetadata m_FileMetadata; /// /// Metadata about the contents of the Rive file. Available only in the Unity editor. /// internal FileMetadata EditorOnlyMetadata { get { if (m_FileMetadata == null || m_FileMetadata.NeedsReload()) { GenerateFileMetadata(); } return m_FileMetadata; } } private void GenerateFileMetadata() { m_FileMetadata = new FileMetadata(); using (var file = File.Load(this)) { if (file == null) return; // View models IReadOnlyList viewModels = file.ViewModels; foreach (var viewModel in viewModels) { var viewModelMeta = FileMetadata.ViewModelMetadata.FromViewModel(viewModel); m_FileMetadata.ViewModels.Add(viewModelMeta); } // Enums foreach (var enumData in file.ViewModelEnums) { var enumMeta = new FileMetadata.ViewModelEnumMetadata(enumData.Name, enumData.Values); m_FileMetadata.Enums.Add(enumMeta); } for (uint i = 0; i < file.ArtboardCount; i++) { var artboard = file.Artboard(i); if (artboard == null) continue; FileMetadata.ViewModelMetadata defaultViewModel = null; if (artboard.DefaultViewModel != null) { defaultViewModel = FileMetadata.ViewModelMetadata.FromViewModel(artboard.DefaultViewModel); } var artboardMeta = new FileMetadata.ArtboardMetadata(name: file.ArtboardName(i), width: artboard.Width, height: artboard.Height, stateMachines: new List(), defaultViewModel: defaultViewModel); for (uint j = 0; j < artboard.StateMachineCount; j++) { var stateMachine = artboard.StateMachine(j); if (stateMachine == null) continue; var smMeta = new FileMetadata.StateMachineMetadata { Name = artboard.StateMachineName(j) }; foreach (var input in stateMachine.Inputs()) { var inputMeta = new FileMetadata.InputMetadata { Name = input.Name, Type = input.IsBoolean ? "Boolean" : input.IsNumber ? "Number" : input.IsTrigger ? "Trigger" : "Unknown" }; smMeta.Inputs.Add(inputMeta); } artboardMeta.StateMachines.Add(smMeta); } m_FileMetadata.Artboards.Add(artboardMeta); } } } #endif /// /// Initializes the asset with the given bytes and embedded asset information. /// /// The raw bytes of the Rive asset. /// The embedded asset data in the Rive asset. internal void SetData(byte[] bytes, EmbeddedAssetData[] embeddedAssetsData) { m_Bytes = bytes; m_EmbeddedAssets = embeddedAssetsData; #if UNITY_EDITOR GenerateFileMetadata(); #endif } /// /// Create a new Rive asset instance from the given bytes and embedded asset data. /// /// The raw bytes of the Rive asset. /// The embedded asset data in the Rive asset. /// The created Rive asset instance. public static Asset Create(byte[] bytes, EmbeddedAssetData[] embeddedAssetsData) { var asset = ScriptableObject.CreateInstance(); asset.SetData(bytes, embeddedAssetsData); return asset; } } }