CustomMap #40
@ -31,8 +31,8 @@ mainClassName = ''
|
||||
|
||||
compileJava.options.encoding = 'UTF-8'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
sourceCompatibility = 11
|
||||
targetCompatibility = 11
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
|
149468
src/colors.nearest
Normale Datei
149468
src/colors.nearest
Normale Datei
Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist
@ -28,6 +28,7 @@ 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.particle.ParticleListener;
|
||||
import de.steamwar.lobby.special.advent.AdventsCalendar;
|
||||
import de.steamwar.lobby.team.TeamPlayer;
|
||||
@ -53,6 +54,8 @@ public class LobbySystem extends JavaPlugin {
|
||||
entityServer = new REntityServer();
|
||||
debugEntityServer = new REntityServer();
|
||||
|
||||
CustomMapNew.init();
|
||||
|
||||
Fightserver.init();
|
||||
new Portals();
|
||||
new PortalCommand();
|
||||
|
41
src/de/steamwar/lobby/map/ColorInit.java
Normale Datei
41
src/de/steamwar/lobby/map/ColorInit.java
Normale Datei
@ -0,0 +1,41 @@
|
||||
package de.steamwar.lobby.map;
|
||||
|
||||
import org.bukkit.map.MapPalette;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ColorInit {
|
||||
|
||||
private static final byte[] colors;
|
||||
|
||||
public static int getColor(int r, int g, int b) {
|
||||
return colors[(r << 16) + (g << 8) + b] & 0xFF;
|
||||
}
|
||||
|
||||
public static byte getColorByte(int r, int g, int b) {
|
||||
return colors[(r << 16) + (g << 8) + b];
|
||||
}
|
||||
|
||||
static {
|
||||
long time = System.currentTimeMillis();
|
||||
InputStream inputStream = ColorInit.class.getResourceAsStream("/colors.nearest");
|
||||
if (inputStream == null) {
|
||||
colors = new byte[256 * 256 * 256];
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
colors[i] = MapPalette.matchColor(new Color(i));
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
byte[] bytes = inputStream.readAllBytes();
|
||||
if (bytes.length != 256*256*256) {
|
||||
throw new RuntimeException("Invalid colors.nearest file");
|
||||
}
|
||||
colors = bytes;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to read colors.nearest file", e);
|
||||
}
|
||||
}
|
||||
System.out.println("[ColorInit] Initialization took " + (System.currentTimeMillis() - time) + "ms");
|
||||
}
|
||||
}
|
354
src/de/steamwar/lobby/map/CustomMapNew.java
Normale Datei
354
src/de/steamwar/lobby/map/CustomMapNew.java
Normale Datei
@ -0,0 +1,354 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Vector, ItemFrame> 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<Point>[] 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<Point> 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<Point> 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));
|
||||
}
|
||||
}
|
20
src/de/steamwar/lobby/map/Point.java
Normale Datei
20
src/de/steamwar/lobby/map/Point.java
Normale Datei
@ -0,0 +1,20 @@
|
||||
package de.steamwar.lobby.map;
|
||||
|
||||
public class Point {
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public Point(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
}
|
In neuem Issue referenzieren
Einen Benutzer sperren