From 97af1a80803ba5c268cc931d5b6d92b617147083 Mon Sep 17 00:00:00 2001 From: Vlammar Date: Wed, 8 Jul 2020 20:06:43 +0200 Subject: [PATCH] dithering floyd (partial don't work properly) --- .../commands/maptool/NewCommand.java | 3 + .../imageonmap/image/MapInitEvent.java | 54 +- .../fr/moribus/imageonmap/image/Renderer.java | 288 ++++++++-- .../fr/moribus/imageonmap/map/MapManager.java | 19 +- .../moribus/imageonmap/ui/MapItemManager.java | 20 +- .../imageonmap/ui/PosterOnASurface.java | 1 + .../fr/moribus/imageonmap/ui/PosterWall.java | 171 +++--- .../imageonmap/ui/SplatterMapManager.java | 498 +++++++++--------- 8 files changed, 672 insertions(+), 382 deletions(-) diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java index daebc02..8f498df 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java +++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java @@ -120,6 +120,9 @@ public class NewCommand extends IoMCommand } }); } + catch(final Throwable e){ + throw e; + } //Added to fix bug with rendering displaying after error finally { ActionBar.removeMessage(player); diff --git a/src/main/java/fr/moribus/imageonmap/image/MapInitEvent.java b/src/main/java/fr/moribus/imageonmap/image/MapInitEvent.java index ef50037..08129f0 100644 --- a/src/main/java/fr/moribus/imageonmap/image/MapInitEvent.java +++ b/src/main/java/fr/moribus/imageonmap/image/MapInitEvent.java @@ -38,6 +38,7 @@ package fr.moribus.imageonmap.image; import fr.moribus.imageonmap.ImageOnMap; import fr.moribus.imageonmap.map.MapManager; +import fr.moribus.imageonmap.ui.SplatterMapManager; import fr.zcraft.zlib.core.ZLib; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -47,9 +48,11 @@ import org.bukkit.entity.HumanEntity; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.inventory.ItemStack; @@ -114,7 +117,56 @@ public class MapInitEvent implements Listener initMap(event.getCursor()); } } - + @EventHandler(priority = EventPriority.HIGHEST) + private void onInventoryClick(InventoryClickEvent event) { + + //Checks if they have clicked anywhere else on the screen while an inventory is open + if(event.getClickedInventory() == null) return; + + //Checks if the clicked slot is empty + if(event.getClickedInventory().getItem(event.getSlot()) == null) return; + + + //Forbid deposit of map in unwanted block + if(event.getInventory().getType().name().equals("GRINDSTONE") & SplatterMapManager.isSplatterMap(event.getCurrentItem())){ + event.setCancelled(true); + return; + } + + + //To cancel removing of glowing effect + if(event.getClickedInventory().getSize()==3) { + + String inventoryClickedTitle=event.getClickedInventory().getType().name(); + //Ignore those blocks + if(event.getClickedInventory().getType()== InventoryType.ANVIL||event.getClickedInventory().getType()==InventoryType.FURNACE||inventoryClickedTitle.equals("BLAST_FURNACE")||inventoryClickedTitle.equals("SMOKER")){ + return; + } + + + if(inventoryClickedTitle.equals("CARTOGRAPHY_TABLE")){ + if(event.getInventory().contains(Material.PAPER)){ + ItemStack[] inventory=event.getClickedInventory().getContents(); + + for(ItemStack item:inventory) { + if (SplatterMapManager.isSplatterMap(item)) { + + event.setCancelled(true); + return; + } + } + } + } + ItemStack[] inventory=event.getClickedInventory().getContents(); + + for(ItemStack item:inventory){ + if (SplatterMapManager.isSplatterMap(item)) { + event.setCancelled(true); + return; + } + } + } + } static public void initMap(ItemStack item) { if (item != null && item.getType() == Material.FILLED_MAP) diff --git a/src/main/java/fr/moribus/imageonmap/image/Renderer.java b/src/main/java/fr/moribus/imageonmap/image/Renderer.java index aa89e26..98f853d 100644 --- a/src/main/java/fr/moribus/imageonmap/image/Renderer.java +++ b/src/main/java/fr/moribus/imageonmap/image/Renderer.java @@ -40,88 +40,280 @@ import fr.zcraft.zlib.tools.PluginLogger; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.map.MapCanvas; +import org.bukkit.map.MapPalette; import org.bukkit.map.MapRenderer; import org.bukkit.map.MapView; +import java.awt.*; import java.awt.image.BufferedImage; -public class Renderer extends MapRenderer -{ - static public boolean isHandled(MapView map) - { - if(map == null) return false; - for(MapRenderer renderer : map.getRenderers()) - { - if(renderer instanceof Renderer) return true; +public class Renderer extends MapRenderer { + private BufferedImage image; + + protected Renderer() { + this(null); + } + + protected Renderer(BufferedImage image) { + this.image = image; + } + + static public boolean isHandled(MapView map) { + if (map == null) return false; + for (MapRenderer renderer : map.getRenderers()) { + if (renderer instanceof Renderer) return true; } return false; } - - static public void installRenderer(PosterImage image, int[] mapsIds) - { - for(int i = 0; i < mapsIds.length; i++) - { + + static public void installRenderer(PosterImage image, int[] mapsIds) { + for (int i = 0; i < mapsIds.length; i++) { installRenderer(image.getImageAt(i), mapsIds[i]); } } - - static public void installRenderer(BufferedImage image, int mapID) - { + + static public void installRenderer(BufferedImage image, int mapID) { MapView map = Bukkit.getMap(mapID); - if(map == null) - { + if (map == null) { PluginLogger.warning("Could not install renderer for map {0}: the Minecraft map does not exist", mapID); - } - else - { + } else { installRenderer(map).setImage(image); } } - - static public Renderer installRenderer(MapView map) - { + + static public Renderer installRenderer(MapView map) { Renderer renderer = new Renderer(); removeRenderers(map); map.addRenderer(renderer); return renderer; } - - static public void removeRenderers(MapView map) - { - for(MapRenderer renderer : map.getRenderers()) - { + + static public void removeRenderers(MapView map) { + for (MapRenderer renderer : map.getRenderers()) { map.removeRenderer(renderer); } } - - private BufferedImage image; - - protected Renderer() - { - this(null); + + + + + private static double getDistance(Color c1, Color c2) { + double rmean = (c1.getRed() + c2.getRed()) / 2.0; + double r = c1.getRed() - c2.getRed(); + double g = c1.getGreen() - c2.getGreen(); + int b = c1.getBlue() - c2.getBlue(); + double weightR = 2 + rmean / 256.0; + double weightG = 4.0; + double weightB = 2 + (255 - rmean) / 256.0; + return weightR * r * r + weightG * g * g + weightB * b * b; } - - protected Renderer(BufferedImage image) - { - this.image = image; + + private byte closestColor(int rgb) { + int alpha = (rgb >>> 24) & 0xFF; + int r = (rgb >>> 16) & 0xFF; + int g = (rgb >>> 8) & 0xFF; + int b = rgb & 0xFF; + byte col = MapPalette.matchColor(new Color(r, g, b, alpha)); + + return col; + } + + protected class RGB{ + private int alpha,r,g,b; + public RGB(int r, int g, int b,int alpha){ + + this.r=r; + this.g=g; + this.b=b; + this.alpha=alpha; + } + public RGB(int rgb){ + int alpha = (rgb >>> 24) & 0xFF; + int r = (rgb >>> 16) & 0xFF; + int g = (rgb >>> 8) & 0xFF; + int b = rgb & 0xFF; + + this.r=r; + this.g=g; + this.b=b; + this.alpha=alpha; + + } + + public RGB(int r, int g, int b){ + + this.r=r; + this.g=g; + this.b=b; + this.alpha=255; + } + public void applyFactor(double factor){ + r*=factor; + g*=factor; + b*=factor; + } + } + private void dithering(MapCanvas canvas) { + + for (int x = 0; x < 128; x++) { + for (int y = 0; y < 128; y++) { + int rgb = image.getRGB(x, y); + Color old_pix = new Color(rgb); + Color new_pix = MapPalette.getColor(MapPalette.matchColor(old_pix));//Couleur la plus proche + + int alpha = (rgb >>> 24) & 0xFF; + if (alpha < 128) { + canvas.setPixel(x, y, (byte) 0); + continue; + } + canvas.setPixel(x, y, MapPalette.matchColor(new_pix));//On applique la nouvelle couleur + + int diff_red=old_pix.getRed()-new_pix.getRed(); + int diff_green=old_pix.getGreen()-new_pix.getGreen(); + int diff_blue=old_pix.getBlue()-new_pix.getBlue(); + + + //Distribution de l'erreur + int X = 0, Y = 0, r, g, b; + int value = 0;//120+4+4+7*4+24+1+16;//208+10*4+4; + if (x + 1 >= 128 | y + 1 >= 128 | x - 1 < 0) { + //PluginLogger.info("On va trop loin"); + canvas.setPixel(x, y, (byte) 20);//MapPalette.matchColor(new_pix)); + continue; + } + double factor; + try { + X = x + 1; + Y = y; + factor=7.0/16; + + rgb=(MapPalette.getColor(canvas.getPixel(X, Y) < 0 ? (byte) (canvas.getPixel(x, y) + value) : canvas.getPixel(x, y)).getRGB()); + //rgb = (int) ((MapPalette.getColor(canvas.getPixel(X, Y) < 0 ? (byte) (canvas.getPixel(x, y) + value) : canvas.getPixel(x, y)).getRGB()) + (error * 7.0 / 16)); + alpha = (rgb >>> 24) & 0xFF; + r = (rgb >>> 16) & 0xFF; + g = (rgb >>> 8) & 0xFF; + b = rgb & 0xFF; + r+=diff_red*factor; + g+=diff_green*factor; + b+=diff_blue*factor; + + if (alpha < 128) + canvas.setPixel(x, y, (byte) 0); + else + canvas.setPixel(x, y, MapPalette.matchColor(r, g, b));//Pb possible avec alpha + + X = x - 1; + Y = y + 1; + factor=3.0/16; + rgb=(MapPalette.getColor(canvas.getPixel(X, Y) < 0 ? (byte) (canvas.getPixel(x, y) + value) : canvas.getPixel(x, y)).getRGB()); + //rgb = (int) ((MapPalette.getColor(canvas.getPixel(X, Y) < 0 ? (byte) (canvas.getPixel(x, y) + value) : canvas.getPixel(x, y)).getRGB()) + (error * 3.0 / 16)); + alpha = (rgb >>> 24) & 0xFF; + r = (rgb >>> 16) & 0xFF; + g = (rgb >>> 8) & 0xFF; + b = rgb & 0xFF; + r+=diff_red*factor; + g+=diff_green*factor; + b+=diff_blue*factor; + if (alpha < 128) + canvas.setPixel(x, y, (byte) 0); + else + canvas.setPixel(x, y, MapPalette.matchColor(r, g, b));//Pb possible avec alpha + + X = x; + Y = y + 1; + factor=5.0/16; + rgb=(MapPalette.getColor(canvas.getPixel(X, Y) < 0 ? (byte) (canvas.getPixel(x, y) + value) : canvas.getPixel(x, y)).getRGB()); + //rgb = (int) ((MapPalette.getColor(canvas.getPixel(X, Y) < 0 ? (byte) (canvas.getPixel(x, y) + value) : canvas.getPixel(x, y)).getRGB()) + (error * 5.0 / 16)); + alpha = (rgb >>> 24) & 0xFF; + r = (rgb >>> 16) & 0xFF; + g = (rgb >>> 8) & 0xFF; + b = rgb & 0xFF; + r+=diff_red*factor; + g+=diff_green*factor; + b+=diff_blue*factor; + if (alpha < 128) + canvas.setPixel(x, y, (byte) 0); + else + canvas.setPixel(x, y, MapPalette.matchColor(r, g, b));//Pb possible avec alpha + + X = x + 1; + Y = y + 1; + factor=1.0/16; + rgb=(MapPalette.getColor(canvas.getPixel(X, Y) < 0 ? (byte) (canvas.getPixel(x, y) + value) : canvas.getPixel(x, y)).getRGB()); + //rgb = (int) ((MapPalette.getColor(canvas.getPixel(X, Y) < 0 ? (byte) (canvas.getPixel(x, y) + value) : canvas.getPixel(x, y)).getRGB()) + (error * 1.0 / 16)); + alpha = (rgb >>> 24) & 0xFF; + r = (rgb >>> 16) & 0xFF; + g = (rgb >>> 8) & 0xFF; + b = rgb & 0xFF; + int rold = r; + int gold = g; + int bold = b; + r+=diff_red*factor; + g+=diff_green*factor; + b+=diff_blue*factor; + if (alpha < 128) + canvas.setPixel(x, y, (byte) 0); + else + canvas.setPixel(x, y, MapPalette.matchColor(r, g, b));//Pb possible avec alpha + // PluginLogger.info("r "+r+" g "+g+" b "+b); + //PluginLogger.info("rold "+rold+" gold "+gold+" bold "+bold); + } catch (final Exception e) { + PluginLogger.info("Exception get color "); + throw e; + } + //canvas.setPixel(x-1,y+1,canvas.getPixel(x-1,y+1)+(error*7.0/16)); + //canvas.setPixel(x,y+1,canvas.getPixel(x,y+1)+(error*7.0/16)); + //canvas.setPixel(x+1,y+1,canvas.getPixel(x+1,y+1)+(error*7.0/16)); + } + } } @Override - public void render(MapView v, final MapCanvas canvas, Player p) - { + public void render(MapView v, MapCanvas canvas, Player p) { + + //Render only once to avoid overloading the server if (image == null) return; - canvas.drawImage(0, 0, image); + boolean dither = true; + // canvas.drawImage(0, 0, image); + if (dither) { + dithering(canvas); + return; + } + for (int x = 0; x < 128; x++) { + for (int y = 0; y < 128; y++) { + int rgb = image.getRGB(x, y); + byte col = closestColor(rgb); + + canvas.setPixel(x, y, col); + } + } + + /* for(int x=0;x<128;x++){ + for(int y=0;y<128;y++){ + + + + int rgb=image.getRGB(x,y); + int r = (rgb >>> 16) & 0xFF; + int g = (rgb >>> 8) & 0xFF; + int b = rgb & 0xFF; + //PluginLogger.info("canvas pixel "+x+" "+y+" r "+r+" g "+g+" b "+b); + PluginLogger.info(""+canvas.getBasePixel(x,y)); + canvas.setPixel(x,y,(byte)208); + + }*/ + + image = null; + } - - public BufferedImage getImage() - { + + public BufferedImage getImage() { return image; } - - public void setImage(BufferedImage image) - { + + public void setImage(BufferedImage image) { this.image = image; } } diff --git a/src/main/java/fr/moribus/imageonmap/map/MapManager.java b/src/main/java/fr/moribus/imageonmap/map/MapManager.java index d06cf8c..47942ea 100644 --- a/src/main/java/fr/moribus/imageonmap/map/MapManager.java +++ b/src/main/java/fr/moribus/imageonmap/map/MapManager.java @@ -126,11 +126,19 @@ abstract public class MapManager static public int[] getNewMapsIds(int amount) { int[] mapsIds = new int[amount]; - for(int i = 0; i < amount; i++) - { - mapsIds[i] = Bukkit.createMap(Bukkit.getWorlds().get(0)).getId(); + try { + for (int i = 0; i < amount; i++) { + mapsIds[i] = Bukkit.createMap(Bukkit.getWorlds().get(0)).getId(); + + } + return mapsIds; } - return mapsIds; + catch (final Throwable e){ + PluginLogger.warning("Erreur a la creation de map !!!"); + throw e; + } + + } /** @@ -140,11 +148,14 @@ abstract public class MapManager */ static public int getMapIdFromItemStack(final ItemStack item) { + + final ItemMeta meta = item.getItemMeta(); if (!(meta instanceof MapMeta)) return 0; return ((MapMeta) meta).hasMapId() ? ((MapMeta) meta).getMapId() : 0; } + static public void addMap(ImageMap map) throws MapManagerException { diff --git a/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java b/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java index e16aad7..13bbaf3 100644 --- a/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java +++ b/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java @@ -36,12 +36,14 @@ package fr.moribus.imageonmap.ui; +import fr.moribus.imageonmap.Permissions; import fr.moribus.imageonmap.map.ImageMap; import fr.moribus.imageonmap.map.MapManager; import fr.moribus.imageonmap.map.PosterMap; import fr.moribus.imageonmap.map.SingleMap; import fr.zcraft.zlib.components.i18n.I; import fr.zcraft.zlib.core.ZLib; +import fr.zcraft.zlib.tools.PluginLogger; import fr.zcraft.zlib.tools.items.ItemStackBuilder; import fr.zcraft.zlib.tools.items.ItemUtils; import org.bukkit.*; @@ -271,6 +273,7 @@ public class MapItemManager implements Listener } else{ + PluginLogger.info("Coucou je suis une carte simple"); frame.setItem(mapItem); } @@ -285,17 +288,20 @@ public class MapItemManager implements Listener ItemStack item = frame.getItem(); if (frame.getItem().getType() != Material.FILLED_MAP) return; - if (player.isSneaking()) + if (Permissions.REMOVE_SPLATTER_MAP.grantedTo(player)) { - PosterMap poster = SplatterMapManager.removeSplatterMap(frame,player); - if (poster != null) + if (player.isSneaking()) { - event.setCancelled(true); + PosterMap poster = SplatterMapManager.removeSplatterMap(frame,player); + if (poster != null) + { + event.setCancelled(true); - if (player.getGameMode() != GameMode.CREATIVE || !SplatterMapManager.hasSplatterMap(player, poster)) - poster.give(player); + if (player.getGameMode() != GameMode.CREATIVE || !SplatterMapManager.hasSplatterMap(player, poster)) + poster.give(player); - return; + return; + } } } diff --git a/src/main/java/fr/moribus/imageonmap/ui/PosterOnASurface.java b/src/main/java/fr/moribus/imageonmap/ui/PosterOnASurface.java index b6334ee..d2dd8a7 100644 --- a/src/main/java/fr/moribus/imageonmap/ui/PosterOnASurface.java +++ b/src/main/java/fr/moribus/imageonmap/ui/PosterOnASurface.java @@ -107,6 +107,7 @@ public class PosterOnASurface { return true; } + //If in creative expand item frames in order to auto deploy public void expand() { } diff --git a/src/main/java/fr/moribus/imageonmap/ui/PosterWall.java b/src/main/java/fr/moribus/imageonmap/ui/PosterWall.java index f8db508..c80c5f5 100644 --- a/src/main/java/fr/moribus/imageonmap/ui/PosterWall.java +++ b/src/main/java/fr/moribus/imageonmap/ui/PosterWall.java @@ -43,113 +43,146 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.ItemFrame; import org.bukkit.inventory.ItemStack; -public class PosterWall -{ - +public class PosterWall { + public FlatLocation loc1; public FlatLocation loc2; - + public ItemFrame[] frames; - - public boolean isValid() - { - ItemFrame curFrame; - FlatLocation bottomLeft = FlatLocation.minMerged(loc1, loc2); - FlatLocation loc = bottomLeft.clone(); - - int distX = FlatLocation.flatBlockDistanceX(loc1, loc2); - int distY = FlatLocation.flatBlockDistanceY(loc1, loc2); - frames = new ItemFrame[distX * distY]; - - for(int x = 0; x < distX; x++) - { - for(int y = 0; y < distY; y++) - { - curFrame = getEmptyFrameAt(loc, loc.getFacing()); - if(curFrame == null) return false; - frames[y * distX + x] = curFrame; - loc.add(0, 1); - } - loc.add(1, 0); - loc.setY(bottomLeft.getY()); + + + private static boolean supportIsValid(FlatLocation location, BlockFace bf, int width, int height) { + //Code to add + FlatLocation loc=location.clone(); + loc.add(0,-1); + switch (bf){ + case EAST: + case WEST: + loc.addH(1,0,bf); + break; + case NORTH: + case SOUTH: + loc.addH(0,1,bf); + break; } - - return true; - } - - public void expand() - { + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + // if(loc.getBlock().) + } + + } + + return false; } - - static public ItemFrame[] getMatchingMapFrames(PosterMap map, FlatLocation location, int mapId) - { + + //Used to expand itemframes when possible + public static void expand(FlatLocation location,BlockFace bf ,int width, int height) throws Exception{ + if (!supportIsValid(location,bf, width, height)) + return; + + FlatLocation loc=location.clone(); + loc.add(0,-1); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + loc.add(0,1); + loc.getWorld().spawnEntity(loc, EntityType.ITEM_FRAME); + } + loc.add(1,-height); + } + } + + /*static public ItemFrame[] getMatchingMapFrames(PosterMap map, FlatLocation location, int mapId, Player p) { + if (p.getGameMode() == GameMode.CREATIVE) + expand(location, map.getColumnCount(), map.getRowCount()); + return getMatchingMapFrames(map, location, mapId); + }*/ + + static public ItemFrame[] getMatchingMapFrames(PosterMap map, FlatLocation location, int mapId) { int mapIndex = map.getIndex(mapId); int x = map.getColumnAt(mapIndex), y = map.getRowAt(mapIndex); - + return getMatchingMapFrames(map, location.clone().add(-x, y)); } - - static public ItemFrame[] getMatchingMapFrames(PosterMap map, FlatLocation location) - { + + static public ItemFrame[] getMatchingMapFrames(PosterMap map, FlatLocation location) { ItemFrame[] frames = new ItemFrame[map.getMapCount()]; FlatLocation loc = location.clone(); - - for(int y = 0; y < map.getRowCount(); ++y) - { - for(int x = 0; x < map.getColumnCount(); ++x) - { + + for (int y = 0; y < map.getRowCount(); ++y) { + for (int x = 0; x < map.getColumnCount(); ++x) { int mapIndex = map.getIndexAt(x, y); ItemFrame frame = getMapFrameAt(loc, map); - if(frame != null) frames[mapIndex] = frame; + if (frame != null) frames[mapIndex] = frame; loc.add(1, 0); } loc.setX(location.getX()); loc.setZ(location.getZ()); loc.add(0, -1); } - + return frames; } - - static public ItemFrame getMapFrameAt(FlatLocation location, PosterMap map) - { + + static public ItemFrame getMapFrameAt(FlatLocation location, PosterMap map) { Entity entities[] = location.getChunk().getEntities(); - - for(Entity entity : entities) - { - if(!(entity instanceof ItemFrame)) continue; - if(!WorldUtils.blockEquals(location, entity.getLocation())) continue; + + for (Entity entity : entities) { + if (!(entity instanceof ItemFrame)) continue; + if (!WorldUtils.blockEquals(location, entity.getLocation())) continue; ItemFrame frame = (ItemFrame) entity; - if(frame.getFacing() != location.getFacing()) continue; + if (frame.getFacing() != location.getFacing()) continue; ItemStack item = frame.getItem(); - if(item.getType() != Material.FILLED_MAP) continue; - if(!map.managesMap(item)) continue; + if (item.getType() != Material.FILLED_MAP) continue; + if (!map.managesMap(item)) continue; return frame; } - + return null; } - - static public ItemFrame getEmptyFrameAt(Location location, BlockFace facing) - { + + static public ItemFrame getEmptyFrameAt(Location location, BlockFace facing) { Entity entities[] = location.getChunk().getEntities(); - - for(Entity entity : entities) - { - if(!(entity instanceof ItemFrame)) continue; - if(!WorldUtils.blockEquals(location, entity.getLocation())) continue; + + for (Entity entity : entities) { + if (!(entity instanceof ItemFrame)) continue; + if (!WorldUtils.blockEquals(location, entity.getLocation())) continue; ItemFrame frame = (ItemFrame) entity; - if(frame.getFacing() != facing) continue; + if (frame.getFacing() != facing) continue; ItemStack item = frame.getItem(); - if(item.getType() != Material.AIR) continue; + if (item.getType() != Material.AIR) continue; return frame; } - + return null; } + + public boolean isValid() { + ItemFrame curFrame; + FlatLocation bottomLeft = FlatLocation.minMerged(loc1, loc2); + FlatLocation loc = bottomLeft.clone(); + + int distX = FlatLocation.flatBlockDistanceX(loc1, loc2); + int distY = FlatLocation.flatBlockDistanceY(loc1, loc2); + + frames = new ItemFrame[distX * distY]; + + for (int x = 0; x < distX; x++) { + for (int y = 0; y < distY; y++) { + curFrame = getEmptyFrameAt(loc, loc.getFacing()); + if (curFrame == null) return false; + frames[y * distX + x] = curFrame; + loc.add(0, 1); + } + loc.add(1, 0); + loc.setY(bottomLeft.getY()); + } + + return true; + } } diff --git a/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java b/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java index e0858ab..8588250 100644 --- a/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java +++ b/src/main/java/fr/moribus/imageonmap/ui/SplatterMapManager.java @@ -52,10 +52,7 @@ import fr.zcraft.zlib.tools.reflection.NMSException; import fr.zcraft.zlib.tools.text.MessageSender; import fr.zcraft.zlib.tools.world.FlatLocation; import fr.zcraft.zlib.tools.world.WorldUtils; -import org.bukkit.ChatColor; -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.Rotation; +import org.bukkit.*; import org.bukkit.block.BlockFace; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; @@ -64,293 +61,288 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.MapMeta; + abstract public class SplatterMapManager { - private SplatterMapManager() { - } + private SplatterMapManager() { + } - static public ItemStack makeSplatterMap(PosterMap map) { + static public ItemStack makeSplatterMap(PosterMap map) { + final ItemStack splatter = new ItemStackBuilder(Material.FILLED_MAP).title(ChatColor.GOLD, map.getName()) + .title(ChatColor.DARK_GRAY, " - ").title(ChatColor.GRAY, I.t("Splatter Map")) + .title(ChatColor.DARK_GRAY, " - ") + .title(ChatColor.GRAY, I.t("{0} × {1}", map.getColumnCount(), map.getRowCount())) + .loreLine(ChatColor.GRAY, map.getId()).loreLine() + /// Title in a splatter map tooltip + .loreLine(ChatColor.BLUE, I.t("Item frames needed")) + /// Size of a map stored in a splatter map + .loreLine(ChatColor.GRAY, + I.t("{0} × {1} (total {2} frames)", map.getColumnCount(), map.getRowCount(), + map.getColumnCount() * map.getRowCount())) + .loreLine() + /// Title in a splatter map tooltip + .loreLine(ChatColor.BLUE, I.t("How to use this?")) + .longLore( + ChatColor.GRAY + + I.t("Place empty item frames on a wall, enough to host the whole map. Then, right-click on the bottom-left frame with this map."), + 40) + .loreLine() + .longLore(ChatColor.GRAY + + I.t("Shift-click one of the placed maps to remove the whole poster in one shot."), 40) + .hideAttributes().craftItem(); - final ItemStack splatter = new ItemStackBuilder(Material.FILLED_MAP).title(ChatColor.GOLD, map.getName()) - .title(ChatColor.DARK_GRAY, " - ").title(ChatColor.GRAY, I.t("Splatter Map")) - .title(ChatColor.DARK_GRAY, " - ") - .title(ChatColor.GRAY, I.t("{0} × {1}", map.getColumnCount(), map.getRowCount())) - .loreLine(ChatColor.GRAY, map.getId()).loreLine() - /// Title in a splatter map tooltip - .loreLine(ChatColor.BLUE, I.t("Item frames needed")) - /// Size of a map stored in a splatter map - .loreLine(ChatColor.GRAY, - I.t("{0} × {1} (total {2} frames)", map.getColumnCount(), map.getRowCount(), - map.getColumnCount() * map.getRowCount())) - .loreLine() - /// Title in a splatter map tooltip - .loreLine(ChatColor.BLUE, I.t("How to use this?")) - .longLore( - ChatColor.GRAY - + I.t("Place empty item frames on a wall, enough to host the whole map. Then, right-click on the bottom-left frame with this map."), - 40) - .loreLine() - .longLore(ChatColor.GRAY - + I.t("Shift-click one of the placed maps to remove the whole poster in one shot."), 40) - .hideAttributes().craftItem(); + final MapMeta meta = (MapMeta) splatter.getItemMeta(); + meta.setMapId(map.getMapIdAt(0)); + meta.setColor(Color.GREEN); + splatter.setItemMeta(meta); - final MapMeta meta = (MapMeta) splatter.getItemMeta(); - meta.setMapId(map.getMapIdAt(0)); - meta.setColor(Color.GREEN); - splatter.setItemMeta(meta); + return addSplatterAttribute(splatter); + } - return addSplatterAttribute(splatter); - } + /** + * To identify image on maps for the auto-splattering to work, we mark the + * items using an enchantment maps are not supposed to have (Mending). + *

+ * Then we check if the map is enchanted at all to know if it's a splatter + * map. This ensure compatibility with old splatter maps from 3.x, where + * zLib's glow effect was used. + *

+ * An AttributeModifier (using zLib's attributes system) is not used, + * because Minecraft (or Spigot) removes them from maps in 1.14+, so that + * wasn't stable enough (and the glowing effect of enchantments is + * prettier). + * + * @param itemStack The item stack to mark as a splatter map. + * @return The modified item stack. The instance may be different if the + * passed item stack is not a craft item stack; that's why the + * instance is returned. + */ + static public ItemStack addSplatterAttribute(final ItemStack itemStack) { + try { + final NBTCompound nbt = NBT.fromItemStack(itemStack); + final NBTList enchantments = new NBTList(); + final NBTCompound protection = new NBTCompound(); - /** - * To identify image on maps for the auto-splattering to work, we mark the - * items using an enchantment maps are not supposed to have (Mending). - * - * Then we check if the map is enchanted at all to know if it's a splatter - * map. This ensure compatibility with old splatter maps from 3.x, where - * zLib's glow effect was used. - * - * An AttributeModifier (using zLib's attributes system) is not used, - * because Minecraft (or Spigot) removes them from maps in 1.14+, so that - * wasn't stable enough (and the glowing effect of enchantments is - * prettier). - * - * @param itemStack - * The item stack to mark as a splatter map. - * @return The modified item stack. The instance may be different if the - * passed item stack is not a craft item stack; that's why the - * instance is returned. - */ - static public ItemStack addSplatterAttribute(final ItemStack itemStack) { - try { - final NBTCompound nbt = NBT.fromItemStack(itemStack); - final NBTList enchantments = new NBTList(); - final NBTCompound protection = new NBTCompound(); + protection.put("id", "minecraft:mending"); + protection.put("lvl", 1); + enchantments.add(protection); - protection.put("id", "minecraft:mending"); - protection.put("lvl", 1); - enchantments.add(protection); + nbt.put("Enchantments", enchantments); - nbt.put("Enchantments", enchantments); + return NBT.addToItemStack(itemStack, nbt, false); + } catch (NBTException | NMSException e) { + PluginLogger.error("Unable to set Splatter Map attribute on item", e); + return itemStack; + } + } - return NBT.addToItemStack(itemStack, nbt, false); - } catch (NBTException | NMSException e) { - PluginLogger.error("Unable to set Splatter Map attribute on item", e); - return itemStack; - } - } + /** + * Checks if an item have the splatter attribute set (i.e. if the item is + * enchanted in any way). + * + * @param itemStack The item to check. + * @return True if the attribute was detected. + */ + static public boolean hasSplatterAttributes(ItemStack itemStack) { + try { + final NBTCompound nbt = NBT.fromItemStack(itemStack); + if (!nbt.containsKey("Enchantments")) + return false; + final Object enchantments = nbt.get("Enchantments"); + if (!(enchantments instanceof NBTList)) + return false; + return !((NBTList) enchantments).isEmpty(); + } catch (NMSException e) { + PluginLogger.error("Unable to get Splatter Map attribute on item", e); + return false; + } + } - /** - * Checks if an item have the splatter attribute set (i.e. if the item is - * enchanted in any way). - * - * @param itemStack - * The item to check. - * @return True if the attribute was detected. - */ - static public boolean hasSplatterAttributes(ItemStack itemStack) { - try { - final NBTCompound nbt = NBT.fromItemStack(itemStack); - if (!nbt.containsKey("Enchantments")) - return false; - final Object enchantments = nbt.get("Enchantments"); - if (!(enchantments instanceof NBTList)) - return false; - return !((NBTList) enchantments).isEmpty(); - } catch (NMSException e) { - PluginLogger.error("Unable to get Splatter Map attribute on item", e); - return false; - } - } - - /** - * Return true if it is a platter map - * - * @param itemStack - * The item to check. - * @return True if is a splatter map - */ - static public boolean isSplatterMap(ItemStack itemStack) { - if(itemStack==null) return false; - return hasSplatterAttributes(itemStack) && MapManager.managesMap(itemStack); - } + /** + * Return true if it is a platter map + * + * @param itemStack The item to check. + * @return True if is a splatter map + */ + static public boolean isSplatterMap(ItemStack itemStack) { + if (itemStack == null) return false; + return hasSplatterAttributes(itemStack) && MapManager.managesMap(itemStack); + } - //TODO doc a faire - static public boolean hasSplatterMap(Player player, PosterMap map) { - Inventory playerInventory = player.getInventory(); + //TODO doc a faire + static public boolean hasSplatterMap(Player player, PosterMap map) { + Inventory playerInventory = player.getInventory(); - for (int i = 0; i < playerInventory.getSize(); ++i) { - ItemStack item = playerInventory.getItem(i); - if (isSplatterMap(item) && map.managesMap(item)) - return true; - } + for (int i = 0; i < playerInventory.getSize(); ++i) { + ItemStack item = playerInventory.getItem(i); + if (isSplatterMap(item) && map.managesMap(item)) + return true; + } - return false; - } + return false; + } - /** - * Place a splatter map - * - * @param startFrame - * Frame clicked by the player - * @param player - * Player placing map - * @return true if the map was correctly placed - */ - static public boolean placeSplatterMap(ItemFrame startFrame, Player player, PlayerInteractEntityEvent event) { - ImageMap map = MapManager.getMap(player.getInventory().getItemInMainHand()); + /** + * Place a splatter map + * + * @param startFrame Frame clicked by the player + * @param player Player placing map + * @return true if the map was correctly placed + */ + static public boolean placeSplatterMap(ItemFrame startFrame, Player player, PlayerInteractEntityEvent event) { + ImageMap map = MapManager.getMap(player.getInventory().getItemInMainHand()); - if (!(map instanceof PosterMap)) - return false; - PosterMap poster = (PosterMap) map; - PosterWall wall = new PosterWall(); + if (!(map instanceof PosterMap)) + return false; + PosterMap poster = (PosterMap) map; + PosterWall wall = new PosterWall(); - if (startFrame.getFacing().equals(BlockFace.DOWN) || startFrame.getFacing().equals(BlockFace.UP)) { - // If it is on floor or ceiling - PosterOnASurface surface = new PosterOnASurface(); - FlatLocation startLocation = new FlatLocation(startFrame.getLocation(), startFrame.getFacing()); - FlatLocation endLocation = startLocation.clone().addH(poster.getColumnCount(), poster.getRowCount(), - WorldUtils.get4thOrientation(player.getLocation())); + if (startFrame.getFacing().equals(BlockFace.DOWN) || startFrame.getFacing().equals(BlockFace.UP)) { + // If it is on floor or ceiling + PosterOnASurface surface = new PosterOnASurface(); + FlatLocation startLocation = new FlatLocation(startFrame.getLocation(), startFrame.getFacing()); + FlatLocation endLocation = startLocation.clone().addH(poster.getColumnCount(), poster.getRowCount(), + WorldUtils.get4thOrientation(player.getLocation())); - surface.loc1 = startLocation; - surface.loc2 = endLocation; + surface.loc1 = startLocation; + surface.loc2 = endLocation; - if (!surface.isValid(player)) { - MessageSender.sendActionBarMessage(player, - I.t("{ce}There is not enough space to place this map ({0} × {1}).", poster.getColumnCount(), - poster.getRowCount())); + if (!surface.isValid(player)) { + MessageSender.sendActionBarMessage(player, + I.t("{ce}There is not enough space to place this map ({0} × {1}).", poster.getColumnCount(), + poster.getRowCount())); - return false; - } + return false; + } - int i = 0; - for (ItemFrame frame : surface.frames) { - BlockFace bf = WorldUtils.get4thOrientation(player.getLocation()); - int id = poster.getMapIdAtReverseZ(i, bf, startFrame.getFacing()); - Rotation rot = Rotation.NONE; - switch(frame.getFacing()){ - case UP: - break; - case DOWN: - rot = Rotation.FLIPPED; - break; - } - //Rotation management relative to player rotation the default position is North, when on ceiling we flipped the rotation - frame.setItem(new ItemStackBuilder(Material.FILLED_MAP).nbt(ImmutableMap.of("map", id)).craftItem()); - if(i==0){//First map need to be rotate one time CounterClockwise - rot=rot.rotateCounterClockwise(); - } + int i = 0; + for (ItemFrame frame : surface.frames) { + BlockFace bf = WorldUtils.get4thOrientation(player.getLocation()); + int id = poster.getMapIdAtReverseZ(i, bf, startFrame.getFacing()); + Rotation rot = Rotation.NONE; + switch (frame.getFacing()) { + case UP: + break; + case DOWN: + rot = Rotation.FLIPPED; + break; + } + //Rotation management relative to player rotation the default position is North, when on ceiling we flipped the rotation + frame.setItem(new ItemStackBuilder(Material.FILLED_MAP).nbt(ImmutableMap.of("map", id)).craftItem()); + if (i == 0) {//First map need to be rotate one time CounterClockwise + rot = rot.rotateCounterClockwise(); + } - switch (bf) { - case NORTH: - if (frame.getFacing() == BlockFace.DOWN) { - rot = rot.rotateClockwise(); - rot = rot.rotateClockwise(); - } - frame.setRotation(rot); - break; - case EAST: - rot = rot.rotateClockwise(); - frame.setRotation(rot); - break; - case SOUTH: - if (frame.getFacing() == BlockFace.UP) { - rot = rot.rotateClockwise(); - rot = rot.rotateClockwise(); - } - frame.setRotation(rot); - break; - case WEST: - rot = rot.rotateCounterClockwise(); - frame.setRotation(rot); - break; - } + switch (bf) { + case NORTH: + if (frame.getFacing() == BlockFace.DOWN) { + rot = rot.rotateClockwise(); + rot = rot.rotateClockwise(); + } + frame.setRotation(rot); + break; + case EAST: + rot = rot.rotateClockwise(); + frame.setRotation(rot); + break; + case SOUTH: + if (frame.getFacing() == BlockFace.UP) { + rot = rot.rotateClockwise(); + rot = rot.rotateClockwise(); + } + frame.setRotation(rot); + break; + case WEST: + rot = rot.rotateCounterClockwise(); + frame.setRotation(rot); + break; + } + + WorldMap + MapInitEvent.initMap(id); + i++; + } + } else { + // If it is on a wall NSEW + FlatLocation startLocation = new FlatLocation(startFrame.getLocation(), startFrame.getFacing()); + FlatLocation endLocation = startLocation.clone().add(poster.getColumnCount(), poster.getRowCount()); + if (player.getGameMode() == GameMode.CREATIVE) + PosterWall.expand(startLocation,startFrame.getAttachedFace(), poster.getColumnCount(), poster.getRowCount()); + wall.loc1 = startLocation; + wall.loc2 = endLocation; + if (!wall.isValid()) { + MessageSender.sendActionBarMessage(player, + I.t("{ce}There is not enough space to place this map ({0} × {1}).", poster.getColumnCount(), + poster.getRowCount())); + return false; + } - MapInitEvent.initMap(id); - i++; - } - } else { - // If it is on a wall NSEW - FlatLocation startLocation = new FlatLocation(startFrame.getLocation(), startFrame.getFacing()); - FlatLocation endLocation = startLocation.clone().add(poster.getColumnCount(), poster.getRowCount()); + int i = 0; + for (ItemFrame frame : wall.frames) { - wall.loc1 = startLocation; - wall.loc2 = endLocation; + int id = poster.getMapIdAtReverseY(i); + frame.setItem(new ItemStackBuilder(Material.FILLED_MAP).nbt(ImmutableMap.of("map", id)).craftItem()); - if (!wall.isValid()) { - MessageSender.sendActionBarMessage(player, - I.t("{ce}There is not enough space to place this map ({0} × {1}).", poster.getColumnCount(), - poster.getRowCount())); - return false; - } + //Force reset of rotation + if (i == 0) {//First map need to be rotate one time Clockwise + frame.setRotation(Rotation.NONE.rotateCounterClockwise()); + } else { + frame.setRotation(Rotation.NONE); + } + MapInitEvent.initMap(id); + ++i; + } + } + return true; + } - int i = 0; - for (ItemFrame frame : wall.frames) { + /** + * Remove splattermap + * + * @param startFrame Frame clicked by the player + * @param player The player removing the map + * @return + */ + static public PosterMap removeSplatterMap(ItemFrame startFrame, Player player) { + final ImageMap map = MapManager.getMap(startFrame.getItem()); + if (!(map instanceof PosterMap)) + return null; + PosterMap poster = (PosterMap) map; + if (!poster.hasColumnData()) + return null; + FlatLocation loc = new FlatLocation(startFrame.getLocation(), startFrame.getFacing()); + ItemFrame[] matchingFrames = null; - int id = poster.getMapIdAtReverseY(i); - frame.setItem(new ItemStackBuilder(Material.FILLED_MAP).nbt(ImmutableMap.of("map", id)).craftItem()); - - //Force reset of rotation - if(i==0){//First map need to be rotate one time Clockwise - frame.setRotation(Rotation.NONE.rotateCounterClockwise()); - } - else{frame.setRotation(Rotation.NONE);} - MapInitEvent.initMap(id); - ++i; - } - } - return true; - } - - /** - * Remove splattermap - * - * @param startFrame - * Frame clicked by the player - * @param player - * The player removing the map - * @return - */ - static public PosterMap removeSplatterMap(ItemFrame startFrame, Player player) { - final ImageMap map = MapManager.getMap(startFrame.getItem()); - if (!(map instanceof PosterMap)) - return null; - PosterMap poster = (PosterMap) map; - if (!poster.hasColumnData()) - return null; - FlatLocation loc = new FlatLocation(startFrame.getLocation(), startFrame.getFacing()); - ItemFrame[] matchingFrames=null; - - switch(startFrame.getFacing()){ - case UP: - case DOWN: + switch (startFrame.getFacing()) { + case UP: + case DOWN: matchingFrames = PosterOnASurface.getMatchingMapFrames(poster, loc, - MapManager.getMapIdFromItemStack(startFrame.getItem()),WorldUtils.get4thOrientation(player.getLocation()));//startFrame.getFacing()); + MapManager.getMapIdFromItemStack(startFrame.getItem()), WorldUtils.get4thOrientation(player.getLocation()));//startFrame.getFacing()); break; - case NORTH: - case SOUTH: - case EAST: - case WEST: - matchingFrames = PosterWall.getMatchingMapFrames(poster, loc, - MapManager.getMapIdFromItemStack(startFrame.getItem())); - } + case NORTH: + case SOUTH: + case EAST: + case WEST: + matchingFrames = PosterWall.getMatchingMapFrames(poster, loc, + MapManager.getMapIdFromItemStack(startFrame.getItem())); + } - if (matchingFrames == null) - return null; + if (matchingFrames == null) + return null; - for (ItemFrame frame : matchingFrames) { - if (frame != null) - frame.setItem(null); - } + for (ItemFrame frame : matchingFrames) { + if (frame != null) + frame.setItem(null); + } - return poster; - } + return poster; + } }