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