Skip to content

Custom Statuses, Navigator Categories, World Downloads & more

Latest

Choose a tag to compare

@thomasmny thomasmny released this 25 Aug 17:40
· 8 commits to master since this release
b40155d

BuildSystem 4.0.0 is a major release. World statuses and navigator categories are no longer hardcoded, worlds can be downloaded as single-player saves, physics can be controlled per behavior, and the developer API has been reworked. Existing data, config.yml and messages.yml are migrated automatically on first start.

Requirements

  • Java 25. Older runtimes will not start the plugin.
  • Minecraft 26.1 or newer.

Upgrading from 3.x? Read the Migration Guide first, especially if you have plugins built against buildsystem-api.

Highlights

  • Custom world statuses — Statuses are no longer a fixed list. Create, restyle, reorder and delete them in-game (/setup → World Statuses) or in statuses.yml. Each status has its own name, colour, icon, ordering, a building-allowed flag and an optional auto-progress target. The six built-ins are seeded on first start and can be changed or removed (never the last one). Assign with buildsystem.setstatus.<id>.
  • Navigator categories — The fixed public/archive/private tabs become categories you define. A category groups worlds by visibility and a set of statuses, with its own name, colour and icon. A world appears in every category that matches it. Create worlds in a category with buildsystem.create.category.<id>.
  • Navigator layout editor/setup → Navigator Layout arranges where each category and the settings button sit in the navigator. Pick a category up and drop it in a slot, drop it outside to remove it, drop it on the delete target to delete it, right-click to edit, or create a new one from the same screen. The status picker for /worlds setStatus uses the same editor.
  • Per-category commands — Every category gets a /worlds <category> shortcut, replacing the hardcoded /worlds archive, /worlds private and /worlds public. The three built-in categories still answer to those names. buildsystem.navigator.category.<id> (granted by default) controls both the shortcut and whether the category is shown.
  • World downloads/worlds download <world> (buildsystem.download) packs a world into a single-player save and sends a clickable link that expires with the archive. Served by a built-in HTTP server (storage: local) or as pre-signed S3 links (storage: s3). Off by default; enable under world.download in config.yml. Player data never leaves the server.
  • Per-world physics exceptions — While a world's physics are off, individual behaviors (block updates, connections, falling blocks, fluid flow, leaf decay, growth, spreading, block forming, block fading) can be re-allowed. Right-click the physics toggle in /worlds edit. Defaults live under world.defaults.physics-exceptions.
  • In-game /setup — A redesigned hub for default world-type icons, world statuses and the navigator layout, with a colour picker, a searchable item picker, skull-texture support and reset-to-defaults.

Added

  • Custom icons for worlds, folders and categories: a material or a player-head texture (%viewer% shows the viewer's own head). In /worlds edit, click the world item to pick a material or right-click a head icon to set its texture (buildsystem.edit.icon).
  • Pinned worlds (#319) sort above everything else in the navigator regardless of the active sort, with a configurable prefix. Toggle in the edit menu; buildsystem.edit.pin.
  • Custom seed on creation. Shift-click a world type in the create menu to enter a seed. Numbers are used as-is, other text is hashed, blank falls back to random.
  • /worlds saveTemplate <world> [name] (#449) copies a world into templates/ at runtime. buildsystem.savetemplate.
  • Configurable void-world block. world.void-block.enabled and world.void-block.material (default GOLD_BLOCK) control the block placed at the spawn of new void worlds. It is placed only when the world is first generated and never overwrites an existing block.
  • EssentialsX warps into unloaded worlds (#528). A warp pointing into a world BuildSystem had unloaded failed with "warp not found". BuildSystem now loads the target world before EssentialsX resolves the warp. Nothing to configure.
  • Per-option /settings permissions: buildsystem.setting.<option> (#250).
  • Per-template and per-generator create permissions: buildsystem.create.template.<name> and buildsystem.create.generator.<name> (#322, #323). Granted by default; deny a node to restrict it.
  • settings.world-permission-whitelist restricts what /worlds setPermission may assign.
  • World-editor toggles show their current value in the lore.
  • Import, unimport and deletion of a world are now logged to the console, like loading and unloading already were.

Changed

  • config.yml and messages.yml are versioned and migrated on load. Missing keys are added; existing values are kept.
  • External storage credentials move from world.backup.storage.<type> to a root storage section, and world.backup.storage.type becomes world.backup.storage. Backups and downloads share the credentials and each name their backend. Where files land moves with the feature (world.backup.path). Existing configs migrate automatically.
  • World limits: world.max-amount.* is now world.limits.* and the value is how many worlds one player may create of that visibility, not a server-wide count. buildsystem.create.<visibility>.<amount> overrides it, buildsystem.admin ignores it, and limits are counted per visibility. Values carry over.
  • world.disabled-physics is replaced by world.defaults.physics-exceptions (migrated automatically).
  • Two config flags are removed and ignored if present: settings.per-option-permissions (superseded by the always-on buildsystem.setting.<option> nodes) and settings.restrict-template-access (superseded by buildsystem.create.template.<name>).
  • Backups and downloads wait for Paper's chunk writer to finish before archiving, so an archive no longer contains half-written region files.
  • The shaded jar dropped from 32 MB to 4 MB.

Fixed

  • Paper 26.1: IncompatibleClassChangeError on org.bukkit.GameRule (#457), and support for the 26.1 world storage layout where every world is a dimension of the main level.
  • World renaming could destroy a world. A partly failed directory copy was logged, not reported, so the rename deleted the original and reported success. The copy now fails loudly and the original is kept. The same fix applies to template saving and creating a world from a template.
  • Backups: the first backup of a world failed because its directory was never created; /buildsystem reload left worlds bound to a closed S3/SFTP client; two backups of the same world no longer overlap; the default world's backup no longer includes every other world (and restoring it in place is refused, since that would delete every world on the server); AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and BUILDSYSTEM_SFTP_PASSWORD now actually work as credential sources.
  • World loading: a world with an unreadable difficulty no longer vanishes on load; settings missing from disk load with the defaults a new world gets instead of disabled or at epoch zero.
  • Bulk import: failed worlds are reported instead of silently dropped, and a world that throws mid-import no longer blocks every later importAll until restart. /worlds import -t and /worlds importAll -g with an unknown value now say so and stop instead of importing with the default.
  • Reset to defaults for statuses or categories now cascades like deleting one does, so folders in a discarded category no longer vanish until restart.
  • Disable interactions now covers every interactable block (crafter, trial spawner, vault, decorated pot, copper doors, pale oak doors, creaking heart and so on).
  • Clicks in the player's own inventory no longer trigger the menu button in the same slot.
  • /night on an unknown world reported the /day error.
  • Scoreboard placeholders were resolved off the main thread and once per line; now once per refresh, on the main thread.
  • settings.date-format uses java.time; an unparsable pattern logs a warning and falls back to dd/MM/yyyy.
  • Missing message keys used for lore are reported in the console.
  • Failed world-directory deletions are reported.
  • Main-thread safety for the NoClip block check, world-rename registry mutation and post-async skull updates; duplicate listener registration on reload; placeholder substitution is literal, not regex.
  • Path-traversal guards on template and world directories. A world name resolving outside the world container (for example ../../plugins/x) is rejected at creation and deletion, as are ./.. and Windows device names (#481).

Performance

  • Navigator armor stands are cached instead of scanned every tick.
  • The NoClip check no longer allocates a Location per tick.
  • Less allocation in scoreboard rendering, colour processing and the template menu.
  • World, folder and player file I/O run on one bounded background pool.

API

Recompile against buildsystem-api 4.0.0. The full list is in the Migration Guide; the short version:

  • Get the instance through BuildSystemProvider.get(); it is registered with Bukkit's ServicesManager.
  • BuildWorldStatus and NavigatorCategory are interfaces resolved through WorldStatusRegistry and NavigatorCategoryRegistry. Compare by getId()/equals(), never with == or switch.
  • World creation and import are fluent: WorldService.newWorld(name) / importWorld(name) ending in build(). WorldService.importWorlds() imports in bulk.
  • Type<T> and the per-setting getters/setters are gone; WorldData is accessed through typed keys: data.get(WorldDataKey.PERMISSION), data.set(WorldDataKey.BLOCK_BREAKING, true).
  • BuildWorld.getWorld() returns Optional<World>.
  • Private worlds are a Visibility (EVERYONE/ADDED_PLAYERS) on WorldData; isPrivateWorld()/setPrivateWorld() are gone.
  • BuildWorldManipulationEvent moved to de.eintosti.buildsystem.api.event.world, joined by BuildWorldCreateEvent, BuildWorldPostCreateEvent, BuildWorldDeleteEvent, BuildWorldPostDeleteEvent, BuildWorldUnimportEvent, BuildWorldRenameEvent and BuildWorldStatusChangeEvent, plus backup and folder events.
  • XSeries is gone from the public API. Icons are Bukkit Material; head textures are plain strings via Displayable.getIconSkullTexture().
  • Removed: BuildWorld.setLoaded(boolean), BuildWorld.asProfileable(), WorldData.getConfigFormat(), WorldData.getAllData(), and the public BuildSystemProvider.register()/unregister().

Migration

Everything below happens on the first 4.0.0 start with no manual steps:

  • Stored status names (IN_PROGRESS) become ids (in_progress); unknown values fall back to not_started.
  • The per-world private flag becomes a Visibility.
  • Folder categories (PUBLIC, ARCHIVE, PRIVATE) become the matching built-in category ids.
  • If statuses.yml does not exist yet, built-in statuses are seeded from your existing status_<id> keys in messages.yml. After that, statuses.yml is authoritative and the status_* message keys are unused.

Full Changelog: 3.0.2...4.0.0