The DrawOp
class is responsible for taking one or more input coordinates/marks and producing output blocks
Some visual examples of draw operations [TODO sample image]
Remarks
- Draw operations do not only have to draw shapes (ReplaceDrawOp, RestoreSelectionDrawOp TODO)
Returns the name of this draw operations
Estimates the total number of blocks that this draw operation may affect
Remarks:
- This should be implemented as a simple estimate (shouldn't perform any complex calculations)
- This is an upper bound/worst case estimate (assumes that all potentially affected blocks will actually be changed)
Performs the draw operation (actually outputs the block using output
)
Initialises/Prepares the state of this draw operation from the given arguments
Remarks:
- Initialises
Player
,Level
,Min
,Max
etc fields
Returns a DrawOpBlock
with the given x,y,z and block calculated by the given brush
Returns a DrawOpBlock
with the given x,y,z and the given block type
Constrains/Clamps the given coordinates to lie within the Level's boundaries
The minimum coordinates of the bounds of this draw operation
Remarks:
- This is the smallest X/Y/Z from all of the input coordinates/marks
The maximum coordinates of the bounds of this draw operation
Remarks:
- This is the largest X/Y/Z from all of the input coordinates/marks
The coordinates of the current block being processed by this draw operation
Remarks:
- This field is mainly intended for use by Brushes
The player that is executing this draw operation
The Level that this draw operation is being performed on
The BlockDB change type for blocks affected by this draw operation
[TODO /b example image]
Remarks:
- This field should be set in the constructor of the draw operation class
- The supported flag values from the
BlockDBFlags
class are -
- Drawn, Replaced, Pasted, Cut, Filled, Restored, UndoOther, UndoSelf, RedoSelf, FixGrass
Whether the output of this draw operation can potentially be transformed (e.g. scaled or rotated) by a Transform
- Draw operations whose output must not be transformed (e.g. Replace, Restore, UndoPlayer) should set this field to false
using MCGalaxy;
using MCGalaxy.Drawing;
using MCGalaxy.Drawing.Brushes;
using MCGalaxy.Drawing.Ops;
using MCGalaxy.Maths;
public class OddBoxDrawOp : DrawOp
{
public override string Name { get { return "OddBox"; } }
public override long BlocksAffected(Level lvl, Vec3S32[] marks) {
long width = Max.X - Min.X + 1;
long height = Max.Y - Min.Y + 1;
long length = Max.Z - Min.Z + 1;
// NOTE: strictly speaking, the marks should be examined to calculate the number of rows
// that will actually get drawn - but it's simpler to just always assume the worst case
return (width / 2 + 1) * height * length;
}
public override void Perform(Vec3S32[] marks, Brush brush, DrawOpOutput output) {
// Min contains the smallest X,Y,Z of the marks, so can be used as lower left corner of the box
// Max contains the largest X,Y,Z of the marks, so can be used as upper right corner of the box
// Both coordinates are then constrained/clamped to lie within the boundaries of the level
Vec3U16 min = Clamp(Min), max = Clamp(Max);
for (ushort y = min.Y; y <= max.Y; y++)
for (ushort z = min.Z; z <= max.Z; z++)
for (ushort x = min.X; x <= max.X; x++)
{
// skip even coordinates on X axis
if ((x % 2) == 0) continue;
// use the given brush to determine the type of block to place at x,y,z
// then actually output the block by invoking 'output' callback function
output(Place(x, y, z, brush));
}
}
}
[TODO output example image]