Editor API

Add your own tools, buttons and drawings to the BuildPrint editor.

Add tools to the The editor. They sit on the toolbar next to the built-in ones and work the same way. From BuildPrint 0.1.17. This API uses BuildPrint's interfaces and Minecraft types, so you compile against the BuildPrint jar.

Register #

Write a class that implements BuildprintEditorPlugin, with a public constructor without arguments. BuildPrint calls it once, after its own tools exist, and only when BuildPrint is installed, so your mod still runs without it. Tell BuildPrint about it in any of three ways. Declaring it more than one way is fine: it is loaded once.

  • On Fabric: list it under the buildprint entrypoint in fabric.mod.json.
  • On NeoForge: put @BuildprintPlugin (com.buildprint.api.editor) on the class. NeoForge reads the annotation without loading the class.
  • On either: a file META-INF/services/com.buildprint.api.editor.BuildprintEditorPlugin in your jar, with the class name on one line.
fabric.mod.jsonJSON
"entrypoints": {
    "buildprint": ["com.example.MyEditorTools"]
}
Java
@BuildprintPlugin   // for NeoForge; harmless on Fabric
public class MyEditorTools implements BuildprintEditorPlugin {
    @Override
    public void registerEditor() {
        BuildprintEditor.registerGroup("mymod:curves", Component.literal("Curves"));
        BuildprintEditor.registerTool("mymod:curves", new SplineTool());
        BuildprintEditor.registerAction(BuildprintEditor.MAKE, new ClearAction());
        BuildprintEditor.registerOverlay("mymod:spline", (draw, state) -> drawSpline(draw));
        BuildprintEditor.addListener(new EditorListener() {
            @Override public void onExit() { dropHalfDoneSpline(); }
        });
    }
}

Groups #

BuildPrint has two: make, for making a new schematic from the world, and place, for moving a loaded build. The toolbar shows make as Create. Add to one of those when your tool does that job. A group of your own gets its own bar on the toolbar, after them.

BuildPrint's own tools #

In toolbar order:

GroupIds
makebuildprint:select, buildprint:magic (Magic select), buildprint:resize, buildprint:save
placebuildprint:place, buildprint:move (moves and turns), buildprint:auto_align, buildprint:paste (only on the toolbar where pasting works)

buildprint:rotate is no tool of its own since 0.1.34: Move's gizmo turns too. selectTool("buildprint:rotate") selects buildprint:move (in 0.1.34 itself it returned false), and activeTool() and the listeners report buildprint:move. New code uses buildprint:move.

Make a tool #

Java
public class SplineTool implements BuildprintTool {
    @Override public String id() { return "mymod:spline"; }
    @Override public Component name() { return Component.literal("Spline"); }
    @Override public ItemStack icon() { return new ItemStack(Items.STRING); }
    @Override public Component leftHint() { return Component.literal("add a point"); }

    @Override
    public boolean onMouseButton(EditorClick click) {
        if (click.button() != EditorClick.LEFT || !click.press()) return false;
        BlockPos at = click.pickBlock(true); // through grass and flowers
        if (at != null) points.add(at);
        return true;
    }

    @Override
    public void renderGizmos(GizmoDraw draw, EditorState state) {
        for (BlockPos p : points) draw.block(p, 0xFFFFE066, 2f, 0x22FFE066);
    }
}
  • The number keys, Q and E, Alt and the wheel and Tab pick it, and the toolbar shows its name and what each click does.
  • While your tool is active you get every mouse press and release, and BuildPrint gets none.
  • renderGizmos runs every frame while the tool is active, after BuildPrint's own.
  • The icon is a GUI sprite (sprite(), drawn 16 by 16) or an item (icon()).
  • Return false from usable(state) to grey it out, for example while there is no region. It can still be picked.

Actions and overlays #

  • Actions (BuildprintAction) are buttons that run once. Clicking one or pressing its number runs run(state). The active tool stays what it was, and stepping through the tools skips them.
  • Overlays are drawn every frame while the editor is open, whatever tool is active. Use them for things that should stay visible, like a curve you are editing.
  • Listeners (EditorListener) hear when the editor opens or closes, the tool changes, or the target build changes. onExit also comes when the editor closes by itself: the player was hurt with the camera away, died, changed dimension or left the world.

Drawing and picking #

  • GizmoDraw draws lines, arrows, dots, boxes, quads, text, region boxes and handles in BuildPrint's style. handleSize(at) gives a size that stays the same on screen at any distance.
  • EditorClick has the button, Shift, Ctrl and Alt, the crosshair ray and pickBlock(skipCover).
  • EditorRay has the ray math BuildPrint's own handles use: hit a box, hit a plane, closest point on a line.
  • EditorState has the selected regions of the dimension the player is in, the active one, the target build and the camera position.

Open and close it yourself #

From your own menu or key, for example a hotkey wheel. open() and close() do what the editor key does, camera and controls included, and your listeners hear about it. The first time on a server open() asks the player free camera or walking, so it can return true with the editor still closed: wait for onEnter, or check isActive(). From BuildPrint 0.1.19.

Java
// Count your own dialog as part of the editor, once.
BuildprintEditor.registerScreen(MyDialog.class);

if (BuildprintEditor.isActive()) BuildprintEditor.close();
else BuildprintEditor.open();
  • close() also closes an editor screen that is open on top of it: BuildPrint's save and tool picker screens, and any screen you registered. Work such a screen started still finishes. A save that is being written, or waiting on the file picker, still lands.
  • isEditorScreen(screen) says whether a screen belongs to the editor: the save screen, the tool picker, the paste screen and the ones you registered.
  • setTarget(id) points the Place tools at a build, as clicking it does. It works while the editor is open, on a build that is shown.

Keys #

1 to 9 and 0 pick the first ten slots in toolbar order. Tab opens a picker with all of them, so tools past the tenth are still easy to reach. Alt and the wheel pick the next tool on every tool. Without Alt the wheel belongs to BuildPrint: with an added tool active it sets fly speed in the free camera, and picks the next tool when the player walks. Ctrl and the wheel do the same. Your tool does not get wheel events.

When your code throws, BuildPrint logs it once and carries on without it, so a bug in a tool does not close the editor.

Reference #

BuildprintEditorWhat it does
registerGroup(String id, Component title)Add a toolbar group, drawn as its own bar.
registerTool(String group, BuildprintTool tool)Add a tool to the end of a group.
registerAction(String group, BuildprintAction action)Add a button that runs once.
registerOverlay(String id, BiConsumer<GizmoDraw, EditorState> overlay)Draw every frame while the editor is open. The same id replaces it.
addListener(EditorListener listener)Hear about open, close, tool and target changes.
isActive()Whether the editor is open.
activeTool()The active tool's id, like buildprint:select. Null when the editor is closed.
selectTool(String id)Make a tool active, or run an action. False when the editor is closed or there is no such id.
state() / crosshair()What the editor is working on, and the crosshair ray.
open() / close()Open or close the editor, as its key does. False when it already was. Since 0.1.19.
isEditorScreen(Screen screen)Whether a screen belongs to the editor. Since 0.1.19.
registerScreen(Class<? extends Screen> type)Count your screens, and their subclasses, as the editor's. Since 0.1.19.
setTarget(int id)Point the Place tools at a shown build. Since 0.1.19.
BuildprintToolWhat it does
id() / name()A namespaced id, and the name shown above the toolbar.
sprite() / icon()The toolbar icon.
leftHint() / rightHint()What a left and right click do, shown on the toolbar.
usable(EditorState state)False to grey it out.
onMouseButton(EditorClick click)A button went down or up. Return true when you used it.
renderGizmos(GizmoDraw draw, EditorState state)Draw while active.
onSelected(EditorState state) / onDeselected()Became active, or stopped being active.

Something missing or wrong on this page? Say so on Discord.