Exemple #1
0
        private string GetVariant()
        {
            string       compoundVariant = null;
            FeatureAsset feature         = FeatureEditorWindow.GetInstance().Feature;

            Vector2Int[] selectedPositions = feature.GetSelectedSections();
            foreach (Vector2Int position in selectedPositions)
            {
                if (feature.TryGetSection(position, out Section section))
                {
                    if (compoundVariant == null)
                    {
                        //first variant found
                        compoundVariant = section.variant;
                    }
                    else if (compoundVariant != section.variant)
                    {
                        //variant names are not uniform
                        return(null);
                    }
                    //variant names are uniform so far, continue
                }
            }
            return(compoundVariant);
        }
Exemple #2
0
        // Check for valid internal links
        void ValidateInternalLink(FeatureAsset feature, Vector2Int featureAssetPos)
        {
            feature.TryGetLink(featureAssetPos, out Link link);

            Assert.IsNotNull(link, "Internal link expected to exist at position: " + featureAssetPos);
            Assert.True(link.open, "Link was expected to be open (found closed) at position: " + featureAssetPos);
            Assert.False(link.external, "Link was expected to be internal (found external) at position: " + featureAssetPos);
        }
Exemple #3
0
        public void CanConvertFromFeature_Square()
        {
            // Feature is a 2x2 square.
            Feature feature = new Feature();

            feature.Add(0, 0);
            feature.Add(1, 0);
            feature.Add(0, 1);
            feature.Add(1, 1);

            FeatureAsset featureAsset = FeatureAsset.FromFeature(feature);

            // Basic test- are sections present?
            ValidateSection(featureAsset, new Vector2Int(0, 0));
            ValidateSection(featureAsset, new Vector2Int(1, 0));
            ValidateSection(featureAsset, new Vector2Int(0, 1));
            ValidateSection(featureAsset, new Vector2Int(1, 1));

            /*
             * Layout of the FeatureAsset grid, for reference.
             *
             *  3 o | o | o
             *  2 - r - r -
             *  1 o | x | o
             *  0 - r - r -
             * -1 o | o | o
             *   -1 0 1 2 3
             */

            ValidateExternalLink(featureAsset, new Vector2Int(0, 3));  // Top
            ValidateExternalLink(featureAsset, new Vector2Int(2, 3));
            ValidateExternalLink(featureAsset, new Vector2Int(-1, 0)); // Left
            ValidateExternalLink(featureAsset, new Vector2Int(-1, 2));
            ValidateExternalLink(featureAsset, new Vector2Int(0, -1)); // Bottom
            ValidateExternalLink(featureAsset, new Vector2Int(2, -1));
            ValidateExternalLink(featureAsset, new Vector2Int(3, 0));  // Right
            ValidateExternalLink(featureAsset, new Vector2Int(3, 2));

            ValidateInternalLink(featureAsset, new Vector2Int(1, 2)); // Top
            ValidateInternalLink(featureAsset, new Vector2Int(0, 1)); // Left
            ValidateInternalLink(featureAsset, new Vector2Int(1, 0)); // Bottom
            ValidateInternalLink(featureAsset, new Vector2Int(2, 1)); // Right
            ValidateInternalLink(featureAsset, new Vector2Int(1, 1)); // Middle

            ValidateMissingLink(featureAsset, new Vector2Int(-1, -1));
            ValidateMissingLink(featureAsset, new Vector2Int(1, -1));
            ValidateMissingLink(featureAsset, new Vector2Int(3, -1));
            ValidateMissingLink(featureAsset, new Vector2Int(-1, 1));
            //ValidateMissingLink(featureAsset, new Vector2Int(1, 1)); // Middle
            ValidateMissingLink(featureAsset, new Vector2Int(3, 1));
            ValidateMissingLink(featureAsset, new Vector2Int(-1, 3));
            ValidateMissingLink(featureAsset, new Vector2Int(1, 3));
            ValidateMissingLink(featureAsset, new Vector2Int(3, 3));
        }
Exemple #4
0
        public void CanConvertFromFeature_Line()
        {
            // Feature 1 is a horizontal line.
            Feature feature1 = new Feature();

            feature1.Add(0, 0);
            feature1.Add(1, 0);
            feature1.Add(2, 0);

            FeatureAsset featureAsset1 = FeatureAsset.FromFeature(feature1);

            // Basic test. Make sure all sections are present in FeatureAsset.
            // FA uses a 2x grid, so we multiply all inputs by 2 to verify.

            ValidateSection(featureAsset1, new Vector2Int(0, 0));
            ValidateSection(featureAsset1, new Vector2Int(1, 0));
            ValidateSection(featureAsset1, new Vector2Int(2, 0));


            /* -1012345
             *  o|o|o|o
             *  -X-X-X-
             *  o|o|o|o
             */

            // Middle
            ValidateExternalLink(featureAsset1, new Vector2Int(-1, 0));
            ValidateInternalLink(featureAsset1, new Vector2Int(1, 0)); // Should be internal
            ValidateInternalLink(featureAsset1, new Vector2Int(3, 0)); // Should be internal
            ValidateExternalLink(featureAsset1, new Vector2Int(5, 0));

            // Top row
            ValidateExternalLink(featureAsset1, new Vector2Int(0, 1));
            ValidateExternalLink(featureAsset1, new Vector2Int(2, 1));
            ValidateExternalLink(featureAsset1, new Vector2Int(4, 1));

            // Bottom row
            ValidateExternalLink(featureAsset1, new Vector2Int(0, -1));
            ValidateExternalLink(featureAsset1, new Vector2Int(2, -1));
            ValidateExternalLink(featureAsset1, new Vector2Int(4, -1));

            // Invalid links
            ValidateMissingLink(featureAsset1, new Vector2Int(-1, 1));
            ValidateMissingLink(featureAsset1, new Vector2Int(1, 1));
            ValidateMissingLink(featureAsset1, new Vector2Int(3, 1));
            ValidateMissingLink(featureAsset1, new Vector2Int(5, 1));
            ValidateMissingLink(featureAsset1, new Vector2Int(-1, -1));
            ValidateMissingLink(featureAsset1, new Vector2Int(1, -1));
            ValidateMissingLink(featureAsset1, new Vector2Int(3, -1));
            ValidateMissingLink(featureAsset1, new Vector2Int(5, -1));
        }
Exemple #5
0
        public void CanConvertFromFeature_Diagonal()
        {
            // Feature is a diagonal line. Shouldn't have a link on the diagonal.
            Feature feature = new Feature();

            feature.Add(0, 0);
            feature.Add(1, 1);

            FeatureAsset featureAsset = FeatureAsset.FromFeature(feature);

            ValidateMissingLink(featureAsset, new Vector2Int(1, 1));

            // More tests should go here
        }
Exemple #6
0
        public void CanConvertFromFeature_Donut()
        {
            // Feature is a 3x3 square with a missing center.
            Feature feature = new Feature();

            feature.Add(0, 0);
            feature.Add(1, 0);
            feature.Add(2, 0);

            feature.Add(0, 1);
            //feature.Add(1, 1);
            feature.Add(2, 1);

            feature.Add(0, 2);
            feature.Add(1, 2);
            feature.Add(2, 2);

            FeatureAsset featureAsset = FeatureAsset.FromFeature(feature);

            // Basic test- are sections present?
            //ValidateSection(featureAsset, new Vector2Int(0, 0));
            //ValidateSection(featureAsset, new Vector2Int(1, 0));
            //ValidateSection(featureAsset, new Vector2Int(0, 1));
            //ValidateSection(featureAsset, new Vector2Int(1, 1));

            /*
             *  5 o | o | o | o
             *  4 - r - r - r -
             *  3 o | o | o | o
             *  2 - r - o - r -
             *  1 o | o | o | o
             *  0 - r - r - r -
             * -1 o | o | o | o
             *   -1 0 1 2 3 4 5
             */

            // Inside the donut, we should have external links
            ValidateExternalLink(featureAsset, new Vector2Int(2, 1));
            ValidateExternalLink(featureAsset, new Vector2Int(2, 3));
            ValidateExternalLink(featureAsset, new Vector2Int(1, 2));
            ValidateExternalLink(featureAsset, new Vector2Int(3, 2));

            // More tests should go here
        }
Exemple #7
0
        public void CanConvertToFromFeature()
        {
            Feature feature1 = new Feature();

            feature1.Add(0, 0);
            feature1.Add(1, 0);
            feature1.Add(2, 0);

            FeatureAsset featureAsset1 = FeatureAsset.FromFeature(feature1);
            Feature      testFeature1  = featureAsset1.ToFeature();

            // Basic test. All input positions should be present in output
            Assert.Contains(new Vector2Int(0, 0), testFeature1.Elements.Keys);
            Assert.Contains(new Vector2Int(1, 0), testFeature1.Elements.Keys);
            Assert.Contains(new Vector2Int(2, 0), testFeature1.Elements.Keys);

            // Basic test. Ensure bounds are unchanged
            Assert.AreEqual(feature1.MaxX, testFeature1.MaxX);
            Assert.AreEqual(feature1.MaxY, testFeature1.MaxY);
            Assert.AreEqual(feature1.MinX, testFeature1.MinX);
            Assert.AreEqual(feature1.MinY, testFeature1.MinY);


            // Harder test. Conversion of Feature -> FeatureAsset -> Feature does not obey identity property.
            // All connections at the end will be present in the original, but additionally,
            // they will be restricted based on FeatureAsset retention rules.
            //
            // Thus, we test FeatureAsset retention rules separately, and ensure that
            // FeatureAfter.connections & FeatureBefore.connections == FeatureAfter.connections
            // to be sure that no connections are ever dropped.
            foreach (KeyValuePair <Vector2Int, Labrys.Generation.Section> kvp in testFeature1.Elements)
            {
                Labrys.Generation.Section orig = feature1.Elements[kvp.Key];
                Labrys.Generation.Section conv = kvp.Value;

                // Some connections may be lost. Ensure no new ones are added.
                Assert.AreEqual(orig.externalConnections & conv.externalConnections, conv.externalConnections);
                Assert.AreEqual(orig.internalConnections & conv.internalConnections, conv.internalConnections);

                // Make sure variants are unchanged.
                Assert.AreEqual(orig.GetVariant(), conv.GetVariant());
            }
        }
Exemple #8
0
        private IField[] GetFields()
        {
            Dictionary <string, AggSectionField> aggregatedFields = new Dictionary <string, AggSectionField>();
            FeatureAsset feature = FeatureEditorWindow.GetInstance().Feature;

            int count = 0;

            // Create aggregate field objects containing all fields in the enumerated sections, common or not
            feature.ForAllSelectedSections((Section s) => {
                count++;
                foreach (SectionField sf in s)
                {
                    if (aggregatedFields.TryGetValue(sf.Name, out AggSectionField aggregate))
                    {
                        aggregate.Fields.Add(sf);
                    }
                    else
                    {
                        aggregatedFields.Add(sf.Name, new AggSectionField()
                        {
                            Fields = { sf }
                        });
                    }
                }
            });

            // If an aggregate contains a field for every enumerated section, then add it to the return list;
            // this can be done because fields are guaranteed to be unique per section
            List <AggSectionField> commonAggregates = new List <AggSectionField>();

            foreach (AggSectionField aggregate in aggregatedFields.Values)
            {
                if (aggregate.Fields.Count == count)
                {
                    commonAggregates.Add(aggregate);
                }
            }

            return(commonAggregates.ToArray());
        }
Exemple #9
0
        private void DrawObjects()
        {
            FeatureAsset feature = FeatureEditorWindow.GetInstance().Feature;

            if (feature == null)
            {
                return;
            }

            Vector2 screenPosition = Vector2.zero;
            Rect    bounds         = new Rect(screenPosition, GetScaledTileSize());

            // Draw Sections
            foreach (KeyValuePair <Vector2Int, Section> section in feature.GetSections())
            {
                screenPosition  = GridToScreenPos(section.Key);
                bounds.position = screenPosition;
                bounds.center   = screenPosition;
                Color temp = GUI.color;
                GUI.color = feature.IsSelected(section.Key) ? sectionSelectedColor : Color.white;
                GUI.Box(bounds, section.Value.variant);
                GUI.color = temp;
            }

            // Draw Links
            foreach (KeyValuePair <Vector2Int, Link> link in feature.GetLinks())
            {
                screenPosition = GridToScreenPos(link.Key);
                Handles.color  = link.Value.open ? linkOpenColor : linkClosedColor;
                Handles.BeginGUI();
                Handles.DrawSolidDisc(new Vector3(screenPosition.x, screenPosition.y), Vector3.forward, scale * LINK_SIZE);
                if (link.Value.external)
                {
                    Handles.color = linkExternalColor;
                    Handles.DrawSolidArc(new Vector3(screenPosition.x, screenPosition.y), Vector3.forward, Vector3.left, 180f, scale * LINK_SIZE);
                }
                Handles.EndGUI();
            }
        }
Exemple #10
0
        public override bool HandleEvent(Event e)
        {
            if (tileEditorPanel.HandleEvent(e))
            {
                return(true);
            }

            switch (e.type)
            {
            case EventType.MouseDown:
                if (IsPrimaryControl(e))
                {
                    //start selection box
                    selectionRect.position = e.mousePosition;
                    e.Use();
                    selectionMode = SELECT_MODE_SELECT;
                    return(true);
                }
                else if (IsSecondaryControl(e))
                {
                    //start selection box
                    selectionRect.position = e.mousePosition;
                    e.Use();
                    selectionMode = SELECT_MODE_DESELECT;
                    return(true);
                }
                break;

            case EventType.MouseDrag:
                if (IsPrimaryControl(e) || IsSecondaryControl(e))
                {
                    //update selection box
                    selectionRect.max = e.mousePosition;
                    e.Use();
                    return(true);
                }
                break;

            case EventType.MouseUp:
                if (IsPrimaryControl(e) || IsSecondaryControl(e))
                {
                    //select all tiles within selection box
                    string       description;
                    UnityAction  action;
                    Vector2Int[] positions = EditorGrid.GetInstance().RectToGridPositions(selectionRect, true);
                    FeatureAsset feature   = FeatureEditorWindow.GetInstance().Feature;
                    if (selectionMode == SELECT_MODE_SELECT)
                    {
                        description = "Select section(s)";
                        action      = () => {
                            if (!e.shift)
                            {
                                //not additive
                                feature.DeselectAllSections();
                            }
                            foreach (Vector2Int gp in positions)
                            {
                                //additive
                                feature.SelectSection(gp);
                            }
                        };
                    }
                    else if (selectionMode == SELECT_MODE_DESELECT)
                    {
                        description = "Deselect section(s)";
                        action      = () => {
                            if (!e.shift)
                            {
                                //not additive
                                feature.DeselectAllSections();
                            }
                            else
                            {
                                //additive
                                foreach (Vector2Int gp in positions)
                                {
                                    feature.DeselectSection(gp);
                                }
                            }
                        };
                    }
                    else
                    {
                        description = "ERROR";
                        action      = null;
                    }

                    ChangeAsset(feature, description, action);

                    selectionRect = new Rect();
                    selectionMode = SELECT_MODE_NONE;
                    e.Use();
                    return(true);
                }
                break;
            }
            return(false);
        }
Exemple #11
0
        // Check for invalid links
        void ValidateMissingLink(FeatureAsset feature, Vector2Int featureAssetPos)
        {
            feature.TryGetLink(featureAssetPos, out Link link);

            Assert.IsNull(link, "Link expected to be missing at position: " + featureAssetPos);
        }
Exemple #12
0
 // Confirms a given section exists at a position.
 private void ValidateSection(FeatureAsset feature, Vector2Int featurePos)
 {
     feature.TryGetSection(featurePos * 2, out Labrys.FeatureEditor.Section section);
     Assert.IsNotNull(section, "Section expected to exist at position: " + (featurePos * 2));
 }
Exemple #13
0
        public override bool HandleEvent(Event e)
        {
            switch (e.type)
            {
            case EventType.MouseDown:
                settingExternal = (IsPrimaryControl(e) || IsSecondaryControl(e)) && e.control;
                goto case EventType.MouseDrag;

            case EventType.MouseDrag:
                if (IsPrimaryControl(e) || IsSecondaryControl(e))
                {
                    Vector2Int position = EditorGrid.GetInstance().ScreenToGridPos(e.mousePosition);
                    if (FeatureEditorWindow.GetInstance().Feature.HasLinkAt(position))
                    {
                        manipPositions.Add(position);
                        if (settingExternal)
                        {
                            previewColor = Color.yellow;
                        }
                        else if (IsPrimaryControl(e))
                        {
                            previewColor = Color.green;
                        }
                        else if (IsSecondaryControl(e))
                        {
                            previewColor = Color.red;
                        }
                        return(true);
                    }
                }
                break;

            case EventType.MouseUp:
                if (IsPrimaryControl(e) || IsSecondaryControl(e))
                {
                    FeatureAsset feature = FeatureEditorWindow.GetInstance().Feature;
                    string       description;
                    UnityAction  action;

                    bool targetState = IsPrimaryControl(e) ? true : IsSecondaryControl(e) ? false : false;
                    if (settingExternal)
                    {
                        description = targetState ? "Set connection(s) to external" : "Set connections(s) to internal";
                        action      = () => {
                            foreach (Vector2Int position in manipPositions)
                            {
                                if (feature.TryGetLink(position, out Link link))
                                {
                                    link.external = targetState;
                                }
                            }
                        };
                    }
                    else
                    {
                        description = targetState ? "Set connection(s) to open" : "Set connections(s) to closed";
                        action      = () => {
                            foreach (Vector2Int position in manipPositions)
                            {
                                if (feature.TryGetLink(position, out Link link))
                                {
                                    link.open = targetState;
                                }
                            }
                        };
                    }

                    ChangeAsset(feature, description, action);

                    e.Use();
                    manipPositions.Clear();
                    return(true);
                }
                break;
            }
            return(false);
        }
Exemple #14
0
        public override bool HandleEvent(Event e)
        {
            switch (e.type)
            {
            case EventType.MouseDown:
            case EventType.MouseDrag:
                if (IsPrimaryControl(e) || IsSecondaryControl(e))
                {
                    Vector2Int position   = EditorGrid.GetInstance().ScreenToGridPos(e.mousePosition, true);
                    bool       posHasTile = FeatureEditorWindow.GetInstance().Feature.HasSectionAt(position);
                    if ((IsPrimaryControl(e) && !posHasTile) || (IsSecondaryControl(e) && posHasTile))
                    {
                        manipPositions.Add(position);
                        if (IsPrimaryControl(e))
                        {
                            previewColor = Color.green;
                        }
                        else if (IsSecondaryControl(e))
                        {
                            previewColor = Color.red;
                        }
                        return(true);
                    }
                }
                break;

            case EventType.MouseUp:
                if (IsPrimaryControl(e) || IsSecondaryControl(e))
                {
                    //attempt to place a tile in accumpulated positions
                    FeatureAsset feature = FeatureEditorWindow.GetInstance().Feature;
                    string       description;
                    UnityAction  action;

                    //add sections
                    if (IsPrimaryControl(e))
                    {
                        description = "Add section(s)";
                        action      = () => {
                            foreach (Vector2Int position in manipPositions)
                            {
                                FeatureEditorWindow.GetInstance().Feature.AddSection(position);
                            }
                        };
                    }
                    //remove sections
                    else if (IsSecondaryControl(e))
                    {
                        description = "Remove section(s)";
                        action      = () => {
                            foreach (Vector2Int position in manipPositions)
                            {
                                FeatureEditorWindow.GetInstance().Feature.RemoveSection(position);
                            }
                        };
                    }
                    else
                    {
                        return(false);
                    }

                    ChangeAsset(feature, description, action);

                    e.Use();
                    manipPositions.Clear();
                    return(true);
                }
                break;
            }
            return(false);
        }
Exemple #15
0
        public override bool HandleEvent(Event e)
        {
            const float padding          = 5;
            const float defControlHeight = 20;
            float       maxWidth         = bounds.width - (padding * 2);
            float       currY            = bounds.yMin + padding;
            float       minX             = bounds.xMin + padding;

            FeatureAsset feature = FeatureEditorWindow.GetInstance().Feature;

            //selected section number
            Rect selSecCountRect = new Rect(minX, currY, maxWidth, defControlHeight);
            int  selectionCount  = feature.GetSelectedCount();

            GUI.Box(selSecCountRect, selectionCount + (selectionCount == 1 ? " tile selected" : " tiles selected"));

            currY += selSecCountRect.height + padding;

            //variant field label
            Rect variantFieldLabelRect = new Rect(minX, currY, maxWidth / 4, defControlHeight);

            GUI.Box(variantFieldLabelRect, "Variant");

            //variant field select button
            Rect variantSelButRect = new Rect(bounds.xMax - padding - (maxWidth / 4), currY, maxWidth / 4, defControlHeight);

            if (GUI.Button(variantSelButRect, "Select"))
            {
                string   fullPath      = EditorUtility.OpenFolderPanel("Select Variant Folder", lastSelectedFolder != "" ? lastSelectedFolder : Application.dataPath, "");
                string[] splitFullPath = fullPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
                variant = splitFullPath[splitFullPath.Length - 1];
                SetVariant(variant);

                //save parent of selected folder
                lastSelectedFolder = fullPath.Substring(0,
                                                        Mathf.Max(
                                                            fullPath.LastIndexOf(Path.AltDirectorySeparatorChar),
                                                            fullPath.LastIndexOf(Path.DirectorySeparatorChar)));
            }

            //variant field text box
            Rect   variantTextRect = new Rect(minX + (maxWidth / 4), currY, maxWidth / 2, defControlHeight);
            string initialVariant  = GetVariant();

            if (initialVariant == null)
            {
                variant = MIXED_VALUES;
            }
            else
            {
                variant = initialVariant;
            }
            string newVariant = EditorGUI.TextField(variantTextRect, variant);

            if (newVariant != MIXED_VALUES && newVariant != variant)
            {
                Undo.RegisterCompleteObjectUndo(feature, "Change variant");
                feature.ForAllSelectedSections((Section s) => { s.variant = variant = newVariant; });
                EditorUtility.SetDirty(feature);
            }

            currY += defControlHeight + padding;

            //kvp add new
            Rect addNewKvpRect = new Rect(minX, currY, maxWidth, defControlHeight);

            if (GUI.Button(addNewKvpRect, "Add New Field"))
            {
                TextDialogWindow.Create((string text) => {
                    Undo.RegisterCompleteObjectUndo(feature, "Add New Field");
                    feature.ForAllSelectedSections((Section s) => { s.AddField(text); });
                    EditorUtility.SetDirty(feature);
                });
            }

            currY += defControlHeight + padding;

            //kvp scroll view
            IField[]    fields          = GetFields();
            const float fieldRectHeight = 20;

            Rect scrollViewRect   = new Rect(minX, currY, maxWidth, bounds.yMax - currY);
            Rect scrollBoundsRect = new Rect(scrollViewRect);

            scrollBoundsRect.height = (fieldRectHeight + padding) * fields.Length;
            scrollBoundsRect.width -= 20;

            kvpFieldScrollPos = GUI.BeginScrollView(scrollViewRect, kvpFieldScrollPos, scrollBoundsRect, false, true);

            Rect  fieldRect = new Rect(scrollBoundsRect);
            float startY    = fieldRect.y;

            fieldRect.height = fieldRectHeight;
            for (int i = 0; i < fields.Length; i++)
            {
                fieldRect.y = startY + (20 + padding) * i;

                Rect fieldRectPartial = new Rect(fieldRect);
                fieldRectPartial.width = fieldRect.width / 2;
                GUI.Box(fieldRectPartial, fields[i].Name);

                fieldRectPartial.x     += fieldRect.width / 2;
                fieldRectPartial.width /= 2;
                string initalValue = fields[i].Value;
                string modifiValue = EditorGUI.TextField(fieldRectPartial, initalValue);
                if (modifiValue != initalValue)
                {
                    Undo.RegisterCompleteObjectUndo(feature, $"Modified {fields[i].Name}");
                    feature.ForAllSelectedSections((Section s) => { s.SetField(fields[i].Name, modifiValue); });
                    EditorUtility.SetDirty(feature);
                }

                fieldRectPartial.x += fieldRect.width / 4;
                if (GUI.Button(fieldRectPartial, "Remove"))
                {
                    feature.ForAllSelectedSections((Section s) => { s.RemoveField(fields[i].Name); });
                }
            }

            GUI.EndScrollView(handleScrollWheel: true);

            return(bounds.Contains(e.mousePosition));
        }