
Список изменений
Better Color Matching
The color lookup cache has been reduced from 8-bit to 7-bit resolution (CACHE_BITS changed from 8 to 7). This cuts the memory used by the color cache significantly, from 16 MB down to around 2 MB, while still providing fast color lookups. In practice, the visual difference is negligible since the CIEDE2000 matching still runs for any edge cases.
The pre-filtering threshold used when searching for the closest palette color has also been tightened (from bestLabEuc * 6.0 + 200.0 down to bestLabEuc * 3.0 + 100.0). This means fewer candidate colors are evaluated with the expensive CIEDE2000 formula, speeding up uncached lookups without meaningfully affecting accuracy. Colors that were far off were never going to win anyway.
Better Transparency Handling
Transparent pixels in all three dithering modes (Fast, Balanced, and High) now map to color index 4 instead of 0. Previously, transparent areas would render as whatever color index 0 happened to be (black), which could cause visual artifacts. Index 4 is the first valid map color, which produces more predictable results when transparency is present in an image.
Better GIF Rendering
GIF processing no longer resizes the entire frame at once and then slices it into grid cells. Instead, each grid cell is extracted from the source frame at its native resolution and resized individually to 128x128. This avoids allocating one large pixel array for the full composite image on every frame, which reduces memory pressure especially for large grids.
The GIF reader now properly reads the background color from the GIF's global color table. When a frame uses the "restore to background color" disposal method, the canvas is now filled with the actual background color specified in the file rather than just clearing to transparent. This fixes rendering glitches on certain GIFs where frames would show holes or incorrect colors between transitions.
Faster Item Frame Detection
The frame grid detection (finding connected item frames for multi-map displays) has been completely rewritten. Before, it searched for neighboring frames by scanning all nearby entities at each BFS step, which could be slow when many entities were in the area. Now, it does a single entity query up front, builds a position lookup map, and then walks the grid using direct coordinate lookups. This is noticeably faster on servers with lots of entities near the item frames.
Smarter GIF Compression
Animation grid compression now uses BEST_SPEED instead of BEST_COMPRESSION for the deflate step. GIF animation data can be very large, and the difference in final file size between the two levels is usually small, while the speed improvement during save is significant. Static map and grid compression still use DEFAULT_COMPRESSION, which is a reasonable middle ground (changed from the previous BEST_COMPRESSION).
Safer Network Requests
DNS resolution for image downloads now runs with a 5-second timeout. Previously, if a hostname took a long time to resolve (or hung indefinitely), the download thread would block with no upper bound. This applies to both the initial URL and any redirect targets. Interrupted and failed DNS lookups now produce clear error messages instead of generic connection failures.
Better Caching Internals
The GIF cache has been switched from a ConcurrentHashMap to a synchronized LinkedHashMap with access-order tracking. This means eviction of the oldest entry is now O(1) instead of requiring a full scan of all entries to find the least-recently-used one. All cache operations are properly synchronized, and the eviction logic is cleaner. The external behavior and limits (20 entries, 100 MB cap, 30-minute expiry) are unchanged.
Smoother Map Initialization
When multiple maps initialize at the same time (common during server startup or world loading), the plugin previously scheduled a separate delayed task for each one. Now, it batches them. Map IDs are collected into a pending set, and a single task applies all of them on the next tick. This reduces scheduler overhead when loading large numbers of saved maps.
Delayed Update Checker Startup
The update checker no longer fires immediately on plugin enable. It now waits 5 seconds (100 ticks) before initializing, which avoids adding network requests to the server's startup sequence. The periodic re-check also guards against overlapping checks with a checkInProgress flag.
Cooldown Map Cleanup
The per-player command cooldown map now periodically prunes expired entries. Previously, cooldown timestamps accumulated forever (one entry per player UUID that ever ran a command). Now, stale entries are cleaned up roughly every 5 minutes, keeping the map small on busy servers.
Other Changes
- The GIF animation tick now skips all work when no players are online, avoiding unnecessary frame calculations on empty servers.
- The
DIRTY_BUFFERstatic list inGifRendererwas replaced with a local list created each tick, removing shared mutable state between ticks. - The
render()method inGifRenderernow delegates tosetMapView()instead of duplicating the map registration logic inline. - The shutdown sequence in
EmageManagernow shuts down the scheduler before the IO executor, ensuring no new tasks are scheduled while draining. - The High quality dithering mode no longer uses serpentine (alternating left-to-right) scanning. It now always scans left-to-right. This is a subtle behavioral change that may slightly affect the appearance of high-quality dithered images.
- The GitHub owner in the update checker URL changed from
EdithyLikesToCodetoEd1thy.
