/// <summary>
        ///		Loads the next node in the given binary reader and returns it.
        /// </summary>
        /// <param name="reader">Binary reader to read node from.</param>
        /// <param name="getProgress">If set to true this node is used to judge the current progress.</param>
        /// <returns>Scene node that was loaded from the binary reader.</returns>
        private SceneNode LoadNode(BinaryReader reader, bool getProgress)
        {
            // Read in the name of this node's class.
            string name = reader.ReadString();

            //HighPreformanceTimer timer = new HighPreformanceTimer();

            // Create a new instance of this entity and tell it to load itself.
            // (See if its a known object first as its quicker to get it without reflection)
            SceneNode node = null;
            if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.entitynode"))
                node = new EntityNode();
            else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.scriptedentitynode"))
                node = new ScriptedEntityNode();
            else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.scenenode"))
                node = new SceneNode();
            else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.groupnode"))
                node = new GroupNode();
            else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.emitternode"))
                node = new EmitterNode();
            else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.tilemapsegmentnode"))
                node = new TilemapSegmentNode();
            else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.pathmarkernode"))
                node = new PathMarkerNode();
            else if (name.ToLower().EndsWith("binaryphoenix.fusion.engine.entitys.tilenode"))
                node = new TileNode();
            else
                node = (SceneNode)ReflectionMethods.CreateObject(name);

            //DebugLogger.WriteLog("Created scene graph node " + name + " in " + timer.DurationMillisecond + ".\n");
            //timer.Restart();

            // Load in this nodes details.
            node.UniqueID = (_uniqueIDTracker++);
            node.Load(reader);

            //DebugLogger.WriteLog("Loaded scene graph node " + name + " in " + timer.DurationMillisecond + ".\n");

            // Read in all the children of this node, and attach
            // them to this node.
            DebugLogger.IncreaseIndent();
            int childCount = reader.ReadInt32();
            for (int i = 0; i < childCount; i++)
            {
                SceneNode childNode = LoadNode(reader);
                node.AddChild(childNode);

                if (getProgress == true)
                    _loadingProgress = (int)(((float)(i + 1) / (float)childCount) * 100.0f);
            }
            DebugLogger.DecreaseIndent();

            return node;
        }
        /// <summary>
        ///		Preforms a flood fill operation of the given tilemap.
        /// </summary>
        /// <param name="tilemapNode">Tilemap to flood fill.</param>
        /// <param name="x">X position to start flood filling.</param>
        /// <param name="y">Y position to start flood filling.</param>
        /// <param name="fillTileset">Tileset to overwrite when flood filling.</param>
        /// <param name="fillFrame">Frame to overwrite when flood filling.</param>
        /// <param name="fillTracker">Array to keep track of tiles that have been flooded.</param>
        /// <param name="selectionX">X position of the tile being used to fill this flood fill step with.</param>
        /// <param name="selectionY">Y position of the tile being used to fill this flood fill step with.</param>
        private void FloodFill(TilemapSegmentNode tilemapNode, int x, int y, Tileset fillTileset, int fillFrame, ref bool[,] fillTracker, int selectionX, int selectionY)
        {
            // If the selection has gone beyond the width or height of the selection
            // then wrap it around.
            if (selectionX < _assetManagerWindow.TilesetSelection.X)
                selectionX = _assetManagerWindow.TilesetSelection.X + _assetManagerWindow.TilesetSelection.Width - 1;

            if (selectionX > _assetManagerWindow.TilesetSelection.X + _assetManagerWindow.TilesetSelection.Width - 1)
                selectionX = _assetManagerWindow.TilesetSelection.X;

            if (selectionY < _assetManagerWindow.TilesetSelection.Y)
                selectionY = _assetManagerWindow.TilesetSelection.Y + _assetManagerWindow.TilesetSelection.Height - 1;

            if (selectionY > _assetManagerWindow.TilesetSelection.Y + _assetManagerWindow.TilesetSelection.Height - 1)
                selectionY = _assetManagerWindow.TilesetSelection.Y;

            // Work out the frame of the selection we should be applying to this tile.
            int selectionFrame = GetSelectedTileset().Image.FrameIndexAtPosition(selectionX * GetSelectedTileset().Image.Width, selectionY * GetSelectedTileset().Image.Height);

            // If this tile should be set then set it.
            if (tilemapNode[x, y].Tileset == fillTileset && tilemapNode[x, y].Frame == fillFrame)
            {
                tilemapNode[x, y].Tileset = GetSelectedTileset();
                tilemapNode[x, y].Frame = selectionFrame;
                tilemapNode[x, y].Scale(_flipTilesX == true ? -1 : 1, _flipTilesY == true ? -1 : 1, 1);
                tilemapNode[x, y].Color = _assetManagerWindow.TilesetColor;
            }

            // Make this tile as filled.
            fillTracker[x, y] = true;

            int tilemapNodeWidth = tilemapNode.Width / tilemapNode.TileWidth;
            int tilemapNodeHeight = tilemapNode.Height / tilemapNode.TileHeight;

            // Check the tile to the left of this one, and see if it can be filled.
            if (x - 1 >= 0 && x - 1 < tilemapNodeWidth && fillTracker[x - 1, y] == false && tilemapNode[x - 1, y].Tileset == fillTileset && tilemapNode[x - 1, y].Frame == fillFrame)
                FloodFill(tilemapNode, x - 1, y, fillTileset, fillFrame, ref fillTracker, selectionX - 1, selectionY);

            // Check the tile to the right of this one, and see if it can be filled.
            if (x + 1 >= 0 && x + 1 < tilemapNodeWidth && fillTracker[x + 1, y] == false && tilemapNode[x + 1, y].Tileset == fillTileset && tilemapNode[x + 1, y].Frame == fillFrame)
                FloodFill(tilemapNode, x + 1, y, fillTileset, fillFrame, ref fillTracker, selectionX + 1, selectionY);

            // Check the tile at the top of this one, and see if it can be filled.
            if (y - 1 >= 0 && y - 1 < tilemapNodeHeight && fillTracker[x, y - 1] == false && tilemapNode[x, y - 1].Tileset == fillTileset && tilemapNode[x, y - 1].Frame == fillFrame)
                FloodFill(tilemapNode, x, y - 1, fillTileset, fillFrame, ref fillTracker, selectionX, selectionY - 1);

            // Check the tile at the bottom of this one, and see if it can be filled.
            if (y + 1 >= 0 && y + 1 < tilemapNodeHeight && fillTracker[x, y + 1] == false && tilemapNode[x, y + 1].Tileset == fillTileset && tilemapNode[x, y + 1].Frame == fillFrame)
                FloodFill(tilemapNode, x, y + 1, fillTileset, fillFrame, ref fillTracker, selectionX, selectionY + 1);
        }
        /// <summary>
        ///		Inserts the current object into the map at the cursors position (or center-screen - 
        ///     - if this is not the active window) at the highest level on the scene graph
        /// </summary>
        private void InsertCurrentObject(bool inCenter, string overrideObjectURL)
        {
            string objectURL = overrideObjectURL != "" ? overrideObjectURL : _assetManagerWindow.SelectedObjectURL;
            EntityNode entity = null;

            // Keep a log of this insertion.
            DebugLogger.WriteLog("Inserting object of type '" + objectURL + "' into map");

            // Check the extension to see if this is a built-in object or not.
            if (objectURL.IndexOf(".fso") >= 0)
            {
                // Compile the script.
                ScriptCompiler compiler = new ScriptCompiler();
                bool errorOccured = false;
                string errorDescription = "\t";
                if (compiler.Compile(objectURL) > 0)
                    foreach (CompileError error in compiler.ErrorList)
                        if (error.AlertLevel == ErrorAlertLevel.Error || error.AlertLevel == ErrorAlertLevel.FatalError)
                        {
                            errorDescription += (errorDescription == "" ? "" : "\n\t") + error.ToString();
                            errorOccured = true;
                        }

                // If an error occured notify the user if not then
                // insert a new scripted entity into the map.
                if (errorOccured == true)
                {
                    MessageBox.Show("Unable to insert object into map, the following error(s) occured while attempt to compile this objects script.\n\n"+errorDescription,"Compile Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    DebugLogger.WriteLog("Object insertion aborted. The following error(s) occured while attempting to compile this objects script.\n\n" + errorDescription, LogAlertLevel.Warning);
                }
                else
                {
                    // Dump the compiled code into a memory stream.
                    MemoryStream memStream = new MemoryStream();
                    BinaryWriter writer = new BinaryWriter(memStream);
                    BinaryReader reader = new BinaryReader(memStream);
                    compiler.DumpExecutableFile(writer);
                    memStream.Position = 0;

                    // Create a new scripted entity with the given script attached to it.
                    ScriptedEntityNode scriptedEntity = new ScriptedEntityNode();
                    entity = scriptedEntity;
                    entity.RenderMode = EntityRenderMode.Rectangle;
                    entity.BoundingRectangle = new Rectangle(0, 0, 16, 16);
                    entity.Width = 16;
                    entity.Height = 16;
                    entity.Name = Path.GetFileNameWithoutExtension(objectURL);

                    ScriptProcess process = new ScriptProcess(VirtualMachine.GlobalInstance, reader);
                    process.Url = objectURL;
                    if (process.DefaultEditorState != null)
                        process.ChangeState(process.DefaultEditorState.Identifier);
                    else
                        process.State = null;
                    scriptedEntity.ScriptProcess = process;

                    // Are we allowed to place the entity?
                    bool canPlace = true;
                    string placeError = "This entity has been flagged as unplaceable. Please choose another or check this objects script.";
                    foreach (Define define in process.Defines)
                    {
                        switch (define.Ident.ToUpper())
                        {
                            case "UNPLACEABLE":
                                canPlace = false;
                                break;
                            case "UNPLACEABLE_ERROR":
                                placeError = define.Value;
                                break;
                        }
                    }
                    if (canPlace == false)
                    {
                        MessageBox.Show(placeError, "Unplaceable", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }

                    Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity);

                    // Invoke OnCreate event.
                    scriptedEntity.ScriptProcess[0].InvokeFunction("OnCreate", true, false);

                    // Free up the streams.
                    memStream.Close();
                    reader.Close();
                    writer.Close();
                }
            }

            // Its built in so create the object requested.
            else
            {
                switch (objectURL.ToLower())
                {
                    case "tilemap segment":
                        TilemapSegmentNode segment = new TilemapSegmentNode(8, 8, 16, 16);
                        Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(segment);
                        segment.IsGridVisible = true;
                        entity = segment;
                        break;

                    case "emitter":
                        entity = new EmitterNode();
                        Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity);
                        entity.BoundingRectangle = new Rectangle(0, 0, 16, 16);
                        entity.Width = 16;
                        entity.Height = 16;
                        break;

                    case "entity":
                        entity = new EntityNode();
                        Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity);
                        entity.BoundingRectangle = new Rectangle(0, 0, 16, 16);
                        entity.Width = 16;
                        entity.Height = 16;
                        break;

                    case "path marker":
                        entity = new PathMarkerNode();
                        Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity);
                        entity.BoundingRectangle = new Rectangle(0, 0, 16, 16);
                        entity.Width = 16;
                        entity.Height = 16;
                        entity.Image = _pathMarkerImage;
                        entity.RenderMode = EntityRenderMode.Image;
                        entity.Name = "Path Marker " + MathMethods.Random(MathMethods.Random(0, 10000), MathMethods.Random(10000, 10000000));

                        foreach (EntityNode selEntity in _selectedEntityList)
                            if (selEntity is PathMarkerNode && ((PathMarkerNode)selEntity).NextNodeName == "")
                            {
                                ((PathMarkerNode)selEntity).NextNode = (PathMarkerNode)entity;
                                ((PathMarkerNode)selEntity).NextNodeName = entity.Name;
                            }

                        break;
                }
            }

            if (entity == null) return;

            // Find the correct position for our new entity.
            int mapX, mapY;
            if (inCenter == false)
            {
                mapX = (int)Editor.GlobalInstance.CameraNode.Transformation.X + (int)((mousePositionBeforeRightClick[0] / Editor.GlobalInstance.CameraNode.Zoom));
                mapY = (int)Editor.GlobalInstance.CameraNode.Transformation.Y + (int)((mousePositionBeforeRightClick[1] / Editor.GlobalInstance.CameraNode.Zoom));
            }
            else
            {
                mapX = (int)Editor.GlobalInstance.CameraNode.Transformation.X + (int)(((mapPanel.ClientSize.Width - entity.BoundingRectangle.Width) / 2) / Editor.GlobalInstance.CameraNode.Zoom);
                mapY = (int)Editor.GlobalInstance.CameraNode.Transformation.Y + (int)(((mapPanel.ClientSize.Height - entity.BoundingRectangle.Height) / 2) / Editor.GlobalInstance.CameraNode.Zoom);
            }

            if (_snapToGrid == true)
            {
                mapX = (mapX / _gridWidth) * _gridWidth;
                mapY = (mapY / _gridHeight) * _gridHeight;
            }

            entity.Position(mapX, mapY, 0.0f);
            entity.IsBoundingBoxVisible = _viewBoundingBoxs;
            entity.IsEventLinesVisible = _viewEventLines;
            entity.IsCollisionBoxVisible = _viewCollisionBoxs;
            entity.ForceVisibility = true;

            ClearSelection();
            AddEntityToSelection(entity);

            // Update the scene graph window if it exists.
            if (_sceneGraphWindow != null) _sceneGraphWindow.SyncronizeData();

            // Update this entitys event nodes and the event nodes of others.
            foreach (SceneNode node in Engine.Engine.GlobalInstance.Map.SceneGraph.EnumerateNodes())
            {
                EntityNode subNode = node as EntityNode;
                if (subNode == null) continue;
                if (subNode.Event.ToLower() == entity.Name.ToString().ToLower()) subNode.EventNodes.Add(entity);
            }

            PushUndoOperation(new InsertNodesUndoOperation(new SceneNode[] { entity }));
            SyncronizeWindow();

            _mapChangedSinceSave = true;
        }
Example #4
0
 public void CreateTilemap(ScriptThread thread)
 {
     EntityNode node = new TilemapSegmentNode();
     thread.SetReturnValue(new SceneNodeScriptObject(node));
 }