diff --git a/src/de/steamwar/lobby/LobbySystem.java b/src/de/steamwar/lobby/LobbySystem.java index 9ebcd3a..0ec117d 100644 --- a/src/de/steamwar/lobby/LobbySystem.java +++ b/src/de/steamwar/lobby/LobbySystem.java @@ -19,11 +19,12 @@ package de.steamwar.lobby; -import de.steamwar.lobby.command.ModifyCommand; import de.steamwar.lobby.command.FlyCommand; import de.steamwar.lobby.command.HologramCommand; +import de.steamwar.lobby.command.ModifyCommand; import de.steamwar.lobby.command.PortalCommand; import de.steamwar.lobby.listener.*; +import de.steamwar.lobby.map.CustomMapCommand; import de.steamwar.lobby.team.TeamPlayer; import de.steamwar.message.Message; import org.bukkit.plugin.java.JavaPlugin; @@ -50,6 +51,7 @@ public class LobbySystem extends JavaPlugin { new HologramCommand(); new FlyCommand(); new ModifyCommand(); + new CustomMapCommand(); config = new Config(getConfig()); new PlayerSpawn(); @@ -66,7 +68,6 @@ public class LobbySystem extends JavaPlugin { new AlphaWall(l -> l.getX() < 2977, AlphaWall.REFLECT_X); new AlphaWall(l -> l.getZ() > 892, AlphaWall.REFLECT_Z); new AlphaWall(l -> l.getZ() < 1794, AlphaWall.REFLECT_Z); - } @Override diff --git a/src/de/steamwar/lobby/listener/WorldInteraction.java b/src/de/steamwar/lobby/listener/WorldInteraction.java index 8bef3fc..707563b 100644 --- a/src/de/steamwar/lobby/listener/WorldInteraction.java +++ b/src/de/steamwar/lobby/listener/WorldInteraction.java @@ -22,20 +22,41 @@ package de.steamwar.lobby.listener; import de.steamwar.lobby.command.ModifyCommand; import org.bukkit.Material; import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent; +import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.server.MapInitializeEvent; import org.bukkit.util.Vector; public class WorldInteraction extends BasicListener { + @EventHandler + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player)) { + return; + } + if(!ModifyCommand.modifying((Player) event.getDamager())) { + event.setCancelled(true); + return; + } + if (!(event.getEntity() instanceof ItemFrame)) { + return; + } + ItemFrame itemFrame = (ItemFrame) event.getEntity(); + ((Player) event.getDamager()).getInventory().addItem(itemFrame.getItem()); + itemFrame.setItem(null); + } + @EventHandler public void handleEntityDamage(EntityDamageEvent event) { event.setCancelled(true); diff --git a/src/de/steamwar/lobby/map/CustomMap.java b/src/de/steamwar/lobby/map/CustomMap.java new file mode 100644 index 0000000..6bf8536 --- /dev/null +++ b/src/de/steamwar/lobby/map/CustomMap.java @@ -0,0 +1,110 @@ +/* + * 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 net.minecraft.server.v1_15_R1.WorldMap; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_15_R1.map.CraftMapView; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.MapMeta; +import org.bukkit.map.MapPalette; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.lang.reflect.Field; + +public class CustomMap { + + 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"); + } + + 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()); + } + } + } + } + + 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.colors[sx + sy * 128] = color; + } + } + 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 int clamp(int value) { + return Math.max(0, Math.min(255, value)); + } + + private static Color getNearest(Color color) { + return MapPalette.getColor(MapPalette.matchColor(color)); + } +} diff --git a/src/de/steamwar/lobby/map/CustomMapCommand.java b/src/de/steamwar/lobby/map/CustomMapCommand.java new file mode 100644 index 0000000..c2d6f6a --- /dev/null +++ b/src/de/steamwar/lobby/map/CustomMapCommand.java @@ -0,0 +1,80 @@ +/* + * 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.GuardChecker; +import de.steamwar.command.GuardResult; +import de.steamwar.command.SWCommand; +import de.steamwar.command.TypeMapper; +import de.steamwar.sql.SteamwarUser; +import de.steamwar.sql.UserGroup; +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(@Guard Player p, File file) { + if (SteamwarUser.get(p).getUserGroup() != UserGroup.Developer) { + return; + } + if (!file.exists()) { + p.sendMessage("§cDiese Datei existiert nicht!"); + return; + } + new CustomMap(p, ImageIO.read(file)); + } + + @ClassGuard(value = Player.class, local = true) + public GuardChecker getGuardChecker() { + return (commandSender, guardCheckType, strings, s) -> { + Player player = (Player) commandSender; + if (SteamwarUser.get(player).getUserGroup() == UserGroup.Developer) { + return GuardResult.ALLOWED; + } + return GuardResult.DENIED; + }; + } + + @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); + } + }; + } +}