diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index 3fd2793..35cc0b4 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -26,5 +26,15 @@ <option name="name" value="sonatype" /> <option name="url" value="https://oss.sonatype.org/content/groups/public/" /> </remote-repository> + <remote-repository> + <option name="id" value="maven2" /> + <option name="name" value="maven2" /> + <option name="url" value="https://hub.spigotmc.org/nexus/content/groups/public/" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven" /> + <option name="name" value="maven" /> + <option name="url" value="https://repo.aikar.co/content/groups/aikar/" /> + </remote-repository> </component> </project> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 242f4dc..02d0572 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -4,6 +4,7 @@ <modules> <module fileurl="file://$PROJECT_DIR$/.idea/modules/PixelBlocks.main.iml" filepath="$PROJECT_DIR$/.idea/modules/PixelBlocks.main.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/eu.mhsl.minecraft.PixelBlocks.main.iml" filepath="$PROJECT_DIR$/.idea/modules/eu.mhsl.minecraft.PixelBlocks.main.iml" /> + <module fileurl="file://$PROJECT_DIR$/.idea/modules/minecraft.PixelBlocks.main.iml" filepath="$PROJECT_DIR$/.idea/modules/minecraft.PixelBlocks.main.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/projects.PixelBlocks.main.iml" filepath="$PROJECT_DIR$/.idea/modules/projects.PixelBlocks.main.iml" /> </modules> </component> diff --git a/.idea/modules/minecraft.PixelBlocks.main.iml b/.idea/modules/minecraft.PixelBlocks.main.iml new file mode 100644 index 0000000..3cf00db --- /dev/null +++ b/.idea/modules/minecraft.PixelBlocks.main.iml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module version="4"> + <component name="FacetManager"> + <facet type="minecraft" name="Minecraft"> + <configuration> + <autoDetectTypes> + <platformType>PAPER</platformType> + </autoDetectTypes> + <projectReimportVersion>1</projectReimportVersion> + </configuration> + </facet> + </component> +</module> \ No newline at end of file diff --git a/build.gradle b/build.gradle index ecb55f6..beb9a10 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id 'java' + id 'com.gradleup.shadow' version '8.3.1' } group = 'eu.mhsl.minecraft' @@ -15,10 +16,14 @@ repositories { name = "sonatype" url = "https://oss.sonatype.org/content/groups/public/" } + maven { + url = "https://repo.aikar.co/content/groups/aikar/" + } } dependencies { compileOnly "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT" + implementation "co.aikar:taskchain-bukkit:3.7.2" } def targetJavaVersion = 21 @@ -31,14 +36,6 @@ java { } } -tasks.withType(JavaCompile).configureEach { - options.encoding = 'UTF-8' - - if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { - options.release.set(targetJavaVersion) - } -} - processResources { def props = [version: version] inputs.properties props @@ -49,8 +46,12 @@ processResources { } tasks.register('copyJarToTestServer', Exec) { - dependsOn jar - mustRunAfter jar - - commandLine 'cp', 'build/libs/PixelBlocks-1.0-SNAPSHOT.jar', '/home/elias/Dokumente/mcTestServer/plugins/pixelblocks.jar' + commandLine 'cp', 'build/libs/PixelBlocks-1.0-SNAPSHOT-all.jar', '/home/elias/Dokumente/mcTestServer/plugins/pixelblocks.jar' } + +shadowJar { + relocate 'co.aikar.taskchain', 'eu.mhsl.minecraft.pixelblocks.taskchain' +} + +jar.dependsOn shadowJar +copyJarToTestServer.dependsOn jar diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlocksPlugin.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/Main.java similarity index 52% rename from src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlocksPlugin.java rename to src/main/java/eu/mhsl/minecraft/pixelblocks/Main.java index ef0c9bb..f60f0d7 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlocksPlugin.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/Main.java @@ -1,5 +1,8 @@ package eu.mhsl.minecraft.pixelblocks; +import co.aikar.taskchain.BukkitTaskChainFactory; +import co.aikar.taskchain.TaskChain; +import co.aikar.taskchain.TaskChainFactory; import eu.mhsl.minecraft.pixelblocks.commands.CreatePixelBlockCommand; import eu.mhsl.minecraft.pixelblocks.commands.ExitWorldCommand; import eu.mhsl.minecraft.pixelblocks.listeners.*; @@ -14,36 +17,45 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.logging.Logger; -public final class PixelBlocksPlugin extends JavaPlugin { - public static PixelBlocksPlugin plugin; - public static PixelBlockConfiguration configuration; - public static PixelBlockDatabase database; +public final class Main extends JavaPlugin { + private static Main plugin; + private static PixelBlockConfiguration configuration; + private static PixelBlockDatabase database; - public static List<PixelBlock> pixelBlocks = new ArrayList<>(); + private static TaskChainFactory taskFactory; + + public final static List<PixelBlock> pixelBlocks = new ArrayList<>(); + + public static <T> TaskChain<T> sharedChain(String name) { + return taskFactory.newSharedChain(name); + } @Override public void onLoad() { - PixelBlocksPlugin.plugin = this; + Main.plugin = this; FileConfiguration config = this.getConfig(); PixelBlockConfiguration.setDefaults(config); this.saveConfig(); - PixelBlocksPlugin.configuration = new PixelBlockConfiguration( - config.getInt(PixelBlockConfiguration.Keys.PixelsPerBlock.getKey()), - config.getDouble(PixelBlockConfiguration.Keys.HitboxOffset.getKey()), - config.getBoolean(PixelBlockConfiguration.Keys.OnlyBreakableByOwners.getKey()), - config.getBoolean(PixelBlockConfiguration.Keys.OnlyEditableByOwners.getKey()) + Main.configuration = new PixelBlockConfiguration( + config.getInt(PixelBlockConfiguration.Keys.PixelsPerBlock.getKey()), + config.getBoolean(PixelBlockConfiguration.Keys.OnlyBreakableByOwners.getKey()), + config.getBoolean(PixelBlockConfiguration.Keys.OnlyEditableByOwners.getKey()) ); File databaseFile = new File(plugin.getDataFolder(), "blocks.db"); - PixelBlocksPlugin.database = new PixelBlockDatabase("jdbc:sqlite:" + databaseFile); + Main.database = new PixelBlockDatabase("jdbc:sqlite:" + databaseFile); } @Override public void onEnable() { + Main.taskFactory = BukkitTaskChainFactory.create(this); + getLogger().info("Start constructing blocks from Database..."); database.loadPixelBlocks(); + getLogger().info("Construction done!"); Listener[] listeners = { new EnterPixelBlockListener(), @@ -52,7 +64,6 @@ public final class PixelBlocksPlugin extends JavaPlugin { new PlacePixelBlockListener(), new PreventInventorysListener(), new ExitPixelWorldListener(), - new CraftPixelBlockListener(), new PreventIllegalBlocksListener(), new BreakPixelBlockListener(), new PlacePixelListener(), @@ -60,10 +71,12 @@ public final class PixelBlocksPlugin extends JavaPlugin { new PreventLiquidsFlowListener(), new PreventPistonsListener(), new PreventEntityPlacementListener(), - new DiscoverRecipesListener() + new DiscoverRecipesListener(), + new QuitWhileInPixelBlockListener(), + new PreventGrowthListener() }; - for (Listener listener : listeners) { + for(Listener listener : listeners) { getServer().getPluginManager().registerEvents(listener, plugin); } @@ -75,10 +88,27 @@ public final class PixelBlocksPlugin extends JavaPlugin { @Override public void onDisable() { + Bukkit.getOnlinePlayers().forEach(QuitWhileInPixelBlockListener::kickPlayerOutOfWorld); try { database.close(); - } catch (SQLException e) { + } catch(SQLException e) { throw new RuntimeException("Failed disabling", e); } } + + public static Main plugin() { + return plugin; + } + + public static Logger logger() { + return plugin.getLogger(); + } + + public static PixelBlockDatabase database() { + return database; + } + + public static PixelBlockConfiguration configuration() { + return configuration; + } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockConfiguration.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockConfiguration.java index 803e288..383fa0e 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockConfiguration.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockConfiguration.java @@ -4,14 +4,12 @@ import org.bukkit.configuration.file.FileConfiguration; import org.jetbrains.annotations.NotNull; public record PixelBlockConfiguration( - int pixelsPerBlock, - double hitboxOffset, - boolean onlyBreakableByOwner, - boolean onlyEditableByOwner + int pixelsPerBlock, + boolean onlyBreakableByOwner, + boolean onlyEditableByOwner ) { public static void setDefaults(FileConfiguration config) { config.addDefault(Keys.PixelsPerBlock.key, 16); - config.addDefault(Keys.HitboxOffset.key, 0.005); config.addDefault(Keys.OnlyBreakableByOwners.key, false); config.addDefault(Keys.OnlyEditableByOwners.key, true); config.options().copyDefaults(true); @@ -19,11 +17,11 @@ public record PixelBlockConfiguration( public enum Keys { PixelsPerBlock("pixelsPerBlock"), - HitboxOffset("hitboxOffset"), OnlyBreakableByOwners("onlyBreakableByOwners"), OnlyEditableByOwners("onlyEditableByOwners"); private final String key; + Keys(@NotNull String key) { this.key = key; } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockDatabase.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockDatabase.java index 19128e3..9ba530f 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockDatabase.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockDatabase.java @@ -1,13 +1,11 @@ package eu.mhsl.minecraft.pixelblocks; -import eu.mhsl.minecraft.pixelblocks.utils.Direction; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; +import eu.mhsl.minecraft.pixelblocks.utils.Direction; import org.bukkit.Bukkit; import org.bukkit.Location; import java.sql.*; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; public class PixelBlockDatabase { @@ -15,9 +13,7 @@ public class PixelBlockDatabase { private final PreparedStatement getAllPixelBlocks; private final PreparedStatement deletePixelBlock; - private final PreparedStatement insertNewPixelBlock; - private final PreparedStatement updateExistingPixelBlock; - + private final PreparedStatement insertOrReplacePixelBlock; public PixelBlockDatabase(String url) { try { @@ -25,134 +21,81 @@ public class PixelBlockDatabase { this.db = DriverManager.getConnection(url); this.db.createStatement().execute( - "CREATE TABLE IF NOT EXISTS pixelblocks (" + - "uuid CHAR(36) PRIMARY KEY, " + - "owner CHAR(36), " + - "locationWorldName CHAR(36), " + - "locationX DOUBLE, " + - "locationY DOUBLE, " + - "locationZ DOUBLE, " + - "entryLocationWorldName CHAR(36), " + - "entryLocationX DOUBLE, " + - "entryLocationY DOUBLE, " + - "entryLocationZ DOUBLE, " + - "direction CHAR(36)" + - ")" + "CREATE TABLE IF NOT EXISTS pixelblocks (" + + "uuid CHAR(36) PRIMARY KEY, " + + "owner CHAR(36), " + + "locationWorldName CHAR(36), " + + "locationX DOUBLE, " + + "locationY DOUBLE, " + + "locationZ DOUBLE, " + + "entryLocationWorldName CHAR(36), " + + "entryLocationX DOUBLE, " + + "entryLocationY DOUBLE, " + + "entryLocationZ DOUBLE, " + + "direction CHAR(36)" + + ")" ); this.deletePixelBlock = this.db.prepareStatement("DELETE FROM pixelblocks WHERE uuid = ?"); this.getAllPixelBlocks = this.db.prepareStatement("SELECT * FROM pixelblocks"); - this.insertNewPixelBlock = this.db.prepareStatement( - "INSERT INTO pixelblocks(uuid, owner, " + - "locationWorldName, locationX, locationY, locationZ, " + - "entryLocationWorldName, entryLocationX, entryLocationY, entryLocationZ, direction) " + - "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + this.insertOrReplacePixelBlock = this.db.prepareStatement( + "INSERT OR REPLACE INTO pixelblocks(uuid, owner, " + + "locationWorldName, locationX, locationY, locationZ, " + + "entryLocationWorldName, entryLocationX, entryLocationY, entryLocationZ, direction) " + + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" ); - this.updateExistingPixelBlock = this.db.prepareStatement( - "UPDATE pixelblocks " + - "SET owner=?, locationWorldName=?, locationX=?, locationY=?, locationZ=?," + - "entryLocationWorldName=?, entryLocationX=?, entryLocationY=?, entryLocationZ=?, direction=? " + - "WHERE uuid=?;" - ); - } catch (SQLException | RuntimeException | ClassNotFoundException e) { - throw new RuntimeException("Failed to load Database", e); + + } catch(SQLException | RuntimeException | ClassNotFoundException e) { + throw new RuntimeException("Error while initializing database", e); } } public void close() throws SQLException { deletePixelBlock.close(); getAllPixelBlocks.close(); - insertNewPixelBlock.close(); - updateExistingPixelBlock.close(); + insertOrReplacePixelBlock.close(); db.close(); } public void deletePixelBlock(PixelBlock pixelBlock) { - Bukkit.getScheduler().runTaskAsynchronously(PixelBlocksPlugin.plugin, () -> { + Bukkit.getScheduler().runTaskAsynchronously(Main.plugin(), () -> { try { - this.deletePixelBlock.setString(1, pixelBlock.blockUUID.toString()); + this.deletePixelBlock.setString(1, pixelBlock.getBlockUUID().toString()); this.deletePixelBlock.executeUpdate(); - PixelBlocksPlugin.plugin.getLogger().info("DB: Deleted PixelBlock: " + pixelBlock.blockUUID); - } catch (SQLException e) { - throw new RuntimeException("Failed to delete PixelBlock", e); + } catch(SQLException e) { + throw new RuntimeException("Failed to delete PixelBlock from the database", e); } }); } public void savePixelBlock(PixelBlock pixelBlock) { - Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> { - List<UUID> storedPixelBlocks = new ArrayList<>(); - + Bukkit.getScheduler().runTask(Main.plugin(), () -> { try { - ResultSet pixelBlocksResult = this.getAllPixelBlocks.executeQuery(); - while (pixelBlocksResult.next()) { - storedPixelBlocks.add(UUID.fromString(pixelBlocksResult.getString("uuid"))); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to fetch PixelBlock list", e); - } + this.insertOrReplacePixelBlock.setString(1, pixelBlock.getBlockUUID().toString()); + this.insertOrReplacePixelBlock.setString(2, pixelBlock.getOwnerUUID().toString()); - if(!storedPixelBlocks.contains(pixelBlock.blockUUID)) { - // create new entry if it does not exist - try { - this.insertNewPixelBlock.setString(1, pixelBlock.blockUUID.toString()); - this.insertNewPixelBlock.setString(2, pixelBlock.ownerUUID.toString()); + this.insertOrReplacePixelBlock.setString(3, pixelBlock.getPixelBlockLocation().getWorld().getName()); + this.insertOrReplacePixelBlock.setDouble(4, pixelBlock.getPixelBlockLocation().getX()); + this.insertOrReplacePixelBlock.setDouble(5, pixelBlock.getPixelBlockLocation().getY()); + this.insertOrReplacePixelBlock.setDouble(6, pixelBlock.getPixelBlockLocation().getZ()); - this.insertNewPixelBlock.setString(3, pixelBlock.pixelBlockLocation.getWorld().getName()); - this.insertNewPixelBlock.setDouble(4, pixelBlock.pixelBlockLocation.getX()); - this.insertNewPixelBlock.setDouble(5, pixelBlock.pixelBlockLocation.getY()); - this.insertNewPixelBlock.setDouble(6, pixelBlock.pixelBlockLocation.getZ()); - - if(pixelBlock.lastEntryLocation != null) { - this.insertNewPixelBlock.setString(7, pixelBlock.lastEntryLocation.getWorld().getName()); - this.insertNewPixelBlock.setDouble(8, pixelBlock.lastEntryLocation.getX()); - this.insertNewPixelBlock.setDouble(9, pixelBlock.lastEntryLocation.getY()); - this.insertNewPixelBlock.setDouble(10, pixelBlock.lastEntryLocation.getZ()); - } else { - this.insertNewPixelBlock.setString(7, Bukkit.getWorlds().getFirst().getName()); - this.insertNewPixelBlock.setDouble(8, Bukkit.getWorlds().getFirst().getSpawnLocation().getX()); - this.insertNewPixelBlock.setDouble(9, Bukkit.getWorlds().getFirst().getSpawnLocation().getY()); - this.insertNewPixelBlock.setDouble(10, Bukkit.getWorlds().getFirst().getSpawnLocation().getZ()); - } - - this.insertNewPixelBlock.setString(11, pixelBlock.facingDirection.toString()); - - this.insertNewPixelBlock.executeUpdate(); - PixelBlocksPlugin.plugin.getLogger().info("DB: Created PixelBlock: " + pixelBlock.blockUUID); - } catch (SQLException e) { - throw new RuntimeException("Failed to save PixelBlock", e); + if(pixelBlock.hasLastEntryLocation()) { + this.insertOrReplacePixelBlock.setString(7, pixelBlock.getLastEntryLocation().getWorld().getName()); + this.insertOrReplacePixelBlock.setDouble(8, pixelBlock.getLastEntryLocation().getX()); + this.insertOrReplacePixelBlock.setDouble(9, pixelBlock.getLastEntryLocation().getY()); + this.insertOrReplacePixelBlock.setDouble(10, pixelBlock.getLastEntryLocation().getZ()); + } else { + this.insertOrReplacePixelBlock.setString(7, pixelBlock.getPixelBlockLocation().getWorld().getName()); + this.insertOrReplacePixelBlock.setDouble(8, pixelBlock.getPixelBlockLocation().getX()); + this.insertOrReplacePixelBlock.setDouble(9, pixelBlock.getPixelBlockLocation().getY()); + this.insertOrReplacePixelBlock.setDouble(10, pixelBlock.getPixelBlockLocation().getZ()); } - } else { - // update existing entry - try { - this.updateExistingPixelBlock.setString(1, pixelBlock.ownerUUID.toString()); + this.insertOrReplacePixelBlock.setString(11, pixelBlock.getFacingDirection().toString()); - this.updateExistingPixelBlock.setString(2, pixelBlock.pixelBlockLocation.getWorld().getName()); - this.updateExistingPixelBlock.setDouble(3, pixelBlock.pixelBlockLocation.getX()); - this.updateExistingPixelBlock.setDouble(4, pixelBlock.pixelBlockLocation.getY()); - this.updateExistingPixelBlock.setDouble(5, pixelBlock.pixelBlockLocation.getZ()); - - if(pixelBlock.lastEntryLocation != null) { - this.updateExistingPixelBlock.setString(6, pixelBlock.lastEntryLocation.getWorld().getName()); - this.updateExistingPixelBlock.setDouble(7, pixelBlock.lastEntryLocation.getX()); - this.updateExistingPixelBlock.setDouble(8, pixelBlock.lastEntryLocation.getY()); - this.updateExistingPixelBlock.setDouble(9, pixelBlock.lastEntryLocation.getZ()); - } else { - this.updateExistingPixelBlock.setString(6, Bukkit.getWorlds().getFirst().getName()); - this.updateExistingPixelBlock.setDouble(7, Bukkit.getWorlds().getFirst().getSpawnLocation().getX()); - this.updateExistingPixelBlock.setDouble(8, Bukkit.getWorlds().getFirst().getSpawnLocation().getY()); - this.updateExistingPixelBlock.setDouble(9, Bukkit.getWorlds().getFirst().getSpawnLocation().getZ()); - } - - this.updateExistingPixelBlock.setString(10, pixelBlock.blockUUID.toString()); - this.updateExistingPixelBlock.setString(11, pixelBlock.facingDirection.toString()); - - this.updateExistingPixelBlock.executeUpdate(); - PixelBlocksPlugin.plugin.getLogger().info("DB: Updated PixelBlock: " + pixelBlock.blockUUID); - } catch (SQLException e) { - throw new RuntimeException("Failed updating PixelBlock", e); - } + this.insertOrReplacePixelBlock.executeUpdate(); + } catch(SQLException e) { + throw new RuntimeException("Failed to create or update PixelBlock in the database", e); } }); } @@ -161,7 +104,7 @@ public class PixelBlockDatabase { try { ResultSet allPixelBlocks = this.getAllPixelBlocks.executeQuery(); - while (allPixelBlocks.next()) { + while(allPixelBlocks.next()) { Location blockLocation = new Location( Bukkit.getWorld(allPixelBlocks.getString("locationWorldName")), allPixelBlocks.getDouble("locationX"), @@ -176,17 +119,16 @@ public class PixelBlockDatabase { allPixelBlocks.getDouble("entryLocationZ") ); - PixelBlock block = new PixelBlock( - blockLocation, - UUID.fromString(allPixelBlocks.getString("owner")), + Main.pixelBlocks.add(PixelBlock.fromExisting( UUID.fromString(allPixelBlocks.getString("uuid")), - Direction.valueOf(allPixelBlocks.getString("direction")) - ); - block.setLastEntryLocation(entryLocation); - PixelBlocksPlugin.plugin.getLogger().info("DB: Loaded PixelBlock: " + block.blockUUID); + UUID.fromString(allPixelBlocks.getString("owner")), + blockLocation, + Direction.valueOf(allPixelBlocks.getString("direction")), + entryLocation + )); } - } catch (SQLException e) { - throw new RuntimeException("Failed loading PixelBlocks", e); + } catch(SQLException e) { + throw new RuntimeException("Failed loading PixelBlocks from the database", e); } } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockItem.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockItem.java index 7f52d37..495de65 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockItem.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/PixelBlockItem.java @@ -11,30 +11,53 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.UUID; public class PixelBlockItem { - public static UUID unusedBlockID = UUID.fromString("98fdf0ae-c3ab-4ef7-ae25-efd518d600de"); + public static final NamespacedKey recipeKey = new NamespacedKey(Main.plugin(), "pixelblock"); + public static NamespacedKey idProperty = new NamespacedKey(Main.plugin(), "id"); + public static NamespacedKey ownerProperty = new NamespacedKey(Main.plugin(), "owner"); + public static final String itemTexture = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzE5NGU5ZTc3NTdkMDZkNmY1ZTViZTg0NTQ4YTdjYjUyMTczZDY4Y2NmODAyZDIxMTI3NWQzMWNkYmEwYTA2ZSJ9fX0="; - public static final NamespacedKey recipeKey = new NamespacedKey(PixelBlocksPlugin.plugin, "pixelblock"); + + public record BlockInfo(UUID id, @Nullable UUID owner) { + public boolean hasOwner() { + return owner != null; + } + } + + public static @Nullable BlockInfo getBlockInfo(ItemStack item) { + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + if(!container.has(idProperty)) return null; + UUID blockId = UUID.fromString(Objects.requireNonNull(container.get(idProperty, PersistentDataType.STRING))); + UUID ownerId = container.has(ownerProperty) + ? UUID.fromString(Objects.requireNonNull(container.get(ownerProperty, PersistentDataType.STRING))) + : null; + return new BlockInfo(blockId, ownerId); + } public static @NotNull ItemStack getBlockAsItem(@NotNull PixelBlock block) { - String ownerName = Optional.ofNullable(Bukkit.getOfflinePlayer(block.ownerUUID).getName()).orElseGet(() -> block.ownerUUID.toString()); + String ownerName = Optional.ofNullable(Bukkit.getOfflinePlayer(block.getOwnerUUID()).getName()).orElseGet(() -> block.getOwnerUUID().toString()); ItemStack itemStack = HeadUtil.getCustomTextureHead(itemTexture); ItemMeta meta = itemStack.getItemMeta(); - meta.itemName(Component.text(block.blockUUID.toString())); + meta.setMaxStackSize(1); + meta.getPersistentDataContainer().set(idProperty, PersistentDataType.STRING, block.getBlockUUID().toString()); + meta.getPersistentDataContainer().set(ownerProperty, PersistentDataType.STRING, block.getOwnerUUID().toString()); meta.displayName(Component.text("Pixelblock von " + ownerName)); meta.lore(List.of( Component.text(ownerName + " ist der Besitzer dieses Blocks."), Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!"), - Component.text(block.blockUUID.toString()).color(NamedTextColor.DARK_GRAY) + Component.text(block.getBlockUUID().toString()).color(NamedTextColor.DARK_GRAY) )); - meta.setEnchantmentGlintOverride(true); itemStack.setItemMeta(meta); return itemStack; @@ -43,13 +66,13 @@ public class PixelBlockItem { public static @NotNull ItemStack getEmptyPixelBlock() { ItemStack item = HeadUtil.getCustomTextureHead(itemTexture); ItemMeta meta = item.getItemMeta(); + meta.setMaxStackSize(1); meta.displayName(Component.text("Leerer Pixelblock")); meta.lore(List.of( 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!") )); - meta.setEnchantmentGlintOverride(true); - meta.itemName(Component.text(unusedBlockID.toString())); + meta.getPersistentDataContainer().set(idProperty, PersistentDataType.STRING, UUID.randomUUID().toString()); item.setItemMeta(meta); return item; } @@ -61,7 +84,7 @@ public class PixelBlockItem { recipe.setIngredient('B', Material.DIAMOND_BLOCK); recipe.setIngredient('C', Material.HEART_OF_THE_SEA); recipe.setIngredient('D', Material.GRASS_BLOCK); - recipe.setIngredient('E', Material.GLOW_BERRIES); + recipe.setIngredient('E', Material.END_CRYSTAL); return recipe; } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/commands/CreatePixelBlockCommand.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/commands/CreatePixelBlockCommand.java index 4b8c69b..0ca7f20 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/commands/CreatePixelBlockCommand.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/commands/CreatePixelBlockCommand.java @@ -1,8 +1,8 @@ package eu.mhsl.minecraft.pixelblocks.commands; +import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld; import eu.mhsl.minecraft.pixelblocks.utils.Direction; -import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.Command; @@ -24,13 +24,12 @@ 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); } return true; } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/commands/ExitWorldCommand.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/commands/ExitWorldCommand.java index 10a4442..c6e33c6 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/commands/ExitWorldCommand.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/commands/ExitWorldCommand.java @@ -9,7 +9,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.Objects; public class ExitWorldCommand implements CommandExecutor { @Override @@ -23,7 +23,7 @@ public class ExitWorldCommand implements CommandExecutor { PixelBlock currentPixelBlock = PixelBlock.getPixelBlockFromBlockWorld(playerWorld); Objects.requireNonNull(currentPixelBlock); - p.teleport(currentPixelBlock.lastEntryLocation); + currentPixelBlock.exitBlock(p); } return true; } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/BreakPixelBlockListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/BreakPixelBlockListener.java index d9863cb..5d1be1c 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/BreakPixelBlockListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/BreakPixelBlockListener.java @@ -1,6 +1,5 @@ package eu.mhsl.minecraft.pixelblocks.listeners; -import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import io.papermc.paper.event.player.PrePlayerAttackEntityEvent; import org.bukkit.Location; @@ -10,10 +9,10 @@ import org.bukkit.event.Listener; public class BreakPixelBlockListener implements Listener { @EventHandler - static void destroyPixelBlock(PrePlayerAttackEntityEvent event) { + public void destroyPixelBlock(PrePlayerAttackEntityEvent event) { if(!(event.getAttacked() instanceof Interaction)) return; - Location blockLocation = event.getAttacked().getLocation().add(0, PixelBlocksPlugin.configuration.hitboxOffset(), 0).toBlockLocation(); + Location blockLocation = event.getAttacked().getLocation().toBlockLocation(); PixelBlock pixelBlock = PixelBlock.getPixelBlockFromPlacedLocation(blockLocation); if(pixelBlock == null) return; pixelBlock.destroy(event.getPlayer()); diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/BreakPixelListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/BreakPixelListener.java index be48781..0dcbddd 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/BreakPixelListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/BreakPixelListener.java @@ -7,7 +7,7 @@ import org.bukkit.event.block.BlockBreakEvent; public class BreakPixelListener implements Listener { @EventHandler - static void onBlockBreak(BlockBreakEvent event) { + public void onBlockBreak(BlockBreakEvent event) { EventCanceling.shouldCancelInPixelBlock( event, event.getBlock().getWorld(), diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/CraftPixelBlockListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/CraftPixelBlockListener.java deleted file mode 100644 index 0201d53..0000000 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/CraftPixelBlockListener.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.mhsl.minecraft.pixelblocks.listeners; - -import eu.mhsl.minecraft.pixelblocks.PixelBlockItem; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -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 java.util.Objects; - -public class CraftPixelBlockListener implements Listener { - @EventHandler - static void onCraftItem(CraftItemEvent event) { - ItemStack craftedItem = event.getCurrentItem(); - Objects.requireNonNull(craftedItem); - - ItemMeta craftedItemMeta = craftedItem.getItemMeta(); - String itemName = PlainTextComponentSerializer.plainText().serialize(craftedItemMeta.itemName()); - - if(!itemName.equals(PixelBlockItem.unusedBlockID.toString())) return; - if(event.isShiftClick()) event.setCancelled(true); - } -} diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/DiscoverRecipesListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/DiscoverRecipesListener.java index 6efb61c..b46ffc2 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/DiscoverRecipesListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/DiscoverRecipesListener.java @@ -1,12 +1,12 @@ package eu.mhsl.minecraft.pixelblocks.listeners; +import eu.mhsl.minecraft.pixelblocks.Main; import eu.mhsl.minecraft.pixelblocks.PixelBlockItem; -import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.inventory.*; +import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.List; @@ -17,10 +17,10 @@ public class DiscoverRecipesListener implements Listener { public void shouldDiscover(InventoryClickEvent event) { ItemStack clickedItem = event.getCurrentItem(); if(clickedItem == null) return; - if(!List.of(Material.HEART_OF_THE_SEA, Material.GLOW_BERRIES).contains(clickedItem.getType())) return; if(!(event.getWhoClicked() instanceof Player player)) return; + if(!List.of(Material.HEART_OF_THE_SEA, Material.END_CRYSTAL).contains(clickedItem.getType())) return; if(player.hasDiscoveredRecipe(PixelBlockItem.recipeKey)) return; - PixelBlocksPlugin.plugin.getLogger().log(Level.INFO, String.format("%s unlocked tne PixelBlock recipe!", player.getName())); + Main.logger().log(Level.INFO, String.format("%s unlocked tne PixelBlock recipe!", player.getName())); player.discoverRecipe(PixelBlockItem.recipeKey); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/EnterPixelBlockListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/EnterPixelBlockListener.java index 13f3c32..43d864a 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/EnterPixelBlockListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/EnterPixelBlockListener.java @@ -1,8 +1,7 @@ package eu.mhsl.minecraft.pixelblocks.listeners; -import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; -import org.bukkit.*; +import org.bukkit.Location; import org.bukkit.entity.Interaction; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -10,14 +9,13 @@ import org.bukkit.event.player.PlayerInteractEntityEvent; public class EnterPixelBlockListener implements Listener { @EventHandler - static void enterPixelBlock(PlayerInteractEntityEvent event) { + public void enterPixelBlock(PlayerInteractEntityEvent event) { if(!(event.getRightClicked() instanceof Interaction)) return; Location interactionLocation = event - .getRightClicked() - .getLocation() - .add(0, PixelBlocksPlugin.configuration.hitboxOffset(), 0) - .toBlockLocation(); + .getRightClicked() + .getLocation() + .toBlockLocation(); PixelBlock pixelBlock = PixelBlock.getPixelBlockFromPlacedLocation(interactionLocation); if(pixelBlock == null) return; pixelBlock.enterBlock(event.getPlayer()); diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/ExitPixelWorldListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/ExitPixelWorldListener.java index 904af61..638f94a 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/ExitPixelWorldListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/ExitPixelWorldListener.java @@ -5,31 +5,19 @@ 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 - static void onPlayerChangeWorld(PlayerChangedWorldEvent event) { - World changingFrom = event.getFrom(); - if(!PixelBlockWorld.isPixelWorld(changingFrom)) return; - - PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(changingFrom); - Objects.requireNonNull(pixelBlock); - pixelBlock.updateEntities(); - } - - @EventHandler - static void onPlayerPortal(PlayerPortalEvent event) { + public void onPlayerPortal(PlayerPortalEvent event) { World pixelBlockWorld = event.getFrom().getWorld(); - if(!PixelBlockWorld.isPixelWorld(pixelBlockWorld)) return; event.setCancelled(true); PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(pixelBlockWorld); Objects.requireNonNull(pixelBlock); - event.getPlayer().teleport(pixelBlock.lastEntryLocation); + pixelBlock.exitBlock(event.getPlayer()); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/FallOutOfPixelBlockListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/FallOutOfPixelBlockListener.java index 856d4b6..3a4a660 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/FallOutOfPixelBlockListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/FallOutOfPixelBlockListener.java @@ -11,7 +11,7 @@ import java.util.Objects; public class FallOutOfPixelBlockListener implements Listener { @EventHandler - static void onPlayerMove(PlayerMoveEvent event) { + public void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); if(player.getLocation().y() > -65) return; if(!PixelBlockWorld.isPixelWorld(player.getWorld())) return; diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PlacePixelBlockListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PlacePixelBlockListener.java index 5e34565..bf73dae 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PlacePixelBlockListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PlacePixelBlockListener.java @@ -1,12 +1,11 @@ package eu.mhsl.minecraft.pixelblocks.listeners; import eu.mhsl.minecraft.pixelblocks.PixelBlockItem; -import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld; import eu.mhsl.minecraft.pixelblocks.utils.Direction; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -14,23 +13,17 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; - -import java.util.UUID; public class PlacePixelBlockListener implements Listener { @EventHandler - static void onBlockPlace(BlockPlaceEvent event) { + public void onBlockPlace(BlockPlaceEvent event) { ItemStack usedItem = event.getItemInHand(); - ItemMeta usedItemMeta = usedItem.getItemMeta(); - Component displayName = usedItemMeta.displayName(); - if(displayName == null) return; - if(!displayName.toString().contains("Pixelblock")) return; - if(!usedItemMeta.getEnchantmentGlintOverride()) return; + PixelBlockItem.BlockInfo info = PixelBlockItem.getBlockInfo(usedItem); + if(info == null) return; World playerWorld = event.getPlayer().getWorld(); if(PixelBlockWorld.isPixelWorld(playerWorld)) { - event.getPlayer().sendMessage("In Pixelblöcken kann kein Pixelblock erstellt werden."); + event.getPlayer().sendMessage(Component.text("In Pixelblöcken kann kein Pixelblock platziert werden.", NamedTextColor.RED)); event.setCancelled(true); return; } @@ -39,34 +32,50 @@ public class PlacePixelBlockListener implements Listener { playerWorld.getBlockAt(newBlockLocation).setType(Material.AIR); Direction direction = Direction.vectorToDirection(event.getPlayer().getLocation().getDirection()); - String itemName = PlainTextComponentSerializer.plainText().serialize(usedItemMeta.itemName()); - PixelBlock pixelBlock; - if(itemName.equals(PixelBlockItem.unusedBlockID.toString())) { - pixelBlock = new PixelBlock( - newBlockLocation, - event.getPlayer().getUniqueId(), - UUID.randomUUID(), - direction - ); - } else { - UUID itemUUID = UUID.fromString(itemName); - pixelBlock = PixelBlocksPlugin.pixelBlocks.stream() - .filter(block -> block.blockUUID.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())); +// } } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PlacePixelListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PlacePixelListener.java index 3130016..ba5d54a 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PlacePixelListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PlacePixelListener.java @@ -8,7 +8,7 @@ import org.bukkit.event.player.PlayerBucketEmptyEvent; public class PlacePixelListener implements Listener { @EventHandler - static void onBlockPlace(BlockPlaceEvent event) { + public void onBlockPlace(BlockPlaceEvent event) { EventCanceling.shouldCancelInPixelBlock( event, event.getBlock().getWorld(), @@ -17,11 +17,11 @@ public class PlacePixelListener implements Listener { } @EventHandler - static void onBuketEmpty(PlayerBucketEmptyEvent event) { + public void onBuketEmpty(PlayerBucketEmptyEvent event) { EventCanceling.shouldCancelInPixelBlock( - event, - event.getBlock().getWorld(), - pixelBlock -> !pixelBlock.getPixelWorld().allowPlacements(event.getBlock().getLocation()) + event, + event.getBlock().getWorld(), + pixelBlock -> !pixelBlock.getPixelWorld().allowPlacements(event.getBlock().getLocation()) ); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventEntityPlacementListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventEntityPlacementListener.java index 9e672ab..12e4929 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventEntityPlacementListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventEntityPlacementListener.java @@ -7,7 +7,7 @@ import org.bukkit.event.entity.EntityPlaceEvent; public class PreventEntityPlacementListener implements Listener { @EventHandler - public static void preventPlace(EntityPlaceEvent event) { + public void preventPlace(EntityPlaceEvent event) { EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld()); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventGrowthListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventGrowthListener.java new file mode 100644 index 0000000..ce227b8 --- /dev/null +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventGrowthListener.java @@ -0,0 +1,23 @@ +package eu.mhsl.minecraft.pixelblocks.listeners; + +import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; +import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockFertilizeEvent; + +import java.util.Objects; + +public class PreventGrowthListener implements Listener { + @EventHandler + public void inBoneMeal(BlockFertilizeEvent event) { + if(!PixelBlockWorld.isPixelWorld(event.getBlock().getWorld())) return; + PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(event.getBlock().getWorld()); + Objects.requireNonNull(pixelBlock); + + event.getBlocks().stream() + .filter(blockState -> !pixelBlock.getPixelWorld().allowPlacements(blockState.getBlock().getLocation())) + .forEach(blockState -> blockState.setType(Material.AIR)); + } +} diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventHopperActionsListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventHopperActionsListener.java index d349a40..2219bc9 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventHopperActionsListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventHopperActionsListener.java @@ -8,7 +8,7 @@ import org.bukkit.event.inventory.InventoryType; public class PreventHopperActionsListener implements Listener { @EventHandler - static void onInventoryPickupItem(InventoryPickupItemEvent event) { + public void onInventoryPickupItem(InventoryPickupItemEvent event) { EventCanceling.shouldCancelInPixelBlock( event, event.getItem().getWorld(), diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventIllegalBlocksListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventIllegalBlocksListener.java index 1b56d95..e0a779f 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventIllegalBlocksListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventIllegalBlocksListener.java @@ -10,22 +10,22 @@ import org.bukkit.event.entity.EntityExplodeEvent; public class PreventIllegalBlocksListener implements Listener { @EventHandler - static void onBlockExplode(BlockExplodeEvent event) { + public void onBlockExplode(BlockExplodeEvent event) { EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld()); } @EventHandler - static void onCreatureSpawn(CreatureSpawnEvent event) { + public void onCreatureSpawn(CreatureSpawnEvent event) { EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld()); } @EventHandler - static void onEntityDamage(EntityDamageEvent event) { + public void onEntityDamage(EntityDamageEvent event) { EventCanceling.cancelIfInPixelWorld(event, event.getEntity().getWorld()); } @EventHandler - static void onEntityExplode(EntityExplodeEvent event) { + public void onEntityExplode(EntityExplodeEvent event) { EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld()); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventInventorysListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventInventorysListener.java index dcec263..ea2339e 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventInventorysListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventInventorysListener.java @@ -3,14 +3,16 @@ package eu.mhsl.minecraft.pixelblocks.listeners; import eu.mhsl.minecraft.pixelblocks.utils.EventCanceling; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.inventory.*; +import org.bukkit.event.inventory.InventoryInteractEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.CraftingInventory; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.PlayerInventory; public class PreventInventorysListener implements Listener { @EventHandler - static void onInventoryOpen(InventoryOpenEvent event) { + public void onInventoryOpen(InventoryOpenEvent event) { EventCanceling.shouldCancelInPixelBlock( event, event.getPlayer().getWorld(), @@ -19,7 +21,7 @@ public class PreventInventorysListener implements Listener { } @EventHandler - static void onInventoryInteract(InventoryInteractEvent event) { + public void onInventoryInteract(InventoryInteractEvent event) { EventCanceling.shouldCancelInPixelBlock( event, event.getWhoClicked().getWorld(), @@ -29,7 +31,7 @@ public class PreventInventorysListener implements Listener { private static boolean isDisallowedInventory(Inventory inventory) { return !(inventory instanceof PlayerInventory - || inventory instanceof CraftingInventory - || inventory.getType() == InventoryType.ENDER_CHEST); + || inventory instanceof CraftingInventory + || inventory.getType() == InventoryType.ENDER_CHEST); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventLiquidsFlowListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventLiquidsFlowListener.java index 79ccc4a..4e5e5b3 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventLiquidsFlowListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventLiquidsFlowListener.java @@ -7,11 +7,11 @@ import org.bukkit.event.block.BlockFromToEvent; public class PreventLiquidsFlowListener implements Listener { @EventHandler - public static void onLiquidFlow(BlockFromToEvent event) { + public void onLiquidFlow(BlockFromToEvent event) { EventCanceling.shouldCancelInPixelBlock( - event, - event.getToBlock().getWorld(), - pixelBlock -> !pixelBlock.getPixelWorld().allowPlacements(event.getToBlock().getLocation()) + event, + event.getToBlock().getWorld(), + pixelBlock -> !pixelBlock.getPixelWorld().allowPlacements(event.getToBlock().getLocation()) ); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventPistonsListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventPistonsListener.java index f9e8b28..57cc363 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventPistonsListener.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/PreventPistonsListener.java @@ -7,13 +7,13 @@ import org.bukkit.event.block.BlockPistonExtendEvent; public class PreventPistonsListener implements Listener { @EventHandler - public static void blockPistons(BlockPistonExtendEvent event) { + public void blockPistons(BlockPistonExtendEvent event) { EventCanceling.shouldCancelInPixelBlock( event, event.getBlock().getWorld(), (pixelBlock) -> event.getBlocks().stream() .anyMatch(block -> !pixelBlock.getPixelWorld() - .allowPlacements(block.getLocation().add(event.getDirection().getDirection()))) + .allowPlacements(block.getLocation().add(event.getDirection().getDirection()))) ); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/QuitWhileInPixelBlockListener.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/QuitWhileInPixelBlockListener.java new file mode 100644 index 0000000..ca03ed2 --- /dev/null +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/listeners/QuitWhileInPixelBlockListener.java @@ -0,0 +1,26 @@ +package eu.mhsl.minecraft.pixelblocks.listeners; + +import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; +import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.Objects; + +public class QuitWhileInPixelBlockListener implements Listener { + @EventHandler + public void onLeave(PlayerQuitEvent event) { + kickPlayerOutOfWorld(event.getPlayer()); + } + + public static void kickPlayerOutOfWorld(Player player) { + World pixelBlockWorld = player.getLocation().getWorld(); + if(!PixelBlockWorld.isPixelWorld(pixelBlockWorld)) return; + PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(pixelBlockWorld); + Objects.requireNonNull(pixelBlock); + pixelBlock.exitBlock(player); + } +} 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 7c9e655..0000000 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/Pixel.java +++ /dev/null @@ -1,57 +0,0 @@ -package eu.mhsl.minecraft.pixelblocks.pixelblock; - -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.BlockDisplay; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.util.Transformation; -import org.jetbrains.annotations.NotNull; - -import javax.annotation.Nullable; -import java.util.Objects; -import java.util.UUID; - -public class Pixel { - public final Location relativeLocation; - public final BlockData blockData; - private final double scale; - - private @Nullable UUID uuid; - - public Pixel(@NotNull Location relativeLocation, @NotNull BlockData blockData, double scale) { - this.relativeLocation = new Location( - relativeLocation.getWorld(), - relativeLocation.x(), - relativeLocation.y(), - relativeLocation.z() - ); - this.blockData = blockData; - this.scale = scale; - } - - public void place(@NotNull Location spawnBlockLocation) { - World world = spawnBlockLocation.getWorld(); - double positionX = spawnBlockLocation.x() + (relativeLocation.x()*scale); - double positionY = spawnBlockLocation.y() + (relativeLocation.y()*scale); - double positionZ = spawnBlockLocation.z() + (relativeLocation.z()*scale); - - Location spawnLocation = new Location(world, positionX, positionY, positionZ); - - BlockDisplay entity = (BlockDisplay) world.spawnEntity(spawnLocation, EntityType.BLOCK_DISPLAY); - this.uuid = entity.getUniqueId(); - - entity.setBlock(blockData); - - Transformation transform = entity.getTransformation(); - transform.getScale().set(scale); - entity.setTransformation(transform); - } - - public void destroy() { - Objects.requireNonNull(this.uuid); - Entity pixelEntity = this.relativeLocation.getWorld().getEntity(this.uuid); - if(pixelEntity != null) pixelEntity.remove(); - } -} 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 3170042..bd539f0 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlock.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlock.java @@ -1,53 +1,53 @@ package eu.mhsl.minecraft.pixelblocks.pixelblock; +import co.aikar.taskchain.TaskChain; +import eu.mhsl.minecraft.pixelblocks.Main; import eu.mhsl.minecraft.pixelblocks.PixelBlockItem; -import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin; import eu.mhsl.minecraft.pixelblocks.utils.Direction; -import eu.mhsl.minecraft.pixelblocks.utils.MinMaxUtil; -import org.bukkit.*; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.*; -import org.bukkit.inventory.ItemStack; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.World; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; -import java.io.File; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.UUID; public class PixelBlock { - private final PixelBlockWorld pixelWorld; + private boolean exists = true; + private PixelBlockWorld pixelWorld; - private final float hitboxOffset = (float) PixelBlocksPlugin.configuration.hitboxOffset(); - private final int pixelsPerBlock = PixelBlocksPlugin.configuration.pixelsPerBlock(); + private final Location pixelBlockLocation; + private final Direction facingDirection; + private Pixels pixels; + private List<PixelBlockWorld.PixelData> pixelData; - public Location pixelBlockLocation; - public Direction facingDirection; - public ArrayList<Pixel> pixels = new ArrayList<>(); + private PixelBlockHitbox hitbox; + private PixelBlockPlaceholder placeholder; - public Interaction hitbox; - public ItemDisplay barrier; - - public long lastEntryTime; - public Location lastEntryLocation; - public UUID ownerUUID; - public UUID blockUUID; - - public static @NotNull String getWorldName(@NotNull PixelBlock pixelBlock) { - return PixelBlocksPlugin.plugin.getDataFolder().getPath() + File.separator + pixelBlock.blockUUID; - } + private Location lastEntryLocation; + private final UUID ownerUUID; + private final UUID blockUUID; public static @Nullable PixelBlock getPixelBlockFromBlockWorld(World world) { - return PixelBlocksPlugin.pixelBlocks.stream() - .filter(block -> block.blockUUID.equals(getUUIDFromWorld(world))) - .findFirst() - .orElse(null); + return Main.pixelBlocks.stream() + .filter(block -> block.blockUUID.equals(getUUIDFromWorld(world))) + .findFirst() + .orElse(null); } public static @Nullable UUID getUUIDFromWorld(@NotNull World world) { try { return UUID.fromString(List.of(world.getName().split("/")).getLast()); - } catch (IllegalArgumentException e) { + } catch(IllegalArgumentException e) { return null; } } @@ -57,226 +57,219 @@ public class PixelBlock { searchLocation.setPitch(0); searchLocation.setYaw(0); - return PixelBlocksPlugin.pixelBlocks.stream() - .filter(block -> block.pixelBlockLocation.equals(searchLocation)) - .findFirst() - .orElse(null); + return Main.pixelBlocks.stream() + .filter(block -> Objects.equals(block.pixelBlockLocation, searchLocation)) + .findFirst() + .orElse(null); } - public PixelBlock(Location originLocation, UUID ownerUUID, UUID blockUUID, Direction direction) { - PixelBlocksPlugin.pixelBlocks.add(this); + public static PixelBlock fromExisting(UUID blockUUID, UUID ownerUUID, Location pixelBlockLocation, Direction direction, Location lastEntryLocation) { + return new PixelBlock(blockUUID, ownerUUID, pixelBlockLocation, direction, lastEntryLocation); + } - this.ownerUUID = ownerUUID; + 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; + try { + this.pixelWorld = new PixelBlockWorld(this); + this.pixelData = this.pixelWorld.getPixels(this.facingDirection); + this.pixels = new Pixels(this); + this.placeholder = new PixelBlockPlaceholder(this); + this.hitbox = new PixelBlockHitbox(this); + + Main.logger().info(String.format("Loaded existing pixelblock '%s'", this.blockUUID)); + } catch(Exception e) { + Main.logger().info(String.format("Failed initializing existing pixelblock '%s': %s", this.blockUUID, e.getMessage())); + } + } + + 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.pixelWorld = new PixelBlockWorld(this); + this.getBlockTaskChain() + .sync(() -> { + this.pixelWorld = new PixelBlockWorld(this); + this.pixelData = this.pixelWorld.getPixels(this.facingDirection); + this.pixels = new Pixels(this); + this.placeholder = new PixelBlockPlaceholder(this); + this.hitbox = new PixelBlockHitbox(this); + }) + .execute(); + + this.scheduleEntityUpdate(); + + this.getBlockTaskChain() + .async(() -> { + Main.database().savePixelBlock(this); + Main.pixelBlocks.add(this); + }) + .execute(); + } + + public <T> TaskChain<T> getBlockTaskChain() { + return Main.sharedChain(this.blockUUID.toString()); } public void enterBlock(@NotNull Player player) { - if(PixelBlocksPlugin.configuration.onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) { - player.sendMessage("Dieser Pixelblock gehört nicht dir!"); + if(Main.configuration().onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) { + player.sendMessage(Component.text("Dieser Pixelblock gehört nicht dir!", NamedTextColor.RED)); return; } - this.lastEntryLocation = player.getLocation(); - this.lastEntryTime = System.currentTimeMillis(); - PixelBlocksPlugin.database.savePixelBlock(this); - - player.teleport(this.pixelWorld.getSpawnLocation()); + getBlockTaskChain() + .async(() -> { + this.lastEntryLocation = player.getLocation(); + Main.database().savePixelBlock(this); + }) + .sync(() -> { + if(!exists) return; + player.teleport(this.pixelWorld.getSpawnLocation()); + }) + .current(() -> Main.logger() + .info(String.format("'%s' entered PixelBlock '%s' at %s", player.getName(), this.blockUUID, this.pixelBlockLocation.toString()))) + .execute(); } - public void setLastEntryLocation(Location lastEntryLocation) { - this.lastEntryLocation = lastEntryLocation; + public void exitBlock(@NotNull Player player) { + this.getBlockTaskChain() + .sync(() -> player.teleport(this.lastEntryLocation != null ? this.lastEntryLocation : this.pixelBlockLocation)) + .sync(() -> this.pixelData = this.pixelWorld.getPixels(this.facingDirection)) + .current(() -> Main.logger().info(String.format("%s exited PixelBlock", player.getName()))) + .delay(1) + .execute(); + + this.scheduleEntityUpdate(); } - public void spawnInteraction(boolean fullBlock) { - if(fullBlock) { - hitbox = (Interaction) pixelBlockLocation.getWorld().spawnEntity( - pixelBlockLocation.clone().add(0.5, -hitboxOffset, 0.5), - EntityType.INTERACTION - ); - hitbox.setInteractionHeight(1 + 2*hitboxOffset); - hitbox.setInteractionWidth(1 + 2*hitboxOffset); - } else { - double startingX = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getX()); - double startingY = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getY()); - double startingZ = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getZ()); - - double endingX = MinMaxUtil.getMaxProperty(this.pixels, pixel -> pixel.relativeLocation.getX()); - double endingY = MinMaxUtil.getMaxProperty(this.pixels, pixel -> pixel.relativeLocation.getY()); - double endingZ = MinMaxUtil.getMaxProperty(this.pixels, pixel -> pixel.relativeLocation.getZ()); - - Location spawnLocation = pixelBlockLocation.clone().add( - ((startingX+endingX+1)/2)/pixelsPerBlock, - (startingY/pixelsPerBlock)-hitboxOffset, - ((startingZ+endingZ+1)/2)/pixelsPerBlock - ); - - float height = (float) (endingY-startingY+1)/pixelsPerBlock + 2*hitboxOffset; - - float width; - if((endingX-startingX) > (endingZ-startingZ)) { - width = (float) (endingX-startingX+1)/pixelsPerBlock + 2*hitboxOffset; - } else { - width = (float) (endingZ-startingZ+1)/pixelsPerBlock + 2*hitboxOffset; - } - - if(spawnLocation.getX()+width/2 > this.pixelBlockLocation.getX()+1) { - spawnLocation.subtract((spawnLocation.getX()+width/2)-(this.pixelBlockLocation.getX()+1), 0, 0); - } - if(spawnLocation.getX()-width/2 < this.pixelBlockLocation.getX()) { - spawnLocation.add(this.pixelBlockLocation.getX()-(spawnLocation.getX()-width/2), 0, 0); - } - - if(spawnLocation.getZ()+width/2 > this.pixelBlockLocation.getZ()+1) { - spawnLocation.subtract(0, 0, (spawnLocation.getZ()+width/2)-(this.pixelBlockLocation.getZ()+1)); - } - if(spawnLocation.getZ()-width/2 < this.pixelBlockLocation.getZ()) { - spawnLocation.add(0, 0, this.pixelBlockLocation.getZ()-(spawnLocation.getZ()-width/2)); - } - - hitbox = (Interaction) pixelBlockLocation.getWorld().spawnEntity( - spawnLocation, - EntityType.INTERACTION - ); - - hitbox.setInteractionHeight(height); - hitbox.setInteractionWidth(width); - } + private void scheduleEntityUpdate() { + this.getBlockTaskChain() + .sync(this::ensureChunksLoaded) + .sync(this::removeEntities) + .delay(1) + .async(() -> Collections.shuffle(this.pixelData)) + .delay(1) + .sync(this::ensureChunksLoaded) + .syncLast((pixelData) -> { + this.pixels.spawn(); + this.hitbox.spawn(); + this.placeholder.spawn(); + }) + .execute(); } - public void updateEntities() { - Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> { - this.clearEntities(); - - 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(pixelBlockLocation.getWorld(), 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() != Material.AIR) { - Pixel newPixel = new Pixel(relativeLocation, block, ((double) 1 /pixelsPerBlock)); - pixels.add(newPixel); - } - } - } - } - - for(Pixel pixel : this.pixels) { - pixel.place(this.pixelBlockLocation); - } - - if(this.pixels.size() < 5) { - Location relativeLocation = new Location(pixelBlockLocation.getWorld(), 0, 0, 0); - BlockData block = Material.GRAY_STAINED_GLASS.createBlockData(); - Pixel newPixel = new Pixel(relativeLocation, block, 1); - pixels.add(newPixel); - newPixel.place(this.pixelBlockLocation); - - Location itemDisplayLocation = this.pixelBlockLocation.clone().add(0.5, 0.5, 0.5); - this.barrier = (ItemDisplay) this.pixelBlockLocation.getWorld().spawnEntity( - itemDisplayLocation, - EntityType.ITEM_DISPLAY - ); - this.barrier.setItemStack(ItemStack.of(Material.BARRIER)); - - spawnInteraction(true); - } else { - spawnInteraction(false); - } - }); - } - - 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."); - - this.pixelBlockLocation = newLocation; - this.facingDirection = direction; - updateEntities(); - PixelBlocksPlugin.database.savePixelBlock(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.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) { - if(PixelBlocksPlugin.configuration.onlyBreakableByOwner() && !destroyedBy.getUniqueId().equals(ownerUUID)) { + if(!this.exists) return; + if(Main.configuration().onlyBreakableByOwner() && !destroyedBy.getUniqueId().equals(ownerUUID)) { destroyedBy.sendMessage("Dieser Pixelblock gehört nicht dir!"); return; } this.pixelWorld.getPlayersInWorld().forEach(p -> { - p.sendMessage("Der Pixelblock wurde von einem anderen Spieler abgebaut."); + p.sendMessage(Component.text("Der Pixelblock wurde von einem anderen Spieler abgebaut!", NamedTextColor.RED)); p.teleport(this.lastEntryLocation); }); + Main.logger().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(); - PixelBlocksPlugin.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.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)); + }) + .async(() -> { + Main.database().deletePixelBlock(this); + Main.pixelBlocks.remove(this); + }) + .execute(); } - private void clearEntities() { + private void removeEntities() { + this.ensureChunksLoaded(); + this.pixels.destroy(); + this.placeholder.destroy(); + this.hitbox.destroy(); + } + + private void ensureChunksLoaded() { Chunk chunk = this.pixelBlockLocation.getChunk(); - if(!chunk.isEntitiesLoaded()) { - chunk.load(true); + if(!chunk.isLoaded() || !chunk.isEntitiesLoaded()) { + Main.logger().info(String.format("Loading chunk '%d, %d' for pixelblock '%s'", chunk.getX(), chunk.getZ(), this.blockUUID)); + chunk.load(); chunk.getEntities(); } - - this.pixels.forEach(Pixel::destroy); - this.pixels.clear(); - - if(hitbox != null) { - this.hitbox.remove(); - this.hitbox = null; - } - - if(barrier != null) { - this.barrier.remove(); - this.barrier = null; - } - - this.pixelBlockLocation.getWorld().getEntities().stream() - .filter(this::isRelevantEntity) - .filter(entity -> entity.getLocation() - .add(0, hitboxOffset, 0) - .toBlockLocation() - .equals(this.pixelBlockLocation)) - .forEach(Entity::remove); } - private boolean isRelevantEntity(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; } - public int getPixelsPerBlock() { - return pixelsPerBlock; + public Location getPixelBlockLocation() { + return pixelBlockLocation.clone(); + } + + public Direction getFacingDirection() { + return facingDirection; + } + + public boolean hasLastEntryLocation() { + return this.lastEntryLocation != null; + } + + public List<PixelBlockWorld.PixelData> getPixelData() { + return pixelData; + } + + public Location getLastEntryLocation() { + return lastEntryLocation.clone(); + } + + public UUID getOwnerUUID() { + return ownerUUID; + } + + public UUID getBlockUUID() { + return blockUUID; } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockHitbox.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockHitbox.java new file mode 100644 index 0000000..5d9e522 --- /dev/null +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockHitbox.java @@ -0,0 +1,99 @@ +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; + +public class PixelBlockHitbox { + private static final NamespacedKey hitboxOfTag = new NamespacedKey(Main.plugin(), "hitbox_of"); + + private final PixelBlock parentBlock; + + public PixelBlockHitbox(PixelBlock parentBlock) { + this.parentBlock = parentBlock; + } + + public void spawn() { + Location absoluteLocation = this.parentBlock.getPixelBlockLocation(); + List<PixelBlockWorld.PixelData> pixels = this.parentBlock.getPixelData(); + int pixelsPerBlock = Main.configuration().pixelsPerBlock(); + + Interaction interaction; + if (pixels.size() <= 5) { + interaction = (Interaction) absoluteLocation.getWorld().spawnEntity( + absoluteLocation.clone().add(0.5, -0, 0.5), + EntityType.INTERACTION + ); + interaction.setInteractionHeight(1); + interaction.setInteractionWidth(1); + } else { + double startingX = MinMaxUtil.getMinProperty(pixels, pixel -> pixel.relativeLocation().getX()); + double startingY = MinMaxUtil.getMinProperty(pixels, pixel -> pixel.relativeLocation().getY()); + double startingZ = MinMaxUtil.getMinProperty(pixels, pixel -> pixel.relativeLocation().getZ()); + + double endingX = MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.relativeLocation().getX()); + double endingY = MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.relativeLocation().getY()); + double endingZ = MinMaxUtil.getMaxProperty(pixels, pixel -> pixel.relativeLocation().getZ()); + + Location spawnLocation = absoluteLocation.clone().add( + ((startingX+endingX)/2)/pixelsPerBlock, + (startingY/pixelsPerBlock)-0, + ((startingZ+endingZ)/2)/pixelsPerBlock + ); + + float height = (float) (endingY-startingY+1)/pixelsPerBlock; + + float width; + if((endingX-startingX) > (endingZ-startingZ)) { + width = (float) (endingX-startingX+1)/pixelsPerBlock; + } else { + width = (float) (endingZ-startingZ+1)/pixelsPerBlock; + } + + if(spawnLocation.getX()+width/2 > absoluteLocation.getX()+1) { + spawnLocation.subtract((spawnLocation.getX()+width/2)-(absoluteLocation.getX()+1), 0, 0); + } + if(spawnLocation.getX()-width/2 < absoluteLocation.getX()) { + spawnLocation.add(absoluteLocation.getX()-(spawnLocation.getX()-width/2), 0, 0); + } + + if(spawnLocation.getZ()+width/2 > absoluteLocation.getZ()+1) { + spawnLocation.subtract(0, 0, (spawnLocation.getZ()+width/2)-(absoluteLocation.getZ()+1)); + } + if(spawnLocation.getZ()-width/2 < absoluteLocation.getZ()) { + spawnLocation.add(0, 0, absoluteLocation.getZ()-(spawnLocation.getZ()-width/2)); + } + + interaction = (Interaction) absoluteLocation.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( + interaction.getPersistentDataContainer().get(hitboxOfTag, PersistentDataType.STRING), + parentBlock.getBlockUUID().toString() + )) + .forEach(Entity::remove); + } +} diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockInteraction.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockInteraction.java deleted file mode 100644 index 19a1863..0000000 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockInteraction.java +++ /dev/null @@ -1,5 +0,0 @@ -package eu.mhsl.minecraft.pixelblocks.pixelblock; - -public class PixelBlockInteraction { - -} diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockPlaceholder.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockPlaceholder.java new file mode 100644 index 0000000..dd35dad --- /dev/null +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockPlaceholder.java @@ -0,0 +1,86 @@ +package eu.mhsl.minecraft.pixelblocks.pixelblock; + +import eu.mhsl.minecraft.pixelblocks.Main; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.ItemDisplay; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataHolder; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.util.Transformation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +public class PixelBlockPlaceholder { + private static final NamespacedKey placeholderOfTag = new NamespacedKey(Main.plugin(), "placeholder_of"); + + private final PixelBlock parentBlock; + + public PixelBlockPlaceholder(PixelBlock parentBlock) { + this.parentBlock = parentBlock; + } + + public void spawn() { + if(parentBlock.getPixelData().size() > 5) return; + + List<ItemDisplay> placeholders = new ArrayList<>(); + Location pixelBlockLocation = parentBlock.getPixelBlockLocation(); + UUID parentBlockUUID = parentBlock.getBlockUUID(); + + World pixelBlockWorld = pixelBlockLocation.getWorld(); + Location itemDisplayLocation = pixelBlockLocation.add(0.5, 0.5, 0.5); + + for(int i = 0; i <= 90; i += 90) { + ItemDisplay verticalCore = (ItemDisplay) pixelBlockWorld.spawnEntity( + itemDisplayLocation, + EntityType.ITEM_DISPLAY + ); + verticalCore.setRotation(i, 0); + placeholders.add(verticalCore); + } + + ItemDisplay horizontalCore = (ItemDisplay) pixelBlockWorld.spawnEntity( + itemDisplayLocation, + EntityType.ITEM_DISPLAY + ); + horizontalCore.setRotation(0, 90); + placeholders.add(horizontalCore); + + placeholders.forEach(coreDisplay -> { + coreDisplay.setItemStack(ItemStack.of(Material.END_CRYSTAL)); + Transformation transform = coreDisplay.getTransformation(); + transform.getScale().set(0.5); + coreDisplay.setTransformation(transform); + }); + + ItemDisplay displayContainer = (ItemDisplay) pixelBlockWorld.spawnEntity( + itemDisplayLocation, + EntityType.ITEM_DISPLAY + ); + displayContainer.setItemStack(ItemStack.of(Material.WHITE_STAINED_GLASS)); + placeholders.add(displayContainer); + + placeholders.stream() + .map(PersistentDataHolder::getPersistentDataContainer) + .forEach(container -> container.set(placeholderOfTag, PersistentDataType.STRING, parentBlockUUID.toString())); + } + + public void destroy() { + 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 4f34c22..4521494 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockWorld.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/pixelblock/PixelBlockWorld.java @@ -1,29 +1,31 @@ package eu.mhsl.minecraft.pixelblocks.pixelblock; -import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin; +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; -import static eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin.plugin; - public class PixelBlockWorld { private final PixelBlock parentPixelBlock; private final World world; int worldGrassBorderWidth = 10; - int pixelsPerBlock = PixelBlocksPlugin.configuration.pixelsPerBlock(); + int pixelsPerBlock = Main.configuration().pixelsPerBlock(); public static boolean isPixelWorld(@NotNull World world) { - return world.getName().startsWith(plugin.getDataFolder().getPath()); + return world.getName().startsWith(Main.plugin().getDataFolder().getPath()); } public static @NotNull List<World> getOtherWorlds() { @@ -44,12 +46,12 @@ public class PixelBlockWorld { Location origin = getBuildOrigin(); int offset = pixelsPerBlock - 1; return blockLocation.x() >= origin.x() && blockLocation.x() <= origin.x() + offset - && blockLocation.z() >= origin.z() && blockLocation.z() <= origin.z() + offset - && blockLocation.y() >= origin.y() && blockLocation.y() <= origin.y() + offset; + && blockLocation.z() >= origin.z() && blockLocation.z() <= origin.z() + offset + && blockLocation.y() >= origin.y() && blockLocation.y() <= origin.y() + offset; } public @NotNull String getWorldPathName() { - return PixelBlocksPlugin.plugin.getDataFolder().getPath() + File.separator + "worlds" + File.separator + this.parentPixelBlock.blockUUID; + return Main.plugin().getDataFolder().getPath() + File.separator + "worlds" + File.separator + this.parentPixelBlock.getBlockUUID(); } public @NotNull Location getSpawnLocation() { @@ -57,7 +59,7 @@ public class PixelBlockWorld { } public @NotNull Location getPortalLocation() { - return this.getBuildOrigin().add((double) pixelsPerBlock/2 -2, 0, -worldGrassBorderWidth+3); + return this.getBuildOrigin().add((double) pixelsPerBlock / 2 - 2, 0, -worldGrassBorderWidth + 3); } public @NotNull List<Player> getPlayersInWorld() { @@ -88,11 +90,46 @@ public class PixelBlockWorld { return getBorderOrigin().add(worldGrassBorderWidth + pixelsPerBlock, 0, worldGrassBorderWidth + pixelsPerBlock); } + public record PixelData(Vector relativeLocation, BlockData block, double scale) { + } + + public List<PixelData> getPixels(Direction direction) { + List<PixelData> 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()); worldCreator.type(WorldType.FLAT); - worldCreator.generator(new ChunkGenerator() {}); + worldCreator.generator(new ChunkGenerator() { + }); World world = Bukkit.createWorld(worldCreator); Objects.requireNonNull(world); @@ -107,32 +144,32 @@ public class PixelBlockWorld { WorldBorder worldBorder = world.getWorldBorder(); worldBorder.setCenter(getBuildOrigin().add((double) pixelsPerBlock / 2, 0, (double) pixelsPerBlock / 2)); - worldBorder.setSize(pixelsPerBlock + (2*worldGrassBorderWidth)); + worldBorder.setSize(pixelsPerBlock + (2 * worldGrassBorderWidth)); worldBorder.setWarningDistance(0); worldBorder.setDamageAmount(0); return world; } private void setBuildingPlatform() { - Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> { - for (int x = 0; x < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; x++) { - for (int z = 0; z < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; z++) { + Bukkit.getScheduler().runTask(Main.plugin(), () -> { + for(int x = 0; x < (pixelsPerBlock + 2) + 2 * worldGrassBorderWidth; x++) { + for(int z = 0; z < (pixelsPerBlock + 2) + 2 * worldGrassBorderWidth; z++) { getPlatformOrigin().add(x, 0, z).getBlock().setType(Material.GRASS_BLOCK); } } - for (int x = 0; x < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; x++) { - for (int z = 0; z < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; z++) { + for(int x = 0; x < (pixelsPerBlock + 2) + 2 * worldGrassBorderWidth; x++) { + for(int z = 0; z < (pixelsPerBlock + 2) + 2 * worldGrassBorderWidth; z++) { getPlatformOrigin().add(x, -1, z).getBlock().setType(Material.DIRT); } } - for (int x = 0; x < (pixelsPerBlock+2); x++) { - for (int z = 0; z < (pixelsPerBlock+2); z++) { + for(int x = 0; x < (pixelsPerBlock + 2); x++) { + for(int z = 0; z < (pixelsPerBlock + 2); z++) { Location currentLocation = getBorderOrigin().add(x, 0, z); - if (currentLocation.x() == getBorderOrigin().x() || currentLocation.z() == getBorderOrigin().z()) { + if(currentLocation.x() == getBorderOrigin().x() || currentLocation.z() == getBorderOrigin().z()) { currentLocation.getBlock().setType(Material.RED_CONCRETE); - } else if (currentLocation.x() == getBorderOrigin().x() + (pixelsPerBlock+1) || currentLocation.z() == getBorderOrigin().z() + (pixelsPerBlock+1)) { + } else if(currentLocation.x() == getBorderOrigin().x() + (pixelsPerBlock + 1) || currentLocation.z() == getBorderOrigin().z() + (pixelsPerBlock + 1)) { currentLocation.getBlock().setType(Material.RED_CONCRETE); } } @@ -140,36 +177,39 @@ public class PixelBlockWorld { Random random = new Random(); LocationUtil.iterateBlocks(getPlatformOrigin().add(1, 1, 1), getPlatformOriginEnd().add(0, 1, 0), location -> { - if (allowPlacements(location)) return; - if (!location.clone().subtract(0, 1, 0).getBlock().getType().equals(Material.GRASS_BLOCK)) return; - if (!location.getBlock().getType().equals(Material.AIR)) return; + if(allowPlacements(location)) return; + if(!location.clone().subtract(0, 1, 0).getBlock().getType().equals(Material.GRASS_BLOCK)) return; - if (random.nextInt(10) == 0) { - Material[] flowers = { - Material.DANDELION, - Material.POPPY, - Material.BLUE_ORCHID, - Material.ALLIUM, - Material.AZURE_BLUET, - Material.RED_TULIP, - Material.ORANGE_TULIP, - Material.WHITE_TULIP, - Material.CORNFLOWER, - Material.LILY_OF_THE_VALLEY, - }; + List<Material> flowers = List.of( + Material.DANDELION, + Material.POPPY, + Material.BLUE_ORCHID, + Material.ALLIUM, + Material.AZURE_BLUET, + Material.RED_TULIP, + Material.ORANGE_TULIP, + Material.WHITE_TULIP, + Material.CORNFLOWER, + Material.LILY_OF_THE_VALLEY, + Material.SHORT_GRASS, + Material.TALL_GRASS + ); + if(flowers.contains(location.getBlock().getType())) location.getBlock().setType(Material.AIR); + if(!location.getBlock().getType().equals(Material.AIR)) return; - Material randomFlower = flowers[random.nextInt(flowers.length)]; + if(random.nextInt(30) == 0) { + Material randomFlower = flowers.get(random.nextInt(flowers.size())); location.getBlock().setType(randomFlower); } }); - for (int x = 0; x < 4; x++) { - for (int y = 0; y < 5; y++) { + for(int x = 0; x < 4; x++) { + for(int y = 0; y < 5; y++) { getPortalLocation().add(x, y, 0).getBlock().setType(Material.OBSIDIAN); } } - for (int x = 1; x < 3; x++) { - for (int y = 1; y < 4; y++) { + for(int x = 1; x < 3; x++) { + for(int y = 1; y < 4; y++) { getPortalLocation().add(x, y, 0).getBlock().setType(Material.NETHER_PORTAL); } } 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..32d6501 --- /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<BlockDisplay> 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 <T> List<List<T>> splitListInParts(int parts, List<T> 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(); + } + +} diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/LocationUtil.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/LocationUtil.java index 83bc1f1..990ea31 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/LocationUtil.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/LocationUtil.java @@ -7,7 +7,7 @@ import java.util.function.Consumer; public class LocationUtil { public static void iterateBlocks(Location loc1, Location loc2, Consumer<Location> action) { - if (loc1.getWorld() != loc2.getWorld()) { + if(loc1.getWorld() != loc2.getWorld()) { throw new IllegalArgumentException("Locations must be in the same world"); } @@ -19,9 +19,9 @@ public class LocationUtil { int minZ = Math.min(loc1.getBlockZ(), loc2.getBlockZ()); int maxZ = Math.max(loc1.getBlockZ(), loc2.getBlockZ()); - for (int x = minX; x <= maxX; x++) { - for (int y = minY; y <= maxY; y++) { - for (int z = minZ; z <= maxZ; z++) { + for(int x = minX; x <= maxX; x++) { + for(int y = minY; y <= maxY; y++) { + for(int z = minZ; z <= maxZ; z++) { action.accept(new Location(world, x, y, z)); } } diff --git a/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/MinMaxUtil.java b/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/MinMaxUtil.java index 861752e..f7ef999 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/MinMaxUtil.java +++ b/src/main/java/eu/mhsl/minecraft/pixelblocks/utils/MinMaxUtil.java @@ -8,6 +8,7 @@ public class MinMaxUtil { public static <I, O extends Comparable<O>> O getMinProperty(List<I> list, Function<I, O> supplier) { return supplier.apply(list.stream().min(Comparator.comparing(supplier)).orElseThrow()); } + public static <I, O extends Comparable<O>> O getMaxProperty(List<I> list, Function<I, O> supplier) { return supplier.apply(list.stream().max(Comparator.comparing(supplier)).orElseThrow()); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 3ec46db..0f5cb33 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: PixelBlocks version: '${version}' -main: eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin +main: eu.mhsl.minecraft.pixelblocks.Main api-version: '1.21' commands: createpixelblock: