ModsJava
StolenItemAdmin
A plugin for searching items and blocks through the entire world and seeing people's inventories and enderchest
⬇ Download on Hangar# StolenItemAdmin
An admin toolkit for tracking down where stolen/stashed items have ended up, **without relying on
item tracing** - so it works retroactively on worlds that were never set up to trace anything.
Built on top of the original RecursiveInvSee inventory viewer.
Targets Paper / Folia build 26.1.2 (and should keep working on other builds in that 26.1+ line,
and reasonably far beyond it - see "Compatibility" below).
## WARNING: Made with AI
I am a random dev, and you should really not trust random stuff you find on the Internet. Take a
look at the source code (click the GitHub "view source" link on the side), and compile it
yourself with `mvn clean package` (requires Java JDK 21+ and Maven installed) if you'd rather not
trust a prebuilt jar.
Because offline inventory editing writes directly to a player's save file, **test on a throwaway
world/backup first**. A `.bak` copy of the `.dat` file is made automatically right before every
save as a safety net, but you're still editing raw player data outside of a running game session.
## Inventory / ender chest viewing
- `/invsee ` - view/edit a player's inventory, online or offline
- `/endersee ` - view/edit a player's ender chest, online or offline
Both are **recursive** (you can open shulker boxes and bundles found inside), work **even when
the target is offline** (edits are written straight to their `.dat` file, with an automatic
`.bak` backup taken first, and the player is prevented from logging in while being edited), and
are **Geyser/Floodgate-aware** so Bedrock accounts resolve too.
## Server-wide container & block search
Four commands, all opened in a **chest-style paginated GUI** (45 results per page with in-GUI
"previous/next page" buttons plus a natural-generation filter toggle) for any player who runs
them, sorted closest-first. Every scan covers the *entire server*, not just what's currently
loaded:
- `/chestfind [item_id] [x] [y] [z]` - lists every storage container on the *entire server*
(chests, trapped chests, barrels, shulker boxes, hoppers, dispensers, droppers, furnaces,
brewing stands, ...), closest to a point of your choosing first. Double chests are listed once,
with their combined contents. Usable from console (as a plain-text summary, printed once the
full scan finishes, since console has no inventory to open a GUI in). **Left-click a result to
teleport to it; right-click to open the container itself right there in the GUI** (recursively -
shulker boxes/bundles inside it open too, same as `/invsee`) without teleporting at all.
- `/chestfindnearby [item_id] [radius_x] [radius_y] [radius_z]` - the same, but always centred on
your current position, and can be narrowed to a box around you instead of the whole server.
Aliases: `/chests`, `/cfn`. Players only (it needs your location).
- `/blockfind [x] [y] [z]` - like `/chestfind`, but finds every occurrence of a
specific block instead of containers (the block id is mandatory). Alias: `/bf`.
- `/blockfindnearby [radius_x] [radius_y] [radius_z]` - a mix of `/blockfind` and
`/chestfindnearby`: mandatory block, centred on you, optional radius. Alias: `/bfn`.
The item/block id argument is optional wherever shown in brackets - e.g. `/chestfindnearby 50 50
50` goes straight to a 50-block radius search with no item filter, exactly like `/chestfindnearby
diamond 50 50 50` does with one. A single radius number (`/chestfindnearby 50`) applies uniformly
to all three axes; give three numbers for separate X/Y/Z radii.
Each result's tooltip shows its world, exact coordinates, distance from you, and (for containers)
how many slots are filled and how many of the searched-for item it holds.
### Hiding naturally-generated results
Between the previous/next page buttons sits a toggle button (a grey/lime dye) that hides or shows
results sitting inside a naturally-generated structure - villages, dungeons, mineshafts,
shipwrecks, temples, ruins, fortresses, bastions, end cities, ancient cities, trial chambers, and
so on. **It's off (hidden) by default**, so a fresh search starts by showing only things that
plausibly look player-placed, not vanilla loot generation. This needs no item tracing and works
immediately even on worlds that were already fully generated before this plugin was ever
installed - it reads three kinds of data Minecraft already permanently records, none of it
placement-tracking:
1. **Structure membership** - most loot-bearing structures (villages, mineshafts, temples,
fortresses, end cities, ...) are recorded per-chunk by the game itself
(`Chunk#getStructures()`), so "is this inside a generated structure's bounding box" is a direct,
reliable check. This also keeps working with most custom/plugin world generators, since it's
the same data vanilla's own structure-locate/map APIs rely on.
2. **Unresolved loot table** - a container nobody has opened yet still carries the loot table it
generated with (`Lootable#getLootTable()`), which Bukkit exposes directly. This catches natural
loot generically, including things structure membership alone can't (see next point) - but only
until the container is opened for the first time, since opening it resolves and clears the tag.
3. **Spawner proximity** - plain "dungeons" (the mossy-cobblestone monster-spawner room) are a
genuine gap in signal 1: they're a world-gen *feature*, not a jigsaw *structure* - not disabled
by the "Generate Structures" option and not findable with `/locate` either, confirmed against
Minecraft's own documentation. There is no structure entry to find for one. A dungeon chest
within a few blocks of its spawner is therefore treated as natural too, as a last-resort signal
for exactly the case where signal 2 no longer applies (an already-opened dungeon chest).
Toggling the filter is purely a display switch - every result is always found and collected
regardless of it, so switching it never triggers extra scanning.
This only reliably works for **containers**. For **blocks**, only ones inside a structure's
bounding box are ever marked natural - there's no equivalent for ordinary terrain generation like
ore veins, since vanilla doesn't record "this block came from worldgen" anywhere accessible
without regenerating the chunk against the world's seed. Blocks outside a structure are always
treated as "not natural" (shown), which is the safe default - it never hides something that might
be worth a closer look.
### Minimum-item filter
Also between the previous/next buttons (containers only - `/chestfind` and `/chestfindnearby`) is
a second toggle that opens a double-chest-sized editor: put items in it - say, 5 netherite blocks -
and close it, and the results list narrows to only containers holding **at least** that many of
**every** item you put in (aggregated across every slot in the container, ignoring things like
enchantments/durability/names - only material and amount matter). Put in nothing and close it to
clear the filter again. **Every item placed in the editor is always handed straight back to you
the moment you close it** - it's a scratch space for specifying criteria, not a real container;
nothing is ever kept or consumed, and if your own inventory happens to be full when it hands
things back, the leftover is dropped at your feet rather than lost. Like the natural-generation
filter, this needs no extra scanning: every container's full item breakdown was already recorded
when it was found, so the filter is purely a display-time narrowing.
### How the whole-server scan works
For a player, a scan happens in two phases, both feeding the *same already-open* GUI:
1. **Instant:** everything already loaded right now is scanned immediately, and the GUI opens with
those results as soon as that finishes - typically well under a second.
2. **Background, on demand:** every other chunk that was *ever generated and saved to disk* for
the world(s) being searched is found by reading region-file headers (cheap - no NBT parsing),
then loaded, scanned, and unloaded again in small throttled batches - but only as many as are
needed to stay one page ahead of whatever you're currently looking at. Once enough results
exist to fill the current page plus a lookahead page, the background scan pauses itself rather
than continuing to grind through the rest of the server for no one; turning to the next page
wakes it back up. The info item in the GUI reflects this ("Scanning...", "Paused - more results
available", or "Whole server scanned" once every chunk really has been covered). Closing the
GUI stops the background scan for good. Console has no paging to drive this, so a console-run
command always scans the *entire* server to completion before printing its one summary. Chunks
this scan itself loads are unloaded again afterwards; chunks that were already loaded for some
other reason are left alone, and a chunk is held with a temporary loading ticket for the whole
time it's being scanned so it can't be unloaded out from under the scan by the server itself.
Two tunables in `config.yml` control how fast/aggressive the background phase is (there is no cap
on how much of the server gets covered - only on how quickly):
```yaml
find:
max-results: 500 # how many results (closest first) are ever shown/paginated at once
chunk-batch-size: 50 # chunks loaded+scanned together per batch
chunk-batch-delay-ticks: 2 # delay between batches (20 ticks = 1s); raise to go easier on the server
```
A hardcoded (non-configurable) safety ceiling of 50,000 total matches also exists purely to avoid
running out of memory on something like a wide-open `/blockfind stone` - if you ever hit it, the
GUI will say so and the fix is narrowing the search (radius/coords, or a rarer block), not raising
a number.
Everything under `stolenitemadmin.find` gates these four commands; `stolenitemadmin.invsee` /
`stolenitemadmin.endersee` gate the two viewer commands; `stolenitemadmin.*` grants all of it. All
default to `op`.
## Compatibility / Folia notes
This plugin is written entirely against the standard Paper/Folia scheduler API
(`RegionScheduler`, `GlobalRegionScheduler`, `Entity#getScheduler()`), not internal Folia
classes, so the same jar runs correctly on both plain Paper and Folia:
- Container scans read live block state on each chunk's owning region thread (via
`Bukkit.getRegionScheduler()`), so contents are always current and thread-safe on Folia.
- Block-type scans only need block *types*, not live state, so the owning thread is used just to
take a cheap chunk snapshot; the actual (potentially large) block-by-block comparison then runs
off that thread entirely, so a big scan never blocks a region tick.
- The background phase loads not-yet-loaded chunks with the async chunk API
(`World#getChunkAtAsync`), never the blocking synchronous loader, and always unloads them again
through the owning region thread afterward.
- Region-file header reads (used to discover every chunk ever generated) are plain `java.io`
disk access on a small dedicated thread pool - not Bukkit/Paper API at all - so they never need
to run on any particular thread and never block a game/region thread.
- Teleporting to a result always uses `Player#teleportAsync`, which Folia requires for
cross-region/cross-world teleports and which behaves identically on plain Paper.
- GUI opening/closing/refreshing is always dispatched through the relevant player's own entity
scheduler.
StolenItemAdmin is a free Minecraft Java mod. Compatible with Minecraft 26.1, 26.1.1, 26.1.2, 26.2. Downloaded 1 times (via Hangar). Download it and open it directly in the game.