using System; using System.Linq; using System.Collections.Generic; using UnityEngine; using UnityEditor.VFX; using UnityEngine.UIElements; using System.Reflection; using UnityObject = UnityEngine.Object; using NodeID = System.UInt32; namespace UnityEditor.VFX.UI { class VFXCopyPasteCommon { protected const NodeID TypeMask = 3u << 30; protected const NodeID ParameterFlag = 1u << 30; protected const NodeID ContextFlag = 2u << 30; protected const NodeID OperatorFlag = 3u << 30; protected const NodeID BlockFlag = 0u << 30; protected const NodeID InvalidID = 0xFFFFFFFF; //NodeID are 32 identifiers to any node that can be in a groupNode or have links //The two high bits are use with the above flags to give the type. // For operators and context all the 30 remaining bit are used as an index // For blocks the high bits 2 to 13 are a block index in the context the 18 remaining bits are an index in the contexts // For parameters the high bits 2 to 13 are a parameter node index the 18 remaining are an index in the parameters // Therefore you can copy : // Up to 2^30 operators // Up to 2^30 contexts, but only the first 2^18 can have blocks with links // Up to 2^30 parameters, but only the first 2^18 can have nodes with links // Up to 2^11 block per context can have links // Up to 2^11 parameter nodes per parameter can have links // Note : 2^30 > 1 billion, 2^18 = 262144, 2^11 = 2048 [Serializable] protected struct DataAnchor { public NodeID targetIndex; public int[] slotPath; } [Serializable] protected struct DataEdge { public DataAnchor input; public DataAnchor output; } [Serializable] protected struct FlowAnchor { public NodeID contextIndex; public int flowIndex; } [Serializable] protected struct FlowEdge { public FlowAnchor input; public FlowAnchor output; } [Serializable] protected struct Property { public string name; public VFXCoordinateSpace space; public VFXSerializableObject value; } [Serializable] protected struct Node { public Vector2 position; [Flags] public enum Flags { Collapsed = 1 << 0, SuperCollapsed = 1 << 1, Enabled = 1 << 2 } public Flags flags; public SerializableType type; public Property[] settings; public Property[] inputSlots; public string[] expandedInputs; public string[] expandedOutputs; public int indexInClipboard; } [Serializable] protected struct Context { public Node node; public int dataIndex; public string label; public Node[] blocks; public SubOutput[] subOutputs; public string systemName; } [Serializable] protected struct SubOutput { public SerializableType type; public Property[] settings; } [Serializable] protected struct Data { public Property[] settings; } [Serializable] protected struct ParameterNode { public Vector2 position; public bool collapsed; public string[] expandedOutput; public int indexInClipboard; } [Serializable] protected struct Parameter { public int originalInstanceID; public string name; public VFXSerializableObject value; public bool exposed; public VFXValueFilter valueFilter; public VFXSerializableObject min; public VFXSerializableObject max; public string[] enumValue; public string tooltip; public bool isOutput; public ParameterNode[] nodes; } [Serializable] protected struct GroupNode { public VFXUI.UIInfo infos; public NodeID[] contents; public int stickNodeCount; } [Serializable] protected class SerializableGraph { public Rect bounds; public bool blocksOnly; public Context[] contexts; public Node[] operators; // this contains blocks if blocksOnly else it contains operators and blocks are included in their respective contexts public Data[] datas; public Parameter[] parameters; public DataEdge[] dataEdges; public FlowEdge[] flowEdges; public VFXUI.StickyNoteInfo[] stickyNotes; public GroupNode[] groupNodes; public int controllerCount; } static Dictionary> s_SerializableFieldByType = new Dictionary>(); protected static List GetFields(Type type) { List fields = null; if (!s_SerializableFieldByType.TryGetValue(type, out fields)) { fields = new List(); while (type != typeof(VFXContext) && type != typeof(VFXOperator) && type != typeof(VFXBlock) && type != typeof(VFXData) && type != typeof(VFXSRPSubOutput)) { var typeFields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); foreach (var field in typeFields) { if (!field.IsPublic) { object[] attributes = field.GetCustomAttributes(true); if (!attributes.Any(t => t is VFXSettingAttribute || t is SerializeField)) continue; } if (field.IsNotSerialized) continue; if (!field.FieldType.IsSerializable && !typeof(UnityObject).IsAssignableFrom(field.FieldType)) // Skip field that are not serializable except for UnityObject that are anyway continue; if (typeof(VFXModel).IsAssignableFrom(field.FieldType) || field.FieldType.IsGenericType && typeof(VFXModel).IsAssignableFrom(field.FieldType.GetGenericArguments()[0])) continue; fields.Add(field); } type = type.BaseType; } s_SerializableFieldByType[type] = fields; } return fields; } protected static IEnumerable AllSlots(IEnumerable slots) { foreach (var slot in slots) { yield return slot; foreach (var child in AllSlots(slot.children)) { yield return child; } } } protected static NodeID GetBlockID(uint contextIndex, uint blockIndex) { if (contextIndex < (1 << 18) && blockIndex < (1 << 11)) { return BlockFlag | (blockIndex << 18) | contextIndex; } return InvalidID; } protected static NodeID GetParameterNodeID(uint parameterIndex, uint nodeIndex) { if (parameterIndex < (1 << 18) && nodeIndex < (1 << 11)) { return ParameterFlag | (nodeIndex << 18) | parameterIndex; } return InvalidID; } } }