Compare commits

..

No commits in common. "88b55d4d7cef8783e4a6cd576a78c473191c5542" and "e35145f8ed68ffd348915a5f92990d5a38335e4f" have entirely different histories.

38 changed files with 595 additions and 870 deletions

View File

@ -26,15 +26,5 @@
<option name="name" value="sonatype" /> <option name="name" value="sonatype" />
<option name="url" value="https://oss.sonatype.org/content/groups/public/" /> <option name="url" value="https://oss.sonatype.org/content/groups/public/" />
</remote-repository> </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> </component>
</project> </project>

1
.idea/modules.xml generated
View File

@ -4,7 +4,6 @@
<modules> <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/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/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" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/projects.PixelBlocks.main.iml" filepath="$PROJECT_DIR$/.idea/modules/projects.PixelBlocks.main.iml" />
</modules> </modules>
</component> </component>

View File

@ -1,13 +0,0 @@
<?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>

View File

@ -1,6 +1,5 @@
plugins { plugins {
id 'java' id 'java'
id 'com.gradleup.shadow' version '8.3.1'
} }
group = 'eu.mhsl.minecraft' group = 'eu.mhsl.minecraft'
@ -16,14 +15,10 @@ repositories {
name = "sonatype" name = "sonatype"
url = "https://oss.sonatype.org/content/groups/public/" url = "https://oss.sonatype.org/content/groups/public/"
} }
maven {
url = "https://repo.aikar.co/content/groups/aikar/"
}
} }
dependencies { dependencies {
compileOnly "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT" compileOnly "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT"
implementation "co.aikar:taskchain-bukkit:3.7.2"
} }
def targetJavaVersion = 21 def targetJavaVersion = 21
@ -36,6 +31,14 @@ java {
} }
} }
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
options.release.set(targetJavaVersion)
}
}
processResources { processResources {
def props = [version: version] def props = [version: version]
inputs.properties props inputs.properties props
@ -46,12 +49,8 @@ processResources {
} }
tasks.register('copyJarToTestServer', Exec) { tasks.register('copyJarToTestServer', Exec) {
commandLine 'cp', 'build/libs/PixelBlocks-1.0-SNAPSHOT-all.jar', '/home/elias/Dokumente/mcTestServer/plugins/pixelblocks.jar' dependsOn jar
} mustRunAfter jar
shadowJar { commandLine 'cp', 'build/libs/PixelBlocks-1.0-SNAPSHOT.jar', '/home/elias/Dokumente/mcTestServer/plugins/pixelblocks.jar'
relocate 'co.aikar.taskchain', 'eu.mhsl.minecraft.pixelblocks.taskchain'
} }
jar.dependsOn shadowJar
copyJarToTestServer.dependsOn jar

View File

@ -5,11 +5,13 @@ import org.jetbrains.annotations.NotNull;
public record PixelBlockConfiguration( public record PixelBlockConfiguration(
int pixelsPerBlock, int pixelsPerBlock,
double hitboxOffset,
boolean onlyBreakableByOwner, boolean onlyBreakableByOwner,
boolean onlyEditableByOwner boolean onlyEditableByOwner
) { ) {
public static void setDefaults(FileConfiguration config) { public static void setDefaults(FileConfiguration config) {
config.addDefault(Keys.PixelsPerBlock.key, 16); config.addDefault(Keys.PixelsPerBlock.key, 16);
config.addDefault(Keys.HitboxOffset.key, 0.005);
config.addDefault(Keys.OnlyBreakableByOwners.key, false); config.addDefault(Keys.OnlyBreakableByOwners.key, false);
config.addDefault(Keys.OnlyEditableByOwners.key, true); config.addDefault(Keys.OnlyEditableByOwners.key, true);
config.options().copyDefaults(true); config.options().copyDefaults(true);
@ -17,11 +19,11 @@ public record PixelBlockConfiguration(
public enum Keys { public enum Keys {
PixelsPerBlock("pixelsPerBlock"), PixelsPerBlock("pixelsPerBlock"),
HitboxOffset("hitboxOffset"),
OnlyBreakableByOwners("onlyBreakableByOwners"), OnlyBreakableByOwners("onlyBreakableByOwners"),
OnlyEditableByOwners("onlyEditableByOwners"); OnlyEditableByOwners("onlyEditableByOwners");
private final String key; private final String key;
Keys(@NotNull String key) { Keys(@NotNull String key) {
this.key = key; this.key = key;
} }

View File

@ -1,11 +1,13 @@
package eu.mhsl.minecraft.pixelblocks; package eu.mhsl.minecraft.pixelblocks;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import eu.mhsl.minecraft.pixelblocks.utils.Direction; import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import java.sql.*; import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public class PixelBlockDatabase { public class PixelBlockDatabase {
@ -13,7 +15,9 @@ public class PixelBlockDatabase {
private final PreparedStatement getAllPixelBlocks; private final PreparedStatement getAllPixelBlocks;
private final PreparedStatement deletePixelBlock; private final PreparedStatement deletePixelBlock;
private final PreparedStatement insertOrReplacePixelBlock; private final PreparedStatement insertNewPixelBlock;
private final PreparedStatement updateExistingPixelBlock;
public PixelBlockDatabase(String url) { public PixelBlockDatabase(String url) {
try { try {
@ -38,64 +42,117 @@ public class PixelBlockDatabase {
this.deletePixelBlock = this.db.prepareStatement("DELETE FROM pixelblocks WHERE uuid = ?"); this.deletePixelBlock = this.db.prepareStatement("DELETE FROM pixelblocks WHERE uuid = ?");
this.getAllPixelBlocks = this.db.prepareStatement("SELECT * FROM pixelblocks"); this.getAllPixelBlocks = this.db.prepareStatement("SELECT * FROM pixelblocks");
this.insertOrReplacePixelBlock = this.db.prepareStatement( this.insertNewPixelBlock = this.db.prepareStatement(
"INSERT OR REPLACE INTO pixelblocks(uuid, owner, " + "INSERT INTO pixelblocks(uuid, owner, " +
"locationWorldName, locationX, locationY, locationZ, " + "locationWorldName, locationX, locationY, locationZ, " +
"entryLocationWorldName, entryLocationX, entryLocationY, entryLocationZ, direction) " + "entryLocationWorldName, entryLocationX, entryLocationY, entryLocationZ, direction) " +
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" "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) { } catch (SQLException | RuntimeException | ClassNotFoundException e) {
throw new RuntimeException("Error while initializing database", e); throw new RuntimeException("Failed to load Database", e);
} }
} }
public void close() throws SQLException { public void close() throws SQLException {
deletePixelBlock.close(); deletePixelBlock.close();
getAllPixelBlocks.close(); getAllPixelBlocks.close();
insertOrReplacePixelBlock.close(); insertNewPixelBlock.close();
updateExistingPixelBlock.close();
db.close(); db.close();
} }
public void deletePixelBlock(PixelBlock pixelBlock) { public void deletePixelBlock(PixelBlock pixelBlock) {
Bukkit.getScheduler().runTaskAsynchronously(Main.plugin(), () -> { Bukkit.getScheduler().runTaskAsynchronously(PixelBlocksPlugin.plugin, () -> {
try { try {
this.deletePixelBlock.setString(1, pixelBlock.getBlockUUID().toString()); this.deletePixelBlock.setString(1, pixelBlock.blockUUID.toString());
this.deletePixelBlock.executeUpdate(); this.deletePixelBlock.executeUpdate();
PixelBlocksPlugin.plugin.getLogger().info("DB: Deleted PixelBlock: " + pixelBlock.blockUUID);
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException("Failed to delete PixelBlock from the database", e); throw new RuntimeException("Failed to delete PixelBlock", e);
} }
}); });
} }
public void savePixelBlock(PixelBlock pixelBlock) { public void savePixelBlock(PixelBlock pixelBlock) {
Bukkit.getScheduler().runTask(Main.plugin(), () -> { Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> {
List<UUID> storedPixelBlocks = new ArrayList<>();
try { try {
this.insertOrReplacePixelBlock.setString(1, pixelBlock.getBlockUUID().toString()); ResultSet pixelBlocksResult = this.getAllPixelBlocks.executeQuery();
this.insertOrReplacePixelBlock.setString(2, pixelBlock.getOwnerUUID().toString()); while (pixelBlocksResult.next()) {
storedPixelBlocks.add(UUID.fromString(pixelBlocksResult.getString("uuid")));
this.insertOrReplacePixelBlock.setString(3, pixelBlock.getPixelBlockLocation().getWorld().getName()); }
this.insertOrReplacePixelBlock.setDouble(4, pixelBlock.getPixelBlockLocation().getX()); } catch (SQLException e) {
this.insertOrReplacePixelBlock.setDouble(5, pixelBlock.getPixelBlockLocation().getY()); throw new RuntimeException("Failed to fetch PixelBlock list", e);
this.insertOrReplacePixelBlock.setDouble(6, pixelBlock.getPixelBlockLocation().getZ());
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());
} }
this.insertOrReplacePixelBlock.setString(11, pixelBlock.getFacingDirection().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.executeUpdate(); 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) { } catch (SQLException e) {
throw new RuntimeException("Failed to create or update PixelBlock in the database", e); throw new RuntimeException("Failed to save PixelBlock", e);
}
} else {
// update existing entry
try {
this.updateExistingPixelBlock.setString(1, pixelBlock.ownerUUID.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);
}
} }
}); });
} }
@ -119,16 +176,17 @@ public class PixelBlockDatabase {
allPixelBlocks.getDouble("entryLocationZ") allPixelBlocks.getDouble("entryLocationZ")
); );
Main.pixelBlocks.add(PixelBlock.fromExisting( PixelBlock block = new PixelBlock(
UUID.fromString(allPixelBlocks.getString("uuid")),
UUID.fromString(allPixelBlocks.getString("owner")),
blockLocation, blockLocation,
Direction.valueOf(allPixelBlocks.getString("direction")), UUID.fromString(allPixelBlocks.getString("owner")),
entryLocation UUID.fromString(allPixelBlocks.getString("uuid")),
)); Direction.valueOf(allPixelBlocks.getString("direction"))
);
block.setLastEntryLocation(entryLocation);
PixelBlocksPlugin.plugin.getLogger().info("DB: Loaded PixelBlock: " + block.blockUUID);
} }
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException("Failed loading PixelBlocks from the database", e); throw new RuntimeException("Failed loading PixelBlocks", e);
} }
} }
} }

View File

@ -11,53 +11,30 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe; import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta; 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.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public class PixelBlockItem { public class PixelBlockItem {
public static final NamespacedKey recipeKey = new NamespacedKey(Main.plugin(), "pixelblock"); public static UUID unusedBlockID = UUID.fromString("98fdf0ae-c3ab-4ef7-ae25-efd518d600de");
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 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) { public static @NotNull ItemStack getBlockAsItem(@NotNull PixelBlock block) {
String ownerName = Optional.ofNullable(Bukkit.getOfflinePlayer(block.getOwnerUUID()).getName()).orElseGet(() -> block.getOwnerUUID().toString()); String ownerName = Optional.ofNullable(Bukkit.getOfflinePlayer(block.ownerUUID).getName()).orElseGet(() -> block.ownerUUID.toString());
ItemStack itemStack = HeadUtil.getCustomTextureHead(itemTexture); ItemStack itemStack = HeadUtil.getCustomTextureHead(itemTexture);
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
meta.setMaxStackSize(1); meta.itemName(Component.text(block.blockUUID.toString()));
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.displayName(Component.text("Pixelblock von " + ownerName));
meta.lore(List.of( meta.lore(List.of(
Component.text(ownerName + " ist der Besitzer dieses Blocks."), Component.text(ownerName + " ist der Besitzer dieses Blocks."),
Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!"), Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!"),
Component.text(block.getBlockUUID().toString()).color(NamedTextColor.DARK_GRAY) Component.text(block.blockUUID.toString()).color(NamedTextColor.DARK_GRAY)
)); ));
meta.setEnchantmentGlintOverride(true);
itemStack.setItemMeta(meta); itemStack.setItemMeta(meta);
return itemStack; return itemStack;
@ -66,13 +43,13 @@ public class PixelBlockItem {
public static @NotNull ItemStack getEmptyPixelBlock() { public static @NotNull ItemStack getEmptyPixelBlock() {
ItemStack item = HeadUtil.getCustomTextureHead(itemTexture); ItemStack item = HeadUtil.getCustomTextureHead(itemTexture);
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
meta.setMaxStackSize(1);
meta.displayName(Component.text("Leerer Pixelblock")); meta.displayName(Component.text("Leerer Pixelblock"));
meta.lore(List.of( meta.lore(List.of(
Component.text("Der erste Spieler, der den Block platziert wird zum Besitzer des Blocks."), Component.text("Der erste Spieler, der den Block platziert wird zum Besitzer des Blocks."),
Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!") Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!")
)); ));
meta.getPersistentDataContainer().set(idProperty, PersistentDataType.STRING, UUID.randomUUID().toString()); meta.setEnchantmentGlintOverride(true);
meta.itemName(Component.text(unusedBlockID.toString()));
item.setItemMeta(meta); item.setItemMeta(meta);
return item; return item;
} }
@ -84,7 +61,7 @@ public class PixelBlockItem {
recipe.setIngredient('B', Material.DIAMOND_BLOCK); recipe.setIngredient('B', Material.DIAMOND_BLOCK);
recipe.setIngredient('C', Material.HEART_OF_THE_SEA); recipe.setIngredient('C', Material.HEART_OF_THE_SEA);
recipe.setIngredient('D', Material.GRASS_BLOCK); recipe.setIngredient('D', Material.GRASS_BLOCK);
recipe.setIngredient('E', Material.END_CRYSTAL); recipe.setIngredient('E', Material.GLOW_BERRIES);
return recipe; return recipe;
} }
} }

View File

@ -1,8 +1,5 @@
package eu.mhsl.minecraft.pixelblocks; 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.CreatePixelBlockCommand;
import eu.mhsl.minecraft.pixelblocks.commands.ExitWorldCommand; import eu.mhsl.minecraft.pixelblocks.commands.ExitWorldCommand;
import eu.mhsl.minecraft.pixelblocks.listeners.*; import eu.mhsl.minecraft.pixelblocks.listeners.*;
@ -17,45 +14,36 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.logging.Logger;
public final class Main extends JavaPlugin { public final class PixelBlocksPlugin extends JavaPlugin {
private static Main plugin; public static PixelBlocksPlugin plugin;
private static PixelBlockConfiguration configuration; public static PixelBlockConfiguration configuration;
private static PixelBlockDatabase database; public static PixelBlockDatabase database;
private static TaskChainFactory taskFactory; public static List<PixelBlock> pixelBlocks = new ArrayList<>();
public final static List<PixelBlock> pixelBlocks = new ArrayList<>();
public static <T> TaskChain<T> sharedChain(String name) {
return taskFactory.newSharedChain(name);
}
@Override @Override
public void onLoad() { public void onLoad() {
Main.plugin = this; PixelBlocksPlugin.plugin = this;
FileConfiguration config = this.getConfig(); FileConfiguration config = this.getConfig();
PixelBlockConfiguration.setDefaults(config); PixelBlockConfiguration.setDefaults(config);
this.saveConfig(); this.saveConfig();
Main.configuration = new PixelBlockConfiguration( PixelBlocksPlugin.configuration = new PixelBlockConfiguration(
config.getInt(PixelBlockConfiguration.Keys.PixelsPerBlock.getKey()), config.getInt(PixelBlockConfiguration.Keys.PixelsPerBlock.getKey()),
config.getDouble(PixelBlockConfiguration.Keys.HitboxOffset.getKey()),
config.getBoolean(PixelBlockConfiguration.Keys.OnlyBreakableByOwners.getKey()), config.getBoolean(PixelBlockConfiguration.Keys.OnlyBreakableByOwners.getKey()),
config.getBoolean(PixelBlockConfiguration.Keys.OnlyEditableByOwners.getKey()) config.getBoolean(PixelBlockConfiguration.Keys.OnlyEditableByOwners.getKey())
); );
File databaseFile = new File(plugin.getDataFolder(), "blocks.db"); File databaseFile = new File(plugin.getDataFolder(), "blocks.db");
Main.database = new PixelBlockDatabase("jdbc:sqlite:" + databaseFile); PixelBlocksPlugin.database = new PixelBlockDatabase("jdbc:sqlite:" + databaseFile);
} }
@Override @Override
public void onEnable() { public void onEnable() {
Main.taskFactory = BukkitTaskChainFactory.create(this);
getLogger().info("Start constructing blocks from Database...");
database.loadPixelBlocks(); database.loadPixelBlocks();
getLogger().info("Construction done!");
Listener[] listeners = { Listener[] listeners = {
new EnterPixelBlockListener(), new EnterPixelBlockListener(),
@ -64,6 +52,7 @@ public final class Main extends JavaPlugin {
new PlacePixelBlockListener(), new PlacePixelBlockListener(),
new PreventInventorysListener(), new PreventInventorysListener(),
new ExitPixelWorldListener(), new ExitPixelWorldListener(),
new CraftPixelBlockListener(),
new PreventIllegalBlocksListener(), new PreventIllegalBlocksListener(),
new BreakPixelBlockListener(), new BreakPixelBlockListener(),
new PlacePixelListener(), new PlacePixelListener(),
@ -71,9 +60,7 @@ public final class Main extends JavaPlugin {
new PreventLiquidsFlowListener(), new PreventLiquidsFlowListener(),
new PreventPistonsListener(), new PreventPistonsListener(),
new PreventEntityPlacementListener(), new PreventEntityPlacementListener(),
new DiscoverRecipesListener(), new DiscoverRecipesListener()
new QuitWhileInPixelBlockListener(),
new PreventGrowthListener()
}; };
for (Listener listener : listeners) { for (Listener listener : listeners) {
@ -88,27 +75,10 @@ public final class Main extends JavaPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
Bukkit.getOnlinePlayers().forEach(QuitWhileInPixelBlockListener::kickPlayerOutOfWorld);
try { try {
database.close(); database.close();
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException("Failed disabling", 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;
}
} }

View File

@ -1,8 +1,8 @@
package eu.mhsl.minecraft.pixelblocks.commands; 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.pixelblock.PixelBlockWorld;
import eu.mhsl.minecraft.pixelblocks.utils.Direction; import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -24,12 +24,13 @@ public class CreatePixelBlockCommand implements CommandExecutor {
} }
Location playerLocation = p.getLocation(); Location playerLocation = p.getLocation();
PixelBlock.createPixelBlock( PixelBlock block = new PixelBlock(
UUID.randomUUID(), playerLocation,
p.getUniqueId(), p.getUniqueId(),
playerLocation.toBlockLocation(), UUID.randomUUID(),
Direction.south Direction.south
); );
block.place(playerLocation, Direction.south);
} }
return true; return true;
} }

View File

@ -9,7 +9,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects; import java.util.*;
public class ExitWorldCommand implements CommandExecutor { public class ExitWorldCommand implements CommandExecutor {
@Override @Override
@ -23,7 +23,7 @@ public class ExitWorldCommand implements CommandExecutor {
PixelBlock currentPixelBlock = PixelBlock.getPixelBlockFromBlockWorld(playerWorld); PixelBlock currentPixelBlock = PixelBlock.getPixelBlockFromBlockWorld(playerWorld);
Objects.requireNonNull(currentPixelBlock); Objects.requireNonNull(currentPixelBlock);
currentPixelBlock.exitBlock(p); p.teleport(currentPixelBlock.lastEntryLocation);
} }
return true; return true;
} }

View File

@ -1,5 +1,6 @@
package eu.mhsl.minecraft.pixelblocks.listeners; package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import io.papermc.paper.event.player.PrePlayerAttackEntityEvent; import io.papermc.paper.event.player.PrePlayerAttackEntityEvent;
import org.bukkit.Location; import org.bukkit.Location;
@ -9,10 +10,10 @@ import org.bukkit.event.Listener;
public class BreakPixelBlockListener implements Listener { public class BreakPixelBlockListener implements Listener {
@EventHandler @EventHandler
public void destroyPixelBlock(PrePlayerAttackEntityEvent event) { static void destroyPixelBlock(PrePlayerAttackEntityEvent event) {
if(!(event.getAttacked() instanceof Interaction)) return; if(!(event.getAttacked() instanceof Interaction)) return;
Location blockLocation = event.getAttacked().getLocation().toBlockLocation(); Location blockLocation = event.getAttacked().getLocation().add(0, PixelBlocksPlugin.configuration.hitboxOffset(), 0).toBlockLocation();
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromPlacedLocation(blockLocation); PixelBlock pixelBlock = PixelBlock.getPixelBlockFromPlacedLocation(blockLocation);
if(pixelBlock == null) return; if(pixelBlock == null) return;
pixelBlock.destroy(event.getPlayer()); pixelBlock.destroy(event.getPlayer());

View File

@ -7,7 +7,7 @@ import org.bukkit.event.block.BlockBreakEvent;
public class BreakPixelListener implements Listener { public class BreakPixelListener implements Listener {
@EventHandler @EventHandler
public void onBlockBreak(BlockBreakEvent event) { static void onBlockBreak(BlockBreakEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getBlock().getWorld(), event.getBlock().getWorld(),

View File

@ -0,0 +1,25 @@
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);
}
}

View File

@ -1,12 +1,12 @@
package eu.mhsl.minecraft.pixelblocks.listeners; package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.Main;
import eu.mhsl.minecraft.pixelblocks.PixelBlockItem; import eu.mhsl.minecraft.pixelblocks.PixelBlockItem;
import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.*;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.util.List; import java.util.List;
@ -17,10 +17,10 @@ public class DiscoverRecipesListener implements Listener {
public void shouldDiscover(InventoryClickEvent event) { public void shouldDiscover(InventoryClickEvent event) {
ItemStack clickedItem = event.getCurrentItem(); ItemStack clickedItem = event.getCurrentItem();
if(clickedItem == null) return; 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(!(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; if(player.hasDiscoveredRecipe(PixelBlockItem.recipeKey)) return;
Main.logger().log(Level.INFO, String.format("%s unlocked tne PixelBlock recipe!", player.getName())); PixelBlocksPlugin.plugin.getLogger().log(Level.INFO, String.format("%s unlocked tne PixelBlock recipe!", player.getName()));
player.discoverRecipe(PixelBlockItem.recipeKey); player.discoverRecipe(PixelBlockItem.recipeKey);
} }
} }

View File

@ -1,7 +1,8 @@
package eu.mhsl.minecraft.pixelblocks.listeners; package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.Location; import org.bukkit.*;
import org.bukkit.entity.Interaction; import org.bukkit.entity.Interaction;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -9,12 +10,13 @@ import org.bukkit.event.player.PlayerInteractEntityEvent;
public class EnterPixelBlockListener implements Listener { public class EnterPixelBlockListener implements Listener {
@EventHandler @EventHandler
public void enterPixelBlock(PlayerInteractEntityEvent event) { static void enterPixelBlock(PlayerInteractEntityEvent event) {
if(!(event.getRightClicked() instanceof Interaction)) return; if(!(event.getRightClicked() instanceof Interaction)) return;
Location interactionLocation = event Location interactionLocation = event
.getRightClicked() .getRightClicked()
.getLocation() .getLocation()
.add(0, PixelBlocksPlugin.configuration.hitboxOffset(), 0)
.toBlockLocation(); .toBlockLocation();
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromPlacedLocation(interactionLocation); PixelBlock pixelBlock = PixelBlock.getPixelBlockFromPlacedLocation(interactionLocation);
if(pixelBlock == null) return; if(pixelBlock == null) return;

View File

@ -5,19 +5,31 @@ import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.event.player.PlayerPortalEvent;
import java.util.Objects; import java.util.Objects;
public class ExitPixelWorldListener implements Listener { public class ExitPixelWorldListener implements Listener {
@EventHandler @EventHandler
public void onPlayerPortal(PlayerPortalEvent event) { 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) {
World pixelBlockWorld = event.getFrom().getWorld(); World pixelBlockWorld = event.getFrom().getWorld();
if(!PixelBlockWorld.isPixelWorld(pixelBlockWorld)) return; if(!PixelBlockWorld.isPixelWorld(pixelBlockWorld)) return;
event.setCancelled(true); event.setCancelled(true);
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(pixelBlockWorld); PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(pixelBlockWorld);
Objects.requireNonNull(pixelBlock); Objects.requireNonNull(pixelBlock);
pixelBlock.exitBlock(event.getPlayer()); event.getPlayer().teleport(pixelBlock.lastEntryLocation);
} }
} }

View File

@ -11,7 +11,7 @@ import java.util.Objects;
public class FallOutOfPixelBlockListener implements Listener { public class FallOutOfPixelBlockListener implements Listener {
@EventHandler @EventHandler
public void onPlayerMove(PlayerMoveEvent event) { static void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if(player.getLocation().y() > -65) return; if(player.getLocation().y() > -65) return;
if(!PixelBlockWorld.isPixelWorld(player.getWorld())) return; if(!PixelBlockWorld.isPixelWorld(player.getWorld())) return;

View File

@ -1,11 +1,12 @@
package eu.mhsl.minecraft.pixelblocks.listeners; package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.PixelBlockItem; 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.PixelBlock;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld;
import eu.mhsl.minecraft.pixelblocks.utils.Direction; import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
@ -13,17 +14,23 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.UUID;
public class PlacePixelBlockListener implements Listener { public class PlacePixelBlockListener implements Listener {
@EventHandler @EventHandler
public void onBlockPlace(BlockPlaceEvent event) { static void onBlockPlace(BlockPlaceEvent event) {
ItemStack usedItem = event.getItemInHand(); ItemStack usedItem = event.getItemInHand();
PixelBlockItem.BlockInfo info = PixelBlockItem.getBlockInfo(usedItem); ItemMeta usedItemMeta = usedItem.getItemMeta();
if(info == null) return; Component displayName = usedItemMeta.displayName();
if(displayName == null) return;
if(!displayName.toString().contains("Pixelblock")) return;
if(!usedItemMeta.getEnchantmentGlintOverride()) return;
World playerWorld = event.getPlayer().getWorld(); World playerWorld = event.getPlayer().getWorld();
if(PixelBlockWorld.isPixelWorld(playerWorld)) { if(PixelBlockWorld.isPixelWorld(playerWorld)) {
event.getPlayer().sendMessage(Component.text("In Pixelblöcken kann kein Pixelblock platziert werden.", NamedTextColor.RED)); event.getPlayer().sendMessage("In Pixelblöcken kann kein Pixelblock erstellt werden.");
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -32,50 +39,34 @@ public class PlacePixelBlockListener implements Listener {
playerWorld.getBlockAt(newBlockLocation).setType(Material.AIR); playerWorld.getBlockAt(newBlockLocation).setType(Material.AIR);
Direction direction = Direction.vectorToDirection(event.getPlayer().getLocation().getDirection()); Direction direction = Direction.vectorToDirection(event.getPlayer().getLocation().getDirection());
String itemName = PlainTextComponentSerializer.plainText().serialize(usedItemMeta.itemName());
PixelBlock.createPixelBlock( PixelBlock pixelBlock;
info.id(), if(itemName.equals(PixelBlockItem.unusedBlockID.toString())) {
info.hasOwner() ? info.owner() : event.getPlayer().getUniqueId(), pixelBlock = new PixelBlock(
newBlockLocation, newBlockLocation,
event.getPlayer().getUniqueId(),
UUID.randomUUID(),
direction direction
); );
// if(!info.hasOwner()) { } else {
// pixelBlock = PixelBlock.createPixelBlock( UUID itemUUID = UUID.fromString(itemName);
// UUID.randomUUID(), pixelBlock = PixelBlocksPlugin.pixelBlocks.stream()
// event.getPlayer().getUniqueId(), .filter(block -> block.blockUUID.equals(itemUUID))
// newBlockLocation, .findFirst()
// Direction.south .orElseGet(() -> new PixelBlock(
// ); newBlockLocation,
//// pixelBlock = new PixelBlock( event.getPlayer().getUniqueId(),
//// newBlockLocation, itemUUID,
//// event.getPlayer().getUniqueId(), direction
//// UUID.randomUUID(), ));
//// direction }
//// );
// } else { try {
// UUID itemUUID = info.id(); pixelBlock.place(newBlockLocation, direction);
// pixelBlock = PixelBlock.createPixelBlock( } catch (IllegalArgumentException e) {
// UUID.randomUUID(), event.setCancelled(true);
// even.getUniqueId(), event.getPlayer().sendMessage(Component.text(e.getMessage()));
// playerLocation.toBlockLocation(), }
// Direction.south
// );
//// pixelBlock = Main.pixelBlocks.stream()
//// .filter(block -> block.getBlockUUID().equals(itemUUID))
//// .findFirst()
//// .orElseGet(() -> new PixelBlock(
//// newBlockLocation,
//// event.getPlayer().getUniqueId(),
//// itemUUID,
//// direction
//// ));
// }
//
// try {
// pixelBlock.place(newBlockLocation, direction);
// } catch (IllegalArgumentException e) {
// event.setCancelled(true);
// event.getPlayer().sendMessage(Component.text(e.getMessage()));
// }
} }
} }

View File

@ -8,7 +8,7 @@ import org.bukkit.event.player.PlayerBucketEmptyEvent;
public class PlacePixelListener implements Listener { public class PlacePixelListener implements Listener {
@EventHandler @EventHandler
public void onBlockPlace(BlockPlaceEvent event) { static void onBlockPlace(BlockPlaceEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getBlock().getWorld(), event.getBlock().getWorld(),
@ -17,7 +17,7 @@ public class PlacePixelListener implements Listener {
} }
@EventHandler @EventHandler
public void onBuketEmpty(PlayerBucketEmptyEvent event) { static void onBuketEmpty(PlayerBucketEmptyEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getBlock().getWorld(), event.getBlock().getWorld(),

View File

@ -7,7 +7,7 @@ import org.bukkit.event.entity.EntityPlaceEvent;
public class PreventEntityPlacementListener implements Listener { public class PreventEntityPlacementListener implements Listener {
@EventHandler @EventHandler
public void preventPlace(EntityPlaceEvent event) { public static void preventPlace(EntityPlaceEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld());
} }
} }

View File

@ -1,23 +0,0 @@
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));
}
}

View File

@ -8,7 +8,7 @@ import org.bukkit.event.inventory.InventoryType;
public class PreventHopperActionsListener implements Listener { public class PreventHopperActionsListener implements Listener {
@EventHandler @EventHandler
public void onInventoryPickupItem(InventoryPickupItemEvent event) { static void onInventoryPickupItem(InventoryPickupItemEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getItem().getWorld(), event.getItem().getWorld(),

View File

@ -10,22 +10,22 @@ import org.bukkit.event.entity.EntityExplodeEvent;
public class PreventIllegalBlocksListener implements Listener { public class PreventIllegalBlocksListener implements Listener {
@EventHandler @EventHandler
public void onBlockExplode(BlockExplodeEvent event) { static void onBlockExplode(BlockExplodeEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld());
} }
@EventHandler @EventHandler
public void onCreatureSpawn(CreatureSpawnEvent event) { static void onCreatureSpawn(CreatureSpawnEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld());
} }
@EventHandler @EventHandler
public void onEntityDamage(EntityDamageEvent event) { static void onEntityDamage(EntityDamageEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getEntity().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getEntity().getWorld());
} }
@EventHandler @EventHandler
public void onEntityExplode(EntityExplodeEvent event) { static void onEntityExplode(EntityExplodeEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld());
} }
} }

View File

@ -3,16 +3,14 @@ package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.utils.EventCanceling; import eu.mhsl.minecraft.pixelblocks.utils.EventCanceling;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryInteractEvent; import org.bukkit.event.inventory.*;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.CraftingInventory; import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.PlayerInventory;
public class PreventInventorysListener implements Listener { public class PreventInventorysListener implements Listener {
@EventHandler @EventHandler
public void onInventoryOpen(InventoryOpenEvent event) { static void onInventoryOpen(InventoryOpenEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getPlayer().getWorld(), event.getPlayer().getWorld(),
@ -21,7 +19,7 @@ public class PreventInventorysListener implements Listener {
} }
@EventHandler @EventHandler
public void onInventoryInteract(InventoryInteractEvent event) { static void onInventoryInteract(InventoryInteractEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getWhoClicked().getWorld(), event.getWhoClicked().getWorld(),

View File

@ -7,7 +7,7 @@ import org.bukkit.event.block.BlockFromToEvent;
public class PreventLiquidsFlowListener implements Listener { public class PreventLiquidsFlowListener implements Listener {
@EventHandler @EventHandler
public void onLiquidFlow(BlockFromToEvent event) { public static void onLiquidFlow(BlockFromToEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getToBlock().getWorld(), event.getToBlock().getWorld(),

View File

@ -7,7 +7,7 @@ import org.bukkit.event.block.BlockPistonExtendEvent;
public class PreventPistonsListener implements Listener { public class PreventPistonsListener implements Listener {
@EventHandler @EventHandler
public void blockPistons(BlockPistonExtendEvent event) { public static void blockPistons(BlockPistonExtendEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getBlock().getWorld(), event.getBlock().getWorld(),

View File

@ -1,26 +0,0 @@
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);
}
}

View File

@ -0,0 +1,57 @@
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();
}
}

View File

@ -1,44 +1,44 @@
package eu.mhsl.minecraft.pixelblocks.pixelblock; 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.PixelBlockItem;
import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import eu.mhsl.minecraft.pixelblocks.utils.Direction; import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import net.kyori.adventure.text.Component; import eu.mhsl.minecraft.pixelblocks.utils.MinMaxUtil;
import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.*;
import org.bukkit.Chunk; import org.bukkit.block.data.BlockData;
import org.bukkit.Location; import org.bukkit.entity.*;
import org.bukkit.Sound; import org.bukkit.inventory.ItemStack;
import org.bukkit.World;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections; import java.io.File;
import java.util.List; import java.util.*;
import java.util.Objects;
import java.util.UUID;
public class PixelBlock { public class PixelBlock {
private boolean exists = true; private final PixelBlockWorld pixelWorld;
private PixelBlockWorld pixelWorld;
private final Location pixelBlockLocation; private final float hitboxOffset = (float) PixelBlocksPlugin.configuration.hitboxOffset();
private final Direction facingDirection; private final int pixelsPerBlock = PixelBlocksPlugin.configuration.pixelsPerBlock();
private Pixels pixels;
private List<PixelBlockWorld.PixelData> pixelData;
private PixelBlockHitbox hitbox; public Location pixelBlockLocation;
private PixelBlockPlaceholder placeholder; public Direction facingDirection;
public ArrayList<Pixel> pixels = new ArrayList<>();
private Location lastEntryLocation; public Interaction hitbox;
private final UUID ownerUUID; public ItemDisplay barrier;
private final UUID blockUUID;
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;
}
public static @Nullable PixelBlock getPixelBlockFromBlockWorld(World world) { public static @Nullable PixelBlock getPixelBlockFromBlockWorld(World world) {
return Main.pixelBlocks.stream() return PixelBlocksPlugin.pixelBlocks.stream()
.filter(block -> block.blockUUID.equals(getUUIDFromWorld(world))) .filter(block -> block.blockUUID.equals(getUUIDFromWorld(world)))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
@ -57,219 +57,226 @@ public class PixelBlock {
searchLocation.setPitch(0); searchLocation.setPitch(0);
searchLocation.setYaw(0); searchLocation.setYaw(0);
return Main.pixelBlocks.stream() return PixelBlocksPlugin.pixelBlocks.stream()
.filter(block -> Objects.equals(block.pixelBlockLocation, searchLocation)) .filter(block -> block.pixelBlockLocation.equals(searchLocation))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
} }
public static PixelBlock fromExisting(UUID blockUUID, UUID ownerUUID, Location pixelBlockLocation, Direction direction, Location lastEntryLocation) { public PixelBlock(Location originLocation, UUID ownerUUID, UUID blockUUID, Direction direction) {
return new PixelBlock(blockUUID, ownerUUID, pixelBlockLocation, direction, lastEntryLocation); PixelBlocksPlugin.pixelBlocks.add(this);
}
private PixelBlock(UUID blockUUID, UUID ownerUUID, Location pixelBlockLocation, Direction direction, Location lastEntryLocation) {
this.blockUUID = blockUUID;
this.ownerUUID = ownerUUID; this.ownerUUID = ownerUUID;
this.pixelBlockLocation = pixelBlockLocation; this.blockUUID = blockUUID;
this.pixelBlockLocation = originLocation.toBlockLocation();
this.pixelBlockLocation.setYaw(0); this.pixelBlockLocation.setYaw(0);
this.pixelBlockLocation.setPitch(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.facingDirection = direction;
this.getBlockTaskChain()
.sync(() -> {
this.pixelWorld = new PixelBlockWorld(this); 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) { public void enterBlock(@NotNull Player player) {
if(Main.configuration().onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) { if(PixelBlocksPlugin.configuration.onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) {
player.sendMessage(Component.text("Dieser Pixelblock gehört nicht dir!", NamedTextColor.RED)); player.sendMessage("Dieser Pixelblock gehört nicht dir!");
return; return;
} }
getBlockTaskChain()
.async(() -> {
this.lastEntryLocation = player.getLocation(); this.lastEntryLocation = player.getLocation();
Main.database().savePixelBlock(this); this.lastEntryTime = System.currentTimeMillis();
}) PixelBlocksPlugin.database.savePixelBlock(this);
.sync(() -> {
if(!exists) return;
player.teleport(this.pixelWorld.getSpawnLocation()); 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 exitBlock(@NotNull Player player) { public void setLastEntryLocation(Location lastEntryLocation) {
this.getBlockTaskChain() this.lastEntryLocation = lastEntryLocation;
.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();
} }
private void scheduleEntityUpdate() { public void spawnInteraction(boolean fullBlock) {
this.getBlockTaskChain() if(fullBlock) {
.sync(this::ensureChunksLoaded) hitbox = (Interaction) pixelBlockLocation.getWorld().spawnEntity(
.sync(this::removeEntities) pixelBlockLocation.clone().add(0.5, -hitboxOffset, 0.5),
.delay(1) EntityType.INTERACTION
.async(() -> Collections.shuffle(this.pixelData)) );
.delay(1) hitbox.setInteractionHeight(1 + 2*hitboxOffset);
.sync(this::ensureChunksLoaded) hitbox.setInteractionWidth(1 + 2*hitboxOffset);
.syncLast((pixelData) -> { } else {
this.pixels.spawn(); double startingX = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getX());
this.hitbox.spawn(); double startingY = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getY());
this.placeholder.spawn(); double startingZ = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getZ());
})
.execute(); 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;
} }
// public void place(Location placeLocation, Direction direction) { if(spawnLocation.getX()+width/2 > this.pixelBlockLocation.getX()+1) {
// Location newLocation = placeLocation.toBlockLocation(); spawnLocation.subtract((spawnLocation.getX()+width/2)-(this.pixelBlockLocation.getX()+1), 0, 0);
// newLocation.setPitch(0); }
// newLocation.setYaw(0); if(spawnLocation.getX()-width/2 < this.pixelBlockLocation.getX()) {
// spawnLocation.add(this.pixelBlockLocation.getX()-(spawnLocation.getX()-width/2), 0, 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.");
// if(spawnLocation.getZ()+width/2 > this.pixelBlockLocation.getZ()+1) {
// Main.logger().info(String.format("Placing PixelBlock '%s' at %s", this.blockUUID, placeLocation)); spawnLocation.subtract(0, 0, (spawnLocation.getZ()+width/2)-(this.pixelBlockLocation.getZ()+1));
// this.pixelBlockLocation = newLocation; }
// this.facingDirection = direction; if(spawnLocation.getZ()-width/2 < this.pixelBlockLocation.getZ()) {
// updateEntities(); spawnLocation.add(0, 0, this.pixelBlockLocation.getZ()-(spawnLocation.getZ()-width/2));
// Main.database.savePixelBlock(this); }
//
// this.placeholder = PixelBlockPlaceholder.newPlaceholder(this); hitbox = (Interaction) pixelBlockLocation.getWorld().spawnEntity(
// } spawnLocation,
EntityType.INTERACTION
);
hitbox.setInteractionHeight(height);
hitbox.setInteractionWidth(width);
}
}
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 destroy(Player destroyedBy) { public void destroy(Player destroyedBy) {
if(!this.exists) return; if(PixelBlocksPlugin.configuration.onlyBreakableByOwner() && !destroyedBy.getUniqueId().equals(ownerUUID)) {
if(Main.configuration().onlyBreakableByOwner() && !destroyedBy.getUniqueId().equals(ownerUUID)) {
destroyedBy.sendMessage("Dieser Pixelblock gehört nicht dir!"); destroyedBy.sendMessage("Dieser Pixelblock gehört nicht dir!");
return; return;
} }
this.pixelWorld.getPlayersInWorld().forEach(p -> { this.pixelWorld.getPlayersInWorld().forEach(p -> {
p.sendMessage(Component.text("Der Pixelblock wurde von einem anderen Spieler abgebaut!", NamedTextColor.RED)); p.sendMessage("Der Pixelblock wurde von einem anderen Spieler abgebaut.");
p.teleport(this.lastEntryLocation); p.teleport(this.lastEntryLocation);
}); });
Main.logger().info(String.format("Destroying PixelBlock '%s' at %s", this.blockUUID, pixelBlockLocation));
this.exists = false;
this.pixelWorld.getEntitiesInWorld().stream() this.pixelWorld.getEntitiesInWorld().stream()
.filter(entity -> entity instanceof Item) .filter(entity -> entity instanceof Item)
.forEach(entity -> entity.teleport(this.lastEntryLocation)); .forEach(entity -> entity.teleport(this.lastEntryLocation));
this.getBlockTaskChain() this.clearEntities();
.sync(() -> { PixelBlocksPlugin.database.deletePixelBlock(this);
this.removeEntities(); this.pixelBlockLocation.getWorld().playSound(this.pixelBlockLocation, Sound.BLOCK_COPPER_BULB_BREAK, 1.0F, 30);
World world = this.pixelBlockLocation.getWorld(); this.pixelBlockLocation.getWorld().dropItem(this.pixelBlockLocation.add(new Vector(0.5, 0.5, 0.5)), PixelBlockItem.getBlockAsItem(this));
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 removeEntities() { private void clearEntities() {
this.ensureChunksLoaded();
this.pixels.destroy();
this.placeholder.destroy();
this.hitbox.destroy();
}
private void ensureChunksLoaded() {
Chunk chunk = this.pixelBlockLocation.getChunk(); Chunk chunk = this.pixelBlockLocation.getChunk();
if(!chunk.isLoaded() || !chunk.isEntitiesLoaded()) { if(!chunk.isEntitiesLoaded()) {
Main.logger().info(String.format("Loading chunk '%d, %d' for pixelblock '%s'", chunk.getX(), chunk.getZ(), this.blockUUID)); chunk.load(true);
chunk.load();
chunk.getEntities(); 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() { public @NotNull PixelBlockWorld getPixelWorld() {
return pixelWorld; return pixelWorld;
} }
public Location getPixelBlockLocation() { public int getPixelsPerBlock() {
return pixelBlockLocation.clone(); return pixelsPerBlock;
}
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;
} }
} }

View File

@ -1,99 +0,0 @@
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);
}
}

View File

@ -0,0 +1,5 @@
package eu.mhsl.minecraft.pixelblocks.pixelblock;
public class PixelBlockInteraction {
}

View File

@ -1,86 +0,0 @@
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);
}
}

View File

@ -1,31 +1,29 @@
package eu.mhsl.minecraft.pixelblocks.pixelblock; package eu.mhsl.minecraft.pixelblocks.pixelblock;
import eu.mhsl.minecraft.pixelblocks.Main; import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.utils.LocationUtil; import eu.mhsl.minecraft.pixelblocks.utils.LocationUtil;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Random; import java.util.Random;
import static eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin.plugin;
public class PixelBlockWorld { public class PixelBlockWorld {
private final PixelBlock parentPixelBlock; private final PixelBlock parentPixelBlock;
private final World world; private final World world;
int worldGrassBorderWidth = 10; int worldGrassBorderWidth = 10;
int pixelsPerBlock = Main.configuration().pixelsPerBlock(); int pixelsPerBlock = PixelBlocksPlugin.configuration.pixelsPerBlock();
public static boolean isPixelWorld(@NotNull World world) { public static boolean isPixelWorld(@NotNull World world) {
return world.getName().startsWith(Main.plugin().getDataFolder().getPath()); return world.getName().startsWith(plugin.getDataFolder().getPath());
} }
public static @NotNull List<World> getOtherWorlds() { public static @NotNull List<World> getOtherWorlds() {
@ -51,7 +49,7 @@ public class PixelBlockWorld {
} }
public @NotNull String getWorldPathName() { public @NotNull String getWorldPathName() {
return Main.plugin().getDataFolder().getPath() + File.separator + "worlds" + File.separator + this.parentPixelBlock.getBlockUUID(); return PixelBlocksPlugin.plugin.getDataFolder().getPath() + File.separator + "worlds" + File.separator + this.parentPixelBlock.blockUUID;
} }
public @NotNull Location getSpawnLocation() { public @NotNull Location getSpawnLocation() {
@ -90,46 +88,11 @@ public class PixelBlockWorld {
return getBorderOrigin().add(worldGrassBorderWidth + pixelsPerBlock, 0, worldGrassBorderWidth + pixelsPerBlock); return getBorderOrigin().add(worldGrassBorderWidth + pixelsPerBlock, 0, worldGrassBorderWidth + pixelsPerBlock);
} }
public record PixelData(Vector relativeLocation, BlockData block, double scale) {
}
public 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() { private World loadOrCreatePixelWorld() {
final WorldCreator worldCreator = new WorldCreator(getWorldPathName()); final WorldCreator worldCreator = new WorldCreator(getWorldPathName());
worldCreator.type(WorldType.FLAT); worldCreator.type(WorldType.FLAT);
worldCreator.generator(new ChunkGenerator() { worldCreator.generator(new ChunkGenerator() {});
});
World world = Bukkit.createWorld(worldCreator); World world = Bukkit.createWorld(worldCreator);
Objects.requireNonNull(world); Objects.requireNonNull(world);
@ -151,7 +114,7 @@ public class PixelBlockWorld {
} }
private void setBuildingPlatform() { private void setBuildingPlatform() {
Bukkit.getScheduler().runTask(Main.plugin(), () -> { Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> {
for (int x = 0; x < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; x++) { for (int x = 0; x < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; x++) {
for (int z = 0; z < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; z++) { for (int z = 0; z < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; z++) {
getPlatformOrigin().add(x, 0, z).getBlock().setType(Material.GRASS_BLOCK); getPlatformOrigin().add(x, 0, z).getBlock().setType(Material.GRASS_BLOCK);
@ -179,8 +142,10 @@ public class PixelBlockWorld {
LocationUtil.iterateBlocks(getPlatformOrigin().add(1, 1, 1), getPlatformOriginEnd().add(0, 1, 0), location -> { LocationUtil.iterateBlocks(getPlatformOrigin().add(1, 1, 1), getPlatformOriginEnd().add(0, 1, 0), location -> {
if (allowPlacements(location)) return; if (allowPlacements(location)) return;
if (!location.clone().subtract(0, 1, 0).getBlock().getType().equals(Material.GRASS_BLOCK)) return; if (!location.clone().subtract(0, 1, 0).getBlock().getType().equals(Material.GRASS_BLOCK)) return;
if (!location.getBlock().getType().equals(Material.AIR)) return;
List<Material> flowers = List.of( if (random.nextInt(10) == 0) {
Material[] flowers = {
Material.DANDELION, Material.DANDELION,
Material.POPPY, Material.POPPY,
Material.BLUE_ORCHID, Material.BLUE_ORCHID,
@ -191,14 +156,9 @@ public class PixelBlockWorld {
Material.WHITE_TULIP, Material.WHITE_TULIP,
Material.CORNFLOWER, Material.CORNFLOWER,
Material.LILY_OF_THE_VALLEY, 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;
if(random.nextInt(30) == 0) { Material randomFlower = flowers[random.nextInt(flowers.length)];
Material randomFlower = flowers.get(random.nextInt(flowers.size()));
location.getBlock().setType(randomFlower); location.getBlock().setType(randomFlower);
} }
}); });

View File

@ -1,62 +0,0 @@
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());
}
}

View File

@ -1,19 +0,0 @@
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();
}
}

View File

@ -8,7 +8,6 @@ public class MinMaxUtil {
public static <I, O extends Comparable<O>> O getMinProperty(List<I> list, Function<I, O> supplier) { 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()); 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) { 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()); return supplier.apply(list.stream().max(Comparator.comparing(supplier)).orElseThrow());
} }

View File

@ -1,6 +1,6 @@
name: PixelBlocks name: PixelBlocks
version: '${version}' version: '${version}'
main: eu.mhsl.minecraft.pixelblocks.Main main: eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin
api-version: '1.21' api-version: '1.21'
commands: commands:
createpixelblock: createpixelblock: