From 8f5f8807540b4b616297f1f21f3d8db5837f47a5 Mon Sep 17 00:00:00 2001 From: Marc Baloup Date: Sun, 22 Dec 2024 23:44:46 +0100 Subject: [PATCH] More complete Javadoc --- .../pandacube/lib/bungee/chat/ChatBungee.java | 3 + .../pandacube/lib/chat/LegacyChatFormat.java | 142 +++++++++++++++--- .../lib/paper/backup/PaperBackupConfig.java | 46 ++++++ .../lib/paper/backup/PaperBackupManager.java | 15 +- .../lib/paper/geometry/DirectionalVector.java | 20 ++- .../lib/paper/geometry/GeometryUtil.java | 63 ++++---- .../lib/paper/geometry/blocks/AABBBlock.java | 94 ++++++++---- .../paper/geometry/blocks/AABBBlockGroup.java | 18 ++- .../lib/paper/geometry/blocks/BlockSet.java | 97 +++++++++++- .../fr/pandacube/lib/paper/gui/GUIHotBar.java | 14 +- .../pandacube/lib/paper/gui/GUIInventory.java | 16 +- .../util/BedrockBambooCollisionFixer.java | 20 ++- .../pandacube/lib/paper/world/ChunkCoord.java | 35 +++++ .../lib/paper/world/RegionCoord.java | 28 ++++ 14 files changed, 517 insertions(+), 94 deletions(-) diff --git a/pandalib-bungee-chat/src/main/java/fr/pandacube/lib/bungee/chat/ChatBungee.java b/pandalib-bungee-chat/src/main/java/fr/pandacube/lib/bungee/chat/ChatBungee.java index b0aa1f8..60e6701 100644 --- a/pandalib-bungee-chat/src/main/java/fr/pandacube/lib/bungee/chat/ChatBungee.java +++ b/pandalib-bungee-chat/src/main/java/fr/pandacube/lib/bungee/chat/ChatBungee.java @@ -7,6 +7,9 @@ import net.kyori.adventure.text.ComponentLike; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import net.md_5.bungee.api.chat.BaseComponent; +/** + * Utility class to ease conversion between our Adventure backed Chat API and BungeeCord chat API. + */ public class ChatBungee { diff --git a/pandalib-chat/src/main/java/fr/pandacube/lib/chat/LegacyChatFormat.java b/pandalib-chat/src/main/java/fr/pandacube/lib/chat/LegacyChatFormat.java index 3bfc866..f2d6807 100644 --- a/pandalib-chat/src/main/java/fr/pandacube/lib/chat/LegacyChatFormat.java +++ b/pandalib-chat/src/main/java/fr/pandacube/lib/chat/LegacyChatFormat.java @@ -11,36 +11,107 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.stream.Collectors; +/** + * Convenient enum to uses legacy format while keeping compatibility with modern chat format and API (Adventure, ...) + */ public enum LegacyChatFormat { + /** + * Black (0) color format code. + */ BLACK('0'), + /** + * Dark blue (1) color format code. + */ DARK_BLUE('1'), + /** + * Dark green (2) color format code. + */ DARK_GREEN('2'), + /** + * Dark aqua (3) color format code. + */ DARK_AQUA('3'), + /** + * Dark red (4) color format code. + */ DARK_RED('4'), + /** + * Dark purple (5) color format code. + */ DARK_PURPLE('5'), + /** + * Gold (6) color format code. + */ GOLD('6'), + /** + * Gray (7) color format code. + */ GRAY('7'), + /** + * Dark gray (8) color format code. + */ DARK_GRAY('8'), + /** + * Blue (9) color format code. + */ BLUE('9'), + /** + * Green (A) color format code. + */ GREEN('a'), + /** + * Aqua (B) color format code. + */ AQUA('b'), + /** + * Red (C) color format code. + */ RED('c'), + /** + * Light purple (D) color format code. + */ LIGHT_PURPLE('d'), + /** + * Yellow (E) color format code. + */ YELLOW('e'), + /** + * White (F) color format code. + */ WHITE('f'), - MAGIC('k'), + /** + * Obfuscated (K) decoration format code. + */ + OBFUSCATED('k'), + /** + * Bold (L) decoration format code. + */ BOLD('l'), + /** + * Strikethrough (M) decoration format code. + */ STRIKETHROUGH('m'), + /** + * Underlined (N) decoration format code. + */ UNDERLINED('n'), + /** + * Italic (O) decoration format code. + */ ITALIC('o'), + /** + * Reset (R) format code. + */ RESET('r'); - - - + /** + * The character used by Minecraft for legacy chat format. + */ public static final char COLOR_CHAR = LegacyComponentSerializer.SECTION_CHAR; + + /** {@link #COLOR_CHAR} but as a String! */ public static final String COLOR_STR_PREFIX = Character.toString(COLOR_CHAR); private static final Map BY_CHAR; @@ -48,10 +119,20 @@ public enum LegacyChatFormat { private static final Map BY_LEGACY; + /** + * Gets the {@link LegacyChatFormat} from the provided chat color code. + * @param code the character code from [0-9A-Fa-fK-Ok-oRr]. + * @return the {@link LegacyChatFormat} related to the provided code. + */ public static LegacyChatFormat of(char code) { return BY_CHAR.get(Character.toLowerCase(code)); } + /** + * Gets the {@link LegacyChatFormat} from the provided {@link TextFormat} instance. + * @param format the {@link TextFormat} instance. + * @return the {@link LegacyChatFormat} related to the provided format. + */ public static LegacyChatFormat of(TextFormat format) { LegacyChatFormat colorOrDecoration = BY_FORMAT.get(format); if (colorOrDecoration != null) @@ -61,19 +142,24 @@ public enum LegacyChatFormat { throw new IllegalArgumentException("Unsupported format of type " + format.getClass()); } + /** + * Gets the {@link LegacyChatFormat} from the provided {@link LegacyFormat} instance. + * @param advLegacy the {@link LegacyFormat} instance. + * @return the {@link LegacyChatFormat} related to the provided format. + */ public static LegacyChatFormat of(LegacyFormat advLegacy) { return BY_LEGACY.get(advLegacy); } - - - - - - - + /** + * The format code of this chat format. + */ public final char code; + + /** + * The Adventure legacy format instance related to this chat format. + */ public final LegacyFormat advLegacyFormat; LegacyChatFormat(char code) { @@ -81,22 +167,42 @@ public enum LegacyChatFormat { advLegacyFormat = LegacyComponentSerializer.parseChar(code); } + /** + * Gets the related {@link TextColor}, or null if it's not a color. + * @return the related {@link TextColor}, or null if it's not a color. + */ public TextColor getTextColor() { return advLegacyFormat.color(); } + /** + * Tells if this format is a color. + * @return true if this format is a color, false otherwise. + */ public boolean isColor() { return getTextColor() != null; } + /** + * Gets the related {@link TextDecoration}, or null if it's not a decoration. + * @return the related {@link TextDecoration}, or null if it's not a decoration. + */ public TextDecoration getTextDecoration() { return advLegacyFormat.decoration(); } + /** + * Tells if this format is a decoration (bold, italic, ...). + * @return true if this format is a decoration, false otherwise. + */ public boolean isDecoration() { return getTextDecoration() != null; } + /** + * Tells if this format is the reset. + * @return true if this format is the reset, false otherwise. + */ public boolean isReset() { return this == RESET; } @@ -109,14 +215,16 @@ public enum LegacyChatFormat { static { - BY_CHAR = Arrays.stream(values()).sequential().collect(Collectors.toMap(e -> e.code, e -> e, (e1, e2) -> e1, LinkedHashMap::new)); + BY_CHAR = Arrays.stream(values()).sequential() + .collect(Collectors.toMap(e -> e.code, e -> e, (e1, e2) -> e1, LinkedHashMap::new)); BY_FORMAT = Arrays.stream(values()).sequential() .filter(e -> e.isColor() || e.isDecoration()) .collect(Collectors.toMap(e -> { - if (e.isColor()) - return e.getTextColor(); - return e.getTextDecoration(); - }, e -> e, (e1, e2) -> e1, LinkedHashMap::new)); - BY_LEGACY = Arrays.stream(values()).sequential().collect(Collectors.toMap(e -> e.advLegacyFormat, e -> e, (e1, e2) -> e1, LinkedHashMap::new)); + if (e.isColor()) + return e.getTextColor(); + return e.getTextDecoration(); + }, e -> e, (e1, e2) -> e1, LinkedHashMap::new)); + BY_LEGACY = Arrays.stream(values()).sequential() + .collect(Collectors.toMap(e -> e.advLegacyFormat, e -> e, (e1, e2) -> e1, LinkedHashMap::new)); } } diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/backup/PaperBackupConfig.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/backup/PaperBackupConfig.java index 20aeb9d..f685d0f 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/backup/PaperBackupConfig.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/backup/PaperBackupConfig.java @@ -6,14 +6,60 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +/** + * A basic class holding configuration for {@link PaperBackupManager}. + */ @SuppressWarnings("CanBeFinal") public class PaperBackupConfig { + + /** + * Set to true to enable worlds backup. + * Defaults to true. + */ public boolean worldBackupEnabled = true; + + /** + * Set to true to enable the backup of the working directory. + * The workdir backup will already ignore the logs directory and any world folder (folder with a level.dat file in it). + * Defaults to true. + */ public boolean workdirBackupEnabled = true; + + /** + * Set to true to enable the backup of logs. + * Defaults to true. + */ public boolean logsBackupEnabled = true; + + /** + * The cron-formatted scheduling of the worlds and workdir backups. + * The default value is {@code "0 2 * * *"}, that is every day at 2am. + */ public String scheduling = "0 2 * * *"; // cron format, here is every day at 2am + + /** + * The backup target directory. + * Must be set (defaults to null). + */ public File backupDirectory = null; + + /** + * The backup cleaner for the worlds backup. + * Defaults to keep 1 backup every 3 month + the last 5 backups. + */ public BackupCleaner worldBackupCleaner = BackupCleaner.KEEPING_1_EVERY_N_MONTH(3).merge(BackupCleaner.KEEPING_N_LAST(5)); + + /** + * The backup cleaner for the workdir backup. + * Defaults to keep 1 backup every 3 month + the last 5 backups. + */ public BackupCleaner workdirBackupCleaner = BackupCleaner.KEEPING_1_EVERY_N_MONTH(3).merge(BackupCleaner.KEEPING_N_LAST(5)); + + /** + * The list of files or directory to ignore. + * Defaults to none. + * The workdir backup will already ignore the logs directory and any world folder (folder with a level.dat file in it). + */ public List workdirIgnoreList = new ArrayList<>(); + } diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/backup/PaperBackupManager.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/backup/PaperBackupManager.java index b986eb8..7a4d144 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/backup/PaperBackupManager.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/backup/PaperBackupManager.java @@ -23,12 +23,19 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CancellationException; +/** + * The backup manager for Paper servers. + */ public class PaperBackupManager extends BackupManager implements Listener { private final Map compressWorlds = new HashMap<>(); PaperBackupConfig config; - + + /** + * Instantiate a new backup manager. + * @param config the configuration of the backups. + */ public PaperBackupManager(PaperBackupConfig config) { super(config.backupDirectory); setConfig(config); @@ -49,13 +56,17 @@ public class PaperBackupManager extends BackupManager implements Listener { super.addProcess(process); } + /** + * Updates the backups config + * @param config the new config. + */ public void setConfig(PaperBackupConfig config) { this.config = config; backupQueue.forEach(this::updateProcessConfig); } - public void updateProcessConfig(BackupProcess process) { + private void updateProcessConfig(BackupProcess process) { if (process instanceof PaperWorkdirProcess) { process.setEnabled(config.workdirBackupEnabled); process.setBackupCleaner(config.workdirBackupCleaner); diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/DirectionalVector.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/DirectionalVector.java index fc03511..14a8f15 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/DirectionalVector.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/DirectionalVector.java @@ -63,6 +63,7 @@ public class DirectionalVector { * contained in the provided {@link Location}. * {@link Location#getYaw()} and {@link Location#getPitch()} values are automatically * converted to conform {@link #yaw} and {@link #pitch} specification. + * @param l the location. */ public DirectionalVector(Location l) { this( @@ -79,6 +80,7 @@ public class DirectionalVector { /** + * Creates a new {@link DirectionalVector} from a simple {@link Vector}. * @param v the vector representing the direction. If v.getX() and v.getZ() are 0, * the yaw will be 0. This may have inconsistency if the vector is calculated * from a {@link Location}'s yaw and pitch. In this case, prefer using @@ -126,7 +128,10 @@ public class DirectionalVector { } - + /** + * Gets a Vector using the internal X, Y and Z values, that is a simple directional 3D vector. + * @return this vector as a simple 3D {@link Vector}. + */ public Vector toVector() { return new Vector(x, y, z); } @@ -135,7 +140,8 @@ public class DirectionalVector { /** * Set the yaw and the pitch of the provided {@link Location} * with the values inside the current {@link DirectionalVector} - * after conversion of these values + * after conversion of these values. + * @param l the location. */ public void putIntoLocation(Location l) { /* std : -PI/2 : <0 ? +2PI : MC @@ -148,7 +154,10 @@ public class DirectionalVector { l.setPitch((float) Math.toDegrees(-pitch)); } - + /** + * Gets the vector pointing to the opposite direction. + * @return the opposite vector. + */ public DirectionalVector getOpposite() { return new DirectionalVector( -x, @@ -163,6 +172,7 @@ public class DirectionalVector { * If the current direction is the player face direction, * this method return the direction of the back of the head. * This is an alias of {@link #getOpposite()} + * @return the opposite of this vector. */ public DirectionalVector getBackDirection() { return getOpposite(); @@ -171,6 +181,7 @@ public class DirectionalVector { /** * If the current direction is the player face direction, * this method return the direction of the bottom of the head. + * @return the vector pointing on the bottom, as if this vector was the front orientation of a player head. */ public DirectionalVector getBottomDirection() { return new DirectionalVector( @@ -182,6 +193,7 @@ public class DirectionalVector { /** * If the current direction is the player face direction, * this method return the direction of the top of the head. + * @return the vector pointing on the top, as if this vector was the front orientation of a player head. */ public DirectionalVector getTopDirection() { return new DirectionalVector( @@ -194,6 +206,7 @@ public class DirectionalVector { /** * If the current direction is the player face direction, * this method return the direction of the left of the head. + * @return the vector pointing on the left, as if this vector was the front orientation of a player head. */ public DirectionalVector getLeftDirection() { return new DirectionalVector( @@ -206,6 +219,7 @@ public class DirectionalVector { /** * If the current direction is the player face direction, * this method return the direction of the right of the head. + * @return the vector pointing on the right, as if this vector was the front orientation of a player head. */ public DirectionalVector getRightDirection() { return new DirectionalVector( diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/GeometryUtil.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/GeometryUtil.java index d58c62b..3aafd4e 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/GeometryUtil.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/GeometryUtil.java @@ -2,24 +2,29 @@ package fr.pandacube.lib.paper.geometry; import org.bukkit.Location; import org.bukkit.entity.Player; +import org.bukkit.util.BoundingBox; +import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; +/** + * Utility class related to geometry and Minecraft. + */ public class GeometryUtil { - + /** * Value equal to {@link Math#PI}. */ - public static final double PI = Math.PI; - + static final double PI = Math.PI; + /** * Value equal to {@link Math#PI} / 2. */ - public static final double PId2 = PI/2; - + static final double PId2 = PI/2; + /** * Value equal to {@link Math#PI} * 2. */ - public static final double PIx2 = PI*2; + static final double PIx2 = PI*2; @@ -55,9 +60,21 @@ public class GeometryUtil { * Value provided by net.minecraft.world.entity.player.Player#getStandingEyeHeight */ public static final double PLAYER_EYE_HEIGHT_SNEAK = 1.27; + /** + * The size of a skin pixel. + */ public static final double PLAYER_SKIN_PIXEL_SIZE = PLAYER_SKIN_HEIGHT / 32; + /** + * The height of the center of rotation of the head, that is the distance between neck and the player's foot. + */ public static final double PLAYER_HEAD_ROTATION_HEIGHT = PLAYER_SKIN_PIXEL_SIZE * 24; + /** + * The height of the center of rotation of the head, that is the distance between neck and the player's foot, but when the player is sneaking. + */ public static final double PLAYER_HEAD_ROTATION_HEIGHT_SNEAK = PLAYER_HEAD_ROTATION_HEIGHT - (PLAYER_SKIN_HEIGHT - PLAYER_SKIN_HEIGHT_SNEAK); + /** + * The size of the first layer of the players head. + */ public static final double PLAYER_HEAD_SIZE = PLAYER_SKIN_PIXEL_SIZE * 8; @@ -67,7 +84,6 @@ public class GeometryUtil { - @@ -76,7 +92,7 @@ public class GeometryUtil { /** * Get the {@link Location}s of the 8 vertex of the player head
* This method only work if the player is standing up - * (not dead, not gliding, not sleeping). + * (not dead, not gliding, not sleeping, not swimming). * @param playerLocation the location of the player, generally provided by {@link Player#getLocation()} * @param isSneaking if the player is sneaking. Generally {@link Player#isSneaking()} * @return an array of 8 {@link Location}s with x, y, and z values filled (yaw and pitch are ignored). @@ -129,27 +145,22 @@ public class GeometryUtil { /** * Check if the path from start location to end pass through * the axis aligned bounding box defined by min and max. + * @param start the start of the path. + * @param end the end of the path. + * @param min the min of the bounding box. + * @param max the max of the bounding box. + * @return true if the path intersects the bounding box. + * @deprecated use {@link BoundingBox#rayTrace(Vector, Vector, double)} instead. */ + @Deprecated public static boolean hasIntersection(Vector start, Vector end, Vector min, Vector max) { - final double epsilon = 0.0001f; - - Vector d = end.clone().subtract(start).multiply(0.5); - Vector e = max.clone().subtract(min).multiply(0.5); - Vector c = start.clone().add(d).subtract(min.clone().add(max).multiply(0.5)); - Vector ad = d.clone(); - ad.setX(Math.abs(ad.getX())); - ad.setY(Math.abs(ad.getY())); - ad.setZ(Math.abs(ad.getZ())); - - return !( - Math.abs(c.getX()) > e.getX() + ad.getX() - || Math.abs(c.getY()) > e.getY() + ad.getY() - || Math.abs(c.getZ()) > e.getX() + ad.getZ() - || Math.abs(d.getY() * c.getZ() - d.getZ() * c.getY()) > e.getY() * ad.getZ() + e.getZ() * ad.getY() + epsilon - || Math.abs(d.getZ() * c.getX() - d.getX() * c.getZ()) > e.getZ() * ad.getX() + e.getX() * ad.getZ() + epsilon - || Math.abs(d.getX() * c.getY() - d.getY() * c.getX()) > e.getX() * ad.getY() + e.getY() * ad.getX() + epsilon - ); + RayTraceResult res = BoundingBox.of(min, max).rayTrace(start, end.clone().subtract(start), end.distance(start)); + return res != null; } + + private GeometryUtil() {} + + } diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/AABBBlock.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/AABBBlock.java index 28bad5c..dc72c11 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/AABBBlock.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/AABBBlock.java @@ -2,11 +2,10 @@ package fr.pandacube.lib.paper.geometry.blocks; import fr.pandacube.lib.util.RandomUtil; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.Block; import org.bukkit.util.BlockVector; import org.bukkit.util.BoundingBox; import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; import java.util.Iterator; @@ -30,10 +29,19 @@ public class AABBBlock implements BlockSet, Cloneable { volume = original.volume; } + /** + * Construct a {@link AABBBlock} based on the two provided Bukkit's {@link Vector}. + * @param p1 the first vector. + * @param p2 the second vector. + */ public AABBBlock(Vector p1, Vector p2) { this(p1.getBlockX(), p1.getBlockY(), p1.getBlockZ(), p2.getBlockX(), p2.getBlockY(), p2.getBlockZ()); } + /** + * Construct a {@link AABBBlock} based on the provided Bukkit's {@link BoundingBox}. + * @param bb the bounding box. + */ public AABBBlock(BoundingBox bb) { pos1 = bb.getMin(); pos2 = bb.getMax(); @@ -41,15 +49,35 @@ public class AABBBlock implements BlockSet, Cloneable { volume = (int) bb.getVolume(); bukkitBoundingBox = bb; } - + + /** + * Construct a {@link AABBBlock} based on the two provided Bukkit's {@link Location}. + * The worlds defined in the provided locations are ignored. + * @param l1 the first location. + * @param l2 the second location. + */ public AABBBlock(Location l1, Location l2) { this(l1.getBlockX(), l1.getBlockY(), l1.getBlockZ(), l2.getBlockX(), l2.getBlockY(), l2.getBlockZ()); } - + + /** + * Construct a {@link AABBBlock} based on the two provided Bukkit's {@link BlockVector}. + * @param l1 the first block vector. + * @param l2 the second block vector. + */ public AABBBlock(BlockVector l1, BlockVector l2) { this(l1.getBlockX(), l1.getBlockY(), l1.getBlockZ(), l2.getBlockX(), l2.getBlockY(), l2.getBlockZ()); } - + + /** + * Construct a {@link AABBBlock} based on the individual coordinates of the 2 vectors. + * @param p1x the x value of the first vector. + * @param p1y the y value of the first vector. + * @param p1z the z value of the first vector. + * @param p2x the x value of the second vector. + * @param p2y the y value of the second vector. + * @param p2z the z value of the second vector. + */ public AABBBlock(int p1x, int p1y, int p1z, int p2x, int p2y, int p2z) { /* * Prends les points extérieurs permettant de former un bounding box englobant @@ -74,22 +102,45 @@ public class AABBBlock implements BlockSet, Cloneable { return this; } + /** + * Gets the value of the "minimum" {@link Vector}, that is the vector with the lowest coordinates that is inside this bounding box. + * @return the minimum vector. + */ public Vector getMin() { return pos1.clone(); } + /** + * Gets the value of the "maximum" {@link Vector}, that is the vector with the highest coordinates that is inside this bounding box. + * @return the maximum vector. + */ public Vector getMax() { return pos2.clone(); } + /** + * Gets the {@link BlockVector} with the lowest coordinates in this bounding box. + * @return the minimum block vector. + */ public BlockVector getMinBlock() { return pos1.toBlockVector(); } + /** + * Gets the {@link BlockVector} with the highest coordinates in this bounding box. + * @return the maximum block vector. + */ public BlockVector getMaxBlock() { return pos2.clone().add(new Vector(-1, -1, -1)).toBlockVector(); } + /** + * Gets a new {@link AABBBlock} with its coordinates shifted by the provided amount. + * @param x the x shift. + * @param y the y shift. + * @param z the z shift. + * @return a shifted bounding box. + */ public AABBBlock shift(int x, int y, int z) { return new AABBBlock(this, x, y, z); } @@ -101,7 +152,6 @@ public class AABBBlock implements BlockSet, Cloneable { } - public boolean overlaps(BoundingBox bb) { return asBukkitBoundingBox().overlaps(bb); } @@ -109,15 +159,23 @@ public class AABBBlock implements BlockSet, Cloneable { public boolean isInside(Vector v) { return asBukkitBoundingBox().contains(v); } - + + /** + * Gets the coordinate of the center of this bounding box. + * @return the center of this bounding box. + */ public Vector getCenter() { return center.clone(); } - + public long getVolume() { return volume; } - + + /** + * Gets the Bukkit equivalent of this bounding box. + * @return a {@link BoundingBox} corresponding to this {@link AABBBlock}. + */ public BoundingBox asBukkitBoundingBox() { if (bukkitBoundingBox == null) { bukkitBoundingBox = new BoundingBox(pos1.getX(), pos1.getY(), pos1.getZ(), @@ -134,7 +192,7 @@ public class AABBBlock implements BlockSet, Cloneable { } @Override - public Iterator iterator() { + public @NotNull Iterator iterator() { return new Iterator<>() { private int x = pos1.getBlockX(), y = pos1.getBlockY(), @@ -162,22 +220,6 @@ public class AABBBlock implements BlockSet, Cloneable { } }; } - - - public Iterable asBlockIterable(World w) { - return () -> new Iterator<>() { - final Iterator nested = AABBBlock.this.iterator(); - @Override - public boolean hasNext() { - return nested.hasNext(); - } - @Override - public Block next() { - BlockVector bv = nested.next(); - return w.getBlockAt(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ()); - } - }; - } @Override diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/AABBBlockGroup.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/AABBBlockGroup.java index 3a6acba..9af3d8e 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/AABBBlockGroup.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/AABBBlockGroup.java @@ -12,19 +12,33 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; +/** + * A group of {@link AABBBlock}. + */ public class AABBBlockGroup implements BlockSet { - + + /** + * The list of {@link AABBBlock} contained in this group. This list is unmodifiable. + */ public final List subAABB; private final AABBBlock englobingAABB; + /** + * Creates a new {@link AABBBlockGroup}. + * @param in the list of {@link AABBBlock} that will be contained in this group. + */ public AABBBlockGroup(Collection in) { if (in.isEmpty()) throw new IllegalArgumentException("Provided collection must not be empty."); subAABB = List.copyOf(in); englobingAABB = initEnglobingAABB(); } - + + /** + * Creates a new {@link AABBBlockGroup}. + * @param in an array of {@link AABBBlock} that will be contained in this group. + */ public AABBBlockGroup(AABBBlock... in) { this(Arrays.asList(in)); } diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/BlockSet.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/BlockSet.java index 3b00fc7..f2c9561 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/BlockSet.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/geometry/blocks/BlockSet.java @@ -1,23 +1,58 @@ package fr.pandacube.lib.paper.geometry.blocks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.util.BlockVector; import org.bukkit.util.BoundingBox; import org.bukkit.util.Vector; +import java.util.Iterator; + +/** + * Represents a set of blocks in a world. + */ public interface BlockSet extends Iterable { + /** + * Gets a random coordinate that is inside this block set. + * @return a random coordinate inside this block set. + */ Vector getRandomPosition(); + + /** + * Gets the volume, in blocks (or cubic meters), of this block set. + * @return the volume of this block set. + */ long getVolume(); + + /** + * Gets the englobing bounding box if this block set. + * @return the englobing bounding box if this block set. + */ AABBBlock getEnglobingAABB(); + /** + * Tells if this block set overlaps the provided bounding box. + * @param bb the provided bounding box + * @return true if its overlaps, false otherwise. + */ boolean overlaps(BoundingBox bb); + /** + * Tells if this block set overlaps the bounding box of the provided entity. + * @param e the provided entity. + * @return true if its overlaps, false otherwise. + */ default boolean overlaps(Entity e) { return overlaps(e.getBoundingBox()); } + /** + * Tells if this block set overlaps the provided one. that is there is at least one block in common. + * @param bs the provided block set. + * @return true if its overlaps, false otherwise. + */ default boolean overlaps(BlockSet bs) { if (this instanceof AABBBlock b1) { if (bs instanceof AABBBlock b2) @@ -37,20 +72,78 @@ public interface BlockSet extends Iterable { } + /** + * Tells if the provided vector is inside this bounding box. + * @param v the vector. + * @return true if its inside, false otherwise. + */ boolean isInside(Vector v); + + /** + * Tells if the provided location is inside this bounding box. + * The world of the location is ignored. + * @param l the location. + * @return true if its inside, false otherwise. + */ default boolean isInside(Location l) { return isInside(l.toVector()); } + + /** + * Tells if the provided block is inside this bounding box. + * The world of the block is ignored. + * @param b the block. + * @return true if its inside, false otherwise. + */ default boolean isInside(Block b) { return isInside(b.getLocation().add(.5, .5, .5)); } - default boolean isInside(Entity p) { - return isInside(p.getLocation()); + + /** + * Tells if the provided entity is inside this bounding box. + * It calls {@link #isInside(Location)} using the returned value of {@link Entity#getLocation()}. + * The world of the entity is ignored. + * @param e the entity. + * @return true if its inside, false otherwise. + */ + default boolean isInside(Entity e) { + return isInside(e.getLocation()); } + + /** + * Gets an iterator iterating through all the blocks of this block set. + * @param w the world of the blocks. + * @return a new iterator. + */ + default Iterable asBlockIterable(World w) { + return () -> new Iterator<>() { + final Iterator nested = BlockSet.this.iterator(); + @Override + public boolean hasNext() { + return nested.hasNext(); + } + @Override + public Block next() { + BlockVector bv = nested.next(); + return w.getBlockAt(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ()); + } + }; + } + + + + /** + * Tests the two block set overlap each other. + * This method works on any implementation of this interface, but they should override the + * {@link #overlaps(BlockSet)} method to provide a more optimized code. + * @param bs1 the first block set. + * @param bs2 the second block set. + * @return true if the two block set overlap, false otherwise. + */ static boolean overlap(BlockSet bs1, BlockSet bs2) { if (!bs1.getEnglobingAABB().overlaps(bs2.getEnglobingAABB())) return false; diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/gui/GUIHotBar.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/gui/GUIHotBar.java index 2dec6bd..2dfbfa3 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/gui/GUIHotBar.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/gui/GUIHotBar.java @@ -69,7 +69,7 @@ public class GUIHotBar implements Listener { /** * Add the hot bar elements to this player, or update them if applicable. - * + *
* The player is automatically removed when they quit. You can remove it before by calling {@link #removePlayer(Player, boolean)}. */ public void addPlayer(Player p) { @@ -144,7 +144,7 @@ public class GUIHotBar implements Listener { @EventHandler - public void onPlayerDropItem(PlayerDropItemEvent event) { + void onPlayerDropItem(PlayerDropItemEvent event) { if (!currentPlayers.contains(event.getPlayer())) return; @@ -159,7 +159,7 @@ public class GUIHotBar implements Listener { @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) { + void onPlayerInteract(PlayerInteractEvent event) { if (!currentPlayers.contains(event.getPlayer())) return; @@ -188,7 +188,7 @@ public class GUIHotBar implements Listener { @EventHandler - public void onInventoryClick(InventoryClickEvent event) { + void onInventoryClick(InventoryClickEvent event) { if (event.getClickedInventory() == null || !(event.getClickedInventory() instanceof PlayerInventory inv)) return; @@ -213,20 +213,20 @@ public class GUIHotBar implements Listener { @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { + void onPlayerQuit(PlayerQuitEvent event) { removePlayer(event.getPlayer()); } @EventHandler - public void onPlayerDeath(PlayerDeathEvent event) { + void onPlayerDeath(PlayerDeathEvent event) { if (!currentPlayers.contains(event.getEntity())) return; event.getDrops().removeAll(itemsAndSetters.keySet()); } @EventHandler - public void onPlayerRespawn(PlayerRespawnEvent event) { + void onPlayerRespawn(PlayerRespawnEvent event) { if (!currentPlayers.contains(event.getPlayer())) return; diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/gui/GUIInventory.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/gui/GUIInventory.java index 08cfab0..677b4a0 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/gui/GUIInventory.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/gui/GUIInventory.java @@ -49,7 +49,11 @@ public class GUIInventory implements Listener { Bukkit.getPluginManager().registerEvents(this, PandaLibPaper.getPlugin()); } - + + /** + * Sets the action when the player closes the inventory window. + * @param closeEventAction the action to run. + */ protected void setCloseEvent(Consumer closeEventAction) { onCloseEvent = closeEventAction; } @@ -188,13 +192,13 @@ public class GUIInventory implements Listener { onCloseEvent.accept(event); isOpened = false; } - - - - - + /** + * Tells the number of inventory line needed to show the provided number of slot. + * @param nb the number of slot. + * @return the number of line. + */ public static int nbLineForNbElements(int nb) { return nb / 9 + ((nb % 9 == 0) ? 0 : 1); } diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/util/BedrockBambooCollisionFixer.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/util/BedrockBambooCollisionFixer.java index 1ee3e2b..dbc3894 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/util/BedrockBambooCollisionFixer.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/util/BedrockBambooCollisionFixer.java @@ -12,11 +12,25 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.util.BoundingBox; -// simplified version of https://github.com/Camotoy/BambooCollisionFix/tree/c7d7d5327791cbb416d106de0b9eb0bf2461acbd/src/main/java/net/camotoy/bamboocollisionfix -// we remove the bamboo bounding box due to bedrock clients not having the same placement for bamboos +// simplified version of + +/** + * Disables the server-side bounding box of the bamboo stalk blocks. + * Bamboo stalks are the thin bamboo plants that are shifted differently, depending on the X and Z coordinate. + * This X/Z dependent shift is different between Java and Bedrock implementation. + * But since this block as a collision box and players cannot go through them, Bedrock players are often rolled back + * when they are walking around bamboo stalk due to the server being in Java Edition and thinking the player tries to + * move through the bamboo. + * To avoid this issue, we reduce to 0 the size of the bounding box on the server. + *
+ * See the original implementation. + */ public final class BedrockBambooCollisionFixer implements Listener { private final BoundingBox originalBambooBoundingBox = new BoundingBox(6.5D / 16D, 0.0D, 6.5D / 16.0D, 9.5D / 16.0D, 1D, 9.5D / 16.0D); + /** + * Creates a new {@link BedrockBambooCollisionFixer}. There is no need for multiple instances. + */ public BedrockBambooCollisionFixer() { // Make the bamboo block have zero collision. try { @@ -34,7 +48,7 @@ public final class BedrockBambooCollisionFixer implements Listener { * our ability. */ @EventHandler - public void onBlockPlace(BlockPlaceEvent event) { + void onBlockPlace(BlockPlaceEvent event) { if (event.getBlockPlaced().getBlockData().getMaterial().equals(Material.BAMBOO)) { BoundingBox currentBambooBoundingBox = originalBambooBoundingBox.clone().shift(event.getBlockPlaced().getLocation()); for (LivingEntity e : event.getBlock().getLocation().getNearbyLivingEntities(5)) { diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/world/ChunkCoord.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/world/ChunkCoord.java index d82006b..df8bbb2 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/world/ChunkCoord.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/world/ChunkCoord.java @@ -5,8 +5,17 @@ import org.bukkit.World; import java.util.concurrent.CompletableFuture; +/** + * Represents a XZ chunk coordinates. + * @param x the x coordinate. + * @param z the z coordinate. + */ public record ChunkCoord(int x, int z) { + /** + * Creates the {@link ChunkCoord} of a {@link Chunk}. + * @param c the chunks from which to get its coordinates. + */ public ChunkCoord(Chunk c) { this(c.getX(), c.getZ()); } @@ -16,22 +25,48 @@ public record ChunkCoord(int x, int z) { return "(" + x + ";" + z + ")"; } + /** + * Gets the coordinates of the region file. + * @return the {@link RegionCoord}. + */ public RegionCoord getRegionCoord() { return new RegionCoord(x >> 5, z >> 5); } + /** + * Get the {@link Chunk} at this coordinate in the provided World. + * @param w the {@link World}. + * @return a chunk, using {@link World#getChunkAt(int, int)}. + */ public Chunk getChunk(World w) { return w.getChunkAt(x, z); } + /** + * Get the {@link Chunk} at this coordinate in the provided World. + * @param w the {@link World}. + * @param generate Whether the chunk should be fully generated or not. + * @return a chunk, using {@link World#getChunkAt(int, int, boolean)}. + */ public Chunk getChunk(World w, boolean generate) { return w.getChunkAt(x, z, generate); } + /** + * Get the {@link Chunk} at this coordinate in the provided World, asynchronously. + * @param w the {@link World}. + * @return a completable future of a chunk, using {@link World#getChunkAtAsync(int, int)}. + */ public CompletableFuture getChunkAsync(World w) { return w.getChunkAtAsync(x, z); } + /** + * Get the {@link Chunk} at this coordinate in the provided World, asynchronously. + * @param w the {@link World}. + * @param generate Whether the chunk should be fully generated or not. + * @return a completable future of a chunk, using {@link World#getChunkAtAsync(int, int, boolean)}. + */ public CompletableFuture getChunkAsync(World w, boolean generate) { return w.getChunkAtAsync(x, z, generate); } diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/world/RegionCoord.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/world/RegionCoord.java index 3d15bd5..d72c8c6 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/world/RegionCoord.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/world/RegionCoord.java @@ -3,20 +3,42 @@ package fr.pandacube.lib.paper.world; import java.util.regex.Matcher; import java.util.regex.Pattern; +/** + * Represents a XZ region coordinates. + * @param x the x coordinate. + * @param z the z coordinate. + */ public record RegionCoord(int x, int z) { + /** + * Gets the Chebyshev distance from this region to the center (0, 0) region. + * The unit is one region, i.e. the region (1, 0) has a distance of 1 from the center. + * @return the distance. + */ public int distToCenter() { return Math.max(Math.abs(x), Math.abs(z)); } + /** + * Gets the file name that store this region. + * @return the region file name. + */ public String getFileName() { return "r." + x + "." + z + ".mca"; } + /** + * Gets the chunk with the lowest coordinates of this region. + * @return the chunk with the lowest coordinates of this region. + */ public ChunkCoord getMinChunk() { return new ChunkCoord(x << 5, z << 5); } + /** + * Gets the chunk with the highest coordinates of this region. + * @return the chunk with the highest coordinates of this region. + */ public ChunkCoord getMaxChunk() { return new ChunkCoord(x << 5 | 31, z << 5 | 31); } @@ -25,6 +47,12 @@ public record RegionCoord(int x, int z) { private static final Pattern REGION_FILE_NAME_PATTERN = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$"); + /** + * Parse the coordinate from a region file name. + * @param name the name of the file to parse + * @return a new {@link RegionCoord} + * @throws IllegalArgumentException if the provided file name is not a valid MCA file name (including the extension). + */ public static RegionCoord fromFileName(String name) { Matcher m = REGION_FILE_NAME_PATTERN.matcher(name); if (m.find()) {