Full attribution go to the source code shared on 2020 by Matt (/u/worldseed) in the r/MinecraftDataMining 's Discord server.
Additional Attributions go to https://github.com/TheWilley/Text2Book and https://github.com/ADP424/MinecraftBookConverter.
All changes are just vibe coded with help of Claude 4.5.
Option 1: JAR (All Platforms)
Download ReadSignsAndBooks.jar - Requires Java 21+
Run with:
java -Xmx10G -jar ReadSignsAndBooks.jarOption 2: Windows (No Java Required)
Download ReadSignsAndBooks-Windows.zip
-
Extract the ZIP file
-
Double-click
ReadSignsAndBooks.exeto open the GUI -
Or run from command line:
ReadSignsAndBooks.exe --world "C:\path\to\world"
This tool scans Minecraft world files and extracts:
-
Written books (with title and author), Writable books (book and quill), including:
-
Books in containers: chests, barrels, shulker boxes, bundles, item frames, minecarts, boats, and more
-
Books in containers of containers (e.g., inside bundles in frames, inside shulker boxes in chests)
-
Books in player inventories and ender chests
-
Duplicate tracking: Saves duplicate books to
.duplicates/folder instead of skipping them
-
-
Signs with text (all variants: regular, hanging, wall signs)
-
Rare Blocks: Search for any block type across dimensions
-
Nether portals: Find all portals with intelligent clustering (dimensions, center coordinates)
-
Find your Minecraft world folder:
-
Windows:
%appdata%\.minecraft\saves\YourWorldNameor%appdata%\ModrinthApp\profiles\FILLMEIN\saves\YourWorldName -
Mac:
~/Library/Application Support/minecraft/saves/YourWorldName -
Linux:
~/.minecraft/saves/YourWorldName
-
-
Run the tool:
java -jar ReadSignsAndBooks.jar --world "C:\Users\YourName\AppData\Roaming\.minecraft\saves\YourWorldName"
You can also run the ReadSignsAndBooks.jar directly from your world folder and run it - This does not work with double-clicking.
The tool creates output in ReadBooks/YYYY-MM-DD/:
-
books/- directory containing individual Stendhal format files for each unique book.-
Title_(PageCount)_by_Author~location~coords.stendhal, Example:My_Book_(3)_by_Joe~minecraft_chest~-10_65_20.stendhal -
.duplicates/- directory containing duplicate books (same content, different locations)
-
-
all_books.txt- concatenation of all books in Stendhal format (clean, formatting codes stripped)-
Separated by
#regionand#endregionmarkers for VSCode folding
-
-
all_books_raw.txt- same as above but with Minecraft formatting codes (§a, §l, etc.) preserved -
all_books.csv- CSV export of all books with metadata (clean, formatting codes stripped)-
Columns:
X,Y,Z,FoundWhere,Bookname,Author,PageCount,Generation,Pages -
Note/TODO: page boundaries lost; use
.stendhalfiles for full content for now
-
-
all_books_raw.csv- same as above but with Minecraft formatting codes preserved -
all_signs.txt- all signs found in the world, one per line-
Example Line:
Chunk [31, 31] (-2 75 -5) Line 1! ⚠ Line 2! ☀
-
-
all_signs.csv- CSV export of all signs with metadata (clean, formatting codes stripped)-
Columns:
X,Y,Z,FoundWhere,SignText,Line1,Line2,Line3,Line4 -
Note/TODO: For 1.20+ signs with front/back text, only front text is included in CSV (back text is preserved in datapack mcfunction files)
-
-
all_signs_raw.csv- same as above but with Minecraft formatting codes preserved -
readbooks_datapack_[1_13|1_14|1_20_5|1_21]/- Ready-to-use Minecraft datapacks (4 versions)-
pack.mcmeta- Datapack metadata with version-appropriate pack_format (4, 4, 41, 48) -
data/readbooks/[functions|function]/-functions/for pre-1.21,function/for 1.21+-
books.mcfunction-/givecommands to recreate all books -
signs.mcfunction-/setblockcommands with clickable teleport to original coordinates
-
-
-
signs.litematic- Litematica schematic file containing all extracted signs-
Signs placed in a grid layout at Y=0
-
First line of each sign is clickable to show original world coordinates
-
Click the coordinates to teleport to original location
-
Load with Litematica mod
-
-
books_commands.litematic- Litematica schematic with command blocks for book distribution-
Chain of command blocks that
/giveshulker boxes organized by author -
First block is impulse (needs redstone/button), rest are chain (auto-execute)
-
Each author gets a deterministic shulker box color
-
27 books max per shulker box, multiple boxes for prolific authors
-
Place the schematic and activate the first command block to receive all books
-
-
blocks.csv- CSV export of found blocks (when using--search-blocks) -
block_index.db- SQLite database of block coordinates (when using--search-blocks)-
See [Block Index Database] for schema and example queries.
-
-
portals.[csv|txt|json]- Portal detection output (when using--find-portals, format via--block-output-format)-
CSV:
dimension,x,y,z,width,height,axis,block_count,center_x,center_y,center_zExample
dimension,x,y,z,width,height,axis,block_count,center_x,center_y,center_z overworld,128,64,-256,4,5,X,20,129.5,66.0,-256.0 nether,16,8,-32,2,3,Z,6,16.0,9.0,-31.5
-
TXT: Human-readable report grouped by dimension
Example
Nether Portal Detection Report ================================================================================ Total portals found: 2 OVERWORLD (1 portals): ---------------------------------------- Portal #1: Anchor: (128, 64, -256) Size: 4x5 (20 blocks) Axis: X Center: (129.5, 66.0, -256.0) NETHER (1 portals): ---------------------------------------- Portal #2: Anchor: (16, 8, -32) Size: 2x3 (6 blocks) Axis: Z Center: (16.0, 9.0, -31.5) -
JSON: Structure with
portalsarray andsummaryobjectExample
{ "portals": [ {"id":1,"dimension":"overworld","x":128,"y":64,"z":-256,"width":4,"height":5,"axis":"X","block_count":20}, {"id":2,"dimension":"nether","x":16,"y":8,"z":-32,"width":2,"height":3,"axis":"Z","block_count":6} ], "summary": { "total_portals": 2, "by_dimension": { "overworld": 1, "nether": 1 } } }
-
-
logs.txt- program debug logs -
summary.txt-
Breakdown by container type (chests, shulker boxes, villagers, etc.)
-
Breakdown by location type (block entities, entities, players)
-
Processing time and performance metrics
-
The generated datapacks can be directly copied into your Minecraft world:
-
Copy the appropriate datapack folder for your Minecraft version:
# Example: For Minecraft 1.21+ cp -r ReadBooks/YYYY-MM-DD/readbooks_datapack_1_21 ~/.minecraft/saves/YourWorldName/datapacks/
-
In Minecraft, reload datapacks:
/reload
You should see a message confirming the datapack was loaded.
-
Run the function to get all books:
/function readbooks:books
-
Run the function to place all signs at your current position:
/function readbooks:signs
The tool generates Litematica .litematic files that can be loaded with the Litematica mod:
-
Install Litematica for your Minecraft version (requires Fabric or similar loader)
-
Load the schematic:
-
Open Litematica menu (default:
Mkey) -
Go to "Load Schematics"
-
Navigate to your
ReadBooks/YYYY-MM-DD/folder -
Select
signs.litematicorbooks_commands.litematic
-
-
For signs:
-
Place the schematic where you want the signs
-
Use Litematica’s paste or build mode to place blocks
-
Click the first line of any sign to see its original coordinates
-
Click the coordinates to teleport to that location
-
-
For books:
-
Place the command block chain schematic
-
Power the first (impulse) command block with a button or lever
-
All shulker boxes will be given to nearby players
-
Break open the shulker boxes to access the books
-
Find all nether portals in your world:
java -jar ReadSignsAndBooks.jar --world "path/to/world" --find-portalsWhen you use --search-blocks, the tool automatically builds a SQLite database (block_index.db) storing all found block coordinates.
java -jar ReadSignsAndBooks.jar --world "path/to/world" --search-blocks "diamond_ore,emerald_ore"Options:
-
--search-blocks "block1,block2"- Search for specific block types -
--search-dimensions "overworld,nether,end"- Dimensions to search -
--block-output-format csv|json|txt- Output format (default: csv) -
--index-limit N- Maximum blocks per type to store (default: 5000)
The program contains sqlite wrapper functions for querying the block index database, if you don’t have sqlite client.
Invoking these does not re-scan the world, and can also be invoked without the --world flag by just using the --output flag.
-
--index-query BLOCK_TYPE- Query existing database for block locationsjava -jar ReadSignsAndBooks.jar --world "path/to/world" --index-query "nether_portal"
-
--index-list- Display summary of all indexed block typesjava -jar ReadSignsAndBooks.jar --output "path/to/world/ReadBooks" --index-listExample output:
Block Index Summary: minecraft:chest: 156 blocks (limit: 5000) minecraft:nether_portal: 48 blocks (limit: 5000) minecraft:spawner: 12 blocks (limit: 5000) Total: 3 block types, 216 blocks indexed
The block_index.db file is a standard SQLite database that you can open with any SQLite client (DB Browser for SQLite, DBeaver, command-line sqlite3, etc.).
Database Schema
-- Main blocks table with coordinates
CREATE TABLE blocks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
block_type TEXT NOT NULL, -- e.g., "minecraft:chest"
dimension TEXT NOT NULL, -- "overworld", "nether", or "end"
x INTEGER NOT NULL,
y INTEGER NOT NULL,
z INTEGER NOT NULL,
properties TEXT, -- JSON block state properties
region_file TEXT, -- Source region file (e.g., "r.0.0.mca")
UNIQUE(block_type, dimension, x, y, z)
);
-- Summary table for fast counts
CREATE TABLE block_summary (
block_type TEXT PRIMARY KEY,
total_found INTEGER, -- Total blocks found (even if limit reached)
indexed_count INTEGER, -- Blocks actually stored in database
limit_reached INTEGER -- 1 if limit was hit, 0 otherwise
);
-- Metadata (index limit, creation time, etc.)
CREATE TABLE metadata (
key TEXT PRIMARY KEY,
value TEXT
);Example Queries:
-- Find all chests in the Nether
SELECT x, y, z FROM blocks WHERE block_type = 'minecraft:chest' AND dimension = 'nether';-- Count blocks by type
SELECT block_type, COUNT(*) as count FROM blocks GROUP BY block_type ORDER BY count DESC;-- Find blocks near coordinates (within 100 blocks of spawn)
SELECT * FROM blocks WHERE x BETWEEN -100 AND 100 AND z BETWEEN -100 AND 100;-- Check which block types hit the limit
SELECT block_type, total_found, indexed_count FROM block_summary WHERE limit_reached = 1;gradle buildRun directly with Gradle:
gradle run --args="--world /path/to/world"To use custom JVM arguments for large worlds:
gradle run "-Dorg.gradle.jvmargs=-Xmx10G -XX:+UseG1GC -XX:MaxGCPauseMillis=200" --args="--world /path/to/world"The integration test uses real minecraft world(s).
gradle testAfterwards, you can look at the generated files in the build/test-worlds/*/ReadBooks/ folder, e.g. ./build/test-worlds/1_21_10-44-3/ReadBooks/

