Skip to content

Commit d23859e

Browse files
committed
Improve the handling of layers.
1 parent 3b88e50 commit d23859e

File tree

10 files changed

+238
-98
lines changed

10 files changed

+238
-98
lines changed

Item Creator/src/main/java/org/broken/arrow/library/itemcreator/meta/map/BuildMapView.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import org.broken.arrow.library.itemcreator.ItemCreator;
5+
import org.broken.arrow.library.itemcreator.meta.map.pixel.MapPixel;
56
import org.broken.arrow.library.itemcreator.utility.FormatString;
67
import org.bukkit.Bukkit;
78
import org.bukkit.World;
@@ -13,11 +14,10 @@
1314
import javax.annotation.Nullable;
1415
import java.lang.reflect.Method;
1516
import java.util.ArrayList;
16-
import java.util.HashSet;
17+
import java.util.HashMap;
1718
import java.util.List;
18-
import java.util.Set;
19+
import java.util.Map;
1920
import java.util.function.Consumer;
20-
import java.util.stream.Collectors;
2121

2222
/**
2323
* A builder and wrapper for {@link MapView} instances, providing enhanced
@@ -204,10 +204,11 @@ public MapRendererData addRenderData(@Nonnull final Consumer<MapRendererData> da
204204
* @param cache the cache to get the image.
205205
*/
206206
public void addCachedPixels(final int cacheId, @Nonnull MapRendererDataCache cache) {
207-
final MapRendererDataCache.PixelCacheEntry mapRendererData = cache.get(cacheId);
208-
if (mapRendererData == null)
207+
final MapRendererDataCache.PixelCacheEntry pixelCacheEntry = cache.get(cacheId);
208+
if (pixelCacheEntry == null)
209209
return;
210-
this.renderer.getPixels().addAll(mapRendererData.getPixels());
210+
this.renderer.replaceLayer(cacheId, pixelCacheEntry.getPixels());
211+
cache.onUpdate(() -> this.renderer.replaceLayer(cacheId, pixelCacheEntry.getPixels()));
211212
}
212213

213214
/**

Item Creator/src/main/java/org/broken/arrow/library/itemcreator/meta/map/MapRendererData.java

Lines changed: 99 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,19 @@
3939
*
4040
* <strong>Overlay Render Order</strong>
4141
* <p>
42-
* Overlays are rendered <strong>in the exact order they are added</strong>.
43-
* The first overlay added becomes the bottom layer, and subsequent overlays
42+
* Overlays are rendered <strong>after what layer they are added</strong>.
43+
* The lowest number becomes the bottom layer, and subsequent overlays
4444
* are drawn on top of it. This applies to all overlay types:
4545
* {@link MapColoredPixel}, {@link TextOverlay}, {@link ImageOverlay}, and others.
4646
* </p>
4747
*
48-
* <p>Example: calling {@code addImage()} followed by {@code addText()} will render
49-
* the image as a background and the text above it.
50-
* </p>
5148
*
5249
*/
5350
public class MapRendererData {
5451
private static int id;
5552
private final int mapRenderId;
5653
private final MapRenderer mapRenderer;
54+
private final Map<Integer, List<MapPixel>> layers = new HashMap<>();
5755
private final List<MapPixel> pixels = new ArrayList<>();
5856
private MapCursorAdapter mapCursors = new MapCursorAdapter();
5957

@@ -97,36 +95,43 @@ public void setDynamicRenderer(MapRenderHandler handler) {
9795
*
9896
* <p>See {@link MapRendererData} documentation for details on overlay layering.</p>
9997
*
98+
* @param layer the layer you want to set the pixel, higher number means it will be
99+
* rendered higher up.
100100
* @param x The x-coordinate of the pixel.
101101
* @param y The y-coordinate of the pixel.
102102
* @param color The color of the pixel.
103103
*/
104-
public void addPixel(int x, int y, Color color) {
105-
pixels.add(new MapColoredPixel(x, y, color));
104+
public void addPixel(int layer, int x, int y, Color color) {
105+
this.addPixel(layer, new MapColoredPixel(x, y, color));
106106
}
107107

108108
/**
109109
* Adds a colored pixel overlay to the map.
110110
*
111111
* <p>See {@link MapRendererData} documentation for details on overlay layering.</p>
112+
*
113+
* @param layer the layer you want to set the pixel, higher number means it will be
114+
* rendered higher up.
112115
* @param mapColoredPixel The {@link MapColoredPixel} to add.
113116
*/
114-
public void addPixel(@Nonnull final MapColoredPixel mapColoredPixel) {
115-
pixels.add(mapColoredPixel);
117+
public void addPixel(int layer, @Nonnull final MapColoredPixel mapColoredPixel) {
118+
this.addMapPixel(layer, mapColoredPixel);
116119
}
117120

118121
/**
119122
* Adds a text overlay to the map without a custom font character sprite.
120123
*
121124
* <p>See {@link MapRendererData} documentation for details on overlay layering.</p>
122125
*
123-
* @param x The x-coordinate of the text.
124-
* @param y The y-coordinate of the text.
125-
* @param text The text to display.
126+
* @param layer the layer you want to set the text, higher number means it will be
127+
* rendered higher up.
128+
* @param x The x-coordinate of the text.
129+
* @param y The y-coordinate of the text.
130+
* @param text The text to display.
126131
* @return returns the newly created text overlay, so you could set some of the options after.
127132
*/
128-
public TextOverlay addText(final int x, int y, @Nonnull final String text) {
129-
return this.addText(x, y, text, null, null);
133+
public TextOverlay addText(int layer, final int x, int y, @Nonnull final String text) {
134+
return this.addText(layer, x, y, text, null, null);
130135
}
131136

132137
/**
@@ -135,37 +140,41 @@ public TextOverlay addText(final int x, int y, @Nonnull final String text) {
135140
*
136141
* <p>See {@link MapRendererData} documentation for details on overlay layering.</p>
137142
*
138-
* @param x The x-coordinate of the text.
139-
* @param y The y-coordinate of the text.
140-
* @param text The text to display.
141-
* @param font The font for the character.
143+
* @param layer the layer you want to set the text, higher number means it will be
144+
* rendered higher up.
145+
* @param x The x-coordinate of the text.
146+
* @param y The y-coordinate of the text.
147+
* @param text The text to display.
148+
* @param font The font for the character.
142149
* @return returns the newly created text overlay, so you could set some of the options after.
143150
*/
144-
public TextOverlay addText(final int x, int y, @Nonnull final String text, @Nullable final Font font) {
145-
return this.addText(x, y, text, null, font);
151+
public TextOverlay addText(int layer, final int x, int y, @Nonnull final String text, @Nullable final Font font) {
152+
return this.addText(layer, x, y, text, null, font);
146153
}
147154

148155
/**
149156
* Adds a text overlay to the map with a custom font character sprite.
150157
*
151158
* <p>See {@link MapRendererData} documentation for details on overlay layering.</p>
152159
*
160+
* @param layer the layer you want to set the text, higher number means it will be
161+
* rendered higher up.
153162
* @param x The x-coordinate of the text.
154163
* @param y The y-coordinate of the text.
155164
* @param text The text to display.
156165
* @param fontChars Set the characters you want to replace in your text with the font.
157166
* @param font The font for the character
158167
* @return returns the newly created text overlay, so you could set some of the options after.
159168
*/
160-
public TextOverlay addText(final int x, int y, @Nonnull final String text, @Nullable final char[] fontChars, @Nullable final Font font) {
169+
public TextOverlay addText(final int layer, final int x, int y, @Nonnull final String text, @Nullable final char[] fontChars, @Nullable final Font font) {
161170
TextOverlay textOverlay = new TextOverlay(x, y, text);
162171
if (font != null) {
163172
if (fontChars != null && fontChars.length > 0) {
164173
this.fontChars = fontChars;
165174
}
166175
textOverlay.setMapFont(this.fontChars, font);
167176
}
168-
this.addText(textOverlay);
177+
this.addText(layer, textOverlay);
169178
return textOverlay;
170179
}
171180

@@ -174,10 +183,12 @@ public TextOverlay addText(final int x, int y, @Nonnull final String text, @Null
174183
*
175184
* <p>See {@link MapRendererData} documentation for details on overlay layering.</p>
176185
*
186+
* @param layer the layer you want to set the text, higher number means it will be
187+
* rendered higher up.
177188
* @param textOverlay The {@link TextOverlay} instance to add.
178189
*/
179-
public void addText(@Nonnull final TextOverlay textOverlay) {
180-
pixels.add(textOverlay);
190+
public void addText(final int layer, @Nonnull final TextOverlay textOverlay) {
191+
this.addMapPixel(layer, textOverlay);
181192
}
182193

183194

@@ -202,12 +213,14 @@ public void addText(@Nonnull final TextOverlay textOverlay) {
202213
*
203214
* <p>See {@link MapRendererData} documentation for details on overlay layering.</p>
204215
*
216+
* @param layer the layer you want to set the text, higher number means it will be
217+
* rendered higher up.
205218
* @param x the top-left X position on the map (0–127)
206219
* @param y the top-left Y position on the map (0–127)
207220
* @param image the image to draw at the given position
208221
*/
209-
public void addImage(final int x, final int y, @Nonnull final Image image) {
210-
pixels.add(new ImageOverlay(x, y, image));
222+
public void addImage(final int layer, final int x, final int y, @Nonnull final Image image) {
223+
this.addImage(layer, new ImageOverlay(x, y, image));
211224
}
212225

213226
/**
@@ -217,8 +230,6 @@ public void addImage(final int x, final int y, @Nonnull final Image image) {
217230
* occurs inside {@link ImageOverlay}. More advanced preprocessing—such
218231
* as color rebalancing or pixel conversion—is performed only when using
219232
* {@link MapRendererDataCache} instead of adding images directly.
220-
* See {@link #addText(TextOverlay)} for additional details about the
221-
* caching workflow.
222233
* </p>
223234
*
224235
* <p><strong>Note:</strong> Adding raw images directly may introduce a performance
@@ -228,10 +239,12 @@ public void addImage(final int x, final int y, @Nonnull final Image image) {
228239
*
229240
* <p>See {@link MapRendererData} documentation for details on overlay layering.</p>
230241
*
242+
* @param layer the layer you want to set the text, higher number means it will be
243+
* rendered higher up.
231244
* @param imageOverlay the preconfigured {@link ImageOverlay} to add
232245
*/
233-
public void addImage(@Nonnull final ImageOverlay imageOverlay) {
234-
pixels.add(imageOverlay);
246+
public void addImage(final int layer, @Nonnull final ImageOverlay imageOverlay) {
247+
this.addMapPixel(layer, imageOverlay);
235248
}
236249

237250
/**
@@ -282,39 +295,41 @@ public MapCursorWrapper addCursor(@Nonnull final MapCursorWrapper cursorWrapper)
282295
}
283296

284297
/**
285-
* Adds a collection of map overlays (pixels, text, or images) to this renderer.
298+
* Sets a collection of map overlays (pixels, text, or images) to this renderer.
286299
* <p>
287-
* This method appends the provided overlays to the existing pixel list
288-
* without clearing previous entries. It can be used to add multiple
289-
* overlay types at once or to batch-apply preprocessed render data.
300+
* This method appends the provided overlays and replace the existing pixel list.
301+
* It can be used to add multiple overlay types at once or to batch-apply
302+
* preprocessed render data.
290303
* </p>
291304
*
292305
* <p><strong>Note:</strong> For most use cases, prefer the more specific
293-
* methods such as {@link #addPixel(int, int, Color)},{@link #addText(int, int, String)}
294-
* or {@link #addImage(int, int, Image)} for clarity.</p>
306+
* methods such as {@link #addPixel(int, int, int, Color)} ,{@link #addText(int, int, int, String)} }
307+
* or {@link #addImage(int, int, int, Image)}} for clarity.</p>
295308
*
296309
* <p>See {@link MapRendererData} documentation for details on overlay layering.</p>
297310
*
298-
* @param mapPixels the list of {@link MapPixel} instances to add
311+
* @param layer the layer you want to set the text, higher number means it will be
312+
* rendered higher up.
313+
* @param pixels the list of {@link MapPixel} instances to replace the layer wioth
299314
*/
300-
public void addAll(List<MapPixel> mapPixels) {
301-
this.pixels.addAll(mapPixels);
315+
public void replaceLayer(int layer, List<MapPixel> pixels) {
316+
layers.put(layer, new ArrayList<>(pixels));
302317
}
303318

304319
/**
305-
* Clear the list of set pixels.
320+
* Clear the map of set pixels.
306321
*/
307322
public void clear() {
308-
this.pixels.clear();
323+
this.layers.clear();
309324
}
310325

311326
/**
312-
* Returns {@code true} if this list contains no elements.
327+
* Returns {@code true} if this map contains no key-value mappings.
313328
*
314-
* @return {@code true} if this list of pixels contains no elements
329+
* @return {@code true} if this map of pixels contains no mappings.
315330
*/
316331
public boolean isPixelsEmpty() {
317-
return this.pixels.isEmpty();
332+
return this.layers.isEmpty();
318333
}
319334

320335
/**
@@ -383,13 +398,29 @@ public MapCursorAdapter getMapCursors() {
383398
return mapCursors;
384399
}
385400

401+
402+
/**
403+
* Returns the current collection of map pixels.
404+
*
405+
* @return The {@link Map} that contains a list of map pixels set for every layer.
406+
*/
407+
public Map<Integer, List<MapPixel>> getLayers() {
408+
return layers;
409+
}
410+
386411
/**
387412
* Returns the current collection of map pixels.
388413
*
389-
* @return The {@link MapCursorAdapter} managing pixels.
414+
* @return The {@link Map} that contains a list of map pixels set for every layer.
390415
*/
391416
public List<MapPixel> getPixels() {
392-
return pixels;
417+
List<MapPixel> all = new ArrayList<>();
418+
419+
layers.entrySet().stream()
420+
.sorted(Map.Entry.comparingByKey())
421+
.forEach(e -> all.addAll(e.getValue()));
422+
423+
return all;
393424
}
394425

395426
/**
@@ -409,7 +440,7 @@ public void render(@Nonnull MapView map, @Nonnull MapCanvas canvas, @Nonnull Pla
409440
return;
410441
canvas.setCursors(mapCursors.getMapCursorCollection());
411442

412-
if (!getPixels().isEmpty()) {
443+
if (!isPixelsEmpty()) {
413444
setPixels(canvas);
414445
}
415446
}
@@ -438,7 +469,7 @@ public int hashCode() {
438469
public Map<String, Object> serialize() {
439470
Map<String, Object> map = new HashMap<>();
440471
map.putAll(mapCursors.serialize());
441-
map.put("pixels", this.pixels.stream().map(MapPixel::serialize).collect(Collectors.toList()));
472+
map.put("pixels", this.layers.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, mapPixels -> mapPixels.getValue().stream().map(MapPixel::serialize))));
442473
return map;
443474
}
444475

@@ -463,13 +494,22 @@ public static MapRendererData deserialize(Map<String, Object> map) {
463494
if (pixels instanceof List<?>) {
464495
for (Object pixel : (List<?>) pixels) {
465496
Map<String, Object> pixelMap = (Map<String, Object>) pixel;
466-
String type = (String) pixelMap.get("type");
467-
if (type.equals("MapColoredPixel"))
468-
mapRendererData.addPixel(MapColoredPixel.deserialize(pixelMap));
469-
if (type.equals("TextOverlay"))
470-
mapRendererData.addText(TextOverlay.deserialize(pixelMap));
471-
if (type.equals("ImageOverlay"))
472-
mapRendererData.addImage(ImageOverlay.deserialize(pixelMap));
497+
for (Map.Entry<String, Object> mapPixels : pixelMap.entrySet()) {
498+
Map<String, Object> mapPixelsValue = (Map<String, Object>) mapPixels.getValue();
499+
String type = (String) mapPixelsValue.get("type");
500+
int layer;
501+
try {
502+
layer = Integer.parseInt(mapPixels.getKey());
503+
} catch (NumberFormatException ignore) {
504+
layer = 0;
505+
}
506+
if (type.equals("MapColoredPixel"))
507+
mapRendererData.addPixel(layer, MapColoredPixel.deserialize(mapPixelsValue));
508+
if (type.equals("TextOverlay"))
509+
mapRendererData.addText(layer, TextOverlay.deserialize(mapPixelsValue));
510+
if (type.equals("ImageOverlay"))
511+
mapRendererData.addImage(layer, ImageOverlay.deserialize(mapPixelsValue));
512+
}
473513
}
474514
}
475515
return mapRendererData;
@@ -486,6 +526,10 @@ public String toString() {
486526
'}';
487527
}
488528

529+
private void addMapPixel(final int layer, final MapPixel mapPixel) {
530+
layers.computeIfAbsent(layer, k -> new ArrayList<>()).add(mapPixel);
531+
}
532+
489533
private void setPixels(@Nonnull final MapCanvas canvas) {
490534
getPixels().forEach(mapPixel -> mapPixel.render(this, canvas));
491535
}

0 commit comments

Comments
 (0)