Compare commits

..

13 Commits

17 changed files with 234 additions and 82 deletions

View File

@@ -22,7 +22,7 @@ repositories {
} }
dependencies { dependencies {
compileOnly "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT" compileOnly "io.papermc.paper:paper-api:1.21.7-R0.1-SNAPSHOT"
implementation "co.aikar:taskchain-bukkit:3.7.2" implementation "co.aikar:taskchain-bukkit:3.7.2"
} }
@@ -46,7 +46,7 @@ processResources {
} }
tasks.register('copyJarToTestServer', Exec) { tasks.register('copyJarToTestServer', Exec) {
commandLine 'cp', 'build/libs/PixelBlocks-1.0-SNAPSHOT-all.jar', '/home/elias/Dokumente/mcTestServer/plugins/pixelblocks.jar' commandLine 'cp', 'build/libs/PixelBlocks-1.0-SNAPSHOT-all.jar', '/home/lars/Documents/Minecraft/Server/pixelblocks/plugins/PixelBlocks-1.0-SNAPSHOT-all.jar'
} }
shadowJar { shadowJar {

View File

@@ -4,7 +4,9 @@ import co.aikar.taskchain.BukkitTaskChainFactory;
import co.aikar.taskchain.TaskChain; import co.aikar.taskchain.TaskChain;
import co.aikar.taskchain.TaskChainFactory; import co.aikar.taskchain.TaskChainFactory;
import eu.mhsl.minecraft.pixelblocks.commands.CreatePixelBlockCommand; import eu.mhsl.minecraft.pixelblocks.commands.CreatePixelBlockCommand;
import eu.mhsl.minecraft.pixelblocks.commands.DestroyPixelBlocksCommand;
import eu.mhsl.minecraft.pixelblocks.commands.ExitWorldCommand; import eu.mhsl.minecraft.pixelblocks.commands.ExitWorldCommand;
import eu.mhsl.minecraft.pixelblocks.commands.GivePixelBlockCommand;
import eu.mhsl.minecraft.pixelblocks.listeners.*; import eu.mhsl.minecraft.pixelblocks.listeners.*;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -69,11 +71,12 @@ public final class Main extends JavaPlugin {
new PlacePixelListener(), new PlacePixelListener(),
new PreventHopperActionsListener(), new PreventHopperActionsListener(),
new PreventLiquidsFlowListener(), new PreventLiquidsFlowListener(),
new PreventPistonsListener(), new PreventRedstoneListener(),
new PreventEntityPlacementListener(), new PreventEntityPlacementListener(),
new DiscoverRecipesListener(), new DiscoverRecipesListener(),
new QuitWhileInPixelBlockListener(), new QuitWhileInPixelBlockListener(),
new PreventGrowthListener() new PreventGrowthListener(),
new CraftPixelBlockListener()
}; };
for(Listener listener : listeners) { for(Listener listener : listeners) {
@@ -81,7 +84,9 @@ public final class Main extends JavaPlugin {
} }
Objects.requireNonNull(getCommand("createpixelblock")).setExecutor(new CreatePixelBlockCommand()); Objects.requireNonNull(getCommand("createpixelblock")).setExecutor(new CreatePixelBlockCommand());
Objects.requireNonNull(getCommand("givepixelblock")).setExecutor(new GivePixelBlockCommand());
Objects.requireNonNull(getCommand("exitworld")).setExecutor(new ExitWorldCommand()); Objects.requireNonNull(getCommand("exitworld")).setExecutor(new ExitWorldCommand());
Objects.requireNonNull(getCommand("destroypixelblocks")).setExecutor(new DestroyPixelBlocksCommand());
Bukkit.addRecipe(PixelBlockItem.getRecipe()); Bukkit.addRecipe(PixelBlockItem.getRecipe());
} }

View File

@@ -25,8 +25,10 @@ public class PixelBlockItem {
public static final NamespacedKey recipeKey = new NamespacedKey(Main.plugin(), "pixelblock"); public static final NamespacedKey recipeKey = new NamespacedKey(Main.plugin(), "pixelblock");
public static NamespacedKey idProperty = new NamespacedKey(Main.plugin(), "id"); public static NamespacedKey idProperty = new NamespacedKey(Main.plugin(), "id");
public static NamespacedKey ownerProperty = new NamespacedKey(Main.plugin(), "owner"); public static NamespacedKey ownerProperty = new NamespacedKey(Main.plugin(), "owner");
public static UUID emptyBlockUUID = UUID.fromString("98fdf0ae-c3ab-4ef7-ae25-efd518d600de");
public static final String itemTexture = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzE5NGU5ZTc3NTdkMDZkNmY1ZTViZTg0NTQ4YTdjYjUyMTczZDY4Y2NmODAyZDIxMTI3NWQzMWNkYmEwYTA2ZSJ9fX0="; public static final String itemTexture = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQ" +
"ubmV0L3RleHR1cmUvYzE5NGU5ZTc3NTdkMDZkNmY1ZTViZTg0NTQ4YTdjYjUyMTczZDY4Y2NmODAyZDIxMTI3NWQzMWNkYmEwYTA2ZSJ9fX0=";
public record BlockInfo(UUID id, @Nullable UUID owner) { public record BlockInfo(UUID id, @Nullable UUID owner) {
public boolean hasOwner() { public boolean hasOwner() {
@@ -67,12 +69,13 @@ public class PixelBlockItem {
ItemStack item = HeadUtil.getCustomTextureHead(itemTexture); ItemStack item = HeadUtil.getCustomTextureHead(itemTexture);
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
meta.setMaxStackSize(1); meta.setMaxStackSize(1);
meta.itemName(Component.text(emptyBlockUUID.toString()));
meta.displayName(Component.text("Leerer Pixelblock")); meta.displayName(Component.text("Leerer Pixelblock"));
meta.lore(List.of( meta.lore(List.of(
Component.text("Der erste Spieler, der den Block platziert wird zum Besitzer des Blocks."), Component.text("Der erste Spieler, der den Block platziert wird zum Besitzer des Blocks."),
Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!") Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!")
)); ));
meta.getPersistentDataContainer().set(idProperty, PersistentDataType.STRING, UUID.randomUUID().toString()); meta.getPersistentDataContainer().set(idProperty, PersistentDataType.STRING, emptyBlockUUID.toString());
item.setItemMeta(meta); item.setItemMeta(meta);
return item; return item;
} }

View File

@@ -0,0 +1,19 @@
package eu.mhsl.minecraft.pixelblocks.commands;
import eu.mhsl.minecraft.pixelblocks.Main;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class DestroyPixelBlocksCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if(sender instanceof Player p) {
Main.pixelBlocks.forEach(pixelBlock -> pixelBlock.destroy(Bukkit.getPlayer(pixelBlock.getOwnerUUID())));
}
return true;
}
}

View File

@@ -0,0 +1,40 @@
package eu.mhsl.minecraft.pixelblocks.commands;
import eu.mhsl.minecraft.pixelblocks.PixelBlockItem;
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.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.UUID;
import static eu.mhsl.minecraft.pixelblocks.PixelBlockItem.getEmptyPixelBlock;
public class GivePixelBlockCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if(sender instanceof Player p) {
ItemStack result = getEmptyPixelBlock();
ItemMeta itemMeta = result.getItemMeta();
PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
if(!dataContainer.has(PixelBlockItem.idProperty)) return false;
String currentId = dataContainer.get(PixelBlockItem.idProperty, PersistentDataType.STRING);
Objects.requireNonNull(currentId);
if(!UUID.fromString(currentId).equals(PixelBlockItem.emptyBlockUUID)) return false;
dataContainer.set(PixelBlockItem.idProperty, PersistentDataType.STRING, args[0]);
result.setItemMeta(itemMeta);
p.getInventory().addItem(result);
}
return true;
}
}

View File

@@ -0,0 +1,30 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.PixelBlockItem;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.Objects;
import java.util.UUID;
public class CraftPixelBlockListener implements Listener {
@EventHandler
public void onCraft(CraftItemEvent event) {
ItemStack result = event.getInventory().getResult();
if(result == null) return;
ItemMeta itemMeta = result.getItemMeta();
PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
if(!dataContainer.has(PixelBlockItem.idProperty)) return;
String currentId = dataContainer.get(PixelBlockItem.idProperty, PersistentDataType.STRING);
Objects.requireNonNull(currentId);
if(!UUID.fromString(currentId).equals(PixelBlockItem.emptyBlockUUID)) return;
dataContainer.set(PixelBlockItem.idProperty, PersistentDataType.STRING, UUID.randomUUID().toString());
result.setItemMeta(itemMeta);
}
}

View File

@@ -5,6 +5,7 @@ import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.event.player.PlayerPortalEvent;
import java.util.Objects; import java.util.Objects;
@@ -20,4 +21,12 @@ public class ExitPixelWorldListener implements Listener {
Objects.requireNonNull(pixelBlock); Objects.requireNonNull(pixelBlock);
pixelBlock.exitBlock(event.getPlayer()); pixelBlock.exitBlock(event.getPlayer());
} }
@EventHandler
public void onEntityPortal(EntityPortalEvent event) {
World pixelBlockWorld = event.getFrom().getWorld();
if(!PixelBlockWorld.isPixelWorld(pixelBlockWorld)) return;
event.setCancelled(true);
}
} }

View File

@@ -10,12 +10,13 @@ import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
public class PlacePixelBlockListener implements Listener { public class PlacePixelBlockListener implements Listener {
@EventHandler @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
public void onBlockPlace(BlockPlaceEvent event) { public void onBlockPlace(BlockPlaceEvent event) {
ItemStack usedItem = event.getItemInHand(); ItemStack usedItem = event.getItemInHand();
PixelBlockItem.BlockInfo info = PixelBlockItem.getBlockInfo(usedItem); PixelBlockItem.BlockInfo info = PixelBlockItem.getBlockInfo(usedItem);
@@ -39,43 +40,5 @@ public class PlacePixelBlockListener implements Listener {
newBlockLocation, newBlockLocation,
direction 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

@@ -4,10 +4,16 @@ import eu.mhsl.minecraft.pixelblocks.utils.EventCanceling;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityPlaceEvent; import org.bukkit.event.entity.EntityPlaceEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
public class PreventEntityPlacementListener implements Listener { public class PreventEntityPlacementListener implements Listener {
@EventHandler @EventHandler
public void preventPlace(EntityPlaceEvent event) { public void preventPlace(EntityPlaceEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld());
} }
@EventHandler
public void preventProjectile(ProjectileLaunchEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getEntity().getWorld());
}
} }

View File

@@ -1,12 +1,14 @@
package eu.mhsl.minecraft.pixelblocks.listeners; package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.utils.EventCanceling; import eu.mhsl.minecraft.pixelblocks.utils.EventCanceling;
import org.bukkit.Material;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.hanging.HangingPlaceEvent;
public class PreventIllegalBlocksListener implements Listener { public class PreventIllegalBlocksListener implements Listener {
@EventHandler @EventHandler
@@ -19,6 +21,13 @@ public class PreventIllegalBlocksListener implements Listener {
EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld());
} }
@EventHandler
public void onItemFrame(HangingPlaceEvent event) {
if(event.getItemStack() == null || event.getPlayer() == null) return;
if(!(event.getItemStack().getType().equals(Material.ITEM_FRAME) || event.getItemStack().getType().equals(Material.GLOW_ITEM_FRAME))) return;
EventCanceling.cancelIfInPixelWorld(event, event.getPlayer().getWorld());
}
@EventHandler @EventHandler
public void onEntityDamage(EntityDamageEvent event) { public void onEntityDamage(EntityDamageEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getEntity().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getEntity().getWorld());

View File

@@ -1,11 +1,19 @@
package eu.mhsl.minecraft.pixelblocks.listeners; package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld;
import eu.mhsl.minecraft.pixelblocks.utils.EventCanceling; import eu.mhsl.minecraft.pixelblocks.utils.EventCanceling;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockRedstoneEvent;
public class PreventRedstoneListener implements Listener {
@EventHandler
public void preventRedstone(BlockRedstoneEvent event) {
boolean isInPixelBlock = PixelBlockWorld.isPixelWorld(event.getBlock().getWorld());
if(isInPixelBlock) event.setNewCurrent(0);
}
public class PreventPistonsListener implements Listener {
@EventHandler @EventHandler
public void blockPistons(BlockPistonExtendEvent event) { public void blockPistons(BlockPistonExtendEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(

View File

@@ -22,7 +22,7 @@ import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public class PixelBlock { public class PixelBlock {
private boolean exists = true; private boolean isAccessible = false;
private PixelBlockWorld pixelWorld; private PixelBlockWorld pixelWorld;
private final Location pixelBlockLocation; private final Location pixelBlockLocation;
@@ -83,6 +83,8 @@ public class PixelBlock {
this.placeholder = new PixelBlockPlaceholder(this); this.placeholder = new PixelBlockPlaceholder(this);
this.hitbox = new PixelBlockHitbox(this); this.hitbox = new PixelBlockHitbox(this);
this.getBlockTaskChain().sync(() -> this.isAccessible = true).execute();
Main.logger().info(String.format("Loaded existing pixelblock '%s'", this.blockUUID)); Main.logger().info(String.format("Loaded existing pixelblock '%s'", this.blockUUID));
} catch(Exception e) { } catch(Exception e) {
Main.logger().info(String.format("Failed initializing existing pixelblock '%s': %s", this.blockUUID, e.getMessage())); Main.logger().info(String.format("Failed initializing existing pixelblock '%s': %s", this.blockUUID, e.getMessage()));
@@ -122,6 +124,8 @@ public class PixelBlock {
Main.pixelBlocks.add(this); Main.pixelBlocks.add(this);
}) })
.execute(); .execute();
this.getBlockTaskChain().sync(() -> this.isAccessible = true).execute();
} }
public <T> TaskChain<T> getBlockTaskChain() { public <T> TaskChain<T> getBlockTaskChain() {
@@ -134,13 +138,12 @@ public class PixelBlock {
return; return;
} }
this.lastEntryLocation = player.getLocation();
getBlockTaskChain() getBlockTaskChain()
.async(() -> { .async(() -> Main.database().savePixelBlock(this))
this.lastEntryLocation = player.getLocation();
Main.database().savePixelBlock(this);
})
.sync(() -> { .sync(() -> {
if(!exists) return; if(!this.isAccessible) return;
player.teleport(this.pixelWorld.getSpawnLocation()); player.teleport(this.pixelWorld.getSpawnLocation());
}) })
.current(() -> Main.logger() .current(() -> Main.logger()
@@ -175,25 +178,8 @@ public class PixelBlock {
.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.logger().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) { public void destroy(Player destroyedBy) {
if(!this.exists) return; if(!this.isAccessible) return;
if(Main.configuration().onlyBreakableByOwner() && !destroyedBy.getUniqueId().equals(ownerUUID)) { if(Main.configuration().onlyBreakableByOwner() && !destroyedBy.getUniqueId().equals(ownerUUID)) {
destroyedBy.sendMessage("Dieser Pixelblock gehört nicht dir!"); destroyedBy.sendMessage("Dieser Pixelblock gehört nicht dir!");
return; return;
@@ -205,7 +191,7 @@ public class PixelBlock {
}); });
Main.logger().info(String.format("Destroying PixelBlock '%s' at %s", this.blockUUID, pixelBlockLocation)); Main.logger().info(String.format("Destroying PixelBlock '%s' at %s", this.blockUUID, pixelBlockLocation));
this.exists = false; this.isAccessible = false;
this.pixelWorld.getEntitiesInWorld().stream() this.pixelWorld.getEntitiesInWorld().stream()
.filter(entity -> entity instanceof Item) .filter(entity -> entity instanceof Item)

View File

@@ -44,9 +44,9 @@ public class PixelBlockHitbox {
double endingZ = MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.relativeLocation().getZ()); double endingZ = MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.relativeLocation().getZ());
Location spawnLocation = absoluteLocation.clone().add( Location spawnLocation = absoluteLocation.clone().add(
((startingX+endingX)/2)/pixelsPerBlock, ((startingX+endingX)/2+0.5)/pixelsPerBlock,
(startingY/pixelsPerBlock)-0, (startingY/pixelsPerBlock)-0,
((startingZ+endingZ)/2)/pixelsPerBlock ((startingZ+endingZ)/2+0.5)/pixelsPerBlock
); );
float height = (float) (endingY-startingY+1)/pixelsPerBlock; float height = (float) (endingY-startingY+1)/pixelsPerBlock;

View File

@@ -4,12 +4,16 @@ import eu.mhsl.minecraft.pixelblocks.Main;
import eu.mhsl.minecraft.pixelblocks.utils.Direction; import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.utils.LocationUtil; import eu.mhsl.minecraft.pixelblocks.utils.LocationUtil;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Rotatable;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@@ -90,7 +94,7 @@ public class PixelBlockWorld {
return getBorderOrigin().add(worldGrassBorderWidth + pixelsPerBlock, 0, worldGrassBorderWidth + pixelsPerBlock); return getBorderOrigin().add(worldGrassBorderWidth + pixelsPerBlock, 0, worldGrassBorderWidth + pixelsPerBlock);
} }
public record PixelData(Vector relativeLocation, BlockData block, double scale) { public record PixelData(Vector relativeLocation, BlockData block, @Nullable Directional directional, @Nullable Rotatable rotatable, BlockState state, double scale) {
} }
public List<PixelData> getPixels(Direction direction) { public List<PixelData> getPixels(Direction direction) {
@@ -112,10 +116,13 @@ public class PixelBlockWorld {
case west -> case west ->
blockLocation.add(relativeLocation.z(), relativeLocation.y(), (pixelsPerBlock - 1) - relativeLocation.x()); blockLocation.add(relativeLocation.z(), relativeLocation.y(), (pixelsPerBlock - 1) - relativeLocation.x());
} }
BlockData block = blockLocation.getBlock().getBlockData(); BlockData blockData = blockLocation.getBlock().getBlockData();
@Nullable Directional directional = blockData instanceof Directional face ? face : null;
@Nullable Rotatable rotatable = blockData instanceof Rotatable rotation ? rotation : null;
BlockState state = blockLocation.getBlock().getState();
if(!block.getMaterial().isEmpty()) { if(!blockData.getMaterial().isAir()) {
pixelData.add(new PixelData(relativeLocation.toVector(), block, (double) 1 / pixelsPerBlock)); pixelData.add(new PixelData(relativeLocation.toVector(), blockData, directional, rotatable, state, (double) 1 / pixelsPerBlock));
} }
} }
} }

View File

@@ -1,15 +1,27 @@
package eu.mhsl.minecraft.pixelblocks.pixelblock; package eu.mhsl.minecraft.pixelblocks.pixelblock;
import eu.mhsl.minecraft.pixelblocks.Main; import eu.mhsl.minecraft.pixelblocks.Main;
import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.utils.ListUtil; import eu.mhsl.minecraft.pixelblocks.utils.ListUtil;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.block.Banner;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Rotatable;
import org.bukkit.block.data.type.Bed;
import org.bukkit.block.data.type.Chest;
import org.bukkit.block.data.type.EnderChest;
import org.bukkit.entity.BlockDisplay; import org.bukkit.entity.BlockDisplay;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.bukkit.util.Transformation; import org.bukkit.util.Transformation;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3d;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -34,12 +46,21 @@ public class Pixels {
private void spawnPixel(PixelBlockWorld.PixelData pixelData) { private void spawnPixel(PixelBlockWorld.PixelData pixelData) {
Location pixelBlockLocation = this.parentBlock.getPixelBlockLocation(); Location pixelBlockLocation = this.parentBlock.getPixelBlockLocation();
Location pixelLocation = pixelBlockLocation.add(pixelData.relativeLocation().multiply(pixelData.scale())); Location pixelLocation = pixelBlockLocation.add(pixelData.relativeLocation().multiply(pixelData.scale()));
BlockDisplay entity = (BlockDisplay) pixelBlockLocation.getWorld().spawnEntity(pixelLocation, EntityType.BLOCK_DISPLAY); Vector3d centerOffset = new Vector3d(0.5, 0.5, 0.5).mul(pixelData.scale());
BlockDisplay entity = (BlockDisplay) pixelBlockLocation.getWorld().spawnEntity(
pixelLocation.add(Vector.fromJOML(centerOffset)),
EntityType.BLOCK_DISPLAY
);
if(!(pixelData.directional() instanceof Bed bed && bed.getPart().equals(Bed.Part.FOOT))) entity.setBlock(pixelData.block());
this.setEntityDirection(entity, pixelData.directional());
this.setEntityRotation(entity, pixelData.rotatable(), pixelData.state());
entity.setBlock(pixelData.block());
Transformation transform = entity.getTransformation(); Transformation transform = entity.getTransformation();
transform.getScale().set(pixelData.scale()); transform.getScale().set(pixelData.scale());
transform.getTranslation().set(centerOffset.mul(-1));
entity.setTransformation(transform); entity.setTransformation(transform);
entity.getPersistentDataContainer().set(pixelOfTag, PersistentDataType.STRING, this.parentBlock.getBlockUUID().toString()); entity.getPersistentDataContainer().set(pixelOfTag, PersistentDataType.STRING, this.parentBlock.getBlockUUID().toString());
} }
@@ -59,4 +80,43 @@ public class Pixels {
.sync(() -> pixels.forEach(Entity::remove)) .sync(() -> pixels.forEach(Entity::remove))
.execute()); .execute());
} }
private void setEntityRotation(Entity entity, @Nullable Rotatable rotatable, BlockState blockState) {
if(rotatable == null) return;
Vector rotation = rotatable.getRotation().getDirection();
float yaw = (float) Math.toDegrees(Math.atan2(rotation.getX(), -rotation.getZ()));
if(blockState instanceof Banner) yaw += 180;
entity.setRotation(entity.getYaw()+yaw, entity.getPitch());
}
private void setEntityDirection(Entity entity, @Nullable Directional direction) {
Direction blockDirection = parentBlock.getFacingDirection();
float angle = switch (blockDirection) {
case Direction.north -> 180;
case Direction.south -> 0;
case Direction.west -> 90;
case Direction.east -> -90;
};
entity.setRotation(entity.getYaw()+angle, entity.getPitch());
if (!(direction instanceof EnderChest || direction instanceof Chest || direction instanceof Bed)) return;
BlockFace blockFace = direction.getFacing();
float yaw = switch (blockFace) {
case NORTH -> 180;
case SOUTH -> 0;
case WEST -> 90;
case EAST -> -90;
default -> entity.getLocation().getYaw();
};
float pitch = switch (blockFace) {
case UP -> 90;
case DOWN -> -90;
default -> 0;
};
entity.setRotation(entity.getYaw()+yaw, entity.getPitch()+pitch);
}
} }

View File

@@ -1,18 +1,23 @@
package eu.mhsl.minecraft.pixelblocks.utils; package eu.mhsl.minecraft.pixelblocks.utils;
import eu.mhsl.minecraft.pixelblocks.Main;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.event.Cancellable; import org.bukkit.event.Cancellable;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
public class EventCanceling { public class EventCanceling {
public static void shouldCancelInPixelBlock(Cancellable event, World world, Function<PixelBlock, Boolean> callback) { public static void shouldCancelInPixelBlock(Cancellable event, World world, Function<PixelBlock, Boolean> callback) {
if(!PixelBlockWorld.isPixelWorld(world)) return; if(!PixelBlockWorld.isPixelWorld(world)) return;
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(world); @Nullable PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(world);
Objects.requireNonNull(pixelBlock); if(pixelBlock == null) {
Main.logger().warning("Cancelling place event because PixelBlock could not be found: " + world.getName());
event.setCancelled(true);
return;
}
if(callback.apply(pixelBlock)) event.setCancelled(true); if(callback.apply(pixelBlock)) event.setCancelled(true);
} }

View File

@@ -5,3 +5,5 @@ api-version: '1.21'
commands: commands:
createpixelblock: createpixelblock:
exitworld: exitworld:
givepixelblock:
destroypixelblocks: