コード例 #1
0
        static void CopyCallback([NotNull] Player player, [NotNull] Vector3I[] marks, [NotNull] object tag)
        {
            int         sx     = Math.Min(marks[0].X, marks[1].X);
            int         ex     = Math.Max(marks[0].X, marks[1].X);
            int         sy     = Math.Min(marks[0].Y, marks[1].Y);
            int         ey     = Math.Max(marks[0].Y, marks[1].Y);
            int         sz     = Math.Min(marks[0].Z, marks[1].Z);
            int         ez     = Math.Max(marks[0].Z, marks[1].Z);
            BoundingBox bounds = new BoundingBox(sx, sy, sz, ex, ey, ez);

            int volume = bounds.Volume;

            if (!player.CanDraw(volume))
            {
                player.MessageNow(
                    "You are only allowed to run commands that affect up to {0} blocks. This one would affect {1} blocks.",
                    player.Info.Rank.DrawLimit,
                    volume);
                return;
            }

            // remember dimensions and orientation
            CopyState copyInfo = new CopyState(marks[0], marks[1]);

            Map   map         = player.WorldMap;
            World playerWorld = player.World;

            if (playerWorld == null)
            {
                PlayerOpException.ThrowNoWorld(player);
            }

            for (int x = sx; x <= ex; x++)
            {
                for (int y = sy; y <= ey; y++)
                {
                    for (int z = sz; z <= ez; z++)
                    {
                        copyInfo.Blocks[x - sx, y - sy, z - sz] = map.GetBlock(x, y, z);
                    }
                }
            }

            copyInfo.OriginWorld = playerWorld.Name;
            copyInfo.CopyTime    = DateTime.UtcNow;
            player.SetCopyState(copyInfo);

            player.MessageNow("{0} blocks copied into slot #{1}, origin at {2} corner. You can now &H/Paste",
                              volume,
                              player.CopySlot + 1,
                              copyInfo.OriginCorner);

            Logger.Log(LogType.UserActivity,
                       "{0} copied {1} blocks from world {2} (between {3} and {4}).",
                       player.Name,
                       volume,
                       playerWorld.Name,
                       bounds.MinVertex,
                       bounds.MaxVertex);
        }
コード例 #2
0
ファイル: BitmapDrawOp.cs プロジェクト: takaaptech/ProCraft
        public void Draw(Bitmap img)
        {
            //guess how big the draw will be
            int white = System.Drawing.Color.White.ToArgb();
            int left, right, top, bottom;
            int count = Crop(img, out left, out right, out top, out bottom);

            //check if player can make the drawing
            if (!player.CanDraw(count))
            {
                player.Message(String.Format("You are only allowed to run commands that affect up to {0} blocks. " +
                                             "This one would affect {1} blocks.",
                                             player.Info.Rank.DrawLimit, count));
                return;
            }

            int dirX = 0, dirY = 0;

            if (direction == Direction.PlusX)
            {
                dirX = 1;
            }
            if (direction == Direction.MinusX)
            {
                dirX = -1;
            }
            if (direction == Direction.PlusZ)
            {
                dirY = 1;
            }
            if (direction == Direction.MinusZ)
            {
                dirY = -1;
            }
            if (dirX == 0 && dirY == 0)
            {
                return;                         //if blockcount = 0, message is shown and returned
            }
            for (int yy = top; yy <= bottom; yy++)
            {
                for (int xx = left; xx <= right; xx++)
                {
                    if (img.GetPixel(xx, yy).ToArgb() == white)
                    {
                        continue;
                    }
                    int dx = xx - left, dy = bottom - yy;

                    Vector3I coords = new Vector3I(origin.X + dirX * dx, origin.Y + dirY * dx, origin.Z + dy);
                    BuildingCommands.DrawOneBlock(
                        player, player.World.Map, blockColor,
                        coords, BlockChangeContext.Drawn,
                        ref blocks, ref blocksDenied, undoState);
                    blockCount++;
                }
            }
        }
コード例 #3
0
ファイル: MathCommands.cs プロジェクト: mstefarov/800craft
        private static void DrawOperationCallback(Player player, Vector3I[] marks, object tag)
        {
            DrawOperation operation = ( DrawOperation )tag;

            if (operation.Prepare(marks))
            {
                if (!player.CanDraw(operation.BlocksTotalEstimate))
                {
                    player.Message("You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.", new object[] { player.Info.Rank.DrawLimit, operation.Bounds.Volume });
                    operation.Cancel();
                }
                else
                {
                    player.Message("{0}: Processing ~{1} blocks.", new object[] { operation.Description, operation.BlocksTotalEstimate });
                    operation.Begin();
                }
            }
        }
コード例 #4
0
ファイル: WorldCommands.cs プロジェクト: Rhinovex/LegendCraft
        static void PortalCreateCallback(Player player, Vector3I[] marks, object tag)
        {
            try
            {
                World world = WorldManager.FindWorldExact(player.PortalWorld);

                if (world != null)
                {
                    DrawOperation op = (DrawOperation)tag;
                    if (!op.Prepare(marks)) return;
                    if (!player.CanDraw(op.BlocksTotalEstimate))
                    {
                        player.MessageNow("You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                           player.Info.Rank.DrawLimit,
                                           op.Bounds.Volume);
                        op.Cancel();
                        return;
                    }

                    int Xmin = Math.Min(marks[0].X, marks[1].X);
                    int Xmax = Math.Max(marks[0].X, marks[1].X);
                    int Ymin = Math.Min(marks[0].Y, marks[1].Y);
                    int Ymax = Math.Max(marks[0].Y, marks[1].Y);
                    int Zmin = Math.Min(marks[0].Z, marks[1].Z);
                    int Zmax = Math.Max(marks[0].Z, marks[1].Z);

                    for (int x = Xmin; x <= Xmax; x++)
                    {
                        for (int y = Ymin; y <= Ymax; y++)
                        {
                            for (int z = Zmin; z <= Zmax; z++)
                            {
                                if (PortalHandler.IsInRangeOfSpawnpoint(player.World, new Vector3I(x, y, z)))
                                {
                                    player.Message("You can not build a portal near a spawnpoint.");
                                    return;
                                }

                                if (PortalHandler.GetInstance().GetPortal(player.World, new Vector3I(x, y, z)) != null)
                                {
                                    player.Message("You can not build a portal inside a portal, U MAD BRO?");
                                    return;
                                }
                            }
                        }
                    }

                    if (player.PortalName == null)
                    {
                        player.PortalName = Portal.GenerateName(player.World);
                    }

                    Portal portal = new Portal(player.PortalWorld, marks, player.PortalName, player.Name, player.World.Name);
                    PortalHandler.CreatePortal(portal, player.World);
                    op.AnnounceCompletion = false;
                    op.Context = BlockChangeContext.Portal;
                    op.Begin();

                    player.Message("Successfully created portal with name " + portal.Name + ".");
                }
                else
                {
                    player.MessageInvalidWorldName(player.PortalWorld);
                }
            }
            catch (Exception ex)
            {
                player.Message("Failed to create portal.");
                Logger.Log(LogType.Error, "WorldCommands.PortalCreateCallback: " + ex);
            }
        }
コード例 #5
0
ファイル: MathCommands.cs プロジェクト: Rhinovex/LegendCraft
 private static void DrawOperationCallback(Player player, Vector3I[] marks, object tag)
 {
     DrawOperation operation = (DrawOperation)tag;
     if (operation.Prepare(marks))
     {
         if (!player.CanDraw(operation.BlocksTotalEstimate))
         {
             player.Message("You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.", new object[] { player.Info.Rank.DrawLimit, operation.Bounds.Volume });
             operation.Cancel();
         }
         else
         {
             player.Message("{0}: Processing ~{1} blocks.", new object[] { operation.Description, operation.BlocksTotalEstimate });
             operation.Begin();
         }
     }
 }
コード例 #6
0
ファイル: BuildingCommands.cs プロジェクト: 727021/800craft
        static void TreeHandler( Player player, Command cmd )
        {
            string shapeName = cmd.Next();
            int height;
            Forester.TreeShape shape;

            // that's one ugly if statement... does the job though.
            if ( shapeName == null ||
                !cmd.NextInt( out height ) ||
                !EnumUtil.TryParse( shapeName, out shape, true ) ||
                shape == Forester.TreeShape.Stickly ||
                shape == Forester.TreeShape.Procedural ) {
                CdTree.PrintUsage( player );
                player.Message( "Available shapes: Normal, Bamboo, Palm, Cone, Round, Rainforest, Mangrove." );
                return;
            }

            if ( height < 6 || height > 1024 ) {
                player.Message( "Tree height must be 6 blocks or above" );
                return;
            }
            int volume = ( int )Math.Pow( height, 3 );
            if ( !player.CanDraw( volume ) ) {
                player.Message( String.Format( "You are only allowed to run commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                               player.Info.Rank.DrawLimit, volume ) );
                return;
            }

            Map map = player.World.Map;

            ForesterArgs args = new ForesterArgs {
                Height = height - 1,
                Operation = Forester.ForesterOperation.Add,
                Map = map,
                Shape = shape,
                TreeCount = 1,
                RootButtresses = false,
                Roots = Forester.RootMode.None,
                Rand = new Random()
            };
            player.SelectionStart( 1, TreeCallback, args, CdTree.Permissions );
            player.MessageNow( "Tree: Place a block or type /Mark to use your location." );
        }
コード例 #7
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        /*
        internal static void EllipsoidHollowCallback( Player player, Position[] marks, object tag ) {
            byte drawBlock = (byte)tag;
            if( drawBlock == (byte)Block.Undefined ) {
                drawBlock = (byte)player.LastUsedBlockType;
            }

            // find start/end coordinates
            int sx = Math.Min( marks[0].X, marks[1].X );
            int ex = Math.Max( marks[0].X, marks[1].X );
            int sy = Math.Min( marks[0].Y, marks[1].Y );
            int ey = Math.Max( marks[0].Y, marks[1].Y );
            int sh = Math.Min( marks[0].H, marks[1].H );
            int eh = Math.Max( marks[0].H, marks[1].H );

            // find axis lengths
            double rx = (ex - sx + 1) / 2d;
            double ry = (ey - sy + 1) / 2d;
            double rh = (eh - sh + 1) / 2d;

            double rx2 = 1 / (rx * rx);
            double ry2 = 1 / (ry * ry);
            double rh2 = 1 / (rh * rh);

            // find center points
            double cx = (ex + sx) / 2d;
            double cy = (ey + sy) / 2d;
            double ch = (eh + sh) / 2d;

            // rougher estimation than the non-hollow form, a voxelized surface is a bit funky
            int volume = (int)(4 / 3d * Math.PI * ((rx + .5) * (ry + .5) * (rh + .5) - (rx - .5) * (ry - .5) * (rh - .5)) * 0.85);
            if( !player.CanDraw( volume ) ) {
                player.MessageNow( "You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                   player.Info.Rank.DrawLimit,
                                   volume );
                return;
            }

            player.UndoBuffer.Clear();

            int blocks = 0, blocksDenied = 0;
            bool cannotUndo = false;

            for( int x = sx; x <= ex; x++ ) {
                for( int y = sy; y <= ey; y++ ) {
                    for( int h = sh; h <= eh; h++ ) {

                        double dx = (x - cx);
                        double dy = (y - cy);
                        double dh = (h - ch);

                        if( (dx * dx) * rx2 + (dy * dy) * ry2 + (dh * dh) * rh2 <= 1 ) {
                            // we touched the surface
                            // keep drilling until we hit an internal block
                            do {
                                DrawOneBlock( player, drawBlock, x, y, h, ref blocks, ref blocksDenied, ref cannotUndo );
                                DrawOneBlock( player, drawBlock, x, y, (int)(ch - dh), ref blocks, ref blocksDenied, ref cannotUndo );
                                dh = (++h - ch);
                            } while( h <= (int)ch &&
                                    ((dx + 1) * (dx + 1) * rx2 + (dy * dy) * ry2 + (dh * dh) * rh2 > 1 ||
                                     (dx - 1) * (dx - 1) * rx2 + (dy * dy) * ry2 + (dh * dh) * rh2 > 1 ||
                                     (dx * dx) * rx2 + (dy + 1) * (dy + 1) * ry2 + (dh * dh) * rh2 > 1 ||
                                     (dx * dx) * rx2 + (dy - 1) * (dy - 1) * ry2 + (dh * dh) * rh2 > 1 ||
                                     (dx * dx) * rx2 + (dy * dy) * ry2 + (dh + 1) * (dh + 1) * rh2 > 1 ||
                                     (dx * dx) * rx2 + (dy * dy) * ry2 + (dh - 1) * (dh - 1) * rh2 > 1) );
                            break;
                        }
                    }
                }
            }
            Logger.Log( "{0} drew a hollow ellipsoid containing {1} blocks of type {2} (on world {3})", LogType.UserActivity,
                        player.Name,
                        blocks,
                        (Block)drawBlock,
                        player.World.Name );
            DrawingFinished( player, "drawn", blocks, blocksDenied );
        }
        */

        internal static void EllipsoidHollowCallback( Player player, Position[] marks, object tag ) {

            HollowShapeArgs args = (HollowShapeArgs)tag;
            byte drawBlock = (byte)args.OuterBlock;
            if( drawBlock == (byte)Block.Undefined ) {
                drawBlock = (byte)player.GetBind( player.LastUsedBlockType );
            }

            // find start/end coordinates
            int sx = Math.Min( marks[0].X, marks[1].X );
            int ex = Math.Max( marks[0].X, marks[1].X );
            int sy = Math.Min( marks[0].Y, marks[1].Y );
            int ey = Math.Max( marks[0].Y, marks[1].Y );
            int sh = Math.Min( marks[0].H, marks[1].H );
            int eh = Math.Max( marks[0].H, marks[1].H );

            bool fillInner = (args.InnerBlock != Block.Undefined && (ex - sx) > 1 && (ey - sy) > 1 && (eh - sh) > 1);

            // find axis lengths
            double rx = (ex - sx + 1) / 2d;
            double ry = (ey - sy + 1) / 2d;
            double rh = (eh - sh + 1) / 2d;

            double rx2 = 1 / (rx * rx);
            double ry2 = 1 / (ry * ry);
            double rh2 = 1 / (rh * rh);

            // find center points
            double cx = (ex + sx) / 2d;
            double cy = (ey + sy) / 2d;
            double ch = (eh + sh) / 2d;

            int volume;
            if( fillInner ) {
                volume = (int)(4 / 3d * Math.PI * rx * ry * rh);
            } else {
                // rougher estimation than the non-hollow form, a voxelized surface is a bit funky
                volume = (int)(4 / 3d * Math.PI * ((rx + .5) * (ry + .5) * (rh + .5) - (rx - .5) * (ry - .5) * (rh - .5)) * 0.85);
            }

            if( !player.CanDraw( volume ) ) {
                player.MessageNow( "You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                   player.Info.Rank.DrawLimit,
                                   volume );
                return;
            }

            player.UndoBuffer.Clear();

            int blocks = 0, blocksDenied = 0;
            bool cannotUndo = false;

            for( int x = sx; x <= ex; x++ ) {
                for( int y = sy; y <= ey; y++ ) {
                    for( int h = sh; h <= eh; h++ ) {

                        double dx = (x - cx);
                        double dy = (y - cy);
                        double dh = (h - ch);

                        if( (dx * dx) * rx2 + (dy * dy) * ry2 + (dh * dh) * rh2 > 1 ) continue;

                        // we touched the surface
                        // keep drilling until we hit an internal block
                        do {
                            DrawOneBlock( player, drawBlock, x, y, h, ref blocks, ref blocksDenied, ref cannotUndo );
                            DrawOneBlock( player, drawBlock, x, y, (int)(ch - dh), ref blocks, ref blocksDenied, ref cannotUndo );
                            dh = (++h - ch);
                        } while( h <= (int)ch &&
                                 ((dx + 1) * (dx + 1) * rx2 + (dy * dy) * ry2 + (dh * dh) * rh2 > 1 ||
                                  (dx - 1) * (dx - 1) * rx2 + (dy * dy) * ry2 + (dh * dh) * rh2 > 1 ||
                                  (dx * dx) * rx2 + (dy + 1) * (dy + 1) * ry2 + (dh * dh) * rh2 > 1 ||
                                  (dx * dx) * rx2 + (dy - 1) * (dy - 1) * ry2 + (dh * dh) * rh2 > 1 ||
                                  (dx * dx) * rx2 + (dy * dy) * ry2 + (dh + 1) * (dh + 1) * rh2 > 1 ||
                                  (dx * dx) * rx2 + (dy * dy) * ry2 + (dh - 1) * (dh - 1) * rh2 > 1)
                            );
                        if( fillInner ) {
                            for( ; h <= (int)(ch - dh); h++ ) {
                                DrawOneBlock( player, (byte)args.InnerBlock, x, y, h, ref blocks, ref blocksDenied, ref cannotUndo );
                            }
                        }
                        break;
                    }
                }
            }
            Logger.Log( "{0} drew a hollow ellipsoid containing {1} blocks of type {2} (on world {3})", LogType.UserActivity,
                        player.Name,
                        blocks,
                        (Block)drawBlock,
                        player.World.Name );
            DrawingFinished( player, "drawn", blocks, blocksDenied );
        }
コード例 #8
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
 static void DrawOperationCallback( Player player, Vector3I[] marks, object tag ) {
     DrawOperation op = (DrawOperation)tag;
     if( !op.Prepare( marks ) ) return;
     if( !player.CanDraw( op.BlocksTotalEstimate ) ) {
         player.MessageNow( "You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.",
                            player.Info.Rank.DrawLimit,
                            op.Bounds.Volume );
         op.Cancel();
         return;
     }
     player.Message( "{0}: Processing ~{1} blocks.",
                     op.Description, op.BlocksTotalEstimate );
     op.Begin();
 }
コード例 #9
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        unsafe internal static void ReplaceCallback( Player player, Position[] marks, object drawArgs ) {
            ReplaceArgs args = (ReplaceArgs)drawArgs;

            byte* specialTypes = stackalloc byte[args.Types.Length];
            int specialTypeCount = args.Types.Length;
            for( int i = 0; i < args.Types.Length; i++ ) {
                specialTypes[i] = (byte)args.Types[i];
            }

            bool doExclude = args.DoExclude;

            // find start/end coordinates
            int sx = Math.Min( marks[0].X, marks[1].X );
            int ex = Math.Max( marks[0].X, marks[1].X );
            int sy = Math.Min( marks[0].Y, marks[1].Y );
            int ey = Math.Max( marks[0].Y, marks[1].Y );
            int sh = Math.Min( marks[0].H, marks[1].H );
            int eh = Math.Max( marks[0].H, marks[1].H );

            int volume = (ex - sx + 1) * (ey - sy + 1) * (eh - sh + 1);
            if( !player.CanDraw( volume ) ) {
                player.MessageNow( "You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                    player.Info.Rank.DrawLimit,
                                    volume );
                return;
            }

            player.UndoBuffer.Clear();

            bool cannotUndo = false;
            int blocks = 0, blocksDenied = 0;
            for( int x = sx; x <= ex; x += DrawStride ) {
                for( int y = sy; y <= ey; y += DrawStride ) {
                    for( int h = sh; h <= eh; h++ ) {
                        for( int y3 = 0; y3 < DrawStride && y + y3 <= ey; y3++ ) {
                            for( int x3 = 0; x3 < DrawStride && x + x3 <= ex; x3++ ) {

                                byte block = player.World.Map.GetBlockByte( x + x3, y + y3, h );

                                bool skip = !args.DoExclude;
                                for( int i = 0; i < specialTypeCount; i++ ) {
                                    if( block == specialTypes[i] ) {
                                        skip = args.DoExclude;
                                        break;
                                    }
                                }
                                if( skip ) continue;

                                if( player.CanPlace( x + x3, y + y3, h, args.ReplacementBlock, false ) != CanPlaceResult.Allowed ) {
                                    blocksDenied++;
                                    continue;
                                }
                                player.World.Map.QueueUpdate( new BlockUpdate( null, x + x3, y + y3, h, args.ReplacementBlock ) );
                                Server.RaisePlayerPlacedBlockEvent( player, (short)x, (short)y, (short)h, (Block)block, args.ReplacementBlock, false );
                                if( blocks < MaxUndoCount ) {
                                    player.UndoBuffer.Enqueue( new BlockUpdate( null, x + x3, y + y3, h, block ) );
                                } else if( !cannotUndo ) {
                                    player.UndoBuffer.Clear();
                                    player.UndoBuffer.TrimExcess();
                                    player.MessageNow( "NOTE: This draw command is too massive to undo." );
                                    cannotUndo = true;
                                    if( player.Can( Permission.ManageWorlds ) ) {
                                        player.MessageNow( "Reminder: You can use &H/wflush&S to accelerate draw commands." );
                                    }
                                }
                                blocks++;

                            }
                        }
                    }
                }
            }


            Logger.Log( "{0} replaced {1} blocks {2} ({3}) with {4} (on world {5})", LogType.UserActivity,
                        player.Name,
                        blocks,
                        (doExclude ? "except" : "of"),
                        args.Types.JoinToString(),
                        args.ReplacementBlock,
                        player.World.Name );

            DrawingFinished( player, "replaced", blocks, blocksDenied );
        }
コード例 #10
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        internal static void CuboidHollowCallback( Player player, Position[] marks, object tag ) {
            HollowShapeArgs args = (HollowShapeArgs)tag;
            byte drawBlock = (byte)args.OuterBlock;
            if( drawBlock == (byte)Block.Undefined ) {
                drawBlock = (byte)player.GetBind( player.LastUsedBlockType );
            }

            // find start/end coordinates
            int sx = Math.Min( marks[0].X, marks[1].X );
            int ex = Math.Max( marks[0].X, marks[1].X );
            int sy = Math.Min( marks[0].Y, marks[1].Y );
            int ey = Math.Max( marks[0].Y, marks[1].Y );
            int sh = Math.Min( marks[0].H, marks[1].H );
            int eh = Math.Max( marks[0].H, marks[1].H );

            bool fillInner = (args.InnerBlock != Block.Undefined && (ex - sx) > 1 && (ey - sy) > 1 && (eh - sh) > 1);


            int volume = (ex - sx + 1) * (ey - sy + 1) * (eh - sh + 1);
            if( !fillInner ) {
                volume -= (ex - sx - 1) * (ey - sy - 1) * (eh - sh - 1);
            }

            if( !player.CanDraw( volume ) ) {
                player.MessageNow( "You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                   player.Info.Rank.DrawLimit,
                                   volume );
                return;
            }

            player.UndoBuffer.Clear();

            int blocks = 0, blocksDenied = 0;
            bool cannotUndo = false;

            for( int x = sx; x <= ex; x++ ) {
                for( int y = sy; y <= ey; y++ ) {
                    DrawOneBlock( player, drawBlock, x, y, sh, ref blocks, ref blocksDenied, ref cannotUndo );
                    DrawOneBlock( player, drawBlock, x, y, eh, ref blocks, ref blocksDenied, ref cannotUndo );
                }
            }
            for( int x = sx; x <= ex; x++ ) {
                for( int h = sh; h <= eh; h++ ) {
                    DrawOneBlock( player, drawBlock, x, sy, h, ref blocks, ref blocksDenied, ref cannotUndo );
                    DrawOneBlock( player, drawBlock, x, ey, h, ref blocks, ref blocksDenied, ref cannotUndo );
                }
            }
            for( int y = sy; y <= ey; y++ ) {
                for( int h = sh; h <= eh; h++ ) {
                    DrawOneBlock( player, drawBlock, sx, y, h, ref blocks, ref blocksDenied, ref cannotUndo );
                    DrawOneBlock( player, drawBlock, ex, y, h, ref blocks, ref blocksDenied, ref cannotUndo );
                }
            }

            if( fillInner ) {
                for( int x = sx + 1; x < ex; x += DrawStride ) {
                    for( int y = sy + 1; y < ey; y += DrawStride ) {
                        for( int h = sh + 1; h < eh; h++ ) {
                            for( int y3 = 0; y3 < DrawStride && y + y3 < ey; y3++ ) {
                                for( int x3 = 0; x3 < DrawStride && x + x3 < ex; x3++ ) {
                                    DrawOneBlock( player, (byte)args.InnerBlock, x + x3, y + y3, h, ref blocks, ref blocksDenied, ref cannotUndo );
                                }
                            }
                        }
                    }
                }
            }

            Logger.Log( "{0} drew a hollow cuboid containing {1} blocks of type {2} (on world {3})", LogType.UserActivity,
                        player.Name,
                        blocks,
                        (Block)drawBlock,
                        player.World.Name );
            DrawingFinished( player, "drawn", blocks, blocksDenied );
        }
コード例 #11
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        internal static void CuboidWireframeCallback( Player player, Position[] marks, object tag ) {
            byte drawBlock = (byte)tag;
            if( drawBlock == (byte)Block.Undefined ) {
                drawBlock = (byte)player.GetBind( player.LastUsedBlockType );
            }

            // find start/end coordinates
            int sx = Math.Min( marks[0].X, marks[1].X );
            int ex = Math.Max( marks[0].X, marks[1].X );
            int sy = Math.Min( marks[0].Y, marks[1].Y );
            int ey = Math.Max( marks[0].Y, marks[1].Y );
            int sh = Math.Min( marks[0].H, marks[1].H );
            int eh = Math.Max( marks[0].H, marks[1].H );

            // Calculate the upper limit on the volume
            int solidVolume = (ex - sx + 1) *  (ey - sy + 1) *  (eh - sh + 1);
            int hollowVolume = Math.Max( 0, ex - sx - 1 ) * Math.Max( 0, ey - sy - 1 ) * Math.Max( 0, eh - sh - 1 );
            int sideVolume = Math.Max( 0, ex - sx - 1 ) * Math.Max( 0, ey - sy - 1 ) * (ex != sx ? 2 : 1) +
                             Math.Max( 0, ey - sy - 1 ) * Math.Max( 0, eh - sh - 1 ) * (ey != sy ? 2 : 1) +
                             Math.Max( 0, eh - sh - 1 ) * Math.Max( 0, ex - sx - 1 ) * (eh != sh ? 2 : 1);
            int volume = solidVolume - hollowVolume - sideVolume;

            if( !player.CanDraw( volume ) ) {
                player.MessageNow( "You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                   player.Info.Rank.DrawLimit,
                                   volume );
                return;
            }

            player.UndoBuffer.Clear();

            int blocks = 0, blocksDenied = 0;
            bool cannotUndo = false;

            // Draw cuboid vertices
            DrawOneBlock( player, drawBlock, sx, sy, sh, ref blocks, ref blocksDenied, ref cannotUndo );
            if( sx != ex ) DrawOneBlock( player, drawBlock, ex, sy, sh, ref blocks, ref blocksDenied, ref cannotUndo );
            if( sy != ey ) DrawOneBlock( player, drawBlock, sx, ey, sh, ref blocks, ref blocksDenied, ref cannotUndo );
            if( sx != ex && sy != ey ) DrawOneBlock( player, drawBlock, ex, ey, sh, ref blocks, ref blocksDenied, ref cannotUndo );
            if( sh != eh ) DrawOneBlock( player, drawBlock, sx, sy, eh, ref blocks, ref blocksDenied, ref cannotUndo );
            if( sx != ex && sh != eh ) DrawOneBlock( player, drawBlock, ex, sy, eh, ref blocks, ref blocksDenied, ref cannotUndo );
            if( sy != ey && sh != eh ) DrawOneBlock( player, drawBlock, sx, ey, eh, ref blocks, ref blocksDenied, ref cannotUndo );
            if( sx != ex && sy != ey && sh != eh ) DrawOneBlock( player, drawBlock, ex, ey, eh, ref blocks, ref blocksDenied, ref cannotUndo );

            // Draw edges along the X axis
            if( ex - sx > 1 ) {
                for( int x = sx + 1; x < ex; x++ ) {
                    DrawOneBlock( player, drawBlock, x, sy, sh, ref blocks, ref blocksDenied, ref cannotUndo );
                    if( sh != eh ) DrawOneBlock( player, drawBlock, x, sy, eh, ref blocks, ref blocksDenied, ref cannotUndo );
                    if( sy != ey ) {
                        DrawOneBlock( player, drawBlock, x, ey, sh, ref blocks, ref blocksDenied, ref cannotUndo );
                        if( sh != eh ) DrawOneBlock( player, drawBlock, x, ey, eh, ref blocks, ref blocksDenied, ref cannotUndo );
                    }
                }
            }

            // Draw edges along the Y axis
            if( ey - sy > 1 ) {
                for( int y = sy + 1; y < ey; y++ ) {
                    DrawOneBlock( player, drawBlock, sx, y, sh, ref blocks, ref blocksDenied, ref cannotUndo );
                    if( sh != eh ) DrawOneBlock( player, drawBlock, sx, y, eh, ref blocks, ref blocksDenied, ref cannotUndo );
                    if( sx != ex ) {
                        DrawOneBlock( player, drawBlock, ex, y, sh, ref blocks, ref blocksDenied, ref cannotUndo );
                        if( sh != eh ) DrawOneBlock( player, drawBlock, ex, y, eh, ref blocks, ref blocksDenied, ref cannotUndo );
                    }
                }
            }

            // Draw edges along the H axis
            if( eh - sh > 1 ) {
                for( int h = sh + 1; h < eh; h++ ) {
                    DrawOneBlock( player, drawBlock, sx, sy, h, ref blocks, ref blocksDenied, ref cannotUndo );
                    if( sy != ey ) DrawOneBlock( player, drawBlock, sx, ey, h, ref blocks, ref blocksDenied, ref cannotUndo );
                    if( sx != ex ) {
                        DrawOneBlock( player, drawBlock, ex, ey, h, ref blocks, ref blocksDenied, ref cannotUndo );
                        if( sy != ey ) DrawOneBlock( player, drawBlock, ex, sy, h, ref blocks, ref blocksDenied, ref cannotUndo );
                    }
                }
            }

            Logger.Log( "{0} drew a wireframe cuboid containing {1} blocks of type {2} (on world {3})", LogType.UserActivity,
                        player.Name,
                        blocks,
                        (Block)drawBlock,
                        player.World.Name );
            DrawingFinished( player, "drawn", blocks, blocksDenied );
        }
コード例 #12
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        unsafe internal static void PasteCallback( Player player, Position[] marks, object tag ) {
            CopyInformation info = player.CopyInformation;

            PasteArgs args = (PasteArgs)tag;
            byte* specialTypes = stackalloc byte[args.BlockTypes.Length];
            int specialTypeCount = args.BlockTypes.Length;
            for( int i = 0; i < args.BlockTypes.Length; i++ ) {
                specialTypes[i] = (byte)args.BlockTypes[i];
            }
            Map map = player.World.Map;

            BoundingBox bounds = new BoundingBox( marks[0], info.WidthX, info.WidthY, info.Height );

            int pasteVolume = bounds.GetIntersection( map.Bounds ).Volume;
            if( !player.CanDraw( pasteVolume ) ) {
                player.MessageNow( "You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                   player.Info.Rank.DrawLimit,
                                   pasteVolume );
                return;
            }

            if( bounds.XMin < 0 || bounds.XMax > map.WidthX - 1 ) {
                player.MessageNow( "Warning: Not enough room horizontally (X), paste cut off." );
            }
            if( bounds.YMin < 0 || bounds.YMax > map.WidthY - 1 ) {
                player.MessageNow( "Warning: Not enough room horizontally (Y), paste cut off." );
            }
            if( bounds.HMin < 0 || bounds.HMax > map.Height - 1 ) {
                player.MessageNow( "Warning: Not enough room vertically, paste cut off." );
            }

            player.UndoBuffer.Clear();

            int blocks = 0, blocksDenied = 0;
            bool cannotUndo = false;

            for( int x = bounds.XMin; x <= bounds.XMax; x += DrawStride ) {
                for( int y = bounds.YMin; y <= bounds.YMax; y += DrawStride ) {
                    for( int h = bounds.HMin; h <= bounds.HMax; h++ ) {
                        for( int y3 = 0; y3 < DrawStride && y + y3 <= bounds.YMax; y3++ ) {
                            for( int x3 = 0; x3 < DrawStride && x + x3 <= bounds.XMax; x3++ ) {
                                byte block = info.Buffer[x + x3 - bounds.XMin, y + y3 - bounds.YMin, h - bounds.HMin];

                                if( args.DoInclude ) {
                                    bool skip = true;
                                    for( int i = 0; i < specialTypeCount; i++ ) {
                                        if( block == specialTypes[i] ) {
                                            skip = false;
                                            break;
                                        }
                                    }
                                    if( skip ) continue;
                                } else if( args.DoExclude ) {
                                    bool skip = false;
                                    for( int i = 0; i < specialTypeCount; i++ ) {
                                        if( block == specialTypes[i] ) {
                                            skip = true;
                                            break;
                                        }
                                    }
                                    if( skip ) continue;
                                }
                                DrawOneBlock( player, block, x + x3, y + y3, h, ref blocks, ref blocksDenied, ref cannotUndo );
                            }
                        }
                    }
                }
            }

            Logger.Log( "{0} pasted {1} blocks to {2}.", LogType.UserActivity,
                        player.Name, blocks, player.World.Name );
            DrawingFinished( player, "pasted", blocks, blocksDenied );
        }
コード例 #13
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        internal static void CutCallback( Player player, Position[] marks, object tag ) {
            int sx = Math.Min( marks[0].X, marks[1].X );
            int ex = Math.Max( marks[0].X, marks[1].X );
            int sy = Math.Min( marks[0].Y, marks[1].Y );
            int ey = Math.Max( marks[0].Y, marks[1].Y );
            int sh = Math.Min( marks[0].H, marks[1].H );
            int eh = Math.Max( marks[0].H, marks[1].H );

            byte fillType = (byte)tag;

            int volume = (ex - sx + 1) * (ey - sy + 1) * (eh - sh + 1);
            if( !player.CanDraw( volume ) ) {
                player.MessageNow( String.Format( "You are only allowed to run commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                               player.Info.Rank.DrawLimit, volume ) );
                return;
            }

            // remember dimensions and orientation
            CopyInformation copyInfo = new CopyInformation {
                WidthX = marks[1].X - marks[0].X,
                WidthY = marks[1].Y - marks[0].Y,
                Height = marks[1].H - marks[0].H,
                Buffer = new byte[ex - sx + 1, ey - sy + 1, eh - sh + 1]
            };

            player.UndoBuffer.Clear();
            int blocks = 0, blocksDenied = 0;
            bool cannotUndo = false;

            for( int x = sx; x <= ex; x++ ) {
                for( int y = sy; y <= ey; y++ ) {
                    for( int h = sh; h <= eh; h++ ) {
                        copyInfo.Buffer[x - sx, y - sy, h - sh] = player.World.Map.GetBlockByte( x, y, h );
                        DrawOneBlock( player, fillType, x, y, h, ref blocks, ref blocksDenied, ref cannotUndo );
                    }
                }
            }

            player.CopyInformation = copyInfo;
            player.MessageNow( "{0} blocks were cut. You can now &H/paste", volume );
            player.MessageNow( "Origin at {0} {1}{2} corner.",
                               (copyInfo.Height > 0 ? "bottom" : "top"),
                               (copyInfo.WidthY > 0 ? "south" : "north"),
                               (copyInfo.WidthX > 0 ? "west" : "east") );

            Logger.Log( "{0} cut {1} blocks from {2}, replacing {3} blocks with {4}.", LogType.UserActivity,
                        player.Name, volume, player.World.Name, blocks, (Block)fillType );

            player.UndoBuffer.TrimExcess();
            Server.RequestGC();
        }
コード例 #14
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        internal static void CopyCallback( Player player, Position[] marks, object tag ) {
            int sx = Math.Min( marks[0].X, marks[1].X );
            int ex = Math.Max( marks[0].X, marks[1].X );
            int sy = Math.Min( marks[0].Y, marks[1].Y );
            int ey = Math.Max( marks[0].Y, marks[1].Y );
            int sh = Math.Min( marks[0].H, marks[1].H );
            int eh = Math.Max( marks[0].H, marks[1].H );

            int volume = (ex - sx + 1) * (ey - sy + 1) * (eh - sh + 1);
            if( !player.CanDraw( volume ) ) {
                player.MessageNow( String.Format( "You are only allowed to run commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                               player.Info.Rank.DrawLimit, volume ) );
                return;
            }

            // remember dimensions and orientation
            CopyInformation copyInfo = new CopyInformation {
                WidthX = marks[1].X - marks[0].X,
                WidthY = marks[1].Y - marks[0].Y,
                Height = marks[1].H - marks[0].H,
                Buffer = new byte[ex - sx + 1, ey - sy + 1, eh - sh + 1]
            };

            for( int x = sx; x <= ex; x++ ) {
                for( int y = sy; y <= ey; y++ ) {
                    for( int h = sh; h <= eh; h++ ) {
                        copyInfo.Buffer[x - sx, y - sy, h - sh] = player.World.Map.GetBlockByte( x, y, h );
                    }
                }
            }

            player.CopyInformation = copyInfo;
            player.MessageNow( "{0} blocks were copied. You can now &H/paste", volume );
            player.MessageNow( "Origin at {0} {1}{2} corner.",
                               (copyInfo.Height > 0 ? "bottom" : "top"),
                               (copyInfo.WidthY > 0 ? "south" : "north"),
                               (copyInfo.WidthX > 0 ? "west" : "east") );

            Logger.Log( "{0} copied {1} blocks from {2}.", LogType.UserActivity,
                        player.Name, volume, player.World.Name );
        }
コード例 #15
0
        public void Draw(Bitmap img)
        {
            //guess how big the draw will be
            int Count = 0;

            for (int x = 0; x < img.Width; x++)
            {
                for (int z = 0; z < img.Height; z++)
                {
                    if (img.GetPixel(x, z).ToArgb() != System.Drawing.Color.White.ToArgb())
                    {
                        Count++;
                    }
                }
            }
            //check if player can make the drawing
            if (!player.CanDraw(Count))
            {
                player.MessageNow(
                    String.Format(
                        "You are only allowed to run commands that affect up to {0} blocks. This one would affect {1} blocks.",
                        player.Info.Rank.DrawLimit, Count));
                return;
            }
            //check direction and draw
            switch (direction)
            {
            case Direction.one:
                for (int x = 0; x < img.Width; x++)
                {
                    for (int z = 0; z < img.Height; z++)
                    {
                        if (img.GetPixel(x, z).ToArgb() != System.Drawing.Color.White.ToArgb())
                        {
                            DrawOneBlock(player, player.World.Map, PixelData.BlockColor,
                                         new Vector3I((PixelData.X + x), PixelData.Y, (PixelData.Z + z)),
                                         BlockChangeContext.Drawn,
                                         ref blocks, ref blocksDenied, undoState);
                            blockCount++;
                        }
                    }
                }
                break;

            case Direction.two:
                for (int x = 0; x < img.Width; x++)
                {
                    for (int z = 0; z < img.Height; z++)
                    {
                        if (img.GetPixel(x, z).ToArgb() != System.Drawing.Color.White.ToArgb())
                        {
                            DrawOneBlock(player, player.World.Map, PixelData.BlockColor,
                                         new Vector3I((PixelData.X - x), PixelData.Y, (PixelData.Z + z)),
                                         BlockChangeContext.Drawn,
                                         ref blocks, ref blocksDenied, undoState);
                            blockCount++;
                        }
                    }
                }
                break;

            case Direction.three:
                for (int y = 0; y < img.Width; y++)
                {
                    for (int z = 0; z < img.Height; z++)
                    {
                        if (img.GetPixel(y, z).ToArgb() != System.Drawing.Color.White.ToArgb())
                        {
                            DrawOneBlock(player, player.World.Map, PixelData.BlockColor,
                                         new Vector3I(PixelData.X, (PixelData.Y + y), (PixelData.Z + z)),
                                         BlockChangeContext.Drawn,
                                         ref blocks, ref blocksDenied, undoState);
                            blockCount++;
                        }
                    }
                }
                break;

            case Direction.four:
                for (int y = 0; y < img.Width; y++)
                {
                    for (int z = 0; z < img.Height; z++)
                    {
                        if (img.GetPixel(y, z).ToArgb() != System.Drawing.Color.White.ToArgb())
                        {
                            DrawOneBlock(player, player.World.Map, PixelData.BlockColor,
                                         new Vector3I(PixelData.X, ((PixelData.Y) - y), (PixelData.Z + z)),
                                         BlockChangeContext.Drawn,
                                         ref blocks, ref blocksDenied, undoState);
                            blockCount++;
                        }
                    }
                }
                break;

            default:
                break;     //if blockcount = 0, message is shown and returned
            }
        }
コード例 #16
0
ファイル: BuildingCommands.cs プロジェクト: Magi1053/ProCraft
 private static void DrawImageCallback(Player player, Vector3I[] marks, object tag)
 {
     ImageDrawOperation op = (ImageDrawOperation)tag;
     player.Message("&HDrawImage: Downloading {0}", op.ImageUrl);
     try
     {
         op.Prepare(marks);
         if (!player.CanDraw(op.BlocksTotalEstimate))
         {
             player.Message(
                 "DrawImage: You are only allowed to run commands that affect up to {0} blocks. This one would affect {1} blocks.",
                 player.Info.Rank.DrawLimit,
                 op.BlocksTotalEstimate);
             return;
         }
         op.Begin();
     }
     catch (ArgumentException ex)
     {
         player.Message("&WDrawImage: Error setting up: " + ex.Message);
     }
     catch (Exception ex)
     {
         Logger.Log(LogType.Warning,
                     "{0}: Error downloading image from {1}: {2}",
                     op.Description,
                     op.ImageUrl,
                     ex);
         player.Message("&WDrawImage: Error downloading: " + ex.Message);
     }
 }
コード例 #17
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        static void RestoreCallback( Player player, Vector3I[] marks, object tag ) {
            BoundingBox selection = new BoundingBox( marks[0], marks[1] );
            Map map = (Map)tag;

            if( !player.CanDraw( selection.Volume ) ) {
                player.MessageNow(
                    "You are only allowed to restore up to {0} blocks at a time. This would affect {1} blocks.",
                    player.Info.Rank.DrawLimit,
                    selection.Volume );
                return;
            }

            int blocksDrawn = 0,
                blocksSkipped = 0;
            UndoState undoState = player.DrawBegin( null );

            World playerWorld = player.World;
            if( playerWorld == null ) PlayerOpException.ThrowNoWorld( player );
            Map playerMap = player.WorldMap;
            Vector3I coord = new Vector3I();
            for( coord.X = selection.XMin; coord.X <= selection.XMax; coord.X++ ) {
                for( coord.Y = selection.YMin; coord.Y <= selection.YMax; coord.Y++ ) {
                    for( coord.Z = selection.ZMin; coord.Z <= selection.ZMax; coord.Z++ ) {
                        DrawOneBlock( player, playerMap, map.GetBlock( coord ), coord,
                                      RestoreContext,
                                      ref blocksDrawn, ref blocksSkipped, undoState );
                    }
                }
            }

            Logger.Log( LogType.UserActivity,
                        "{0} restored {1} blocks on world {2} (@{3},{4},{5} - {6},{7},{8}) from file {9}.",
                        player.Name, blocksDrawn,
                        playerWorld.Name,
                        selection.XMin, selection.YMin, selection.ZMin,
                        selection.XMax, selection.YMax, selection.ZMax,
                        map.Metadata["fCraft.Temp", "FileName"] );

            DrawingFinished( player, "Restored", blocksDrawn, blocksSkipped );
        }
コード例 #18
0
ファイル: BuildingCommands.cs プロジェクト: Magi1053/ProCraft
 static void DrawOperationCallback( Player player, Vector3I[] marks, object tag ) {
     DrawOperation op = (DrawOperation)tag;
     if( !op.Prepare( marks ) ) return;
     if( !player.Info.ClassicubeVerified ) {
     	player.Message("As you had an older minecraft.net account, you must have an admin verify your " +
     	               "new classicube.net account actually is you with /verify before you can use drawing commands.");
     	op.Cancel();
     	return;
     }
     if( !player.CanDraw( op.BlocksTotalEstimate ) ) {
         player.Message( "You are only allowed to run draw commands that affect up to &f{0}&s blocks. This one would affect &f{1}&s blocks.",
                            player.Info.Rank.DrawLimit,
                            op.Bounds.Volume );
         op.Cancel();
         return;
     }
     player.Message( "{0}: Processing ~&f{1}&s blocks.",
                     op.Description, op.BlocksTotalEstimate );
     op.Begin();
 }
コード例 #19
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        static void CopyCallback( Player player, Vector3I[] marks, object tag ) {
            int sx = Math.Min( marks[0].X, marks[1].X );
            int ex = Math.Max( marks[0].X, marks[1].X );
            int sy = Math.Min( marks[0].Y, marks[1].Y );
            int ey = Math.Max( marks[0].Y, marks[1].Y );
            int sz = Math.Min( marks[0].Z, marks[1].Z );
            int ez = Math.Max( marks[0].Z, marks[1].Z );
            BoundingBox bounds = new BoundingBox( sx, sy, sz, ex, ey, ez );

            int volume = bounds.Volume;
            if( !player.CanDraw( volume ) ) {
                player.MessageNow( "You are only allowed to run commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                   player.Info.Rank.DrawLimit, volume );
                return;
            }

            // remember dimensions and orientation
            CopyState copyInfo = new CopyState( marks[0], marks[1] );

            Map map = player.WorldMap;
            World playerWorld = player.World;
            if( playerWorld == null ) PlayerOpException.ThrowNoWorld( player );

            for( int x = sx; x <= ex; x++ ) {
                for( int y = sy; y <= ey; y++ ) {
                    for( int z = sz; z <= ez; z++ ) {
                        copyInfo.Blocks[x - sx, y - sy, z - sz] = map.GetBlock( x, y, z );
                    }
                }
            }

            copyInfo.OriginWorld = playerWorld.Name;
            copyInfo.CopyTime = DateTime.UtcNow;
            player.SetCopyState( copyInfo );

            player.MessageNow( "{0} blocks copied into slot #{1}, origin at {2} corner. You can now &H/Paste",
                               volume,
                               player.CopySlot + 1,
                               copyInfo.OriginCorner );

            Logger.Log( LogType.UserActivity,
                        "{0} copied {1} blocks from world {2} (between {3} and {4}).",
                        player.Name, volume, playerWorld.Name,
                        bounds.MinVertex, bounds.MaxVertex );
        }
コード例 #20
0
ファイル: BuildingCommands.cs プロジェクト: fragmer/fCraft
        internal static void EllipsoidCallback( Player player, Position[] marks, object tag ) {
            byte drawBlock = (byte)tag;
            if( drawBlock == (byte)Block.Undefined ) {
                drawBlock = (byte)player.GetBind( player.LastUsedBlockType );
            }

            // find start/end coordinates
            int sx = Math.Min( marks[0].X, marks[1].X );
            int ex = Math.Max( marks[0].X, marks[1].X );
            int sy = Math.Min( marks[0].Y, marks[1].Y );
            int ey = Math.Max( marks[0].Y, marks[1].Y );
            int sh = Math.Min( marks[0].H, marks[1].H );
            int eh = Math.Max( marks[0].H, marks[1].H );

            // find axis lengths
            double rx = (ex - sx + 1) / 2d;
            double ry = (ey - sy + 1) / 2d;
            double rh = (eh - sh + 1) / 2d;

            double rx2 = 1 / (rx * rx);
            double ry2 = 1 / (ry * ry);
            double rh2 = 1 / (rh * rh);

            // find center points
            double cx = (ex + sx) / 2d;
            double cy = (ey + sy) / 2d;
            double ch = (eh + sh) / 2d;


            int volume = (int)(4 / 3d * Math.PI * rx * ry * rh);
            if( !player.CanDraw( volume ) ) {
                player.MessageNow( "You are only allowed to run draw commands that affect up to {0} blocks. This one would affect {1} blocks.",
                                   player.Info.Rank.DrawLimit,
                                   volume );
                return;
            }

            player.UndoBuffer.Clear();

            int blocks = 0, blocksDenied = 0;
            bool cannotUndo = false;

            for( int x = sx; x <= ex; x += DrawStride ) {
                for( int y = sy; y <= ey; y += DrawStride ) {
                    for( int h = sh; h <= eh; h++ ) {
                        for( int y3 = 0; y3 < DrawStride && y + y3 <= ey; y3++ ) {
                            for( int x3 = 0; x3 < DrawStride && x + x3 <= ex; x3++ ) {

                                // get relative coordinates
                                double dx = (x + x3 - cx);
                                double dy = (y + y3 - cy);
                                double dh = (h - ch);

                                // test if it's inside ellipse
                                if( (dx * dx) * rx2 + (dy * dy) * ry2 + (dh * dh) * rh2 <= 1 ) {
                                    DrawOneBlock( player, drawBlock, x + x3, y + y3, h, ref blocks, ref blocksDenied, ref cannotUndo );
                                }
                            }
                        }
                    }
                }
            }
            Logger.Log( "{0} drew an ellipsoid containing {1} blocks of type {2} (on world {3})", LogType.UserActivity,
                        player.Name,
                        blocks,
                        (Block)drawBlock,
                        player.World.Name );
            DrawingFinished( player, "drawn", blocks, blocksDenied );
        }