Repository navigation
Commands
简体中文 | English
This page is written for server owners: when mobs actually act, what each subcommand can show you, how to hand out permissions, how mobs and worlds are filtered, and why the same jar runs on both Paper and Folia and how it coexists with BlockLocker.
| Behaviour | Trigger | Key config |
|---|---|---|
| Mining | Ceiling blocked / target below / under the target / pathfinding blocked by a block ahead / a configured block appears in front | all of mining.yml
|
| Placement | A height difference or a gap between the mob and its chase target, and the backpack still holds blocks |
placement.* + backpack.* + entries in placement.yml
|
| Pickup | A "worth picking up" drop (block / pickaxe) within radius |
pickup.* in placement.yml
|
| No action | No pickaxe (mining), no backpack / out of placements (placement), no target, world or mob filtered out, cooling down |
enabled, worlds, mob-whitelist/blacklist, equip.yml
|
The first match wins, in this order:
| Order | Trigger | Condition | Config key |
|---|---|---|---|
| 1 | Mine the ceiling | The target is ≥1.5 blocks above, and the 2nd block above the mob's feet is occupied | trigger.ceiling-blocked |
| 2 | Mine below itself | The target is ≥1.5 blocks below, within 3 blocks horizontally, the mob stands on ground, and the 2nd block below is not a liquid | trigger.dig-below-self |
| 3 | Mine under the target | The target is ≥0.5 blocks above, and the block under it is mineable | trigger.dig-under-target |
| 4 | Path blocked | First the two blocks straight ahead (at foot and head level), then the first solid block on the "eyes → target" ray | trigger.path-blocked |
| 5 | Configured blocks | A block from trigger.configured-blocks.blocks appears within max-distance in front (line of sight not required) |
trigger.configured-blocks.enabled |
- Before all of this there is a tool gate: with
tool.require-pickaxe: true(the default), a mob whose main hand holds no pickaxe does not mine at all. - Every candidate must also pass material, safety, reach, protection and duration checks. The ray does not pierce: if the first non-passable block cannot be mined, the attempt is abandoned instead of digging through bedrock to reach something behind it.
- The safety blacklist (bedrock, barriers, command blocks, structure blocks, portals, moving pistons, spawners, ...) is never touched, and neither is anything outside the world height or world border; block-entity containers are skipped by default.
- With
require-adjacent: true(the default) only blocks touching the body are mined (horizontal ±1, vertical −1..+2); setting it tofalsefalls back tomax-distance(default 4.5). -
protect-mob-blocks: true(the default) leaves blocks placed by the mob itself or its fellows alone, so a bridge is not torn down right after it is built.
- The mob has a chase target (
placement.vertical-aggro: truelets it actively lock onto a visible survival / adventure player up to 16 blocks above); - The backpack is not empty (rolled by
backpack.chance, or filled by pickup); - The current chase has not used up
placement.max-per-chase(default 32) placements, and the mob is not in a placement cooldown; - If the picked entry is a functional block (TNT / bucket),
special-only-under-target: true(the default) places it only in the target's own block and never uses it for path building.
Strategy order is melee → get out of water → gain height (stairs / pillar) → bridge / build down:
| Condition | Action |
|---|---|
| Less than 1 block horizontally and the target is no more than 2 blocks higher | No placement, leave it to vanilla melee |
| The mob is in water (its own block or the one below is a liquid) | Walk to a nearby dry spot first, consuming no blocks |
Height difference ≥ 2, horizontal ≥ stair-min-distance(4) and height difference < pillar-far-height(8) |
Build stairs |
Height difference ≥ pillar-far-height(8), or horizontal ≤ pillar-near-distance(2) |
Pillar up in place |
| Anything else | Pillar up to the target's height, then bridge horizontally towards it |
The target is clearly lower (vertical-drop, default 1.5) and there is a gap ahead |
Build one block downwards |
Hard rules against reckless placement: walk up existing steps or solid ground; drop down when the fall is ≤ 3 blocks; never bridge over a liquid; leave walls of two blocks or more to vanilla pathing or mining; never place into a block containing a living entity (the chase target itself does not count as blocking); step aside first when crowded by fellows.
- With
pickup.enabled: true(the default), every managed mob that passes the world / mob filters checks for drops once per second; note thatenabledinplacement.ymlis the master switch and governs both placement and pickup; - Search radius
pickup.radiusdefaults to8.0(horizontalradius, verticalmax(2, radius × 0.5)); the item is only taken atpickup.reach(default1.8).reachmust be smaller thanradius, otherwise it is lowered toradius / 2with a warning; - Only "worth picking up" blocks and pickaxes: no gravity-affected blocks (sand, gravel), no hard-blacklisted blocks such as bedrock or spawners, and no non-block items;
- Blocks go into the virtual backpack, pickaxes go to the main hand (
pickup.blocks/pickup.pickaxes); if the mob cannot hold one, the item is dropped back on the ground instead of vanishing; - A mob that is currently mining or placing is never interrupted by pickup.
| Symptom | Cause | Where to look |
|---|---|---|
| Never mines | No pickaxe (tool.require-pickaxe: true and the main hand is not a pickaxe) |
chance in equip.yml, tool.give.chance
|
| Never builds | No backpack, or max-per-chase used up, or the backpack is empty |
backpack.chance, placement.max-per-chase
|
| No target at all | No chase target; with targeting.yml disabled the mob will not lock onto players either |
enabled / radius in targeting.yml
|
| A whole area is idle | The world is filtered out: worlds.whitelist is non-empty and does not list it, or the world is in worlds.blacklist
|
worlds.* in mining.yml / placement.yml
|
| Only some mobs are idle | The mob is filtered out: not in the default humanoid set, matched by mob-blacklist, or mob-whitelist is non-empty without it |
mob-whitelist / mob-blacklist
|
| Acts, then pauses for seconds | Cooling down: mining success cooldown-seconds (default 8 s), failure retry-seconds (default 1.5 s), functional-block placement placement.cooldown-seconds (default 3 s) |
mining.yml / placement.yml
|
| Stares at a block forever | The duration exceeds break-time.hard-cap-seconds, so the block counts as "unmineable" and is skipped (one console note per material) |
break-time.hard-cap-seconds, materials.multiplier
|
| Nothing works at all |
enabled is false in the relevant file |
enabled in mining.yml / placement.yml
|
A sensible order: run /mobinteract status first to make sure filters and switches are not disabling a whole area, then use /mobinteract inspect on the specific mob to read its "most recent behaviour", and only then turn on debug to see candidate-block decisions (it is very noisy — turn it off afterwards).
The command is /mobinteract, alias /mi. No argument is equivalent to status.
| Subcommand | Notes |
|---|---|
/mobinteract reload |
Reloads the six config files (mining.yml / placement.yml / equip.yml / targeting.yml / message.yml / update.yml); the reply carries the current message count |
/mobinteract status |
Configuration summary: world / mob filters, mining parameters, tools, placement limits, path-building strategy, pickup, spawn equipment, known mob count, number of mobs currently mining, temporary block count, BlockLocker integration state |
/mobinteract inspect |
Players only; inspects the mob within 16 blocks of the crosshair (within about a 20° angle and with line of sight): cooldowns, placements used in the current chase, main-hand pickaxe, most recent behaviour, pillar height, backpack contents |
/mobinteract update |
Asks GitHub Releases whether a newer version exists and reports the result to whoever ran it |
- All six config files are re-read together,
message.ymlandupdate.ymlincluded: changing texts, probabilities, filters or the update interval never requires a restart. - Where hot reload stops: the configuration is swapped wholesale and running mining / placement actions are not interrupted. The block being mined is finished with the old values, the current bridge segment is built with the old values; only behaviour started after the reload uses the new ones.
- The reply carries the current message count, which confirms
message.ymlwas actually read (a count that looks wrong usually means an unsaved file or broken YAML indentation). - A deleted key falls back to the built-in default with a single console warning; it never errors out or stops the plugin.
- To change that reply itself, edit
command.reload.successinmessage.yml(it carries the{count}placeholder) and reload again.
The whole-server picture, ideal right after installing:
- The current world and mob filter result (all worlds / all mobs / default humanoids / whitelist(n) / blacklist(n));
- Mining parameters (distance, adjacency, cooldown), tools and grant chances;
- Placement limits and path-building strategy, pickup switch;
- Spawn-equipment chance;
- Runtime numbers: known mob count, number of mobs currently mining, temporary block count;
- BlockLocker integration state, shown as "BlockLocker protection: yes/no".
- Players only (run from the console you get the generic player-only message).
- It looks at the mob within 16 blocks of the crosshair, within about a 20° angle and with line of sight; aim slightly off or stand behind a wall and nothing is found.
- The output contains: cooldowns, placements used in the current chase, main-hand pickaxe, most recent behaviour, pillar height, backpack contents (one line per backpack entry).
- The "most recent behaviour" line is the first-hand answer to "why isn't it moving", for example:
放置次数已用完(max-per-chase=32)
放置失败 cobblestone @x,y,z
挖掘停滞,已放弃
放置次数已用完 (placements used up) means raise placement.max-per-chase; 放置失败 (placement failed) is usually an occupied landing spot or a liquid ahead; 挖掘停滞,已放弃 (mining stalled, abandoned) means there was no progress for 3 seconds, typically because the target block is obstructed or the region task did not go through.
- Runs one check right now instead of waiting for the background timer; the result is printed to whoever ran it (console or player).
- What it does: asks GitHub Releases for the newest published, non-draft release, compares its tag with the version of the jar you are running, and answers one of four ways — up to date; a new version exists (with the release page link); checks are disabled in
update.yml; or the check failed (usually the server cannot reachapi.github.com). - The answer is cached as "the last result", which is what the console notice and the admin join reminder reuse — so a busy server does not hammer GitHub.
- Nothing is downloaded or installed automatically; upgrading is still swapping the jar.
- Interval, first delay, pre-release handling and the three notification switches live in
update.yml; the texts live inmessage.ymlunderupdate.*andcommand.update.*.
- Every text sent to players (the output of
status/inspect/reload, including filter summaries, state words and backpack entry templates) lives inmessage.yml, generated on first start. - Common fragments are
command.common.no-permission/usage/player-only; state words cover enabled / disabled, on / off, yes / no, none, forever, unmineable, decided / undecided. - Colour codes use
&(such as&7,&f); placeholders use{name}(in use:{count},{mob},{worlds},{percent},{seconds},{max},{maxPerChase},{kinds},{total},{id},{type}, ...). - Any message can be written as a YAML list and is then sent line by line; use that to split a
statusline into two.
| Permission node | Default | Scope |
|---|---|---|
mobinteract.admin |
op | Every subcommand of /mobinteract and its alias /mi: reload, status, inspect
|
- The plugin defines a single node for this command, and all three subcommands fall under it: there is no separate read-only node for
statusorinspect. If ordinary admins should only read status, grant themmobinteract.adminand accept that they can also runreload. - Only ops have it by default; when granting it through a permission plugin, copy the node exactly as
mobinteract.admin, without a leading slash. - Without permission the plugin sends
command.common.no-permissionfrommessage.yml, which you can reword. - The command changes no game rules and
reloadonly re-reads configuration, so no extra high-level node is needed.
The plugin only manages Mob subclasses (living creatures with their own AI). Players, armour stands, dropped items, boats and minecarts are untouched. The default humanoid set is:
- Zombies (including drowned / husks / zombie villagers / zombified piglins)
- Skeletons (including strays, wither skeletons and the rest of the skeleton family)
- Illagers (vindicators, evokers, pillagers)
- Piglins
- Witches
Villagers / wandering traders are not in the set; add them back explicitly with mob-whitelist: [VILLAGER, WANDERING_TRADER]. mob-whitelist: ["*"] (or ALL / ANY) means all mobs; mob-blacklist always takes precedence — a mob listed in both is treated as blacklisted.
The filter applies to mining, placement and pickup at once: a filtered-out mob neither mines, nor builds, nor picks anything up.
| File | Keys | What it governs |
|---|---|---|
equip.yml |
chance, worlds.<world name>
|
Spawn-equipment chance: how likely a mob in this world spawns with a pickaxe / blocks (world names are case-insensitive) |
mining.yml / placement.yml
|
worlds.whitelist / worlds.blacklist
|
Whether the behaviour applies: an empty whitelist = all worlds; non-empty = only those worlds; the blacklist takes precedence |
- World names are case-insensitive:
worldandWorldare the same world. A misspelled name is not an error — it simply means "nothing happens in that world", so check the filter result with/mobinteract statusafter editing. - The blacklist wins over the whitelist: a world in both lists counts as disabled.
- To enable behaviour only in the overworld and a resource world while leaving a minigame world alone:
worlds.whitelist: [world, resource], or putworld_minigameintoworlds.blacklist. - How the spawn-equipment gate (
chanceinequip.yml, default0.10) relates to the two finer-grained chances:
passes the gate (chance in equip.yml, default 0.10)
├── pickaxe roll: mining.yml tool.give.chance (default 0.80)
└── backpack roll: placement.yml backpack.chance (default 0.65)
So at spawn the share of mobs with "pickaxe ∪ blocks" never exceeds chance (roughly 9.3% with the defaults). For any given mob that result is final: one that failed the gate is never granted a backpack or a pickaxe later on, and pickup.only-equipped (on by default) keeps "picked-up equipment" outside the gate as well.
- The plugin never assumes "every world runs on one main thread". Behaviour decisions, cooldowns, the backpack and counters all run on the region thread the mob itself belongs to; actual block changes (breaking, placing, pouring a fluid, priming TNT) are dispatched to the region thread that owns the target block.
- Gaining height uses an asynchronous teleport and then switches back to the mob's own thread to place the block, so the world is never touched from the wrong thread.
- As a result the same jar can be dropped into
plugins/as-is: it runs on Paper normally and does not error or crash on Folia because of cross-region access. The two server types need no separate builds. - Behaviour is added, not replaced: only a mining behaviour and a path-building behaviour are introduced, they claim movement and look control while active and hand control back to vanilla when they stop.
Blocks placed by mobs disappear after 15 seconds by default (placement.block-lifetime-seconds; 0 = permanent, source marking only). On Folia this cleanup is not "delete at the exact moment":
- Sweeping is a timed batch job: a global sweep runs every 20 ticks (1 second), then merges the expired blocks of the same chunk into one region task and deletes a whole batch at once. The real disappearance time is therefore the expiry time plus up to about 1 second (plus queueing in that region).
- A mob standing on it renews it: if a living entity (including a mob crossing the bridge) is within 1.2 blocks above the block at expiry, the block gets a full extra cycle. Bridges therefore do not collapse under a crossing mob — seeing a block live longer is intended.
- Material is re-checked before deletion: if a player replaced that block in the meantime, only the record is dropped and the block is not removed.
- Unloaded chunk means waiting: that entry is retried after 5 seconds and the record is not lost; it is removed once the chunk loads. That is why an old bridge can still be there when you return and then vanish shortly after.
-
Shutdown / uninstall fallback: every registered block (permanent ones included) is written to
plugins/MobInteract/pending-blocks.txt, deleted directly where possible and otherwise dispatched to the owning region; on the next start the list is cleaned again, covering a hard kill during shutdown. - The registry holds at most 50,000 entries and evicts the oldest in insertion order beyond that. On very busy servers, lowering
placement.block-lifetime-secondskeeps the registry smaller.
- If the chunk holding the block to change has no ready task queue at that moment, the submission fails; the plugin treats "did not go through" as a failure, enters a short
retry-secondscooldown and tries again instead of leaving a mining action "started but never finishing". - Expiry cleanup takes a different path when the chunk is unloaded: it retries after 5 seconds and keeps the record, rather than counting it as deleted.
- This is a soft dependency: having BlockLocker installed only affects load order, and nothing is affected when it is absent — the plugin never fails to start because of it.
- At startup the plugin tries to hook into BlockLocker's protection query. Once hooked, the mining, placement and block-destroying paths all skip blocks it protects — chests, doors, trapdoors, barrels and the like.
-
/mobinteract statusshows whether the hook is active ("BlockLocker protection: yes/no"), so check that line right after deploying. - A failed query is treated as "not protected" (fail-open) and warns only once per instance, so a broken BlockLocker cannot freeze mob behaviour entirely. Remember this when investigating grief reports: if BlockLocker itself breaks, mobs become able to open chests again.
- Other protection plugins (WorldGuard, Residence, ...) register a check through the extension point; with several registered, a single denial counts as protected, so a later registration never overrides an earlier one.
- Suggested rollout: enable
worlds.whitelistfor one small area first, confirm chests and doors stay untouched, then widen it to the whole server.
MobInteract · QQ 群 995974858 · Repository · Releases · Issues · English | 简体中文