diff --git a/src/de/steamwar/lobby/LobbySystem.java b/src/de/steamwar/lobby/LobbySystem.java
index aab6a57..4d198d4 100644
--- a/src/de/steamwar/lobby/LobbySystem.java
+++ b/src/de/steamwar/lobby/LobbySystem.java
@@ -27,8 +27,7 @@ import de.steamwar.lobby.command.PortalCommand;
import de.steamwar.lobby.jumpandrun.JumpAndRun;
import de.steamwar.lobby.jumpandrun.JumpAndRunCommand;
import de.steamwar.lobby.listener.*;
-import de.steamwar.lobby.map.CustomMapCommand;
-import de.steamwar.lobby.map.CustomMapNew;
+import de.steamwar.lobby.map.CustomMap;
import de.steamwar.lobby.particle.ParticleListener;
import de.steamwar.lobby.special.advent.AdventsCalendar;
import de.steamwar.lobby.team.TeamPlayer;
@@ -54,7 +53,7 @@ public class LobbySystem extends JavaPlugin {
entityServer = new REntityServer();
debugEntityServer = new REntityServer();
- CustomMapNew.init();
+ CustomMap.init();
Fightserver.init();
new Portals();
@@ -62,7 +61,6 @@ public class LobbySystem extends JavaPlugin {
new HologramCommand();
new FlyCommand();
new ModifyCommand();
- new CustomMapCommand();
new JumpAndRun();
new JumpAndRunCommand();
diff --git a/src/de/steamwar/lobby/map/CustomMap.java b/src/de/steamwar/lobby/map/CustomMap.java
index 0e9885e..4e7d859 100644
--- a/src/de/steamwar/lobby/map/CustomMap.java
+++ b/src/de/steamwar/lobby/map/CustomMap.java
@@ -1,110 +1,356 @@
/*
- * This file is a part of the SteamWar software.
+ * This file is a part of the SteamWar software.
*
- * Copyright (C) 2022 SteamWar.de-Serverteam
+ * Copyright (C) 2024 SteamWar.de-Serverteam
*
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
*
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
*/
package de.steamwar.lobby.map;
-import net.minecraft.world.level.saveddata.maps.WorldMap;
+import de.steamwar.lobby.LobbySystem;
import org.bukkit.Bukkit;
import org.bukkit.Material;
-import org.bukkit.craftbukkit.v1_20_R1.map.CraftMapView;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.MapMeta;
+import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapPalette;
+import org.bukkit.map.MapRenderer;
+import org.bukkit.map.MapView;
+import org.bukkit.util.Vector;
+import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
-import java.lang.reflect.Field;
+import java.awt.image.WritableRaster;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
-public class CustomMap {
+public class CustomMap implements Listener {
- public CustomMap(Player player, BufferedImage image) {
- if (image.getWidth() % 128 != 0) {
- throw new IllegalArgumentException("Image width must be a multiple of 128");
- }
- if (image.getHeight() % 128 != 0) {
- throw new IllegalArgumentException("Image height must be a multiple of 128");
+ public static void init() {
+ }
+
+ private static final CustomMap LEFT = new CustomMap(new File(System.getProperty("user.home") + "/lobbyBanner/left.png"),
+ new Vector(2346, 48, 1297), new Vector(2345, 48, 1297), new Vector(2344, 48, 1297), new Vector(2343, 48, 1297), new Vector(2342, 48, 1297), new Vector(2341, 48, 1297), new Vector(2340, 48, 1297),
+ new Vector(2346, 47, 1297), new Vector(2345, 47, 1297), new Vector(2344, 47, 1297), new Vector(2343, 47, 1297), new Vector(2342, 47, 1297), new Vector(2341, 47, 1297), new Vector(2340, 47, 1297),
+ new Vector(2346, 46, 1297), new Vector(2345, 46, 1297), new Vector(2344, 46, 1297), new Vector(2343, 46, 1297), new Vector(2342, 46, 1297), new Vector(2341, 46, 1297), new Vector(2340, 46, 1297),
+ new Vector(2346, 45, 1297), new Vector(2345, 45, 1297), new Vector(2344, 45, 1297), new Vector(2343, 45, 1297), new Vector(2342, 45, 1297), new Vector(2341, 45, 1297), new Vector(2340, 45, 1297)
+ );
+
+ private static final CustomMap RIGHT = new CustomMap(new File(System.getProperty("user.home") + "/lobbyBanner/right.png"),
+ new Vector(2330, 48, 1297), new Vector(2329, 48, 1297), new Vector(2328, 48, 1297), new Vector(2327, 48, 1297), new Vector(2326, 48, 1297), new Vector(2325, 48, 1297), new Vector(2324, 48, 1297),
+ new Vector(2330, 47, 1297), new Vector(2329, 47, 1297), new Vector(2328, 47, 1297), new Vector(2327, 47, 1297), new Vector(2326, 47, 1297), new Vector(2325, 47, 1297), new Vector(2324, 47, 1297),
+ new Vector(2330, 46, 1297), new Vector(2329, 46, 1297), new Vector(2328, 46, 1297), new Vector(2327, 46, 1297), new Vector(2326, 46, 1297), new Vector(2325, 46, 1297), new Vector(2324, 46, 1297),
+ new Vector(2330, 45, 1297), new Vector(2329, 45, 1297), new Vector(2328, 45, 1297), new Vector(2327, 45, 1297), new Vector(2326, 45, 1297), new Vector(2325, 45, 1297), new Vector(2324, 45, 1297)
+ );
+
+ private File mapFile;
+ private Map itemFrameIndex = new HashMap<>();
+ private ItemFrame[] itemFrames;
+ private long lastModified = Long.MAX_VALUE;
+
+ public CustomMap(File mapFile, Vector... itemFrames) {
+ this.mapFile = mapFile;
+ this.itemFrames = new ItemFrame[itemFrames.length];
+ for (int i = 0; i < itemFrames.length; i++) {
+ itemFrameIndex.put(itemFrames[i], i);
}
- BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
- for (int y = 0; y < image.getHeight(); y++) {
- for (int x = 0; x < image.getWidth(); x++) {
- Color oldPixel = new Color(image.getRGB(x, y));
- Color newPixel = getNearest(oldPixel);
- bufferedImage.setRGB(x, y, newPixel.getRGB());
- int quantErrorRed = oldPixel.getRed() - newPixel.getRed();
- int quantErrorGreen = oldPixel.getGreen() - newPixel.getGreen();
- int quantErrorBlue = oldPixel.getBlue() - newPixel.getBlue();
- if (x < image.getWidth() - 1) {
- image.setRGB(x + 1, y, updateViaQuantError(new Color(image.getRGB(x + 1, y)), quantErrorRed, quantErrorGreen, quantErrorBlue, 7 / 16.0).getRGB());
- }
- if (x > 0) {
- image.setRGB(x - 1, y, updateViaQuantError(new Color(image.getRGB(x - 1, y)), quantErrorRed, quantErrorGreen, quantErrorBlue, 3 / 16.0).getRGB());
- }
- if (y < image.getHeight() - 1) {
- image.setRGB(x, y + 1, updateViaQuantError(new Color(image.getRGB(x, y + 1)), quantErrorRed, quantErrorGreen, quantErrorBlue, 5 / 16.0).getRGB());
- if (x < image.getWidth() - 1) {
- image.setRGB(x + 1, y + 1, updateViaQuantError(new Color(image.getRGB(x + 1, y + 1)), quantErrorRed, quantErrorGreen, quantErrorBlue, 1 / 16.0).getRGB());
+ Bukkit.getScheduler().runTaskTimer(LobbySystem.getPlugin(), () -> {
+ long modified = mapFile.lastModified();
+ if (modified > lastModified) {
+ lastModified = modified;
+ System.out.println("Updating Banner: " + mapFile.getName());
+ Bukkit.getScheduler().runTaskAsynchronously(LobbySystem.getPlugin(), () -> {
+ try {
+ run();
+ } catch (IOException e) {
+ // Ignore
}
- }
+ });
}
- }
+ }, 200L, 200L);
+ Bukkit.getPluginManager().registerEvents(this, LobbySystem.getPlugin());
+ }
- for (int x = 0; x < bufferedImage.getWidth(); x += 128) {
- for (int y = 0; y < bufferedImage.getHeight(); y += 128) {
- BufferedImage subImage = bufferedImage.getSubimage(x, y, 128, 128);
- CraftMapView craftMapView = (CraftMapView) Bukkit.createMap(player.getWorld());
- try {
- Field field = CraftMapView.class.getDeclaredField("worldMap");
- field.setAccessible(true);
- WorldMap worldMap = (WorldMap) field.get(craftMapView);
- for (int sx = 0; sx < 128; sx++) {
- for (int sy = 0; sy < 128; sy++) {
- byte color = MapPalette.matchColor(new Color(subImage.getRGB(sx, sy)));
- worldMap.g[sx + sy * 128] = color;
+ @EventHandler
+ public void onChunkLoad(ChunkLoadEvent event) {
+ for (Entity entity : event.getChunk().getEntities()) {
+ if (!(entity instanceof ItemFrame)) continue;
+ ItemFrame itemFrame = (ItemFrame) entity;
+ ItemStack itemStack = itemFrame.getItem();
+ if (itemStack.getType() != Material.FILLED_MAP) continue;
+ Vector vector = itemFrame.getLocation().getBlock().getLocation().toVector();
+ if (itemFrameIndex.containsKey(vector)) {
+ if (itemFrames[itemFrameIndex.get(vector)] != null) continue;
+ itemFrames[itemFrameIndex.get(vector)] = itemFrame;
+ lastModified = 0;
+ MapView mapView = ((MapMeta) itemFrame.getItem().getItemMeta()).getMapView();
+ new ArrayList<>(mapView.getRenderers()).forEach(mapView::removeRenderer);
+ mapView.addRenderer(new MapRenderer() {
+ @Override
+ public void render(MapView map, MapCanvas canvas, Player player) {
+ for (int x = 0; x < 128; x++) {
+ for (int y = 0; y < 128; y++) {
+ canvas.setPixel(x, y, (byte) 32);
+ }
}
}
- craftMapView.setLocked(true);
- } catch (IllegalAccessException | NoSuchFieldException e) {
- throw new SecurityException(e.getMessage(), e);
- }
- ItemStack itemStack = new ItemStack(Material.FILLED_MAP, 1);
- MapMeta mapMeta = (MapMeta) itemStack.getItemMeta();
- mapMeta.setMapView(craftMapView);
- itemStack.setItemMeta(mapMeta);
- player.getInventory().addItem(itemStack);
+ });
}
}
}
- private Color updateViaQuantError(Color color, int quantErrorRed, int quantErrorGreen, int quantErrorBlue, double multiplier) {
- int newRed = (int) (color.getRed() + quantErrorRed * multiplier);
- int newGreen = (int) (color.getGreen() + quantErrorGreen * multiplier);
- int newBlue = (int) (color.getBlue() + quantErrorBlue * multiplier);
- return new Color(clamp(newRed), clamp(newGreen), clamp(newBlue));
+ private void run() throws IOException {
+ BufferedImage bufferedImage = ImageIO.read(mapFile);
+
+ Set[] patches = new Set[256];
+ for (int patch = 0; patch < patches.length; patch++) {
+ patches[patch] = new HashSet<>();
+ }
+
+ for (int y = 0; y < bufferedImage.getHeight(); y++) {
+ for (int x = 0; x < bufferedImage.getWidth(); x++) {
+ Color color = new Color(bufferedImage.getRGB(x, y));
+ double red = color.getRed() / 255.0;
+ double green = color.getGreen() / 255.0;
+ double blue = color.getBlue() / 255.0;
+ double luminance = Math.sqrt(0.299 * red * red + 0.587 * green * green + 0.114 * blue * blue);
+ luminance *= 255;
+ patches[(int) luminance].add(new Point(x, y));
+ }
+ }
+
+ for (int patch = 0; patch < patches.length; patch++) {
+ Set points = patches[patch];
+ if (points.isEmpty()) continue;
+ BufferedImage patchImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
+ points.forEach(point -> {
+ patchImage.setRGB(point.getX(), point.getY(), bufferedImage.getRGB(point.getX(), point.getY()));
+ });
+ floodFill(patchImage);
+ dither(patchImage);
+ points.forEach(point -> {
+ bufferedImage.setRGB(point.getX(), point.getY(), patchImage.getRGB(point.getX(), point.getY()));
+ });
+ }
+
+ for (int y = 0; y < bufferedImage.getHeight(); y += 128) {
+ for (int x = 0; x < bufferedImage.getWidth(); x += 128) {
+ ItemFrame itemFrame = itemFrames[y / 128 * 7 + x / 128];
+ if (itemFrame == null) continue;
+ int finalX = x;
+ int finalY = y;
+ Bukkit.getScheduler().runTaskLater(LobbySystem.getPlugin(), () -> {
+ ItemStack itemStack = itemFrame.getItem();
+ MapMeta mapMeta = (MapMeta) itemStack.getItemMeta();
+ MapView mapView = mapMeta.getMapView();
+ new ArrayList<>(mapView.getRenderers()).forEach(mapView::removeRenderer);
+ mapView.addRenderer(new MapRenderer() {
+ @Override
+ public void render(MapView map, MapCanvas canvas, Player player) {
+ for (int dy = 0; dy < 128; dy++) {
+ for (int dx = 0; dx < 128; dx++) {
+ int ax = dx + finalX;
+ int ay = dy + finalY;
+ Color color = new Color(bufferedImage.getRGB(ax, ay));
+ canvas.setPixel(dx, dy, ColorInit.getColorByte(color.getRed(), color.getGreen(), color.getBlue()));
+ }
+ }
+ }
+ });
+
+ mapMeta.setMapView(mapView);
+ itemStack.setItemMeta(mapMeta);
+ itemFrame.setItem(itemStack);
+ }, 1);
+ }
+ }
}
- private int clamp(int value) {
- return Math.max(0, Math.min(255, value));
+ private static void floodFill(BufferedImage bufferedImage) {
+ WritableRaster alpha = bufferedImage.getAlphaRaster();
+ int[] data = alpha.getPixels(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), new int[bufferedImage.getWidth() * bufferedImage.getHeight()]);
+ for (int i = 0; i < 5; i++) {
+ Set changes = new HashSet<>();
+ for (int y = 0; y < bufferedImage.getHeight(); y++) {
+ for (int x = 0; x < bufferedImage.getWidth(); x++) {
+ if (data[y * bufferedImage.getWidth() + x] == 0) continue;
+ int color = bufferedImage.getRGB(x, y);
+ if (x > 0 && data[y * bufferedImage.getWidth() + x - 1] == 0) {
+ bufferedImage.setRGB(x - 1, y, color);
+ changes.add(new Point(x - 1, y));
+ }
+ if (x < bufferedImage.getWidth() - 1 && data[y * bufferedImage.getWidth() + x + 1] == 0) {
+ bufferedImage.setRGB(x + 1, y, color);
+ changes.add(new Point(x + 1, y));
+ }
+ if (y > 0 && data[(y - 1) * bufferedImage.getWidth() + x] == 0) {
+ bufferedImage.setRGB(x, y - 1, color);
+ changes.add(new Point(x, y - 1));
+ }
+ if (y < bufferedImage.getHeight() - 1 && data[(y + 1) * bufferedImage.getWidth() + x] == 0) {
+ bufferedImage.setRGB(x, y + 1, color);
+ changes.add(new Point(x, y + 1));
+ }
+ }
+ }
+ if (changes.isEmpty()) return;
+ changes.forEach(point -> {
+ data[point.getY() * bufferedImage.getWidth() + point.getX()] = 255;
+ });
+ }
}
- private static Color getNearest(Color color) {
- return MapPalette.getColor(MapPalette.matchColor(color));
+ private static BufferedImage dither(BufferedImage image) {
+ final double multiplier1 = 7 / 48.0;
+ final double multiplier2 = 3 / 48.0;
+ final double multiplier3 = 5 / 48.0;
+ final double multiplier4 = 1 / 48.0;
+ WritableRaster alphaRaster = image.getAlphaRaster();
+ WritableRaster raster = image.getRaster();
+ int numBands = raster.getNumBands();
+ int[] pixels = raster.getPixels(0, 0, image.getWidth(), image.getHeight(), new int[image.getWidth() * image.getHeight() * numBands]);
+
+ int width = image.getWidth();
+ int height = image.getHeight();
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ if (alphaRaster.getPixel(x, y, new int[1])[0] == 0) continue;
+
+ int red = pixels[(y * width + x) * numBands];
+ int i2 = (y * width + x) * numBands + 1;
+ int green = pixels[i2];
+ int i3 = (y * width + x) * numBands + 2;
+ int blue = pixels[i3];
+ Color nearest = MapPalette.getColor(ColorInit.getColorByte(red, green, blue));
+
+ pixels[(y * width + x) * numBands] = nearest.getRed();
+ pixels[i2] = nearest.getGreen();
+ pixels[i3] = nearest.getBlue();
+
+ int quantErrorRed = red - nearest.getRed();
+ int quantErrorGreen = green - nearest.getGreen();
+ int quantErrorBlue = blue - nearest.getBlue();
+
+ int mr1 = (int) (quantErrorRed * multiplier1);
+ int mg1 = (int) (quantErrorGreen * multiplier1);
+ int mb1 = (int) (quantErrorBlue * multiplier1);
+
+ int mr2 = (int) (quantErrorRed * multiplier2);
+ int mg2 = (int) (quantErrorGreen * multiplier2);
+ int mb2 = (int) (quantErrorBlue * multiplier2);
+
+ int mr3 = (int) (quantErrorRed * multiplier3);
+ int mg3 = (int) (quantErrorGreen * multiplier3);
+ int mb3 = (int) (quantErrorBlue * multiplier3);
+
+ int mr4 = (int) (quantErrorRed * multiplier4);
+ int mg4 = (int) (quantErrorGreen * multiplier4);
+ int mb4 = (int) (quantErrorBlue * multiplier4);
+
+ if (x < width - 1) {
+ int i = (y * width + x + 1) * numBands;
+ pixels[i] = clamp(pixels[i] + mr1);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg1);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb1);
+ }
+
+ if (x < width - 2) {
+ int i = (y * width + x + 2) * numBands;
+ pixels[i] = clamp(pixels[i] + mr3);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg3);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb3);
+ }
+
+ if (y < height - 1) {
+ if (x > 1) {
+ int i = ((y + 1) * width + x - 2) * numBands;
+ pixels[i] = clamp(pixels[i] + mr2);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg2);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb2);
+ }
+ if (x > 0) {
+ int i = ((y + 1) * width + x - 1) * numBands;
+ pixels[i] = clamp(pixels[i] + mr3);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg3);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb3);
+ }
+ if (x < width - 1) {
+ int i = ((y + 1) * width + x + 1) * numBands;
+ pixels[i] = clamp(pixels[i] + mr3);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg3);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb3);
+ }
+ if (x < width - 2) {
+ int i = ((y + 1) * width + x + 2) * numBands;
+ pixels[i] = clamp(pixels[i] + mr2);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg2);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb2);
+ }
+ int i = (y * width + x) * numBands;
+ pixels[i] = clamp(pixels[i] + mr1);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg1);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb1);
+ }
+
+ if (y < height - 2) {
+ if (x > 1) {
+ int i = ((y + 2) * width + x - 2) * numBands;
+ pixels[i] = clamp(pixels[i] + mr4);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg4);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb4);
+ }
+ if (x > 0) {
+ int i = ((y + 2) * width + x - 1) * numBands;
+ pixels[i] = clamp(pixels[i] + mr2);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg2);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb2);
+ }
+ if (x < width - 1) {
+ int i = ((y + 2) * width + x + 1) * numBands;
+ pixels[i] = clamp(pixels[i] + mr2);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg2);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb2);
+ }
+ if (x < width - 2) {
+ int i = ((y + 2) * width + x + 2) * numBands;
+ pixels[i] = clamp(pixels[i] + mr4);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg4);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb4);
+ }
+ int i = (y * width + x) * numBands;
+ pixels[i] = clamp(pixels[i] + mr3);
+ pixels[i + 1] = clamp(pixels[i + 1] + mg3);
+ pixels[i + 2] = clamp(pixels[i + 2] + mb3);
+ }
+ }
+ }
+ raster.setPixels(0, 0, width, height, pixels);
+ return image;
+ }
+
+ private static int clamp(int value) {
+ return Math.max(0, Math.min(value, 255));
}
}
diff --git a/src/de/steamwar/lobby/map/CustomMapCommand.java b/src/de/steamwar/lobby/map/CustomMapCommand.java
deleted file mode 100644
index c0489d9..0000000
--- a/src/de/steamwar/lobby/map/CustomMapCommand.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2022 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.lobby.map;
-
-import de.steamwar.command.SWCommand;
-import de.steamwar.command.TypeMapper;
-import de.steamwar.command.TypeValidator;
-import de.steamwar.sql.SteamwarUser;
-import de.steamwar.sql.UserPerm;
-import lombok.SneakyThrows;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-
-import javax.imageio.ImageIO;
-import java.io.File;
-import java.util.List;
-
-public class CustomMapCommand extends SWCommand {
-
- public CustomMapCommand() {
- super("map");
- }
-
- @Register
- @SneakyThrows
- public void render(@Validator Player p, File file) {
- if (!SteamwarUser.get(p.getUniqueId()).hasPerm(UserPerm.ADMINISTRATION)) {
- return;
- }
- if (!file.exists()) {
- p.sendMessage("§cDiese Datei existiert nicht!");
- return;
- }
- new CustomMap(p, ImageIO.read(file));
- }
-
- @ClassValidator(value = Player.class, local = true)
- public TypeValidator getGuardChecker() {
- return (commandSender, player, messageSender) -> SteamwarUser.get(player.getUniqueId()).hasPerm(UserPerm.ADMINISTRATION);
- }
-
- @ClassMapper(value = File.class, local = true)
- public TypeMapper getTypeMapper() {
- return new TypeMapper() {
- @Override
- public List tabCompletes(CommandSender commandSender, String[] strings, String s) {
- return null;
- }
-
- @Override
- public File map(CommandSender commandSender, String[] previousArguments, String s) {
- return new File(s);
- }
- };
- }
-}
diff --git a/src/de/steamwar/lobby/map/CustomMapNew.java b/src/de/steamwar/lobby/map/CustomMapNew.java
deleted file mode 100644
index c9703b4..0000000
--- a/src/de/steamwar/lobby/map/CustomMapNew.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2024 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.lobby.map;
-
-import de.steamwar.lobby.LobbySystem;
-import net.minecraft.world.level.saveddata.maps.WorldMap;
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.World;
-import org.bukkit.craftbukkit.v1_20_R1.map.CraftMapView;
-import org.bukkit.entity.ItemFrame;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.MapMeta;
-import org.bukkit.map.MapPalette;
-import org.bukkit.util.Vector;
-
-import javax.imageio.ImageIO;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.awt.image.WritableRaster;
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class CustomMapNew {
-
- public static void init() {
- }
-
- private static final World WORLD = Bukkit.getWorlds().get(0);
-
- private static final CustomMapNew LEFT = new CustomMapNew(new File(System.getProperty("user.home") + "/lobbyBanner/left.png"),
- new Vector(2346, 48, 1297), new Vector(2345, 48, 1297), new Vector(2344, 48, 1297), new Vector(2343, 48, 1297), new Vector(2342, 48, 1297), new Vector(2341, 48, 1297), new Vector(2340, 48, 1297),
- new Vector(2346, 47, 1297), new Vector(2345, 47, 1297), new Vector(2344, 47, 1297), new Vector(2343, 47, 1297), new Vector(2342, 47, 1297), new Vector(2341, 47, 1297), new Vector(2340, 47, 1297),
- new Vector(2346, 46, 1297), new Vector(2345, 46, 1297), new Vector(2344, 46, 1297), new Vector(2343, 46, 1297), new Vector(2342, 46, 1297), new Vector(2341, 46, 1297), new Vector(2340, 46, 1297),
- new Vector(2346, 45, 1297), new Vector(2345, 45, 1297), new Vector(2344, 45, 1297), new Vector(2343, 45, 1297), new Vector(2342, 45, 1297), new Vector(2341, 45, 1297), new Vector(2340, 45, 1297)
- );
-
- private File mapFile;
- private ItemFrame[] itemFrames = null;
-
- public CustomMapNew(File mapFile, Vector... itemFrames) {
- this.mapFile = mapFile;
-
- Bukkit.getScheduler().runTaskTimer(LobbySystem.getPlugin(), () -> {
- long lastModified = 0;
- while (true) {
- try {
- Thread.sleep(10000);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- if (this.itemFrames == null) {
- loadItemFrames(itemFrames);
- continue;
- }
-
- long modified = mapFile.lastModified();
- System.out.println(lastModified + " " + modified);
- if (modified > lastModified) {
- lastModified = modified;
- System.out.println("Updating Banner: " + mapFile.getName());
- Bukkit.getScheduler().runTaskAsynchronously(LobbySystem.getPlugin(), () -> {
- try {
- run();
- } catch (IOException e) {
- // Ignore
- }
- });
- }
- }
- }, 200L, 200L);
- }
-
- private void loadItemFrames(Vector... itemFrames) {
- for (int i = 0; i < itemFrames.length; i++) {
- itemFrames[i] = itemFrames[i].toLocation(WORLD).getBlock().getLocation().toVector();
- }
- Map worldMaps = new HashMap<>();
- WORLD.getEntitiesByClass(ItemFrame.class).forEach(itemFrame -> {
- ItemStack itemStack = itemFrame.getItem();
- System.out.println(itemFrame.getLocation().getBlock() + ": " + itemFrame + " " + itemStack);
- if (itemStack.getType() != Material.FILLED_MAP) return;
- worldMaps.put(itemFrame.getLocation().getBlock().getLocation().toVector(), itemFrame);
- });
-
- ItemFrame[] frames = new ItemFrame[itemFrames.length];
- for (int i = 0; i < frames.length; i++) {
- if (worldMaps.get(itemFrames[i]) == null) {
- System.out.println("ItemFrame at location " + itemFrames[i] + " is missing!");
- return;
- }
- frames[i] = worldMaps.get(itemFrames[i]);
- }
- this.itemFrames = frames;
- }
-
- private void run() throws IOException {
- BufferedImage bufferedImage = ImageIO.read(mapFile);
-
- Set[] patches = new Set[256];
- for (int patch = 0; patch < patches.length; patch++) {
- patches[patch] = new HashSet<>();
- }
-
- for (int y = 0; y < bufferedImage.getHeight(); y++) {
- for (int x = 0; x < bufferedImage.getWidth(); x++) {
- Color color = new Color(bufferedImage.getRGB(x, y));
- double red = color.getRed() / 255.0;
- double green = color.getGreen() / 255.0;
- double blue = color.getBlue() / 255.0;
- double luminance = Math.sqrt(0.299 * red * red + 0.587 * green * green + 0.114 * blue * blue);
- luminance *= 255;
- patches[(int) luminance].add(new Point(x, y));
- }
- }
-
- for (int patch = 0; patch < patches.length; patch++) {
- Set points = patches[patch];
- if (points.isEmpty()) continue;
- BufferedImage patchImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
- points.forEach(point -> {
- patchImage.setRGB(point.getX(), point.getY(), bufferedImage.getRGB(point.getX(), point.getY()));
- });
- floodFill(patchImage);
- dither(patchImage);
- points.forEach(point -> {
- bufferedImage.setRGB(point.getX(), point.getY(), patchImage.getRGB(point.getX(), point.getY()));
- });
- }
-
- for (int y = 0; y < bufferedImage.getHeight() / 128; y += 128) {
- for (int x = 0; x < bufferedImage.getWidth() / 128; x += 128) {
- ItemFrame itemFrame = itemFrames[y / 128 * 7 + x / 128];
- int finalX = x;
- int finalY = y;
- Bukkit.getScheduler().runTaskLater(LobbySystem.getPlugin(), () -> {
- ItemStack itemStack = itemFrame.getItem();
- MapMeta mapMeta = (MapMeta) itemStack.getItemMeta();
- CraftMapView mapView = (CraftMapView) mapMeta.getMapView();
-
- try {
- Field field = CraftMapView.class.getDeclaredField("worldMap");
- field.setAccessible(true);
- WorldMap worldMap = (WorldMap) field.get(mapView);
-
- for (int dy = 0; dy < 128; dy++) {
- for (int dx = 0; dx < 128; dx++) {
- int ax = dx + finalX;
- int ay = dy + finalY;
- Color color = new Color(bufferedImage.getRGB(ax, ay));
- worldMap.g[dx + dy * 128] = ColorInit.getColorByte(color.getRed(), color.getGreen(), color.getBlue());
- }
- }
- } catch (IllegalAccessException | NoSuchFieldException e) {
- throw new SecurityException(e.getMessage(), e);
- }
-
- mapMeta.setMapView(mapView);
- itemStack.setItemMeta(mapMeta);
- itemFrame.setItem(itemStack);
- }, 1);
- }
- }
- }
-
- private static void floodFill(BufferedImage bufferedImage) {
- WritableRaster alpha = bufferedImage.getAlphaRaster();
- int[] data = alpha.getPixels(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), new int[bufferedImage.getWidth() * bufferedImage.getHeight()]);
- for (int i = 0; i < 5; i++) {
- Set changes = new HashSet<>();
- for (int y = 0; y < bufferedImage.getHeight(); y++) {
- for (int x = 0; x < bufferedImage.getWidth(); x++) {
- if (data[y * bufferedImage.getWidth() + x] == 0) continue;
- int color = bufferedImage.getRGB(x, y);
- if (x > 0 && data[y * bufferedImage.getWidth() + x - 1] == 0) {
- bufferedImage.setRGB(x - 1, y, color);
- changes.add(new Point(x - 1, y));
- }
- if (x < bufferedImage.getWidth() - 1 && data[y * bufferedImage.getWidth() + x + 1] == 0) {
- bufferedImage.setRGB(x + 1, y, color);
- changes.add(new Point(x + 1, y));
- }
- if (y > 0 && data[(y - 1) * bufferedImage.getWidth() + x] == 0) {
- bufferedImage.setRGB(x, y - 1, color);
- changes.add(new Point(x, y - 1));
- }
- if (y < bufferedImage.getHeight() - 1 && data[(y + 1) * bufferedImage.getWidth() + x] == 0) {
- bufferedImage.setRGB(x, y + 1, color);
- changes.add(new Point(x, y + 1));
- }
- }
- }
- if (changes.isEmpty()) return;
- changes.forEach(point -> {
- data[point.getY() * bufferedImage.getWidth() + point.getX()] = 255;
- });
- }
- }
-
- private static BufferedImage dither(BufferedImage image) {
- final double multiplier1 = 7 / 48.0;
- final double multiplier2 = 3 / 48.0;
- final double multiplier3 = 5 / 48.0;
- final double multiplier4 = 1 / 48.0;
- WritableRaster alphaRaster = image.getAlphaRaster();
- WritableRaster raster = image.getRaster();
- int numBands = raster.getNumBands();
- int[] pixels = raster.getPixels(0, 0, image.getWidth(), image.getHeight(), new int[image.getWidth() * image.getHeight() * numBands]);
-
- int width = image.getWidth();
- int height = image.getHeight();
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- if (alphaRaster.getPixel(x, y, new int[1])[0] == 0) continue;
-
- int red = pixels[(y * width + x) * numBands];
- int i2 = (y * width + x) * numBands + 1;
- int green = pixels[i2];
- int i3 = (y * width + x) * numBands + 2;
- int blue = pixels[i3];
- Color nearest = MapPalette.getColor(ColorInit.getColorByte(red, green, blue));
-
- pixels[(y * width + x) * numBands] = nearest.getRed();
- pixels[i2] = nearest.getGreen();
- pixels[i3] = nearest.getBlue();
-
- int quantErrorRed = red - nearest.getRed();
- int quantErrorGreen = green - nearest.getGreen();
- int quantErrorBlue = blue - nearest.getBlue();
-
- int mr1 = (int) (quantErrorRed * multiplier1);
- int mg1 = (int) (quantErrorGreen * multiplier1);
- int mb1 = (int) (quantErrorBlue * multiplier1);
-
- int mr2 = (int) (quantErrorRed * multiplier2);
- int mg2 = (int) (quantErrorGreen * multiplier2);
- int mb2 = (int) (quantErrorBlue * multiplier2);
-
- int mr3 = (int) (quantErrorRed * multiplier3);
- int mg3 = (int) (quantErrorGreen * multiplier3);
- int mb3 = (int) (quantErrorBlue * multiplier3);
-
- int mr4 = (int) (quantErrorRed * multiplier4);
- int mg4 = (int) (quantErrorGreen * multiplier4);
- int mb4 = (int) (quantErrorBlue * multiplier4);
-
- if (x < width - 1) {
- int i = (y * width + x + 1) * numBands;
- pixels[i] = clamp(pixels[i] + mr1);
- pixels[i + 1] = clamp(pixels[i + 1] + mg1);
- pixels[i + 2] = clamp(pixels[i + 2] + mb1);
- }
-
- if (x < width - 2) {
- int i = (y * width + x + 2) * numBands;
- pixels[i] = clamp(pixels[i] + mr3);
- pixels[i + 1] = clamp(pixels[i + 1] + mg3);
- pixels[i + 2] = clamp(pixels[i + 2] + mb3);
- }
-
- if (y < height - 1) {
- if (x > 1) {
- int i = ((y + 1) * width + x - 2) * numBands;
- pixels[i] = clamp(pixels[i] + mr2);
- pixels[i + 1] = clamp(pixels[i + 1] + mg2);
- pixels[i + 2] = clamp(pixels[i + 2] + mb2);
- }
- if (x > 0) {
- int i = ((y + 1) * width + x - 1) * numBands;
- pixels[i] = clamp(pixels[i] + mr3);
- pixels[i + 1] = clamp(pixels[i + 1] + mg3);
- pixels[i + 2] = clamp(pixels[i + 2] + mb3);
- }
- if (x < width - 1) {
- int i = ((y + 1) * width + x + 1) * numBands;
- pixels[i] = clamp(pixels[i] + mr3);
- pixels[i + 1] = clamp(pixels[i + 1] + mg3);
- pixels[i + 2] = clamp(pixels[i + 2] + mb3);
- }
- if (x < width - 2) {
- int i = ((y + 1) * width + x + 2) * numBands;
- pixels[i] = clamp(pixels[i] + mr2);
- pixels[i + 1] = clamp(pixels[i + 1] + mg2);
- pixels[i + 2] = clamp(pixels[i + 2] + mb2);
- }
- int i = (y * width + x) * numBands;
- pixels[i] = clamp(pixels[i] + mr1);
- pixels[i + 1] = clamp(pixels[i + 1] + mg1);
- pixels[i + 2] = clamp(pixels[i + 2] + mb1);
- }
-
- if (y < height - 2) {
- if (x > 1) {
- int i = ((y + 2) * width + x - 2) * numBands;
- pixels[i] = clamp(pixels[i] + mr4);
- pixels[i + 1] = clamp(pixels[i + 1] + mg4);
- pixels[i + 2] = clamp(pixels[i + 2] + mb4);
- }
- if (x > 0) {
- int i = ((y + 2) * width + x - 1) * numBands;
- pixels[i] = clamp(pixels[i] + mr2);
- pixels[i + 1] = clamp(pixels[i + 1] + mg2);
- pixels[i + 2] = clamp(pixels[i + 2] + mb2);
- }
- if (x < width - 1) {
- int i = ((y + 2) * width + x + 1) * numBands;
- pixels[i] = clamp(pixels[i] + mr2);
- pixels[i + 1] = clamp(pixels[i + 1] + mg2);
- pixels[i + 2] = clamp(pixels[i + 2] + mb2);
- }
- if (x < width - 2) {
- int i = ((y + 2) * width + x + 2) * numBands;
- pixels[i] = clamp(pixels[i] + mr4);
- pixels[i + 1] = clamp(pixels[i + 1] + mg4);
- pixels[i + 2] = clamp(pixels[i + 2] + mb4);
- }
- int i = (y * width + x) * numBands;
- pixels[i] = clamp(pixels[i] + mr3);
- pixels[i + 1] = clamp(pixels[i + 1] + mg3);
- pixels[i + 2] = clamp(pixels[i + 2] + mb3);
- }
- }
- }
- raster.setPixels(0, 0, width, height, pixels);
- return image;
- }
-
- private static int clamp(int value) {
- return Math.max(0, Math.min(value, 255));
- }
-}