feature-remove-db #8

Merged
Pupsi merged 21 commits from feature-remove-db into main 2024-10-19 13:25:58 +00:00
38 changed files with 871 additions and 596 deletions

View File

@ -26,5 +26,15 @@
<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,6 +4,7 @@
<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

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

View File

@ -1,5 +1,6 @@
plugins { plugins {
id 'java' id 'java'
id 'com.gradleup.shadow' version '8.3.1'
} }
group = 'eu.mhsl.minecraft' group = 'eu.mhsl.minecraft'
@ -15,10 +16,14 @@ 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
@ -31,14 +36,6 @@ 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
@ -49,8 +46,12 @@ processResources {
} }
tasks.register('copyJarToTestServer', Exec) { tasks.register('copyJarToTestServer', Exec) {
dependsOn jar commandLine 'cp', 'build/libs/PixelBlocks-1.0-SNAPSHOT-all.jar', '/home/elias/Dokumente/mcTestServer/plugins/pixelblocks.jar'
mustRunAfter jar
commandLine 'cp', 'build/libs/PixelBlocks-1.0-SNAPSHOT.jar', '/home/elias/Dokumente/mcTestServer/plugins/pixelblocks.jar'
} }
shadowJar {
relocate 'co.aikar.taskchain', 'eu.mhsl.minecraft.pixelblocks.taskchain'
}
jar.dependsOn shadowJar
copyJarToTestServer.dependsOn jar

View File

@ -1,5 +1,8 @@
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.*;
@ -14,36 +17,45 @@ 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 PixelBlocksPlugin extends JavaPlugin { public final class Main extends JavaPlugin {
public static PixelBlocksPlugin plugin; private static Main plugin;
public static PixelBlockConfiguration configuration; private static PixelBlockConfiguration configuration;
public static PixelBlockDatabase database; 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 @Override
public void onLoad() { public void onLoad() {
PixelBlocksPlugin.plugin = this; Main.plugin = this;
FileConfiguration config = this.getConfig(); FileConfiguration config = this.getConfig();
PixelBlockConfiguration.setDefaults(config); PixelBlockConfiguration.setDefaults(config);
this.saveConfig(); this.saveConfig();
PixelBlocksPlugin.configuration = new PixelBlockConfiguration( Main.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");
PixelBlocksPlugin.database = new PixelBlockDatabase("jdbc:sqlite:" + databaseFile); Main.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(),
@ -52,7 +64,6 @@ public final class PixelBlocksPlugin 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(),
@ -60,10 +71,12 @@ public final class PixelBlocksPlugin 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) {
getServer().getPluginManager().registerEvents(listener, plugin); getServer().getPluginManager().registerEvents(listener, plugin);
} }
@ -75,10 +88,27 @@ public final class PixelBlocksPlugin 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

@ -4,14 +4,12 @@ import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull; 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);
@ -19,11 +17,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,13 +1,11 @@
package eu.mhsl.minecraft.pixelblocks; package eu.mhsl.minecraft.pixelblocks;
import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import eu.mhsl.minecraft.pixelblocks.utils.Direction;
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 {
@ -15,9 +13,7 @@ public class PixelBlockDatabase {
private final PreparedStatement getAllPixelBlocks; private final PreparedStatement getAllPixelBlocks;
private final PreparedStatement deletePixelBlock; private final PreparedStatement deletePixelBlock;
private final PreparedStatement insertNewPixelBlock; private final PreparedStatement insertOrReplacePixelBlock;
private final PreparedStatement updateExistingPixelBlock;
public PixelBlockDatabase(String url) { public PixelBlockDatabase(String url) {
try { try {
@ -25,134 +21,81 @@ public class PixelBlockDatabase {
this.db = DriverManager.getConnection(url); this.db = DriverManager.getConnection(url);
this.db.createStatement().execute( this.db.createStatement().execute(
"CREATE TABLE IF NOT EXISTS pixelblocks (" + "CREATE TABLE IF NOT EXISTS pixelblocks (" +
"uuid CHAR(36) PRIMARY KEY, " + "uuid CHAR(36) PRIMARY KEY, " +
"owner CHAR(36), " + "owner CHAR(36), " +
"locationWorldName CHAR(36), " + "locationWorldName CHAR(36), " +
"locationX DOUBLE, " + "locationX DOUBLE, " +
"locationY DOUBLE, " + "locationY DOUBLE, " +
"locationZ DOUBLE, " + "locationZ DOUBLE, " +
"entryLocationWorldName CHAR(36), " + "entryLocationWorldName CHAR(36), " +
"entryLocationX DOUBLE, " + "entryLocationX DOUBLE, " +
"entryLocationY DOUBLE, " + "entryLocationY DOUBLE, " +
"entryLocationZ DOUBLE, " + "entryLocationZ DOUBLE, " +
"direction CHAR(36)" + "direction CHAR(36)" +
")" ")"
); );
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.insertNewPixelBlock = this.db.prepareStatement( this.insertOrReplacePixelBlock = this.db.prepareStatement(
"INSERT INTO pixelblocks(uuid, owner, " + "INSERT OR REPLACE 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 " + } catch(SQLException | RuntimeException | ClassNotFoundException e) {
"SET owner=?, locationWorldName=?, locationX=?, locationY=?, locationZ=?," + throw new RuntimeException("Error while initializing database", e);
"entryLocationWorldName=?, entryLocationX=?, entryLocationY=?, entryLocationZ=?, direction=? " +
"WHERE uuid=?;"
);
} catch (SQLException | RuntimeException | ClassNotFoundException 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();
insertNewPixelBlock.close(); insertOrReplacePixelBlock.close();
updateExistingPixelBlock.close();
db.close(); db.close();
} }
public void deletePixelBlock(PixelBlock pixelBlock) { public void deletePixelBlock(PixelBlock pixelBlock) {
Bukkit.getScheduler().runTaskAsynchronously(PixelBlocksPlugin.plugin, () -> { Bukkit.getScheduler().runTaskAsynchronously(Main.plugin(), () -> {
try { try {
this.deletePixelBlock.setString(1, pixelBlock.blockUUID.toString()); this.deletePixelBlock.setString(1, pixelBlock.getBlockUUID().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(PixelBlocksPlugin.plugin, () -> { Bukkit.getScheduler().runTask(Main.plugin(), () -> {
List<UUID> storedPixelBlocks = new ArrayList<>();
try { try {
ResultSet pixelBlocksResult = this.getAllPixelBlocks.executeQuery(); this.insertOrReplacePixelBlock.setString(1, pixelBlock.getBlockUUID().toString());
while (pixelBlocksResult.next()) { this.insertOrReplacePixelBlock.setString(2, pixelBlock.getOwnerUUID().toString());
storedPixelBlocks.add(UUID.fromString(pixelBlocksResult.getString("uuid")));
}
} catch (SQLException e) {
throw new RuntimeException("Failed to fetch PixelBlock list", e);
}
if(!storedPixelBlocks.contains(pixelBlock.blockUUID)) { this.insertOrReplacePixelBlock.setString(3, pixelBlock.getPixelBlockLocation().getWorld().getName());
// create new entry if it does not exist this.insertOrReplacePixelBlock.setDouble(4, pixelBlock.getPixelBlockLocation().getX());
try { this.insertOrReplacePixelBlock.setDouble(5, pixelBlock.getPixelBlockLocation().getY());
this.insertNewPixelBlock.setString(1, pixelBlock.blockUUID.toString()); this.insertOrReplacePixelBlock.setDouble(6, pixelBlock.getPixelBlockLocation().getZ());
this.insertNewPixelBlock.setString(2, pixelBlock.ownerUUID.toString());
this.insertNewPixelBlock.setString(3, pixelBlock.pixelBlockLocation.getWorld().getName()); if(pixelBlock.hasLastEntryLocation()) {
this.insertNewPixelBlock.setDouble(4, pixelBlock.pixelBlockLocation.getX()); this.insertOrReplacePixelBlock.setString(7, pixelBlock.getLastEntryLocation().getWorld().getName());
this.insertNewPixelBlock.setDouble(5, pixelBlock.pixelBlockLocation.getY()); this.insertOrReplacePixelBlock.setDouble(8, pixelBlock.getLastEntryLocation().getX());
this.insertNewPixelBlock.setDouble(6, pixelBlock.pixelBlockLocation.getZ()); this.insertOrReplacePixelBlock.setDouble(9, pixelBlock.getLastEntryLocation().getY());
this.insertOrReplacePixelBlock.setDouble(10, pixelBlock.getLastEntryLocation().getZ());
if(pixelBlock.lastEntryLocation != null) { } else {
this.insertNewPixelBlock.setString(7, pixelBlock.lastEntryLocation.getWorld().getName()); this.insertOrReplacePixelBlock.setString(7, pixelBlock.getPixelBlockLocation().getWorld().getName());
this.insertNewPixelBlock.setDouble(8, pixelBlock.lastEntryLocation.getX()); this.insertOrReplacePixelBlock.setDouble(8, pixelBlock.getPixelBlockLocation().getX());
this.insertNewPixelBlock.setDouble(9, pixelBlock.lastEntryLocation.getY()); this.insertOrReplacePixelBlock.setDouble(9, pixelBlock.getPixelBlockLocation().getY());
this.insertNewPixelBlock.setDouble(10, pixelBlock.lastEntryLocation.getZ()); this.insertOrReplacePixelBlock.setDouble(10, pixelBlock.getPixelBlockLocation().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);
} }
} else { this.insertOrReplacePixelBlock.setString(11, pixelBlock.getFacingDirection().toString());
// update existing entry
try {
this.updateExistingPixelBlock.setString(1, pixelBlock.ownerUUID.toString());
this.updateExistingPixelBlock.setString(2, pixelBlock.pixelBlockLocation.getWorld().getName()); this.insertOrReplacePixelBlock.executeUpdate();
this.updateExistingPixelBlock.setDouble(3, pixelBlock.pixelBlockLocation.getX()); } catch(SQLException e) {
this.updateExistingPixelBlock.setDouble(4, pixelBlock.pixelBlockLocation.getY()); throw new RuntimeException("Failed to create or update PixelBlock in the database", e);
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);
}
} }
}); });
} }
@ -161,7 +104,7 @@ public class PixelBlockDatabase {
try { try {
ResultSet allPixelBlocks = this.getAllPixelBlocks.executeQuery(); ResultSet allPixelBlocks = this.getAllPixelBlocks.executeQuery();
while (allPixelBlocks.next()) { while(allPixelBlocks.next()) {
Location blockLocation = new Location( Location blockLocation = new Location(
Bukkit.getWorld(allPixelBlocks.getString("locationWorldName")), Bukkit.getWorld(allPixelBlocks.getString("locationWorldName")),
allPixelBlocks.getDouble("locationX"), allPixelBlocks.getDouble("locationX"),
@ -176,17 +119,16 @@ public class PixelBlockDatabase {
allPixelBlocks.getDouble("entryLocationZ") allPixelBlocks.getDouble("entryLocationZ")
); );
PixelBlock block = new PixelBlock( Main.pixelBlocks.add(PixelBlock.fromExisting(
blockLocation,
UUID.fromString(allPixelBlocks.getString("owner")),
UUID.fromString(allPixelBlocks.getString("uuid")), UUID.fromString(allPixelBlocks.getString("uuid")),
Direction.valueOf(allPixelBlocks.getString("direction")) UUID.fromString(allPixelBlocks.getString("owner")),
); blockLocation,
block.setLastEntryLocation(entryLocation); Direction.valueOf(allPixelBlocks.getString("direction")),
PixelBlocksPlugin.plugin.getLogger().info("DB: Loaded PixelBlock: " + block.blockUUID); entryLocation
));
} }
} catch (SQLException e) { } catch(SQLException e) {
throw new RuntimeException("Failed loading PixelBlocks", e); throw new RuntimeException("Failed loading PixelBlocks from the database", e);
} }
} }
} }

View File

@ -11,30 +11,53 @@ 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 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 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.ownerUUID).getName()).orElseGet(() -> block.ownerUUID.toString()); String ownerName = Optional.ofNullable(Bukkit.getOfflinePlayer(block.getOwnerUUID()).getName()).orElseGet(() -> block.getOwnerUUID().toString());
ItemStack itemStack = HeadUtil.getCustomTextureHead(itemTexture); ItemStack itemStack = HeadUtil.getCustomTextureHead(itemTexture);
ItemMeta meta = itemStack.getItemMeta(); 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.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.blockUUID.toString()).color(NamedTextColor.DARK_GRAY) Component.text(block.getBlockUUID().toString()).color(NamedTextColor.DARK_GRAY)
)); ));
meta.setEnchantmentGlintOverride(true);
itemStack.setItemMeta(meta); itemStack.setItemMeta(meta);
return itemStack; return itemStack;
@ -43,13 +66,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.setEnchantmentGlintOverride(true); meta.getPersistentDataContainer().set(idProperty, PersistentDataType.STRING, UUID.randomUUID().toString());
meta.itemName(Component.text(unusedBlockID.toString()));
item.setItemMeta(meta); item.setItemMeta(meta);
return item; return item;
} }
@ -61,7 +84,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.GLOW_BERRIES); recipe.setIngredient('E', Material.END_CRYSTAL);
return recipe; return recipe;
} }
} }

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,13 +24,12 @@ public class CreatePixelBlockCommand implements CommandExecutor {
} }
Location playerLocation = p.getLocation(); Location playerLocation = p.getLocation();
PixelBlock block = new PixelBlock( PixelBlock.createPixelBlock(
playerLocation,
p.getUniqueId(),
UUID.randomUUID(), UUID.randomUUID(),
p.getUniqueId(),
playerLocation.toBlockLocation(),
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.*; import java.util.Objects;
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);
p.teleport(currentPixelBlock.lastEntryLocation); currentPixelBlock.exitBlock(p);
} }
return true; return true;
} }

View File

@ -1,6 +1,5 @@
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;
@ -10,10 +9,10 @@ import org.bukkit.event.Listener;
public class BreakPixelBlockListener implements Listener { public class BreakPixelBlockListener implements Listener {
@EventHandler @EventHandler
static void destroyPixelBlock(PrePlayerAttackEntityEvent event) { public void destroyPixelBlock(PrePlayerAttackEntityEvent event) {
if(!(event.getAttacked() instanceof Interaction)) return; 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); 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
static void onBlockBreak(BlockBreakEvent event) { public void onBlockBreak(BlockBreakEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getBlock().getWorld(), event.getBlock().getWorld(),

View File

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

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.*; import org.bukkit.event.inventory.InventoryClickEvent;
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;
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); player.discoverRecipe(PixelBlockItem.recipeKey);
} }
} }

View File

@ -1,8 +1,7 @@
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.*; import org.bukkit.Location;
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;
@ -10,14 +9,13 @@ import org.bukkit.event.player.PlayerInteractEntityEvent;
public class EnterPixelBlockListener implements Listener { public class EnterPixelBlockListener implements Listener {
@EventHandler @EventHandler
static void enterPixelBlock(PlayerInteractEntityEvent event) { public 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;
pixelBlock.enterBlock(event.getPlayer()); pixelBlock.enterBlock(event.getPlayer());

View File

@ -5,31 +5,19 @@ 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
static void onPlayerChangeWorld(PlayerChangedWorldEvent event) { public void onPlayerPortal(PlayerPortalEvent 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);
event.getPlayer().teleport(pixelBlock.lastEntryLocation); pixelBlock.exitBlock(event.getPlayer());
} }
} }

View File

@ -11,7 +11,7 @@ import java.util.Objects;
public class FallOutOfPixelBlockListener implements Listener { public class FallOutOfPixelBlockListener implements Listener {
@EventHandler @EventHandler
static void onPlayerMove(PlayerMoveEvent event) { public 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,12 +1,11 @@
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.serializer.plain.PlainTextComponentSerializer; import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
@ -14,23 +13,17 @@ 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
static void onBlockPlace(BlockPlaceEvent event) { public void onBlockPlace(BlockPlaceEvent event) {
ItemStack usedItem = event.getItemInHand(); ItemStack usedItem = event.getItemInHand();
ItemMeta usedItemMeta = usedItem.getItemMeta(); PixelBlockItem.BlockInfo info = PixelBlockItem.getBlockInfo(usedItem);
Component displayName = usedItemMeta.displayName(); if(info == null) return;
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("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); event.setCancelled(true);
return; return;
} }
@ -39,34 +32,50 @@ 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 pixelBlock; PixelBlock.createPixelBlock(
if(itemName.equals(PixelBlockItem.unusedBlockID.toString())) { info.id(),
pixelBlock = new PixelBlock( info.hasOwner() ? info.owner() : event.getPlayer().getUniqueId(),
newBlockLocation, newBlockLocation,
event.getPlayer().getUniqueId(), direction
UUID.randomUUID(), );
direction // if(!info.hasOwner()) {
); // pixelBlock = PixelBlock.createPixelBlock(
} else { // UUID.randomUUID(),
UUID itemUUID = UUID.fromString(itemName); // event.getPlayer().getUniqueId(),
pixelBlock = PixelBlocksPlugin.pixelBlocks.stream() // newBlockLocation,
.filter(block -> block.blockUUID.equals(itemUUID)) // Direction.south
.findFirst() // );
.orElseGet(() -> new PixelBlock( //// pixelBlock = new PixelBlock(
newBlockLocation, //// newBlockLocation,
event.getPlayer().getUniqueId(), //// event.getPlayer().getUniqueId(),
itemUUID, //// UUID.randomUUID(),
direction //// direction
)); //// );
} // } else {
// UUID itemUUID = info.id();
try { // pixelBlock = PixelBlock.createPixelBlock(
pixelBlock.place(newBlockLocation, direction); // UUID.randomUUID(),
} catch (IllegalArgumentException e) { // even.getUniqueId(),
event.setCancelled(true); // playerLocation.toBlockLocation(),
event.getPlayer().sendMessage(Component.text(e.getMessage())); // 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
static void onBlockPlace(BlockPlaceEvent event) { public void onBlockPlace(BlockPlaceEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getBlock().getWorld(), event.getBlock().getWorld(),
@ -17,11 +17,11 @@ public class PlacePixelListener implements Listener {
} }
@EventHandler @EventHandler
static void onBuketEmpty(PlayerBucketEmptyEvent event) { public void onBuketEmpty(PlayerBucketEmptyEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getBlock().getWorld(), event.getBlock().getWorld(),
pixelBlock -> !pixelBlock.getPixelWorld().allowPlacements(event.getBlock().getLocation()) pixelBlock -> !pixelBlock.getPixelWorld().allowPlacements(event.getBlock().getLocation())
); );
} }
} }

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 static void preventPlace(EntityPlaceEvent event) { public void preventPlace(EntityPlaceEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld());
} }
} }

View File

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

View File

@ -8,7 +8,7 @@ import org.bukkit.event.inventory.InventoryType;
public class PreventHopperActionsListener implements Listener { public class PreventHopperActionsListener implements Listener {
@EventHandler @EventHandler
static void onInventoryPickupItem(InventoryPickupItemEvent event) { public 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
static void onBlockExplode(BlockExplodeEvent event) { public void onBlockExplode(BlockExplodeEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getBlock().getWorld());
} }
@EventHandler @EventHandler
static void onCreatureSpawn(CreatureSpawnEvent event) { public void onCreatureSpawn(CreatureSpawnEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld());
} }
@EventHandler @EventHandler
static void onEntityDamage(EntityDamageEvent event) { public void onEntityDamage(EntityDamageEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getEntity().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getEntity().getWorld());
} }
@EventHandler @EventHandler
static void onEntityExplode(EntityExplodeEvent event) { public void onEntityExplode(EntityExplodeEvent event) {
EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld()); EventCanceling.cancelIfInPixelWorld(event, event.getLocation().getWorld());
} }
} }

View File

@ -3,14 +3,16 @@ 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.*; 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.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
static void onInventoryOpen(InventoryOpenEvent event) { public void onInventoryOpen(InventoryOpenEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getPlayer().getWorld(), event.getPlayer().getWorld(),
@ -19,7 +21,7 @@ public class PreventInventorysListener implements Listener {
} }
@EventHandler @EventHandler
static void onInventoryInteract(InventoryInteractEvent event) { public void onInventoryInteract(InventoryInteractEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getWhoClicked().getWorld(), event.getWhoClicked().getWorld(),
@ -29,7 +31,7 @@ public class PreventInventorysListener implements Listener {
private static boolean isDisallowedInventory(Inventory inventory) { private static boolean isDisallowedInventory(Inventory inventory) {
return !(inventory instanceof PlayerInventory return !(inventory instanceof PlayerInventory
|| inventory instanceof CraftingInventory || inventory instanceof CraftingInventory
|| inventory.getType() == InventoryType.ENDER_CHEST); || inventory.getType() == InventoryType.ENDER_CHEST);
} }
} }

View File

@ -7,11 +7,11 @@ import org.bukkit.event.block.BlockFromToEvent;
public class PreventLiquidsFlowListener implements Listener { public class PreventLiquidsFlowListener implements Listener {
@EventHandler @EventHandler
public static void onLiquidFlow(BlockFromToEvent event) { public void onLiquidFlow(BlockFromToEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getToBlock().getWorld(), event.getToBlock().getWorld(),
pixelBlock -> !pixelBlock.getPixelWorld().allowPlacements(event.getToBlock().getLocation()) pixelBlock -> !pixelBlock.getPixelWorld().allowPlacements(event.getToBlock().getLocation())
); );
} }
} }

View File

@ -7,13 +7,13 @@ import org.bukkit.event.block.BlockPistonExtendEvent;
public class PreventPistonsListener implements Listener { public class PreventPistonsListener implements Listener {
@EventHandler @EventHandler
public static void blockPistons(BlockPistonExtendEvent event) { public void blockPistons(BlockPistonExtendEvent event) {
EventCanceling.shouldCancelInPixelBlock( EventCanceling.shouldCancelInPixelBlock(
event, event,
event.getBlock().getWorld(), event.getBlock().getWorld(),
(pixelBlock) -> event.getBlocks().stream() (pixelBlock) -> event.getBlocks().stream()
.anyMatch(block -> !pixelBlock.getPixelWorld() .anyMatch(block -> !pixelBlock.getPixelWorld()
.allowPlacements(block.getLocation().add(event.getDirection().getDirection()))) .allowPlacements(block.getLocation().add(event.getDirection().getDirection())))
); );
} }
} }

View File

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

View File

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

View File

@ -1,53 +1,53 @@
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 eu.mhsl.minecraft.pixelblocks.utils.MinMaxUtil; import net.kyori.adventure.text.Component;
import org.bukkit.*; import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.block.data.BlockData; import org.bukkit.Chunk;
import org.bukkit.entity.*; import org.bukkit.Location;
import org.bukkit.inventory.ItemStack; 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.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File; import java.util.Collections;
import java.util.*; import java.util.List;
import java.util.Objects;
import java.util.UUID;
public class PixelBlock { public class PixelBlock {
private final PixelBlockWorld pixelWorld; private boolean exists = true;
private PixelBlockWorld pixelWorld;
private final float hitboxOffset = (float) PixelBlocksPlugin.configuration.hitboxOffset(); private final Location pixelBlockLocation;
private final int pixelsPerBlock = PixelBlocksPlugin.configuration.pixelsPerBlock(); private final Direction facingDirection;
private Pixels pixels;
private List<PixelBlockWorld.PixelData> pixelData;
public Location pixelBlockLocation; private PixelBlockHitbox hitbox;
public Direction facingDirection; private PixelBlockPlaceholder placeholder;
public ArrayList<Pixel> pixels = new ArrayList<>();
public Interaction hitbox; private Location lastEntryLocation;
public ItemDisplay barrier; private final UUID ownerUUID;
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 PixelBlocksPlugin.pixelBlocks.stream() return Main.pixelBlocks.stream()
.filter(block -> block.blockUUID.equals(getUUIDFromWorld(world))) .filter(block -> block.blockUUID.equals(getUUIDFromWorld(world)))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
} }
public static @Nullable UUID getUUIDFromWorld(@NotNull World world) { public static @Nullable UUID getUUIDFromWorld(@NotNull World world) {
try { try {
return UUID.fromString(List.of(world.getName().split("/")).getLast()); return UUID.fromString(List.of(world.getName().split("/")).getLast());
} catch (IllegalArgumentException e) { } catch(IllegalArgumentException e) {
return null; return null;
} }
} }
@ -57,226 +57,219 @@ public class PixelBlock {
searchLocation.setPitch(0); searchLocation.setPitch(0);
searchLocation.setYaw(0); searchLocation.setYaw(0);
return PixelBlocksPlugin.pixelBlocks.stream() return Main.pixelBlocks.stream()
.filter(block -> block.pixelBlockLocation.equals(searchLocation)) .filter(block -> Objects.equals(block.pixelBlockLocation, searchLocation))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
} }
public PixelBlock(Location originLocation, UUID ownerUUID, UUID blockUUID, Direction direction) { public static PixelBlock fromExisting(UUID blockUUID, UUID ownerUUID, Location pixelBlockLocation, Direction direction, Location lastEntryLocation) {
PixelBlocksPlugin.pixelBlocks.add(this); 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.blockUUID = blockUUID;
this.ownerUUID = ownerUUID;
this.pixelBlockLocation = originLocation.toBlockLocation(); this.pixelBlockLocation = pixelBlockLocation;
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.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) { public void enterBlock(@NotNull Player player) {
if(PixelBlocksPlugin.configuration.onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) { if(Main.configuration().onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) {
player.sendMessage("Dieser Pixelblock gehört nicht dir!"); player.sendMessage(Component.text("Dieser Pixelblock gehört nicht dir!", NamedTextColor.RED));
return; return;
} }
this.lastEntryLocation = player.getLocation(); getBlockTaskChain()
this.lastEntryTime = System.currentTimeMillis(); .async(() -> {
PixelBlocksPlugin.database.savePixelBlock(this); this.lastEntryLocation = player.getLocation();
Main.database().savePixelBlock(this);
player.teleport(this.pixelWorld.getSpawnLocation()); })
.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) { public void exitBlock(@NotNull Player player) {
this.lastEntryLocation = lastEntryLocation; 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) { private void scheduleEntityUpdate() {
if(fullBlock) { this.getBlockTaskChain()
hitbox = (Interaction) pixelBlockLocation.getWorld().spawnEntity( .sync(this::ensureChunksLoaded)
pixelBlockLocation.clone().add(0.5, -hitboxOffset, 0.5), .sync(this::removeEntities)
EntityType.INTERACTION .delay(1)
); .async(() -> Collections.shuffle(this.pixelData))
hitbox.setInteractionHeight(1 + 2*hitboxOffset); .delay(1)
hitbox.setInteractionWidth(1 + 2*hitboxOffset); .sync(this::ensureChunksLoaded)
} else { .syncLast((pixelData) -> {
double startingX = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getX()); this.pixels.spawn();
double startingY = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getY()); this.hitbox.spawn();
double startingZ = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getZ()); this.placeholder.spawn();
})
double endingX = MinMaxUtil.getMaxProperty(this.pixels, pixel -> pixel.relativeLocation.getX()); .execute();
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);
}
} }
public void updateEntities() { // public void place(Location placeLocation, Direction direction) {
Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> { // Location newLocation = placeLocation.toBlockLocation();
this.clearEntities(); // newLocation.setPitch(0);
// newLocation.setYaw(0);
for (int x = 0; x < pixelsPerBlock; x++) { //
for (int y = 0; y < pixelsPerBlock; y++) { // @Nullable PixelBlock blockAtLocation = PixelBlock.getPixelBlockFromPlacedLocation(newLocation);
for (int z = 0; z < pixelsPerBlock; z++) { // if(blockAtLocation != null && blockAtLocation != this) throw new IllegalArgumentException("Es können nicht mehrere Pixelblöcke ineinander platziert werden.");
Location relativeLocation = new Location(pixelBlockLocation.getWorld(), x, y, z); //
Location blockLocation = this.pixelWorld.getBuildOrigin(); // Main.logger().info(String.format("Placing PixelBlock '%s' at %s", this.blockUUID, placeLocation));
switch (this.facingDirection) { // this.pixelBlockLocation = newLocation;
case south -> blockLocation.add(relativeLocation.x(), relativeLocation.y(), relativeLocation.z()); // this.facingDirection = direction;
case north -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.x(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.z()); // updateEntities();
case east -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.z(), relativeLocation.y(), relativeLocation.x()); // Main.database.savePixelBlock(this);
case west -> blockLocation.add(relativeLocation.z(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.x()); //
} // this.placeholder = PixelBlockPlaceholder.newPlaceholder(this);
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(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!"); destroyedBy.sendMessage("Dieser Pixelblock gehört nicht dir!");
return; return;
} }
this.pixelWorld.getPlayersInWorld().forEach(p -> { 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); 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.clearEntities(); this.getBlockTaskChain()
PixelBlocksPlugin.database.deletePixelBlock(this); .sync(() -> {
this.pixelBlockLocation.getWorld().playSound(this.pixelBlockLocation, Sound.BLOCK_COPPER_BULB_BREAK, 1.0F, 30); this.removeEntities();
this.pixelBlockLocation.getWorld().dropItem(this.pixelBlockLocation.add(new Vector(0.5, 0.5, 0.5)), PixelBlockItem.getBlockAsItem(this)); 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(); Chunk chunk = this.pixelBlockLocation.getChunk();
if(!chunk.isEntitiesLoaded()) { if(!chunk.isLoaded() || !chunk.isEntitiesLoaded()) {
chunk.load(true); Main.logger().info(String.format("Loading chunk '%d, %d' for pixelblock '%s'", chunk.getX(), chunk.getZ(), this.blockUUID));
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 int getPixelsPerBlock() { public Location getPixelBlockLocation() {
return pixelsPerBlock; 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;
} }
} }

View File

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

View File

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

View File

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

View File

@ -1,29 +1,31 @@
package eu.mhsl.minecraft.pixelblocks.pixelblock; 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 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 = PixelBlocksPlugin.configuration.pixelsPerBlock(); int pixelsPerBlock = Main.configuration().pixelsPerBlock();
public static boolean isPixelWorld(@NotNull World world) { 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() { public static @NotNull List<World> getOtherWorlds() {
@ -44,12 +46,12 @@ public class PixelBlockWorld {
Location origin = getBuildOrigin(); Location origin = getBuildOrigin();
int offset = pixelsPerBlock - 1; int offset = pixelsPerBlock - 1;
return blockLocation.x() >= origin.x() && blockLocation.x() <= origin.x() + offset return blockLocation.x() >= origin.x() && blockLocation.x() <= origin.x() + offset
&& blockLocation.z() >= origin.z() && blockLocation.z() <= origin.z() + offset && blockLocation.z() >= origin.z() && blockLocation.z() <= origin.z() + offset
&& blockLocation.y() >= origin.y() && blockLocation.y() <= origin.y() + offset; && blockLocation.y() >= origin.y() && blockLocation.y() <= origin.y() + offset;
} }
public @NotNull String getWorldPathName() { 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() { public @NotNull Location getSpawnLocation() {
@ -57,7 +59,7 @@ public class PixelBlockWorld {
} }
public @NotNull Location getPortalLocation() { 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() { public @NotNull List<Player> getPlayersInWorld() {
@ -88,11 +90,46 @@ 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);
@ -107,32 +144,32 @@ public class PixelBlockWorld {
WorldBorder worldBorder = world.getWorldBorder(); WorldBorder worldBorder = world.getWorldBorder();
worldBorder.setCenter(getBuildOrigin().add((double) pixelsPerBlock / 2, 0, (double) pixelsPerBlock / 2)); 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.setWarningDistance(0);
worldBorder.setDamageAmount(0); worldBorder.setDamageAmount(0);
return world; return world;
} }
private void setBuildingPlatform() { private void setBuildingPlatform() {
Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> { Bukkit.getScheduler().runTask(Main.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);
} }
} }
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, -1, z).getBlock().setType(Material.DIRT); getPlatformOrigin().add(x, -1, z).getBlock().setType(Material.DIRT);
} }
} }
for (int x = 0; x < (pixelsPerBlock+2); x++) { for(int x = 0; x < (pixelsPerBlock + 2); x++) {
for (int z = 0; z < (pixelsPerBlock+2); z++) { for(int z = 0; z < (pixelsPerBlock + 2); z++) {
Location currentLocation = getBorderOrigin().add(x, 0, 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); 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); currentLocation.getBlock().setType(Material.RED_CONCRETE);
} }
} }
@ -140,36 +177,39 @@ public class PixelBlockWorld {
Random random = new Random(); Random random = new Random();
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;
if (random.nextInt(10) == 0) { List<Material> flowers = List.of(
Material[] flowers = { Material.DANDELION,
Material.DANDELION, Material.POPPY,
Material.POPPY, Material.BLUE_ORCHID,
Material.BLUE_ORCHID, Material.ALLIUM,
Material.ALLIUM, Material.AZURE_BLUET,
Material.AZURE_BLUET, Material.RED_TULIP,
Material.RED_TULIP, Material.ORANGE_TULIP,
Material.ORANGE_TULIP, 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;
Material randomFlower = flowers[random.nextInt(flowers.length)]; if(random.nextInt(30) == 0) {
Material randomFlower = flowers.get(random.nextInt(flowers.size()));
location.getBlock().setType(randomFlower); location.getBlock().setType(randomFlower);
} }
}); });
for (int x = 0; x < 4; x++) { for(int x = 0; x < 4; x++) {
for (int y = 0; y < 5; y++) { for(int y = 0; y < 5; y++) {
getPortalLocation().add(x, y, 0).getBlock().setType(Material.OBSIDIAN); getPortalLocation().add(x, y, 0).getBlock().setType(Material.OBSIDIAN);
} }
} }
for (int x = 1; x < 3; x++) { for(int x = 1; x < 3; x++) {
for (int y = 1; y < 4; y++) { for(int y = 1; y < 4; y++) {
getPortalLocation().add(x, y, 0).getBlock().setType(Material.NETHER_PORTAL); getPortalLocation().add(x, y, 0).getBlock().setType(Material.NETHER_PORTAL);
} }
} }

View File

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

View File

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

View File

@ -7,7 +7,7 @@ import java.util.function.Consumer;
public class LocationUtil { public class LocationUtil {
public static void iterateBlocks(Location loc1, Location loc2, Consumer<Location> action) { 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"); 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 minZ = Math.min(loc1.getBlockZ(), loc2.getBlockZ());
int maxZ = Math.max(loc1.getBlockZ(), loc2.getBlockZ()); int maxZ = Math.max(loc1.getBlockZ(), loc2.getBlockZ());
for (int x = minX; x <= maxX; x++) { for(int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) { for(int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) { for(int z = minZ; z <= maxZ; z++) {
action.accept(new Location(world, x, y, z)); action.accept(new Location(world, x, y, z));
} }
} }

View File

@ -8,6 +8,7 @@ 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.PixelBlocksPlugin main: eu.mhsl.minecraft.pixelblocks.Main
api-version: '1.21' api-version: '1.21'
commands: commands:
createpixelblock: createpixelblock: