wip: code cleanup

This commit is contained in:
Elias Müller 2024-07-22 19:14:47 +02:00
parent 966f870d96
commit e5e1f39989
32 changed files with 623 additions and 606 deletions

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/projects.PixelBlocks.main.iml" filepath="$PROJECT_DIR$/.idea/modules/projects.PixelBlocks.main.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View File

@ -11,4 +11,8 @@
</configuration> </configuration>
</facet> </facet>
</component> </component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module> </module>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>PAPER</platformType>
<platformType>ADVENTURE</platformType>
</autoDetectTypes>
<projectReimportVersion>1</projectReimportVersion>
</configuration>
</facet>
</component>
</module>

View File

@ -0,0 +1,44 @@
package eu.mhsl.minecraft.pixelblocks;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
public record PixelBlockConfiguration(
int pixelsPerBlock,
boolean liveUpdate,
int worldGrassBorderWidth,
double hitboxOffset,
boolean deleteOnBreak, // TODO does no longer exists
boolean onlyBreakableByOwner,
boolean onlyEditableByOwner
) {
public static void setDefaults(FileConfiguration config) {
config.addDefault(Keys.PixelsPerBlock.key, 16);
config.addDefault(Keys.LiveUpdate.key, true);
config.addDefault(Keys.WorldGrassBorderWidth.key, 5);
config.addDefault(Keys.HitboxOffset.key, 0.005);
config.addDefault(Keys.DeleteOnBreak.key, false);
config.addDefault(Keys.OnlyBreakableByOwners.key, false);
config.addDefault(Keys.OnlyEditableByOwners.key, true);
config.options().copyDefaults(true);
}
public enum Keys {
PixelsPerBlock("pixelsPerBlock"),
LiveUpdate("liveUpdate"),
WorldGrassBorderWidth("worldGrassBorderWidth"),
HitboxOffset("hitboxOffset"),
DeleteOnBreak("deleteOnBreak"),
OnlyBreakableByOwners("onlyBreakableByOwners"),
OnlyEditableByOwners("onlyEditableByOwners");
private final String key;
Keys(@NotNull String key) {
this.key = key;
}
public @NotNull String getKey() {
return key;
}
}
}

View File

@ -1,6 +1,6 @@
package eu.mhsl.minecraft.pixelblocks; package eu.mhsl.minecraft.pixelblocks;
import eu.mhsl.minecraft.pixelblocks.pixelblock.Direction; import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -12,29 +12,27 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static eu.mhsl.minecraft.pixelblocks.PixelBlocks.plugin; public class PixelBlockDatabase {
public Connection db;
public class DataBase { public PixelBlockDatabase(String url) {
public static String url; try {
this.db = DriverManager.getConnection(url);
public DataBase(String url) { } catch (SQLException e) {
DataBase.url = url; throw new RuntimeException("Failed to load Database", e);
} }
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(url);
} }
public Statement getStatement() throws SQLException { public Statement getStatement() throws SQLException {
return getConnection().createStatement(); return this.db.createStatement();
} }
public void removePixelBlock(PixelBlock pixelBlock) { public void removePixelBlock(PixelBlock pixelBlock) {
Bukkit.getScheduler().runTask(plugin, () -> { Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> {
try (var conn = getConnection()) { try {
PreparedStatement prep = conn.prepareStatement("DELETE FROM pixelblocks WHERE uuid = ?"); PreparedStatement prep = this.db.prepareStatement("DELETE FROM pixelblocks WHERE uuid = ?");
prep.setString(1, pixelBlock.uuid.toString()); prep.setString(1, pixelBlock.blockUUID.toString());
prep.executeUpdate(); prep.executeUpdate();
prep.close(); prep.close();
@ -46,7 +44,7 @@ public class DataBase {
} }
public void savePixelBlock(PixelBlock pixelBlock) { public void savePixelBlock(PixelBlock pixelBlock) {
Bukkit.getScheduler().runTask(plugin, () -> { Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> {
List<UUID> uuids = new ArrayList<>(); List<UUID> uuids = new ArrayList<>();
try (var statement = getStatement()) { try (var statement = getStatement()) {
@ -58,17 +56,17 @@ public class DataBase {
System.err.println(e.getMessage()); System.err.println(e.getMessage());
} }
if(!uuids.contains(pixelBlock.uuid)) { if(!uuids.contains(pixelBlock.blockUUID)) {
try (var conn = getConnection()) { try {
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = this.db.prepareStatement(
"INSERT INTO pixelblocks(uuid, owner, " + "INSERT INTO pixelblocks(uuid, owner, " +
"locationWorldName, locationX, locationY, locationZ, " + "locationWorldName, locationX, locationY, locationZ, " +
"entryLocationWorldName, entryLocationX, entryLocationY, entryLocationZ, direction) " + "entryLocationWorldName, entryLocationX, entryLocationY, entryLocationZ, direction) " +
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
); );
prep.setString(1, pixelBlock.uuid.toString()); prep.setString(1, pixelBlock.blockUUID.toString());
prep.setString(2, pixelBlock.ownerUID.toString()); prep.setString(2, pixelBlock.ownerUUID.toString());
prep.setString(3, pixelBlock.pixelBlockLocation.getWorld().getName()); prep.setString(3, pixelBlock.pixelBlockLocation.getWorld().getName());
prep.setDouble(4, pixelBlock.pixelBlockLocation.getX()); prep.setDouble(4, pixelBlock.pixelBlockLocation.getX());
@ -87,7 +85,7 @@ public class DataBase {
prep.setDouble(10, Bukkit.getWorlds().getFirst().getSpawnLocation().getZ()); prep.setDouble(10, Bukkit.getWorlds().getFirst().getSpawnLocation().getZ());
} }
prep.setString(11, pixelBlock.direction.toString()); prep.setString(11, pixelBlock.facingDirection.toString());
prep.executeUpdate(); prep.executeUpdate();
prep.close(); prep.close();
@ -96,14 +94,14 @@ public class DataBase {
} }
} else { } else {
try (var conn = getConnection()) { try {
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = this.db.prepareStatement(
"UPDATE pixelblocks " + "UPDATE pixelblocks " +
"SET owner=?, locationWorldName=?, locationX=?, locationY=?, locationZ=?," + "SET owner=?, locationWorldName=?, locationX=?, locationY=?, locationZ=?," +
"entryLocationWorldName=?, entryLocationX=?, entryLocationY=?, entryLocationZ=?, direction=? " + "entryLocationWorldName=?, entryLocationX=?, entryLocationY=?, entryLocationZ=?, direction=? " +
"WHERE uuid=?;" "WHERE uuid=?;"
); );
prep.setString(1, pixelBlock.ownerUID.toString()); prep.setString(1, pixelBlock.ownerUUID.toString());
prep.setString(2, pixelBlock.pixelBlockLocation.getWorld().getName()); prep.setString(2, pixelBlock.pixelBlockLocation.getWorld().getName());
prep.setDouble(3, pixelBlock.pixelBlockLocation.getX()); prep.setDouble(3, pixelBlock.pixelBlockLocation.getX());
@ -122,8 +120,8 @@ public class DataBase {
prep.setDouble(9, Bukkit.getWorlds().getFirst().getSpawnLocation().getZ()); prep.setDouble(9, Bukkit.getWorlds().getFirst().getSpawnLocation().getZ());
} }
prep.setString(10, pixelBlock.uuid.toString()); prep.setString(10, pixelBlock.blockUUID.toString());
prep.setString(11, pixelBlock.direction.toString()); prep.setString(11, pixelBlock.facingDirection.toString());
prep.executeUpdate(); prep.executeUpdate();
prep.close(); prep.close();
@ -184,13 +182,12 @@ public class DataBase {
newPixelBlockLocation.getChunk().getEntities(); newPixelBlockLocation.getChunk().getEntities();
} }
entities.stream().filter(entity -> entity. entities.stream().filter(entity -> entity
getLocation(). .getLocation()
clone(). .add(0, PixelBlocksPlugin.configuration.hitboxOffset(), 0)
add(0, PixelBlock.hitboxOffset, 0). .toBlockLocation()
toBlockLocation(). .equals(newPixelBlockLocation))
equals(newPixelBlockLocation)). .forEach(Entity::remove);
forEach(Entity::remove);
PixelBlock newPixelBlock = new PixelBlock( PixelBlock newPixelBlock = new PixelBlock(
newPixelBlockLocation, newPixelBlockLocation,

View File

@ -0,0 +1,50 @@
package eu.mhsl.minecraft.pixelblocks;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public class PixelBlockItem {
public static @NotNull ItemStack getBlockAsItem(@NotNull PixelBlock block) {
ItemStack itemStack = ItemStack.of(Material.GRAY_STAINED_GLASS);
String ownerName = Optional.ofNullable(Bukkit.getOfflinePlayer(block.ownerUUID).getName()).orElseGet(() -> block.ownerUUID.toString());
ItemMeta meta = itemStack.getItemMeta();
meta.itemName(Component.text(block.blockUUID.toString()));
meta.displayName(Component.text("Pixelblock von " + ownerName));
meta.setEnchantmentGlintOverride(true);
itemStack.setItemMeta(meta);
return itemStack;
}
public static @NotNull ItemStack getEmptyPixelBlock() {
ItemStack item = ItemStack.of(Material.GRAY_STAINED_GLASS);
ItemMeta meta = item.getItemMeta();
meta.displayName(Component.text("Leerer Pixelblock"));
meta.setEnchantmentGlintOverride(true);
meta.itemName(Component.text("Pixelblock"));
item.setItemMeta(meta);
return item;
}
public static @NotNull Recipe getRecipe() {
NamespacedKey key = new NamespacedKey(PixelBlocksPlugin.plugin, "pixelblock");
ShapedRecipe recipe = new ShapedRecipe(key, getEmptyPixelBlock());
recipe.shape("ABA", "BCB", "ABA");
recipe.setIngredient('A', Material.DIAMOND_BLOCK);
recipe.setIngredient('B', Material.EMERALD_BLOCK);
recipe.setIngredient('C', Material.GRAY_STAINED_GLASS);
return recipe;
}
}

View File

@ -1,94 +0,0 @@
package eu.mhsl.minecraft.pixelblocks;
import eu.mhsl.minecraft.pixelblocks.commands.CreatePixelBlockCommand;
import eu.mhsl.minecraft.pixelblocks.commands.ExitWorldCommand;
import eu.mhsl.minecraft.pixelblocks.listeners.*;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.Objects;
public final class PixelBlocks extends JavaPlugin {
public static PixelBlocks plugin;
public static DataBase dataBase;
public static String pathSeparator;
public FileConfiguration config;
@Override
public void onEnable() {
PixelBlocks.plugin = this;
this.getLogger().info("PixelBlocks Plugin was enabled.");
pathSeparator = File.separator;
config = this.getConfig();
config.addDefault("pixelsPerBlock", 16);
config.addDefault("liveUpdate", true);
config.addDefault("worldGrassBorderWidth", 5);
config.addDefault("hitboxOffset", 0.005);
config.addDefault("deleteOnBreak", false);
config.addDefault("onlyBreakableByOwners", false);
config.addDefault("onlyEditableByOwners", true);
config.options().copyDefaults(true);
saveConfig();
PixelBlock.pixelsPerBlock = config.getInt("pixelsPerBlock");
PixelBlock.liveUpdate = config.getBoolean("liveUpdate");
PixelBlock.worldGrassBorderWidth = config.getInt("worldGrassBorderWidth");
PixelBlock.hitboxOffset = (float) config.getDouble("hitboxOffset");
PixelBlock.deleteOnBreak = config.getBoolean("deleteOnBreak");
PixelBlock.onlyBreakableByOwners = config.getBoolean("onlyBreakableByOwners");
PixelBlock.onlyEditableByOwners = config.getBoolean("onlyEditableByOwners");
dataBase = new DataBase("jdbc:sqlite:pixelblocks.db");
dataBase.loadPixelBlocks();
Listener[] listeners = {
new PlayerInteractListener(),
new PlayerMoveListener(),
new EntityDamageListener(),
new BlockBreakListener(),
new BlockPlaceListener(),
new CreatureSpawnListener(),
new EntityExplodeListener(),
new BlockExplodeListener(),
new PlayerPortalListener(),
new InventoryListener(),
new PlayerChangeWorldListener(),
new CraftItemListener()
};
for (Listener listener : listeners) {
getServer().getPluginManager().registerEvents(listener, plugin);
}
Objects.requireNonNull(getCommand("createpixelblock")).setExecutor(new CreatePixelBlockCommand());
Objects.requireNonNull(getCommand("exitworld")).setExecutor(new ExitWorldCommand());
ItemStack item = ItemStack.of(Material.GRAY_STAINED_GLASS);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName("Pixelblock");
meta.setEnchantmentGlintOverride(true);
meta.setItemName("Pixelblock");
item.setItemMeta(meta);
NamespacedKey key = new NamespacedKey(this, "pixelblock");
ShapedRecipe recipe = new ShapedRecipe(key, item);
recipe.shape("ABA", "BCB", "ABA");
recipe.setIngredient('A', Material.DIAMOND_BLOCK);
recipe.setIngredient('B', Material.EMERALD_BLOCK);
recipe.setIngredient('C', Material.GRAY_STAINED_GLASS);
Bukkit.addRecipe(recipe);
}
}

View File

@ -0,0 +1,68 @@
package eu.mhsl.minecraft.pixelblocks;
import eu.mhsl.minecraft.pixelblocks.commands.CreatePixelBlockCommand;
import eu.mhsl.minecraft.pixelblocks.commands.ExitWorldCommand;
import eu.mhsl.minecraft.pixelblocks.listeners.*;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public final class PixelBlocksPlugin extends JavaPlugin {
public static PixelBlocksPlugin plugin;
public static PixelBlockConfiguration configuration;
public static PixelBlockDatabase database;
public static List<PixelBlock> placedPixelBlocks = new ArrayList<>();
@Override
public void onLoad() {
PixelBlocksPlugin.plugin = this;
FileConfiguration config = this.getConfig();
PixelBlockConfiguration.setDefaults(config);
this.saveConfig();
PixelBlocksPlugin.configuration = new PixelBlockConfiguration(
config.getInt(PixelBlockConfiguration.Keys.PixelsPerBlock.getKey()),
config.getBoolean(PixelBlockConfiguration.Keys.LiveUpdate.getKey()),
config.getInt(PixelBlockConfiguration.Keys.WorldGrassBorderWidth.getKey()),
config.getDouble(PixelBlockConfiguration.Keys.HitboxOffset.getKey()),
config.getBoolean(PixelBlockConfiguration.Keys.DeleteOnBreak.getKey()),
config.getBoolean(PixelBlockConfiguration.Keys.OnlyBreakableByOwners.getKey()),
config.getBoolean(PixelBlockConfiguration.Keys.OnlyEditableByOwners.getKey())
);
PixelBlocksPlugin.database = new PixelBlockDatabase("jdbc:sqlite:pixelblocks.db");
}
@Override
public void onEnable() {
database.loadPixelBlocks();
Listener[] listeners = {
new PlayerInteractListener(),
new PlayerMoveListener(),
// new BlockBreakListener(),
new BlockPlaceListener(),
new InventoryListener(),
new PlayerChangeWorldListener(),
new CraftItemListener(),
new InPixelWorldCancelListener()
};
for (Listener listener : listeners) {
getServer().getPluginManager().registerEvents(listener, plugin);
}
Objects.requireNonNull(getCommand("createpixelblock")).setExecutor(new CreatePixelBlockCommand());
Objects.requireNonNull(getCommand("exitworld")).setExecutor(new ExitWorldCommand());
Bukkit.addRecipe(PixelBlockItem.getRecipe());
}
}

View File

@ -1,6 +1,6 @@
package eu.mhsl.minecraft.pixelblocks.commands; package eu.mhsl.minecraft.pixelblocks.commands;
import eu.mhsl.minecraft.pixelblocks.pixelblock.Direction; import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -24,7 +24,7 @@ public class CreatePixelBlockCommand implements CommandExecutor {
if(Arrays.stream(standardWorlds).toList().contains(playerWorld)) { if(Arrays.stream(standardWorlds).toList().contains(playerWorld)) {
Location playerLocation = p.getLocation(); Location playerLocation = p.getLocation();
PixelBlock pixelBlock = new PixelBlock(playerLocation, p.getUniqueId(), UUID.randomUUID()); PixelBlock pixelBlock = new PixelBlock(playerLocation, p.getUniqueId(), UUID.randomUUID());
pixelBlock.place(playerLocation, Direction.POSITIVE_Z); pixelBlock.place(playerLocation, Direction.south);
} else { } else {
p.sendMessage("Du kannst nur in der Overworld oder im Nether Pixelblocks erstellen!"); p.sendMessage("Du kannst nur in der Overworld oder im Nether Pixelblocks erstellen!");
} }

View File

@ -1,5 +1,6 @@
package eu.mhsl.minecraft.pixelblocks.commands; package eu.mhsl.minecraft.pixelblocks.commands;
import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -21,8 +22,8 @@ public class ExitWorldCommand implements CommandExecutor {
if(!Arrays.stream(standardWorlds).toList().contains(playerWorld)) { if(!Arrays.stream(standardWorlds).toList().contains(playerWorld)) {
List<PixelBlock> ownedBlocks = PixelBlock.placedPixelBlocks.stream() List<PixelBlock> ownedBlocks = PixelBlocksPlugin.placedPixelBlocks.stream()
.filter(pixelBlock -> pixelBlock.ownerUID.equals(p.getUniqueId())) .filter(pixelBlock -> pixelBlock.ownerUUID.equals(p.getUniqueId()))
.sorted(Comparator.comparing(pixelBlock -> pixelBlock.lastEntryTime)) .sorted(Comparator.comparing(pixelBlock -> pixelBlock.lastEntryTime))
.toList(); .toList();

View File

@ -1,18 +1,18 @@
package eu.mhsl.minecraft.pixelblocks.listeners; //package eu.mhsl.minecraft.pixelblocks.listeners;
//
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; //import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import org.bukkit.event.EventHandler; //import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; //import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent; //import org.bukkit.event.block.BlockBreakEvent;
//
public class BlockBreakListener implements Listener { //public class BlockBreakListener implements Listener {
@EventHandler // @EventHandler
static void onBlockBreak(BlockBreakEvent event) { // static void onBlockBreak(BlockBreakEvent event) {
if(CommonEventHandlers.isInPixelWorld(event.getBlock().getWorld())) { // if(CommonEventHandlers.isInPixelWorld(event.getBlock().getWorld())) {
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromWorld(event.getBlock().getLocation().getWorld()); // PixelBlock pixelBlock = PixelBlock.getPixelBlockFromWorld(event.getBlock().getLocation().getWorld());
//
assert pixelBlock != null; // assert pixelBlock != null;
pixelBlock.handleBlockBreak(event); // pixelBlock.handleBlockBreak(event);
} // }
} // }
} //}

View File

@ -1,12 +0,0 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockExplodeEvent;
public class BlockExplodeListener implements Listener {
@EventHandler
static void onBlockExplode(BlockExplodeEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getBlock().getWorld());
}
}

View File

@ -1,6 +1,7 @@
package eu.mhsl.minecraft.pixelblocks.listeners; package eu.mhsl.minecraft.pixelblocks.listeners;
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 org.bukkit.World; import org.bukkit.World;
@ -15,6 +16,7 @@ import java.util.UUID;
public class BlockPlaceListener implements Listener { public class BlockPlaceListener implements Listener {
@EventHandler @EventHandler
static void onBlockPlace(BlockPlaceEvent event) { static void onBlockPlace(BlockPlaceEvent event) {
if(event.getItemInHand().getItemMeta().getDisplayName().contains("Pixelblock") if(event.getItemInHand().getItemMeta().getDisplayName().contains("Pixelblock")
&& !event.getItemInHand().getItemMeta().getItemName().isEmpty() && !event.getItemInHand().getItemMeta().getItemName().isEmpty()
&& event.getItemInHand().getItemMeta().getEnchantmentGlintOverride()) { && event.getItemInHand().getItemMeta().getEnchantmentGlintOverride()) {
@ -33,7 +35,7 @@ public class BlockPlaceListener implements Listener {
} }
PixelBlock pixelBlock = new PixelBlock(newBlockLocation, event.getPlayer().getUniqueId(), UUID.fromString(event.getItemInHand().getItemMeta().getItemName())); PixelBlock pixelBlock = new PixelBlock(newBlockLocation, event.getPlayer().getUniqueId(), UUID.fromString(event.getItemInHand().getItemMeta().getItemName()));
if(pixelBlock.place(newBlockLocation, PixelBlock.vectorToDirection(event.getPlayer().getLocation().getDirection()))) { if(pixelBlock.place(newBlockLocation, Direction.vectorToDirection(event.getPlayer().getLocation().getDirection()))) {
event.getPlayer().getInventory().remove(event.getItemInHand()); event.getPlayer().getInventory().remove(event.getItemInHand());
} else { } else {
event.getPlayer().sendMessage("Hier wurde bereits ein Pixelblock plaziert."); event.getPlayer().sendMessage("Hier wurde bereits ein Pixelblock plaziert.");
@ -42,12 +44,12 @@ public class BlockPlaceListener implements Listener {
event.getPlayer().sendMessage("Du kannst nur in der Overworld oder im Nether Pixelblocks platzieren!"); event.getPlayer().sendMessage("Du kannst nur in der Overworld oder im Nether Pixelblocks platzieren!");
} }
} else { } else {
if(CommonEventHandlers.isInPixelWorld(event.getBlock().getWorld())) { // if(CommonEventHandlers.isInPixelWorld(event.getBlock().getWorld())) {
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromWorld(event.getBlock().getLocation().getWorld()); // PixelBlock pixelBlock = PixelBlock.getPixelBlockFromWorld(event.getBlock().getLocation().getWorld());
//
assert pixelBlock != null; // assert pixelBlock != null;
pixelBlock.handleBlockPlace(event); // pixelBlock.handleBlockPlace(event);
} // }
} }
} }
} }

View File

@ -6,12 +6,12 @@ import org.bukkit.event.Cancellable;
import java.util.List; import java.util.List;
import static eu.mhsl.minecraft.pixelblocks.PixelBlocks.plugin; import static eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin.plugin;
public class CommonEventHandlers { public class CommonEventHandlers {
public static boolean isInPixelWorld(World world) { public static boolean isInPixelWorld(World world) {
List<World> standardWorlds = Bukkit.getWorlds().stream() List<World> standardWorlds = Bukkit.getWorlds().stream()
.filter(world1 -> !world1.getName().startsWith(plugin.getDataFolder().getPath())) .filter(w -> !w.getName().startsWith(plugin.getDataFolder().getPath()))
.toList(); .toList();
return !standardWorlds.contains(world); return !standardWorlds.contains(world);

View File

@ -1,12 +0,0 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
public class CreatureSpawnListener implements Listener {
@EventHandler
static void onCreatureSpawn(CreatureSpawnEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getLocation().getWorld());
}
}

View File

@ -1,12 +0,0 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
public class EntityDamageListener implements Listener {
@EventHandler
static void onEntityDamage(EntityDamageEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getEntity().getWorld());
}
}

View File

@ -1,12 +0,0 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
public class EntityExplodeListener implements Listener {
@EventHandler
static void onEntityExplode(EntityExplodeEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getLocation().getWorld());
}
}

View File

@ -0,0 +1,42 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerPortalEvent;
public class InPixelWorldCancelListener implements Listener {
@EventHandler
static void onBlockExplode(BlockExplodeEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getBlock().getWorld());
}
@EventHandler
static void onCreatureSpawn(CreatureSpawnEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getLocation().getWorld());
}
@EventHandler
static void onEntityDamage(EntityDamageEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getEntity().getWorld());
}
@EventHandler
static void onEntityExplode(EntityExplodeEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getLocation().getWorld());
}
@EventHandler
static void onPlayerDropItem(PlayerDropItemEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getItemDrop().getWorld());
}
@EventHandler
static void onPlayerPortal(PlayerPortalEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getFrom().getWorld());
}
}

View File

@ -12,7 +12,7 @@ public class PlayerChangeWorldListener implements Listener {
static void onPlayerChangeWorld(PlayerChangedWorldEvent event) { static void onPlayerChangeWorld(PlayerChangedWorldEvent event) {
if(CommonEventHandlers.isInPixelWorld(event.getFrom())) { if(CommonEventHandlers.isInPixelWorld(event.getFrom())) {
// Bukkit.getScheduler().runTaskLater(plugin, () -> Objects.requireNonNull(PixelBlock.getPixelBlockFromWorld(event.getFrom())).update(), 60); // Bukkit.getScheduler().runTaskLater(plugin, () -> Objects.requireNonNull(PixelBlock.getPixelBlockFromWorld(event.getFrom())).update(), 60);
Objects.requireNonNull(PixelBlock.getPixelBlockFromWorld(event.getFrom())).update(); Objects.requireNonNull(PixelBlock.getPixelBlockFromBlockWorld(event.getFrom())).update();
} }
} }
} }

View File

@ -1,12 +0,0 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerDropItemEvent;
public class PlayerDropItemListener implements Listener {
@EventHandler
static void onPlayerDropItem(PlayerDropItemEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getItemDrop().getWorld());
}
}

View File

@ -1,5 +1,6 @@
package eu.mhsl.minecraft.pixelblocks.listeners; package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import io.papermc.paper.event.player.PrePlayerAttackEntityEvent; import io.papermc.paper.event.player.PrePlayerAttackEntityEvent;
import org.bukkit.*; import org.bukkit.*;
@ -12,28 +13,28 @@ public class PlayerInteractListener implements Listener {
@EventHandler @EventHandler
static void onPlayerInteractEntity(PlayerInteractEntityEvent event) { static void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if(event.getRightClicked() instanceof Interaction) { if(event.getRightClicked() instanceof Interaction) {
Location interactionLocation = event.getRightClicked().getLocation().clone().add(0, PixelBlock.hitboxOffset, 0).toBlockLocation(); Location interactionLocation = event.getRightClicked().getLocation().clone().add(0, PixelBlocksPlugin.configuration.hitboxOffset(), 0).toBlockLocation();
interactionLocation.setYaw(0); interactionLocation.setYaw(0);
interactionLocation.setPitch(0); interactionLocation.setPitch(0);
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromLocation(interactionLocation); PixelBlock pixelBlock = PixelBlock.getPixelBlockFromPlacedLocation(interactionLocation);
assert pixelBlock != null; assert pixelBlock != null;
pixelBlock.handleInteraction(event.getPlayer()); pixelBlock.enterBlock(event.getPlayer());
} }
} }
@EventHandler @EventHandler
static void onPlayerAttackEntity(PrePlayerAttackEntityEvent event) { static void onPlayerAttackEntity(PrePlayerAttackEntityEvent event) {
if(event.getAttacked() instanceof Interaction) { if(event.getAttacked() instanceof Interaction) {
Location blockLocation = event.getAttacked().getLocation().add(0, PixelBlock.hitboxOffset, 0).toBlockLocation(); Location blockLocation = event.getAttacked().getLocation().add(0, PixelBlocksPlugin.configuration.hitboxOffset(), 0).toBlockLocation();
blockLocation.setYaw(0); blockLocation.setYaw(0);
blockLocation.setPitch(0); blockLocation.setPitch(0);
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromLocation(blockLocation); PixelBlock pixelBlock = PixelBlock.getPixelBlockFromPlacedLocation(blockLocation);
assert pixelBlock != null; assert pixelBlock != null;
pixelBlock.handleAttack(event.getPlayer()); pixelBlock.destroy(event.getPlayer());
} }
} }
} }

View File

@ -11,12 +11,12 @@ public class PlayerMoveListener implements Listener {
static void onPlayerMove(PlayerMoveEvent event) { static void onPlayerMove(PlayerMoveEvent event) {
if(CommonEventHandlers.isInPixelWorld(event.getPlayer().getWorld())) { if(CommonEventHandlers.isInPixelWorld(event.getPlayer().getWorld())) {
Location playerLocation = event.getPlayer().getLocation(); Location playerLocation = event.getPlayer().getLocation();
PixelBlock pixelBlock = PixelBlock.getPixelBlockFromWorld(event.getPlayer().getWorld()); PixelBlock pixelBlock = PixelBlock.getPixelBlockFromBlockWorld(event.getPlayer().getWorld());
assert pixelBlock != null; assert pixelBlock != null;
Location portalLocation = pixelBlock.getPortalLocation().clone(); Location portalLocation = pixelBlock.getPixelWorld().getPortalLocation().clone();
if(playerLocation.y() < -65) { if(playerLocation.y() < -65) {
event.getPlayer().teleport(pixelBlock.getPlayerSpawnLocation(event.getPlayer())); event.getPlayer().teleport(pixelBlock.getPixelWorld().getSpawnLocation());
} else if(playerLocation.getZ() < portalLocation.getZ()+1 } else if(playerLocation.getZ() < portalLocation.getZ()+1
&& playerLocation.getZ() > portalLocation.getZ()) { && playerLocation.getZ() > portalLocation.getZ()) {
if(playerLocation.getX() < portalLocation.getX()+3 if(playerLocation.getX() < portalLocation.getX()+3

View File

@ -1,12 +0,0 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerPortalEvent;
public class PlayerPortalListener implements Listener {
@EventHandler
static void onPlayerPortal(PlayerPortalEvent event) {
CommonEventHandlers.cancelIfInPixelWorld(event, event.getFrom().getWorld());
}
}

View File

@ -1,8 +0,0 @@
package eu.mhsl.minecraft.pixelblocks.pixelblock;
public enum Direction {
POSITIVE_X,
POSITIVE_Z,
NEGATIVE_X,
NEGATIVE_Z
}

View File

@ -1,23 +1,26 @@
package eu.mhsl.minecraft.pixelblocks.pixelblock; package eu.mhsl.minecraft.pixelblocks.pixelblock;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.entity.BlockDisplay; import org.bukkit.entity.BlockDisplay;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.util.Transformation; import org.bukkit.util.Transformation;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public class Pixel { public class Pixel {
public Location relativeLocation; public final Location relativeLocation;
public BlockData blockData; public final BlockData blockData;
double scale; private final double scale;
double offset;
public UUID uuid; private @Nullable UUID uuid;
public Pixel(Location relativeLocation, BlockData blockData, double scale, double offset) { public Pixel(@NotNull Location relativeLocation, @NotNull BlockData blockData, double scale) {
this.relativeLocation = new Location( this.relativeLocation = new Location(
relativeLocation.getWorld(), relativeLocation.getWorld(),
relativeLocation.x(), relativeLocation.x(),
@ -26,31 +29,28 @@ public class Pixel {
); );
this.blockData = blockData; this.blockData = blockData;
this.scale = scale; this.scale = scale;
this.offset = offset;
} }
public void spawn(Location spawnBlockLocation) { public void place(@NotNull Location spawnBlockLocation) {
double positionX = spawnBlockLocation.x()+relativeLocation.x()*scale+offset; World world = spawnBlockLocation.getWorld();
double positionY = spawnBlockLocation.y()+relativeLocation.y()*scale+offset; double positionX = spawnBlockLocation.x() + (relativeLocation.x()*scale);
double positionZ = spawnBlockLocation.z()+relativeLocation.z()*scale+offset; double positionY = spawnBlockLocation.y() + (relativeLocation.y()*scale);
double positionZ = spawnBlockLocation.z() + (relativeLocation.z()*scale);
Location spawnLocation = new Location(spawnBlockLocation.getWorld(), positionX, positionY, positionZ); Location spawnLocation = new Location(world, positionX, positionY, positionZ);
BlockDisplay bd = (BlockDisplay) spawnLocation.getWorld().spawnEntity( BlockDisplay entity = (BlockDisplay) world.spawnEntity(spawnLocation, EntityType.BLOCK_DISPLAY);
spawnLocation, this.uuid = entity.getUniqueId();
EntityType.BLOCK_DISPLAY
);
bd.setBlock(blockData); entity.setBlock(blockData);
Transformation transform = bd.getTransformation(); Transformation transform = entity.getTransformation();
transform.getScale().set(scale); transform.getScale().set(scale);
bd.setTransformation(transform); entity.setTransformation(transform);
this.uuid = bd.getUniqueId();
} }
public void remove() { public void destroy() {
Objects.requireNonNull(this.uuid);
Entity pixelEntity = this.relativeLocation.getWorld().getEntity(this.uuid); Entity pixelEntity = this.relativeLocation.getWorld().getEntity(this.uuid);
if(pixelEntity != null) pixelEntity.remove(); if(pixelEntity != null) pixelEntity.remove();
} }

View File

@ -1,308 +1,110 @@
package eu.mhsl.minecraft.pixelblocks.pixelblock; package eu.mhsl.minecraft.pixelblocks.pixelblock;
import eu.mhsl.minecraft.pixelblocks.PixelBlocks; import eu.mhsl.minecraft.pixelblocks.PixelBlockItem;
import eu.mhsl.minecraft.pixelblocks.chunkGenerators.EmptyChunkGenerator; import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.utils.MinMaxUtil;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.entity.*; import org.bukkit.entity.*;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.codehaus.plexus.util.FileUtils; import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.*; import java.util.*;
import static eu.mhsl.minecraft.pixelblocks.PixelBlocks.*;
import static java.lang.Math.abs;
public class PixelBlock { public class PixelBlock {
public static List<PixelBlock> placedPixelBlocks = new ArrayList<>(); private final PixelBlockWorld pixelWorld;
public static float hitboxOffset = 0.005F;
public static int worldGrassBorderWidth = 5; private final float hitboxOffset = (float) PixelBlocksPlugin.configuration.hitboxOffset();
public static int pixelsPerBlock = 16; private final int pixelsPerBlock = PixelBlocksPlugin.configuration.pixelsPerBlock();
public static boolean liveUpdate = true;
public static boolean deleteOnBreak = false;
public static boolean onlyBreakableByOwners = false;
public static boolean onlyEditableByOwners = true;
public Location pixelBlockLocation; public Location pixelBlockLocation;
public Direction direction; public Direction facingDirection;
public ArrayList<Pixel> pixels = new ArrayList<>(); public ArrayList<Pixel> pixels = new ArrayList<>();
public Interaction hitbox; public Interaction hitbox;
public ItemDisplay barrier; public ItemDisplay barrier;
public long lastEntryTime; public long lastEntryTime;
public Location lastEntryLocation; public Location lastEntryLocation;
public UUID ownerUID; public UUID ownerUUID;
public UUID uuid; public UUID blockUUID;
public PixelBlock(Location originLocation, UUID ownerUID, UUID blockUUID) { public static @NotNull String getWorldName(@NotNull PixelBlock pixelBlock) {
this.uuid = blockUUID; return PixelBlocksPlugin.plugin.getDataFolder().getPath() + File.separator + pixelBlock.blockUUID;
}
public static @Nullable PixelBlock getPixelBlockFromBlockWorld(World world) {
return PixelBlocksPlugin.placedPixelBlocks.stream()
.filter(block -> block.blockUUID.equals(getUUIDFromWorld(world)))
.findFirst()
.orElse(null);
}
public static @Nullable UUID getUUIDFromWorld(@NotNull World world) {
try {
return UUID.fromString(List.of(world.getName().split("/")).getLast());
} catch (IllegalArgumentException e) {
return null;
}
}
public static @Nullable PixelBlock getPixelBlockFromPlacedLocation(@NotNull Location placedLocation) {
Location searchLocation = placedLocation.clone().toBlockLocation();
searchLocation.setPitch(0);
searchLocation.setYaw(0);
return PixelBlocksPlugin.placedPixelBlocks.stream()
.filter(block -> block.pixelBlockLocation.equals(searchLocation))
.findFirst()
.orElse(null);
}
public PixelBlock(Location originLocation, UUID ownerUUID, UUID blockUUID) {
this.ownerUUID = ownerUUID;
this.blockUUID = blockUUID;
this.pixelBlockLocation = originLocation.toBlockLocation(); this.pixelBlockLocation = originLocation.toBlockLocation();
this.direction = Direction.POSITIVE_Z;
this.pixelBlockLocation.setYaw(0); this.pixelBlockLocation.setYaw(0);
this.pixelBlockLocation.setPitch(0); this.pixelBlockLocation.setPitch(0);
this.ownerUID = ownerUID;
createPixelWorld(); this.facingDirection = Direction.south; // TODO ??
this.pixelWorld = new PixelBlockWorld(this);
} }
public static PixelBlock getPixelBlockFromWorld(World world) { public void enterBlock(@NotNull Player player) {
String blockUUID = Arrays.stream(world.getName().split(pathSeparator)).toList().getLast(); if(PixelBlocksPlugin.configuration.onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) {
List<PixelBlock> pixelBlocks = placedPixelBlocks.stream().filter(block -> block.uuid.toString().equals(blockUUID)).toList();
if(!pixelBlocks.isEmpty()) {
return pixelBlocks.getFirst();
} else {
return null;
}
}
public static PixelBlock getPixelBlockFromLocation(Location location) {
Location loc = location.clone().toBlockLocation();
loc.setPitch(0);
loc.setYaw(0);
List<PixelBlock> pixelBlocks = placedPixelBlocks.stream()
.filter(block -> block.pixelBlockLocation.equals(loc))
.toList();
if(pixelBlocks.isEmpty()) {
return null;
} else {
return pixelBlocks.getFirst();
}
}
public static String getWorldPathFromPixelblock(PixelBlock pixelBlock) {
return plugin.getDataFolder().getPath() + pathSeparator + pixelBlock.uuid.toString();
}
public static Direction vectorToDirection(Vector vector) {
if(abs(vector.getX()) > abs(vector.getZ())) {
if(vector.getX() >= 0) {
return Direction.POSITIVE_X;
} else {
return Direction.NEGATIVE_X;
}
} else {
if(vector.getZ() >= 0) {
return Direction.POSITIVE_Z;
} else {
return Direction.NEGATIVE_Z;
}
}
}
void createPixelWorld() {
File file = new File(getWorldPathFromPixelblock(this));
final WorldCreator worldCreator = new WorldCreator(getWorldPathFromPixelblock(this));
if(!file.exists() || !file.isDirectory()) {
worldCreator.type(WorldType.FLAT);
worldCreator.generator(new EmptyChunkGenerator());
World newWorld = Bukkit.createWorld(worldCreator);
assert newWorld != null;
newWorld.setGameRule(GameRule.RANDOM_TICK_SPEED, 0);
newWorld.setGameRule(GameRule.DO_FIRE_TICK, false);
newWorld.setGameRule(GameRule.DO_MOB_SPAWNING, false);
newWorld.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
newWorld.setGameRule(GameRule.DO_VINES_SPREAD, false);
newWorld.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
Location borderStartLocation = newWorld.getSpawnLocation().clone().subtract(1, 1, 1);
Location grassStartLocation = borderStartLocation.clone().subtract(worldGrassBorderWidth, 0, worldGrassBorderWidth);
Bukkit.getScheduler().runTask(plugin, () -> {
for (int x = 0; x < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; x++) {
for (int z = 0; z < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; z++) {
grassStartLocation.clone().add(x, 0, z).getBlock().setType(Material.GRASS_BLOCK);
}
}
for (int x = 0; x < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; x++) {
for (int z = 0; z < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; z++) {
grassStartLocation.clone().add(x, -1, z).getBlock().setType(Material.DIRT);
}
}
for (int x = 0; x < (pixelsPerBlock+2); x++) {
for (int z = 0; z < (pixelsPerBlock+2); z++) {
Location currentLocation = borderStartLocation.clone().add(x, 0, z);
if (currentLocation.x() == borderStartLocation.x() || currentLocation.z() == borderStartLocation.z()) {
currentLocation.getBlock().setType(Material.RED_CONCRETE);
} else if (currentLocation.x() == borderStartLocation.x() + (pixelsPerBlock+1) || currentLocation.z() == borderStartLocation.z() + (pixelsPerBlock+1)) {
currentLocation.getBlock().setType(Material.RED_CONCRETE);
}
}
}
for (int x = (2*worldGrassBorderWidth+pixelsPerBlock-1)/2; x < (2*worldGrassBorderWidth+pixelsPerBlock-1)/2+4; x++) {
for (int y = 0; y < 5; y++) {
grassStartLocation.clone().add(x, 1+y, 0).getBlock().setType(Material.OBSIDIAN);
}
}
for (int x = (2*worldGrassBorderWidth+pixelsPerBlock-1)/2+1; x < (2*worldGrassBorderWidth+pixelsPerBlock-1)/2+3; x++) {
for (int y = 1; y < 4; y++) {
grassStartLocation.clone().add(x, 1+y, 0).getBlock().setType(Material.NETHER_PORTAL);
}
}
});
} else {
worldCreator.createWorld();
}
}
public ItemStack getAsItem() {
ItemStack itemStack = ItemStack.of(Material.GRAY_STAINED_GLASS);
ItemMeta meta = itemStack.getItemMeta();
meta.setDisplayName("Pixelblock von " + Objects.requireNonNull(Bukkit.getPlayer(this.ownerUID)).getName());
meta.setEnchantmentGlintOverride(true);
meta.setItemName(this.uuid.toString());
itemStack.setItemMeta(meta);
return itemStack;
}
public void handleInteraction(Player player) {
if(onlyEditableByOwners && !player.getUniqueId().equals(ownerUID)) {
player.sendMessage("Dieser Pixelblock gehört nicht dir!"); player.sendMessage("Dieser Pixelblock gehört nicht dir!");
return; return;
} }
this.lastEntryLocation = player.getLocation(); this.lastEntryLocation = player.getLocation();
this.lastEntryTime = System.currentTimeMillis(); this.lastEntryTime = System.currentTimeMillis();
dataBase.savePixelBlock(this); PixelBlocksPlugin.database.savePixelBlock(this);
player.teleport(getPlayerSpawnLocation(player)); player.teleport(this.pixelWorld.getSpawnLocation());
}
public void handleAttack(Player player) {
if(onlyBreakableByOwners && !player.getUniqueId().equals(ownerUID)) {
player.sendMessage("Dieser Pixelblock gehört nicht dir!");
return;
}
World world = Objects.requireNonNull(this.getPixelWorld());
world.getPlayers().forEach(
player1 -> {
player1.sendMessage("Der Pixelblock wurde abgebaut!");
player1.teleport(this.lastEntryLocation);
}
);
world.getEntities().forEach(entity -> entity.teleport(this.lastEntryLocation));
if(deleteOnBreak) {
this.delete();
} else {
this.remove();
this.pixelBlockLocation.getWorld().playSound(this.pixelBlockLocation, Sound.BLOCK_COPPER_BULB_BREAK, 1.0F, 30);
this.pixelBlockLocation.getWorld().dropItem(this.pixelBlockLocation, this.getAsItem());
}
}
public void handleBlockBreak(BlockBreakEvent event) {
Location blockLocation = event.getBlock().getLocation();
Location spawnLocation = blockLocation.getWorld().getSpawnLocation();
if(blockLocation.x() < spawnLocation.x() || blockLocation.z() < spawnLocation.z() || blockLocation.y() < spawnLocation.y()) {
event.setCancelled(true);
return;
} else if(blockLocation.x() > spawnLocation.x()+(pixelsPerBlock-1) || blockLocation.z() > spawnLocation.z()+(pixelsPerBlock-1) || blockLocation.y() > spawnLocation.y()+(pixelsPerBlock-1)) {
event.setCancelled(true);
return;
}
Bukkit.getScheduler().runTask(plugin, () -> {
if(liveUpdate) {
Location relativeLocation = blockLocation.subtract(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ());
relativeLocation.setWorld(this.pixelBlockLocation.getWorld());
List<Pixel> pixels = this.pixels.stream().filter(pixel -> pixel.relativeLocation.equals(relativeLocation)).toList();
if(!pixels.isEmpty()) {
Pixel pixel = pixels.getFirst();
pixel.remove();
this.pixels.remove(pixel);
}
}
});
}
public void handleBlockPlace(BlockPlaceEvent event) {
Location blockLocation = event.getBlock().getLocation();
Location spawnLocation = blockLocation.getWorld().getSpawnLocation();
if(blockLocation.x() < spawnLocation.x() || blockLocation.z() < spawnLocation.z() || blockLocation.y() < spawnLocation.y()) {
event.setCancelled(true);
return;
} else if(blockLocation.x() > spawnLocation.x()+(pixelsPerBlock-1) || blockLocation.z() > spawnLocation.z()+(pixelsPerBlock-1) || blockLocation.y() > spawnLocation.y()+(pixelsPerBlock-1)) {
event.setCancelled(true);
return;
}
Bukkit.getScheduler().runTask(PixelBlocks.plugin, () -> {
if(liveUpdate) {
Location relativeLocation = blockLocation.subtract(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ());
relativeLocation.setWorld(this.pixelBlockLocation.getWorld());
Pixel newPixel = new Pixel(relativeLocation, event.getBlock().getBlockData(), ((double) 1 /pixelsPerBlock), 0);
this.pixels.add(newPixel);
newPixel.spawn(this.pixelBlockLocation);
}
});
}
public Location getPlayerSpawnLocation(Player player) {
Location spawnLocation = getPixelWorld().getSpawnLocation().clone().add((double) pixelsPerBlock/2, 0, 1.5-worldGrassBorderWidth);
// spawnLocation.setYaw(player.getLocation().getYaw());
// spawnLocation.setPitch(player.getLocation().getPitch());
return spawnLocation;
}
public Location getPortalLocation() {
return getPixelWorld().getSpawnLocation().clone().add((double) pixelsPerBlock/2 -2, 0, -worldGrassBorderWidth-1);
}
public World getPixelWorld() {
return Bukkit.getWorld(getWorldPathFromPixelblock(this));
} }
public void spawnInteraction(boolean fullBlock) { public void spawnInteraction(boolean fullBlock) {
if(fullBlock || pixels.isEmpty()) { if(fullBlock) {
hitbox = (Interaction) pixelBlockLocation.getWorld().spawnEntity( hitbox = (Interaction) pixelBlockLocation.getWorld().spawnEntity(
pixelBlockLocation.clone().add(0.5, -hitboxOffset, 0.5), pixelBlockLocation.clone().add(0.5, -hitboxOffset, 0.5),
EntityType.INTERACTION EntityType.INTERACTION
); );
hitbox.setInteractionHeight(1F + 2*hitboxOffset); hitbox.setInteractionHeight(1 + 2*hitboxOffset);
hitbox.setInteractionWidth(1F + 2*hitboxOffset); hitbox.setInteractionWidth(1 + 2*hitboxOffset);
} else { } else {
double startingX = this.pixels.stream() double startingX = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getX());
.min(Comparator.comparing(pixel -> pixel.relativeLocation.getX())) double startingY = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getY());
.orElseThrow().relativeLocation.getX(); double startingZ = MinMaxUtil.getMinProperty(this.pixels, pixel -> pixel.relativeLocation.getZ());
double startingY = this.pixels.stream()
.min(Comparator.comparing(pixel -> pixel.relativeLocation.getY()))
.orElseThrow().relativeLocation.getY();
double startingZ = this.pixels.stream()
.min(Comparator.comparing(pixel -> pixel.relativeLocation.getZ()))
.orElseThrow().relativeLocation.getZ();
double endingX = this.pixels.stream() double endingX = MinMaxUtil.getMaxProperty(this.pixels, pixel -> pixel.relativeLocation.getX());
.max(Comparator.comparing(pixel -> pixel.relativeLocation.getX())) double endingY = MinMaxUtil.getMaxProperty(this.pixels, pixel -> pixel.relativeLocation.getY());
.orElseThrow().relativeLocation.getX(); double endingZ = MinMaxUtil.getMaxProperty(this.pixels, pixel -> pixel.relativeLocation.getZ());
double endingY = this.pixels.stream()
.max(Comparator.comparing(pixel -> pixel.relativeLocation.getY()))
.orElseThrow().relativeLocation.getY();
double endingZ = this.pixels.stream()
.max(Comparator.comparing(pixel -> pixel.relativeLocation.getZ()))
.orElseThrow().relativeLocation.getZ();
Location spawnLocation = pixelBlockLocation.clone().add( Location spawnLocation = pixelBlockLocation.clone().add(
((startingX+endingX+1)/2)/pixelsPerBlock, ((startingX+endingX+1)/2)/pixelsPerBlock,
@ -344,27 +146,24 @@ public class PixelBlock {
} }
public void update() { public void update() {
Bukkit.getScheduler().runTask(plugin, () -> { Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> {
this.clearEntities(true); this.clearEntities();
for (int x = 0; x < pixelsPerBlock; x++) { for (int x = 0; x < pixelsPerBlock; x++) {
for (int y = 0; y < pixelsPerBlock; y++) { for (int y = 0; y < pixelsPerBlock; y++) {
for (int z = 0; z < pixelsPerBlock; z++) { for (int z = 0; z < pixelsPerBlock; z++) {
Location relativeLocation = new Location(pixelBlockLocation.getWorld(), x, y, z); Location relativeLocation = new Location(pixelBlockLocation.getWorld(), x, y, z);
Location blockLocation = Objects.requireNonNull(Bukkit Location blockLocation = this.pixelWorld.getBuildOrigin();
.getWorld(getWorldPathFromPixelblock(this))) switch (this.facingDirection) {
.getSpawnLocation() case south -> blockLocation.add(relativeLocation.x(), relativeLocation.y(), relativeLocation.z());
.clone(); case north -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.x(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.z());
switch (this.direction) { case east -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.z(), relativeLocation.y(), relativeLocation.x());
case POSITIVE_Z -> blockLocation.add(relativeLocation.x(), relativeLocation.y(), relativeLocation.z()); case west -> blockLocation.add(relativeLocation.z(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.x());
case NEGATIVE_Z -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.x(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.z());
case POSITIVE_X -> blockLocation.add((pixelsPerBlock-1)-relativeLocation.z(), relativeLocation.y(), relativeLocation.x());
case NEGATIVE_X -> blockLocation.add(relativeLocation.z(), relativeLocation.y(), (pixelsPerBlock-1)-relativeLocation.x());
} }
BlockData block = blockLocation.getBlock().getBlockData(); BlockData block = blockLocation.getBlock().getBlockData();
if(block.getMaterial() != Material.AIR) { if(block.getMaterial() != Material.AIR) {
Pixel newPixel = new Pixel(relativeLocation, block, ((double) 1 /pixelsPerBlock), 0); Pixel newPixel = new Pixel(relativeLocation, block, ((double) 1 /pixelsPerBlock));
pixels.add(newPixel); pixels.add(newPixel);
} }
} }
@ -372,15 +171,15 @@ public class PixelBlock {
} }
for(Pixel pixel : this.pixels) { for(Pixel pixel : this.pixels) {
pixel.spawn(this.pixelBlockLocation); pixel.place(this.pixelBlockLocation);
} }
if(this.pixels.size() < 5) { if(this.pixels.size() < 5) {
Location relativeLocation = new Location(pixelBlockLocation.getWorld(), 0, 0, 0); Location relativeLocation = new Location(pixelBlockLocation.getWorld(), 0, 0, 0);
BlockData block = Material.GRAY_STAINED_GLASS.createBlockData(); BlockData block = Material.GRAY_STAINED_GLASS.createBlockData();
Pixel newPixel = new Pixel(relativeLocation, block, 1, 0); Pixel newPixel = new Pixel(relativeLocation, block, 1);
pixels.add(newPixel); pixels.add(newPixel);
newPixel.spawn(this.pixelBlockLocation); newPixel.place(this.pixelBlockLocation);
Location itemDisplayLocation = this.pixelBlockLocation.clone().add(0.5, 0.5, 0.5); Location itemDisplayLocation = this.pixelBlockLocation.clone().add(0.5, 0.5, 0.5);
this.barrier = (ItemDisplay) this.pixelBlockLocation.getWorld().spawnEntity( this.barrier = (ItemDisplay) this.pixelBlockLocation.getWorld().spawnEntity(
@ -396,17 +195,52 @@ public class PixelBlock {
}); });
} }
public void clearEntities(boolean secure) { public boolean place(Location placeLocation, Direction direction) {
if(!this.pixelBlockLocation.getChunk().isEntitiesLoaded()) { Location newLocation = placeLocation.toBlockLocation();
this.pixelBlockLocation.getChunk().load(true); newLocation.setPitch(0);
this.pixelBlockLocation.getChunk().getEntities(); newLocation.setYaw(0);
if(PixelBlock.getPixelBlockFromPlacedLocation(newLocation) == null || PixelBlock.getPixelBlockFromPlacedLocation(newLocation) == this) {
this.pixelBlockLocation = newLocation;
this.facingDirection = direction;
update();
PixelBlocksPlugin.database.savePixelBlock(this);
PixelBlocksPlugin.placedPixelBlocks.add(this);
return true;
}
return false;
} }
if(!pixels.isEmpty()) { public void destroy(Player destroyedBy) {
this.pixels.forEach(Pixel::remove); if(PixelBlocksPlugin.configuration.onlyBreakableByOwner() && !destroyedBy.getUniqueId().equals(ownerUUID)) {
this.pixels.clear(); destroyedBy.sendMessage("Dieser Pixelblock gehört nicht dir!");
return;
} }
this.pixelWorld.getPlayersInWorld().forEach(p -> {
p.sendMessage("Der Pixelblock wurde abgebaut!");
p.teleport(this.lastEntryLocation);
});
this.pixelWorld.getEntitiesInWorld().forEach(entity -> entity.teleport(this.lastEntryLocation));
this.clearEntities();
PixelBlocksPlugin.database.removePixelBlock(this);
PixelBlocksPlugin.placedPixelBlocks.remove(this);
this.pixelBlockLocation.getWorld().playSound(this.pixelBlockLocation, Sound.BLOCK_COPPER_BULB_BREAK, 1.0F, 30);
this.pixelBlockLocation.getWorld().dropItem(this.pixelBlockLocation.add(new Vector(0.5, 0.5, 0.5)), PixelBlockItem.getBlockAsItem(this));
}
private void clearEntities() {
Chunk chunk = this.pixelBlockLocation.getChunk();
if(!chunk.isEntitiesLoaded()) {
chunk.load(true);
chunk.getEntities();
}
this.pixels.forEach(Pixel::destroy);
this.pixels.clear();
if(hitbox != null) { if(hitbox != null) {
this.hitbox.remove(); this.hitbox.remove();
this.hitbox = null; this.hitbox = null;
@ -417,59 +251,23 @@ public class PixelBlock {
this.barrier = null; this.barrier = null;
} }
if(secure) { this.pixelBlockLocation.getWorld().getEntities().stream()
List<Entity> entities = new ArrayList<>(); .filter(this::isRelevantEntity)
entities.addAll(Bukkit.getWorlds().get(0).getEntities().stream() .filter(entity -> entity.getLocation()
.filter(entity -> entity.getType().equals(EntityType.BLOCK_DISPLAY) || entity.getType().equals(EntityType.INTERACTION) || entity.getType().equals(EntityType.ITEM_DISPLAY)) .add(0, hitboxOffset, 0)
.toList()); .toBlockLocation()
entities.addAll(Bukkit.getWorlds().get(1).getEntities().stream() .equals(this.pixelBlockLocation))
.filter(entity -> entity.getType().equals(EntityType.BLOCK_DISPLAY) || entity.getType().equals(EntityType.INTERACTION) || entity.getType().equals(EntityType.ITEM_DISPLAY)) .forEach(Entity::remove);
.toList());
entities.addAll(Bukkit.getWorlds().get(2).getEntities().stream()
.filter(entity -> entity.getType().equals(EntityType.BLOCK_DISPLAY) || entity.getType().equals(EntityType.INTERACTION) || entity.getType().equals(EntityType.ITEM_DISPLAY))
.toList());
entities.stream().filter(entity -> entity.
getLocation().
clone().
add(0, PixelBlock.hitboxOffset, 0).
toBlockLocation().
equals(this.pixelBlockLocation)).
forEach(Entity::remove);
}
} }
public boolean place(Location placeLocation, Direction direction) { private boolean isRelevantEntity(Entity entity) {
Location newLocation = placeLocation.toBlockLocation(); return entity.getType().equals(EntityType.BLOCK_DISPLAY)
newLocation.setPitch(0); || entity.getType().equals(EntityType.INTERACTION)
newLocation.setYaw(0); || entity.getType().equals(EntityType.ITEM_DISPLAY);
if(PixelBlock.getPixelBlockFromLocation(newLocation) == null || PixelBlock.getPixelBlockFromLocation(newLocation) == this) {
this.pixelBlockLocation = newLocation;
this.direction = direction;
update();
dataBase.savePixelBlock(this);
placedPixelBlocks.add(this);
return true;
}
return false;
} }
public void remove() {
dataBase.removePixelBlock(this);
clearEntities(true); public PixelBlockWorld getPixelWorld() {
placedPixelBlocks.remove(this); return pixelWorld;
}
public void delete() {
this.remove();
Bukkit.unloadWorld(getPixelWorld(), true);
try {
FileUtils.deleteDirectory(getWorldPathFromPixelblock(this));
} catch (IOException e) {
System.err.println("World could not be deleted: " + e.getMessage());
}
} }
} }

View File

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

View File

@ -0,0 +1,124 @@
package eu.mhsl.minecraft.pixelblocks.pixelblock;
import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import eu.mhsl.minecraft.pixelblocks.chunkGenerators.EmptyChunkGenerator;
import org.bukkit.*;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.List;
import java.util.Objects;
import static eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin.plugin;
public class PixelBlockWorld {
private final PixelBlock parentPixelBlock;
private final World world;
int worldGrassBorderWidth = PixelBlocksPlugin.configuration.worldGrassBorderWidth();
int pixelsPerBlock = PixelBlocksPlugin.configuration.pixelsPerBlock();
public static boolean isPixelWorld(@NotNull World world) {
return world.getName().startsWith(plugin.getDataFolder().getPath());
}
public static @NotNull List<World> getOtherWorlds() {
return Bukkit.getWorlds().stream().filter(w -> !PixelBlockWorld.isPixelWorld(w)).toList();
}
public static @NotNull List<World> getPixelBlockWorlds() {
return Bukkit.getWorlds().stream().filter(PixelBlockWorld::isPixelWorld).toList();
}
public PixelBlockWorld(PixelBlock parentPixelBlock) {
this.parentPixelBlock = parentPixelBlock;
this.world = this.loadOrCreatePixelWorld();
this.setBuildingPlatform();
}
public @NotNull String getWorldPathName() {
return PixelBlocksPlugin.plugin.getDataFolder().getPath() + File.separator + this.parentPixelBlock.blockUUID;
}
public @NotNull Location getSpawnLocation() {
return this.getPortalLocation().add(1.5, 1, 2.5);
}
public @NotNull Location getPortalLocation() {
return this.getBuildOrigin().add((double) pixelsPerBlock/2 -2, 0, -worldGrassBorderWidth);
}
public @NotNull List<Player> getPlayersInWorld() {
return this.world.getPlayers();
}
public @NotNull List<Entity> getEntitiesInWorld() {
return this.world.getEntities();
}
public @NotNull Location getBuildOrigin() {
return new Location(this.world, 0, -60, 0);
}
private World loadOrCreatePixelWorld() {
final WorldCreator worldCreator = new WorldCreator(getWorldPathName());
worldCreator.type(WorldType.FLAT);
worldCreator.generator(new EmptyChunkGenerator());
World world = Bukkit.createWorld(worldCreator);
Objects.requireNonNull(world);
world.setGameRule(GameRule.RANDOM_TICK_SPEED, 0);
world.setGameRule(GameRule.DO_FIRE_TICK, false);
world.setGameRule(GameRule.DO_MOB_SPAWNING, false);
world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
world.setGameRule(GameRule.DO_VINES_SPREAD, false);
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
WorldBorder worldBorder = world.getWorldBorder();
worldBorder.setCenter(getBuildOrigin());
return world;
}
private void setBuildingPlatform() {
Location borderStartLocation = getBuildOrigin().subtract(1, 1, 1);
Location grassStartLocation = borderStartLocation.clone().subtract(worldGrassBorderWidth, 0, worldGrassBorderWidth);
Bukkit.getScheduler().runTask(PixelBlocksPlugin.plugin, () -> {
for (int x = 0; x < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; x++) {
for (int z = 0; z < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; z++) {
grassStartLocation.clone().add(x, 0, z).getBlock().setType(Material.GRASS_BLOCK);
}
}
for (int x = 0; x < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; x++) {
for (int z = 0; z < (pixelsPerBlock+2) + 2 * worldGrassBorderWidth; z++) {
grassStartLocation.clone().add(x, -1, z).getBlock().setType(Material.DIRT);
}
}
for (int x = 0; x < (pixelsPerBlock+2); x++) {
for (int z = 0; z < (pixelsPerBlock+2); z++) {
Location currentLocation = borderStartLocation.clone().add(x, 0, z);
if (currentLocation.x() == borderStartLocation.x() || currentLocation.z() == borderStartLocation.z()) {
currentLocation.getBlock().setType(Material.RED_CONCRETE);
} else if (currentLocation.x() == borderStartLocation.x() + (pixelsPerBlock+1) || currentLocation.z() == borderStartLocation.z() + (pixelsPerBlock+1)) {
currentLocation.getBlock().setType(Material.RED_CONCRETE);
}
}
}
for (int x = (2*worldGrassBorderWidth+pixelsPerBlock-1)/2; x < (2*worldGrassBorderWidth+pixelsPerBlock-1)/2+4; x++) {
for (int y = 0; y < 5; y++) {
grassStartLocation.clone().add(x, 1+y, 0).getBlock().setType(Material.OBSIDIAN);
}
}
for (int x = (2*worldGrassBorderWidth+pixelsPerBlock-1)/2+1; x < (2*worldGrassBorderWidth+pixelsPerBlock-1)/2+3; x++) {
for (int y = 1; y < 4; y++) {
grassStartLocation.clone().add(x, 1+y, 0).getBlock().setType(Material.NETHER_PORTAL);
}
}
});
}
}

View File

@ -0,0 +1,26 @@
package eu.mhsl.minecraft.pixelblocks.utils;
import org.bukkit.util.Vector;
public enum Direction {
north,
east,
south,
west;
public static Direction vectorToDirection(Vector vector) {
if(Math.abs(vector.getX()) > Math.abs(vector.getZ())) {
if(vector.getX() >= 0) {
return east;
} else {
return west;
}
} else {
if(vector.getZ() >= 0) {
return south;
} else {
return north;
}
}
}
}

View File

@ -0,0 +1,14 @@
package eu.mhsl.minecraft.pixelblocks.utils;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
public class MinMaxUtil {
public static <I, O extends Comparable<O>> O getMinProperty(List<I> list, Function<I, O> supplier) {
return supplier.apply(list.stream().min(Comparator.comparing(supplier)).orElseThrow());
}
public static <I, O extends Comparable<O>> O getMaxProperty(List<I> list, Function<I, O> supplier) {
return supplier.apply(list.stream().max(Comparator.comparing(supplier)).orElseThrow());
}
}

View File

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