diff --git a/src/main/java/net/minestom/server/ServerFlag.java b/src/main/java/net/minestom/server/ServerFlag.java index 93765323c5b..d28705e1392 100644 --- a/src/main/java/net/minestom/server/ServerFlag.java +++ b/src/main/java/net/minestom/server/ServerFlag.java @@ -23,14 +23,17 @@ public final class ServerFlag { public static final int MAX_PACKET_SIZE = intProperty("minestom.max-packet-size", 2_097_151); // 3 bytes var-int public static final int SOCKET_SEND_BUFFER_SIZE = intProperty("minestom.send-buffer-size", 262_143); public static final int SOCKET_RECEIVE_BUFFER_SIZE = intProperty("minestom.receive-buffer-size", 32_767); + public static final boolean SOCKET_NO_DELAY = booleanProperty("minestom.tcp-no-delay", true); public static final int POOLED_BUFFER_SIZE = intProperty("minestom.pooled-buffer-size", 262_143); - public static final int PLAYER_PACKET_PER_TICK = intProperty("minestom.packet-per-tick", 20); - public static final int PLAYER_PACKET_QUEUE_SIZE = intProperty("minestom.packet-queue-size", 1000); public static final int SEND_LIGHT_AFTER_BLOCK_PLACEMENT_DELAY = intProperty("minestom.send-light-after-block-placement-delay", 100); - public static final long KEEP_ALIVE_DELAY = longProperty("minestom.keep-alive-delay", 10_000); - public static final long KEEP_ALIVE_KICK = longProperty("minestom.keep-alive-kick", 30_000); public static final long LOGIN_PLUGIN_MESSAGE_TIMEOUT = longProperty("minestom.login-plugin-message-timeout", 5_000); + // Network rate limiting + public static final int PLAYER_PACKET_PER_TICK = intProperty("minestom.packet-per-tick", 50); + public static final int PLAYER_PACKET_QUEUE_SIZE = intProperty("minestom.packet-queue-size", 1000); + public static final long KEEP_ALIVE_DELAY = longProperty("minestom.keep-alive-delay", 10_000); + public static final long KEEP_ALIVE_KICK = longProperty("minestom.keep-alive-kick", 15_000); + // Chunk update public static final float MIN_CHUNKS_PER_TICK = floatProperty("minestom.chunk-queue.min-per-tick", 0.01f); public static final float MAX_CHUNKS_PER_TICK = floatProperty("minestom.chunk-queue.max-per-tick", 64.0f); diff --git a/src/main/java/net/minestom/server/coordinate/Vec.java b/src/main/java/net/minestom/server/coordinate/Vec.java index d3ba7ce6b89..4535890c689 100644 --- a/src/main/java/net/minestom/server/coordinate/Vec.java +++ b/src/main/java/net/minestom/server/coordinate/Vec.java @@ -15,6 +15,7 @@ public record Vec(double x, double y, double z) implements Point { public static final Vec ZERO = new Vec(0); public static final Vec ONE = new Vec(1); + public static final Vec SECTION = new Vec(16); public static final double EPSILON = 0.000001; diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index bce75c63dfd..e7d92570389 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -1699,7 +1699,7 @@ public boolean isOccluded(@NotNull Shape shape, @NotNull BlockFace face) { @Override public boolean intersectBox(@NotNull Point positionRelative, @NotNull BoundingBox boundingBox) { - return boundingBox.intersectBox(positionRelative, boundingBox); + return this.boundingBox.intersectBox(positionRelative, boundingBox); } @Override diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index ae54fea9901..83a02db94cf 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -10,6 +10,7 @@ import net.minestom.server.entity.attribute.AttributeOperation; import net.minestom.server.entity.damage.Damage; import net.minestom.server.entity.damage.DamageType; +import net.minestom.server.entity.metadata.EntityMeta; import net.minestom.server.entity.metadata.LivingEntityMeta; import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.entity.EntityDamageEvent; @@ -83,36 +84,25 @@ public class LivingEntity extends Entity implements EquipmentHandler { private float health = 1F; // Equipments - private ItemStack mainHandItem; - private ItemStack offHandItem; + private ItemStack mainHandItem = ItemStack.AIR; + private ItemStack offHandItem = ItemStack.AIR; - private ItemStack helmet; - private ItemStack chestplate; - private ItemStack leggings; - private ItemStack boots; + private ItemStack helmet = ItemStack.AIR; + private ItemStack chestplate = ItemStack.AIR; + private ItemStack leggings = ItemStack.AIR; + private ItemStack boots = ItemStack.AIR; /** * Constructor which allows to specify an UUID. Only use if you know what you are doing! */ public LivingEntity(@NotNull EntityType entityType, @NotNull UUID uuid) { super(entityType, uuid); - initEquipments(); } public LivingEntity(@NotNull EntityType entityType) { this(entityType, UUID.randomUUID()); } - private void initEquipments() { - this.mainHandItem = ItemStack.AIR; - this.offHandItem = ItemStack.AIR; - - this.helmet = ItemStack.AIR; - this.chestplate = ItemStack.AIR; - this.leggings = ItemStack.AIR; - this.boots = ItemStack.AIR; - } - @Override public void setSprinting(boolean sprinting) { super.setSprinting(sprinting); @@ -125,91 +115,37 @@ public void setSprinting(boolean sprinting) { else speed.removeModifier(SPRINTING_SPEED_MODIFIER); } - @NotNull - @Override - public ItemStack getItemInMainHand() { - return mainHandItem; - } - - @Override - public void setItemInMainHand(@NotNull ItemStack itemStack) { - ItemStack oldItem = this.mainHandItem; - this.mainHandItem = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); - syncEquipment(EquipmentSlot.MAIN_HAND); - updateEquipmentAttributes(oldItem, this.mainHandItem, EquipmentSlot.MAIN_HAND); - } - - @NotNull @Override - public ItemStack getItemInOffHand() { - return offHandItem; + public @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot) { + return switch (slot) { + case MAIN_HAND -> mainHandItem; + case OFF_HAND -> offHandItem; + case BOOTS -> boots; + case LEGGINGS -> leggings; + case CHESTPLATE -> chestplate; + case HELMET -> helmet; + }; } @Override - public void setItemInOffHand(@NotNull ItemStack itemStack) { - ItemStack oldItem = this.offHandItem; - this.offHandItem = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); - syncEquipment(EquipmentSlot.OFF_HAND); - updateEquipmentAttributes(oldItem, this.offHandItem, EquipmentSlot.OFF_HAND); - } - - @NotNull - @Override - public ItemStack getHelmet() { - return helmet; - } - - @Override - public void setHelmet(@NotNull ItemStack itemStack) { - ItemStack oldItem = this.helmet; - this.helmet = getEquipmentItem(itemStack, EquipmentSlot.HELMET); - syncEquipment(EquipmentSlot.HELMET); - updateEquipmentAttributes(oldItem, this.helmet, EquipmentSlot.HELMET); - } - - @NotNull - @Override - public ItemStack getChestplate() { - return chestplate; - } - - @Override - public void setChestplate(@NotNull ItemStack itemStack) { - ItemStack oldItem = this.chestplate; - this.chestplate = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); - syncEquipment(EquipmentSlot.CHESTPLATE); - updateEquipmentAttributes(oldItem, this.chestplate, EquipmentSlot.CHESTPLATE); - } - - @NotNull - @Override - public ItemStack getLeggings() { - return leggings; - } - - @Override - public void setLeggings(@NotNull ItemStack itemStack) { - ItemStack oldItem = this.leggings; - this.leggings = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); - syncEquipment(EquipmentSlot.LEGGINGS); - updateEquipmentAttributes(oldItem, this.leggings, EquipmentSlot.LEGGINGS); - } - - @NotNull - @Override - public ItemStack getBoots() { - return boots; - } + public void setEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) { + ItemStack oldItem = getEquipment(slot); + ItemStack newItem = slotChangeEvent(itemStack, slot); + + switch (slot) { + case MAIN_HAND -> mainHandItem = newItem; + case OFF_HAND -> offHandItem = newItem; + case BOOTS -> boots = newItem; + case LEGGINGS -> leggings = newItem; + case CHESTPLATE -> chestplate = newItem; + case HELMET -> helmet = newItem; + } - @Override - public void setBoots(@NotNull ItemStack itemStack) { - ItemStack oldItem = this.boots; - this.boots = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); - syncEquipment(EquipmentSlot.BOOTS); - updateEquipmentAttributes(oldItem, this.boots, EquipmentSlot.BOOTS); + syncEquipment(slot); + updateEquipmentAttributes(oldItem, newItem, slot); } - private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { + private ItemStack slotChangeEvent(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot); EventDispatcher.call(entityEquipEvent); return entityEquipEvent.getEquippedItem(); @@ -720,7 +656,7 @@ public void setTeam(@Nullable Team team) { } /** - * Gets {@link net.minestom.server.entity.metadata.EntityMeta} of this entity casted to {@link LivingEntityMeta}. + * Gets {@link EntityMeta} of this entity casted to {@link LivingEntityMeta}. * * @return null if meta of this entity does not inherit {@link LivingEntityMeta}, casted value otherwise. */ diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index e88d90de368..f8f3c599401 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -97,8 +97,7 @@ import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.DimensionType; -import org.jctools.queues.MessagePassingQueue; -import org.jctools.queues.MpscUnboundedXaddArrayQueue; +import org.jctools.queues.MpscArrayQueue; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -175,7 +174,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, private final AtomicInteger teleportId = new AtomicInteger(); private int receivedTeleportId; - private final MessagePassingQueue packets = new MpscUnboundedXaddArrayQueue<>(32); + private final MpscArrayQueue packets = new MpscArrayQueue<>(ServerFlag.PLAYER_PACKET_QUEUE_SIZE); private final boolean levelFlat; private final PlayerSettings settings; private float exp; @@ -2127,15 +2126,14 @@ protected void refreshAbilities() { * @param packet the packet to add in the queue */ public void addPacketToQueue(@NotNull ClientPacket packet) { - this.packets.offer(packet); + final boolean success = packets.offer(packet); + if (!success) { + kick(Component.text("Too Many Packets", NamedTextColor.RED)); + } } @ApiStatus.Internal public void interpretPacketQueue() { - if (this.packets.size() >= ServerFlag.PLAYER_PACKET_QUEUE_SIZE) { - kick(Component.text("Too Many Packets", NamedTextColor.RED)); - return; - } final PacketListenerManager manager = MinecraftServer.getPacketListenerManager(); // This method is NOT thread-safe this.packets.drain(packet -> manager.processClientPacket(packet, playerConnection), ServerFlag.PLAYER_PACKET_PER_TICK); @@ -2291,63 +2289,13 @@ protected void showPlayer(@NotNull PlayerConnection connection) { } @Override - public @NotNull ItemStack getItemInMainHand() { - return inventory.getItemInMainHand(); - } - - @Override - public void setItemInMainHand(@NotNull ItemStack itemStack) { - inventory.setItemInMainHand(itemStack); - } - - @Override - public @NotNull ItemStack getItemInOffHand() { - return inventory.getItemInOffHand(); - } - - @Override - public void setItemInOffHand(@NotNull ItemStack itemStack) { - inventory.setItemInOffHand(itemStack); - } - - @Override - public @NotNull ItemStack getHelmet() { - return inventory.getHelmet(); - } - - @Override - public void setHelmet(@NotNull ItemStack itemStack) { - inventory.setHelmet(itemStack); - } - - @Override - public @NotNull ItemStack getChestplate() { - return inventory.getChestplate(); - } - - @Override - public void setChestplate(@NotNull ItemStack itemStack) { - inventory.setChestplate(itemStack); - } - - @Override - public @NotNull ItemStack getLeggings() { - return inventory.getLeggings(); - } - - @Override - public void setLeggings(@NotNull ItemStack itemStack) { - inventory.setLeggings(itemStack); - } - - @Override - public @NotNull ItemStack getBoots() { - return inventory.getBoots(); + public @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot) { + return inventory.getEquipment(slot); } @Override - public void setBoots(@NotNull ItemStack itemStack) { - inventory.setBoots(itemStack); + public void setEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) { + inventory.setEquipment(slot, itemStack); } @Override diff --git a/src/main/java/net/minestom/server/entity/pathfinding/Navigator.java b/src/main/java/net/minestom/server/entity/pathfinding/Navigator.java index f218a05e438..79ab7874ea3 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/Navigator.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/Navigator.java @@ -35,7 +35,7 @@ public final class Navigator { private double minimumDistance; - NodeGenerator nodeGenerator = new GroundNodeGenerator(); + NodeGenerator nodeGenerator = new GroundNodeGenerator(); private NodeFollower nodeFollower; public Navigator(@NotNull Entity entity) { diff --git a/src/main/java/net/minestom/server/entity/pathfinding/PathGenerator.java b/src/main/java/net/minestom/server/entity/pathfinding/PathGenerator.java index 14016ccafdd..eab43400202 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/PathGenerator.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/PathGenerator.java @@ -16,7 +16,6 @@ public class PathGenerator { private static final ExecutorService pool = Executors.newWorkStealingPool(); - private static final PNode repathNode = new PNode(0, 0, 0, 0, 0, PNode.NodeType.REPATH, null); private static final Comparator pNodeComparator = (s1, s2) -> (int) (((s1.g() + s1.h()) - (s2.g() + s2.h())) * 1000); public static @NotNull PPath generate(@NotNull Instance instance, @NotNull Pos orgStart, @NotNull Point orgTarget, double closeDistance, double maxDistance, double pathVariance, @NotNull BoundingBox boundingBox, boolean isOnGround, @NotNull NodeGenerator generator, @Nullable Runnable onComplete) { @@ -34,6 +33,10 @@ public class PathGenerator { return path; } + private static PNode buildRepathNode(PNode parent) { + return new PNode(0, 0, 0, 0, 0, PNode.NodeType.REPATH, parent); + } + private static void computePath(Instance instance, Point start, Point target, double closeDistance, double maxDistance, double pathVariance, BoundingBox boundingBox, PPath path, NodeGenerator generator) { double closestDistance = Double.MAX_VALUE; double straightDistance = generator.heuristic(start, target); @@ -93,8 +96,7 @@ private static void computePath(Instance instance, Point start, Point target, do current = closestFoundNodes.get(0); if (!open.isEmpty()) { - repathNode.setParent(current); - current = repathNode; + current = buildRepathNode(current); } } diff --git a/src/main/java/net/minestom/server/instance/generator/GeneratorImpl.java b/src/main/java/net/minestom/server/instance/generator/GeneratorImpl.java index 34026a5af3c..9d41bc7f24b 100644 --- a/src/main/java/net/minestom/server/instance/generator/GeneratorImpl.java +++ b/src/main/java/net/minestom/server/instance/generator/GeneratorImpl.java @@ -22,8 +22,6 @@ @ApiStatus.Internal public final class GeneratorImpl { - private static final Vec SECTION_SIZE = new Vec(16); - public record GenSection(Palette blocks, Palette biomes, Int2ObjectMap specials) { public GenSection(Palette blocks, Palette biomes) { this(blocks, biomes, new Int2ObjectOpenHashMap<>(0)); @@ -37,9 +35,9 @@ public GenSection() { static GenerationUnit section(DynamicRegistry biomeRegistry, GenSection section, int sectionX, int sectionY, int sectionZ, boolean fork) { - final Vec start = SECTION_SIZE.mul(sectionX, sectionY, sectionZ); - final Vec end = start.add(SECTION_SIZE); - final UnitModifier modifier = new SectionModifierImpl(biomeRegistry, SECTION_SIZE, + final Vec start = Vec.SECTION.mul(sectionX, sectionY, sectionZ); + final Vec end = start.add(Vec.SECTION); + final UnitModifier modifier = new SectionModifierImpl(biomeRegistry, Vec.SECTION, start, end, section, fork); return unit(biomeRegistry, modifier, start, end, null); } @@ -49,7 +47,7 @@ public static GenerationUnit section(DynamicRegistry biomeRegistry, GenSe } public static UnitImpl chunk(DynamicRegistry biomeRegistry, GenSection[] chunkSections, int chunkX, int minSection, int chunkZ) { - final Vec start = new Vec(chunkX * 16, minSection * 16, chunkZ * 16); + final Vec start = Vec.SECTION.mul(chunkX, minSection, chunkZ); return area(biomeRegistry, start, 1, chunkSections.length, 1, chunkSections); } @@ -72,7 +70,7 @@ public static UnitImpl area(DynamicRegistry biomeRegistry, Point start, i } sections = List.copyOf(sections); - final Point size = SECTION_SIZE.mul(width, height, depth); + final Point size = Vec.SECTION.mul(width, height, depth); final Point end = start.add(size); final UnitModifier modifier = new AreaModifierImpl(size, start, end, width, height, depth, sections); return unit(biomeRegistry, modifier, start, end, sections); @@ -119,7 +117,7 @@ private void resize(int x, int y, int z) { final int sectionY = getChunkCoordinate(y); final int sectionZ = getChunkCoordinate(z); if (sections == null) { - this.minSection = new Vec(sectionX * 16, sectionY * 16, sectionZ * 16); + this.minSection = Vec.SECTION.mul(sectionX, sectionY, sectionZ); this.width = 1; this.height = 1; this.depth = 1; @@ -190,16 +188,17 @@ public record UnitImpl(DynamicRegistry biomeRegistry, UnitModifier modifi GenerationUnit[] units = new GenerationUnit[width * height * depth]; int index = 0; - for (int sectionX = minSectionX; sectionX < maxSectionX; sectionX++) { + // Z -> Y -> X order is important for indexing + for (int sectionZ = minSectionZ; sectionZ < maxSectionZ; sectionZ++) { for (int sectionY = minSectionY; sectionY < maxSectionY; sectionY++) { - for (int sectionZ = minSectionZ; sectionZ < maxSectionZ; sectionZ++) { + for (int sectionX = minSectionX; sectionX < maxSectionX; sectionX++) { final GenerationUnit unit = section(biomeRegistry, new GenSection(), sectionX, sectionY, sectionZ, true); units[index++] = unit; } } } final List sections = List.of(units); - final Point startSection = new Vec(minSectionX * 16, minSectionY * 16, minSectionZ * 16); + final Point startSection = Vec.SECTION.mul(minSectionX, minSectionY, minSectionZ); return registerFork(startSection, sections, width, height, depth); } @@ -294,7 +293,8 @@ public void fillBiome(@NotNull DynamicRegistry.Key biome) { } private int retrieveBlockId(Block block) { - return fork ? block.stateId() + 1 : block.stateId(); + final int stateId = block.stateId(); + return fork ? stateId + 1 : stateId; } private void handleCache(int x, int y, int z, Block block) { @@ -344,7 +344,7 @@ public void setRelative(int x, int y, int z, @NotNull Block block) { @Override public void setAll(@NotNull Supplier supplier) { for (GenerationUnit section : sections) { - final var start = section.absoluteStart(); + final Point start = section.absoluteStart(); final int startX = start.blockX(); final int startY = start.blockY(); final int startZ = start.blockZ(); @@ -429,11 +429,7 @@ private GenerationUnit findAbsoluteSection(int x, int y, int z) { } private GenerationUnit findRelativeSection(int x, int y, int z) { - final int sectionX = getChunkCoordinate(x); - final int sectionY = getChunkCoordinate(y); - final int sectionZ = getChunkCoordinate(z); - final int index = sectionZ + sectionY * depth + sectionX * depth * height; - return sections.get(index); + return findAbsolute(sections, Vec.ZERO, width, height, depth, x, y, z); } private void checkBorder(int x, int y, int z) { @@ -532,6 +528,7 @@ private static GenerationUnit findAbsolute(List units, Point sta private static int findIndex(int width, int height, int depth, int x, int y, int z) { + assert width > 0 && height > 0 && depth > 0; return (z * width * height) + (y * width) + x; } diff --git a/src/main/java/net/minestom/server/inventory/EquipmentHandler.java b/src/main/java/net/minestom/server/inventory/EquipmentHandler.java index 576dddd4dad..9488b5a9f70 100644 --- a/src/main/java/net/minestom/server/inventory/EquipmentHandler.java +++ b/src/main/java/net/minestom/server/inventory/EquipmentHandler.java @@ -15,33 +15,51 @@ */ public interface EquipmentHandler { + /** + * Gets the equipment in a specific slot. + * + * @param slot the equipment to get the item from + * @return the equipment {@link ItemStack} + */ + @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot); + + void setEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack); + /** * Gets the {@link ItemStack} in main hand. * * @return the {@link ItemStack} in main hand */ - @NotNull ItemStack getItemInMainHand(); + default @NotNull ItemStack getItemInMainHand() { + return getEquipment(EquipmentSlot.MAIN_HAND); + } /** * Changes the main hand {@link ItemStack}. * * @param itemStack the main hand {@link ItemStack} */ - void setItemInMainHand(@NotNull ItemStack itemStack); + default void setItemInMainHand(@NotNull ItemStack itemStack) { + setEquipment(EquipmentSlot.MAIN_HAND, itemStack); + } /** * Gets the {@link ItemStack} in off hand. * * @return the item in off hand */ - @NotNull ItemStack getItemInOffHand(); + default @NotNull ItemStack getItemInOffHand() { + return getEquipment(EquipmentSlot.OFF_HAND); + } /** * Changes the off hand {@link ItemStack}. * * @param itemStack the off hand {@link ItemStack} */ - void setItemInOffHand(@NotNull ItemStack itemStack); + default void setItemInOffHand(@NotNull ItemStack itemStack) { + setEquipment(EquipmentSlot.OFF_HAND, itemStack); + } /** * Gets the {@link ItemStack} in the specific hand. @@ -74,83 +92,71 @@ default void setItemInHand(@NotNull Player.Hand hand, @NotNull ItemStack stack) * * @return the helmet */ - @NotNull ItemStack getHelmet(); + default @NotNull ItemStack getHelmet() { + return getEquipment(EquipmentSlot.HELMET); + } /** * Changes the helmet. * * @param itemStack the helmet */ - void setHelmet(@NotNull ItemStack itemStack); + default void setHelmet(@NotNull ItemStack itemStack) { + setEquipment(EquipmentSlot.HELMET, itemStack); + } /** * Gets the chestplate. * * @return the chestplate */ - @NotNull ItemStack getChestplate(); + default @NotNull ItemStack getChestplate() { + return getEquipment(EquipmentSlot.CHESTPLATE); + } /** * Changes the chestplate. * * @param itemStack the chestplate */ - void setChestplate(@NotNull ItemStack itemStack); + default void setChestplate(@NotNull ItemStack itemStack) { + setEquipment(EquipmentSlot.CHESTPLATE, itemStack); + } /** * Gets the leggings. * * @return the leggings */ - @NotNull ItemStack getLeggings(); + default @NotNull ItemStack getLeggings() { + return getEquipment(EquipmentSlot.LEGGINGS); + } /** * Changes the leggings. * * @param itemStack the leggings */ - void setLeggings(@NotNull ItemStack itemStack); + default void setLeggings(@NotNull ItemStack itemStack) { + setEquipment(EquipmentSlot.LEGGINGS, itemStack); + } /** * Gets the boots. * * @return the boots */ - @NotNull ItemStack getBoots(); + default @NotNull ItemStack getBoots() { + return getEquipment(EquipmentSlot.BOOTS); + } /** * Changes the boots. * * @param itemStack the boots */ - void setBoots(@NotNull ItemStack itemStack); - - /** - * Gets the equipment in a specific slot. - * - * @param slot the equipment to get the item from - * @return the equipment {@link ItemStack} - */ - default @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot) { - return switch (slot) { - case MAIN_HAND -> getItemInMainHand(); - case OFF_HAND -> getItemInOffHand(); - case HELMET -> getHelmet(); - case CHESTPLATE -> getChestplate(); - case LEGGINGS -> getLeggings(); - case BOOTS -> getBoots(); - }; - } - - default void setEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) { - switch (slot) { - case MAIN_HAND -> setItemInMainHand(itemStack); - case OFF_HAND -> setItemInOffHand(itemStack); - case HELMET -> setHelmet(itemStack); - case CHESTPLATE -> setChestplate(itemStack); - case LEGGINGS -> setLeggings(itemStack); - case BOOTS -> setBoots(itemStack); - } + default void setBoots(@NotNull ItemStack itemStack) { + setEquipment(EquipmentSlot.BOOTS, itemStack); } default boolean hasEquipment(@NotNull EquipmentSlot slot) { diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 85774354e92..30203a0f194 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -44,64 +44,22 @@ public int getInnerSize() { return INNER_INVENTORY_SIZE; } - @Override - public @NotNull ItemStack getItemInMainHand() { - return getItemStack(player.getHeldSlot()); - } - - @Override - public void setItemInMainHand(@NotNull ItemStack itemStack) { - safeItemInsert(player.getHeldSlot(), itemStack); - } - - @Override - public @NotNull ItemStack getItemInOffHand() { - return getItemStack(OFFHAND_SLOT); - } - - @Override - public void setItemInOffHand(@NotNull ItemStack itemStack) { - safeItemInsert(OFFHAND_SLOT, itemStack); - } - - @Override - public @NotNull ItemStack getHelmet() { - return getItemStack(HELMET_SLOT); - } - - @Override - public void setHelmet(@NotNull ItemStack itemStack) { - safeItemInsert(HELMET_SLOT, itemStack); - } - - @Override - public @NotNull ItemStack getChestplate() { - return getItemStack(CHESTPLATE_SLOT); - } - - @Override - public void setChestplate(@NotNull ItemStack itemStack) { - safeItemInsert(CHESTPLATE_SLOT, itemStack); - } - - @Override - public @NotNull ItemStack getLeggings() { - return getItemStack(LEGGINGS_SLOT); - } - - @Override - public void setLeggings(@NotNull ItemStack itemStack) { - safeItemInsert(LEGGINGS_SLOT, itemStack); + private int getSlotId(@NotNull EquipmentSlot slot) { + return switch (slot) { + case MAIN_HAND -> player.getHeldSlot(); + case OFF_HAND -> OFFHAND_SLOT; + default -> slot.armorSlot(); + }; } @Override - public @NotNull ItemStack getBoots() { - return getItemStack(BOOTS_SLOT); + public @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot) { + return getItemStack(getSlotId(slot)); } @Override - public void setBoots(@NotNull ItemStack itemStack) { - safeItemInsert(BOOTS_SLOT, itemStack); + public void setEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) { + safeItemInsert(getSlotId(slot), itemStack); } /** diff --git a/src/main/java/net/minestom/server/item/component/BannerPatterns.java b/src/main/java/net/minestom/server/item/component/BannerPatterns.java index a06d22b1981..d18ebc00fa6 100644 --- a/src/main/java/net/minestom/server/item/component/BannerPatterns.java +++ b/src/main/java/net/minestom/server/item/component/BannerPatterns.java @@ -1,5 +1,6 @@ package net.minestom.server.item.component; +import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.color.DyeColor; import net.minestom.server.instance.block.banner.BannerPattern; @@ -30,13 +31,23 @@ public Layer read(@NotNull NetworkBuffer buffer) { return new Layer(buffer.read(BannerPattern.NETWORK_TYPE), buffer.read(DyeColor.NETWORK_TYPE)); } }; - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( - tag -> new Layer(BannerPattern.NBT_TYPE.read(tag.get("pattern")), DyeColor.NBT_TYPE.read(tag.get("color"))), - layer -> CompoundBinaryTag.builder() - .put("pattern", BannerPattern.NBT_TYPE.write(layer.pattern)) - .put("color", DyeColor.NBT_TYPE.write(layer.color)) - .build() - ); + public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer() { + @Override + public @NotNull BinaryTag write(@NotNull Context context, @NotNull Layer value) { + return CompoundBinaryTag.builder() + .put("pattern", BannerPattern.NBT_TYPE.write(value.pattern)) + .put("color", DyeColor.NBT_TYPE.write(value.color)) + .build(); + } + + @Override + public @NotNull Layer read(@NotNull Context context, @NotNull BinaryTag tag) { + if (!(tag instanceof CompoundBinaryTag compound)) + throw new IllegalArgumentException("Expected a compound tag"); + return new Layer(BannerPattern.NBT_TYPE.read(context, compound.get("pattern")), + DyeColor.NBT_TYPE.read(context, compound.get("color"))); + } + }; } public BannerPatterns { diff --git a/src/main/java/net/minestom/server/network/socket/Server.java b/src/main/java/net/minestom/server/network/socket/Server.java index 7fb6459861d..b28c8e96292 100644 --- a/src/main/java/net/minestom/server/network/socket/Server.java +++ b/src/main/java/net/minestom/server/network/socket/Server.java @@ -5,6 +5,8 @@ import net.minestom.server.network.PacketProcessor; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.*; @@ -15,15 +17,10 @@ import java.nio.file.Files; import java.util.Arrays; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public final class Server { - private static final Logger LOGGER = LoggerFactory.getLogger(Server.class); - public static final boolean NO_DELAY = true; - private volatile boolean stop; private final Selector selector = Selector.open(); diff --git a/src/main/java/net/minestom/server/network/socket/Worker.java b/src/main/java/net/minestom/server/network/socket/Worker.java index af5669f2ef6..2050976f377 100644 --- a/src/main/java/net/minestom/server/network/socket/Worker.java +++ b/src/main/java/net/minestom/server/network/socket/Worker.java @@ -138,7 +138,7 @@ void receiveConnection(SocketChannel channel) throws IOException { Socket socket = channel.socket(); socket.setSendBufferSize(ServerFlag.SOCKET_SEND_BUFFER_SIZE); socket.setReceiveBufferSize(ServerFlag.SOCKET_RECEIVE_BUFFER_SIZE); - socket.setTcpNoDelay(Server.NO_DELAY); + socket.setTcpNoDelay(ServerFlag.SOCKET_NO_DELAY); socket.setSoTimeout(30 * 1000); // 30 seconds } } diff --git a/src/test/java/net/minestom/server/instance/generator/GeneratorTest.java b/src/test/java/net/minestom/server/instance/generator/GeneratorTest.java index f8240db9660..cb8c4ad1682 100644 --- a/src/test/java/net/minestom/server/instance/generator/GeneratorTest.java +++ b/src/test/java/net/minestom/server/instance/generator/GeneratorTest.java @@ -23,10 +23,11 @@ import static org.junit.jupiter.api.Assertions.*; class GeneratorTest { + @Test void unitSize() { - assertDoesNotThrow(() -> dummyUnit(Vec.ZERO, new Vec(16))); - assertDoesNotThrow(() -> dummyUnit(new Vec(16), new Vec(32))); + assertDoesNotThrow(() -> dummyUnit(Vec.ZERO, Vec.SECTION)); + assertDoesNotThrow(() -> dummyUnit(Vec.SECTION, new Vec(32))); assertThrows(IllegalArgumentException.class, () -> dummyUnit(new Vec(15), Vec.ZERO)); assertThrows(IllegalArgumentException.class, () -> dummyUnit(new Vec(15), new Vec(32))); assertThrows(IllegalArgumentException.class, () -> dummyUnit(new Vec(15), new Vec(31))); @@ -107,7 +108,7 @@ void sectionSize() { final int sectionY = -5; final int sectionZ = -2; GenerationUnit section = GeneratorImpl.section(null, new GenSection(), sectionX, sectionY, sectionZ); - assertEquals(new Vec(16), section.size()); + assertEquals(Vec.SECTION, section.size()); assertEquals(new Vec(sectionX * 16, sectionY * 16, sectionZ * 16), section.absoluteStart()); assertEquals(new Vec(sectionX * 16 + 16, sectionY * 16 + 16, sectionZ * 16 + 16), section.absoluteEnd()); } @@ -126,7 +127,7 @@ void chunkSubdivide() { assertEquals(sectionCount, subUnits.size()); for (int i = 0; i < sectionCount; i++) { var subUnit = subUnits.get(i); - assertEquals(new Vec(16, 16, 16), subUnit.size()); + assertEquals(Vec.SECTION, subUnit.size()); assertEquals(new Vec(chunkX * 16, (i + minSection) * 16, chunkZ * 16), subUnit.absoluteStart()); assertEquals(subUnit.absoluteStart().add(16), subUnit.absoluteEnd()); } @@ -300,7 +301,7 @@ void chunkFillHeightOneOff() { } @Test - public void sectionFill() { + void sectionFill() { GenSection section = new GenSection(); var chunkUnit = GeneratorImpl.section(null, section, -1, -1, 0); Generator generator = chunk -> chunk.modifier().fill(Block.STONE); @@ -309,6 +310,65 @@ public void sectionFill() { assertEquals(Block.STONE.stateId(), value)); } + @Test + void testForkAcrossBorders() { + final int minSection = -4; + final int maxSection = 4; + + final int sectionCount = maxSection - minSection; + GenSection[] sections = new GenSection[sectionCount]; + Arrays.setAll(sections, i -> new GenSection()); + var chunkUnits = GeneratorImpl.chunk(null, sections, 0, minSection, 0); + Generator generator = unit -> { + if (unit.absoluteStart().x() == 0 && unit.absoluteStart().z() == 0) { + var start = unit.absoluteStart().withY(0).add(0, 0, 8).sub(2, 2, 0); + var end = unit.absoluteStart().withY(0).add(0, 0, 8).add(2, 2, 1); + + var fork = unit.fork(start, end); + fork.modifier().fill(start, end, Block.STONE); + } + }; + generator.generate(chunkUnits); + + Set stones = new HashSet<>(); + + for (GeneratorImpl.UnitImpl fork : chunkUnits.forks()) { + GeneratorImpl.AreaModifierImpl impl = (GeneratorImpl.AreaModifierImpl) fork.modifier(); + + for (GenerationUnit section : impl.sections()) { + GeneratorImpl.UnitImpl unit = (GeneratorImpl.UnitImpl) section; + GeneratorImpl.SectionModifierImpl modifier = (GeneratorImpl.SectionModifierImpl) unit.modifier(); + + modifier.genSection().blocks().getAllPresent((x, y, z, state) -> { + final Point blockPos = modifier.start().add(x, y, z); + stones.add(blockPos); + }); + } + } + + var expectedStones = Set.of( + new Vec(-2, -2, 8), + new Vec(-2, -1, 8), + new Vec(-2, 0, 8), + new Vec(-2, 1, 8), + new Vec(-1, -2, 8), + new Vec(-1, -1, 8), + new Vec(-1, 0, 8), + new Vec(-1, 1, 8), + new Vec(0, -2, 8), + new Vec(0, -1, 8), + new Vec(0, 0, 8), + new Vec(0, 1, 8), + new Vec(1, -2, 8), + new Vec(1, -1, 8), + new Vec(1, 0, 8), + new Vec(1, 1, 8) + ); + + assertEquals(expectedStones.size(), stones.size()); + assertEquals(expectedStones, stones); + } + static GenerationUnit dummyUnit(Point start, Point end) { return unit(null, null, start, end, null); }