Пример #1
0
        /// <summary>
        /// Saves the surface to bytes. Performs also modified child surfaces saving before.
        /// </summary>
        /// <remarks>
        /// Assume this method does not throw exceptions but uses return value as a error code.
        /// </remarks>
        /// <returns>True if failed, otherwise false.</returns>
        public bool Save()
        {
            // Save all children modified before saving the current surface
            for (int i = 0; i < Children.Count; i++)
            {
                if (Children[i].IsModified && Children[i].Save())
                {
                    return(true);
                }
            }

            _meta.Release();

            Saving?.Invoke(this);

            // Save surface meta
            _meta.AddEntry(10, Utils.StructureToByteArray(ref CachedSurfaceMeta));

            // Save all nodes meta
            VisjectSurface.Meta11 meta11;
            for (int i = 0; i < Nodes.Count; i++)
            {
                var node = Nodes[i];
                meta11.Position = node.Location;
                meta11.Selected = false; // don't save selection to prevent stupid binary diffs on asset
                node.Meta.Release();
                // TODO: reuse byte[] array for all nodes to reduce dynamic memory allocations
                node.Meta.AddEntry(11, Utils.StructureToByteArray(ref meta11));
            }

            // Save graph
            try
            {
                // Save graph
                using (var stream = new MemoryStream())
                    using (var writer = new BinaryWriter(stream))
                    {
                        // Save graph to bytes
                        SaveGraph(writer);
                        var bytes = stream.ToArray();

                        // Send data to the container
                        Context.SurfaceData = bytes;

                        Saved?.Invoke(this);

                        // Clear modification flag
                        _isModified = false;
                    }
            }
            catch (Exception ex)
            {
                // Error
                Editor.LogWarning("Saving Visject Surface data failed.");
                Editor.LogWarning(ex);
                return(true);
            }

            return(false);
        }
 /// <summary>
 /// Searches for the types and fills with data.
 /// </summary>
 protected virtual void Search()
 {
     // Special case for attributes
     if (_type.BaseType == typeof(Attribute))
     {
         Utils.GetTypesWithAttributeDefined(_type, _list, _checkFunc, _checkAssembly);
     }
     else
     {
         Utils.GetDerivedTypes(_type, _list, _checkFunc, _checkAssembly);
     }
 }
Пример #3
0
        /// <summary>
        /// Gets the collection of the Control types that can be spawned in the game (valid ones).
        /// </summary>
        /// <returns>The Control types collection (readonly).</returns>
        public List <Type> GetControlTypes()
        {
            if (!_hasValidControlTypes)
            {
                _controlTypes.Clear();
                _hasValidControlTypes = true;

                Utils.GetDerivedTypes(typeof(Control), _controlTypes, IsTypeValidControlType, HasAssemblyValidControlTypes);
            }

            return(_controlTypes);
        }
        private NodeArchetype GetArchetype(MethodBase method)
        {
            // Validate method signature
            if (!method.IsStatic ||
                !method.IsPublic ||
                method as MethodInfo == null ||
                ((MethodInfo)method).ReturnType != typeof(NodeArchetype) ||
                method.GetParameters().Length != 0 ||
                method.IsGenericMethod)
            {
                return(null);
            }

            // Invoke method
            try
            {
                var arch = (NodeArchetype)method.Invoke(null, null);

                // Validate archetype
                if (arch.Tag != null || string.IsNullOrEmpty(arch.Title))
                {
                    Debug.LogWarning(string.Format("Method {0} from {1} returned invalid node archetype. Tag must be null and title must be specified.", method, method.DeclaringType));
                    return(null);
                }
                if (arch.DefaultValues == null || arch.DefaultValues.Length < 2 || string.IsNullOrEmpty(arch.DefaultValues[0] as string) || string.IsNullOrEmpty(arch.DefaultValues[1] as string))
                {
                    Debug.LogWarning(string.Format("Method {0} from {1} returned invalid node archetype. Default values are invalid. DefaultValues[0] must specify the C# runtime controller typename. DefaultValues[1] must specify the node group name.", method, method.DeclaringType));
                    return(null);
                }

                // Validate node type
                var typeName = Surface.Archetypes.Custom.GetNodeTypeName(arch);
                var type     = Utils.GetType(typeName);
                if (type == null)
                {
                    Debug.LogWarning(string.Format("Method {0} from {1} returned invalid node archetype. Failed to find node logic defined in type {2}.", method, method.DeclaringType, typeName));
                    return(null);
                }

                // Check if type comes from scripts that can be reloaded at runtime
                HasTypeFromGameScripts |= Utils.IsTypeFromGameScripts(method.DeclaringType) || Utils.IsTypeFromGameScripts(type);

                return(arch);
            }
            catch (Exception ex)
            {
                Debug.LogWarning("Failed to get the custom node archetype.");
                Debug.LogWarning(ex);
            }

            return(null);
        }
Пример #5
0
        /// <summary>
        /// Gets all the script types from the all loaded assemblies (including project scripts and scripts from the plugins).
        /// </summary>
        /// <returns>The script types collection (readonly).</returns>
        public List <Type> GetScripts()
        {
            if (!_hasValidScripts)
            {
                _scripts.Clear();
                _hasValidScripts = true;

                Editor.Log("Searching valid script types");
                var start = DateTime.Now;
                Utils.GetDerivedTypes(typeof(Script), _scripts, IsTypeValidScriptType, HasAssemblyValidScriptTypes);
                var end = DateTime.Now;
                Editor.Log(string.Format("Found {0} script types (in {1} ms)", _scripts.Count, (int)(end - start).TotalMilliseconds));
            }

            return(_scripts);
        }
Пример #6
0
        /// <summary>
        /// Gets the collection of the Control types that can be spawned in the game (valid ones).
        /// </summary>
        /// <returns>The Control types collection (readonly).</returns>
        public List <Type> GetControlTypes()
        {
            if (!_hasValidControlTypes)
            {
                _controlTypes.Clear();
                _hasValidControlTypes = true;

                Editor.Log("Searching valid control types");
                var start = DateTime.Now;
                Utils.GetDerivedTypes(typeof(Control), _controlTypes, IsTypeValidControlType, HasAssemblyValidControlTypes);
                var end = DateTime.Now;
                Editor.Log(string.Format("Found {0} control types (in {1} ms)", _controlTypes.Count, (int)(end - start).TotalMilliseconds));
            }

            return(_controlTypes);
        }
Пример #7
0
        /// <summary>
        /// Called when node gets loaded and should be added to the surface. Creates node elements from the archetype.
        /// </summary>
        /// <param name="node">The node.</param>
        public virtual void OnNodeLoaded(SurfaceNode node)
        {
            // Create child elements of the node based on it's archetype
            int elementsCount = node.Archetype.Elements?.Length ?? 0;

            for (int i = 0; i < elementsCount; i++)
            {
                // ReSharper disable once PossibleNullReferenceException
                node.AddElement(node.Archetype.Elements[i]);
            }

            // Load metadata
            var meta = node.Meta.GetEntry(11);

            if (meta.Data != null)
            {
                var meta11 = Utils.ByteArrayToStructure <VisjectSurface.Meta11>(meta.Data);
                node.Location = meta11.Position;
                //node.IsSelected = meta11.Selected;
            }
        }
        /// <summary>
        /// Called when node gets loaded and should be added to the surface. Creates node elements from the archetype.
        /// </summary>
        /// <param name="node">The node.</param>
        public virtual void OnNodeLoaded(SurfaceNode node)
        {
            // Create child elements of the node based on it's archetype
            int elementsCount = node.Archetype.Elements?.Length ?? 0;

            for (int i = 0; i < elementsCount; i++)
            {
                // ReSharper disable once PossibleNullReferenceException
                var arch = node.Archetype.Elements[i];
                ISurfaceNodeElement element = null;
                switch (arch.Type)
                {
                case NodeElementType.Input:
                    element = new InputBox(node, arch);
                    break;

                case NodeElementType.Output:
                    element = new OutputBox(node, arch);
                    break;

                case NodeElementType.BoolValue:
                    element = new BoolValue(node, arch);
                    break;

                case NodeElementType.FloatValue:
                    element = new FloatValue(node, arch);
                    break;

                case NodeElementType.IntegerValue:
                    element = new IntegerValue(node, arch);
                    break;

                case NodeElementType.ColorValue:
                    element = new ColorValue(node, arch);
                    break;

                case NodeElementType.ComboBox:
                    element = new ComboBoxElement(node, arch);
                    break;

                case NodeElementType.Asset:
                    element = new AssetSelect(node, arch);
                    break;

                case NodeElementType.Text:
                    element = new TextView(node, arch);
                    break;

                case NodeElementType.TextBox:
                    element = new TextBoxView(node, arch);
                    break;

                case NodeElementType.SkeletonNodeSelect:
                    element = new SkeletonNodeSelectElement(node, arch);
                    break;
                }
                if (element != null)
                {
                    // Link element
                    node.AddElement(element);
                }
            }

            // Load metadata
            var meta = node.Meta.GetEntry(11);

            if (meta.Data != null)
            {
                var meta11 = Utils.ByteArrayToStructure <VisjectSurface.Meta11>(meta.Data);
                node.Location = meta11.Position;
                //node.IsSelected = meta11.Selected;
            }
        }
        private void LoadGraph(BinaryReader stream)
        {
            // IMPORTANT! This must match C++ Graph format

            // Magic Code
            int tmp = stream.ReadInt32();

            if (tmp != 1963542358)
            {
                // Error
                throw new Exception("Invalid Graph format version");
            }

            // Engine Build
            uint engineBuild = stream.ReadUInt32();

            // Load1
            {
                // Time saved (not used anymore to prevent binary diffs after saving unmodified surface)
                stream.ReadInt64();
                byte[] guidBytes = new byte[16];

                // Nodes count
                int nodesCount = stream.ReadInt32();
                if (Nodes.Capacity < nodesCount)
                {
                    Nodes.Capacity = nodesCount;
                }
                List <ConnectionHint> tmpHints = _cachedConnections.Value;
                tmpHints.Clear();
                tmpHints.Capacity = Mathf.Max(tmpHints.Capacity, nodesCount * 4);

                // Parameters count
                int parametersCount = stream.ReadInt32();
                if (Parameters.Capacity < parametersCount)
                {
                    Parameters.Capacity = parametersCount;
                }

                // For each node
                for (int i = 0; i < nodesCount; i++)
                {
                    // ID
                    uint id = stream.ReadUInt32();

                    // Type
                    ushort typeId  = stream.ReadUInt16();
                    ushort groupId = stream.ReadUInt16();

                    // Create node
                    SurfaceNode node;
                    if (groupId == Archetypes.Custom.GroupID)
                    {
                        node = new Archetypes.Custom.DummyCustomNode(id, this);
                    }
                    else
                    {
                        node = NodeFactory.CreateNode(_surface.NodeArchetypes, id, this, groupId, typeId);
                    }
                    if (node == null)
                    {
                        // Error
                        throw new Exception("Cannot create graph node.");
                    }
                    Nodes.Add(node);
                }

                // For each param
                for (int i = 0; i < parametersCount; i++)
                {
                    // Create param
                    var param = new SurfaceParameter();
                    Parameters.Add(param);

                    // Properties
                    param.Type = (ParameterType)stream.ReadByte();
                    stream.Read(guidBytes, 0, 16);
                    param.ID           = new Guid(guidBytes);
                    param.Name         = Utils.ReadStr(stream, 97);
                    param.IsPublic     = stream.ReadByte() != 0;
                    param.IsStatic     = stream.ReadByte() != 0;
                    param.IsUIVisible  = stream.ReadByte() != 0;
                    param.IsUIEditable = stream.ReadByte() != 0;

                    // References
                    int refsCount = stream.ReadInt32();
                    param.ReferencedBy.Capacity = refsCount;
                    for (int j = 0; j < refsCount; j++)
                    {
                        uint refID = stream.ReadUInt32();
                        var  node  = FindNode(refID);
                        if (node == null)
                        {
                            // Error
                            Editor.LogWarning($"Invalid node reference id (param: {param.Name}, node ref: {refID})");
                        }
                        else
                        {
                            param.ReferencedBy.Add(node);
                        }
                    }

                    // Value
                    Utils.ReadCommonValue(stream, ref param.Value);

                    // Meta
                    param.Meta.Load(engineBuild, stream);
                }

                // For each node
                for (int i = 0; i < nodesCount; i++)
                {
                    var node = Nodes[i];

                    int valuesCnt         = stream.ReadInt32();
                    int firstValueReadIdx = 0;

                    // Special case for custom nodes
                    if (node is Archetypes.Custom.DummyCustomNode dummyCustom)
                    {
                        // TODO: maybe reuse the same dummy node (static) because is only a placeholder

                        // Values check
                        if (valuesCnt < 2)
                        {
                            throw new Exception("Missing custom nodes data.");
                        }

                        // Node typename check
                        object typeName = null;
                        Utils.ReadCommonValue(stream, ref typeName);
                        firstValueReadIdx = 1;
                        if (string.IsNullOrEmpty(typeName as string))
                        {
                            throw new Exception("Missing custom node typename.");
                        }

                        // Find custom node archetype that matches this node type (it must be unique)
                        var customNodes = _surface.GetCustomNodes();
                        if (customNodes?.Archetypes == null)
                        {
                            throw new Exception("Cannot find any custom nodes archetype.");
                        }
                        NodeArchetype arch = null;
                        for (int j = 0; j < customNodes.Archetypes.Length; j++)
                        {
                            if (string.Equals(Archetypes.Custom.GetNodeTypeName(customNodes.Archetypes[j]), (string)typeName, StringComparison.OrdinalIgnoreCase))
                            {
                                arch = customNodes.Archetypes[j];
                                break;
                            }
                        }
                        if (arch == null)
                        {
                            throw new Exception("Missing custom node " + typeName);
                        }

                        // Create custom node and replace dummy placeholder
                        node = NodeFactory.CreateNode(dummyCustom.ID, this, customNodes, arch);
                        if (node == null)
                        {
                            throw new Exception("Failed to create custom node " + typeName);
                        }
                        Nodes[i] = node;

                        // Store node typename in values container
                        node.Values[0] = typeName;
                    }

                    // Values
                    int nodeValuesCnt = node.Values?.Length ?? 0;
                    if (valuesCnt == nodeValuesCnt)
                    {
                        for (int j = firstValueReadIdx; j < valuesCnt; j++)
                        {
                            // ReSharper disable once PossibleNullReferenceException
                            Utils.ReadCommonValue(stream, ref node.Values[j]);
                        }
                    }
                    else
                    {
                        Editor.LogWarning(String.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID));

                        object dummy = null;
                        for (int j = firstValueReadIdx; j < valuesCnt; j++)
                        {
                            Utils.ReadCommonValue(stream, ref dummy);
                        }
                    }

                    // Boxes
                    ushort boxesCount = stream.ReadUInt16();
                    for (int j = 0; j < boxesCount; j++)
                    {
                        var    id             = stream.ReadByte();
                        uint   type           = stream.ReadUInt32();
                        ushort connectionsCnt = stream.ReadUInt16();

                        ConnectionHint hint;
                        hint.NodeB = node.ID;
                        hint.BoxB  = id;

                        for (int k = 0; k < connectionsCnt; k++)
                        {
                            uint targetNodeID = stream.ReadUInt32();
                            byte targetBoxID  = stream.ReadByte();

                            hint.NodeA = targetNodeID;
                            hint.BoxA  = targetBoxID;

                            tmpHints.Add(hint);
                        }
                    }

                    // Meta
                    node.Meta.Load(engineBuild, stream);

                    OnControlLoaded(node);
                }

                // Visject Meta
                _meta.Load(engineBuild, stream);

                // Setup connections
                for (int i = 0; i < tmpHints.Count; i++)
                {
                    var c = tmpHints[i];

                    var nodeA = FindNode(c.NodeA);
                    var nodeB = FindNode(c.NodeB);
                    if (nodeA == null || nodeB == null)
                    {
                        // Error
                        Editor.LogWarning("Invalid connected node id.");
                        continue;
                    }

                    var boxA = nodeA.GetBox(c.BoxA);
                    var boxB = nodeB.GetBox(c.BoxB);
                    if (boxA != null && boxB != null)
                    {
                        boxA.Connections.Add(boxB);
                    }
                }

                // Ending char
                byte end = stream.ReadByte();
                if (end != '\t')
                {
                    // Error
                    throw new Exception("Invalid data.");
                }
            }
        }
        /// <summary>
        /// Loads the surface from bytes. Clears the surface before and uses context source data as a surface bytes source.
        /// </summary>
        /// <remarks>
        /// Assume this method does not throw exceptions but uses return value as a error code.
        /// </remarks>
        /// <returns>True if failed, otherwise false.</returns>
        public bool Load()
        {
            try
            {
                // Prepare
                Clear();

                Loading?.Invoke(this);

                // Load bytes
                var bytes = Context.SurfaceData;
                if (bytes == null)
                {
                    throw new Exception("Failed to load surface data.");
                }

                // Load graph (empty bytes data means empty graph for simplicity when using subgraphs)
                if (bytes.Length > 0)
                {
                    using (var stream = new MemoryStream(bytes))
                        using (var reader = new BinaryReader(stream))
                        {
                            LoadGraph(reader);
                        }
                }

                // Load surface meta
                var meta = _meta.GetEntry(10);
                if (meta.Data != null)
                {
                    Utils.ByteArrayToStructure(meta.Data, out CachedSurfaceMeta);
                }
                else
                {
                    // Reset view
                    CachedSurfaceMeta.ViewCenterPosition = Vector2.Zero;
                    CachedSurfaceMeta.Scale = 1.0f;
                }

                // Load surface comments
                var commentsData = _meta.GetEntry(666);
                if (commentsData.Data != null)
                {
                    using (var stream = new MemoryStream(commentsData.Data))
                        using (var reader = new BinaryReader(stream))
                        {
                            var commentsCount = reader.ReadInt32();

                            for (int i = 0; i < commentsCount; i++)
                            {
                                var title  = Utils.ReadStr(reader, 71);
                                var color  = new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                                var bounds = new Rectangle(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());

                                var comment = SpawnComment(ref bounds);
                                if (comment == null)
                                {
                                    throw new InvalidOperationException("Failed to create comment.");
                                }

                                comment.Title = title;
                                comment.Color = color;

                                OnControlLoaded(comment);
                            }
                        }
                }

                // Post load
                for (int i = 0; i < RootControl.Children.Count; i++)
                {
                    if (RootControl.Children[i] is SurfaceControl control)
                    {
                        control.OnSurfaceLoaded();
                    }
                }

                RootControl.UnlockChildrenRecursive();

                // Update boxes types for nodes that dependant box types based on incoming connections
                {
                    bool keepUpdating = false;
                    int  updateLimit  = 100;
                    do
                    {
                        for (int i = 0; i < RootControl.Children.Count; i++)
                        {
                            if (RootControl.Children[i] is SurfaceNode node && !node.HasDependentBoxesSetup)
                            {
                                node.UpdateBoxesTypes();
                                keepUpdating = true;
                            }
                        }
                    } while (keepUpdating && updateLimit-- > 0);
                }

                Loaded?.Invoke(this);

                // Clear modification flag
                _isModified = false;
            }
            catch (Exception ex)
            {
                // Error
                Editor.LogWarning("Loading Visject Surface data failed.");
                Editor.LogWarning(ex);
                return(true);
            }

            return(false);
        }
        private void SaveGraph(BinaryWriter stream)
        {
            // IMPORTANT! This must match C++ Graph format
            // Changes: don't write save time and keep engine build constant

            // Magic Code
            stream.Write(1963542358);

            // Engine Build
            stream.Write(6118);

            // Time saved
            stream.Write((long)0);

            // Nodes count
            stream.Write(Nodes.Count);

            // Parameters count
            stream.Write(Parameters.Count);

            // For each node
            for (int i = 0; i < Nodes.Count; i++)
            {
                var node = Nodes[i];

                // ID
                stream.Write(node.ID);

                // Type
                stream.Write(node.Type);
            }

            // For each param
            for (int i = 0; i < Parameters.Count; i++)
            {
                var param = Parameters[i];

                // Properties
                stream.Write((byte)param.Type);
                stream.Write(param.ID.ToByteArray());
                Utils.WriteStr(stream, param.Name, 97);
                stream.Write((byte)(param.IsPublic ? 1 : 0));
                stream.Write((byte)(param.IsStatic ? 1 : 0));
                stream.Write((byte)(param.IsUIVisible ? 1 : 0));
                stream.Write((byte)(param.IsUIEditable ? 1 : 0));

                // References
                stream.Write(param.ReferencedBy.Count);
                for (int j = 0; j < param.ReferencedBy.Count; j++)
                {
                    stream.Write(param.ReferencedBy[j].ID);
                }

                // Value
                Utils.WriteCommonValue(stream, param.Value);

                // Meta
                param.Meta.Save(stream);
            }

            // For each node
            var boxes = _cachedBoxes.Value;

            boxes.Clear();
            for (int i = 0; i < Nodes.Count; i++)
            {
                var node = Nodes[i];

                // Values
                if (node.Values != null)
                {
                    stream.Write(node.Values.Length);
                    for (int j = 0; j < node.Values.Length; j++)
                    {
                        Utils.WriteCommonValue(stream, node.Values[j]);
                    }
                }
                else
                {
                    stream.Write(0);
                }

                // Boxes
                node.GetBoxes(boxes);
                stream.Write((ushort)boxes.Count);
                for (int j = 0; j < boxes.Count; j++)
                {
                    var box = boxes[j];

                    stream.Write((byte)box.ID);
                    stream.Write((uint)box.DefaultType);
                    stream.Write((ushort)box.Connections.Count);
                    for (int k = 0; k < box.Connections.Count; k++)
                    {
                        var targetBox = box.Connections[k];

                        if (targetBox == null)
                        {
                            throw new Exception("Missing target box.");
                        }

                        stream.Write(targetBox.ParentNode.ID);
                        stream.Write((byte)targetBox.ID);
                    }
                }

                // Meta
                node.Meta.Save(stream);
            }
            boxes.Clear();

            // Visject Meta
            _meta.Save(stream);

            // Ending char
            stream.Write((byte)'\t');
        }
Пример #12
0
        private void LoadGraph(BinaryReader stream)
        {
            // IMPORTANT! This must match C++ Graph format

            // Magic Code
            int tmp = stream.ReadInt32();

            if (tmp != 1963542358)
            {
                // Error
                throw new Exception("Invalid Graph format version");
            }

            // Engine Build
            uint engineBuild = stream.ReadUInt32();

            // Load1
            {
                // Time saved (not used anymore to prevent binary diffs after saving unmodified surface)
                stream.ReadInt64();
                byte[] guidBytes = new byte[16];

                // Nodes count
                int nodesCount = stream.ReadInt32();
                if (Nodes.Capacity < nodesCount)
                {
                    Nodes.Capacity = nodesCount;
                }
                List <ConnectionHint> tmpHints = _cachedConnections.Value;
                tmpHints.Clear();
                tmpHints.Capacity = Mathf.Max(tmpHints.Capacity, nodesCount * 4);

                // Parameters count
                int parametersCount = stream.ReadInt32();
                if (Parameters.Capacity < parametersCount)
                {
                    Parameters.Capacity = parametersCount;
                }

                // For each node
                for (int i = 0; i < nodesCount; i++)
                {
                    // ID
                    uint id = stream.ReadUInt32();

                    // Type
                    ushort typeId  = stream.ReadUInt16();
                    ushort groupId = stream.ReadUInt16();

                    // Create node
                    var node = NodeFactory.CreateNode(_surface.NodeArchetypes, id, this, groupId, typeId);
                    if (node == null)
                    {
                        // Error
                        throw new Exception("Cannot create graph node.");
                    }
                    Nodes.Add(node);
                }

                // For each param
                for (int i = 0; i < parametersCount; i++)
                {
                    // Create param
                    var param = new SurfaceParameter();
                    Parameters.Add(param);

                    // Properties
                    param.Type = (ParameterType)stream.ReadByte();
                    stream.Read(guidBytes, 0, 16);
                    param.ID           = new Guid(guidBytes);
                    param.Name         = Utils.ReadStr(stream, 97);
                    param.IsPublic     = stream.ReadByte() != 0;
                    param.IsStatic     = stream.ReadByte() != 0;
                    param.IsUIVisible  = stream.ReadByte() != 0;
                    param.IsUIEditable = stream.ReadByte() != 0;

                    // References
                    int refsCount = stream.ReadInt32();
                    param.ReferencedBy.Capacity = refsCount;
                    for (int j = 0; j < refsCount; j++)
                    {
                        uint refID = stream.ReadUInt32();
                        var  node  = FindNode(refID);
                        if (node == null)
                        {
                            // Error
                            Editor.LogWarning($"Invalid node reference id (param: {param.Name}, node ref: {refID})");
                        }
                        else
                        {
                            param.ReferencedBy.Add(node);
                        }
                    }

                    // Value
                    Utils.ReadCommonValue(stream, ref param.Value);

                    // Meta
                    param.Meta.Load(engineBuild, stream);
                }

                // For each node
                for (int i = 0; i < nodesCount; i++)
                {
                    var node = Nodes[i];

                    // Values
                    int valuesCnt     = stream.ReadInt32();
                    int nodeValuesCnt = node.Values?.Length ?? 0;
                    if (valuesCnt == nodeValuesCnt)
                    {
                        for (int j = 0; j < valuesCnt; j++)
                        {
                            // ReSharper disable once PossibleNullReferenceException
                            Utils.ReadCommonValue(stream, ref node.Values[j]);
                        }
                    }
                    else
                    {
                        Editor.LogWarning(String.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID));

                        object dummy = null;
                        for (int j = 0; j < valuesCnt; j++)
                        {
                            Utils.ReadCommonValue(stream, ref dummy);
                        }
                    }

                    // Boxes
                    ushort boxesCount = stream.ReadUInt16();
                    for (int j = 0; j < boxesCount; j++)
                    {
                        var    id             = stream.ReadByte();
                        uint   type           = stream.ReadUInt32();
                        ushort connectionsCnt = stream.ReadUInt16();

                        ConnectionHint hint;
                        hint.NodeB = node;
                        hint.BoxB  = id;

                        for (int k = 0; k < connectionsCnt; k++)
                        {
                            uint targetNodeID = stream.ReadUInt32();
                            byte targetBoxID  = stream.ReadByte();

                            hint.NodeA = FindNode(targetNodeID);
                            if (hint.NodeA == null)
                            {
                                // Error
                                Editor.LogWarning("Invalid connected node id.");
                            }
                            else
                            {
                                hint.BoxA = targetBoxID;

                                tmpHints.Add(hint);
                            }
                        }
                    }

                    // Meta
                    node.Meta.Load(engineBuild, stream);

                    OnControlLoaded(node);
                }

                // Visject Meta
                _meta.Load(engineBuild, stream);

                // Setup connections
                for (int i = 0; i < tmpHints.Count; i++)
                {
                    var c    = tmpHints[i];
                    var boxA = c.NodeA.GetBox(c.BoxA);
                    var boxB = c.NodeB.GetBox(c.BoxB);
                    if (boxA != null && boxB != null)
                    {
                        boxA.Connections.Add(boxB);
                    }
                }

                // Ending char
                byte end = stream.ReadByte();
                if (end != '\t')
                {
                    // Error
                    throw new Exception("Invalid data.");
                }
            }
        }
        /// <summary>
        /// Resizes collection to the specified new size.
        /// </summary>
        /// <param name="newSize">The new size.</param>
        protected void Resize(int newSize)
        {
            var dictionary = Values[0] as IDictionary;
            var oldSize    = dictionary?.Count ?? 0;

            if (oldSize == newSize)
            {
                return;
            }

            // Allocate new collection
            var type      = Values.Type;
            var argTypes  = type.GetGenericArguments();
            var keyType   = argTypes[0];
            var valueType = argTypes[1];
            var newValues = (IDictionary)Activator.CreateInstance(type);

            // Copy all keys/values
            int itemsLeft = newSize;

            if (dictionary != null)
            {
                foreach (var e in dictionary.Keys)
                {
                    if (itemsLeft == 0)
                    {
                        break;
                    }
                    newValues[e] = dictionary[e];
                    itemsLeft--;
                }
            }

            // Insert new items (find unique keys)
            int newItemsLeft = newSize - oldSize;

            while (newItemsLeft-- > 0)
            {
                if (keyType.IsPrimitive)
                {
                    long uniqueKey = 0;
                    bool isUnique;
                    do
                    {
                        isUnique = true;
                        foreach (var e in newValues.Keys)
                        {
                            var asLong = Convert.ToInt64(e);
                            if (asLong == uniqueKey)
                            {
                                uniqueKey++;
                                isUnique = false;
                                break;
                            }
                        }
                    } while (!isUnique);

                    newValues[Convert.ChangeType(uniqueKey, keyType)] = Utils.GetDefaultValue(valueType);
                }
                else if (keyType.IsEnum)
                {
                    var  enumValues     = Enum.GetValues(keyType);
                    int  uniqueKeyIndex = 0;
                    bool isUnique;
                    do
                    {
                        isUnique = true;
                        foreach (var e in newValues.Keys)
                        {
                            if (Equals(e, enumValues.GetValue(uniqueKeyIndex)))
                            {
                                uniqueKeyIndex++;
                                isUnique = false;
                                break;
                            }
                        }
                    } while (!isUnique && uniqueKeyIndex < enumValues.Length);

                    newValues[enumValues.GetValue(uniqueKeyIndex)] = Utils.GetDefaultValue(valueType);
                }
                else if (keyType == typeof(string))
                {
                    string uniqueKey = "Key";
                    bool   isUnique;
                    do
                    {
                        isUnique = true;
                        foreach (var e in newValues.Keys)
                        {
                            if ((string)e == uniqueKey)
                            {
                                uniqueKey += "*";
                                isUnique   = false;
                                break;
                            }
                        }
                    } while (!isUnique);

                    newValues[uniqueKey] = Utils.GetDefaultValue(valueType);
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }

            SetValue(newValues);
        }
Пример #14
0
        /// <inheritdoc />
        public override void Initialize(LayoutElementsContainer layout)
        {
            _readOnly        = false;
            _canReorderItems = true;
            _notNullItems    = false;

            // No support for different collections for now
            if (HasDifferentValues || HasDifferentTypes)
            {
                return;
            }

            var type = Values.Type;
            var size = Count;

            // Try get MemberCollectionAttribute for collection editor meta
            var  attributes         = Values.GetAttributes();
            Type overrideEditorType = null;

            if (attributes != null)
            {
                var memberCollection = (MemberCollectionAttribute)attributes.FirstOrDefault(x => x is MemberCollectionAttribute);
                if (memberCollection != null)
                {
                    // TODO: handle ReadOnly and NotNullItems by filtering child editors SetValue
                    // TODO: handle CanReorderItems

                    _readOnly          = memberCollection.ReadOnly;
                    _canReorderItems   = memberCollection.CanReorderItems;
                    _notNullItems      = memberCollection.NotNullItems;
                    overrideEditorType = Utils.GetType(memberCollection.OverrideEditorTypeName);
                }
            }

            // Size
            if (_readOnly)
            {
                layout.Label("Size", size.ToString());
            }
            else
            {
                _size = layout.IntegerValue("Size");
                _size.IntValue.MinValue      = 0;
                _size.IntValue.MaxValue      = ushort.MaxValue;
                _size.IntValue.Value         = size;
                _size.IntValue.ValueChanged += OnSizeChanged;
            }

            // Elements
            if (size > 0)
            {
                var argTypes       = type.GetGenericArguments();
                var keyType        = argTypes[0];
                var valueType      = argTypes[1];
                var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType <object>();
                var keys           = keysEnumerable as object[] ?? keysEnumerable.ToArray();
                for (int i = 0; i < size; i++)
                {
                    var item     = layout.CustomContainer <UniformGridPanel>();
                    var itemGrid = item.CustomControl;
                    itemGrid.Height            = TextBox.DefaultHeight; // TODO: make slots auto sizable instead of fixed height
                    itemGrid.SlotsHorizontally = 2;
                    itemGrid.SlotsVertically   = 1;

                    // Key
                    // TODO: allow edit keys
                    var key = keys.ElementAt(i);
                    item.Label(key.ToString());

                    // Value
                    var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
                    item.Object(new DictionaryValueContainer(valueType, key, Values), overrideEditor);
                }
            }
            _elementsCount = size;
        }
Пример #15
0
        /// <summary>
        /// Resizes collection to the specified new size.
        /// </summary>
        /// <param name="newSize">The new size.</param>
        protected void Resize(int newSize)
        {
            var dictionary = Values[0] as IDictionary;
            var oldSize    = dictionary?.Count ?? 0;

            if (oldSize != newSize)
            {
                // Allocate new collection
                var type      = Values.Type;
                var argTypes  = type.GetGenericArguments();
                var keyType   = argTypes[0];
                var valueType = argTypes[1];
                var newValues = (IDictionary)Activator.CreateInstance(type);

                // Copy all keys/values
                int itemsLeft = newSize;
                if (dictionary != null)
                {
                    foreach (var e in dictionary.Keys)
                    {
                        if (itemsLeft == 0)
                        {
                            break;
                        }
                        newValues[e] = dictionary[e];
                        itemsLeft--;
                    }
                }

                // Insert new items (find unique keys)
                int newItesmLeft = newSize - oldSize;
                while (newItesmLeft-- > 0)
                {
                    if (keyType == typeof(int))
                    {
                        int  uniqueKey = 0;
                        bool isUnique;
                        do
                        {
                            isUnique = true;
                            foreach (var e in newValues.Keys)
                            {
                                if ((int)e == uniqueKey)
                                {
                                    uniqueKey++;
                                    isUnique = false;
                                    break;
                                }
                            }
                        } while (!isUnique);

                        newValues[uniqueKey] = Utils.GetDefaultValue(valueType);
                    }
                    else if (keyType == typeof(string))
                    {
                        string uniqueKey = "Key";
                        bool   isUnique;
                        do
                        {
                            isUnique = true;
                            foreach (var e in newValues.Keys)
                            {
                                if ((string)e == uniqueKey)
                                {
                                    uniqueKey += "*";
                                    isUnique   = false;
                                    break;
                                }
                            }
                        } while (!isUnique);

                        newValues[uniqueKey] = Utils.GetDefaultValue(valueType);
                    }
                    else
                    {
                        throw new InvalidOperationException();
                    }
                }

                SetValue(newValues);
            }
        }
Пример #16
0
        /// <inheritdoc />
        public override void Initialize(LayoutElementsContainer layout)
        {
            _readOnly        = false;
            _canReorderItems = true;
            _notNullItems    = false;

            // No support for different collections for now
            if (HasDifferentValues || HasDifferentTypes)
            {
                return;
            }

            var size = Count;

            // Try get MemberCollectionAttribute for collection editor meta
            var  attributes         = Values.GetAttributes();
            Type overrideEditorType = null;

            if (attributes != null)
            {
                var memberCollection = (MemberCollectionAttribute)attributes.FirstOrDefault(x => x is MemberCollectionAttribute);
                if (memberCollection != null)
                {
                    // TODO: handle NotNullItems by filtering child editors SetValue

                    _readOnly          = memberCollection.ReadOnly;
                    _canReorderItems   = memberCollection.CanReorderItems;
                    _notNullItems      = memberCollection.NotNullItems;
                    overrideEditorType = Utils.GetType(memberCollection.OverrideEditorTypeName);
                }
            }

            // Size
            if (_readOnly)
            {
                layout.Label("Size", size.ToString());
            }
            else
            {
                _size = layout.IntegerValue("Size");
                _size.IntValue.MinValue      = 0;
                _size.IntValue.MaxValue      = ushort.MaxValue;
                _size.IntValue.Value         = size;
                _size.IntValue.ValueChanged += OnSizeChanged;
            }

            // Elements
            if (size > 0)
            {
                var elementType = ElementType;
                if (_canReorderItems)
                {
                    for (int i = 0; i < size; i++)
                    {
                        var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
                        layout.Object(new CollectionItemLabel(this, i), new ListValueContainer(elementType, i, Values), overrideEditor);
                    }
                }
                else
                {
                    for (int i = 0; i < size; i++)
                    {
                        var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
                        layout.Object("Element " + i, new ListValueContainer(elementType, i, Values), overrideEditor);
                    }
                }
            }
            _elementsCount = size;

            // Add/Remove buttons
            if (!_readOnly)
            {
                var area      = layout.Space(20);
                var addButton = new Button(area.ContainerControl.Width - (16 + 16 + 2 + 2), 2, 16, 16)
                {
                    Text         = "+",
                    TooltipText  = "Add new item",
                    AnchorPreset = AnchorPresets.TopRight,
                    Parent       = area.ContainerControl
                };
                addButton.Clicked += () =>
                {
                    if (IsSetBlocked)
                    {
                        return;
                    }

                    Resize(Count + 1);
                };
                var removeButton = new Button(addButton.Right + 2, addButton.Y, 16, 16)
                {
                    Text         = "-",
                    TooltipText  = "Remove last item",
                    AnchorPreset = AnchorPresets.TopRight,
                    Parent       = area.ContainerControl,
                    Enabled      = size > 0
                };
                removeButton.Clicked += () =>
                {
                    if (IsSetBlocked)
                    {
                        return;
                    }

                    Resize(Count - 1);
                };
            }
        }
        /// <inheritdoc />
        public override void Initialize(LayoutElementsContainer layout)
        {
            _readOnly     = false;
            _notNullItems = false;

            // No support for different collections for now
            if (HasDifferentValues || HasDifferentTypes)
            {
                return;
            }

            var type      = Values.Type;
            var size      = Count;
            var argTypes  = type.GetGenericArguments();
            var keyType   = argTypes[0];
            var valueType = argTypes[1];

            _canEditKeys = keyType == typeof(string) || keyType.IsPrimitive || keyType.IsEnum;

            // Try get CollectionAttribute for collection editor meta
            var  attributes         = Values.GetAttributes();
            Type overrideEditorType = null;

            if (attributes != null)
            {
                var collection = (CollectionAttribute)attributes.FirstOrDefault(x => x is CollectionAttribute);
                if (collection != null)
                {
                    // TODO: handle ReadOnly and NotNullItems by filtering child editors SetValue

                    _readOnly          = collection.ReadOnly;
                    _notNullItems      = collection.NotNullItems;
                    overrideEditorType = Utils.GetType(collection.OverrideEditorTypeName);
                }
            }

            // Size
            if (_readOnly || !_canEditKeys)
            {
                layout.Label("Size", size.ToString());
            }
            else
            {
                _size = layout.IntegerValue("Size");
                _size.IntValue.MinValue      = 0;
                _size.IntValue.MaxValue      = ushort.MaxValue;
                _size.IntValue.Value         = size;
                _size.IntValue.ValueChanged += OnSizeChanged;
            }

            // Elements
            if (size > 0)
            {
                var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType <object>();
                var keys           = keysEnumerable as object[] ?? keysEnumerable.ToArray();
                for (int i = 0; i < size; i++)
                {
                    var key            = keys.ElementAt(i);
                    var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
                    layout.Object(new DictionaryItemLabel(this, key), new DictionaryValueContainer(valueType, key, Values), overrideEditor);
                }
            }
            _elementsCount = size;

            // Add/Remove buttons
            if (!_readOnly && _canEditKeys)
            {
                var area      = layout.Space(20);
                var addButton = new Button(area.ContainerControl.Width - (16 + 16 + 2 + 2), 2, 16, 16)
                {
                    Text         = "+",
                    TooltipText  = "Add new item",
                    AnchorPreset = AnchorPresets.TopRight,
                    Parent       = area.ContainerControl
                };
                addButton.Clicked += () =>
                {
                    if (IsSetBlocked)
                    {
                        return;
                    }

                    Resize(Count + 1);
                };
                var removeButton = new Button(addButton.Right + 2, addButton.Y, 16, 16)
                {
                    Text         = "-",
                    TooltipText  = "Remove last item",
                    AnchorPreset = AnchorPresets.TopRight,
                    Parent       = area.ContainerControl,
                    Enabled      = size > 0
                };
                removeButton.Clicked += () =>
                {
                    if (IsSetBlocked)
                    {
                        return;
                    }

                    Resize(Count - 1);
                };
            }
        }