Skip to content

Add exclusion zones to movement settings (like upstream mineflayer-pathfinder)#5

Closed
XaXayo12 wants to merge 3 commits into
Minecraft-Pathfinding:2026-rewritefrom
XaXayo12:feature/exclusion-zones
Closed

Add exclusion zones to movement settings (like upstream mineflayer-pathfinder)#5
XaXayo12 wants to merge 3 commits into
Minecraft-Pathfinding:2026-rewritefrom
XaXayo12:feature/exclusion-zones

Conversation

@XaXayo12

@XaXayo12 XaXayo12 commented Jun 15, 2026

Copy link
Copy Markdown

What & why

Adds exclusion zones ("keep out" areas) to the movement settings, bringing back the exclusion-area concept from upstream PrismarineJS/mineflayer-pathfinder. The 2026-rewrite branch kept the doc comments referencing exclusionStep/exclusionBreak/stepExclusionAreas but the implementation had been removed — this wires it back up cleanly.

You can now tell the bot to avoid (softly) or never enter (hard) a region, and likewise restrict where it may mine or build.

New settings (MovementOptions)

All default to [], so there is zero overhead when unused:

Setting Applies to
exclusionAreasStep blocks the bot would stand in / walk into
exclusionAreasBreak blocks the bot would break (mine)
exclusionAreasPlace blocks the bot would place (build on)

Each entry is a function (block: BlockInfo) => number returning the extra cost of using that block; >= COST_INF (or Infinity) forbids it. Costs from every area in a list are summed. This is API-compatible with upstream's exclusion areas.

Helpers (exported from the package root)

  • createBoxExclusion(corner1, corner2, cost?) — axis-aligned box (corners inclusive, any order)
  • createRadiusExclusion(center, radius, cost?) — sphere (height counts)
  • createColumnRadiusExclusion(center, radius, cost?) — vertical pillar (ignores height)
  • EXCLUSION_NEVER constant and the ExclusionArea type
const { createBoxExclusion } = require('@nxg-org/mineflayer-pathfinder')
const noGo = createBoxExclusion(new Vec3(-8, 60, -8), new Vec3(8, 80, 8))
bot.pathfinder.setMoveOptions({ exclusionAreasStep: [noGo] })

How it's implemented

  • Step exclusion is applied inside each movement provider, on the block the bot lands in (already fetched while generating the move) and folded into the move cost before the move is created. So Move.cost stays readonly, there is no extra/unrouted block lookup, and forbidden landings are simply never generated (no array splicing). Covers walking, jumping, dropping, parkour and towers.
  • Break/place exclusion is folded into Movement.breakCost / Movement.placeCost, which every break/place caller already routes through.
  • buildMovementOptions() merges over the defaults and always hands out fresh copies of the three arrays (the defaults are frozen), so two bots — or two setMoveOptions calls — never share and then mutate the same array.
  • Hard zones (>= COST_INF) skip the move; soft zones just add their cost.

Tests

tests/exclusionZones.test.ts (runs in the existing node --test rig):

  • Unit tests for the zone-builder math (inside/outside/boundary, corner-order independence, soft cost, sphere vs. pillar).
  • Functional pathfinding: a hard wall forces a detour (and no path node lands inside it), a soft wall still routes to the goal, and a hard zone on the goal block makes it unreachable.

Full suite: 25/25 passing (17 pre-existing + 8 new). tsc build is clean.

Docs & example

  • docs/API.md: Settings table + a dedicated Exclusion Zones section.
  • docs/AdvancedUsage.md: a beginner-friendly "Keep-Out Areas" section.
  • examples/exclusionZones.js: a runnable chat-driven demo.

Scope note

This PR is intentionally focused: it touches only the files needed for the feature, plus its docs and example. It does not include the repo's pre-existing ts-standard lint failures, which exist independently of this change across unrelated files.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 16d5f0c4e0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +78 to +80
exclusionAreasStep: [],
exclusionAreasBreak: [],
exclusionAreasPlace: []

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid sharing default exclusion arrays

Because the default option object now contains mutable arrays and the rest of the code copies it with shallow spreads/Object.assign, any in-place update to a bot's public defaultMoveSettings.exclusionAreasStep (or to DEFAULT_MOVEMENT_OPTS) mutates this shared default array. In that scenario, later pathfinders or later setMoveOptions calls that fall back to the default will inherit zones from another bot/session; use fresh arrays when constructing defaults instead of storing these shared [] instances.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 508ff8b. Added buildMovementOptions(), which merges over the defaults and always returns fresh copies of the three exclusion arrays, and used it at all four build sites (Movement ctor, MovementHandler.create, ThePathfinder ctor and setMoveOptions). The default arrays are also frozen now. Added regression tests asserting independent (non-shared) arrays and frozen defaults.

XaXayo12 pushed a commit to XaXayo12/minecraft-pathfinding that referenced this pull request Jun 15, 2026
…ings

DEFAULT_MOVEMENT_OPTS held one shared [] per exclusion list, and every
settings object was built with a shallow Object.assign/spread. So when a
user didn't override the arrays, all settings objects pointed at the SAME
array instance. Mutating one in place (e.g.
bot.pathfinder.defaultMoveSettings.exclusionAreasStep.push(zone)) leaked
zones into other bots in the same process and into later setMoveOptions
calls, and could even pollute the module-level default.

Fix: add buildMovementOptions(), which merges over the defaults and always
returns fresh copies of the three exclusion arrays. Use it at all four
build sites (Movement ctor, MovementHandler.create, ThePathfinder ctor and
setMoveOptions). The default arrays are also frozen as a safety net.

Adds regression tests: fresh/independent arrays per settings object,
user-supplied arrays are copied (not referenced), and the defaults are
frozen. Full suite: 28/28.

Reported by the codex review bot on PR Minecraft-Pathfinding#5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@XaXayo12 XaXayo12 force-pushed the feature/exclusion-zones branch from 508ff8b to 4c9c8fe Compare June 15, 2026 17:26

@GenerelSchwerz GenerelSchwerz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of changes to be made. Also, the exclusion zones are not properly addressed (exclusionStep, notably), during post-processing at all, resulting in optimized paths still interacting with excluded terrain.

Comment thread docs/AdvancedUsage.md
}
```

<h1 align="center">Exclusion Zones (Keep-Out Areas)</h1>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These docs are too conversational. Make this more concise.

Comment thread docs/API.md Outdated

<h3>How it works</h3>

An **exclusion area** is just a function. You give it one block, and it returns

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, a bit too conversational. Cut it down.

Comment thread docs/API.md Outdated

<h3>Ready-made zone shapes</h3>

You usually don't need to write the function yourself. These helpers build the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments are to be removed, adding utility functions is not in scope for this library. Users are expected to come up with these themselves, imo. this one can be argued.

* @param cost extra cost for blocks inside the box. Defaults to "never"
* ({@link EXCLUSION_NEVER}). Pass a smaller positive number for a "soft" zone.
*/
export function createBoxExclusion (corner1: Vec3, corner2: Vec3, cost: number = EXCLUSION_NEVER): ExclusionArea {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a fine implementation, but these should be shown in examples rather than be directly included in the library in the interest of encouraging users to create their own functions for this.

// Exclusion zones: forbid or make-expensive any move that ends with the bot
// standing inside a "step" keep-out area. When no step areas are configured
// (the default), this is skipped entirely, so normal pathfinding pays nothing.
if (this.settings.exclusionAreasStep.length > 0) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea what this is. This should be calculated during actual A* calculations. This seems entirely incorrect and should be removed. Convince me otherwise.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upon reading further, I believe I am correct. ExclusionPlace and ExclusionBreak are handled more or less correctly--exclusionStep is handled in the wrong place and must be fixed. This should be handled during the calculation step, not after the path has been made.

* jumping, dropping, parkour, towers — respects the same zones, with no extra
* work when no zones are configured.
*/
private applyStepExclusions (moves: Move[]): void {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/Minecraft-Pathfinding/minecraft-pathfinding/pull/5/changes#r3422198575

Same issue. This appears to be entirely redundant and should not be handled here.

Comment thread src/mineflayer-specific/move.ts Outdated
toBreak: BreakHandler[],
public readonly remainingBlocks: number,
public readonly cost: number,
// NOTE: not readonly on purpose. MovementHandler.getNeighbors may add a small

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also incorrect. This should remain readonly and the exclusionStep cost should be calculated before the move is ever made. Convince me otherwise in terms of performance only. The rest of the system is constructed in this way.

Comment thread src/index.ts Outdated
export type { MovementOptions } from './mineflayer-specific/movements'

// Exclusion zones ("keep out" areas), like upstream mineflayer-pathfinder.
export {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, get rid of these entirely and move them to examples. Utilities are not needed.

@GenerelSchwerz

Copy link
Copy Markdown
Collaborator

My bad about the selections for the review btw, I have never done that before. I'll make sure to highlight the correct sections next time. The line that was selected for each comment is accurate though.

…eam)

Add "keep out" exclusion zones to the movement settings, matching the
exclusion-area concept from upstream PrismarineJS/mineflayer-pathfinder.

- exclusionAreasStep / exclusionAreasBreak / exclusionAreasPlace in
  MovementOptions (default []). Each is a (block: BlockInfo) => number;
  a sum >= COST_INF forbids the block, a positive value is a soft penalty.
- Step exclusion is applied inside each movement provider, on the block the
  bot lands in (already fetched during move generation), folded into the move
  cost BEFORE the move is created. So Move.cost stays readonly, there is no
  extra/unrouted block lookup, and forbidden landings are simply never
  generated (no array splicing). Covers walk/jump/drop/parkour/tower.
- Break/place exclusion is folded into Movement.breakCost / placeCost, which
  every break/place caller already routes through.
- buildMovementOptions() merges over the defaults and always hands out fresh
  copies of the three arrays (defaults are frozen), so bots/sessions never
  share or mutate the same array.
- Helpers createBoxExclusion / createRadiusExclusion /
  createColumnRadiusExclusion, EXCLUSION_NEVER, and the ExclusionArea type.
- Tests (28/28), docs (API + AdvancedUsage), and an example.
@XaXayo12 XaXayo12 force-pushed the feature/exclusion-zones branch from 4c9c8fe to 63a63dd Compare June 16, 2026 16:25
XaXayo12 added 2 commits June 17, 2026 00:03
- Post-processing: the Optimizer now refuses to straight-line a merge whose
  swept line crosses a HARD step-exclusion zone, so optimized/straight-lined
  paths no longer cut through "keep out" terrain the A* route went around.
  Soft zones still allow straightening (a preference, not a wall). The check
  is central in Optimizer.compute, so every optimizer respects it.
- Remove the box/radius/column zone-builder utilities from the library and
  keep only the ExclusionArea type; the shape helpers now live in
  examples/exclusionZones.js for users to copy. Utilities are out of scope.
- Trim the Exclusion Zones docs (API.md, AdvancedUsage.md) to be concise.
- Tests: add two deterministic optimizer-guard tests (merge skipped across a
  hard zone; merged freely without one); drop the now-removed helper unit tests.

Build clean, 25/25 tests pass.
- Optimizer: replace the approximate 0.5-block sampling in the hard-zone check
  with an exact voxel traversal (Amanatides & Woo). It visits exactly the cells
  the merged segment crosses, so it can neither skip a thin hard cell nor do
  redundant block lookups -- more correct and cheaper.
- Reuse: extract sumExclusionAreas() and call it from exclusionStep/Break/Place
  and the optimizer's hard-zone check, instead of repeating the same sum loop
  four times.
- Add an optimizer test for diagonal merges (a single hard cell on the diagonal),
  which exercises the voxel traversal's tie handling.

Build clean, 26/26 tests pass.
@XaXayo12

Copy link
Copy Markdown
Author

Superseded by a clean single-commit PR: #6.

@XaXayo12 XaXayo12 closed this Jun 16, 2026
@XaXayo12 XaXayo12 deleted the feature/exclusion-zones branch June 16, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants