Skip to content

World and Overlay Drawing

This example draws a glowing box, a vertical line and a nametag at a configurable world position, plus a small HUD panel in the top-left corner of the screen. It uses only the version-independent plugin API, so the exact same source compiles and runs on 1.8.9, 1.18.2, 1.20.4 and 1.21.

It demonstrates:

  • Subscribing to RenderTickEvent and switching on event.type.
  • World drawing (drawWorldBox, drawBlockBox, drawWorldLine, drawWorldNameTag) during the WORLD render tick.
  • Overlay drawing (drawOverlayFilledRect, drawOverlayRect, drawOverlayLine, drawOverlayText) during the OVERLAY render tick.
  • Plugin settings (Boolean, Coords, FloatSlider) controlling the drawing.

Entry point

import com.originmint.managers.PluginManager;
import com.originmint.plugin.IPlugin;
import com.originmint.plugin.settings.Boolean;
import com.originmint.plugin.settings.Coords;
import com.originmint.plugin.settings.FloatSlider;

public class DrawExample implements IPlugin {
  final Boolean drawWorld = new Boolean("draw.world", "Draw world shapes", "Draw the box, line and nametag", true);
  final Boolean drawOverlay = new Boolean("draw.overlay", "Draw overlay panel", "Draw the HUD panel", true);
  final Boolean throughWalls = new Boolean("draw.through_walls", "Through walls", "Draw world shapes through terrain", true);
  final Coords anchor = new Coords("draw.anchor", "Anchor position", "World position to draw around", 0, 100, 0);
  final FloatSlider lineWidth = new FloatSlider("draw.line_width", "Line width", "Line thickness in pixels", 0.5F, 8.0F, 2.0F);

  private final DrawListener listener = new DrawListener(this);

  @Override
  public void onEnable() {
      PluginManager.getInstance().PLUGIN_EVENT_BUS.register(listener);
  }

  @Override
  public void onDisable() {
      PluginManager.getInstance().PLUGIN_EVENT_BUS.unregister(listener);
  }
}

Draw listener

import com.originmint.managers.RenderManager;
import com.originmint.plugin.eventbus.Subscribe;
import com.originmint.plugin.events.RenderTickEvent;

public class DrawListener {
  private final DrawExample owner;

  public DrawListener(DrawExample owner) {
      this.owner = owner;
  }

  @Subscribe
  public void onRenderTick(RenderTickEvent event) {
      if (event.type == RenderTickEvent.Type.WORLD && owner.drawWorld.value) {
          drawWorldShapes();
      } else if (event.type == RenderTickEvent.Type.OVERLAY && owner.drawOverlay.value) {
          drawOverlayPanel();
      }
  }

  private void drawWorldShapes() {
      RenderManager render = RenderManager.getInstance();
      double x = owner.anchor.x;
      double y = owner.anchor.y;
      double z = owner.anchor.z;
      float width = owner.lineWidth.value;
      boolean walls = owner.throughWalls.value;

      // 1x1x1 wireframe box on the anchor block
      render.drawWorldBox(x, y, z, x + 1, y + 1, z + 1, 0.2F, 1.0F, 0.4F, 1.0F, width, walls);
      // Same idea with the block helper two blocks up (ARGB color)
      render.drawBlockBox(x, y + 2, z, 0xFF2ED1FF, width, walls);
      // Line from the box to a point 5 blocks up
      render.drawWorldLine(x + 0.5, y + 1, z + 0.5, x + 0.5, y + 6, z + 0.5, 1.0F, 0.8F, 0.1F, 1.0F, width, walls);
      // Billboarded nametag above everything
      render.drawWorldNameTag(x + 0.5, y + 7, z + 0.5, "DrawExample", "anchor", 1.0F, 1.0F, 1.0F, 1.0F, walls, true);
  }

  private void drawOverlayPanel() {
      RenderManager render = RenderManager.getInstance();
      float width = owner.lineWidth.value;
      int screenW = render.getOverlayWidth();
      int screenH = render.getOverlayHeight();

      render.drawOverlayFilledRect(10, 10, 220, 50, 0.0F, 0.0F, 0.0F, 0.6F);
      render.drawOverlayRect(10, 10, 220, 50, 0.2F, 1.0F, 0.4F, 1.0F, width);
      render.drawOverlayText(18, 18, "DrawExample " + screenW + "x" + screenH, 1.0F, 1.0F, 1.0F, 1.0F, 16);
      render.drawOverlayText(18, 38, "anchor " + owner.anchor.x + ", " + owner.anchor.y + ", " + owner.anchor.z, 0.8F, 0.8F, 0.8F, 1.0F, 14);
  }
}

Drawing around entities

To outline entities instead of fixed positions, use the entity helpers — they take a net.minecraft.entity.Entity (same class name on every version):

render.drawEntityBox(entity, 0x80FF0000);   // box around the entity
render.drawEntityLine(entity, 0x8000FF00);  // camera-to-entity line
render.drawTracerLine(entity, 0x800000FF);  // tracer from screen bottom

How you obtain the Entity instance (iterating the world entity list, etc.) depends on the Minecraft version your plugin targets, so it is not part of this version-independent example.