Skip to main content
PortalGeometry controls how Dimensions detects portal structures in the world, determines whether an entity is inside a portal, and builds exit portals at a destination. The default implementation handles standard rectangular vertical portals. Override it when your portal type uses a different shape, a horizontal orientation, or any detection logic that the default geometry cannot express.
PortalGeometry is scheduled to change in a future Dimensions update. Keep your geometry implementation as self-contained as possible so it is easy to migrate.

When to Use a Custom PortalGeometry

You need a custom PortalGeometry when your portal type has non-standard characteristics — for example, the HorizontalPortals addon ships its own HorizontalPortalGeometry because Dimensions’ default geometry only handles vertical frames. Other cases include:
  • Portals shaped as circles, crosses, or other non-rectangular frames.
  • Portals that can face any direction beyond the standard X/Z axes.
  • Detection logic that depends on block patterns rather than bounding boxes.

Creating a Custom PortalGeometry

Extend PortalGeometry and implement the four required methods below. Every method must be present for Dimensions to function correctly with your geometry class.
// Return a new instance of your geometry class
public PortalGeometry createGeometry(Vector min, Vector max)

// Find the portal structure at a given location
public PortalGeometry getPortal(CustomPortal customPortal, Location loc)

// Return true if location is inside the portal
public boolean isInside(Location location, boolean outside, boolean corner)

// Build an exit portal at the given location
public void buildPortal(Location newLocation, World destinationWorld, CustomPortal customPortal)

Full Example Class

public class CustomPortalGeometry extends PortalGeometry {

    protected CustomPortalGeometry(Vector min, Vector max) {
        super(min, max);

        // If you change min or max here, you MUST update the bounding box.
        // Without this, entities teleport using the default bounding box
        // generated from the original min/max vectors.
        // getBoundingBox().copy(BoundingBox.of(getInsideMin(), getInsideMax()));
    }

    // Required — Dimensions calls this to create instances of your geometry
    public PortalGeometry createGeometry(Vector min, Vector max) {
        return new CustomPortalGeometry(min, max);
    }

    public PortalGeometry getPortal(CustomPortal customPortal, Location loc) {

        // Perform your structure detection here. Once you have determined
        // the min and max corners of the portal, return a new instance.
        // Even non-rectangular portals must provide a min/max bounding box;
        // handle finer shape checks inside isInside().

        return new CustomPortalGeometry(min, max);
    }

    public boolean isInside(Location location, boolean outside, boolean corner) {

        // Return true if the given location is within the portal interior.
        // When outside == true, you MUST include the frame blocks as well,
        // or the plugin may fail to detect portal interactions correctly.
        // When corner == true, include corner blocks in your check.

        return false;
    }

    @Override
    public void buildPortal(Location newLocation, World destinationWorld, CustomPortal customPortal) {

        // Build the exit portal in destinationWorld.
        // newLocation is PortalGeometry#min — the bottom corner of the portal.
        // Build upward and along +x or +z depending on the portal's Axis.

    }
}

Key Implementation Notes

Bounding box updates — if you modify the min or max vectors in your constructor, call getBoundingBox().copy(BoundingBox.of(getInsideMin(), getInsideMax())) immediately after. Skipping this causes entities to teleport using the wrong bounding box. isInside flags — the outside flag expands the check to include the frame; the corner flag includes corner positions. Failing to honour these flags will cause Dimensions to miss legitimate interactions at the edges of your portal. buildPortal originnewLocation is always PortalGeometry#min, the minimum corner of the new portal. Place your blocks moving upward (increasing Y) and along the positive X or Z axis to match the portal’s orientation axis.

Registering Your Geometry

Once you have implemented your class, register it for a specific portal type using:
PortalGeometry.setCustomGeometry(customPortal, new CustomPortalGeometry(min, max));
Call this inside your addon’s registerPortal(YamlConfiguration config, CustomPortal portal) override so it runs once per portal type when Dimensions loads its portal definitions.