cleanup and introducing plugin structure

This commit is contained in:
Elias Müller 2025-03-19 17:40:18 +01:00
parent 0103a654c3
commit ddbe59a5ac
9 changed files with 201 additions and 154 deletions

1
.idea/modules.xml generated

@ -3,6 +3,7 @@
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/PixelPic.main.iml" filepath="$PROJECT_DIR$/.idea/modules/PixelPic.main.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/eu.mhsl.minecraft.pixelpic.PixelPic.main.iml" filepath="$PROJECT_DIR$/.idea/modules/eu.mhsl.minecraft.pixelpic.PixelPic.main.iml" />
</modules>
</component>
</project>

@ -11,4 +11,8 @@
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>PAPER</platformType>
<platformType>ADVENTURE</platformType>
</autoDetectTypes>
<projectReimportVersion>1</projectReimportVersion>
</configuration>
</facet>
</component>
</module>

@ -1,6 +1,5 @@
package eu.mhsl.minecraft.pixelpic;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapRenderer;
@ -10,23 +9,19 @@ import org.jetbrains.annotations.NotNull;
import java.awt.image.BufferedImage;
public class ImageMapRenderer extends MapRenderer {
public final int IMAGE_SIZE = 128;
private BufferedImage image;
private final int x;
private final int y;
public static final int IMAGE_SIZE = 128;
private final BufferedImage image;
private boolean alreadyRendered = false;
public ImageMapRenderer(BufferedImage image) {
this(image, 0, 0);
}
public ImageMapRenderer(BufferedImage image, int x, int y) {
this.x = x;
this.y = y;
recalculateInput(image);
this.image = recalculateInput(image, x, y);
}
public void recalculateInput(BufferedImage input) {
public static BufferedImage recalculateInput(BufferedImage input, int x, int y) {
if (x * IMAGE_SIZE > input.getWidth() || y * IMAGE_SIZE > input.getHeight())
throw new RuntimeException(String.format("Input image mus match a multiple of x and y with %d", IMAGE_SIZE));
@ -37,14 +32,15 @@ public class ImageMapRenderer extends MapRenderer {
int y2 = (int) (double) Math.min(input.getHeight(), ((y + 1) * IMAGE_SIZE));
if (x2 - x1 <= 0 || y2 - y1 <= 0)
return;
throw new RuntimeException("Invalid Image dimensions!");
this.image = input.getSubimage(x1, y1, x2 - x1, y2 - y1);
return input.getSubimage(x1, y1, x2 - x1, y2 - y1);
}
@Override
public void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player player) {
if(image == null) return;
Bukkit.getScheduler().runTaskLater(Main.getInstance(), () -> canvas.drawImage(0, 0, image), 2L);
if(this.alreadyRendered) return;
canvas.drawImage(0, 0, this.image);
this.alreadyRendered = true;
}
}

@ -1,120 +1,83 @@
package eu.mhsl.minecraft.pixelpic;
import eu.mhsl.minecraft.pixelpic.commands.PixelPicCommand;
import eu.mhsl.minecraft.pixelpic.render.render.DefaultScreenRenderer;
import eu.mhsl.minecraft.pixelpic.render.render.Renderer;
import eu.mhsl.minecraft.pixelpic.render.render.Resolution;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.map.MapView;
import org.bukkit.plugin.java.JavaPlugin;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
public final class Main extends JavaPlugin {
private static Main instance;
private Renderer screenRenderer;
@Override
public void onEnable() {
this.instance = this;
this.screenRenderer = new DefaultScreenRenderer();
Bukkit.getPluginCommand("test").setExecutor((sender, command, label, args) -> {
if(!(sender instanceof Player player)) return false;
Resolution.Pixels pixels = Resolution.Pixels._128P;
Resolution.AspectRatio aspectRatio = Resolution.AspectRatio._1_1;
Resolution resolution = new Resolution(pixels, aspectRatio);
BufferedImage image = screenRenderer.render((Player) sender, resolution);
Bukkit.broadcast(Component.text(image.toString()));
File file = new File(getDataFolder(), "Bild" + ".png");
try {
getDataFolder().mkdir();
ImageIO.write(image, "png", file);
} catch (Exception e) {
return true;
}
ItemStack map = new ItemStack(Material.FILLED_MAP, 1);
MapMeta meta = (MapMeta) map.getItemMeta();
MapView mapView = Bukkit.createMap(Bukkit.getWorlds().getFirst());
mapView.addRenderer(new ImageMapRenderer(image));
meta.setMapView(mapView);
map.setItemMeta(meta);
player.getInventory().addItem(map);
player.updateInventory();
return true;
});
Bukkit.getPluginCommand("test2").setExecutor((sender, command, label, args) -> {
if(!(sender instanceof Player player)) return false;
Bukkit.broadcast(Component.text("HI"));
Resolution.Pixels pixels = Resolution.Pixels._256P;
Resolution.AspectRatio aspectRatio = Resolution.AspectRatio._1_1;
Resolution resolution = new Resolution(pixels, aspectRatio);
BufferedImage image = screenRenderer.render((Player) sender, resolution);
Bukkit.broadcast(Component.text(image.toString()));
File file = new File(getDataFolder(), "Bild" + ".png");
try {
getDataFolder().mkdir();
ImageIO.write(image, "png", file);
} catch (Exception e) {
return true;
}
ItemStack map = new ItemStack(Material.FILLED_MAP, 1);
MapMeta meta = (MapMeta) map.getItemMeta();
MapView mapView = Bukkit.createMap(Bukkit.getWorlds().getFirst());
mapView.addRenderer(new ImageMapRenderer(image, 0, 0));
meta.setMapView(mapView);
map.setItemMeta(meta);
player.getInventory().addItem(map);
ItemStack map2 = new ItemStack(Material.FILLED_MAP, 1);
MapMeta meta1 = (MapMeta) map2.getItemMeta();
MapView mapView4 = Bukkit.createMap(Bukkit.getWorlds().getFirst());
mapView4.addRenderer(new ImageMapRenderer(image, 1, 0));
meta1.setMapView(mapView4);
map2.setItemMeta(meta1);
player.getInventory().addItem(map2);
ItemStack map3 = new ItemStack(Material.FILLED_MAP, 1);
MapMeta meta2 = (MapMeta) map3.getItemMeta();
MapView mapView3 = Bukkit.createMap(Bukkit.getWorlds().getFirst());
mapView3.addRenderer(new ImageMapRenderer(image, 0, 1));
meta2.setMapView(mapView3);
map3.setItemMeta(meta2);
player.getInventory().addItem(map3);
ItemStack map4 = new ItemStack(Material.FILLED_MAP, 1);
MapMeta meta3 = (MapMeta) map4.getItemMeta();
MapView mapView2 = Bukkit.createMap(Bukkit.getWorlds().getFirst());
mapView2.addRenderer(new ImageMapRenderer(image, 1, 1));
meta3.setMapView(mapView2);
map4.setItemMeta(meta3);
player.getInventory().addItem(map4);
player.updateInventory();
return true;
});
instance = this;
Bukkit.getPluginCommand("pixelPic").setExecutor(new PixelPicCommand());
//
// Bukkit.getPluginCommand("test2").setExecutor((sender, command, label, args) -> {
// if(!(sender instanceof Player player)) return false;
// Bukkit.broadcast(Component.text("HI"));
//
// Resolution.Pixels pixels = Resolution.Pixels._256P;
// Resolution.AspectRatio aspectRatio = Resolution.AspectRatio._1_1;
// Resolution resolution = new Resolution(pixels, aspectRatio);
// BufferedImage image = screenRenderer.render((Player) sender, resolution);
// Bukkit.broadcast(Component.text(image.toString()));
//
// File file = new File(getDataFolder(), "Bild" + ".png");
// try {
// getDataFolder().mkdir();
// ImageIO.write(image, "png", file);
// } catch (Exception e) {
// return true;
// }
//
// ItemStack map = new ItemStack(Material.FILLED_MAP, 1);
// MapMeta meta = (MapMeta) map.getItemMeta();
// MapView mapView = Bukkit.createMap(Bukkit.getWorlds().getFirst());
// mapView.addRenderer(new ImageMapRenderer(image, 0, 0));
// meta.setMapView(mapView);
// map.setItemMeta(meta);
// player.getInventory().addItem(map);
//
// ItemStack map2 = new ItemStack(Material.FILLED_MAP, 1);
// MapMeta meta1 = (MapMeta) map2.getItemMeta();
// MapView mapView4 = Bukkit.createMap(Bukkit.getWorlds().getFirst());
// mapView4.addRenderer(new ImageMapRenderer(image, 1, 0));
// meta1.setMapView(mapView4);
// map2.setItemMeta(meta1);
// player.getInventory().addItem(map2);
//
// ItemStack map3 = new ItemStack(Material.FILLED_MAP, 1);
// MapMeta meta2 = (MapMeta) map3.getItemMeta();
// MapView mapView3 = Bukkit.createMap(Bukkit.getWorlds().getFirst());
// mapView3.addRenderer(new ImageMapRenderer(image, 0, 1));
// meta2.setMapView(mapView3);
// map3.setItemMeta(meta2);
// player.getInventory().addItem(map3);
//
// ItemStack map4 = new ItemStack(Material.FILLED_MAP, 1);
// MapMeta meta3 = (MapMeta) map4.getItemMeta();
// MapView mapView2 = Bukkit.createMap(Bukkit.getWorlds().getFirst());
// mapView2.addRenderer(new ImageMapRenderer(image, 1, 1));
// meta3.setMapView(mapView2);
// map4.setItemMeta(meta3);
// player.getInventory().addItem(map4);
//
// player.updateInventory();
//
// return true;
// });
}
@Override
public void onDisable() {
// Plugin shutdown logic
}
public Renderer getScreenRenderer() {
if(this.screenRenderer == null) this.screenRenderer = new DefaultScreenRenderer();
return this.screenRenderer;
}
public static Main getInstance() {

@ -0,0 +1,56 @@
package eu.mhsl.minecraft.pixelpic.commands;
import eu.mhsl.minecraft.pixelpic.ImageMapRenderer;
import eu.mhsl.minecraft.pixelpic.Main;
import eu.mhsl.minecraft.pixelpic.render.render.Resolution;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.map.MapView;
import org.jetbrains.annotations.NotNull;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
public class PixelPicCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String @NotNull [] args) {
if(!(sender instanceof Player player))
throw new IllegalStateException("Dieser Command kann nur von einem Spieler ausgeführt werden!");
Resolution.Pixels pixels = Resolution.Pixels._128P;
Resolution.AspectRatio aspectRatio = Resolution.AspectRatio._1_1;
Resolution resolution = new Resolution(pixels, aspectRatio);
BufferedImage image = Main.getInstance().getScreenRenderer().render(player, resolution);
File file = new File(Main.getInstance().getDataFolder(), "Bild" + ".png");
try {
Main.getInstance().getDataFolder().mkdir();
ImageIO.write(image, "png", file);
} catch (Exception e) {
return true;
}
ItemStack map = new ItemStack(Material.FILLED_MAP, 1);
MapMeta meta = (MapMeta) map.getItemMeta();
MapView mapView = Bukkit.createMap(Bukkit.getWorlds().getFirst());
mapView.getRenderers().forEach(mapView::removeRenderer);
mapView.addRenderer(new ImageMapRenderer(image));
meta.setMapView(mapView);
map.setItemMeta(meta);
player.getInventory().addItem(map);
player.updateInventory();
return true;
}
}

@ -15,14 +15,20 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.util.Vector;
public class DefaultRaytracer implements Raytracer {
private static final int MAX_DISTANCE = 300;
private static final int REFLECTION_DEPTH = 10;
private final int maxDistance;
private final int reflectionDepth;
private final ModelRegistry textureRegistry;
private Block reflectedBlock;
public DefaultRaytracer() {
this(300, 10);
}
public DefaultRaytracer(int maxDistance, int reflectionDepth) {
this.maxDistance = maxDistance;
this.reflectionDepth = reflectionDepth;
this.textureRegistry = new DefaultModelRegistry();
this.textureRegistry.initialize();
@ -31,7 +37,7 @@ public class DefaultRaytracer implements Raytracer {
@Override
public int trace(World world, Vector point, Vector direction) {
return trace(world, point, direction, REFLECTION_DEPTH);
return trace(world, point, direction, reflectionDepth);
}
private int trace(World world, Vector point, Vector direction, int reflectionDepth) {
@ -52,19 +58,10 @@ public class DefaultRaytracer implements Raytracer {
Material occlusionMaterial = null;
BlockData occlusionData = null;
for (int i = 0; i < MAX_DISTANCE; i++) {
if (!iterator.hasNext()) {
break;
}
for (int i = 0; i < maxDistance; i++) {
if (!iterator.hasNext()) break;
Block block = iterator.next();
if (block == null) {
continue;
}
if (reflectedBlock != null && reflectedBlock.equals(block)) {
continue;
}
if (reflectedBlock != null && reflectedBlock.equals(block)) continue;
reflectedBlock = null;
Material material = block.getType();
@ -75,20 +72,30 @@ public class DefaultRaytracer implements Raytracer {
}
Model textureModel = textureRegistry.getModel(block);
Intersection currentIntersection = Intersection.of(MathUtil.toVector(iterator.getIntersectionFace()),
i == 0 ? point : iterator.getIntersectionPoint(), direction);
Intersection currentIntersection = Intersection.of(
MathUtil.toVector(iterator.getIntersectionFace()),
i == 0 ? point : iterator.getIntersectionPoint(),
direction
);
Intersection newIntersection = textureModel.intersect(block, currentIntersection);
if (newIntersection == null) {
continue;
}
if (newIntersection == null) continue;
int color = newIntersection.getColor();
if (!reflected && textureModel.getReflectionFactor() > 0 && reflectionDepth > 0 && (color >> 24) != 0) {
reflectedBlock = block;
reflectionColor = trace(world, newIntersection.getPoint(), MathUtil.reflectVector(point, direction,
newIntersection.getPoint(), newIntersection.getNormal()), reflectionDepth - 1);
reflectionColor = trace(
world,
newIntersection.getPoint(),
MathUtil.reflectVector(
point,
direction,
newIntersection.getPoint(),
newIntersection.getNormal()
),
reflectionDepth - 1
);
reflectionFactor = textureModel.getReflectionFactor();
reflected = true;
}
@ -102,9 +109,7 @@ public class DefaultRaytracer implements Raytracer {
if (textureModel.isOccluding()) {
BlockData data = block.getBlockData();
if (material == occlusionMaterial && data.equals(occlusionData)) {
continue;
}
if (material == occlusionMaterial && data.equals(occlusionData)) continue;
occlusionMaterial = material;
occlusionData = data;
@ -113,13 +118,8 @@ public class DefaultRaytracer implements Raytracer {
occlusionData = null;
}
if (transparencyStart != null && textureModel.getTransparencyFactor() > 0) {
continue;
}
if ((color >> 24) == 0) {
continue;
}
if (transparencyStart != null && textureModel.getTransparencyFactor() > 0) continue;
if ((color >> 24) == 0) continue;
baseColor = color;
finalIntersection = newIntersection.getPoint();
@ -127,13 +127,22 @@ public class DefaultRaytracer implements Raytracer {
}
if (transparencyStart != null) {
baseColor = MathUtil.weightedColorSum(baseColor, transparencyColor, transparencyFactor, (1
baseColor = MathUtil.weightedColorSum(
baseColor,
transparencyColor,
transparencyFactor,
(1
- transparencyFactor)
* (1 + transparencyStart.distance(finalIntersection == null ? transparencyStart : finalIntersection)
/ 5.0));
}
if (reflected) {
baseColor = MathUtil.weightedColorSum(baseColor, reflectionColor, 1 - reflectionFactor, reflectionFactor);
baseColor = MathUtil.weightedColorSum(
baseColor,
reflectionColor,
1 - reflectionFactor,
reflectionFactor
);
}
return baseColor & 0xFFFFFF;

@ -5,6 +5,7 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.util.BlockIterator;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
public class BlockRaytracer extends BlockIterator {
@ -32,14 +33,16 @@ public class BlockRaytracer extends BlockIterator {
public Vector getIntersectionPoint() {
BlockFace lastFace = getIntersectionFace();
Vector planeNormal = new Vector(lastFace.getModX(), lastFace.getModY(), lastFace.getModZ());
Vector planePoint = lastBlock.getLocation().add(0.5, 0.5, 0.5).toVector()
.add(planeNormal.clone().multiply(0.5));
Vector planePoint = lastBlock.getLocation()
.add(0.5, 0.5, 0.5)
.toVector()
.add(planeNormal.clone().multiply(0.5));
return MathUtil.getLinePlaneIntersection(position, direction, planePoint, planeNormal, true);
}
@Override
public Block next() {
public @NotNull Block next() {
Block currentBlock = super.next();
currentFace = lastBlock == null ? BlockFace.SELF : currentBlock.getFace(lastBlock);

@ -3,5 +3,6 @@ version: '1.0-SNAPSHOT'
main: eu.mhsl.minecraft.pixelpic.Main
api-version: '1.21'
commands:
test:
test2:
pixelPic:
permission: "pixelpic.use"
usage: "pixelpic take"