New EntityTagUtil replaces the three copies of the tag/find/remove
logic for display and interaction entities. The pixel world naming
scheme (build, parse, recognize) now lives in one place in
PixelBlockWorld with a cached base path instead of allocating on every
event. getPixels works with int arithmetic instead of two Location
allocations per cell, setBuildingPlatform lost its copy-pasted loops
and rebuilds the flower list only once, SubCommand is an abstract base
class instead of an interface with 12 trivial getters, and dead
methods were removed.
Blocks destroyed before ever being entered no longer NPE on the null
entry location (new getReturnLocation fallback), destroy no longer
mutates the stored block location, placing an item whose block UUID
already exists cancels the event with a message instead of eating the
item, and pending task chains are flushed on shutdown. Failed block
initialization now propagates instead of leaving half-built blocks
registered. Listener null checks replaced requireNonNull, listener and
method name typos fixed, and the test-server copy path in build.gradle
is now a gradle property instead of a hardcoded home directory.
New /pixelblocks (alias /pb) with create, give, exit and destroyall
subcommands, each gated by a permission (exit defaults to true, the
rest to op). Fixes the args[0] crash and missing UUID validation in
give, and the offline-owner NPE plus concurrent-modification risk in
destroyall (destroy now takes a force flag that skips the ownership
check for admins). Also centralizes the item id tag in
PixelBlockItem.setBlockId and drops the overridden itemName leftover.
SQLite I/O no longer runs on the main server thread and the shared
PreparedStatements are confined to one thread. savePixelBlock captures
a snapshot of the block data on the calling thread. Main.pixelBlocks is
now a CopyOnWriteArrayList and list mutations moved out of async chains.
Blocks that fail to initialize on startup are skipped with a proper
error log instead of being registered half-built.