refactored pixelblock and fully utilizing taskchains

This commit is contained in:
Elias Müller 2024-10-12 03:03:30 +02:00
parent 503c596616
commit 70c7059e43
10 changed files with 232 additions and 182 deletions

View File

@ -56,7 +56,9 @@ public final class Main extends JavaPlugin {
@Override
public void onEnable() {
Main.taskFactory = BukkitTaskChainFactory.create(this);
getLogger().info("Loading existing blocks from Database");
database.loadPixelBlocks();
getLogger().info("Pixelblock loading done");
Listener[] listeners = {
new EnterPixelBlockListener(),

View File

@ -119,13 +119,14 @@ public class PixelBlockDatabase {
allPixelBlocks.getDouble("entryLocationZ")
);
PixelBlock block = new PixelBlock(
blockLocation,
UUID.fromString(allPixelBlocks.getString("owner")),
Main.plugin.getLogger().info("Pixelblock found ");
Main.pixelBlocks.add(PixelBlock.fromExisting(
UUID.fromString(allPixelBlocks.getString("uuid")),
Direction.valueOf(allPixelBlocks.getString("direction"))
);
block.setLastEntryLocation(entryLocation);
UUID.fromString(allPixelBlocks.getString("owner")),
blockLocation,
Direction.valueOf(allPixelBlocks.getString("direction")),
entryLocation
));
}
} catch (SQLException e) {
throw new RuntimeException("Failed loading PixelBlocks from the database", e);

View File

@ -24,13 +24,19 @@ public class CreatePixelBlockCommand implements CommandExecutor {
}
Location playerLocation = p.getLocation();
PixelBlock block = new PixelBlock(
playerLocation,
p.getUniqueId(),
PixelBlock.createPixelBlock(
UUID.randomUUID(),
p.getUniqueId(),
playerLocation.toBlockLocation(),
Direction.south
);
block.place(playerLocation, Direction.south);
// PixelBlock block = new PixelBlock(
// playerLocation,
// p.getUniqueId(),
// UUID.randomUUID(),
// Direction.south
// );
// block.place(playerLocation, Direction.south);
}
return true;
}

View File

@ -5,22 +5,11 @@ import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import java.util.Objects;
public class ExitPixelWorldListener implements Listener {
@EventHandler
public void onPlayerChangeWorld(PlayerChangedWorldEvent event) {
World changingFrom = event.getFrom();
if(!PixelBlockWorld.isPixelWorld(changingFrom)) return;
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(changingFrom);
Objects.requireNonNull(pixelBlock);
pixelBlock.updateEntities();
}
@EventHandler
public void onPlayerPortal(PlayerPortalEvent event) {
World pixelBlockWorld = event.getFrom().getWorld();

View File

@ -1,7 +1,6 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.PixelBlockItem;
import eu.mhsl.minecraft.pixelblocks.Main;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld;
import eu.mhsl.minecraft.pixelblocks.utils.Direction;
@ -15,8 +14,6 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
import java.util.UUID;
public class PlacePixelBlockListener implements Listener {
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
@ -36,32 +33,49 @@ public class PlacePixelBlockListener implements Listener {
Direction direction = Direction.vectorToDirection(event.getPlayer().getLocation().getDirection());
PixelBlock pixelBlock;
if(!info.hasOwner()) {
pixelBlock = new PixelBlock(
newBlockLocation,
event.getPlayer().getUniqueId(),
UUID.randomUUID(),
direction
);
} else {
UUID itemUUID = info.id();
pixelBlock = Main.pixelBlocks.stream()
.filter(block -> block.getBlockUUID().equals(itemUUID))
.findFirst()
.orElseGet(() -> new PixelBlock(
newBlockLocation,
event.getPlayer().getUniqueId(),
itemUUID,
direction
));
}
try {
pixelBlock.place(newBlockLocation, direction);
} catch (IllegalArgumentException e) {
event.setCancelled(true);
event.getPlayer().sendMessage(Component.text(e.getMessage()));
}
PixelBlock.createPixelBlock(
info.id(),
info.hasOwner() ? info.owner() : event.getPlayer().getUniqueId(),
newBlockLocation,
direction
);
// if(!info.hasOwner()) {
// pixelBlock = PixelBlock.createPixelBlock(
// UUID.randomUUID(),
// event.getPlayer().getUniqueId(),
// newBlockLocation,
// Direction.south
// );
//// pixelBlock = new PixelBlock(
//// newBlockLocation,
//// event.getPlayer().getUniqueId(),
//// UUID.randomUUID(),
//// direction
//// );
// } else {
// UUID itemUUID = info.id();
// pixelBlock = PixelBlock.createPixelBlock(
// UUID.randomUUID(),
// even.getUniqueId(),
// playerLocation.toBlockLocation(),
// Direction.south
// );
//// pixelBlock = Main.pixelBlocks.stream()
//// .filter(block -> block.getBlockUUID().equals(itemUUID))
//// .findFirst()
//// .orElseGet(() -> new PixelBlock(
//// newBlockLocation,
//// event.getPlayer().getUniqueId(),
//// itemUUID,
//// direction
//// ));
// }
//
// try {
// pixelBlock.place(newBlockLocation, direction);
// } catch (IllegalArgumentException e) {
// event.setCancelled(true);
// event.getPlayer().sendMessage(Component.text(e.getMessage()));
// }
}
}

View File

@ -6,14 +6,14 @@ import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.BlockDisplay;
import org.bukkit.entity.EntityType;
import org.bukkit.persistence.PersistentDataContainer;
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.UUID;
import java.util.stream.Collectors;
public class Pixel {
private static final NamespacedKey pixelOfTag = new NamespacedKey(Main.plugin, "pixel_of");
@ -26,12 +26,16 @@ public class Pixel {
private final double scale;
public static Pixel existingPixel(PixelBlock parentBlock, BlockDisplay entity) {
PersistentDataContainer dataContainer = entity.getPersistentDataContainer();
if(!dataContainer.has(pixelOfTag)) throw new IllegalArgumentException("Entity is missing the parent tag in the DataContainer");
UUID expectedParentUuid = UUID.fromString(Objects.requireNonNull(dataContainer.get(pixelOfTag, PersistentDataType.STRING)));
if(!parentBlock.getBlockUUID().equals(expectedParentUuid)) throw new IllegalArgumentException("Pixel is from a different parent block");
return new Pixel(parentBlock, entity);
public static List<Pixel> 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());
}
public static Pixel newPixel(PixelBlock parentBlock, Vector relativePosition, BlockData blockData, double scale) {

View File

@ -19,13 +19,14 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class PixelBlock {
private final PixelBlockWorld pixelWorld;
private boolean exists = true;
private PixelBlockWorld pixelWorld;
private final int pixelsPerBlock = Main.configuration.pixelsPerBlock();
private Location pixelBlockLocation;
private Direction facingDirection;
private final List<Pixel> pixels = new ArrayList<>();
private final Location pixelBlockLocation;
private final Direction facingDirection;
private List<Pixel> pixels = new ArrayList<>();
private PixelBlockHitbox hitbox;
private PixelBlockPlaceholder placeholder;
@ -66,30 +67,54 @@ public class PixelBlock {
.orElse(null);
}
public PixelBlock(Location originLocation, UUID ownerUUID, UUID blockUUID, Direction direction) {
Main.pixelBlocks.add(this);
this.ownerUUID = ownerUUID;
public static PixelBlock fromExisting(UUID blockUUID, UUID ownerUUID, Location pixelBlockLocation, Direction direction, Location lastEntryLocation) {
return new PixelBlock(blockUUID, ownerUUID, pixelBlockLocation, direction, lastEntryLocation);
}
private PixelBlock(UUID blockUUID, UUID ownerUUID, Location pixelBlockLocation, Direction direction, Location lastEntryLocation) {
this.blockUUID = blockUUID;
this.pixelBlockLocation = originLocation.toBlockLocation();
this.ownerUUID = ownerUUID;
this.pixelBlockLocation = pixelBlockLocation;
this.pixelBlockLocation.setYaw(0);
this.pixelBlockLocation.setPitch(0);
this.facingDirection = direction;
this.lastEntryLocation = lastEntryLocation;
this.pixelWorld = new PixelBlockWorld(this);
this.pixelBlockLocation.getNearbyEntitiesByType(BlockDisplay.class, 1).forEach(blockDisplay -> {
try {
this.pixels.add(Pixel.existingPixel(this, blockDisplay));
} catch(IllegalArgumentException ignored) {}
});
this.pixels = Pixel.fromExisting(this);
this.placeholder = PixelBlockPlaceholder.fromExisting(this);
try {
this.hitbox = PixelBlockHitbox.fromExisting(this);
} catch(NoSuchElementException ignored) {}
this.hitbox = PixelBlockHitbox.fromExisting(this);
}
public static PixelBlock createPixelBlock(UUID blockUUID, UUID ownerUUID, Location pixelBlockLocation, Direction direction) {
return new PixelBlock(blockUUID, ownerUUID, pixelBlockLocation, direction);
}
private PixelBlock(UUID blockUUID, UUID ownerUUID, Location pixelBlockLocation, Direction direction) {
if(Main.pixelBlocks.stream().anyMatch(pixelBlock -> pixelBlock.getBlockUUID().equals(blockUUID)))
throw new IllegalStateException(String.format("PixelBlock '%s' ist bereits in der Welt vorhanden!", blockUUID));
this.blockUUID = blockUUID;
this.ownerUUID = ownerUUID;
this.pixelBlockLocation = pixelBlockLocation;
this.pixelBlockLocation.setYaw(0);
this.pixelBlockLocation.setPitch(0);
this.facingDirection = direction;
this.getBlockTaskChain()
.sync(() -> {
this.pixelWorld = new PixelBlockWorld(this);
this.placeholder = PixelBlockPlaceholder.newPlaceholder(this);
this.hitbox = PixelBlockHitbox.newHitbox(this);
})
.execute();
this.scheduleEntityUpdate();
this.getBlockTaskChain()
.async(() -> {
Main.database.savePixelBlock(this);
Main.pixelBlocks.add(this);
})
.execute();
}
public <T> TaskChain<T> getBlockTaskChain() {
@ -102,26 +127,30 @@ public class PixelBlock {
return;
}
Main.plugin.getLogger().info(String.format("'%s' entered PixelBlock '%s' at %s", player.getName(), this.blockUUID, this.pixelBlockLocation.toString()));
getBlockTaskChain()
.async(() -> {
this.lastEntryLocation = player.getLocation();
Main.database.savePixelBlock(this);
})
.sync(() -> player.teleport(this.pixelWorld.getSpawnLocation()))
.sync(() -> {
if(!exists) return;
player.teleport(this.pixelWorld.getSpawnLocation());
})
.current(() -> Main.plugin.getLogger()
.info(String.format("'%s' entered PixelBlock '%s' at %s", player.getName(), this.blockUUID, this.pixelBlockLocation.toString())))
.execute();
}
public void exitBlock(@NotNull Player player) {
Main.plugin.getLogger().info(String.format("%s exited PixelBlock", player.getName()));
player.teleport(this.lastEntryLocation);
this.getBlockTaskChain()
.sync(() -> player.teleport(this.lastEntryLocation != null ? this.lastEntryLocation : this.pixelBlockLocation))
.current(() -> Main.plugin.getLogger().info(String.format("%s exited PixelBlock", player.getName())))
.execute();
this.scheduleEntityUpdate();
}
public void setLastEntryLocation(Location lastEntryLocation) {
this.lastEntryLocation = lastEntryLocation;
}
public void updateEntities() {
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);
@ -129,67 +158,74 @@ public class PixelBlock {
}
List<PixelData> pixelData = new ArrayList<>();
this.clearEntities();
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);
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();
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));
if(!block.getMaterial().isEmpty()) {
pixelData.add(new PixelData(this, relativeLocation.toVector(), block, (double) 1 / pixelsPerBlock));
}
}
}
}
}
}
int spawnSpreadInTicks = 10;
int chunkSize = (int) Math.ceil((double) pixelData.size() / spawnSpreadInTicks);
IntStream.range(0, spawnSpreadInTicks)
.mapToObj(i -> pixelData.stream()
.skip((long) i * chunkSize)
.limit(chunkSize)
.collect(Collectors.toList()))
.forEach(pixels -> this.getBlockTaskChain()
.delay(1)
.sync(() -> pixels.forEach(pixel -> this.pixels.add(pixel.create())))
.execute());
this.getBlockTaskChain()
.sync(() -> {
this.hitbox = PixelBlockHitbox.newHitbox(this);
Main.plugin.getLogger().info(String.format("Placed %d entities for PixelBlock '%s'", this.pixels.size(), this.blockUUID));
})
.async(() -> Collections.shuffle(pixelData))
.asyncFirst(() -> {
int spawnSpreadInTicks = 10;
int chunkSize = (int) Math.ceil((double) pixelData.size() / spawnSpreadInTicks);
TaskChain<Object> 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();
}
public void place(Location placeLocation, Direction direction) {
Location newLocation = placeLocation.toBlockLocation();
newLocation.setPitch(0);
newLocation.setYaw(0);
@Nullable PixelBlock blockAtLocation = PixelBlock.getPixelBlockFromPlacedLocation(newLocation);
if(blockAtLocation != null && blockAtLocation != this) throw new IllegalArgumentException("Es können nicht mehrere Pixelblöcke ineinander platziert werden.");
Main.plugin.getLogger().info(String.format("Placing PixelBlock '%s' at %s", this.blockUUID, placeLocation));
this.pixelBlockLocation = newLocation;
this.facingDirection = direction;
updateEntities();
Main.database.savePixelBlock(this);
this.placeholder = PixelBlockPlaceholder.newPlaceholder(this);
}
// public void place(Location placeLocation, Direction direction) {
// Location newLocation = placeLocation.toBlockLocation();
// newLocation.setPitch(0);
// newLocation.setYaw(0);
//
// @Nullable PixelBlock blockAtLocation = PixelBlock.getPixelBlockFromPlacedLocation(newLocation);
// if(blockAtLocation != null && blockAtLocation != this) throw new IllegalArgumentException("Es können nicht mehrere Pixelblöcke ineinander platziert werden.");
//
// Main.plugin.getLogger().info(String.format("Placing PixelBlock '%s' at %s", this.blockUUID, placeLocation));
// this.pixelBlockLocation = newLocation;
// this.facingDirection = direction;
// updateEntities();
// Main.database.savePixelBlock(this);
//
// this.placeholder = PixelBlockPlaceholder.newPlaceholder(this);
// }
public void destroy(Player destroyedBy) {
if(Main.configuration.onlyBreakableByOwner() && !destroyedBy.getUniqueId().equals(ownerUUID)) {
@ -203,52 +239,45 @@ public class PixelBlock {
});
Main.plugin.getLogger().info(String.format("Destroying PixelBlock '%s' at %s", this.blockUUID, pixelBlockLocation));
this.exists = false;
this.pixelWorld.getEntitiesInWorld().stream()
.filter(entity -> entity instanceof Item)
.forEach(entity -> entity.teleport(this.lastEntryLocation));
this.clearEntities();
Main.database.deletePixelBlock(this);
this.pixelBlockLocation.getWorld().playSound(this.pixelBlockLocation, Sound.BLOCK_COPPER_BULB_BREAK, 1.0F, 30);
this.pixelBlockLocation.getWorld().dropItem(this.pixelBlockLocation.add(new Vector(0.5, 0.5, 0.5)), PixelBlockItem.getBlockAsItem(this));
this.pixelBlockLocation = null;
this.scheduleEntityRemove();
this.getBlockTaskChain()
.sync(() -> {
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));
})
.async(() -> {
Main.database.deletePixelBlock(this);
Main.pixelBlocks.remove(this);
})
.execute();
}
private void clearEntities() {
Chunk chunk = this.pixelBlockLocation.getChunk();
if(!chunk.isEntitiesLoaded()) {
chunk.load(true);
chunk.getEntities();
}
private void scheduleEntityRemove() {
// Chunk chunk = this.pixelBlockLocation.getChunk();
// if(!chunk.isEntitiesLoaded()) {
// chunk.load(true);
// chunk.getEntities();
// }
Main.plugin.getLogger().info(String.format("Removing %d entities for PixelBlock '%s'", this.pixels.size(), this.blockUUID));
this.pixels.forEach(Pixel::destroy);
this.pixels.clear();
if(hitbox != null) {
this.hitbox.remove();
this.hitbox = null;
}
this.placeholder.destroy();
// this.pixelBlockLocation.getWorld().getEntities().stream()
// .filter(this::isPixelBlockComponent)
// .filter(entity -> entity.getLocation()
// .add(0, hitboxOffset, 0)
// .toBlockLocation()
// .equals(this.pixelBlockLocation))
// .forEach(Entity::remove);
this.getBlockTaskChain()
.current(() -> Main.plugin.getLogger()
.info(String.format("Removing %d entities for PixelBlock '%s'", this.pixels.size(), this.blockUUID)))
.sync(() -> {
this.pixels.forEach(Pixel::destroy);
this.pixels.clear();
this.placeholder.destroy();
this.hitbox.destroy();
})
.execute();
}
private boolean isPixelBlockComponent(Entity entity) {
return entity.getType().equals(EntityType.BLOCK_DISPLAY)
|| entity.getType().equals(EntityType.INTERACTION)
|| entity.getType().equals(EntityType.ITEM_DISPLAY);
}
public @NotNull PixelBlockWorld getPixelWorld() {
return pixelWorld;
}

View File

@ -103,7 +103,7 @@ public class PixelBlockHitbox {
.set(hitboxOfTag, PersistentDataType.STRING, parentBlockUUID.toString());
}
public void remove() {
public void destroy() {
this.interaction.remove();
}
}

View File

@ -35,14 +35,19 @@ public class PixelBlockPlaceholder {
}
public static PixelBlockPlaceholder newPlaceholder(PixelBlock parentBlock) {
return new PixelBlockPlaceholder(parentBlock.getPixelBlockLocation(), parentBlock.getBlockUUID());
return new PixelBlockPlaceholder(parentBlock);
}
private PixelBlockPlaceholder(List<ItemDisplay> itemDisplays) {
this.placeholders = itemDisplays;
}
private PixelBlockPlaceholder(Location pixelBlockLocation, UUID parentBlockUUID) {
private PixelBlockPlaceholder(PixelBlock parentBlock) {
if(parentBlock.getPixels().size() > 5) return;
Location pixelBlockLocation = parentBlock.getPixelBlockLocation();
UUID parentBlockUUID = parentBlock.getBlockUUID();
World pixelBlockWorld = pixelBlockLocation.getWorld();
Location itemDisplayLocation = pixelBlockLocation.add(0.5, 0.5, 0.5);

View File

@ -17,7 +17,7 @@ import static eu.mhsl.minecraft.pixelblocks.Main.plugin;
public class PixelBlockWorld {
private final PixelBlock parentPixelBlock;
private final World world;
private World world;
int worldGrassBorderWidth = 10;
int pixelsPerBlock = Main.configuration.pixelsPerBlock();