From c3bf1943a5cdb971b13ec25bf28cd08c895c7601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sun, 13 Oct 2024 18:38:05 +0200 Subject: [PATCH] refactored to not store entities --- .../pixelblocks/pixelblock/Pixel.java | 65 -------- .../pixelblocks/pixelblock/PixelBlock.java | 131 +++------------ .../pixelblock/PixelBlockHitbox.java | 157 +++++++++--------- .../pixelblock/PixelBlockPlaceholder.java | 52 +++--- .../pixelblock/PixelBlockWorld.java | 34 +++- .../pixelblocks/pixelblock/Pixels.java | 62 +++++++ .../minecraft/pixelblocks/utils/ListUtil.java | 19 +++ 7 files changed, 236 insertions(+), 284 deletions(-) delete mode 100644 src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/Pixel.java create mode 100644 src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/Pixels.java create mode 100644 src/main/java/eu/mhsl/minecraft/pixelblocks/utils/ListUtil.java diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/Pixel.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/Pixel.java deleted file mode 100644 index 76488c5..0000000 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/Pixel.java +++ /dev/null @@ -1,65 +0,0 @@ -package eu.mhsl.minecraft.pixelblocks.pixelblock; - -import eu.mhsl.minecraft.pixelblocks.Main; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.BlockDisplay; -import org.bukkit.entity.EntityType; -import org.bukkit.persistence.PersistentDataType; -import org.bukkit.util.Transformation; -import org.bukkit.util.Vector; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -public class Pixel { - private static final NamespacedKey pixelOfTag = new NamespacedKey(Main.plugin, "pixel_of"); - - private final @NotNull PixelBlock parentBlock; - private final @NotNull BlockDisplay entity; - - private final Location location; - - public static List fromExisting(PixelBlock parentBlock) { - return parentBlock.getPixelBlockLocation().getNearbyEntitiesByType(BlockDisplay.class, 1) - .stream() - .filter(blockDisplay -> blockDisplay.getPersistentDataContainer().has(pixelOfTag)) - .filter(blockDisplay -> Objects.equals( - blockDisplay.getPersistentDataContainer().get(pixelOfTag, PersistentDataType.STRING), - parentBlock.getBlockUUID().toString() - )) - .map(blockDisplay -> new Pixel(parentBlock, blockDisplay)) - .collect(Collectors.toList()); - } - private Pixel(@NotNull PixelBlock parentBlock, @NotNull BlockDisplay entity) { - this.parentBlock = parentBlock; - this.entity = entity; - this.location = entity.getLocation(); - } - - public static Pixel newPixel(PixelBlock parentBlock, Vector relativePosition, BlockData blockData, double scale) { - return new Pixel(parentBlock, relativePosition, blockData, scale); - } - private Pixel(@NotNull PixelBlock parentBlock, @NotNull Vector relativePosition, @NotNull BlockData blockData, double scale) { - this.parentBlock = parentBlock; - this.location = parentBlock.getPixelBlockLocation().add(relativePosition.multiply(scale)); - this.entity = (BlockDisplay) this.location.getWorld().spawnEntity(this.location, EntityType.BLOCK_DISPLAY); - - this.entity.setBlock(blockData); - Transformation transform = this.entity.getTransformation(); - transform.getScale().set(scale); - this.entity.setTransformation(transform); - this.entity.getPersistentDataContainer().set(pixelOfTag, PersistentDataType.STRING, this.parentBlock.getBlockUUID().toString()); - } - - public void destroy() { - this.entity.remove(); - } - - public Location getLocation() { - return location.clone(); - } -} diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlock.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlock.java index 38111a3..dafc3be 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlock.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlock.java @@ -7,26 +7,21 @@ import eu.mhsl.minecraft.pixelblocks.utils.Direction; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.*; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; -import java.io.File; import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.IntStream; public class PixelBlock { private boolean exists = true; private PixelBlockWorld pixelWorld; - private final int pixelsPerBlock = Main.configuration.pixelsPerBlock(); - private final Location pixelBlockLocation; private final Direction facingDirection; - private List pixels = new ArrayList<>(); + private Pixels pixels; + private List pixelData; private PixelBlockHitbox hitbox; private PixelBlockPlaceholder placeholder; @@ -35,12 +30,6 @@ public class PixelBlock { private final UUID ownerUUID; private final UUID blockUUID; - public static final int maxPixelsPerBlock = 2000; - - public static @NotNull String getWorldName(@NotNull PixelBlock pixelBlock) { - return Main.plugin.getDataFolder().getPath() + File.separator + pixelBlock.blockUUID; - } - public static @Nullable PixelBlock getPixelBlockFromBlockWorld(World world) { return Main.pixelBlocks.stream() .filter(block -> block.blockUUID.equals(getUUIDFromWorld(world))) @@ -79,14 +68,14 @@ public class PixelBlock { this.facingDirection = direction; this.lastEntryLocation = lastEntryLocation; - this.ensureChunksLoaded(); try { this.pixelWorld = new PixelBlockWorld(this); - this.pixels = Pixel.fromExisting(this); - this.placeholder = PixelBlockPlaceholder.fromExisting(this); - this.hitbox = PixelBlockHitbox.fromExisting(this); + this.pixelData = this.pixelWorld.getPixels(this.facingDirection); + this.pixels = new Pixels(this); + this.placeholder = new PixelBlockPlaceholder(this); + this.hitbox = new PixelBlockHitbox(this); - Main.plugin.getLogger().info(String.format("Loaded existing pixelblock '%s' with %d pixels", this.blockUUID, this.pixels.size())); + Main.plugin.getLogger().info(String.format("Loaded existing pixelblock '%s'", this.blockUUID)); } catch(Exception e) { Main.plugin.getLogger().info(String.format("Failed initializing existing pixelblock '%s': %s", this.blockUUID, e.getMessage())); } @@ -109,8 +98,10 @@ public class PixelBlock { this.getBlockTaskChain() .sync(() -> { this.pixelWorld = new PixelBlockWorld(this); - this.placeholder = PixelBlockPlaceholder.newPlaceholder(this); - this.hitbox = PixelBlockHitbox.newHitbox(this); + this.pixelData = this.pixelWorld.getPixels(this.facingDirection); + this.pixels = new Pixels(this); + this.placeholder = new PixelBlockPlaceholder(this); + this.hitbox = new PixelBlockHitbox(this); }) .execute(); @@ -128,15 +119,6 @@ public class PixelBlock { return Main.sharedChain(this.blockUUID.toString()); } - private void ensureChunksLoaded() { - Chunk chunk = this.pixelBlockLocation.getChunk(); - if(!chunk.isLoaded() || !chunk.isEntitiesLoaded()) { - Main.plugin.getLogger().info(String.format("Loading chunk '%d, %d' for pixelblock '%s'", chunk.getX(), chunk.getZ(), this.blockUUID)); - chunk.load(true); - chunk.getEntities(); - } - } - public void enterBlock(@NotNull Player player) { if(Main.configuration.onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) { player.sendMessage(Component.text("Dieser Pixelblock gehört nicht dir!", NamedTextColor.RED)); @@ -161,68 +143,22 @@ public class PixelBlock { this.getBlockTaskChain() .sync(() -> player.teleport(this.lastEntryLocation != null ? this.lastEntryLocation : this.pixelBlockLocation)) .current(() -> Main.plugin.getLogger().info(String.format("%s exited PixelBlock", player.getName()))) + .sync(() -> this.pixelData = this.pixelWorld.getPixels(this.facingDirection)) .execute(); this.scheduleEntityUpdate(); } private void scheduleEntityUpdate() { - record PixelData(PixelBlock parent, Vector relativeLocation, BlockData block, double scale) { - Pixel create() { - return Pixel.newPixel(this.parent, this.relativeLocation, this.block, this.scale); - } - } - List pixelData = new ArrayList<>(); - - this.scheduleEntityRemove(); this.getBlockTaskChain() - .async(() -> { - for (int x = 0; x < pixelsPerBlock; x++) { - for (int y = 0; y < pixelsPerBlock; y++) { - for (int z = 0; z < pixelsPerBlock; z++) { - World world = pixelBlockLocation.getWorld(); - Location relativeLocation = new Location(world, x, y, z); - - Location blockLocation = this.pixelWorld.getBuildOrigin(); - switch (this.facingDirection) { - case south -> blockLocation.add(relativeLocation.x(), relativeLocation.y(), relativeLocation.z()); - case north -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.x(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.z()); - case east -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.z(), relativeLocation.y(), relativeLocation.x()); - case west -> blockLocation.add(relativeLocation.z(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.x()); - } - BlockData block = blockLocation.getBlock().getBlockData(); - - if(!block.getMaterial().isEmpty()) { - pixelData.add(new PixelData(this, relativeLocation.toVector(), block, (double) 1 / pixelsPerBlock)); - } - } - } - } + .sync(this::removeEntities) + .async(() -> Collections.shuffle(this.pixelData)) + .delay(1) + .syncLast((pixelData) -> { + this.pixels.spawn(); + this.hitbox.spawn(); + this.placeholder.spawn(); }) - .async(() -> Collections.shuffle(pixelData)) - .asyncFirst(() -> { - int spawnSpreadInTicks = 10; - int chunkSize = (int) Math.ceil((double) pixelData.size() / spawnSpreadInTicks); - - TaskChain spawnTask = this.getBlockTaskChain(); - IntStream.range(0, spawnSpreadInTicks) - .mapToObj(i -> pixelData.stream() - .skip((long) i * chunkSize) - .limit(chunkSize) - .collect(Collectors.toList())) - .forEach(pixels -> spawnTask - .delay(1) - .sync(() -> pixels.forEach(pixel -> this.pixels.add(pixel.create())))); - - return spawnTask; - }) - .syncLast((chain) -> chain - .sync(() -> { - this.hitbox = PixelBlockHitbox.newHitbox(this); - this.placeholder = PixelBlockPlaceholder.newPlaceholder(this); - Main.plugin.getLogger().info(String.format("Placed %d entities for PixelBlock '%s'", this.pixels.size(), this.blockUUID)); - }) - .execute()) .execute(); } @@ -261,9 +197,9 @@ public class PixelBlock { .filter(entity -> entity instanceof Item) .forEach(entity -> entity.teleport(this.lastEntryLocation)); - this.scheduleEntityRemove(); this.getBlockTaskChain() .sync(() -> { + this.removeEntities(); World world = this.pixelBlockLocation.getWorld(); world.playSound(this.pixelBlockLocation, Sound.BLOCK_COPPER_BULB_BREAK, 1.0F, 30); world.dropItem(this.pixelBlockLocation.add(new Vector(0.5, 0.5, 0.5)), PixelBlockItem.getBlockAsItem(this)); @@ -275,25 +211,10 @@ public class PixelBlock { .execute(); } - private void scheduleEntityRemove() { - this.getBlockTaskChain() - .current(() -> Main.plugin.getLogger() - .info(String.format("Removing %d pixels in PixelBlock '%s'", this.pixels.size(), this.blockUUID))) - .sync(this::ensureChunksLoaded) - .delay(1) - .sync(() -> { - List entitiesBefore = this.pixelBlockLocation.getWorld().getEntities(); - this.pixels.forEach(Pixel::destroy); - List entitiesAfter = this.pixelBlockLocation.getWorld().getEntities(); - - Main.plugin.getLogger().info("Entities im Chunk vor dem Entfernen: " + entitiesBefore.size()); - Main.plugin.getLogger().info("Entities im Chunk nach dem Entfernen: " + entitiesAfter.size()); - - this.pixels.clear(); - this.placeholder.destroy(); - this.hitbox.destroy(); - }) - .execute(); + private void removeEntities() { + this.pixels.destroy(); + this.placeholder.destroy(); + this.hitbox.destroy(); } public @NotNull PixelBlockWorld getPixelWorld() { @@ -312,8 +233,8 @@ public class PixelBlock { return this.lastEntryLocation != null; } - public List getPixels() { - return pixels; + public List getPixelData() { + return pixelData; } public Location getLastEntryLocation() { diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockHitbox.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockHitbox.java index cd42909..95989d4 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockHitbox.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockHitbox.java @@ -1,24 +1,94 @@ package eu.mhsl.minecraft.pixelblocks.pixelblock; import eu.mhsl.minecraft.pixelblocks.Main; -import eu.mhsl.minecraft.pixelblocks.utils.MinMaxUtil; import org.bukkit.Location; import org.bukkit.NamespacedKey; +import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Interaction; import org.bukkit.persistence.PersistentDataType; import java.util.List; import java.util.Objects; -import java.util.UUID; public class PixelBlockHitbox { private static final NamespacedKey hitboxOfTag = new NamespacedKey(Main.plugin, "hitbox_of"); - private final Interaction interaction; + private final PixelBlock parentBlock; - public static PixelBlockHitbox fromExisting(PixelBlock parentBlock) { - Interaction hitBox = parentBlock.getPixelBlockLocation().getNearbyEntitiesByType(Interaction.class, 1) + public PixelBlockHitbox(PixelBlock parentBlock) { + this.parentBlock = parentBlock; + } + + public void spawn() { + Location pixelBlockLocation = this.parentBlock.getPixelBlockLocation(); + List pixels = this.parentBlock.getPixelData(); + double scale = pixels.getFirst().scale(); + + float offset = (float) Main.configuration.hitboxOffset(); + int pixelsPerBlock = Main.configuration.pixelsPerBlock(); + + Interaction interaction; + if(true) { + interaction = (Interaction) pixelBlockLocation.getWorld().spawnEntity( + pixelBlockLocation.clone().add(0.5, -offset, 0.5), + EntityType.INTERACTION + ); + interaction.setInteractionHeight(1 + 2*offset); + interaction.setInteractionWidth(1 + 2*offset); + } else { +// double startingX = this.parentBlock.getPixelBlockLocation().x() + MinMaxUtil.getMinProperty(pixels, pixel -> pixel.relativeLocation().getX()) * scale; +// double startingY = this.parentBlock.getPixelBlockLocation().y() + MinMaxUtil.getMinProperty(pixels, pixel -> pixel.relativeLocation().getY()) * scale; +// double startingZ = this.parentBlock.getPixelBlockLocation().z() + MinMaxUtil.getMinProperty(pixels, pixel -> pixel.relativeLocation().getZ()) * scale; +// +// double endingX = this.parentBlock.getPixelBlockLocation().x() + MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.relativeLocation().getX()) * scale; +// double endingY = this.parentBlock.getPixelBlockLocation().y() + MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.relativeLocation().getY()) * scale; +// double endingZ = this.parentBlock.getPixelBlockLocation().z() + MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.relativeLocation().getZ()) * scale; +// +// Location spawnLocation = pixelBlockLocation.clone().add( +// ((startingX+endingX+1)/2)/pixelsPerBlock, +// (startingY/pixelsPerBlock)-offset, +// ((startingZ+endingZ+1)/2)/pixelsPerBlock +// ); +// +// float height = (float) (endingY-startingY+1)/pixelsPerBlock + 2*offset; +// +// float width; +// if((endingX-startingX) > (endingZ-startingZ)) { +// width = (float) (endingX-startingX+1)/pixelsPerBlock + 2*offset; +// } else { +// width = (float) (endingZ-startingZ+1)/pixelsPerBlock + 2*offset; +// } +// +// if(spawnLocation.getX()+width/2 > pixelBlockLocation.getX()+1) { +// spawnLocation.subtract((spawnLocation.getX()+width/2)-(pixelBlockLocation.getX()+1), 0, 0); +// } +// if(spawnLocation.getX()-width/2 < pixelBlockLocation.getX()) { +// spawnLocation.add(pixelBlockLocation.getX()-(spawnLocation.getX()-width/2), 0, 0); +// } +// +// if(spawnLocation.getZ()+width/2 > pixelBlockLocation.getZ()+1) { +// spawnLocation.subtract(0, 0, (spawnLocation.getZ()+width/2)-(pixelBlockLocation.getZ()+1)); +// } +// if(spawnLocation.getZ()-width/2 < pixelBlockLocation.getZ()) { +// spawnLocation.add(0, 0, pixelBlockLocation.getZ()-(spawnLocation.getZ()-width/2)); +// } +// +// interaction = (Interaction) pixelBlockLocation.getWorld().spawnEntity( +// spawnLocation, +// EntityType.INTERACTION +// ); +// +// interaction.setInteractionHeight(height); +// interaction.setInteractionWidth(width); + } + + interaction.getPersistentDataContainer() + .set(hitboxOfTag, PersistentDataType.STRING, this.parentBlock.getBlockUUID().toString()); + } + + public void destroy() { + this.parentBlock.getPixelBlockLocation().getNearbyEntitiesByType(Interaction.class, 1) .stream() .filter(interaction -> interaction.getPersistentDataContainer().has(hitboxOfTag)) .filter(interaction -> Objects.equals( @@ -28,81 +98,6 @@ public class PixelBlockHitbox { .reduce((a, b) -> { throw new IllegalStateException(String.format("Mehrere hitboxen für PixelBlock '%s' gefunden!", parentBlock.getBlockUUID())); }) - .orElseThrow(); - - Main.plugin.getLogger().info(String.format("Found existing hitbox '%s' for block '%s'", hitBox.getUniqueId(), parentBlock.getBlockUUID())); - return new PixelBlockHitbox(hitBox); - } - private PixelBlockHitbox(Interaction interaction) { - this.interaction = interaction; - } - - public static PixelBlockHitbox newHitbox(PixelBlock parentBlock) { - return new PixelBlockHitbox(parentBlock.getPixelBlockLocation(), parentBlock.getPixels(), parentBlock.getBlockUUID()); - } - private PixelBlockHitbox(Location pixelBlockLocation, List pixels, UUID parentBlockUUID) { - float offset = (float) Main.configuration.hitboxOffset(); - int pixelsPerBlock = Main.configuration.pixelsPerBlock(); - - if(pixels.size() > 5 || true) { - interaction = (Interaction) pixelBlockLocation.getWorld().spawnEntity( - pixelBlockLocation.clone().add(0.5, -offset, 0.5), - EntityType.INTERACTION - ); - interaction.setInteractionHeight(1 + 2*offset); - interaction.setInteractionWidth(1 + 2*offset); - } else { - double startingX = MinMaxUtil.getMinProperty(pixels, pixel -> pixel.getLocation().getX()); - double startingY = MinMaxUtil.getMinProperty(pixels, pixel -> pixel.getLocation().getY()); - double startingZ = MinMaxUtil.getMinProperty(pixels, pixel -> pixel.getLocation().getZ()); - - double endingX = MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.getLocation().getX()); - double endingY = MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.getLocation().getY()); - double endingZ = MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.getLocation().getZ()); - - Location spawnLocation = pixelBlockLocation.clone().add( - ((startingX+endingX+1)/2)/pixelsPerBlock, - (startingY/pixelsPerBlock)-offset, - ((startingZ+endingZ+1)/2)/pixelsPerBlock - ); - - float height = (float) (endingY-startingY+1)/pixelsPerBlock + 2*offset; - - float width; - if((endingX-startingX) > (endingZ-startingZ)) { - width = (float) (endingX-startingX+1)/pixelsPerBlock + 2*offset; - } else { - width = (float) (endingZ-startingZ+1)/pixelsPerBlock + 2*offset; - } - - if(spawnLocation.getX()+width/2 > pixelBlockLocation.getX()+1) { - spawnLocation.subtract((spawnLocation.getX()+width/2)-(pixelBlockLocation.getX()+1), 0, 0); - } - if(spawnLocation.getX()-width/2 < pixelBlockLocation.getX()) { - spawnLocation.add(pixelBlockLocation.getX()-(spawnLocation.getX()-width/2), 0, 0); - } - - if(spawnLocation.getZ()+width/2 > pixelBlockLocation.getZ()+1) { - spawnLocation.subtract(0, 0, (spawnLocation.getZ()+width/2)-(pixelBlockLocation.getZ()+1)); - } - if(spawnLocation.getZ()-width/2 < pixelBlockLocation.getZ()) { - spawnLocation.add(0, 0, pixelBlockLocation.getZ()-(spawnLocation.getZ()-width/2)); - } - - interaction = (Interaction) pixelBlockLocation.getWorld().spawnEntity( - spawnLocation, - EntityType.INTERACTION - ); - - interaction.setInteractionHeight(height); - interaction.setInteractionWidth(width); - } - - this.interaction.getPersistentDataContainer() - .set(hitboxOfTag, PersistentDataType.STRING, parentBlockUUID.toString()); - } - - public void destroy() { - this.interaction.remove(); + .ifPresent(Entity::remove); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockPlaceholder.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockPlaceholder.java index f7ed9d8..4272eea 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockPlaceholder.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockPlaceholder.java @@ -18,32 +18,16 @@ import java.util.*; public class PixelBlockPlaceholder { private static final NamespacedKey placeholderOfTag = new NamespacedKey(Main.plugin, "placeholder_of"); - List placeholders = new ArrayList<>(); + private final PixelBlock parentBlock; - public static PixelBlockPlaceholder fromExisting(PixelBlock parentBlock) { - List placeholders = parentBlock.getPixelBlockLocation() - .getNearbyEntitiesByType(ItemDisplay.class, 1) - .stream() - .filter(itemDisplay -> itemDisplay.getPersistentDataContainer().has(placeholderOfTag)) - .filter(itemDisplay -> Objects.equals( - itemDisplay.getPersistentDataContainer().get(placeholderOfTag, PersistentDataType.STRING), - parentBlock.getBlockUUID().toString() - )) - .toList(); - - Main.plugin.getLogger().info(String.format("Found %d existing placeholders for block '%s'", placeholders.size(), parentBlock.getBlockUUID())); - return new PixelBlockPlaceholder(placeholders); - } - private PixelBlockPlaceholder(List itemDisplays) { - this.placeholders = itemDisplays; + public PixelBlockPlaceholder(PixelBlock parentBlock) { + this.parentBlock = parentBlock; } - public static PixelBlockPlaceholder newPlaceholder(PixelBlock parentBlock) { - return new PixelBlockPlaceholder(parentBlock); - } - private PixelBlockPlaceholder(PixelBlock parentBlock) { - if(parentBlock.getPixels().size() > 5) return; + public void spawn() { + if(parentBlock.getPixelData().size() > 5) return; + List placeholders = new ArrayList<>(); Location pixelBlockLocation = parentBlock.getPixelBlockLocation(); UUID parentBlockUUID = parentBlock.getBlockUUID(); @@ -56,7 +40,7 @@ public class PixelBlockPlaceholder { EntityType.ITEM_DISPLAY ); verticalCore.setRotation(i, 0); - this.placeholders.add(verticalCore); + placeholders.add(verticalCore); } ItemDisplay horizontalCore = (ItemDisplay) pixelBlockWorld.spawnEntity( @@ -64,9 +48,9 @@ public class PixelBlockPlaceholder { EntityType.ITEM_DISPLAY ); horizontalCore.setRotation(0, 90); - this.placeholders.add(horizontalCore); + placeholders.add(horizontalCore); - this.placeholders.forEach(coreDisplay -> { + placeholders.forEach(coreDisplay -> { coreDisplay.setItemStack(ItemStack.of(Material.END_CRYSTAL)); Transformation transform = coreDisplay.getTransformation(); transform.getScale().set(0.5); @@ -78,18 +62,22 @@ public class PixelBlockPlaceholder { EntityType.ITEM_DISPLAY ); displayContainer.setItemStack(ItemStack.of(Material.WHITE_STAINED_GLASS)); - this.placeholders.add(displayContainer); + placeholders.add(displayContainer); - this.setDataTags(parentBlockUUID); - } - - private void setDataTags(UUID parentBlockUUID) { - this.placeholders.stream() + placeholders.stream() .map(PersistentDataHolder::getPersistentDataContainer) .forEach(container -> container.set(placeholderOfTag, PersistentDataType.STRING, parentBlockUUID.toString())); } public void destroy() { - this.placeholders.forEach(Entity::remove); + this.parentBlock.getPixelBlockLocation() + .getNearbyEntitiesByType(ItemDisplay.class, 1) + .stream() + .filter(itemDisplay -> itemDisplay.getPersistentDataContainer().has(placeholderOfTag)) + .filter(itemDisplay -> Objects.equals( + itemDisplay.getPersistentDataContainer().get(placeholderOfTag, PersistentDataType.STRING), + parentBlock.getBlockUUID().toString() + )) + .forEach(Entity::remove); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockWorld.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockWorld.java index 330bc22..09c3225 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockWorld.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockWorld.java @@ -1,14 +1,18 @@ package eu.mhsl.minecraft.pixelblocks.pixelblock; import eu.mhsl.minecraft.pixelblocks.Main; +import eu.mhsl.minecraft.pixelblocks.utils.Direction; import eu.mhsl.minecraft.pixelblocks.utils.LocationUtil; import org.bukkit.*; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Random; @@ -17,7 +21,7 @@ import static eu.mhsl.minecraft.pixelblocks.Main.plugin; public class PixelBlockWorld { private final PixelBlock parentPixelBlock; - private World world; + private final World world; int worldGrassBorderWidth = 10; int pixelsPerBlock = Main.configuration.pixelsPerBlock(); @@ -88,6 +92,34 @@ public class PixelBlockWorld { return getBorderOrigin().add(worldGrassBorderWidth + pixelsPerBlock, 0, worldGrassBorderWidth + pixelsPerBlock); } + public record PixelData(Vector relativeLocation, BlockData block, double scale) {} + public List getPixels(Direction direction) { + List pixelData = new ArrayList<>(); + + for (int x = 0; x < pixelsPerBlock; x++) { + for (int y = 0; y < pixelsPerBlock; y++) { + for (int z = 0; z < pixelsPerBlock; z++) { + Location relativeLocation = new Location(world, x, y, z); + + Location blockLocation = this.getBuildOrigin(); + switch (direction) { + case south -> blockLocation.add(relativeLocation.x(), relativeLocation.y(), relativeLocation.z()); + case north -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.x(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.z()); + case east -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.z(), relativeLocation.y(), relativeLocation.x()); + case west -> blockLocation.add(relativeLocation.z(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.x()); + } + BlockData block = blockLocation.getBlock().getBlockData(); + + if(!block.getMaterial().isEmpty()) { + pixelData.add(new PixelData(relativeLocation.toVector(), block, (double) 1 / pixelsPerBlock)); + } + } + } + } + + return pixelData; + } + private World loadOrCreatePixelWorld() { final WorldCreator worldCreator = new WorldCreator(getWorldPathName()); diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/Pixels.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/Pixels.java new file mode 100644 index 0000000..7e2346b --- /dev/null +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/Pixels.java @@ -0,0 +1,62 @@ +package eu.mhsl.minecraft.pixelblocks.pixelblock; + +import eu.mhsl.minecraft.pixelblocks.Main; +import eu.mhsl.minecraft.pixelblocks.utils.ListUtil; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.BlockDisplay; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.util.Transformation; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Objects; + +public class Pixels { + private static final NamespacedKey pixelOfTag = new NamespacedKey(Main.plugin, "pixel_of"); + + private final @NotNull PixelBlock parentBlock; + + public Pixels(@NotNull PixelBlock parentBlock) { + this.parentBlock = parentBlock; + } + + public void spawn() { + ListUtil.splitListInParts(10, this.parentBlock.getPixelData()) + .forEach(pixels -> parentBlock.getBlockTaskChain() + .delay(1) + .sync(() -> pixels.forEach(this::spawnPixel)) + .execute()); + } + + private void spawnPixel(PixelBlockWorld.PixelData pixelData) { + Location pixelBlockLocation = this.parentBlock.getPixelBlockLocation(); + Location pixelLocation = pixelBlockLocation.add(pixelData.relativeLocation().multiply(pixelData.scale())); + BlockDisplay entity = (BlockDisplay) pixelBlockLocation.getWorld().spawnEntity(pixelLocation, EntityType.BLOCK_DISPLAY); + + entity.setBlock(pixelData.block()); + Transformation transform = entity.getTransformation(); + transform.getScale().set(pixelData.scale()); + entity.setTransformation(transform); + entity.getPersistentDataContainer().set(pixelOfTag, PersistentDataType.STRING, this.parentBlock.getBlockUUID().toString()); + } + + public void destroy() { + List entities = parentBlock.getPixelBlockLocation().getNearbyEntitiesByType(BlockDisplay.class, 1) + .stream() + .filter(blockDisplay -> blockDisplay.getPersistentDataContainer().has(pixelOfTag)) + .filter(blockDisplay -> Objects.equals( + blockDisplay.getPersistentDataContainer().get(pixelOfTag, PersistentDataType.STRING), + parentBlock.getBlockUUID().toString() + )) + .toList(); + + ListUtil.splitListInParts(10, entities) + .forEach(pixels -> parentBlock.getBlockTaskChain() + .delay(1) + .sync(() -> pixels.forEach(Entity::remove)) + .execute()); + } +} diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/ListUtil.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/ListUtil.java new file mode 100644 index 0000000..d51b49d --- /dev/null +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/ListUtil.java @@ -0,0 +1,19 @@ +package eu.mhsl.minecraft.pixelblocks.utils; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class ListUtil { + public static List> splitListInParts(int parts, List list) { + int actualParts = Math.min(parts, list.size()); + int chunkSize = (int) Math.ceil((double) list.size() / actualParts); + return IntStream.range(0, actualParts) + .mapToObj(i -> list.stream() + .skip((long) i * chunkSize) + .limit(chunkSize) + .collect(Collectors.toList())) + .toList(); + } + +}