13
0

CustomMap #40

Zusammengeführt
YoyoNow hat 2 Commits von CustomMap nach master 2024-07-17 21:17:34 +02:00 zusammengeführt
6 geänderte Dateien mit 149888 neuen und 2 gelöschten Zeilen
Nur Änderungen aus Commit 60b543d426 werden angezeigt - Alle Commits anzeigen

Datei anzeigen

@ -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

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Datei anzeigen

@ -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();

Datei anzeigen

@ -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");
}
}

Datei anzeigen

@ -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));
}
}

Datei anzeigen

@ -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;
}
}