Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📚 AGHPB Minecraft Plugin

Bringing anime girls holding programming books straight onto your Minecraft maps!

Spigot Kotlin Maven License

This is a Spigot/Bukkit plugin that lets you fetch images from the web, including random anime girls holding programming books from the AGHPB API, and render them onto in-game Minecraft maps.

It supports splitting a single image across a grid of multiple maps (auto-scaling to fit), permanently persists rendered maps across server restarts, caches downloaded images locally to avoid redundant network calls, and lets you pick from a list of known AGHPB instances or supply your own.

Written entirely in Kotlin with zero external dependencies beyond the Kotlin standard library and the Spigot API itself -> no image libraries, no HTTP clients, no JSON parsers.

🌐 Supported AGHPB instances

Pick the closest instance to you for FASTER ANIME GIRLS! Configurable via config.yml or in-game with /aghpb instance.

Country URL Hosted by Notes
🇬🇧 https://api.devgoldy.xyz/aghpb/v1 DevGoldy ⭐ Official Instance (default)
🇸🇪 https://aghpb.zeeraa.net Zeeraa Backup

You can also point the plugin at a self-hosted instance, or any other AGHPB-compatible server, via /aghpb instance set <url>.

✨ Features

  • Any image, any URL -> render any web-hosted image onto maps, not just AGHPB books (aghpb.url permission required)
  • Random AGHPB books -> fetch a random book, optionally filtered by category
  • Configurable map grids -> split a single image across a W x H grid of maps (up to a configurable maximum), or keep it to a single 128×128 map; images are automatically scaled and letterboxed to fit
  • True persistence -> rendered maps survive server restarts by saving each tile to disk and actively reattaching renderers on startup, not relying on unreliable Bukkit map-load events
  • Local image cache -> downloaded images are cached to disk (SHA-256 keyed, with configurable TTL) so repeat fetches of the same URL don't hit the network again
  • Named map items -> each map item is labeled with the book/image name, with grid position suffixed when split across multiple maps
  • Instance selection -> switch between configured AGHPB instances or supply a custom base URL per-player
  • Optimized rendering -> uses direct pixel writes (MapCanvas.setPixelColor) instead of legacy palette-matched image drawing, scaling much better on large grids
  • No external dependencies -> HTTP via java.net.HttpURLConnection, images via javax.imageio, both bundled with the JVM

📦 Installation

  1. Download or build aghpb-1.0.0.jar (see Building below)
  2. Drop it into your server's plugins/ folder
  3. Restart or start your Spigot 1.21.x server
  4. Edit plugins/AGHPB/config.yml to taste, then /aghpb reload

Requirements

  • Spigot/Paper 1.21.x
  • Java 21+

🕹️ Commands

All commands require the aghpb.use permission (default: op).

Command Description
/aghpb random [category] [WxH] Fetch a random book, optionally by category, rendered across an optional WxH map grid
/aghpb url <imageUrl> [WxH] Render any image from a URL onto a map grid (requires aghpb.url)
/aghpb instance list List configured AGHPB instances and which one is currently active
/aghpb instance set <index|url> Switch to a listed instance by index, or supply your own custom base URL
/aghpb categories List all available book categories from the current instance
/aghpb info Show stats about the current instance (book count, version, repo hash, etc.)
/aghpb reload Reload config.yml (requires aghpb.admin)
/aghpb version Show the plugin's version and server's Bukkit version
/aghpb about Show credits and plugin information
/aghpb help Show the command list

Grid format is WxH, e.g. 2x3 = 2 maps wide, 3 maps tall (256×384 pixels total). Each individual map is 128×128 pixels.

Examples

/aghpb random
/aghpb random rust 2x2
/aghpb url https://example.com/image.png 3x2
/aghpb instance list
/aghpb instance set 1
/aghpb instance set https://my-self-hosted-aghpb.example.com

🔐 Permissions

Permission Description Default
aghpb.use Use /aghpb commands op
aghpb.admin Reload the config op
aghpb.url Fetch images from arbitrary custom URLs (not just AGHPB) op

⚙️ Configuration

plugins/AGHPB/config.yml:

# Default grid size for image rendering.
# Each map is 128x128 pixels. A 2x2 grid = 256x256 total.
default-grid:
  width: 1  # Number of maps horizontally
  height: 1 # Number of maps vertically

# Maximum allowed grid size (to prevent abuse)
max-grid:
  width: 8
  height: 8

# Timeout in milliseconds for HTTP requests
http-timeout-ms: 8000

# Known AGHPB public instances.
# The first entry is used as default.
# Players can also supply a custom URL via command.
aghpb-instances:
  - name: "Official (UK)"
    url: "https://api.devgoldy.xyz/aghpb/v1"
  - name: "Zeeraa (SE)"
    url: "https://aghpb.zeeraa.net"

# Default instance index (0-based, refers to list above)
default-instance: 0

# Local disk cache for downloaded images (avoids re-downloading identical URLs).
image-cache:
  enabled: true
  ttl-minutes: 1440 # 0 = never expire

# Persisted maps (rendered tiles saved to disk, restored on server restart)
persistence:
  enabled: true

🏗️ How it works

Rendering pipeline

  1. An image is fetched, either a random AGHPB book via AGHPBClient, or an arbitrary URL via ImageFetcher (checking ImageCache first)
  2. ImageScaler scales the source image to fit the requested W x H grid (letterboxed, aspect-ratio preserved) and slices it into 128×128 tiles
  3. On the main thread, one MapView is created per tile via Bukkit.createMap(), with an ImageMapRenderer attached that writes pixels directly via MapCanvas.setPixelColor
  4. Each map item is named after the source image/book, suffixed with its grid position when tiled (e.g. Some Book [2,1 of 2x2])
  5. Maps are given to the player's inventory, overflow dropped on the ground

Persistence

Bukkit doesn't serialize custom MapRenderer instances across restarts, and MapInitializeEvent only fires the first time a map is ever loaded into memory -> it's not a reliable "server just started" signal. To work around this, every rendered tile is saved to disk as a PNG keyed by map ID (plugins/AGHPB/cache/maps/<id>.png), and on plugin startup MapPersistence.restoreAll() actively looks up every persisted map via Bukkit.getMap(id) and reattaches its renderer -> guaranteeing your maps come back exactly as rendered, every restart.

Caching

Downloaded image bytes are cached on disk under plugins/AGHPB/cache/images/, keyed by the SHA-256 hash of the source URL, with a configurable TTL. Random AGHPB fetches are intentionally not cached, since each request is meant to return a different book.

🛠️ Building

Prerequisites

  1. Clone the repo
    git clone https://github.com/thenolle/aghpb.mc && cd aghpb.mc
  2. Build with Maven
    mvn clean package
  3. Grab the shaded jar
    cp target/aghpb-1.0.0.jar /path/to/server/plugins/

💫 Credits

📜 License

WTFPL - Do whatever the f*ck you want


Made with 🩵 by Nolly

About

Bringing Anime Girls Holding Programming Books straight onto your Minecraft maps!

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Contributors

Languages