From de3443f173d121ca3316a7139ca9a83d6d430ec4 Mon Sep 17 00:00:00 2001 From: Articdive <13535885+Articdive@users.noreply.github.com> Date: Mon, 22 Feb 2021 17:05:41 +0100 Subject: [PATCH 01/66] Stop using authlib --- build.gradle | 1 - .../minestom/server/extras/MojangAuth.java | 18 ---------- .../login/EncryptionResponsePacket.java | 35 +++++++++++++------ 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/build.gradle b/build.gradle index 790b4c874..d910ee39a 100644 --- a/build.gradle +++ b/build.gradle @@ -135,7 +135,6 @@ dependencies { // Guava 21.0+ required for Mixin, but Authlib imports 17.0 api 'com.google.guava:guava:21.0' - api 'com.mojang:authlib:1.5.21' // Code modification api "org.ow2.asm:asm:${asmVersion}" diff --git a/src/main/java/net/minestom/server/extras/MojangAuth.java b/src/main/java/net/minestom/server/extras/MojangAuth.java index 02831864c..d322ef4fe 100644 --- a/src/main/java/net/minestom/server/extras/MojangAuth.java +++ b/src/main/java/net/minestom/server/extras/MojangAuth.java @@ -1,14 +1,10 @@ package net.minestom.server.extras; -import com.mojang.authlib.AuthenticationService; -import com.mojang.authlib.minecraft.MinecraftSessionService; -import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; import net.minestom.server.MinecraftServer; import net.minestom.server.extras.mojangAuth.MojangCrypt; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.Nullable; -import java.net.Proxy; import java.security.KeyPair; public final class MojangAuth { @@ -16,8 +12,6 @@ public final class MojangAuth { private static volatile boolean enabled = false; private static KeyPair keyPair; - private static AuthenticationService authService; - private static MinecraftSessionService sessionService; /** * Enables mojang authentication on the server. @@ -32,8 +26,6 @@ public final class MojangAuth { // Generate necessary fields... keyPair = MojangCrypt.generateKeyPair(); - authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, ""); - sessionService = authService.createMinecraftSessionService(); } public static boolean isEnabled() { @@ -44,14 +36,4 @@ public final class MojangAuth { public static KeyPair getKeyPair() { return keyPair; } - - @Nullable - public static AuthenticationService getAuthService() { - return authService; - } - - @Nullable - public static MinecraftSessionService getSessionService() { - return sessionService; - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/login/EncryptionResponsePacket.java b/src/main/java/net/minestom/server/network/packet/client/login/EncryptionResponsePacket.java index 0b6917e91..0b1720162 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/EncryptionResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/EncryptionResponsePacket.java @@ -1,7 +1,7 @@ package net.minestom.server.network.packet.client.login; -import com.mojang.authlib.GameProfile; -import com.mojang.authlib.exceptions.AuthenticationUnavailableException; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import net.minestom.server.MinecraftServer; import net.minestom.server.data.type.array.ByteArrayData; import net.minestom.server.extras.MojangAuth; @@ -14,11 +14,16 @@ import net.minestom.server.utils.binary.BinaryReader; import org.jetbrains.annotations.NotNull; import javax.crypto.SecretKey; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.math.BigInteger; +import java.net.URL; import java.util.Arrays; +import java.util.UUID; public class EncryptionResponsePacket implements ClientPreplayPacket { - + private static final Gson GSON = new Gson(); private byte[] sharedSecret; private byte[] verifyToken; @@ -38,7 +43,7 @@ public class EncryptionResponsePacket implements ClientPreplayPacket { MinecraftServer.LOGGER.error("{} tried to login with an invalid nonce!", loginUsername); return; } - if (!loginUsername.isEmpty()) { + if (loginUsername != null && !loginUsername.isEmpty()) { final byte[] digestedData = MojangCrypt.digestData("", MojangAuth.getKeyPair().getPublic(), getSecretKey()); @@ -49,14 +54,24 @@ public class EncryptionResponsePacket implements ClientPreplayPacket { return; } - final String string3 = new BigInteger(digestedData).toString(16); - final GameProfile gameProfile = MojangAuth.getSessionService().hasJoinedServer(new GameProfile(null, loginUsername), string3); - nettyConnection.setEncryptionKey(getSecretKey()); + // Query Mojang's sessionserver. + final String serverId = new BigInteger(digestedData).toString(16); + InputStream gameProfileStream = new URL( + "https://sessionserver.mojang.com/session/minecraft/hasJoined?" + + "username=" + loginUsername + "&" + + "serverId=" + serverId + // TODO: Add ability to add ip query tag. See: https://wiki.vg/Protocol_Encryption#Authentication + ).openStream(); - MinecraftServer.LOGGER.info("UUID of player {} is {}", loginUsername, gameProfile.getId()); - CONNECTION_MANAGER.startPlayState(connection, gameProfile.getId(), gameProfile.getName(), true); + final JsonObject gameProfile = GSON.fromJson(new InputStreamReader(gameProfileStream), JsonObject.class); + nettyConnection.setEncryptionKey(getSecretKey()); + UUID profileUUID = UUID.fromString(gameProfile.get("id").getAsString().replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); + String profileName = gameProfile.get("name").getAsString(); + + MinecraftServer.LOGGER.info("UUID of player {} is {}", loginUsername, profileUUID); + CONNECTION_MANAGER.startPlayState(connection, profileUUID, profileName, true); } - } catch (AuthenticationUnavailableException e) { + } catch (IOException e) { MinecraftServer.getExceptionManager().handleException(e); } }); From bf92a7db7233719a8aad44abc7a2634471eef76b Mon Sep 17 00:00:00 2001 From: Articdive <13535885+Articdive@users.noreply.github.com> Date: Mon, 22 Feb 2021 21:01:38 +0100 Subject: [PATCH 02/66] Include commons-codec for digest utilities. --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index d910ee39a..bfdddecba 100644 --- a/build.gradle +++ b/build.gradle @@ -121,6 +121,9 @@ dependencies { // https://mvnrepository.com/artifact/com.google.code.gson/gson api 'com.google.code.gson:gson:2.8.6' + // https://mvnrepository.com/artifact/commons-codec/commons-codec + api 'commons-codec:commons-codec:1.15' + // Noise library for terrain generation // https://jitpack.io/#Articdive/Jnoise api 'com.github.Articdive:Jnoise:1.0.0' From dbfb3f7ff4447df5b39f1f48c40c4a41a6654b67 Mon Sep 17 00:00:00 2001 From: Articdive <13535885+Articdive@users.noreply.github.com> Date: Fri, 5 Mar 2021 21:03:23 +0100 Subject: [PATCH 03/66] Remove commons-codec dependency --- build.gradle | 3 -- .../entity/metadata/animal/FoxMeta.java | 2 +- .../server/registry/ResourceGatherer.java | 31 ++++++++++++++----- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 35c1340a7..ab0c98a2b 100644 --- a/build.gradle +++ b/build.gradle @@ -124,9 +124,6 @@ dependencies { // https://mvnrepository.com/artifact/com.google.code.gson/gson api 'com.google.code.gson:gson:2.8.6' - // https://mvnrepository.com/artifact/commons-codec/commons-codec - api 'commons-codec:commons-codec:1.15' - // Noise library for terrain generation // https://jitpack.io/#Articdive/Jnoise api 'com.github.Articdive:Jnoise:1.0.0' diff --git a/src/main/java/net/minestom/server/entity/metadata/animal/FoxMeta.java b/src/main/java/net/minestom/server/entity/metadata/animal/FoxMeta.java index cc45e76e4..e91063e3d 100644 --- a/src/main/java/net/minestom/server/entity/metadata/animal/FoxMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/animal/FoxMeta.java @@ -3,8 +3,8 @@ package net.minestom.server.entity.metadata.animal; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Metadata; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.UUID; public class FoxMeta extends AnimalMeta { diff --git a/src/main/java/net/minestom/server/registry/ResourceGatherer.java b/src/main/java/net/minestom/server/registry/ResourceGatherer.java index 7af935d5b..914f26dcc 100644 --- a/src/main/java/net/minestom/server/registry/ResourceGatherer.java +++ b/src/main/java/net/minestom/server/registry/ResourceGatherer.java @@ -5,16 +5,27 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.io.FastBufferedInputStream; -import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.math.BigInteger; import java.net.URL; -import java.nio.file.*; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; /** * Responsible for making sure Minestom has the necessary files to run (notably registry files) @@ -177,13 +188,19 @@ public class ResourceGatherer { } // Verify checksum try (FileInputStream fis = new FileInputStream(target)) { - String sha1Target = DigestUtils.sha1Hex(fis); + MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); + messageDigest.reset(); + // This just converts the sha1 back into a readable string. + String sha1Target = new BigInteger(1, messageDigest.digest(fis.readAllBytes())).toString(16); if (!sha1Target.equals(sha1Source)) { - LOGGER.debug("The checksum test failed after downloading the Minecraft server jar."); - LOGGER.debug("The expected checksum was: {}.", sha1Source); - LOGGER.debug("The calculated checksum was: {}.", sha1Target); + LOGGER.error("The checksum test failed after downloading the Minecraft server jar."); + LOGGER.error("The expected checksum was: {}.", sha1Source); + LOGGER.error("The calculated checksum was: {}.", sha1Target); throw new IOException("Failed to download Minecraft server jar."); } + } catch (NoSuchAlgorithmException e) { + LOGGER.error("Failed to find SHA-1 hashing algorithm in Java Environment."); + throw new IOException("Failed to download Minecraft server jar."); } return target; } From 512ec8dcbcf66a2c3e6f2f63af984a30bb6fb38f Mon Sep 17 00:00:00 2001 From: LeoDog896 Date: Tue, 6 Apr 2021 22:28:12 -0400 Subject: [PATCH 04/66] Catch command execution --- .../server/command/builder/ParsedCommand.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/minestom/server/command/builder/ParsedCommand.java b/src/main/java/net/minestom/server/command/builder/ParsedCommand.java index cc3059af2..496f4023b 100644 --- a/src/main/java/net/minestom/server/command/builder/ParsedCommand.java +++ b/src/main/java/net/minestom/server/command/builder/ParsedCommand.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder; +import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.condition.CommandCondition; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; @@ -54,11 +55,19 @@ public class ParsedCommand { final CommandCondition commandCondition = syntax.getCommandCondition(); if (commandCondition == null || commandCondition.canUse(source, commandString)) { context.retrieveDefaultValues(syntax.getDefaultValuesMap()); - executor.apply(source, context); + try { + executor.apply(source, context); + } catch (Exception exception) { + MinecraftServer.getExceptionManager().handleException(exception); + } } } else { // The executor is probably the default one - executor.apply(source, context); + try { + executor.apply(source, context); + } catch (Exception exception) { + MinecraftServer.getExceptionManager().handleException(exception); + } } } else if (callback != null && argumentSyntaxException != null) { // No syntax has been validated but the faulty argument with a callback has been found From 5e4af20992ac4d48480548819b00c32f5b189934 Mon Sep 17 00:00:00 2001 From: LeoDog896 Date: Tue, 6 Apr 2021 22:29:24 -0400 Subject: [PATCH 05/66] And handle event exceptions --- .../server/event/handler/EventHandler.java | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/minestom/server/event/handler/EventHandler.java b/src/main/java/net/minestom/server/event/handler/EventHandler.java index 5bb0bf40a..071ad043d 100644 --- a/src/main/java/net/minestom/server/event/handler/EventHandler.java +++ b/src/main/java/net/minestom/server/event/handler/EventHandler.java @@ -109,22 +109,27 @@ public interface EventHandler extends IExtensionObserver { */ default void callEvent(@NotNull Class eventClass, @NotNull E event) { - // Global listeners - if (!(this instanceof GlobalEventHandler)) { - final GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler(); - runEvent(globalEventHandler.getEventCallbacks(eventClass), event); - } + try { - // Local listeners - final Collection eventCallbacks = getEventCallbacks(eventClass); - runEvent(eventCallbacks, event); - - // Call the same event for the current entity instance - if (this instanceof Entity) { - final Instance instance = ((Entity) this).getInstance(); - if (instance != null) { - runEvent(instance.getEventCallbacks(eventClass), event); + // Global listeners + if (!(this instanceof GlobalEventHandler)) { + final GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler(); + runEvent(globalEventHandler.getEventCallbacks(eventClass), event); } + + // Local listeners + final Collection eventCallbacks = getEventCallbacks(eventClass); + runEvent(eventCallbacks, event); + + // Call the same event for the current entity instance + if (this instanceof Entity) { + final Instance instance = ((Entity) this).getInstance(); + if (instance != null) { + runEvent(instance.getEventCallbacks(eventClass), event); + } + } + } catch (Exception exception) { + MinecraftServer.getExceptionManager().handleException(exception); } } From a9d2f4e8ca7f830955e142bbcd40a022640b5e46 Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Wed, 5 May 2021 18:21:38 +0100 Subject: [PATCH 06/66] Respect client chat settings --- .../audience/PacketGroupingAudience.java | 5 +- .../net/minestom/server/entity/Player.java | 32 +++-- .../server/listener/ChatMessageListener.java | 28 ++-- .../server/listener/SettingsListener.java | 2 +- .../server/message/ChatMessageType.java | 65 +++++++++ .../minestom/server/message/ChatPosition.java | 79 +++++++++++ .../minestom/server/message/Messenger.java | 126 ++++++++++++++++++ .../client/play/ClientSettingsPacket.java | 7 +- .../packet/server/play/ChatMessagePacket.java | 56 ++------ .../net/minestom/server/utils/Action.java | 17 +++ 10 files changed, 341 insertions(+), 76 deletions(-) create mode 100644 src/main/java/net/minestom/server/message/ChatMessageType.java create mode 100644 src/main/java/net/minestom/server/message/ChatPosition.java create mode 100644 src/main/java/net/minestom/server/message/Messenger.java create mode 100644 src/main/java/net/minestom/server/utils/Action.java diff --git a/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java b/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java index f391c8765..2a2329374 100644 --- a/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java +++ b/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java @@ -12,7 +12,8 @@ import net.kyori.adventure.title.Title; import net.minestom.server.MinecraftServer; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.entity.Player; -import net.minestom.server.network.packet.server.play.ChatMessagePacket; +import net.minestom.server.message.ChatPosition; +import net.minestom.server.message.Messenger; import net.minestom.server.network.packet.server.play.PlayerListHeaderAndFooterPacket; import net.minestom.server.network.packet.server.play.TitlePacket; import net.minestom.server.utils.PacketUtils; @@ -46,7 +47,7 @@ public interface PacketGroupingAudience extends ForwardingAudience { @Override default void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) { - PacketUtils.sendGroupedPacket(this.getPlayers(), new ChatMessagePacket(message, ChatMessagePacket.Position.fromMessageType(type), source.uuid())); + Messenger.sendMessage(this.getPlayers(), message, ChatPosition.fromMessageType(type), source.uuid()); } @Override diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 4ed2c950d..dce6aab68 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -38,12 +38,15 @@ import net.minestom.server.event.player.*; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.CustomBlock; +import net.minestom.server.message.ChatMessageType; +import net.minestom.server.message.ChatPosition; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.metadata.WrittenBookMeta; import net.minestom.server.listener.PlayerDiggingListener; +import net.minestom.server.message.Messenger; import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.PlayerProvider; @@ -69,7 +72,6 @@ import net.minestom.server.utils.entity.EntityUtils; import net.minestom.server.utils.identity.NamedAndIdentified; import net.minestom.server.utils.instance.InstanceUtils; import net.minestom.server.utils.inventory.PlayerInventoryUtils; -import net.minestom.server.utils.player.PlayerUtils; import net.minestom.server.utils.time.Cooldown; import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.time.UpdateOption; @@ -739,8 +741,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, @Override public void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) { - ChatMessagePacket chatMessagePacket = new ChatMessagePacket(message, ChatMessagePacket.Position.fromMessageType(type), source.uuid()); - playerConnection.sendPacket(chatMessagePacket); + Messenger.sendMessage(this, message, ChatPosition.fromMessageType(type), source.uuid()); } /** @@ -2599,6 +2600,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable, RIGHT } + /** + * @deprecated See {@link ChatMessageType} + */ + @Deprecated public enum ChatMode { ENABLED, COMMANDS_ONLY, @@ -2609,7 +2614,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, private String locale; private byte viewDistance; - private ChatMode chatMode; + private ChatMessageType chatMessageType; private boolean chatColors; private byte displayedSkinParts; private MainHand mainHand; @@ -2638,7 +2643,16 @@ public class Player extends LivingEntity implements CommandSender, Localizable, * @return the player chat mode */ public ChatMode getChatMode() { - return chatMode; + return ChatMode.values()[chatMessageType.ordinal()]; + } + + /** + * Gets the messages this player wants to receive. + * + * @return the messages + */ + public @NotNull ChatMessageType getChatMessageType() { + return chatMessageType; } /** @@ -2670,19 +2684,19 @@ public class Player extends LivingEntity implements CommandSender, Localizable, * * @param locale the player locale * @param viewDistance the player view distance - * @param chatMode the player chat mode - * @param chatColors the player chat colors + * @param chatMessageType the chat messages the player wishes to receive + * @param chatColors if chat colors should be displayed * @param displayedSkinParts the player displayed skin parts * @param mainHand the player main hand */ - public void refresh(String locale, byte viewDistance, ChatMode chatMode, boolean chatColors, + public void refresh(String locale, byte viewDistance, ChatMessageType chatMessageType, boolean chatColors, byte displayedSkinParts, MainHand mainHand) { final boolean viewDistanceChanged = this.viewDistance != viewDistance; this.locale = locale; this.viewDistance = viewDistance; - this.chatMode = chatMode; + this.chatMessageType = chatMessageType; this.chatColors = chatColors; this.displayedSkinParts = displayedSkinParts; this.mainHand = mainHand; diff --git a/src/main/java/net/minestom/server/listener/ChatMessageListener.java b/src/main/java/net/minestom/server/listener/ChatMessageListener.java index 1f5e56a49..d58525f69 100644 --- a/src/main/java/net/minestom/server/listener/ChatMessageListener.java +++ b/src/main/java/net/minestom/server/listener/ChatMessageListener.java @@ -6,10 +6,10 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandManager; import net.minestom.server.entity.Player; import net.minestom.server.event.player.PlayerChatEvent; +import net.minestom.server.message.ChatPosition; +import net.minestom.server.message.Messenger; import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.packet.client.play.ClientChatMessagePacket; -import net.minestom.server.network.packet.server.play.ChatMessagePacket; -import net.minestom.server.utils.PacketUtils; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -26,21 +26,26 @@ public class ChatMessageListener { final String cmdPrefix = CommandManager.COMMAND_PREFIX; if (message.startsWith(cmdPrefix)) { // The message is a command - message = message.replaceFirst(cmdPrefix, ""); + final String command = message.replaceFirst(cmdPrefix, ""); - COMMAND_MANAGER.execute(player, message); + // check if we can receive commands + Messenger.receiveCommand(player, () -> COMMAND_MANAGER.execute(player, command)); // Do not call chat event return; } + // check if we can receive messages + if (!Messenger.canReceiveMessage(player)) { + Messenger.sendRejectionMessage(player); + return; + } + final Collection players = CONNECTION_MANAGER.getOnlinePlayers(); - String finalMessage = message; - PlayerChatEvent playerChatEvent = new PlayerChatEvent(player, players, () -> buildDefaultChatMessage(player, finalMessage), message); + PlayerChatEvent playerChatEvent = new PlayerChatEvent(player, players, () -> buildDefaultChatMessage(player, message), message); // Call the event player.callCancellableEvent(PlayerChatEvent.class, playerChatEvent, () -> { - final Function formatFunction = playerChatEvent.getChatFormatFunction(); Component textObject; @@ -55,15 +60,10 @@ public class ChatMessageListener { final Collection recipients = playerChatEvent.getRecipients(); if (!recipients.isEmpty()) { - // Send the message with the correct player UUID - ChatMessagePacket chatMessagePacket = - new ChatMessagePacket(textObject, ChatMessagePacket.Position.CHAT, player.getUuid()); - - PacketUtils.sendGroupedPacket(recipients, chatMessagePacket); + // delegate to the messenger to avoid sending messages we shouldn't be + Messenger.sendMessage(recipients, textObject, ChatPosition.CHAT, player.getUuid()); } - }); - } private static @NotNull Component buildDefaultChatMessage(@NotNull Player player, @NotNull String message) { diff --git a/src/main/java/net/minestom/server/listener/SettingsListener.java b/src/main/java/net/minestom/server/listener/SettingsListener.java index 7f23840be..3099a8226 100644 --- a/src/main/java/net/minestom/server/listener/SettingsListener.java +++ b/src/main/java/net/minestom/server/listener/SettingsListener.java @@ -8,7 +8,7 @@ public class SettingsListener { public static void listener(ClientSettingsPacket packet, Player player) { Player.PlayerSettings settings = player.getSettings(); - settings.refresh(packet.locale, packet.viewDistance, packet.chatMode, packet.chatColors, packet.displayedSkinParts, packet.mainHand); + settings.refresh(packet.locale, packet.viewDistance, packet.chatMessageType, packet.chatColors, packet.displayedSkinParts, packet.mainHand); PlayerSettingsChangeEvent playerSettingsChangeEvent = new PlayerSettingsChangeEvent(player); player.callEvent(PlayerSettingsChangeEvent.class, playerSettingsChangeEvent); diff --git a/src/main/java/net/minestom/server/message/ChatMessageType.java b/src/main/java/net/minestom/server/message/ChatMessageType.java new file mode 100644 index 000000000..73bf2fffd --- /dev/null +++ b/src/main/java/net/minestom/server/message/ChatMessageType.java @@ -0,0 +1,65 @@ +package net.minestom.server.message; + +import org.jetbrains.annotations.NotNull; + +import java.util.EnumSet; + +/** + * The messages that a player is willing to receive. + */ +public enum ChatMessageType { + /** + * The client wants all chat messages. + */ + FULL(EnumSet.allOf(ChatPosition.class)), + + /** + * The client only wants messages from commands, or system messages. + */ + SYSTEM(EnumSet.of(ChatPosition.SYSTEM_MESSAGE, ChatPosition.GAME_INFO)), + + /** + * The client doesn't want any messages. + */ + NONE(EnumSet.of(ChatPosition.GAME_INFO)); + + private final EnumSet acceptedPositions; + + ChatMessageType(@NotNull EnumSet acceptedPositions) { + this.acceptedPositions = acceptedPositions; + } + + /** + * Checks if this message type is accepting of messages from a given position. + * + * @param chatPosition the position + * @return if the message is accepted + */ + public boolean accepts(@NotNull ChatPosition chatPosition) { + return this.acceptedPositions.contains(chatPosition); + } + + /** + * Gets the packet ID for this chat message type. + * + * @return the packet ID + */ + public int getPacketID() { + return this.ordinal(); + } + + /** + * Gets a chat message type from a packet ID. + * + * @param id the packet ID + * @return the chat message type + */ + public static @NotNull ChatMessageType fromPacketID(int id) { + switch (id) { + case 0: return FULL; + case 1: return SYSTEM; + case 2: return NONE; + default: throw new IllegalArgumentException("id must be between 0-2 (inclusive)"); + } + } +} diff --git a/src/main/java/net/minestom/server/message/ChatPosition.java b/src/main/java/net/minestom/server/message/ChatPosition.java new file mode 100644 index 000000000..345fa0677 --- /dev/null +++ b/src/main/java/net/minestom/server/message/ChatPosition.java @@ -0,0 +1,79 @@ +package net.minestom.server.message; + +import net.kyori.adventure.audience.MessageType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The different positions for chat messages. + */ +public enum ChatPosition { + /** + * A player-initiated chat message. + */ + CHAT(MessageType.CHAT), + + /** + * Feedback from running a command or other system messages. + */ + SYSTEM_MESSAGE(MessageType.SYSTEM), + + /** + * Game state information displayed above the hot bar. + */ + GAME_INFO(null); + + private final MessageType messageType; + + ChatPosition(@NotNull MessageType messageType) { + this.messageType = messageType; + } + + /** + * Gets the Adventure message type from this position. Note that there is no + * message type for {@link #GAME_INFO}, as Adventure uses the title methods for this. + * + * @return the message type, if any + */ + public @Nullable MessageType getMessageType() { + return this.messageType; + } + + /** + * Gets the packet ID of this chat position. + * + * @return the ID + */ + public byte getID() { + return (byte) this.ordinal(); + } + + /** + * Gets a position from an Adventure message type. + * + * @param messageType the message type + * @return the position + */ + public static @NotNull ChatPosition fromMessageType(@NotNull MessageType messageType) { + switch (messageType) { + case CHAT: return CHAT; + case SYSTEM: return SYSTEM_MESSAGE; + } + throw new IllegalArgumentException("Cannot get position from message type!"); + } + + /** + * Gets a position from a packet ID. + * + * @param id the id + * @return the chat position + */ + public static @NotNull ChatPosition fromPacketID(byte id) { + switch (id) { + case 0: return CHAT; + case 1: return SYSTEM_MESSAGE; + case 2: return GAME_INFO; + default: throw new IllegalArgumentException("id must be between 0-2 (inclusive)"); + } + } +} diff --git a/src/main/java/net/minestom/server/message/Messenger.java b/src/main/java/net/minestom/server/message/Messenger.java new file mode 100644 index 000000000..0e5e69bfc --- /dev/null +++ b/src/main/java/net/minestom/server/message/Messenger.java @@ -0,0 +1,126 @@ +package net.minestom.server.message; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.entity.Player; +import net.minestom.server.network.packet.server.play.ChatMessagePacket; +import net.minestom.server.utils.Action; +import net.minestom.server.utils.PacketUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * Utility class to handle client chat settings. + */ +public class Messenger { + /** + * The message sent to the client if they send a chat message but it is rejected by the server. + */ + public static final Component CANNOT_SEND_MESSAGE = Component.translatable("chat.cannotSend", NamedTextColor.RED); + + private static final ChatMessagePacket CANNOT_SEND_PACKET = new ChatMessagePacket(CANNOT_SEND_MESSAGE, ChatPosition.SYSTEM_MESSAGE, null); + + /** + * Sends a message to a player, respecting their chat settings. + * + * @param player the player + * @param message the message + * @param position the position + * @param uuid the UUID of the sender, if any + * @return if the message was sent + */ + public static boolean sendMessage(@NotNull Player player, @NotNull Component message, @NotNull ChatPosition position, @Nullable UUID uuid) { + if (player.getSettings().getChatMessageType().accepts(position)) { + player.getPlayerConnection().sendPacket(new ChatMessagePacket(message, position, uuid)); + return true; + } + + return false; + } + + /** + * Sends a message to some players, respecting their chat settings. + * + * @param players the players + * @param message the message + * @param position the position + * @param uuid the UUID of the sender, if any + * @return a set of players who received the message + */ + public static @NotNull Set sendMessage(@NotNull Iterable players, @NotNull Component message, + @NotNull ChatPosition position, @Nullable UUID uuid) { + final Set sentTo = new HashSet<>(); + + for (Player player : players) { + if (player.getSettings().getChatMessageType().accepts(position)) { + sentTo.add(player); + } + } + + PacketUtils.sendGroupedPacket(sentTo, new ChatMessagePacket(message, position, uuid)); + return sentTo; + } + + /** + * Checks if the server should receive messages from a player, given their chat settings. + * + * @param player the player + * @return if the server should receive messages from them + */ + public static boolean canReceiveMessage(@NotNull Player player) { + return player.getSettings().getChatMessageType() == ChatMessageType.FULL; + } + + /** + * Performs an action if the server can receive messages from a player. + * This method will send the rejection message automatically. + * + * @param player the player + * @param action the action + */ + public static void receiveMessage(@NotNull Player player, @NotNull Action action) { + if (canReceiveMessage(player)) { + action.act(); + } else { + sendRejectionMessage(player); + } + } + + /** + * Checks if the server should receive commands from a player, given their chat settings. + * + * @param player the player + * @return if the server should receive commands from them + */ + public static boolean canReceiveCommand(@NotNull Player player) { + return player.getSettings().getChatMessageType() != ChatMessageType.NONE; + } + + /** + * Performs an action if the server can receive commands from a player. + * This method will send the rejection message automatically. + * + * @param player the player + * @param action the action + */ + public static void receiveCommand(@NotNull Player player, @NotNull Action action) { + if (canReceiveCommand(player)) { + action.act(); + } else { + sendRejectionMessage(player); + } + } + + /** + * Sends a message to the player informing them we are rejecting their message or command. + * + * @param player the player + */ + public static void sendRejectionMessage(@NotNull Player player) { + player.getPlayerConnection().sendPacket(CANNOT_SEND_PACKET); + } +} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSettingsPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSettingsPacket.java index 968216cc9..8af3da577 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSettingsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSettingsPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.entity.Player; +import net.minestom.server.message.ChatMessageType; import net.minestom.server.network.packet.client.ClientPlayPacket; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; @@ -10,7 +11,7 @@ public class ClientSettingsPacket extends ClientPlayPacket { public String locale = ""; public byte viewDistance; - public Player.ChatMode chatMode = Player.ChatMode.ENABLED; + public ChatMessageType chatMessageType = ChatMessageType.FULL; public boolean chatColors; public byte displayedSkinParts; public Player.MainHand mainHand = Player.MainHand.RIGHT; @@ -19,7 +20,7 @@ public class ClientSettingsPacket extends ClientPlayPacket { public void read(@NotNull BinaryReader reader) { this.locale = reader.readSizedString(128); this.viewDistance = reader.readByte(); - this.chatMode = Player.ChatMode.values()[reader.readVarInt()]; + this.chatMessageType = ChatMessageType.fromPacketID(reader.readVarInt()); this.chatColors = reader.readBoolean(); this.displayedSkinParts = reader.readByte(); this.mainHand = Player.MainHand.values()[reader.readVarInt()]; @@ -31,7 +32,7 @@ public class ClientSettingsPacket extends ClientPlayPacket { throw new IllegalArgumentException("Locale cannot be longer than 128 characters."); writer.writeSizedString(locale); writer.writeByte(viewDistance); - writer.writeVarInt(chatMode.ordinal()); + writer.writeVarInt(chatMessageType.getPacketID()); writer.writeBoolean(chatColors); writer.writeByte(displayedSkinParts); writer.writeVarInt(mainHand.ordinal()); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChatMessagePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChatMessagePacket.java index cc9f57195..246edb55d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChatMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChatMessagePacket.java @@ -1,7 +1,7 @@ package net.minestom.server.network.packet.server.play; -import net.kyori.adventure.audience.MessageType; import net.kyori.adventure.text.Component; +import net.minestom.server.message.ChatPosition; import net.minestom.server.network.packet.server.ComponentHoldingServerPacket; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; @@ -12,6 +12,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; +import java.util.Objects; import java.util.UUID; import java.util.function.UnaryOperator; @@ -22,21 +23,19 @@ public class ChatMessagePacket implements ComponentHoldingServerPacket { private static final UUID NULL_UUID = new UUID(0, 0); public Component message; - public Position position; + public ChatPosition position; public UUID uuid; public ChatMessagePacket() { - this(Component.empty(), Position.CHAT); + this.message = Component.empty(); + this.position = ChatPosition.SYSTEM_MESSAGE; + this.uuid = NULL_UUID; } - public ChatMessagePacket(Component message, Position position, UUID uuid) { + public ChatMessagePacket(@NotNull Component message, @NotNull ChatPosition position, @Nullable UUID uuid) { this.message = message; this.position = position; - this.uuid = uuid; - } - - public ChatMessagePacket(Component message, Position position) { - this(message, position, NULL_UUID); + this.uuid = Objects.requireNonNullElse(uuid, NULL_UUID); } @Override @@ -49,7 +48,7 @@ public class ChatMessagePacket implements ComponentHoldingServerPacket { @Override public void read(@NotNull BinaryReader reader) { message = reader.readComponent(Integer.MAX_VALUE); - position = Position.values()[reader.readByte()]; + position = ChatPosition.fromPacketID(reader.readByte()); uuid = reader.readUuid(); } @@ -67,41 +66,4 @@ public class ChatMessagePacket implements ComponentHoldingServerPacket { public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator operator) { return new ChatMessagePacket(operator.apply(message), position, uuid); } - - public enum Position { - CHAT(MessageType.CHAT), - SYSTEM_MESSAGE(MessageType.SYSTEM), - GAME_INFO(null); - - private final MessageType messageType; - - Position(MessageType messageType) { - this.messageType = messageType; - } - - /** - * Gets the Adventure message type from this position. Note that there is no - * message type for {@link #GAME_INFO}, as Adventure uses the title methods for this. - * - * @return the message type, if any - */ - public @Nullable MessageType getMessageType() { - return this.messageType; - } - - /** - * Gets a position from an Adventure message type. - * - * @param messageType the message type - * - * @return the position - */ - public static @NotNull Position fromMessageType(@NotNull MessageType messageType) { - switch (messageType) { - case CHAT: return CHAT; - case SYSTEM: return SYSTEM_MESSAGE; - } - throw new IllegalArgumentException("Cannot get position from message type!"); - } - } } diff --git a/src/main/java/net/minestom/server/utils/Action.java b/src/main/java/net/minestom/server/utils/Action.java new file mode 100644 index 000000000..e2fda399b --- /dev/null +++ b/src/main/java/net/minestom/server/utils/Action.java @@ -0,0 +1,17 @@ +package net.minestom.server.utils; + +/** + * A functional interface to perform an action. + */ +@FunctionalInterface +public interface Action { + /** + * An empty action. + */ + Action EMPTY = () -> {}; + + /** + * Performs the action. + */ + void act(); +} From 2404f19fe22c26f68819db27d783f5fe5ee8085a Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Thu, 6 May 2021 16:12:46 +0100 Subject: [PATCH 07/66] Avoid NPEs when obtaining chat message type from player --- .../net/minestom/server/entity/Player.java | 4 +++- .../minestom/server/message/Messenger.java | 21 ++++++++++++++----- .../network/player/PlayerConnection.java | 2 +- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index dce6aab68..5cebbf447 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -2641,7 +2641,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable, * Gets the player chat mode. * * @return the player chat mode + * @deprecated Use {@link #getChatMessageType()} */ + @Deprecated public ChatMode getChatMode() { return ChatMode.values()[chatMessageType.ordinal()]; } @@ -2651,7 +2653,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, * * @return the messages */ - public @NotNull ChatMessageType getChatMessageType() { + public @Nullable ChatMessageType getChatMessageType() { return chatMessageType; } diff --git a/src/main/java/net/minestom/server/message/Messenger.java b/src/main/java/net/minestom/server/message/Messenger.java index 0e5e69bfc..f6c8f263c 100644 --- a/src/main/java/net/minestom/server/message/Messenger.java +++ b/src/main/java/net/minestom/server/message/Messenger.java @@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.HashSet; +import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -34,7 +35,7 @@ public class Messenger { * @return if the message was sent */ public static boolean sendMessage(@NotNull Player player, @NotNull Component message, @NotNull ChatPosition position, @Nullable UUID uuid) { - if (player.getSettings().getChatMessageType().accepts(position)) { + if (getChatMessageType(player).accepts(position)) { player.getPlayerConnection().sendPacket(new ChatMessagePacket(message, position, uuid)); return true; } @@ -56,7 +57,7 @@ public class Messenger { final Set sentTo = new HashSet<>(); for (Player player : players) { - if (player.getSettings().getChatMessageType().accepts(position)) { + if (getChatMessageType(player).accepts(position)) { sentTo.add(player); } } @@ -72,7 +73,7 @@ public class Messenger { * @return if the server should receive messages from them */ public static boolean canReceiveMessage(@NotNull Player player) { - return player.getSettings().getChatMessageType() == ChatMessageType.FULL; + return getChatMessageType(player) == ChatMessageType.FULL; } /** @@ -97,7 +98,7 @@ public class Messenger { * @return if the server should receive commands from them */ public static boolean canReceiveCommand(@NotNull Player player) { - return player.getSettings().getChatMessageType() != ChatMessageType.NONE; + return getChatMessageType(player) != ChatMessageType.NONE; } /** @@ -121,6 +122,16 @@ public class Messenger { * @param player the player */ public static void sendRejectionMessage(@NotNull Player player) { - player.getPlayerConnection().sendPacket(CANNOT_SEND_PACKET); + player.getPlayerConnection().sendPacket(CANNOT_SEND_PACKET, false); + } + + /** + * Gets the chat message type for a player, returning {@link ChatMessageType#FULL} if not set. + * + * @param player the player + * @return the chat message type + */ + private static @NotNull ChatMessageType getChatMessageType(@NotNull Player player) { + return Objects.requireNonNullElse(player.getSettings().getChatMessageType(), ChatMessageType.FULL); } } diff --git a/src/main/java/net/minestom/server/network/player/PlayerConnection.java b/src/main/java/net/minestom/server/network/player/PlayerConnection.java index 730836dbd..0d890c232 100644 --- a/src/main/java/net/minestom/server/network/player/PlayerConnection.java +++ b/src/main/java/net/minestom/server/network/player/PlayerConnection.java @@ -95,7 +95,7 @@ public abstract class PlayerConnection { } /** - * Serializes the packet and send it to the client, skipping the translation phase. + * Serializes the packet and send it to the client, optionally skipping the translation phase. *

* Also responsible for executing {@link ConnectionManager#onPacketSend(ServerPacketConsumer)} consumers. * From 37f0f797fd9bcfac84e67d490b69efd9a8d36e9c Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Thu, 6 May 2021 16:40:31 +0100 Subject: [PATCH 08/66] Add ability to mimic messages from a player with the echo command --- src/test/java/demo/commands/EchoCommand.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/java/demo/commands/EchoCommand.java b/src/test/java/demo/commands/EchoCommand.java index e04800fc6..67932cbee 100644 --- a/src/test/java/demo/commands/EchoCommand.java +++ b/src/test/java/demo/commands/EchoCommand.java @@ -1,24 +1,32 @@ package demo.commands; +import net.kyori.adventure.audience.MessageType; +import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.arguments.ArgumentType; import net.minestom.server.command.builder.arguments.minecraft.ArgumentComponent; +import net.minestom.server.command.builder.arguments.minecraft.ArgumentUUID; public class EchoCommand extends Command { public EchoCommand() { super("echo"); this.setDefaultExecutor((sender, context) -> sender.sendMessage( - Component.text("Usage: /echo ") + Component.text("Usage: /echo [uuid]") .hoverEvent(Component.text("Click to get this command.") .clickEvent(ClickEvent.suggestCommand("/echo "))))); ArgumentComponent json = ArgumentType.Component("json"); + ArgumentUUID uuid = ArgumentType.UUID("uuid"); this.addSyntax((sender, context) -> { sender.sendMessage(context.get(json)); }, json); + + this.addSyntax((sender, context) -> { + sender.sendMessage(Identity.identity(context.get(uuid)), context.get(json), MessageType.CHAT); + }, uuid, json); } } From 19e22d03ce2b83a22b699caf0bbf6e2c8d50f579 Mon Sep 17 00:00:00 2001 From: TheMode Date: Tue, 11 May 2021 08:35:42 +0200 Subject: [PATCH 09/66] Deprecate packet listening API --- .../server/network/ConnectionManager.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index 932a6c0b7..49176c461 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -188,8 +188,12 @@ public final class ConnectionManager { * Gets all the listeners which are called for each packet received. * * @return a list of packet's consumers + * @deprecated all packet listening methods will ultimately be removed. + * May or may not work depending on the packet. + * It is instead recommended to use a proxy, improving scalability and increasing server performance */ @NotNull + @Deprecated public List getReceivePacketConsumers() { return receiveClientPacketConsumers; } @@ -198,7 +202,11 @@ public final class ConnectionManager { * Adds a consumer to call once a packet is received. * * @param clientPacketConsumer the packet consumer + * @deprecated all packet listening methods will ultimately be removed. + * May or may not work depending on the packet. + * It is instead recommended to use a proxy, improving scalability and increasing server performance */ + @Deprecated public void onPacketReceive(@NotNull ClientPacketConsumer clientPacketConsumer) { this.receiveClientPacketConsumers.add(clientPacketConsumer); } @@ -207,8 +215,12 @@ public final class ConnectionManager { * Gets all the listeners which are called for each packet sent. * * @return a list of packet's consumers + * @deprecated all packet listening methods will ultimately be removed. + * May or may not work depending on the packet. + * It is instead recommended to use a proxy, improving scalability and increasing server performance */ @NotNull + @Deprecated public List getSendPacketConsumers() { return sendClientPacketConsumers; } @@ -217,7 +229,11 @@ public final class ConnectionManager { * Adds a consumer to call once a packet is sent. * * @param serverPacketConsumer the packet consumer + * @deprecated all packet listening methods will ultimately be removed. + * May or may not work depending on the packet. + * It is instead recommended to use a proxy, improving scalability and increasing server performance */ + @Deprecated public void onPacketSend(@NotNull ServerPacketConsumer serverPacketConsumer) { this.sendClientPacketConsumers.add(serverPacketConsumer); } From 29b0f5448d4cacecbfce21ef275c32b42d6d32e9 Mon Sep 17 00:00:00 2001 From: Arne Dalhuisen <59421074+Bloepiloepi@users.noreply.github.com> Date: Tue, 11 May 2021 14:10:45 +0200 Subject: [PATCH 10/66] Moved EquipmentSlot out of equipment packet --- .../minestom/server/entity/EquipmentSlot.java | 49 +++++++++++++++++++ .../minestom/server/entity/LivingEntity.java | 12 ++--- .../net/minestom/server/entity/Player.java | 2 +- .../type/decoration/EntityArmorStand.java | 18 +++---- .../server/inventory/EquipmentHandler.java | 13 ++--- .../server/inventory/PlayerInventory.java | 10 ++-- .../server/play/EntityEquipmentPacket.java | 37 +++----------- .../readwritepackets/ReadWritePackets.java | 3 +- 8 files changed, 83 insertions(+), 61 deletions(-) create mode 100644 src/main/java/net/minestom/server/entity/EquipmentSlot.java diff --git a/src/main/java/net/minestom/server/entity/EquipmentSlot.java b/src/main/java/net/minestom/server/entity/EquipmentSlot.java new file mode 100644 index 000000000..c269bfcaf --- /dev/null +++ b/src/main/java/net/minestom/server/entity/EquipmentSlot.java @@ -0,0 +1,49 @@ +package net.minestom.server.entity; + +import net.minestom.server.event.item.ArmorEquipEvent; +import net.minestom.server.item.attribute.AttributeSlot; +import org.jetbrains.annotations.NotNull; + +public enum EquipmentSlot { + MAIN_HAND, + OFF_HAND, + BOOTS, + LEGGINGS, + CHESTPLATE, + HELMET; + + @NotNull + public static EquipmentSlot fromArmorSlot(ArmorEquipEvent.ArmorSlot armorSlot) { + switch (armorSlot) { + case HELMET: + return HELMET; + case CHESTPLATE: + return CHESTPLATE; + case LEGGINGS: + return LEGGINGS; + case BOOTS: + return BOOTS; + } + throw new IllegalStateException("Something weird happened"); + } + + @NotNull + public static EquipmentSlot fromAttributeSlot(AttributeSlot attributeSlot) { + switch (attributeSlot) { + case MAINHAND: + return MAIN_HAND; + case OFFHAND: + return OFF_HAND; + case FEET: + return BOOTS; + case LEGS: + return LEGGINGS; + case CHEST: + return CHESTPLATE; + case HEAD: + return HELMET; + } + throw new IllegalStateException("Something weird happened"); + } + +} diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index 1c9a27c7b..a7f99c053 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -128,7 +128,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setItemInMainHand(@NotNull ItemStack itemStack) { this.mainHandItem = itemStack; - syncEquipment(EntityEquipmentPacket.Slot.MAIN_HAND); + syncEquipment(EquipmentSlot.MAIN_HAND); } @NotNull @@ -140,7 +140,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setItemInOffHand(@NotNull ItemStack itemStack) { this.offHandItem = itemStack; - syncEquipment(EntityEquipmentPacket.Slot.OFF_HAND); + syncEquipment(EquipmentSlot.OFF_HAND); } @NotNull @@ -152,7 +152,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setHelmet(@NotNull ItemStack itemStack) { this.helmet = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.HELMET); - syncEquipment(EntityEquipmentPacket.Slot.HELMET); + syncEquipment(EquipmentSlot.HELMET); } @NotNull @@ -164,7 +164,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setChestplate(@NotNull ItemStack itemStack) { this.chestplate = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.CHESTPLATE); - syncEquipment(EntityEquipmentPacket.Slot.CHESTPLATE); + syncEquipment(EquipmentSlot.CHESTPLATE); } @NotNull @@ -176,7 +176,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setLeggings(@NotNull ItemStack itemStack) { this.leggings = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.LEGGINGS); - syncEquipment(EntityEquipmentPacket.Slot.LEGGINGS); + syncEquipment(EquipmentSlot.LEGGINGS); } @NotNull @@ -188,7 +188,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setBoots(@NotNull ItemStack itemStack) { this.boots = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.BOOTS); - syncEquipment(EntityEquipmentPacket.Slot.BOOTS); + syncEquipment(EquipmentSlot.BOOTS); } private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull ArmorEquipEvent.ArmorSlot armorSlot) { diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 8a7ecad0c..282bdea57 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -2256,7 +2256,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, */ public void refreshHeldSlot(byte slot) { this.heldSlot = slot; - syncEquipment(EntityEquipmentPacket.Slot.MAIN_HAND); + syncEquipment(EquipmentSlot.MAIN_HAND); refreshEating(null); } diff --git a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java index 89a600d02..a89decefc 100644 --- a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java +++ b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java @@ -1,13 +1,9 @@ package net.minestom.server.entity.type.decoration; -import net.minestom.server.entity.EntityType; -import net.minestom.server.entity.Metadata; -import net.minestom.server.entity.ObjectEntity; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.*; import net.minestom.server.event.item.ArmorEquipEvent; import net.minestom.server.inventory.EquipmentHandler; import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; import net.minestom.server.utils.Position; import net.minestom.server.utils.Vector; import net.minestom.server.utils.binary.BitmaskUtil; @@ -74,7 +70,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setItemInMainHand(@NotNull ItemStack itemStack) { this.mainHandItem = itemStack; - syncEquipment(EntityEquipmentPacket.Slot.MAIN_HAND); + syncEquipment(EquipmentSlot.MAIN_HAND); } @NotNull @@ -86,7 +82,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setItemInOffHand(@NotNull ItemStack itemStack) { this.offHandItem = itemStack; - syncEquipment(EntityEquipmentPacket.Slot.OFF_HAND); + syncEquipment(EquipmentSlot.OFF_HAND); } @NotNull @@ -98,7 +94,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setHelmet(@NotNull ItemStack itemStack) { this.helmet = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.HELMET); - syncEquipment(EntityEquipmentPacket.Slot.HELMET); + syncEquipment(EquipmentSlot.HELMET); } @NotNull @@ -110,7 +106,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setChestplate(@NotNull ItemStack itemStack) { this.chestplate = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.CHESTPLATE); - syncEquipment(EntityEquipmentPacket.Slot.CHESTPLATE); + syncEquipment(EquipmentSlot.CHESTPLATE); } @NotNull @@ -122,7 +118,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setLeggings(@NotNull ItemStack itemStack) { this.leggings = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.LEGGINGS); - syncEquipment(EntityEquipmentPacket.Slot.LEGGINGS); + syncEquipment(EquipmentSlot.LEGGINGS); } @NotNull @@ -134,7 +130,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setBoots(@NotNull ItemStack itemStack) { this.boots = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.BOOTS); - syncEquipment(EntityEquipmentPacket.Slot.BOOTS); + syncEquipment(EquipmentSlot.BOOTS); } public boolean isSmall() { diff --git a/src/main/java/net/minestom/server/inventory/EquipmentHandler.java b/src/main/java/net/minestom/server/inventory/EquipmentHandler.java index e515112aa..8d6562132 100644 --- a/src/main/java/net/minestom/server/inventory/EquipmentHandler.java +++ b/src/main/java/net/minestom/server/inventory/EquipmentHandler.java @@ -1,6 +1,7 @@ package net.minestom.server.inventory; import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.entity.Player; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; @@ -139,7 +140,7 @@ public interface EquipmentHandler { * @param slot the equipment to get the item from * @return the equipment {@link ItemStack} */ - default @NotNull ItemStack getEquipment(@NotNull EntityEquipmentPacket.Slot slot) { + default @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot) { switch (slot) { case MAIN_HAND: return getItemInMainHand(); @@ -157,7 +158,7 @@ public interface EquipmentHandler { throw new IllegalStateException("Something weird happened"); } - default void setEquipment(@NotNull EntityEquipmentPacket.Slot slot, @NotNull ItemStack itemStack) { + default void setEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) { switch (slot) { case MAIN_HAND: setItemInMainHand(itemStack); @@ -187,7 +188,7 @@ public interface EquipmentHandler { * * @param slot the slot of the equipment */ - default void syncEquipment(@NotNull EntityEquipmentPacket.Slot slot) { + default void syncEquipment(@NotNull EquipmentSlot slot) { Check.stateCondition(!(this instanceof Entity), "Only accessible for Entity"); Entity entity = (Entity) this; @@ -196,7 +197,7 @@ public interface EquipmentHandler { EntityEquipmentPacket entityEquipmentPacket = new EntityEquipmentPacket(); entityEquipmentPacket.entityId = entity.getEntityId(); - entityEquipmentPacket.slots = new EntityEquipmentPacket.Slot[]{slot}; + entityEquipmentPacket.slots = new EquipmentSlot[]{slot}; entityEquipmentPacket.itemStacks = new ItemStack[]{itemStack}; entity.sendPacketToViewers(entityEquipmentPacket); @@ -213,12 +214,12 @@ public interface EquipmentHandler { final Entity entity = (Entity) this; - final EntityEquipmentPacket.Slot[] slots = EntityEquipmentPacket.Slot.values(); + final EquipmentSlot[] slots = EquipmentSlot.values(); List itemStacks = new ArrayList<>(slots.length); // Fill items - for (EntityEquipmentPacket.Slot slot : slots) { + for (EquipmentSlot slot : slots) { final ItemStack equipment = getEquipment(slot); itemStacks.add(equipment); } diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 840850d5b..12f9bfc7a 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -1,12 +1,12 @@ package net.minestom.server.inventory; +import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.entity.Player; import net.minestom.server.event.item.ArmorEquipEvent; import net.minestom.server.inventory.click.ClickType; import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.WindowItemsPacket; import net.minestom.server.utils.MathUtils; @@ -170,12 +170,12 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl "The slot {0} does not exist for player", slot); Check.notNull(itemStack, "The ItemStack cannot be null, you can set air instead"); - EntityEquipmentPacket.Slot equipmentSlot; + EquipmentSlot equipmentSlot; if (slot == player.getHeldSlot()) { - equipmentSlot = EntityEquipmentPacket.Slot.MAIN_HAND; + equipmentSlot = EquipmentSlot.MAIN_HAND; } else if (slot == OFFHAND_SLOT) { - equipmentSlot = EntityEquipmentPacket.Slot.OFF_HAND; + equipmentSlot = EquipmentSlot.OFF_HAND; } else { ArmorEquipEvent armorEquipEvent = null; @@ -191,7 +191,7 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl if (armorEquipEvent != null) { ArmorEquipEvent.ArmorSlot armorSlot = armorEquipEvent.getArmorSlot(); - equipmentSlot = EntityEquipmentPacket.Slot.fromArmorSlot(armorSlot); + equipmentSlot = EquipmentSlot.fromArmorSlot(armorSlot); player.callEvent(ArmorEquipEvent.class, armorEquipEvent); itemStack = armorEquipEvent.getArmorItem(); } else { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java index a2e92abdd..5707fba40 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java @@ -1,6 +1,6 @@ package net.minestom.server.network.packet.server.play; -import net.minestom.server.event.item.ArmorEquipEvent; +import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; @@ -14,7 +14,7 @@ import java.util.List; public class EntityEquipmentPacket implements ServerPacket { public int entityId; - public Slot[] slots; + public EquipmentSlot[] slots; public ItemStack[] itemStacks; public EntityEquipmentPacket() { @@ -33,7 +33,7 @@ public class EntityEquipmentPacket implements ServerPacket { } for (int i = 0; i < slots.length; i++) { - final Slot slot = slots[i]; + final EquipmentSlot slot = slots[i]; final ItemStack itemStack = itemStacks[i]; final boolean last = i == slots.length - 1; @@ -52,17 +52,17 @@ public class EntityEquipmentPacket implements ServerPacket { entityId = reader.readVarInt(); boolean hasRemaining = true; - List slots = new LinkedList<>(); + List slots = new LinkedList<>(); List stacks = new LinkedList<>(); while (hasRemaining) { byte slotEnum = reader.readByte(); hasRemaining = (slotEnum & 0x80) == 0x80; - slots.add(Slot.values()[slotEnum & 0x7F]); + slots.add(EquipmentSlot.values()[slotEnum & 0x7F]); stacks.add(reader.readItemStack()); } - this.slots = slots.toArray(new Slot[0]); + this.slots = slots.toArray(new EquipmentSlot[0]); this.itemStacks = stacks.toArray(new ItemStack[0]); } @@ -71,29 +71,4 @@ public class EntityEquipmentPacket implements ServerPacket { return ServerPacketIdentifier.ENTITY_EQUIPMENT; } - public enum Slot { - MAIN_HAND, - OFF_HAND, - BOOTS, - LEGGINGS, - CHESTPLATE, - HELMET; - - @NotNull - public static Slot fromArmorSlot(ArmorEquipEvent.ArmorSlot armorSlot) { - switch (armorSlot) { - case HELMET: - return HELMET; - case CHESTPLATE: - return CHESTPLATE; - case LEGGINGS: - return LEGGINGS; - case BOOTS: - return BOOTS; - } - throw new IllegalStateException("Something weird happened"); - } - - } - } diff --git a/src/test/java/readwritepackets/ReadWritePackets.java b/src/test/java/readwritepackets/ReadWritePackets.java index 5f28d8152..30d6ace81 100644 --- a/src/test/java/readwritepackets/ReadWritePackets.java +++ b/src/test/java/readwritepackets/ReadWritePackets.java @@ -2,6 +2,7 @@ package readwritepackets; import com.google.common.reflect.ClassPath; import net.minestom.server.MinecraftServer; +import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.server.ServerPacket; @@ -67,7 +68,7 @@ public class ReadWritePackets { // requires at least one slot and one item EntityEquipmentPacket p = new EntityEquipmentPacket(); p.itemStacks = new ItemStack[]{ItemStack.AIR}; - p.slots = new EntityEquipmentPacket.Slot[]{EntityEquipmentPacket.Slot.MAIN_HAND}; + p.slots = new EquipmentSlot[]{EquipmentSlot.MAIN_HAND}; packet = (T) p; } else { packet = (T) constructor.newInstance(); From 92d97c624f9f64b37f1f747c8be9d893c4aa9b4e Mon Sep 17 00:00:00 2001 From: Arne Dalhuisen <59421074+Bloepiloepi@users.noreply.github.com> Date: Tue, 11 May 2021 14:12:19 +0200 Subject: [PATCH 11/66] Added isHand and isArmor to EquipmentSlot --- .../java/net/minestom/server/entity/EquipmentSlot.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/net/minestom/server/entity/EquipmentSlot.java b/src/main/java/net/minestom/server/entity/EquipmentSlot.java index c269bfcaf..6002e181e 100644 --- a/src/main/java/net/minestom/server/entity/EquipmentSlot.java +++ b/src/main/java/net/minestom/server/entity/EquipmentSlot.java @@ -12,6 +12,14 @@ public enum EquipmentSlot { CHESTPLATE, HELMET; + public boolean isHand() { + return this == MAIN_HAND || this == OFF_HAND; + } + + public boolean isArmor() { + return !isHand(); + } + @NotNull public static EquipmentSlot fromArmorSlot(ArmorEquipEvent.ArmorSlot armorSlot) { switch (armorSlot) { From 77ef5f7d4287605503da0ad24bb72f27242487d5 Mon Sep 17 00:00:00 2001 From: Arne Dalhuisen <59421074+Bloepiloepi@users.noreply.github.com> Date: Tue, 11 May 2021 14:45:14 +0200 Subject: [PATCH 12/66] Made EntityEquipEvent, replacing ArmorEquipEvent --- .../minestom/server/entity/EquipmentSlot.java | 17 +-------- .../minestom/server/entity/LivingEntity.java | 22 ++++++------ .../type/decoration/EntityArmorStand.java | 22 ++++++------ ...rEquipEvent.java => EntityEquipEvent.java} | 20 ++++------- .../server/inventory/PlayerInventory.java | 36 ++++++++----------- 5 files changed, 45 insertions(+), 72 deletions(-) rename src/main/java/net/minestom/server/event/item/{ArmorEquipEvent.java => EntityEquipEvent.java} (61%) diff --git a/src/main/java/net/minestom/server/entity/EquipmentSlot.java b/src/main/java/net/minestom/server/entity/EquipmentSlot.java index 6002e181e..27a7cf02d 100644 --- a/src/main/java/net/minestom/server/entity/EquipmentSlot.java +++ b/src/main/java/net/minestom/server/entity/EquipmentSlot.java @@ -1,6 +1,6 @@ package net.minestom.server.entity; -import net.minestom.server.event.item.ArmorEquipEvent; +import net.minestom.server.event.item.EntityEquipEvent; import net.minestom.server.item.attribute.AttributeSlot; import org.jetbrains.annotations.NotNull; @@ -20,21 +20,6 @@ public enum EquipmentSlot { return !isHand(); } - @NotNull - public static EquipmentSlot fromArmorSlot(ArmorEquipEvent.ArmorSlot armorSlot) { - switch (armorSlot) { - case HELMET: - return HELMET; - case CHESTPLATE: - return CHESTPLATE; - case LEGGINGS: - return LEGGINGS; - case BOOTS: - return BOOTS; - } - throw new IllegalStateException("Something weird happened"); - } - @NotNull public static EquipmentSlot fromAttributeSlot(AttributeSlot attributeSlot) { switch (attributeSlot) { diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index a7f99c053..37ac9a77f 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -10,7 +10,7 @@ import net.minestom.server.entity.metadata.LivingEntityMeta; import net.minestom.server.event.entity.EntityDamageEvent; import net.minestom.server.event.entity.EntityDeathEvent; import net.minestom.server.event.entity.EntityFireEvent; -import net.minestom.server.event.item.ArmorEquipEvent; +import net.minestom.server.event.item.EntityEquipEvent; import net.minestom.server.event.item.PickupItemEvent; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.block.Block; @@ -127,7 +127,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setItemInMainHand(@NotNull ItemStack itemStack) { - this.mainHandItem = itemStack; + this.mainHandItem = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); syncEquipment(EquipmentSlot.MAIN_HAND); } @@ -139,7 +139,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setItemInOffHand(@NotNull ItemStack itemStack) { - this.offHandItem = itemStack; + this.offHandItem = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); syncEquipment(EquipmentSlot.OFF_HAND); } @@ -151,7 +151,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setHelmet(@NotNull ItemStack itemStack) { - this.helmet = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.HELMET); + this.helmet = getEquipmentItem(itemStack, EquipmentSlot.HELMET); syncEquipment(EquipmentSlot.HELMET); } @@ -163,7 +163,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setChestplate(@NotNull ItemStack itemStack) { - this.chestplate = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.CHESTPLATE); + this.chestplate = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); syncEquipment(EquipmentSlot.CHESTPLATE); } @@ -175,7 +175,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setLeggings(@NotNull ItemStack itemStack) { - this.leggings = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.LEGGINGS); + this.leggings = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); syncEquipment(EquipmentSlot.LEGGINGS); } @@ -187,14 +187,14 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setBoots(@NotNull ItemStack itemStack) { - this.boots = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.BOOTS); + this.boots = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); syncEquipment(EquipmentSlot.BOOTS); } - private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull ArmorEquipEvent.ArmorSlot armorSlot) { - ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent(this, itemStack, armorSlot); - callEvent(ArmorEquipEvent.class, armorEquipEvent); - return armorEquipEvent.getArmorItem(); + private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { + EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot); + callEvent(EntityEquipEvent.class, entityEquipEvent); + return entityEquipEvent.getArmorItem(); } @Override diff --git a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java index a89decefc..c36c6ffc9 100644 --- a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java +++ b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java @@ -1,7 +1,7 @@ package net.minestom.server.entity.type.decoration; import net.minestom.server.entity.*; -import net.minestom.server.event.item.ArmorEquipEvent; +import net.minestom.server.event.item.EntityEquipEvent; import net.minestom.server.inventory.EquipmentHandler; import net.minestom.server.item.ItemStack; import net.minestom.server.utils.Position; @@ -69,7 +69,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setItemInMainHand(@NotNull ItemStack itemStack) { - this.mainHandItem = itemStack; + this.mainHandItem = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); syncEquipment(EquipmentSlot.MAIN_HAND); } @@ -81,7 +81,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setItemInOffHand(@NotNull ItemStack itemStack) { - this.offHandItem = itemStack; + this.offHandItem = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); syncEquipment(EquipmentSlot.OFF_HAND); } @@ -93,7 +93,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setHelmet(@NotNull ItemStack itemStack) { - this.helmet = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.HELMET); + this.helmet = getEquipmentItem(itemStack, EquipmentSlot.HELMET); syncEquipment(EquipmentSlot.HELMET); } @@ -105,7 +105,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setChestplate(@NotNull ItemStack itemStack) { - this.chestplate = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.CHESTPLATE); + this.chestplate = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); syncEquipment(EquipmentSlot.CHESTPLATE); } @@ -117,7 +117,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setLeggings(@NotNull ItemStack itemStack) { - this.leggings = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.LEGGINGS); + this.leggings = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); syncEquipment(EquipmentSlot.LEGGINGS); } @@ -129,7 +129,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setBoots(@NotNull ItemStack itemStack) { - this.boots = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.BOOTS); + this.boots = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); syncEquipment(EquipmentSlot.BOOTS); } @@ -235,9 +235,9 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { // Equipments - private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull ArmorEquipEvent.ArmorSlot armorSlot) { - ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent(this, itemStack, armorSlot); - callEvent(ArmorEquipEvent.class, armorEquipEvent); - return armorEquipEvent.getArmorItem(); + private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { + EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot); + callEvent(EntityEquipEvent.class, entityEquipEvent); + return entityEquipEvent.getArmorItem(); } } diff --git a/src/main/java/net/minestom/server/event/item/ArmorEquipEvent.java b/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java similarity index 61% rename from src/main/java/net/minestom/server/event/item/ArmorEquipEvent.java rename to src/main/java/net/minestom/server/event/item/EntityEquipEvent.java index f54ba4d32..fc2f2e72e 100644 --- a/src/main/java/net/minestom/server/event/item/ArmorEquipEvent.java +++ b/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java @@ -1,20 +1,21 @@ package net.minestom.server.event.item; import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.event.Event; import net.minestom.server.item.ItemStack; import org.jetbrains.annotations.NotNull; -public class ArmorEquipEvent extends Event { +public class EntityEquipEvent extends Event { private final Entity entity; private ItemStack armorItem; - private final ArmorSlot armorSlot; + private final EquipmentSlot slot; - public ArmorEquipEvent(@NotNull Entity entity, @NotNull ItemStack armorItem, @NotNull ArmorSlot armorSlot) { + public EntityEquipEvent(@NotNull Entity entity, @NotNull ItemStack armorItem, @NotNull EquipmentSlot slot) { this.entity = entity; this.armorItem = armorItem; - this.armorSlot = armorSlot; + this.slot = slot; } @NotNull @@ -32,14 +33,7 @@ public class ArmorEquipEvent extends Event { } @NotNull - public ArmorSlot getArmorSlot() { - return armorSlot; - } - - public enum ArmorSlot { - HELMET, - CHESTPLATE, - LEGGINGS, - BOOTS + public EquipmentSlot getSlot() { + return slot; } } diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 12f9bfc7a..59ee59ae8 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -2,7 +2,7 @@ package net.minestom.server.inventory; import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.entity.Player; -import net.minestom.server.event.item.ArmorEquipEvent; +import net.minestom.server.event.item.EntityEquipEvent; import net.minestom.server.inventory.click.ClickType; import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.inventory.condition.InventoryCondition; @@ -170,33 +170,27 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl "The slot {0} does not exist for player", slot); Check.notNull(itemStack, "The ItemStack cannot be null, you can set air instead"); - EquipmentSlot equipmentSlot; + EquipmentSlot equipmentSlot = null; if (slot == player.getHeldSlot()) { equipmentSlot = EquipmentSlot.MAIN_HAND; } else if (slot == OFFHAND_SLOT) { equipmentSlot = EquipmentSlot.OFF_HAND; - } else { - ArmorEquipEvent armorEquipEvent = null; + } else if (slot == HELMET_SLOT) { + equipmentSlot = EquipmentSlot.HELMET; + } else if (slot == CHESTPLATE_SLOT) { + equipmentSlot = EquipmentSlot.CHESTPLATE; + } else if (slot == LEGGINGS_SLOT) { + equipmentSlot = EquipmentSlot.LEGGINGS; + } else if (slot == BOOTS_SLOT) { + equipmentSlot = EquipmentSlot.BOOTS; + } - if (slot == HELMET_SLOT) { - armorEquipEvent = new ArmorEquipEvent(player, itemStack, ArmorEquipEvent.ArmorSlot.HELMET); - } else if (slot == CHESTPLATE_SLOT) { - armorEquipEvent = new ArmorEquipEvent(player, itemStack, ArmorEquipEvent.ArmorSlot.CHESTPLATE); - } else if (slot == LEGGINGS_SLOT) { - armorEquipEvent = new ArmorEquipEvent(player, itemStack, ArmorEquipEvent.ArmorSlot.LEGGINGS); - } else if (slot == BOOTS_SLOT) { - armorEquipEvent = new ArmorEquipEvent(player, itemStack, ArmorEquipEvent.ArmorSlot.BOOTS); - } + if (equipmentSlot != null) { + EntityEquipEvent entityEquipEvent = new EntityEquipEvent(player, itemStack, equipmentSlot); - if (armorEquipEvent != null) { - ArmorEquipEvent.ArmorSlot armorSlot = armorEquipEvent.getArmorSlot(); - equipmentSlot = EquipmentSlot.fromArmorSlot(armorSlot); - player.callEvent(ArmorEquipEvent.class, armorEquipEvent); - itemStack = armorEquipEvent.getArmorItem(); - } else { - equipmentSlot = null; - } + player.callEvent(EntityEquipEvent.class, entityEquipEvent); + itemStack = entityEquipEvent.getArmorItem(); } this.itemStacks[slot] = itemStack; From ed010ff110e015ee793f59af2bfac56660b07e53 Mon Sep 17 00:00:00 2001 From: Arne Dalhuisen <59421074+Bloepiloepi@users.noreply.github.com> Date: Tue, 11 May 2021 14:48:52 +0200 Subject: [PATCH 13/66] Renamed armorItem to equippedItem in EntityEquipEvent --- .../net/minestom/server/entity/LivingEntity.java | 2 +- .../entity/type/decoration/EntityArmorStand.java | 2 +- .../server/event/item/EntityEquipEvent.java | 14 +++++++------- .../minestom/server/inventory/PlayerInventory.java | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index 37ac9a77f..f03e0849b 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -194,7 +194,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot); callEvent(EntityEquipEvent.class, entityEquipEvent); - return entityEquipEvent.getArmorItem(); + return entityEquipEvent.getEquippedItem(); } @Override diff --git a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java index c36c6ffc9..121146e7b 100644 --- a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java +++ b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java @@ -238,6 +238,6 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot); callEvent(EntityEquipEvent.class, entityEquipEvent); - return entityEquipEvent.getArmorItem(); + return entityEquipEvent.getEquippedItem(); } } diff --git a/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java b/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java index fc2f2e72e..501273eaf 100644 --- a/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java +++ b/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java @@ -9,12 +9,12 @@ import org.jetbrains.annotations.NotNull; public class EntityEquipEvent extends Event { private final Entity entity; - private ItemStack armorItem; + private ItemStack equippedItem; private final EquipmentSlot slot; - public EntityEquipEvent(@NotNull Entity entity, @NotNull ItemStack armorItem, @NotNull EquipmentSlot slot) { + public EntityEquipEvent(@NotNull Entity entity, @NotNull ItemStack equippedItem, @NotNull EquipmentSlot slot) { this.entity = entity; - this.armorItem = armorItem; + this.equippedItem = equippedItem; this.slot = slot; } @@ -24,12 +24,12 @@ public class EntityEquipEvent extends Event { } @NotNull - public ItemStack getArmorItem() { - return armorItem; + public ItemStack getEquippedItem() { + return equippedItem; } - public void setArmorItem(@NotNull ItemStack armorItem) { - this.armorItem = armorItem; + public void setEquippedItem(@NotNull ItemStack armorItem) { + this.equippedItem = armorItem; } @NotNull diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 59ee59ae8..a4723b8fd 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -190,7 +190,7 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl EntityEquipEvent entityEquipEvent = new EntityEquipEvent(player, itemStack, equipmentSlot); player.callEvent(EntityEquipEvent.class, entityEquipEvent); - itemStack = entityEquipEvent.getArmorItem(); + itemStack = entityEquipEvent.getEquippedItem(); } this.itemStacks[slot] = itemStack; From d72fb72e74ad7af34e88406890f14a790f1b9aef Mon Sep 17 00:00:00 2001 From: Arne Dalhuisen <59421074+Bloepiloepi@users.noreply.github.com> Date: Tue, 11 May 2021 17:05:16 +0200 Subject: [PATCH 14/66] Made EntityEquipEvent cancellable --- .../minestom/server/entity/EquipmentSlot.java | 1 - .../minestom/server/entity/LivingEntity.java | 44 +++++++++++++------ .../type/decoration/EntityArmorStand.java | 44 +++++++++++++------ .../server/event/item/EntityEquipEvent.java | 15 ++++++- .../server/inventory/PlayerInventory.java | 6 +++ 5 files changed, 82 insertions(+), 28 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/EquipmentSlot.java b/src/main/java/net/minestom/server/entity/EquipmentSlot.java index 27a7cf02d..7a3b70708 100644 --- a/src/main/java/net/minestom/server/entity/EquipmentSlot.java +++ b/src/main/java/net/minestom/server/entity/EquipmentSlot.java @@ -1,6 +1,5 @@ package net.minestom.server.entity; -import net.minestom.server.event.item.EntityEquipEvent; import net.minestom.server.item.attribute.AttributeSlot; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index f03e0849b..22ddef528 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -127,8 +127,11 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setItemInMainHand(@NotNull ItemStack itemStack) { - this.mainHandItem = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); - syncEquipment(EquipmentSlot.MAIN_HAND); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); + if (itemStack != null) { + this.mainHandItem = itemStack; + syncEquipment(EquipmentSlot.MAIN_HAND); + } } @NotNull @@ -139,8 +142,11 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setItemInOffHand(@NotNull ItemStack itemStack) { - this.offHandItem = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); - syncEquipment(EquipmentSlot.OFF_HAND); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); + if (itemStack != null) { + this.offHandItem = itemStack; + syncEquipment(EquipmentSlot.OFF_HAND); + } } @NotNull @@ -151,8 +157,11 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setHelmet(@NotNull ItemStack itemStack) { - this.helmet = getEquipmentItem(itemStack, EquipmentSlot.HELMET); - syncEquipment(EquipmentSlot.HELMET); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.HELMET); + if (itemStack != null) { + this.helmet = itemStack; + syncEquipment(EquipmentSlot.HELMET); + } } @NotNull @@ -163,8 +172,11 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setChestplate(@NotNull ItemStack itemStack) { - this.chestplate = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); - syncEquipment(EquipmentSlot.CHESTPLATE); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); + if (itemStack != null) { + this.chestplate = itemStack; + syncEquipment(EquipmentSlot.CHESTPLATE); + } } @NotNull @@ -175,8 +187,11 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setLeggings(@NotNull ItemStack itemStack) { - this.leggings = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); - syncEquipment(EquipmentSlot.LEGGINGS); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); + if (itemStack != null) { + this.leggings = itemStack; + syncEquipment(EquipmentSlot.LEGGINGS); + } } @NotNull @@ -187,14 +202,17 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setBoots(@NotNull ItemStack itemStack) { - this.boots = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); - syncEquipment(EquipmentSlot.BOOTS); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); + if (itemStack != null) { + this.boots = itemStack; + syncEquipment(EquipmentSlot.BOOTS); + } } private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot); callEvent(EntityEquipEvent.class, entityEquipEvent); - return entityEquipEvent.getEquippedItem(); + return entityEquipEvent.isCancelled() ? null : entityEquipEvent.getEquippedItem(); } @Override diff --git a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java index 121146e7b..4e3a1074f 100644 --- a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java +++ b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java @@ -69,8 +69,11 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setItemInMainHand(@NotNull ItemStack itemStack) { - this.mainHandItem = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); - syncEquipment(EquipmentSlot.MAIN_HAND); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); + if (itemStack != null) { + this.mainHandItem = itemStack; + syncEquipment(EquipmentSlot.MAIN_HAND); + } } @NotNull @@ -81,8 +84,11 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setItemInOffHand(@NotNull ItemStack itemStack) { - this.offHandItem = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); - syncEquipment(EquipmentSlot.OFF_HAND); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); + if (itemStack != null) { + this.offHandItem = itemStack; + syncEquipment(EquipmentSlot.OFF_HAND); + } } @NotNull @@ -93,8 +99,11 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setHelmet(@NotNull ItemStack itemStack) { - this.helmet = getEquipmentItem(itemStack, EquipmentSlot.HELMET); - syncEquipment(EquipmentSlot.HELMET); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.HELMET); + if (itemStack != null) { + this.helmet = itemStack; + syncEquipment(EquipmentSlot.HELMET); + } } @NotNull @@ -105,8 +114,11 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setChestplate(@NotNull ItemStack itemStack) { - this.chestplate = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); - syncEquipment(EquipmentSlot.CHESTPLATE); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); + if (itemStack != null) { + this.chestplate = itemStack; + syncEquipment(EquipmentSlot.CHESTPLATE); + } } @NotNull @@ -117,8 +129,11 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setLeggings(@NotNull ItemStack itemStack) { - this.leggings = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); - syncEquipment(EquipmentSlot.LEGGINGS); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); + if (itemStack != null) { + this.leggings = itemStack; + syncEquipment(EquipmentSlot.LEGGINGS); + } } @NotNull @@ -129,8 +144,11 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setBoots(@NotNull ItemStack itemStack) { - this.boots = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); - syncEquipment(EquipmentSlot.BOOTS); + itemStack = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); + if (itemStack != null) { + this.boots = itemStack; + syncEquipment(EquipmentSlot.BOOTS); + } } public boolean isSmall() { @@ -238,6 +256,6 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot); callEvent(EntityEquipEvent.class, entityEquipEvent); - return entityEquipEvent.getEquippedItem(); + return entityEquipEvent.isCancelled() ? null : entityEquipEvent.getEquippedItem(); } } diff --git a/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java b/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java index 501273eaf..98f4ae3ca 100644 --- a/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java +++ b/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java @@ -2,16 +2,19 @@ package net.minestom.server.event.item; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EquipmentSlot; +import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.Event; import net.minestom.server.item.ItemStack; import org.jetbrains.annotations.NotNull; -public class EntityEquipEvent extends Event { +public class EntityEquipEvent extends Event implements CancellableEvent { private final Entity entity; private ItemStack equippedItem; private final EquipmentSlot slot; + private boolean cancelled; + public EntityEquipEvent(@NotNull Entity entity, @NotNull ItemStack equippedItem, @NotNull EquipmentSlot slot) { this.entity = entity; this.equippedItem = equippedItem; @@ -36,4 +39,14 @@ public class EntityEquipEvent extends Event { public EquipmentSlot getSlot() { return slot; } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } } diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index a4723b8fd..d095bfab3 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -186,11 +186,17 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl equipmentSlot = EquipmentSlot.BOOTS; } + boolean cancel = false; if (equipmentSlot != null) { EntityEquipEvent entityEquipEvent = new EntityEquipEvent(player, itemStack, equipmentSlot); player.callEvent(EntityEquipEvent.class, entityEquipEvent); itemStack = entityEquipEvent.getEquippedItem(); + cancel = entityEquipEvent.isCancelled(); + } + + if (cancel) { + return; } this.itemStacks[slot] = itemStack; From 00278881eeecd23e478d25c990717899a2006f56 Mon Sep 17 00:00:00 2001 From: Arne Dalhuisen <59421074+Bloepiloepi@users.noreply.github.com> Date: Tue, 11 May 2021 20:11:56 +0200 Subject: [PATCH 15/66] Revert "Made EntityEquipEvent cancellable" This reverts commit d72fb72e --- .../minestom/server/entity/EquipmentSlot.java | 1 + .../minestom/server/entity/LivingEntity.java | 44 ++++++------------- .../type/decoration/EntityArmorStand.java | 44 ++++++------------- .../server/event/item/EntityEquipEvent.java | 15 +------ .../server/inventory/PlayerInventory.java | 6 --- 5 files changed, 28 insertions(+), 82 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/EquipmentSlot.java b/src/main/java/net/minestom/server/entity/EquipmentSlot.java index 7a3b70708..27a7cf02d 100644 --- a/src/main/java/net/minestom/server/entity/EquipmentSlot.java +++ b/src/main/java/net/minestom/server/entity/EquipmentSlot.java @@ -1,5 +1,6 @@ package net.minestom.server.entity; +import net.minestom.server.event.item.EntityEquipEvent; import net.minestom.server.item.attribute.AttributeSlot; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index 22ddef528..f03e0849b 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -127,11 +127,8 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setItemInMainHand(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); - if (itemStack != null) { - this.mainHandItem = itemStack; - syncEquipment(EquipmentSlot.MAIN_HAND); - } + this.mainHandItem = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); + syncEquipment(EquipmentSlot.MAIN_HAND); } @NotNull @@ -142,11 +139,8 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setItemInOffHand(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); - if (itemStack != null) { - this.offHandItem = itemStack; - syncEquipment(EquipmentSlot.OFF_HAND); - } + this.offHandItem = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); + syncEquipment(EquipmentSlot.OFF_HAND); } @NotNull @@ -157,11 +151,8 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setHelmet(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.HELMET); - if (itemStack != null) { - this.helmet = itemStack; - syncEquipment(EquipmentSlot.HELMET); - } + this.helmet = getEquipmentItem(itemStack, EquipmentSlot.HELMET); + syncEquipment(EquipmentSlot.HELMET); } @NotNull @@ -172,11 +163,8 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setChestplate(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); - if (itemStack != null) { - this.chestplate = itemStack; - syncEquipment(EquipmentSlot.CHESTPLATE); - } + this.chestplate = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); + syncEquipment(EquipmentSlot.CHESTPLATE); } @NotNull @@ -187,11 +175,8 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setLeggings(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); - if (itemStack != null) { - this.leggings = itemStack; - syncEquipment(EquipmentSlot.LEGGINGS); - } + this.leggings = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); + syncEquipment(EquipmentSlot.LEGGINGS); } @NotNull @@ -202,17 +187,14 @@ public class LivingEntity extends Entity implements EquipmentHandler { @Override public void setBoots(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); - if (itemStack != null) { - this.boots = itemStack; - syncEquipment(EquipmentSlot.BOOTS); - } + this.boots = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); + syncEquipment(EquipmentSlot.BOOTS); } private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot); callEvent(EntityEquipEvent.class, entityEquipEvent); - return entityEquipEvent.isCancelled() ? null : entityEquipEvent.getEquippedItem(); + return entityEquipEvent.getEquippedItem(); } @Override diff --git a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java index 4e3a1074f..121146e7b 100644 --- a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java +++ b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java @@ -69,11 +69,8 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setItemInMainHand(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); - if (itemStack != null) { - this.mainHandItem = itemStack; - syncEquipment(EquipmentSlot.MAIN_HAND); - } + this.mainHandItem = getEquipmentItem(itemStack, EquipmentSlot.MAIN_HAND); + syncEquipment(EquipmentSlot.MAIN_HAND); } @NotNull @@ -84,11 +81,8 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setItemInOffHand(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); - if (itemStack != null) { - this.offHandItem = itemStack; - syncEquipment(EquipmentSlot.OFF_HAND); - } + this.offHandItem = getEquipmentItem(itemStack, EquipmentSlot.OFF_HAND); + syncEquipment(EquipmentSlot.OFF_HAND); } @NotNull @@ -99,11 +93,8 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setHelmet(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.HELMET); - if (itemStack != null) { - this.helmet = itemStack; - syncEquipment(EquipmentSlot.HELMET); - } + this.helmet = getEquipmentItem(itemStack, EquipmentSlot.HELMET); + syncEquipment(EquipmentSlot.HELMET); } @NotNull @@ -114,11 +105,8 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setChestplate(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); - if (itemStack != null) { - this.chestplate = itemStack; - syncEquipment(EquipmentSlot.CHESTPLATE); - } + this.chestplate = getEquipmentItem(itemStack, EquipmentSlot.CHESTPLATE); + syncEquipment(EquipmentSlot.CHESTPLATE); } @NotNull @@ -129,11 +117,8 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setLeggings(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); - if (itemStack != null) { - this.leggings = itemStack; - syncEquipment(EquipmentSlot.LEGGINGS); - } + this.leggings = getEquipmentItem(itemStack, EquipmentSlot.LEGGINGS); + syncEquipment(EquipmentSlot.LEGGINGS); } @NotNull @@ -144,11 +129,8 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { @Override public void setBoots(@NotNull ItemStack itemStack) { - itemStack = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); - if (itemStack != null) { - this.boots = itemStack; - syncEquipment(EquipmentSlot.BOOTS); - } + this.boots = getEquipmentItem(itemStack, EquipmentSlot.BOOTS); + syncEquipment(EquipmentSlot.BOOTS); } public boolean isSmall() { @@ -256,6 +238,6 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { private ItemStack getEquipmentItem(@NotNull ItemStack itemStack, @NotNull EquipmentSlot slot) { EntityEquipEvent entityEquipEvent = new EntityEquipEvent(this, itemStack, slot); callEvent(EntityEquipEvent.class, entityEquipEvent); - return entityEquipEvent.isCancelled() ? null : entityEquipEvent.getEquippedItem(); + return entityEquipEvent.getEquippedItem(); } } diff --git a/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java b/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java index 98f4ae3ca..501273eaf 100644 --- a/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java +++ b/src/main/java/net/minestom/server/event/item/EntityEquipEvent.java @@ -2,19 +2,16 @@ package net.minestom.server.event.item; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EquipmentSlot; -import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.Event; import net.minestom.server.item.ItemStack; import org.jetbrains.annotations.NotNull; -public class EntityEquipEvent extends Event implements CancellableEvent { +public class EntityEquipEvent extends Event { private final Entity entity; private ItemStack equippedItem; private final EquipmentSlot slot; - private boolean cancelled; - public EntityEquipEvent(@NotNull Entity entity, @NotNull ItemStack equippedItem, @NotNull EquipmentSlot slot) { this.entity = entity; this.equippedItem = equippedItem; @@ -39,14 +36,4 @@ public class EntityEquipEvent extends Event implements CancellableEvent { public EquipmentSlot getSlot() { return slot; } - - @Override - public boolean isCancelled() { - return cancelled; - } - - @Override - public void setCancelled(boolean cancel) { - this.cancelled = cancel; - } } diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index d095bfab3..a4723b8fd 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -186,17 +186,11 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl equipmentSlot = EquipmentSlot.BOOTS; } - boolean cancel = false; if (equipmentSlot != null) { EntityEquipEvent entityEquipEvent = new EntityEquipEvent(player, itemStack, equipmentSlot); player.callEvent(EntityEquipEvent.class, entityEquipEvent); itemStack = entityEquipEvent.getEquippedItem(); - cancel = entityEquipEvent.isCancelled(); - } - - if (cancel) { - return; } this.itemStacks[slot] = itemStack; From 9b38d5527afa1563522a0f085e9d5d98d295625c Mon Sep 17 00:00:00 2001 From: thiccaxe <51303986+thiccaxe@users.noreply.github.com> Date: Wed, 12 May 2021 11:41:47 -0700 Subject: [PATCH 16/66] add jansi library --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index d754a86b8..b57ec1b37 100644 --- a/build.gradle +++ b/build.gradle @@ -154,6 +154,10 @@ dependencies { // https://mvnrepository.com/artifact/org.jline/jline implementation group: 'org.jline', name: 'jline', version: '3.20.0' + // Jline compatibility for windows + // https://search.maven.org/artifact/org.fusesource.jansi/jansi/2.3.2/jar + implementation 'org.fusesource.jansi:jansi:2.3.2' + // Guava 21.0+ required for Mixin, but Authlib imports 17.0 api 'com.google.guava:guava:30.1-jre' api 'com.mojang:authlib:1.5.21' From 1c39e06d5547e98642bc4c5d7e9200589472cbb7 Mon Sep 17 00:00:00 2001 From: TheMode Date: Thu, 13 May 2021 08:06:42 +0200 Subject: [PATCH 17/66] Added CachedObject to access a single-object cache --- .../server/instance/DynamicChunk.java | 32 ++++----- .../net/minestom/server/item/ItemMeta.java | 20 +++--- .../server/utils/cache/CachedObject.java | 69 +++++++++++++++++++ 3 files changed, 91 insertions(+), 30 deletions(-) create mode 100644 src/main/java/net/minestom/server/utils/cache/CachedObject.java diff --git a/src/main/java/net/minestom/server/instance/DynamicChunk.java b/src/main/java/net/minestom/server/instance/DynamicChunk.java index 01b5c8a53..c3291ff30 100644 --- a/src/main/java/net/minestom/server/instance/DynamicChunk.java +++ b/src/main/java/net/minestom/server/instance/DynamicChunk.java @@ -16,6 +16,7 @@ import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.block.CustomBlockUtils; +import net.minestom.server.utils.cache.CachedObject; import net.minestom.server.utils.callback.OptionalCallback; import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.chunk.ChunkUtils; @@ -26,7 +27,6 @@ import net.minestom.server.world.biomes.Biome; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.lang.ref.SoftReference; import java.util.Set; /** @@ -60,8 +60,7 @@ public class DynamicChunk extends Chunk { private long lastChangeTime; - private SoftReference cachedPacket = new SoftReference<>(null); - private long cachedPacketTime; + private CachedObject cachedPacket = new CachedObject<>(); public DynamicChunk(@NotNull Instance instance, @Nullable Biome[] biomes, int chunkX, int chunkZ, @NotNull PaletteStorage blockPalette, @NotNull PaletteStorage customBlockPalette) { @@ -387,22 +386,17 @@ public class DynamicChunk extends Chunk { @NotNull @Override protected ChunkDataPacket createFreshPacket() { - ChunkDataPacket packet = cachedPacket.get(); - if (packet != null && cachedPacketTime == getLastChangeTime()) { - return packet; - } - packet = new ChunkDataPacket(getIdentifier(), getLastChangeTime()); - packet.biomes = biomes; - packet.chunkX = chunkX; - packet.chunkZ = chunkZ; - packet.paletteStorage = blockPalette.clone(); - packet.customBlockPaletteStorage = customBlockPalette.clone(); - packet.blockEntities = blockEntities.clone(); - packet.blocksData = blocksData.clone(); - - this.cachedPacketTime = getLastChangeTime(); - this.cachedPacket = new SoftReference<>(packet); - return packet; + return cachedPacket.getUpdatedCache(() -> { + ChunkDataPacket chunkDataPacket = new ChunkDataPacket(getIdentifier(), getLastChangeTime()); + chunkDataPacket.biomes = biomes; + chunkDataPacket.chunkX = chunkX; + chunkDataPacket.chunkZ = chunkZ; + chunkDataPacket.paletteStorage = blockPalette.clone(); + chunkDataPacket.customBlockPaletteStorage = customBlockPalette.clone(); + chunkDataPacket.blockEntities = blockEntities.clone(); + chunkDataPacket.blocksData = blocksData.clone(); + return chunkDataPacket; + }, getLastChangeTime()); } @NotNull diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 04d0023ba..49b892717 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -6,6 +6,7 @@ import net.minestom.server.instance.block.Block; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.Writeable; +import net.minestom.server.utils.cache.CachedObject; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,8 +34,8 @@ public class ItemMeta implements Writeable { private final NBTCompound nbt; private final ItemMetaBuilder emptyBuilder; - private String cachedSNBT; - private ByteBuf cachedBuffer; + private CachedObject cachedSNBT = new CachedObject<>(); + private CachedObject cachedBuffer = new CachedObject<>(); protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { this.damage = metaBuilder.damage; @@ -128,10 +129,7 @@ public class ItemMeta implements Writeable { } public @NotNull String toSNBT() { - if (cachedSNBT == null) { - this.cachedSNBT = nbt.toSNBT(); - } - return cachedSNBT; + return cachedSNBT.getCache(nbt::toSNBT); } @Override @@ -155,12 +153,12 @@ public class ItemMeta implements Writeable { @Override public synchronized void write(@NotNull BinaryWriter writer) { - if (cachedBuffer == null) { + final var buffer = cachedBuffer.getCache(() -> { BinaryWriter w = new BinaryWriter(); w.writeNBT("", nbt); - this.cachedBuffer = w.getBuffer(); - } - writer.write(cachedBuffer); - this.cachedBuffer.resetReaderIndex(); + return w.getBuffer(); + }); + writer.write(buffer); + buffer.resetReaderIndex(); } } diff --git a/src/main/java/net/minestom/server/utils/cache/CachedObject.java b/src/main/java/net/minestom/server/utils/cache/CachedObject.java new file mode 100644 index 000000000..5d52497fd --- /dev/null +++ b/src/main/java/net/minestom/server/utils/cache/CachedObject.java @@ -0,0 +1,69 @@ +package net.minestom.server.utils.cache; + +import com.google.common.annotations.Beta; +import org.jetbrains.annotations.NotNull; + +import java.lang.ref.SoftReference; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +/** + * Represents a single that can be collected by the garbage collector + * depending on memory demand. + * + * @param the object to cache + */ +@Beta +public class CachedObject extends SoftReference> { + + private long cacheTime; + + public CachedObject() { + super(new AtomicReference<>()); + } + + /** + * Retrieves the cache. + * + * @param supplier supplier for the value if absent + * @return the cache + */ + public @NotNull T getCache(@NotNull Supplier<@NotNull T> supplier) { + var referent = get(); + assert referent != null; + var value = referent.get(); + if (value == null) { + value = supplier.get(); + referent.set(value); + } + return value; + } + + /** + * Retrieves the cache, and ensure that the value is up-to-date. + * + * @param supplier supplier for the value if absent or outdated + * @param lastUpdate the required internal timestamp, supplier will be called otherwise + * @return the cache + */ + public @NotNull T getUpdatedCache(@NotNull Supplier<@NotNull T> supplier, long lastUpdate) { + var referent = get(); + assert referent != null; + var value = referent.get(); + if (value == null || cacheTime != lastUpdate) { + value = supplier.get(); + this.cacheTime = lastUpdate; + referent.set(value); + } + return value; + } + + /** + * @deprecated use {@link #getCache(Supplier)} + */ + @Override + @Deprecated + public AtomicReference get() { + return super.get(); + } +} From 6a712b33a073cee2f65e3098856cc2ef1cff6cec Mon Sep 17 00:00:00 2001 From: TheMode Date: Thu, 13 May 2021 08:32:26 +0200 Subject: [PATCH 18/66] Revert "Added CachedObject to access a single-object cache" This reverts commit 1c39e06d --- .../server/instance/DynamicChunk.java | 32 +++++---- .../net/minestom/server/item/ItemMeta.java | 20 +++--- .../server/utils/cache/CachedObject.java | 69 ------------------- 3 files changed, 30 insertions(+), 91 deletions(-) delete mode 100644 src/main/java/net/minestom/server/utils/cache/CachedObject.java diff --git a/src/main/java/net/minestom/server/instance/DynamicChunk.java b/src/main/java/net/minestom/server/instance/DynamicChunk.java index c3291ff30..01b5c8a53 100644 --- a/src/main/java/net/minestom/server/instance/DynamicChunk.java +++ b/src/main/java/net/minestom/server/instance/DynamicChunk.java @@ -16,7 +16,6 @@ import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.block.CustomBlockUtils; -import net.minestom.server.utils.cache.CachedObject; import net.minestom.server.utils.callback.OptionalCallback; import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.chunk.ChunkUtils; @@ -27,6 +26,7 @@ import net.minestom.server.world.biomes.Biome; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.ref.SoftReference; import java.util.Set; /** @@ -60,7 +60,8 @@ public class DynamicChunk extends Chunk { private long lastChangeTime; - private CachedObject cachedPacket = new CachedObject<>(); + private SoftReference cachedPacket = new SoftReference<>(null); + private long cachedPacketTime; public DynamicChunk(@NotNull Instance instance, @Nullable Biome[] biomes, int chunkX, int chunkZ, @NotNull PaletteStorage blockPalette, @NotNull PaletteStorage customBlockPalette) { @@ -386,17 +387,22 @@ public class DynamicChunk extends Chunk { @NotNull @Override protected ChunkDataPacket createFreshPacket() { - return cachedPacket.getUpdatedCache(() -> { - ChunkDataPacket chunkDataPacket = new ChunkDataPacket(getIdentifier(), getLastChangeTime()); - chunkDataPacket.biomes = biomes; - chunkDataPacket.chunkX = chunkX; - chunkDataPacket.chunkZ = chunkZ; - chunkDataPacket.paletteStorage = blockPalette.clone(); - chunkDataPacket.customBlockPaletteStorage = customBlockPalette.clone(); - chunkDataPacket.blockEntities = blockEntities.clone(); - chunkDataPacket.blocksData = blocksData.clone(); - return chunkDataPacket; - }, getLastChangeTime()); + ChunkDataPacket packet = cachedPacket.get(); + if (packet != null && cachedPacketTime == getLastChangeTime()) { + return packet; + } + packet = new ChunkDataPacket(getIdentifier(), getLastChangeTime()); + packet.biomes = biomes; + packet.chunkX = chunkX; + packet.chunkZ = chunkZ; + packet.paletteStorage = blockPalette.clone(); + packet.customBlockPaletteStorage = customBlockPalette.clone(); + packet.blockEntities = blockEntities.clone(); + packet.blocksData = blocksData.clone(); + + this.cachedPacketTime = getLastChangeTime(); + this.cachedPacket = new SoftReference<>(packet); + return packet; } @NotNull diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 49b892717..04d0023ba 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -6,7 +6,6 @@ import net.minestom.server.instance.block.Block; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.Writeable; -import net.minestom.server.utils.cache.CachedObject; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,8 +33,8 @@ public class ItemMeta implements Writeable { private final NBTCompound nbt; private final ItemMetaBuilder emptyBuilder; - private CachedObject cachedSNBT = new CachedObject<>(); - private CachedObject cachedBuffer = new CachedObject<>(); + private String cachedSNBT; + private ByteBuf cachedBuffer; protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { this.damage = metaBuilder.damage; @@ -129,7 +128,10 @@ public class ItemMeta implements Writeable { } public @NotNull String toSNBT() { - return cachedSNBT.getCache(nbt::toSNBT); + if (cachedSNBT == null) { + this.cachedSNBT = nbt.toSNBT(); + } + return cachedSNBT; } @Override @@ -153,12 +155,12 @@ public class ItemMeta implements Writeable { @Override public synchronized void write(@NotNull BinaryWriter writer) { - final var buffer = cachedBuffer.getCache(() -> { + if (cachedBuffer == null) { BinaryWriter w = new BinaryWriter(); w.writeNBT("", nbt); - return w.getBuffer(); - }); - writer.write(buffer); - buffer.resetReaderIndex(); + this.cachedBuffer = w.getBuffer(); + } + writer.write(cachedBuffer); + this.cachedBuffer.resetReaderIndex(); } } diff --git a/src/main/java/net/minestom/server/utils/cache/CachedObject.java b/src/main/java/net/minestom/server/utils/cache/CachedObject.java deleted file mode 100644 index 5d52497fd..000000000 --- a/src/main/java/net/minestom/server/utils/cache/CachedObject.java +++ /dev/null @@ -1,69 +0,0 @@ -package net.minestom.server.utils.cache; - -import com.google.common.annotations.Beta; -import org.jetbrains.annotations.NotNull; - -import java.lang.ref.SoftReference; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; - -/** - * Represents a single that can be collected by the garbage collector - * depending on memory demand. - * - * @param the object to cache - */ -@Beta -public class CachedObject extends SoftReference> { - - private long cacheTime; - - public CachedObject() { - super(new AtomicReference<>()); - } - - /** - * Retrieves the cache. - * - * @param supplier supplier for the value if absent - * @return the cache - */ - public @NotNull T getCache(@NotNull Supplier<@NotNull T> supplier) { - var referent = get(); - assert referent != null; - var value = referent.get(); - if (value == null) { - value = supplier.get(); - referent.set(value); - } - return value; - } - - /** - * Retrieves the cache, and ensure that the value is up-to-date. - * - * @param supplier supplier for the value if absent or outdated - * @param lastUpdate the required internal timestamp, supplier will be called otherwise - * @return the cache - */ - public @NotNull T getUpdatedCache(@NotNull Supplier<@NotNull T> supplier, long lastUpdate) { - var referent = get(); - assert referent != null; - var value = referent.get(); - if (value == null || cacheTime != lastUpdate) { - value = supplier.get(); - this.cacheTime = lastUpdate; - referent.set(value); - } - return value; - } - - /** - * @deprecated use {@link #getCache(Supplier)} - */ - @Override - @Deprecated - public AtomicReference get() { - return super.get(); - } -} From d50b5ac1799bfc0ea4976ed14e8dafe54b154ad6 Mon Sep 17 00:00:00 2001 From: LeoDog896 Date: Thu, 13 May 2021 08:15:02 -0400 Subject: [PATCH 19/66] Add documentation to Argument methods --- .../command/builder/arguments/Argument.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/command/builder/arguments/Argument.java b/src/main/java/net/minestom/server/command/builder/arguments/Argument.java index 4cff3f232..2b32ffa00 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/Argument.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/Argument.java @@ -195,23 +195,48 @@ public abstract class Argument { return this; } + /** + * Sets the default value supplier of the argument. + * + * @param defaultValue the default argument value + * @return 'this' for chaining + */ @NotNull - public Argument setDefaultValue(@Nullable T defaultValue) { + public Argument setDefaultValue(@NotNull T defaultValue) { this.defaultValue = () -> defaultValue; return this; } + /** + * Gets the suggestion callback of the argument + * + * @see #setSuggestionCallback + * @return the suggestion callback of the argument, null if it doesn't exist + */ @Nullable public SuggestionCallback getSuggestionCallback() { return suggestionCallback; } + /** + * Sets the suggestion callback (for dynamic tab completion) of this argument. + *

+ * Note: This will not automatically filter arguments by user input. + * + * @param suggestionCallback The suggestion callback to set. + * @return 'this' for chaining + */ @Beta public Argument setSuggestionCallback(@NotNull SuggestionCallback suggestionCallback) { this.suggestionCallback = suggestionCallback; return this; } + /** + * Check if the argument has a suggestion. + * + * @return If this argument has a suggestion. + */ public boolean hasSuggestion() { return suggestionCallback != null; } From 93360d7e1b192ffe263503ba4be6eb6f9ff0b9d6 Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 14 May 2021 18:15:41 +0200 Subject: [PATCH 20/66] Fix thread count stuck to 1 --- src/main/java/net/minestom/server/MinecraftServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/MinecraftServer.java b/src/main/java/net/minestom/server/MinecraftServer.java index 1a8a71b8a..4057bace8 100644 --- a/src/main/java/net/minestom/server/MinecraftServer.java +++ b/src/main/java/net/minestom/server/MinecraftServer.java @@ -826,6 +826,6 @@ public final class MinecraftServer { } private static int getThreadCount(@NotNull String property, int count) { - return Integer.getInteger(property, Math.min(1, count)); + return Integer.getInteger(property, Math.max(1, count)); } } From 34d428be10ecab6de5dd95bed214df8510723869 Mon Sep 17 00:00:00 2001 From: R0bbyYT Date: Fri, 14 May 2021 18:35:09 +0200 Subject: [PATCH 21/66] Start with the elytra implementation --- .../net/minestom/server/entity/LivingEntity.java | 8 ++++++++ .../player/PlayerStartFlyingWithElytraEvent.java | 12 ++++++++++++ .../server/listener/EntityActionListener.java | 13 +++++++++---- 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/main/java/net/minestom/server/event/player/PlayerStartFlyingWithElytraEvent.java diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index 1c9a27c7b..0613e5347 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -595,6 +595,14 @@ public class LivingEntity extends Entity implements EquipmentHandler { } } + public boolean isFlyingWithElytra() { + return this.entityMeta.isFlyingWithElytra(); + } + + public void setFlyingWithElytra(boolean isFlying) { + this.entityMeta.setFlyingWithElytra(isFlying); + } + /** * Used to change the {@code isDead} internal field. * diff --git a/src/main/java/net/minestom/server/event/player/PlayerStartFlyingWithElytraEvent.java b/src/main/java/net/minestom/server/event/player/PlayerStartFlyingWithElytraEvent.java new file mode 100644 index 000000000..28ca41575 --- /dev/null +++ b/src/main/java/net/minestom/server/event/player/PlayerStartFlyingWithElytraEvent.java @@ -0,0 +1,12 @@ +package net.minestom.server.event.player; + +import net.minestom.server.entity.Player; +import net.minestom.server.event.PlayerEvent; +import org.jetbrains.annotations.NotNull; + +public class PlayerStartFlyingWithElytraEvent extends PlayerEvent { + + public PlayerStartFlyingWithElytraEvent(@NotNull Player player) { + super(player); + } +} diff --git a/src/main/java/net/minestom/server/listener/EntityActionListener.java b/src/main/java/net/minestom/server/listener/EntityActionListener.java index e99cffc75..dea235c90 100644 --- a/src/main/java/net/minestom/server/listener/EntityActionListener.java +++ b/src/main/java/net/minestom/server/listener/EntityActionListener.java @@ -1,10 +1,7 @@ package net.minestom.server.listener; import net.minestom.server.entity.Player; -import net.minestom.server.event.player.PlayerStartSneakingEvent; -import net.minestom.server.event.player.PlayerStartSprintingEvent; -import net.minestom.server.event.player.PlayerStopSneakingEvent; -import net.minestom.server.event.player.PlayerStopSprintingEvent; +import net.minestom.server.event.player.*; import net.minestom.server.network.packet.client.play.ClientEntityActionPacket; public class EntityActionListener { @@ -24,6 +21,9 @@ public class EntityActionListener { case STOP_SPRINTING: EntityActionListener.setSprinting(player, false); break; + case START_FLYING_ELYTRA: + EntityActionListener.startFlyingElytra(player); + break; // TODO do remaining actions } } @@ -55,4 +55,9 @@ public class EntityActionListener { } } } + + private static void startFlyingElytra(Player player) { + player.setFlyingWithElytra(true); + player.callEvent(PlayerStartFlyingWithElytraEvent.class, new PlayerStartFlyingWithElytraEvent(player)); + } } From 2145bf4115aaf586dfe8da40a4df3d4d541f6963 Mon Sep 17 00:00:00 2001 From: R0bbyYT Date: Fri, 14 May 2021 19:00:07 +0200 Subject: [PATCH 22/66] Reset flying with elytra when the player is on the ground --- src/main/java/net/minestom/server/entity/Player.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 8a7ecad0c..5b9c29be0 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -2223,6 +2223,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable, public void refreshOnGround(boolean onGround) { this.onGround = onGround; + if(this.onGround && this.isFlyingWithElytra()) { + this.setFlyingWithElytra(false); + } } /** From cd988f12710b7f987bf47b902ddbc3288ae0b5c3 Mon Sep 17 00:00:00 2001 From: R0bbyYT Date: Fri, 14 May 2021 19:00:07 +0200 Subject: [PATCH 23/66] Reset flying with elytra when the player is on the ground --- src/main/java/net/minestom/server/entity/Player.java | 4 ++++ .../player/PlayerStopFlyingWithElytraEvent.java | 12 ++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/main/java/net/minestom/server/event/player/PlayerStopFlyingWithElytraEvent.java diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 8a7ecad0c..e9c8afbeb 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -2223,6 +2223,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable, public void refreshOnGround(boolean onGround) { this.onGround = onGround; + if(this.onGround && this.isFlyingWithElytra()) { + this.setFlyingWithElytra(false); + this.callEvent(PlayerStopFlyingWithElytraEvent.class, new PlayerStopFlyingWithElytraEvent(this)); + } } /** diff --git a/src/main/java/net/minestom/server/event/player/PlayerStopFlyingWithElytraEvent.java b/src/main/java/net/minestom/server/event/player/PlayerStopFlyingWithElytraEvent.java new file mode 100644 index 000000000..314f16e22 --- /dev/null +++ b/src/main/java/net/minestom/server/event/player/PlayerStopFlyingWithElytraEvent.java @@ -0,0 +1,12 @@ +package net.minestom.server.event.player; + +import net.minestom.server.entity.Player; +import net.minestom.server.event.PlayerEvent; +import org.jetbrains.annotations.NotNull; + +public class PlayerStopFlyingWithElytraEvent extends PlayerEvent { + + public PlayerStopFlyingWithElytraEvent(@NotNull Player player) { + super(player); + } +} From dfad9f294784fb1b2544422e7cd108336dd17db3 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 15 May 2021 07:57:28 +0200 Subject: [PATCH 24/66] Remove minecraft repo --- build.gradle | 3 +-- .../packet/client/login/EncryptionResponsePacket.java | 6 +++--- .../java/net/minestom/server/utils/mojang/MojangUtils.java | 1 - 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index dda3be025..f0fefe1e4 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +33,6 @@ switch (OperatingSystem.current()) { allprojects { repositories { mavenCentral() - maven { url 'https://libraries.minecraft.net' } maven { url 'https://jitpack.io' } maven { name 'sponge' @@ -158,7 +157,7 @@ dependencies { // https://search.maven.org/artifact/org.fusesource.jansi/jansi/2.3.2/jar implementation 'org.fusesource.jansi:jansi:2.3.2' - // Guava 21.0+ required for Mixin, but Authlib imports 17.0 + // Guava 21.0+ required for Mixin api 'com.google.guava:guava:30.1-jre' // Code modification diff --git a/src/main/java/net/minestom/server/network/packet/client/login/EncryptionResponsePacket.java b/src/main/java/net/minestom/server/network/packet/client/login/EncryptionResponsePacket.java index 282b75406..83d5ef855 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/EncryptionResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/EncryptionResponsePacket.java @@ -65,7 +65,7 @@ public class EncryptionResponsePacket implements ClientPreplayPacket { InputStream gameProfileStream = new URL( "https://sessionserver.mojang.com/session/minecraft/hasJoined?" + "username=" + loginUsername + "&" - + "serverId=" + serverId + + "serverId=" + serverId // TODO: Add ability to add ip query tag. See: https://wiki.vg/Protocol_Encryption#Authentication ).openStream(); @@ -95,11 +95,11 @@ public class EncryptionResponsePacket implements ClientPreplayPacket { ByteArrayData.encodeByteArray(writer, verifyToken); } - public SecretKey getSecretKey() { + private SecretKey getSecretKey() { return MojangCrypt.decryptByteToSecretKey(MojangAuth.getKeyPair().getPrivate(), sharedSecret); } - public byte[] getNonce() { + private byte[] getNonce() { return MojangAuth.getKeyPair().getPrivate() == null ? this.verifyToken : MojangCrypt.decryptUsingKey(MojangAuth.getKeyPair().getPrivate(), this.verifyToken); } diff --git a/src/main/java/net/minestom/server/utils/mojang/MojangUtils.java b/src/main/java/net/minestom/server/utils/mojang/MojangUtils.java index b42b98bbf..04e0df2d7 100644 --- a/src/main/java/net/minestom/server/utils/mojang/MojangUtils.java +++ b/src/main/java/net/minestom/server/utils/mojang/MojangUtils.java @@ -27,7 +27,6 @@ public final class MojangUtils { .softValues() .build(); - @Nullable public static JsonObject fromUuid(@NotNull String uuid) { From 88dba380f90377dd737174e47f46393cb11e2aeb Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 15 May 2021 08:31:24 +0200 Subject: [PATCH 25/66] Remove apache common text dependency --- build.gradle | 3 - .../java/net/minestom/server/color/Color.java | 23 ++- .../server/command/builder/Command.java | 2 +- .../command/builder/CommandContext.java | 2 +- .../command/builder/CommandDispatcher.java | 2 +- .../server/command/builder/CommandSyntax.java | 2 +- .../builder/arguments/ArgumentCommand.java | 2 +- .../arguments/ArgumentDynamicStringArray.java | 2 +- .../arguments/ArgumentDynamicWord.java | 2 +- .../builder/arguments/ArgumentGroup.java | 2 +- .../builder/arguments/ArgumentLoop.java | 2 +- .../builder/arguments/ArgumentString.java | 4 +- .../arguments/ArgumentStringArray.java | 2 +- .../builder/arguments/ArgumentWord.java | 2 +- .../arguments/minecraft/ArgumentEntity.java | 2 +- .../minecraft/ArgumentResourceLocation.java | 2 +- .../ArgumentRelativeBlockPosition.java | 2 +- .../relative/ArgumentRelativeVec2.java | 2 +- .../relative/ArgumentRelativeVec3.java | 2 +- .../builder/parser/ArgumentParser.java | 2 +- .../command/builder/parser/CommandParser.java | 2 +- .../rule/vanilla/StairsPlacementRule.java | 6 +- .../server/listener/TabCompleteListener.java | 4 +- .../server/network/ConnectionManager.java | 25 ++- .../packet/server/play/TitlePacket.java | 14 +- .../server/registry/ResourceGatherer.java | 2 +- .../minestom/server/utils/StringUtils.java | 161 ++++++++++++++++++ .../net/minestom/server/utils/TickUtils.java | 9 +- 28 files changed, 221 insertions(+), 66 deletions(-) create mode 100644 src/main/java/net/minestom/server/utils/StringUtils.java diff --git a/build.gradle b/build.gradle index f0fefe1e4..3ce127ef8 100644 --- a/build.gradle +++ b/build.gradle @@ -129,9 +129,6 @@ dependencies { api 'io.netty:netty-transport-native-kqueue:4.1.63.Final:osx-x86_64' api 'io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.5.Final:linux-x86_64' - // https://mvnrepository.com/artifact/org.apache.commons/commons-text - compile group: 'org.apache.commons', name: 'commons-text', version: '1.9' - // https://mvnrepository.com/artifact/it.unimi.dsi/fastutil api 'it.unimi.dsi:fastutil:8.5.4' diff --git a/src/main/java/net/minestom/server/color/Color.java b/src/main/java/net/minestom/server/color/Color.java index 9fc613792..7eddf0614 100644 --- a/src/main/java/net/minestom/server/color/Color.java +++ b/src/main/java/net/minestom/server/color/Color.java @@ -2,7 +2,8 @@ package net.minestom.server.color; import net.kyori.adventure.util.RGBLike; import net.minestom.server.chat.ChatColor; -import org.apache.commons.lang3.Validate; +import net.minestom.server.utils.MathUtils; +import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -38,17 +39,15 @@ public class Color implements RGBLike { /** * Creates a color from red, green, and blue components. * - * @param red the red component + * @param red the red component * @param green the green component - * @param blue the blue component - * + * @param blue the blue component * @throws IllegalArgumentException if any component value is not between 0-255 (inclusive) */ public Color(int red, int green, int blue) { - Validate.isTrue(red >= 0 && red <= 255, "Red is not between 0-255: ", red); - Validate.isTrue(green >= 0 && green <= 255, "Green is not between 0-255: ", green); - Validate.isTrue(blue >= 0 && blue <= 255, "Blue is not between 0-255: ", blue); - + Check.argCondition(!MathUtils.isBetween(red, 0, 255), "Red is not between 0-255: {0}", red); + Check.argCondition(!MathUtils.isBetween(green, 0, 255), "Green is not between 0-255: {0}", green); + Check.argCondition(!MathUtils.isBetween(blue, 0, 255), "Blue is not between 0-255: {0}", blue); this.red = red; this.green = green; this.blue = blue; @@ -69,7 +68,7 @@ public class Color implements RGBLike { * @param red the red component, from 0 to 255 */ public void setRed(int red) { - Validate.isTrue(red >= 0 && red <= 255, "Red is not between 0-255: ", red); + Check.argCondition(!MathUtils.isBetween(red, 0, 255), "Red is not between 0-255: {0}", red); this.red = red; } @@ -88,7 +87,7 @@ public class Color implements RGBLike { * @param green the red component, from 0 to 255 */ public void setGreen(int green) { - Validate.isTrue(green >= 0 && green <= 255, "Green is not between 0-255: ", green); + Check.argCondition(!MathUtils.isBetween(green, 0, 255), "Green is not between 0-255: {0}", green); this.green = green; } @@ -107,7 +106,7 @@ public class Color implements RGBLike { * @param blue the red component, from 0 to 255 */ public void setBlue(int blue) { - Validate.isTrue(blue >= 0 && blue <= 255, "Blue is not between 0-255: ", blue); + Check.argCondition(!MathUtils.isBetween(blue, 0, 255), "Blue is not between 0-255: {0}", blue); this.blue = blue; } @@ -132,8 +131,6 @@ public class Color implements RGBLike { * @param colors the colors */ public void mixWith(@NotNull RGBLike... colors) { - Validate.noNullElements(colors, "Colors cannot be null"); - // store the current highest component int max = Math.max(Math.max(this.red, this.green), this.blue); diff --git a/src/main/java/net/minestom/server/command/builder/Command.java b/src/main/java/net/minestom/server/command/builder/Command.java index 14b3252f8..e84cce5c3 100644 --- a/src/main/java/net/minestom/server/command/builder/Command.java +++ b/src/main/java/net/minestom/server/command/builder/Command.java @@ -7,7 +7,7 @@ import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.arguments.*; import net.minestom.server.command.builder.arguments.minecraft.SuggestionType; import net.minestom.server.command.builder.condition.CommandCondition; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; diff --git a/src/main/java/net/minestom/server/command/builder/CommandContext.java b/src/main/java/net/minestom/server/command/builder/CommandContext.java index 4eedfef6b..3b23ca872 100644 --- a/src/main/java/net/minestom/server/command/builder/CommandContext.java +++ b/src/main/java/net/minestom/server/command/builder/CommandContext.java @@ -1,7 +1,7 @@ package net.minestom.server.command.builder; import net.minestom.server.command.builder.arguments.Argument; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/minestom/server/command/builder/CommandDispatcher.java b/src/main/java/net/minestom/server/command/builder/CommandDispatcher.java index 730919479..dc930af34 100644 --- a/src/main/java/net/minestom/server/command/builder/CommandDispatcher.java +++ b/src/main/java/net/minestom/server/command/builder/CommandDispatcher.java @@ -10,7 +10,7 @@ import net.minestom.server.command.builder.parser.CommandParser; import net.minestom.server.command.builder.parser.CommandQueryResult; import net.minestom.server.command.builder.parser.CommandSuggestionHolder; import net.minestom.server.command.builder.parser.ValidSyntaxHolder; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/minestom/server/command/builder/CommandSyntax.java b/src/main/java/net/minestom/server/command/builder/CommandSyntax.java index 5a5a7a5cc..a076ce956 100644 --- a/src/main/java/net/minestom/server/command/builder/CommandSyntax.java +++ b/src/main/java/net/minestom/server/command/builder/CommandSyntax.java @@ -3,7 +3,7 @@ package net.minestom.server.command.builder; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.condition.CommandCondition; import net.minestom.server.entity.Player; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentCommand.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentCommand.java index d6179499a..335be5300 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentCommand.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentCommand.java @@ -7,7 +7,7 @@ import net.minestom.server.command.builder.CommandResult; import net.minestom.server.command.builder.NodeMaker; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; public class ArgumentCommand extends Argument { diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentDynamicStringArray.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentDynamicStringArray.java index 3ede1e208..c9084f849 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentDynamicStringArray.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentDynamicStringArray.java @@ -7,7 +7,7 @@ import net.minestom.server.command.builder.suggestion.SuggestionCallback; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.callback.validator.StringArrayValidator; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentDynamicWord.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentDynamicWord.java index d72e1c6ca..2143e83e5 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentDynamicWord.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentDynamicWord.java @@ -6,9 +6,9 @@ import net.minestom.server.command.builder.arguments.minecraft.SuggestionType; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.command.builder.suggestion.SuggestionCallback; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; +import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.callback.validator.StringValidator; -import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentGroup.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentGroup.java index 513839b60..9d4c8f659 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentGroup.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentGroup.java @@ -5,7 +5,7 @@ import net.minestom.server.command.builder.NodeMaker; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.command.builder.parser.CommandParser; import net.minestom.server.command.builder.parser.ValidSyntaxHolder; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLoop.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLoop.java index 0bbadee1c..5387bae0f 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLoop.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLoop.java @@ -3,7 +3,7 @@ package net.minestom.server.command.builder.arguments; import net.minestom.server.command.builder.NodeMaker; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java index 0bca51aa8..f5b9dcd0d 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java @@ -4,8 +4,8 @@ import io.netty.util.internal.StringUtil; import net.minestom.server.command.builder.NodeMaker; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; +import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.binary.BinaryWriter; -import org.apache.commons.text.StringEscapeUtils; import org.jetbrains.annotations.NotNull; /** @@ -75,7 +75,7 @@ public class ArgumentString extends Argument { } } - return StringEscapeUtils.unescapeJava(input); + return StringUtils.unescapeJavaString(input); } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java index e56781dbc..e6429a4c1 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java @@ -2,8 +2,8 @@ package net.minestom.server.command.builder.arguments; import net.minestom.server.command.builder.NodeMaker; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; +import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.binary.BinaryWriter; -import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import java.util.regex.Pattern; diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java index 5f2deb5b3..91da3861e 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java @@ -5,7 +5,7 @@ import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.validate.Check; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java index 11e51b08b..84cd7d2a2 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java @@ -10,7 +10,7 @@ import net.minestom.server.registry.Registries; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.entity.EntityFinder; import net.minestom.server.utils.math.IntRange; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import java.util.Arrays; diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceLocation.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceLocation.java index 44d41ecc7..666e467e9 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceLocation.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceLocation.java @@ -4,7 +4,7 @@ import net.minestom.server.command.builder.NodeMaker; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; public class ArgumentResourceLocation extends Argument { diff --git a/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeBlockPosition.java b/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeBlockPosition.java index bb0a7f4d1..eeda34d76 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeBlockPosition.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeBlockPosition.java @@ -5,7 +5,7 @@ import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.location.RelativeBlockPosition; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec2.java b/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec2.java index 9aa894b37..904179195 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec2.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec2.java @@ -5,7 +5,7 @@ import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; import net.minestom.server.utils.Vector; import net.minestom.server.utils.location.RelativeVec; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec3.java b/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec3.java index 6f632b6a7..6e6f8a4fe 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec3.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec3.java @@ -5,7 +5,7 @@ import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; import net.minestom.server.utils.Vector; import net.minestom.server.utils.location.RelativeVec; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/net/minestom/server/command/builder/parser/ArgumentParser.java b/src/main/java/net/minestom/server/command/builder/parser/ArgumentParser.java index 2aceda1de..0c51c8aa5 100644 --- a/src/main/java/net/minestom/server/command/builder/parser/ArgumentParser.java +++ b/src/main/java/net/minestom/server/command/builder/parser/ArgumentParser.java @@ -11,7 +11,7 @@ import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeBl import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeVec2; import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeVec3; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/minestom/server/command/builder/parser/CommandParser.java b/src/main/java/net/minestom/server/command/builder/parser/CommandParser.java index 98316d5e9..f0e1333cb 100644 --- a/src/main/java/net/minestom/server/command/builder/parser/CommandParser.java +++ b/src/main/java/net/minestom/server/command/builder/parser/CommandParser.java @@ -7,7 +7,7 @@ import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.CommandContext; import net.minestom.server.command.builder.CommandSyntax; import net.minestom.server.command.builder.arguments.Argument; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/minestom/server/instance/block/rule/vanilla/StairsPlacementRule.java b/src/main/java/net/minestom/server/instance/block/rule/vanilla/StairsPlacementRule.java index 4a53096f2..6499fd96c 100644 --- a/src/main/java/net/minestom/server/instance/block/rule/vanilla/StairsPlacementRule.java +++ b/src/main/java/net/minestom/server/instance/block/rule/vanilla/StairsPlacementRule.java @@ -1,5 +1,6 @@ package net.minestom.server.instance.block.rule.vanilla; +import it.unimi.dsi.fastutil.Pair; import net.minestom.server.entity.Player; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; @@ -7,7 +8,6 @@ import net.minestom.server.instance.block.BlockAlternative; import net.minestom.server.instance.block.BlockFace; import net.minestom.server.instance.block.rule.BlockPlacementRule; import net.minestom.server.utils.BlockPosition; -import org.apache.commons.lang3.tuple.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -113,10 +113,10 @@ public class StairsPlacementRule extends BlockPlacementRule { @Nullable private Shape getShapeFromSide(@NotNull Pair side, @NotNull Facing facing, @NotNull Shape right, @NotNull Shape left) { - if (side.getLeft() == null) { + if (side.left() == null) { return null; } - Facing sideFacing = side.getRight(); + Facing sideFacing = side.right(); if (facing.equals(Facing.NORTH)) { if (sideFacing.equals(Facing.EAST)) { return right; diff --git a/src/main/java/net/minestom/server/listener/TabCompleteListener.java b/src/main/java/net/minestom/server/listener/TabCompleteListener.java index 73e95dc91..de2869527 100644 --- a/src/main/java/net/minestom/server/listener/TabCompleteListener.java +++ b/src/main/java/net/minestom/server/listener/TabCompleteListener.java @@ -11,7 +11,7 @@ import net.minestom.server.command.builder.suggestion.SuggestionCallback; import net.minestom.server.entity.Player; import net.minestom.server.network.packet.client.play.ClientTabCompletePacket; import net.minestom.server.network.packet.server.play.TabCompletePacket; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import java.util.Arrays; @@ -48,7 +48,7 @@ public class TabCompleteListener { final int inputLength = input.length(); final int commandLength = Arrays.stream(split).map(String::length).reduce(0, Integer::sum) + - StringUtils.countMatches(args, StringUtils.SPACE); + StringUtils.countMatches(args, StringUtils.SPACE_CHAR); final int trailingSpaces = !input.isEmpty() ? text.length() - text.trim().length() : 0; final int start = commandLength - inputLength + 1 - trailingSpaces; diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index 49176c461..67ae73556 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -20,10 +20,10 @@ import net.minestom.server.network.packet.server.play.DisconnectPacket; import net.minestom.server.network.packet.server.play.KeepAlivePacket; import net.minestom.server.network.player.NettyPlayerConnection; import net.minestom.server.network.player.PlayerConnection; +import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.callback.validator.PlayerValidator; import net.minestom.server.utils.validate.Check; -import org.apache.commons.text.similarity.JaroWinklerDistance; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,6 +33,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; /** @@ -83,7 +84,6 @@ public final class ConnectionManager { /** * Finds the closest player matching a given username. - *

* * @param username the player username (can be partial) * @return the closest match, null if no players are online @@ -91,18 +91,17 @@ public final class ConnectionManager { public @Nullable Player findPlayer(@NotNull String username) { Player exact = getPlayer(username); if (exact != null) return exact; + final String username1 = username.toLowerCase(Locale.ROOT); - String lowercase = username.toLowerCase(); - double currentDistance = 0; - for (Player player : getOnlinePlayers()) { - final JaroWinklerDistance jaroWinklerDistance = new JaroWinklerDistance(); - final double distance = jaroWinklerDistance.apply(lowercase, player.getUsername().toLowerCase()); - if (distance > currentDistance) { - currentDistance = distance; - exact = player; - } - } - return exact; + Function distanceFunction = player -> { + final String username2 = player.getUsername().toLowerCase(Locale.ROOT); + return StringUtils.jaroWinklerScore(username1, username2); + }; + return getOnlinePlayers() + .stream() + .min(Comparator.comparingDouble(distanceFunction::apply)) + .filter(player -> distanceFunction.apply(player) > 0) + .orElse(null); } /** diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TitlePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TitlePacket.java index b7942cb5e..1b21cb80e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TitlePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TitlePacket.java @@ -8,7 +8,7 @@ import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.TickUtils; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; -import org.apache.commons.lang3.Validate; +import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -32,13 +32,13 @@ public class TitlePacket implements ComponentHoldingServerPacket { /** * Constructs a new title packet from an action that can take a component argument. * - * @param action the action + * @param action the action * @param payload the payload * @throws IllegalArgumentException if the action is not {@link Action#SET_TITLE}, - * {@link Action#SET_SUBTITLE} or {@link Action#SET_ACTION_BAR} + * {@link Action#SET_SUBTITLE} or {@link Action#SET_ACTION_BAR} */ public TitlePacket(@NotNull Action action, @NotNull Component payload) { - Validate.isTrue(action == SET_TITLE || action == SET_SUBTITLE || action == SET_ACTION_BAR, "Invalid action type"); + Check.argCondition(action != SET_TITLE && action != SET_SUBTITLE && action != SET_ACTION_BAR, "Invalid action type"); this.action = action; this.payload = payload; } @@ -48,7 +48,7 @@ public class TitlePacket implements ComponentHoldingServerPacket { * * @param action the action * @throws IllegalArgumentException if the action is not {@link Action#RESET}, - * or {@link Action#HIDE} + * or {@link Action#HIDE} */ public TitlePacket(@NotNull Action action) { this.action = action; @@ -57,8 +57,8 @@ public class TitlePacket implements ComponentHoldingServerPacket { /** * Constructs a new title packet for {@link Action#SET_TIMES_AND_DISPLAY}. * - * @param fadeIn the fade in time - * @param stay the stay time + * @param fadeIn the fade in time + * @param stay the stay time * @param fadeOut the fade out time */ public TitlePacket(int fadeIn, int stay, int fadeOut) { diff --git a/src/main/java/net/minestom/server/registry/ResourceGatherer.java b/src/main/java/net/minestom/server/registry/ResourceGatherer.java index 914f26dcc..bda94d91c 100644 --- a/src/main/java/net/minestom/server/registry/ResourceGatherer.java +++ b/src/main/java/net/minestom/server/registry/ResourceGatherer.java @@ -5,7 +5,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.io.FastBufferedInputStream; -import org.apache.commons.lang3.StringUtils; +import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/net/minestom/server/utils/StringUtils.java b/src/main/java/net/minestom/server/utils/StringUtils.java new file mode 100644 index 000000000..332d0795e --- /dev/null +++ b/src/main/java/net/minestom/server/utils/StringUtils.java @@ -0,0 +1,161 @@ +package net.minestom.server.utils; + +import org.jetbrains.annotations.NotNull; + +public class StringUtils { + + public static final String SPACE = " "; + public static final char SPACE_CHAR = ' '; + + public static int countMatches(@NotNull final CharSequence str, final char ch) { + if (str.length() == 0) { + return 0; + } + int count = 0; + // We could also call str.toCharArray() for faster look ups but that would generate more garbage. + for (int i = 0; i < str.length(); i++) { + if (ch == str.charAt(i)) { + count++; + } + } + return count; + } + + /** + * Applies the Jaro-Winkler distance algorithm to the given strings, providing information about the + * similarity of them. + * + * @param s1 The first string that gets compared. May be null or empty. + * @param s2 The second string that gets compared. May be null or empty. + * @return The Jaro-Winkler score (between 0.0 and 1.0), with a higher value indicating larger similarity. + * @author Thomas Trojer + */ + public static double jaroWinklerScore(final String s1, final String s2) { + // lowest score on empty strings + if (s1 == null || s2 == null || s1.isEmpty() || s2.isEmpty()) { + return 0; + } + // highest score on equal strings + if (s1.equals(s2)) { + return 1; + } + // some score on different strings + int prefixMatch = 0; // exact prefix matches + int matches = 0; // matches (including prefix and ones requiring transpostion) + int transpositions = 0; // matching characters that are not aligned but close together + int maxLength = Math.max(s1.length(), s2.length()); + int maxMatchDistance = Math.max((int) Math.floor(maxLength / 2.0) - 1, 0); // look-ahead/-behind to limit transposed matches + // comparison + final String shorter = s1.length() < s2.length() ? s1 : s2; + final String longer = s1.length() >= s2.length() ? s1 : s2; + for (int i = 0; i < shorter.length(); i++) { + // check for exact matches + boolean match = shorter.charAt(i) == longer.charAt(i); + if (match) { + if (i < 4) { + // prefix match (of at most 4 characters, as described by the algorithm) + prefixMatch++; + } + matches++; + continue; + } + // check fro transposed matches + for (int j = Math.max(i - maxMatchDistance, 0); j < Math.min(i + maxMatchDistance, longer.length()); j++) { + if (i == j) { + // case already covered + continue; + } + // transposition required to match? + match = shorter.charAt(i) == longer.charAt(j); + if (match) { + transpositions++; + break; + } + } + } + // any matching characters? + if (matches == 0) { + return 0; + } + // modify transpositions (according to the algorithm) + transpositions = (int) (transpositions / 2.0); + // non prefix-boosted score + double score = 0.3334 * (matches / (double) longer.length() + matches / (double) shorter.length() + (matches - transpositions) + / (double) matches); + if (score < 0.7) { + return score; + } + // we already have a good match, hence we boost the score proportional to the common prefix + return score + prefixMatch * 0.1 * (1.0 - score); + } + + public static String unescapeJavaString(String st) { + StringBuilder sb = new StringBuilder(st.length()); + + for (int i = 0; i < st.length(); i++) { + char ch = st.charAt(i); + if (ch == '\\') { + char nextChar = (i == st.length() - 1) ? '\\' : st + .charAt(i + 1); + // Octal escape? + if (nextChar >= '0' && nextChar <= '7') { + String code = "" + nextChar; + i++; + if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' + && st.charAt(i + 1) <= '7') { + code += st.charAt(i + 1); + i++; + if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' + && st.charAt(i + 1) <= '7') { + code += st.charAt(i + 1); + i++; + } + } + sb.append((char) Integer.parseInt(code, 8)); + continue; + } + switch (nextChar) { + case '\\': + ch = '\\'; + break; + case 'b': + ch = '\b'; + break; + case 'f': + ch = '\f'; + break; + case 'n': + ch = '\n'; + break; + case 'r': + ch = '\r'; + break; + case 't': + ch = '\t'; + break; + case '\"': + ch = '\"'; + break; + case '\'': + ch = '\''; + break; + // Hex Unicode: u???? + case 'u': + if (i >= st.length() - 5) { + ch = 'u'; + break; + } + int code = Integer.parseInt( + "" + st.charAt(i + 2) + st.charAt(i + 3) + + st.charAt(i + 4) + st.charAt(i + 5), 16); + sb.append(Character.toChars(code)); + i += 5; + continue; + } + i++; + } + sb.append(ch); + } + return sb.toString(); + } +} diff --git a/src/main/java/net/minestom/server/utils/TickUtils.java b/src/main/java/net/minestom/server/utils/TickUtils.java index aa5c98500..7b68618a3 100644 --- a/src/main/java/net/minestom/server/utils/TickUtils.java +++ b/src/main/java/net/minestom/server/utils/TickUtils.java @@ -1,7 +1,7 @@ package net.minestom.server.utils; import net.minestom.server.MinecraftServer; -import org.apache.commons.lang3.Validate; +import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import java.time.Duration; @@ -22,6 +22,7 @@ public class TickUtils { /** * Creates a number of ticks from a given duration, based on {@link MinecraftServer#TICK_MS}. + * * @param duration the duration * @return the number of ticks * @throws IllegalArgumentException if duration is negative @@ -32,14 +33,14 @@ public class TickUtils { /** * Creates a number of ticks from a given duration. - * @param duration the duration + * + * @param duration the duration * @param msPerTick the number of milliseconds per tick * @return the number of ticks * @throws IllegalArgumentException if duration is negative */ public static int fromDuration(@NotNull Duration duration, int msPerTick) { - Validate.isTrue(!duration.isNegative(), "Duration cannot be negative"); - + Check.argCondition(duration.isNegative(), "Duration cannot be negative"); return (int) (duration.toMillis() / msPerTick); } } From bcf184123dbfebd91454c11f9adcc7246bc5ca42 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 15 May 2021 10:12:04 +0200 Subject: [PATCH 26/66] Fix build --- src/main/java/net/minestom/server/utils/StringUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/minestom/server/utils/StringUtils.java b/src/main/java/net/minestom/server/utils/StringUtils.java index 332d0795e..eaf91dcab 100644 --- a/src/main/java/net/minestom/server/utils/StringUtils.java +++ b/src/main/java/net/minestom/server/utils/StringUtils.java @@ -25,8 +25,8 @@ public class StringUtils { * Applies the Jaro-Winkler distance algorithm to the given strings, providing information about the * similarity of them. * - * @param s1 The first string that gets compared. May be null or empty. - * @param s2 The second string that gets compared. May be null or empty. + * @param s1 The first string that gets compared. May be null or empty. + * @param s2 The second string that gets compared. May be null or empty. * @return The Jaro-Winkler score (between 0.0 and 1.0), with a higher value indicating larger similarity. * @author Thomas Trojer */ From 2b17edfc46d0c8b713b16db1eb7c166f9da9c184 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 15 May 2021 10:14:05 +0200 Subject: [PATCH 27/66] Fix build 2 --- src/main/java/net/minestom/server/utils/StringUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/utils/StringUtils.java b/src/main/java/net/minestom/server/utils/StringUtils.java index eaf91dcab..870380cba 100644 --- a/src/main/java/net/minestom/server/utils/StringUtils.java +++ b/src/main/java/net/minestom/server/utils/StringUtils.java @@ -28,7 +28,7 @@ public class StringUtils { * @param s1 The first string that gets compared. May be null or empty. * @param s2 The second string that gets compared. May be null or empty. * @return The Jaro-Winkler score (between 0.0 and 1.0), with a higher value indicating larger similarity. - * @author Thomas Trojer + * @author Thomas Trojer thomas@trojer.net */ public static double jaroWinklerScore(final String s1, final String s2) { // lowest score on empty strings From bb1f4a37929b6699e33379ca47a3eadec2995447 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 15 May 2021 11:02:07 +0200 Subject: [PATCH 28/66] Add CommandContext#getOrDefault --- .../server/command/builder/CommandContext.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/command/builder/CommandContext.java b/src/main/java/net/minestom/server/command/builder/CommandContext.java index 3b23ca872..ddbec96b8 100644 --- a/src/main/java/net/minestom/server/command/builder/CommandContext.java +++ b/src/main/java/net/minestom/server/command/builder/CommandContext.java @@ -44,10 +44,16 @@ public class CommandContext { } public T get(@NotNull String identifier) { - return (T) args.computeIfAbsent(identifier, s -> { - throw new NullPointerException( - "The argument with the id '" + identifier + "' has no value assigned, be sure to check your arguments id, your syntax, and that you do not change the argument id dynamically."); - }); + return (T) args.get(identifier); + } + + public T getOrDefault(@NotNull Argument argument, T defaultValue) { + return getOrDefault(argument.getId(), defaultValue); + } + + public T getOrDefault(@NotNull String identifier, T defaultValue) { + T value; + return (value = get(identifier)) != null ? value : defaultValue; } public boolean has(@NotNull Argument argument) { From e3d31f113abcf54fc62c5168f5aa2c15ee5eb5ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9meth=20Noel?= Date: Sat, 15 May 2021 21:07:42 +0200 Subject: [PATCH 29/66] Don't send scheduled sync to the player it self --- .../java/net/minestom/server/entity/Entity.java | 14 ++++++++------ .../java/net/minestom/server/entity/Player.java | 9 +++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 87b539f61..477cd9f2d 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -268,7 +268,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, final ChunkCallback endCallback = (chunk) -> { refreshPosition(teleportPosition); - synchronizePosition(); + synchronizePosition(true); OptionalCallback.execute(callback); }; @@ -594,7 +594,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, // Synchronization and packets... if (!isNettyClient) { - synchronizePosition(); + synchronizePosition(true); } // Verify if velocity packet has to be sent if (hasVelocity() || (!isNettyClient && gravityTickCount > 0)) { @@ -665,7 +665,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, // Scheduled synchronization if (!Cooldown.hasCooldown(time, lastAbsoluteSynchronizationTime, getSynchronizationCooldown())) { - synchronizePosition(); + synchronizePosition(false); } if (shouldRemove() && !MinecraftServer.isStopping()) { @@ -680,7 +680,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, * The following packets are sent to viewers (check are performed in this order): *

    *
  1. {@link EntityTeleportPacket} if {@code distanceX > 8 || distanceY > 8 || distanceZ > 8} - * (performed using {@link #synchronizePosition()})
  2. + * (performed using {@link #synchronizePosition(boolean)}) *
  3. {@link EntityPositionAndRotationPacket} if {@code positionChange && viewChange}
  4. *
  5. {@link EntityPositionPacket} if {@code positionChange}
  6. *
  7. {@link EntityRotationPacket} and {@link EntityHeadLookPacket} if {@code viewChange}
  8. @@ -698,7 +698,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, final boolean positionChange = (distanceX+distanceY+distanceZ) > 0; if (distanceX > 8 || distanceY > 8 || distanceZ > 8) { - synchronizePosition(); + synchronizePosition(true); // #synchronizePosition sets sync fields, it's safe to return return; } else if (positionChange && viewChange) { @@ -1583,9 +1583,11 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, * {@link EntityTeleportPacket} to viewers, in case of a player this is * overridden in order to send an additional {@link PlayerPositionAndLookPacket} * to itself. + * @param includeSelf if {@code true} and this is a {@link Player} an additional {@link PlayerPositionAndLookPacket} + * will be sent to the player itself */ @ApiStatus.Internal - protected void synchronizePosition() { + protected void synchronizePosition(boolean includeSelf) { final Position pos = position.clone(); final EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket(); entityTeleportPacket.entityId = getEntityId(); diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 8a7ecad0c..cb7ea2dd4 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -661,7 +661,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, } if (dimensionChange || firstSpawn) { - synchronizePosition(); // So the player doesn't get stuck + synchronizePosition(true); // So the player doesn't get stuck this.inventory.update(); } @@ -1984,18 +1984,19 @@ public class Player extends LivingEntity implements CommandSender, Localizable, } /** - * @see Entity#synchronizePosition() + * @see Entity#synchronizePosition(boolean) + * @param includeSelf */ @Override @ApiStatus.Internal - protected void synchronizePosition() { + protected void synchronizePosition(boolean includeSelf) { final PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket(); positionAndLookPacket.position = position.clone(); positionAndLookPacket.flags = 0x00; positionAndLookPacket.teleportId = teleportId.incrementAndGet(); playerConnection.sendPacket(positionAndLookPacket); - super.synchronizePosition(); + super.synchronizePosition(includeSelf); } /** From 3081ffbb0051de090053defcba74457317a474bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9meth=20Noel?= Date: Sat, 15 May 2021 21:11:48 +0200 Subject: [PATCH 30/66] Include the check --- .../java/net/minestom/server/entity/Player.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index cb7ea2dd4..92b45c27d 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -1985,16 +1985,17 @@ public class Player extends LivingEntity implements CommandSender, Localizable, /** * @see Entity#synchronizePosition(boolean) - * @param includeSelf */ @Override @ApiStatus.Internal protected void synchronizePosition(boolean includeSelf) { - final PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket(); - positionAndLookPacket.position = position.clone(); - positionAndLookPacket.flags = 0x00; - positionAndLookPacket.teleportId = teleportId.incrementAndGet(); - playerConnection.sendPacket(positionAndLookPacket); + if (includeSelf) { + final PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket(); + positionAndLookPacket.position = position.clone(); + positionAndLookPacket.flags = 0x00; + positionAndLookPacket.teleportId = teleportId.incrementAndGet(); + playerConnection.sendPacket(positionAndLookPacket); + } super.synchronizePosition(includeSelf); } From 9e2d8bc40806fcb8af941857b0cf0f1b790e763a Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 16 May 2021 23:57:42 +0200 Subject: [PATCH 31/66] Fix view being reset after velocity application --- .../net/minestom/server/entity/Entity.java | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 477cd9f2d..d30c80fc0 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -552,7 +552,10 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, // Apply the position if changed if (!finalVelocityPosition.isSimilar(position)) { - refreshPosition(finalVelocityPosition); + refreshPosition(finalVelocityPosition.getX(), + finalVelocityPosition.getY(), + finalVelocityPosition.getZ()); + sendPositionUpdate(true); } @@ -677,25 +680,25 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, * Sends the correct packets to update the entity's position, should be called * every tick. The movement is checked inside the method! *

    - * The following packets are sent to viewers (check are performed in this order): - *

      - *
    1. {@link EntityTeleportPacket} if {@code distanceX > 8 || distanceY > 8 || distanceZ > 8} - * (performed using {@link #synchronizePosition(boolean)})
    2. - *
    3. {@link EntityPositionAndRotationPacket} if {@code positionChange && viewChange}
    4. - *
    5. {@link EntityPositionPacket} if {@code positionChange}
    6. - *
    7. {@link EntityRotationPacket} and {@link EntityHeadLookPacket} if {@code viewChange}
    8. - *
    - * In case of a player's position and/or view change an additional {@link PlayerPositionAndLookPacket} - * is sent to self. + * The following packets are sent to viewers (check are performed in this order): + *
      + *
    1. {@link EntityTeleportPacket} if {@code distanceX > 8 || distanceY > 8 || distanceZ > 8} + * (performed using {@link #synchronizePosition(boolean)})
    2. + *
    3. {@link EntityPositionAndRotationPacket} if {@code positionChange && viewChange}
    4. + *
    5. {@link EntityPositionPacket} if {@code positionChange}
    6. + *
    7. {@link EntityRotationPacket} and {@link EntityHeadLookPacket} if {@code viewChange}
    8. + *
    + * In case of a player's position and/or view change an additional {@link PlayerPositionAndLookPacket} + * is sent to self. * * @param clientSide {@code true} if the client triggered this action */ protected void sendPositionUpdate(final boolean clientSide) { final boolean viewChange = !position.hasSimilarView(lastSyncedPosition); - final double distanceX = Math.abs(position.getX()-lastSyncedPosition.getX()); - final double distanceY = Math.abs(position.getY()-lastSyncedPosition.getY()); - final double distanceZ = Math.abs(position.getZ()-lastSyncedPosition.getZ()); - final boolean positionChange = (distanceX+distanceY+distanceZ) > 0; + final double distanceX = Math.abs(position.getX() - lastSyncedPosition.getX()); + final double distanceY = Math.abs(position.getY() - lastSyncedPosition.getY()); + final double distanceZ = Math.abs(position.getZ() - lastSyncedPosition.getZ()); + final boolean positionChange = (distanceX + distanceY + distanceZ) > 0; if (distanceX > 8 || distanceY > 8 || distanceZ > 8) { synchronizePosition(true); @@ -742,7 +745,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, final PlayerPositionAndLookPacket playerPositionAndLookPacket = new PlayerPositionAndLookPacket(); playerPositionAndLookPacket.flags = 0b111; playerPositionAndLookPacket.position = position.clone().subtract(lastSyncedPosition.getX(), lastSyncedPosition.getY(), lastSyncedPosition.getZ()); - playerPositionAndLookPacket.teleportId = ((Player)this).getNextTeleportId(); + playerPositionAndLookPacket.teleportId = ((Player) this).getNextTeleportId(); ((Player) this).getPlayerConnection().sendPacket(playerPositionAndLookPacket); } @@ -1393,8 +1396,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, /** * Updates internal fields and sends updates * - * @param position the new position - * + * @param position the new position * @see #refreshPosition(double, double, double) * @see #refreshView(float, float) * @see #sendPositionUpdate(boolean) @@ -1583,6 +1585,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, * {@link EntityTeleportPacket} to viewers, in case of a player this is * overridden in order to send an additional {@link PlayerPositionAndLookPacket} * to itself. + * * @param includeSelf if {@code true} and this is a {@link Player} an additional {@link PlayerPositionAndLookPacket} * will be sent to the player itself */ From 9c41a195926a94a8563bcdac3543a19ef235026f Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 12:34:45 +0200 Subject: [PATCH 32/66] Initial tag commit --- .../java/net/minestom/server/tag/Tag.java | 110 ++++++++++++++++++ .../net/minestom/server/tag/TagGetter.java | 8 ++ .../net/minestom/server/tag/TagSetter.java | 8 ++ 3 files changed, 126 insertions(+) create mode 100644 src/main/java/net/minestom/server/tag/Tag.java create mode 100644 src/main/java/net/minestom/server/tag/TagGetter.java create mode 100644 src/main/java/net/minestom/server/tag/TagSetter.java diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java new file mode 100644 index 000000000..2b9f3ab21 --- /dev/null +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -0,0 +1,110 @@ +package net.minestom.server.tag; + +import org.jetbrains.annotations.NotNull; +import org.jglrxavpok.hephaistos.nbt.NBT; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class Tag { + + private final String key; + private final Function readFunction; + private final BiConsumer writeConsumer; + + private Tag(@NotNull String key, + @NotNull Function readFunction, + @NotNull BiConsumer writeConsumer) { + this.key = key; + this.readFunction = readFunction; + this.writeConsumer = writeConsumer; + } + + public @NotNull String getKey() { + return key; + } + + protected T read(@NotNull NBTCompound nbtCompound) { + return readFunction.apply(nbtCompound); + } + + protected void write(@NotNull NBTCompound nbtCompound, @NotNull T value) { + this.writeConsumer.accept(nbtCompound, value); + } + + public static @NotNull Tag Byte(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getByte(key), + (nbtCompound, value) -> nbtCompound.setByte(key, value)); + } + + public static @NotNull Tag Short(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getShort(key), + (nbtCompound, value) -> nbtCompound.setShort(key, value)); + } + + public static @NotNull Tag Integer(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getInt(key), + (nbtCompound, integer) -> nbtCompound.setInt(key, integer)); + } + + public static @NotNull Tag Long(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getLong(key), + (nbtCompound, value) -> nbtCompound.setLong(key, value)); + } + + public static @NotNull Tag Float(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getFloat(key), + (nbtCompound, value) -> nbtCompound.setFloat(key, value)); + } + + public static @NotNull Tag Double(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getDouble(key), + (nbtCompound, value) -> nbtCompound.setDouble(key, value)); + } + + public static @NotNull Tag ByteArray(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getByteArray(key), + (nbtCompound, value) -> nbtCompound.setByteArray(key, value)); + } + + public static @NotNull Tag String(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getString(key), + (nbtCompound, value) -> nbtCompound.setString(key, value)); + } + + public static @NotNull Tag NBT(@NotNull String key) { + return new Tag<>(key, + nbt -> { + var currentNBT = nbt.get(key); + + // Avoid a NPE when cloning a null variable. + if (currentNBT == null) { + return null; + } + + return currentNBT.deepClone(); + }, + ((nbt, value) -> nbt.set(key, value.deepClone()))); + } + + public static @NotNull Tag IntArray(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getIntArray(key), + (nbtCompound, value) -> nbtCompound.setIntArray(key, value)); + } + + public static @NotNull Tag LongArray(@NotNull String key) { + return new Tag<>(key, + nbtCompound -> nbtCompound.getLongArray(key), + (nbtCompound, value) -> nbtCompound.setLongArray(key, value)); + } +} diff --git a/src/main/java/net/minestom/server/tag/TagGetter.java b/src/main/java/net/minestom/server/tag/TagGetter.java new file mode 100644 index 000000000..9f5b99852 --- /dev/null +++ b/src/main/java/net/minestom/server/tag/TagGetter.java @@ -0,0 +1,8 @@ +package net.minestom.server.tag; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface TagGetter { + @Nullable T getTag(@NotNull Tag tag); +} diff --git a/src/main/java/net/minestom/server/tag/TagSetter.java b/src/main/java/net/minestom/server/tag/TagSetter.java new file mode 100644 index 000000000..ecd3c8db5 --- /dev/null +++ b/src/main/java/net/minestom/server/tag/TagSetter.java @@ -0,0 +1,8 @@ +package net.minestom.server.tag; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface TagSetter { + void setTag(@NotNull Tag tag, @Nullable T value); +} From 0a7b773aa879973694525d09f71197f8a112c5cc Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 12:44:22 +0200 Subject: [PATCH 33/66] Added tag default value --- src/main/java/net/minestom/server/tag/Tag.java | 18 ++++++++++++++++++ .../net/minestom/server/tag/TagGetter.java | 2 ++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 2b9f3ab21..10ff89b1d 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -1,11 +1,13 @@ package net.minestom.server.tag; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBT; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.function.BiConsumer; import java.util.function.Function; +import java.util.function.Supplier; public class Tag { @@ -13,6 +15,8 @@ public class Tag { private final Function readFunction; private final BiConsumer writeConsumer; + protected volatile Supplier defaultValue; + private Tag(@NotNull String key, @NotNull Function readFunction, @NotNull BiConsumer writeConsumer) { @@ -25,6 +29,20 @@ public class Tag { return key; } + public Tag defaultValue(@NotNull Supplier defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public Tag defaultValue(@NotNull T defaultValue) { + defaultValue(() -> defaultValue); + return this; + } + + public @Nullable Supplier<@Nullable T> getDefaultValue() { + return defaultValue; + } + protected T read(@NotNull NBTCompound nbtCompound) { return readFunction.apply(nbtCompound); } diff --git a/src/main/java/net/minestom/server/tag/TagGetter.java b/src/main/java/net/minestom/server/tag/TagGetter.java index 9f5b99852..e02d0a520 100644 --- a/src/main/java/net/minestom/server/tag/TagGetter.java +++ b/src/main/java/net/minestom/server/tag/TagGetter.java @@ -5,4 +5,6 @@ import org.jetbrains.annotations.Nullable; public interface TagGetter { @Nullable T getTag(@NotNull Tag tag); + + boolean hasTag(@NotNull Tag tag); } From 1715e55b4dcac13cec610e2ce5619e6d94367923 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 13:04:00 +0200 Subject: [PATCH 34/66] Handle tag logic inside read/write --- src/main/java/net/minestom/server/tag/Tag.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 10ff89b1d..d1669c811 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -43,12 +43,20 @@ public class Tag { return defaultValue; } - protected T read(@NotNull NBTCompound nbtCompound) { - return readFunction.apply(nbtCompound); + public @Nullable T read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey(key)) { + return readFunction.apply(nbtCompound); + } else { + return defaultValue != null ? defaultValue.get() : null; + } } - protected void write(@NotNull NBTCompound nbtCompound, @NotNull T value) { - this.writeConsumer.accept(nbtCompound, value); + public void write(@NotNull NBTCompound nbtCompound, @Nullable T value) { + if (value != null) { + this.writeConsumer.accept(nbtCompound, value); + } else { + nbtCompound.removeTag(key); + } } public static @NotNull Tag Byte(@NotNull String key) { From d3b4b2ac5614f87230b0a7a35a69f616ded5be24 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 14:02:14 +0200 Subject: [PATCH 35/66] Added TagSerializer --- .../java/net/minestom/server/tag/Tag.java | 21 +++++++++++++++++++ .../tag/{TagGetter.java => TagReader.java} | 2 +- .../minestom/server/tag/TagSerializer.java | 11 ++++++++++ .../tag/{TagSetter.java => TagWriter.java} | 2 +- 4 files changed, 34 insertions(+), 2 deletions(-) rename src/main/java/net/minestom/server/tag/{TagGetter.java => TagReader.java} (88%) create mode 100644 src/main/java/net/minestom/server/tag/TagSerializer.java rename src/main/java/net/minestom/server/tag/{TagSetter.java => TagWriter.java} (86%) diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index d1669c811..cfb90c189 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -133,4 +133,25 @@ public class Tag { nbtCompound -> nbtCompound.getLongArray(key), (nbtCompound, value) -> nbtCompound.setLongArray(key, value)); } + + public static @NotNull Tag Custom(@NotNull String key, @NotNull TagSerializer serializer) { + return new Tag<>(key, + nbtCompound -> serializer.read(new TagReader() { + @Override + public @Nullable T getTag(@NotNull Tag tag) { + return tag.read(nbtCompound); + } + + @Override + public boolean hasTag(@NotNull Tag tag) { + return nbtCompound.containsKey(tag.key); + } + }), + (nbtCompound, value) -> new TagWriter() { + @Override + public void setTag(@NotNull Tag tag, @Nullable T value) { + tag.write(nbtCompound, value); + } + }); + } } diff --git a/src/main/java/net/minestom/server/tag/TagGetter.java b/src/main/java/net/minestom/server/tag/TagReader.java similarity index 88% rename from src/main/java/net/minestom/server/tag/TagGetter.java rename to src/main/java/net/minestom/server/tag/TagReader.java index e02d0a520..74f0007a3 100644 --- a/src/main/java/net/minestom/server/tag/TagGetter.java +++ b/src/main/java/net/minestom/server/tag/TagReader.java @@ -3,7 +3,7 @@ package net.minestom.server.tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public interface TagGetter { +public interface TagReader { @Nullable T getTag(@NotNull Tag tag); boolean hasTag(@NotNull Tag tag); diff --git a/src/main/java/net/minestom/server/tag/TagSerializer.java b/src/main/java/net/minestom/server/tag/TagSerializer.java new file mode 100644 index 000000000..26692c591 --- /dev/null +++ b/src/main/java/net/minestom/server/tag/TagSerializer.java @@ -0,0 +1,11 @@ +package net.minestom.server.tag; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface TagSerializer { + + @Nullable T read(@NotNull TagReader reader); + + void write(@NotNull TagWriter writer, @NotNull T value); +} diff --git a/src/main/java/net/minestom/server/tag/TagSetter.java b/src/main/java/net/minestom/server/tag/TagWriter.java similarity index 86% rename from src/main/java/net/minestom/server/tag/TagSetter.java rename to src/main/java/net/minestom/server/tag/TagWriter.java index ecd3c8db5..d6e9d1ce3 100644 --- a/src/main/java/net/minestom/server/tag/TagSetter.java +++ b/src/main/java/net/minestom/server/tag/TagWriter.java @@ -3,6 +3,6 @@ package net.minestom.server.tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public interface TagSetter { +public interface TagWriter { void setTag(@NotNull Tag tag, @Nullable T value); } From 1ec631fa5b46c282e13f9c802cbaf4cca620306b Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 14:05:03 +0200 Subject: [PATCH 36/66] Create TagReader/Writer from compound --- .../java/net/minestom/server/tag/Tag.java | 19 ++----------------- .../net/minestom/server/tag/TagReader.java | 15 +++++++++++++++ .../net/minestom/server/tag/TagWriter.java | 10 ++++++++++ 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index cfb90c189..49c920690 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -136,22 +136,7 @@ public class Tag { public static @NotNull Tag Custom(@NotNull String key, @NotNull TagSerializer serializer) { return new Tag<>(key, - nbtCompound -> serializer.read(new TagReader() { - @Override - public @Nullable T getTag(@NotNull Tag tag) { - return tag.read(nbtCompound); - } - - @Override - public boolean hasTag(@NotNull Tag tag) { - return nbtCompound.containsKey(tag.key); - } - }), - (nbtCompound, value) -> new TagWriter() { - @Override - public void setTag(@NotNull Tag tag, @Nullable T value) { - tag.write(nbtCompound, value); - } - }); + nbtCompound -> serializer.read(TagReader.fromCompound(nbtCompound)), + (nbtCompound, value) -> serializer.write(TagWriter.fromCompound(nbtCompound), value)); } } diff --git a/src/main/java/net/minestom/server/tag/TagReader.java b/src/main/java/net/minestom/server/tag/TagReader.java index 74f0007a3..b29f944b6 100644 --- a/src/main/java/net/minestom/server/tag/TagReader.java +++ b/src/main/java/net/minestom/server/tag/TagReader.java @@ -2,9 +2,24 @@ package net.minestom.server.tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; public interface TagReader { @Nullable T getTag(@NotNull Tag tag); boolean hasTag(@NotNull Tag tag); + + static @NotNull TagReader fromCompound(@NotNull NBTCompound compound) { + return new TagReader() { + @Override + public @Nullable T getTag(@NotNull Tag tag) { + return tag.read(compound); + } + + @Override + public boolean hasTag(@NotNull Tag tag) { + return compound.containsKey(tag.getKey()); + } + }; + } } diff --git a/src/main/java/net/minestom/server/tag/TagWriter.java b/src/main/java/net/minestom/server/tag/TagWriter.java index d6e9d1ce3..c88504c6d 100644 --- a/src/main/java/net/minestom/server/tag/TagWriter.java +++ b/src/main/java/net/minestom/server/tag/TagWriter.java @@ -2,7 +2,17 @@ package net.minestom.server.tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; public interface TagWriter { void setTag(@NotNull Tag tag, @Nullable T value); + + static @NotNull TagWriter fromCompound(@NotNull NBTCompound compound) { + return new TagWriter() { + @Override + public void setTag(@NotNull Tag tag, @Nullable T value) { + tag.write(compound, value); + } + }; + } } From 429a14e22028d49eace4c091544e55f19dffeaa9 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 15:14:16 +0200 Subject: [PATCH 37/66] Add tag comments --- .../java/net/minestom/server/tag/Tag.java | 9 +++++++- .../net/minestom/server/tag/TagHandler.java | 7 ++++++ .../net/minestom/server/tag/TagReader.java | 23 +++++++++++++++++++ .../minestom/server/tag/TagSerializer.java | 17 ++++++++++++++ .../net/minestom/server/tag/TagWriter.java | 17 ++++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/minestom/server/tag/TagHandler.java diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 49c920690..9ef0bc584 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -9,7 +9,14 @@ import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Supplier; -public class Tag { +/** + * Represents a key to retrieve or change a value. + *

    + * All tags are serializable. + * + * @param the tag type + */ +public final class Tag { private final String key; private final Function readFunction; diff --git a/src/main/java/net/minestom/server/tag/TagHandler.java b/src/main/java/net/minestom/server/tag/TagHandler.java new file mode 100644 index 000000000..c5b9632cf --- /dev/null +++ b/src/main/java/net/minestom/server/tag/TagHandler.java @@ -0,0 +1,7 @@ +package net.minestom.server.tag; + +/** + * Represents an element which can read and write {@link Tag tags}. + */ +public interface TagHandler extends TagReader, TagWriter { +} diff --git a/src/main/java/net/minestom/server/tag/TagReader.java b/src/main/java/net/minestom/server/tag/TagReader.java index b29f944b6..79338c0df 100644 --- a/src/main/java/net/minestom/server/tag/TagReader.java +++ b/src/main/java/net/minestom/server/tag/TagReader.java @@ -4,11 +4,34 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; +/** + * Represents an element which can read {@link Tag tags}. + */ public interface TagReader { + + /** + * Reads the specified tag. + * + * @param tag the tag to read + * @param the tag type + * @return the read tag, null if not present + */ @Nullable T getTag(@NotNull Tag tag); + /** + * Returns if a tag is present. + * + * @param tag the tag to check + * @return true if the tag is present, false otherwise + */ boolean hasTag(@NotNull Tag tag); + /** + * Converts an nbt compound to a tag reader. + * + * @param compound the compound to convert + * @return a {@link TagReader} capable of reading {@code compound} + */ static @NotNull TagReader fromCompound(@NotNull NBTCompound compound) { return new TagReader() { @Override diff --git a/src/main/java/net/minestom/server/tag/TagSerializer.java b/src/main/java/net/minestom/server/tag/TagSerializer.java index 26692c591..151d1de0e 100644 --- a/src/main/java/net/minestom/server/tag/TagSerializer.java +++ b/src/main/java/net/minestom/server/tag/TagSerializer.java @@ -3,9 +3,26 @@ package net.minestom.server.tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * Interface used to create custom types compatible with {@link Tag#Custom(String, TagSerializer)}. + * + * @param the type to serialize + */ public interface TagSerializer { + /** + * Reads the custom tag from a {@link TagReader}. + * + * @param reader the reader + * @return the deserialized value + */ @Nullable T read(@NotNull TagReader reader); + /** + * Writes the custom tag to a {@link TagWriter}. + * + * @param writer the writer + * @param value the value to serialize + */ void write(@NotNull TagWriter writer, @NotNull T value); } diff --git a/src/main/java/net/minestom/server/tag/TagWriter.java b/src/main/java/net/minestom/server/tag/TagWriter.java index c88504c6d..8b85d5151 100644 --- a/src/main/java/net/minestom/server/tag/TagWriter.java +++ b/src/main/java/net/minestom/server/tag/TagWriter.java @@ -4,9 +4,26 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; +/** + * Represents an element which can write {@link Tag tags}. + */ public interface TagWriter { + + /** + * Writes the specified type. + * + * @param tag the tag to write + * @param value the tag value, null to remove + * @param the tag type + */ void setTag(@NotNull Tag tag, @Nullable T value); + /** + * Converts an nbt compound to a tag writer. + * + * @param compound the compound to convert + * @return a {@link TagWriter} capable of writing {@code compound} + */ static @NotNull TagWriter fromCompound(@NotNull NBTCompound compound) { return new TagWriter() { @Override From 9255adb7ec083a2422e3eb617859863965ffdb97 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 15:17:53 +0200 Subject: [PATCH 38/66] No need to expose tag default value --- src/main/java/net/minestom/server/tag/Tag.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 9ef0bc584..d1f546709 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -21,8 +21,7 @@ public final class Tag { private final String key; private final Function readFunction; private final BiConsumer writeConsumer; - - protected volatile Supplier defaultValue; + private volatile Supplier defaultValue; private Tag(@NotNull String key, @NotNull Function readFunction, @@ -46,15 +45,12 @@ public final class Tag { return this; } - public @Nullable Supplier<@Nullable T> getDefaultValue() { - return defaultValue; - } - public @Nullable T read(@NotNull NBTCompound nbtCompound) { if (nbtCompound.containsKey(key)) { return readFunction.apply(nbtCompound); } else { - return defaultValue != null ? defaultValue.get() : null; + final var supplier = defaultValue; + return supplier != null ? supplier.get() : null; } } From cdedcd89d6cb84cfb5edc3888b763e6e2b71a68a Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Mon, 17 May 2021 14:46:25 +0100 Subject: [PATCH 39/66] Simplify Messenger implementation --- .../server/listener/ChatMessageListener.java | 4 +- .../minestom/server/message/Messenger.java | 55 ++----------------- .../net/minestom/server/utils/Action.java | 17 ------ 3 files changed, 9 insertions(+), 67 deletions(-) delete mode 100644 src/main/java/net/minestom/server/utils/Action.java diff --git a/src/main/java/net/minestom/server/listener/ChatMessageListener.java b/src/main/java/net/minestom/server/listener/ChatMessageListener.java index d58525f69..0bd9cbe23 100644 --- a/src/main/java/net/minestom/server/listener/ChatMessageListener.java +++ b/src/main/java/net/minestom/server/listener/ChatMessageListener.java @@ -29,7 +29,9 @@ public class ChatMessageListener { final String command = message.replaceFirst(cmdPrefix, ""); // check if we can receive commands - Messenger.receiveCommand(player, () -> COMMAND_MANAGER.execute(player, command)); + if (Messenger.canReceiveCommand(player)) { + COMMAND_MANAGER.execute(player, command); + } // Do not call chat event return; diff --git a/src/main/java/net/minestom/server/message/Messenger.java b/src/main/java/net/minestom/server/message/Messenger.java index f6c8f263c..c4dc90ba1 100644 --- a/src/main/java/net/minestom/server/message/Messenger.java +++ b/src/main/java/net/minestom/server/message/Messenger.java @@ -1,19 +1,15 @@ package net.minestom.server.message; +import java.util.*; + import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.entity.Player; import net.minestom.server.network.packet.server.play.ChatMessagePacket; -import net.minestom.server.utils.Action; import net.minestom.server.utils.PacketUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - /** * Utility class to handle client chat settings. */ @@ -50,20 +46,11 @@ public class Messenger { * @param message the message * @param position the position * @param uuid the UUID of the sender, if any - * @return a set of players who received the message */ - public static @NotNull Set sendMessage(@NotNull Iterable players, @NotNull Component message, - @NotNull ChatPosition position, @Nullable UUID uuid) { - final Set sentTo = new HashSet<>(); - - for (Player player : players) { - if (getChatMessageType(player).accepts(position)) { - sentTo.add(player); - } - } - - PacketUtils.sendGroupedPacket(sentTo, new ChatMessagePacket(message, position, uuid)); - return sentTo; + public static void sendMessage(@NotNull Collection players, @NotNull Component message, + @NotNull ChatPosition position, @Nullable UUID uuid) { + PacketUtils.sendGroupedPacket(players, new ChatMessagePacket(message, position, uuid), + player -> getChatMessageType(player).accepts(position)); } /** @@ -76,21 +63,6 @@ public class Messenger { return getChatMessageType(player) == ChatMessageType.FULL; } - /** - * Performs an action if the server can receive messages from a player. - * This method will send the rejection message automatically. - * - * @param player the player - * @param action the action - */ - public static void receiveMessage(@NotNull Player player, @NotNull Action action) { - if (canReceiveMessage(player)) { - action.act(); - } else { - sendRejectionMessage(player); - } - } - /** * Checks if the server should receive commands from a player, given their chat settings. * @@ -101,21 +73,6 @@ public class Messenger { return getChatMessageType(player) != ChatMessageType.NONE; } - /** - * Performs an action if the server can receive commands from a player. - * This method will send the rejection message automatically. - * - * @param player the player - * @param action the action - */ - public static void receiveCommand(@NotNull Player player, @NotNull Action action) { - if (canReceiveCommand(player)) { - action.act(); - } else { - sendRejectionMessage(player); - } - } - /** * Sends a message to the player informing them we are rejecting their message or command. * diff --git a/src/main/java/net/minestom/server/utils/Action.java b/src/main/java/net/minestom/server/utils/Action.java deleted file mode 100644 index e2fda399b..000000000 --- a/src/main/java/net/minestom/server/utils/Action.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.minestom.server.utils; - -/** - * A functional interface to perform an action. - */ -@FunctionalInterface -public interface Action { - /** - * An empty action. - */ - Action EMPTY = () -> {}; - - /** - * Performs the action. - */ - void act(); -} From 931806d40a255666578bb28230ff044f03e32b7d Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Mon, 17 May 2021 14:48:44 +0100 Subject: [PATCH 40/66] Send rejection message on incorrect command execution --- .../java/net/minestom/server/listener/ChatMessageListener.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/net/minestom/server/listener/ChatMessageListener.java b/src/main/java/net/minestom/server/listener/ChatMessageListener.java index 0bd9cbe23..cc1f491df 100644 --- a/src/main/java/net/minestom/server/listener/ChatMessageListener.java +++ b/src/main/java/net/minestom/server/listener/ChatMessageListener.java @@ -31,6 +31,8 @@ public class ChatMessageListener { // check if we can receive commands if (Messenger.canReceiveCommand(player)) { COMMAND_MANAGER.execute(player, command); + } else { + Messenger.sendRejectionMessage(player); } // Do not call chat event From 354b4e3bc322d4486ab8ca2f857f05e141631e46 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 17:46:56 +0200 Subject: [PATCH 41/66] Replace ItemTag --- .../net/minestom/server/item/ItemMeta.java | 20 +++- .../minestom/server/item/ItemMetaBuilder.java | 17 +-- .../net/minestom/server/item/ItemTag.java | 107 +++++------------- .../java/net/minestom/server/tag/Tag.java | 6 +- 4 files changed, 60 insertions(+), 90 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 04d0023ba..2f1b4657e 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -4,6 +4,8 @@ import io.netty.buffer.ByteBuf; import net.kyori.adventure.text.Component; import net.minestom.server.instance.block.Block; import net.minestom.server.item.attribute.ItemAttribute; +import net.minestom.server.tag.Tag; +import net.minestom.server.tag.TagReader; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.Writeable; import org.jetbrains.annotations.Contract; @@ -14,7 +16,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.*; import java.util.function.Consumer; -public class ItemMeta implements Writeable { +public class ItemMeta implements TagReader, Writeable { private final int damage; private final boolean unbreakable; @@ -110,7 +112,7 @@ public class ItemMeta implements Writeable { } @Contract(pure = true) - public T getOrDefault(@NotNull ItemTag tag, @Nullable T defaultValue) { + public T getOrDefault(@NotNull Tag tag, @Nullable T defaultValue) { var key = tag.getKey(); if (nbt.containsKey(key)) { return tag.read(toNBT()); @@ -119,8 +121,18 @@ public class ItemMeta implements Writeable { } } - public @Nullable T get(@NotNull ItemTag tag) { - return tag.read(toNBT()); + @Override + public @Nullable T getTag(@NotNull Tag tag) { + return tag.read(nbt); + } + + @Override + public boolean hasTag(@NotNull Tag tag) { + return nbt.containsKey(tag.getKey()); + } + + public @Nullable T get(@NotNull Tag tag) { + return getTag(tag); } public @NotNull NBTCompound toNBT() { diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 58b23f92e..351a413db 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -5,6 +5,8 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minestom.server.adventure.AdventureSerializer; import net.minestom.server.instance.block.Block; import net.minestom.server.item.attribute.ItemAttribute; +import net.minestom.server.tag.Tag; +import net.minestom.server.tag.TagWriter; import net.minestom.server.utils.NBTUtils; import net.minestom.server.utils.Utils; import org.jetbrains.annotations.Contract; @@ -16,7 +18,7 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; -public abstract class ItemMetaBuilder { +public abstract class ItemMetaBuilder implements TagWriter { protected NBTCompound nbt = new NBTCompound(); @@ -183,12 +185,13 @@ public abstract class ItemMetaBuilder { return canDestroy(Set.of(blocks)); } - public @NotNull ItemMetaBuilder set(@NotNull ItemTag tag, @Nullable T value) { - if (value != null) { - tag.write(nbt, value); - } else { - this.nbt.removeTag(tag.getKey()); - } + @Override + public void setTag(@NotNull Tag tag, @Nullable T value) { + tag.write(nbt, value); + } + + public @NotNull ItemMetaBuilder set(@NotNull Tag tag, @Nullable T value) { + setTag(tag, value); return this; } diff --git a/src/main/java/net/minestom/server/item/ItemTag.java b/src/main/java/net/minestom/server/item/ItemTag.java index 6f0c02a65..70ad3b527 100644 --- a/src/main/java/net/minestom/server/item/ItemTag.java +++ b/src/main/java/net/minestom/server/item/ItemTag.java @@ -1,112 +1,65 @@ package net.minestom.server.item; +import net.minestom.server.tag.Tag; import org.jetbrains.annotations.NotNull; import org.jglrxavpok.hephaistos.nbt.NBT; import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTList; import java.util.function.BiConsumer; import java.util.function.Function; -public class ItemTag { +/** + * @deprecated use {@link Tag}. + */ +@Deprecated +public class ItemTag extends Tag { - private final String key; - private final Function readFunction; - private final BiConsumer writeConsumer; - - private ItemTag(@NotNull String key, - @NotNull Function readFunction, - @NotNull BiConsumer writeConsumer) { - this.key = key; - this.readFunction = readFunction; - this.writeConsumer = writeConsumer; + protected ItemTag(@NotNull String key, @NotNull Function readFunction, @NotNull BiConsumer writeConsumer) { + super(key, readFunction, writeConsumer); } - public @NotNull String getKey() { - return key; + public static @NotNull Tag Byte(@NotNull String key) { + return Tag.Byte(key); } - protected T read(@NotNull NBTCompound nbtCompound) { - return readFunction.apply(nbtCompound); + public static @NotNull Tag Short(@NotNull String key) { + return Tag.Short(key); } - protected void write(@NotNull NBTCompound nbtCompound, @NotNull T value) { - this.writeConsumer.accept(nbtCompound, value); + public static @NotNull Tag Integer(@NotNull String key) { + return Tag.Integer(key); } - public static @NotNull ItemTag Byte(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getByte(key), - (nbtCompound, value) -> nbtCompound.setByte(key, value)); + public static @NotNull Tag Long(@NotNull String key) { + return Tag.Long(key); } - public static @NotNull ItemTag Short(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getShort(key), - (nbtCompound, value) -> nbtCompound.setShort(key, value)); + public static @NotNull Tag Float(@NotNull String key) { + return Tag.Float(key); } - public static @NotNull ItemTag Integer(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getInt(key), - (nbtCompound, integer) -> nbtCompound.setInt(key, integer)); + public static @NotNull Tag Double(@NotNull String key) { + return Tag.Double(key); } - public static @NotNull ItemTag Long(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getLong(key), - (nbtCompound, value) -> nbtCompound.setLong(key, value)); + public static @NotNull Tag ByteArray(@NotNull String key) { + return Tag.ByteArray(key); } - public static @NotNull ItemTag Float(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getFloat(key), - (nbtCompound, value) -> nbtCompound.setFloat(key, value)); + public static @NotNull Tag String(@NotNull String key) { + return Tag.String(key); } - public static @NotNull ItemTag Double(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getDouble(key), - (nbtCompound, value) -> nbtCompound.setDouble(key, value)); + public static @NotNull Tag NBT(@NotNull String key) { + return Tag.NBT(key); } - public static @NotNull ItemTag ByteArray(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getByteArray(key), - (nbtCompound, value) -> nbtCompound.setByteArray(key, value)); + public static @NotNull Tag IntArray(@NotNull String key) { + return Tag.IntArray(key); } - public static @NotNull ItemTag String(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getString(key), - (nbtCompound, value) -> nbtCompound.setString(key, value)); - } - - public static @NotNull ItemTag NBT(@NotNull String key) { - return new ItemTag<>(key, - nbt -> { - var currentNBT = nbt.get(key); - - // Avoid a NPE when cloning a null variable. - if (currentNBT == null) { - return null; - } - - return currentNBT.deepClone(); - }, - ((nbt, value) -> nbt.set(key, value.deepClone()))); - } - - public static @NotNull ItemTag IntArray(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getIntArray(key), - (nbtCompound, value) -> nbtCompound.setIntArray(key, value)); - } - - public static @NotNull ItemTag LongArray(@NotNull String key) { - return new ItemTag<>(key, - nbtCompound -> nbtCompound.getLongArray(key), - (nbtCompound, value) -> nbtCompound.setLongArray(key, value)); + public static @NotNull Tag LongArray(@NotNull String key) { + return Tag.LongArray(key); } } diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index d1f546709..797413253 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -1,5 +1,6 @@ package net.minestom.server.tag; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBT; @@ -16,14 +17,15 @@ import java.util.function.Supplier; * * @param the tag type */ -public final class Tag { +@ApiStatus.NonExtendable +public class Tag { private final String key; private final Function readFunction; private final BiConsumer writeConsumer; private volatile Supplier defaultValue; - private Tag(@NotNull String key, + protected Tag(@NotNull String key, @NotNull Function readFunction, @NotNull BiConsumer writeConsumer) { this.key = key; From 418fc8b4beeb4b08037879d19ae5bf8b3c7922ac Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 17:50:05 +0200 Subject: [PATCH 42/66] Deprecate old tag getters in ItemMeta --- .../net/minestom/server/item/ItemMeta.java | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 2f1b4657e..bf8acec03 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -15,6 +15,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.*; import java.util.function.Consumer; +import java.util.function.Supplier; public class ItemMeta implements TagReader, Writeable { @@ -111,16 +112,6 @@ public class ItemMeta implements TagReader, Writeable { return Collections.unmodifiableSet(canPlaceOn); } - @Contract(pure = true) - public T getOrDefault(@NotNull Tag tag, @Nullable T defaultValue) { - var key = tag.getKey(); - if (nbt.containsKey(key)) { - return tag.read(toNBT()); - } else { - return defaultValue; - } - } - @Override public @Nullable T getTag(@NotNull Tag tag) { return tag.read(nbt); @@ -131,10 +122,6 @@ public class ItemMeta implements TagReader, Writeable { return nbt.containsKey(tag.getKey()); } - public @Nullable T get(@NotNull Tag tag) { - return getTag(tag); - } - public @NotNull NBTCompound toNBT() { return nbt.deepClone(); } @@ -175,4 +162,26 @@ public class ItemMeta implements TagReader, Writeable { writer.write(cachedBuffer); this.cachedBuffer.resetReaderIndex(); } + + /** + * @deprecated use {@link #getTag(Tag)} with {@link Tag#defaultValue(Supplier)} + */ + @Deprecated + @Contract(pure = true) + public T getOrDefault(@NotNull Tag tag, @Nullable T defaultValue) { + var key = tag.getKey(); + if (nbt.containsKey(key)) { + return tag.read(toNBT()); + } else { + return defaultValue; + } + } + + /** + * @deprecated use {@link #getTag(Tag)} + */ + @Deprecated + public @Nullable T get(@NotNull Tag tag) { + return getTag(tag); + } } From 7e5940d1a5497f1cdc40297f67255aecfc4dcbd2 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 18:26:38 +0200 Subject: [PATCH 43/66] Rename TagReadable & TagWritable --- src/main/java/net/minestom/server/item/ItemMeta.java | 4 ++-- .../java/net/minestom/server/item/ItemMetaBuilder.java | 4 ++-- src/main/java/net/minestom/server/tag/Tag.java | 4 ++-- src/main/java/net/minestom/server/tag/TagHandler.java | 2 +- .../server/tag/{TagReader.java => TagReadable.java} | 8 ++++---- src/main/java/net/minestom/server/tag/TagSerializer.java | 8 ++++---- .../server/tag/{TagWriter.java => TagWritable.java} | 8 ++++---- 7 files changed, 19 insertions(+), 19 deletions(-) rename src/main/java/net/minestom/server/tag/{TagReader.java => TagReadable.java} (83%) rename src/main/java/net/minestom/server/tag/{TagWriter.java => TagWritable.java} (78%) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index bf8acec03..2128a180a 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -5,7 +5,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.instance.block.Block; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.tag.Tag; -import net.minestom.server.tag.TagReader; +import net.minestom.server.tag.TagReadable; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.Writeable; import org.jetbrains.annotations.Contract; @@ -17,7 +17,7 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; -public class ItemMeta implements TagReader, Writeable { +public class ItemMeta implements TagReadable, Writeable { private final int damage; private final boolean unbreakable; diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 351a413db..c0d8f9529 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -6,7 +6,7 @@ import net.minestom.server.adventure.AdventureSerializer; import net.minestom.server.instance.block.Block; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.tag.Tag; -import net.minestom.server.tag.TagWriter; +import net.minestom.server.tag.TagWritable; import net.minestom.server.utils.NBTUtils; import net.minestom.server.utils.Utils; import org.jetbrains.annotations.Contract; @@ -18,7 +18,7 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; -public abstract class ItemMetaBuilder implements TagWriter { +public abstract class ItemMetaBuilder implements TagWritable { protected NBTCompound nbt = new NBTCompound(); diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 797413253..c60dfbf73 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -141,7 +141,7 @@ public class Tag { public static @NotNull Tag Custom(@NotNull String key, @NotNull TagSerializer serializer) { return new Tag<>(key, - nbtCompound -> serializer.read(TagReader.fromCompound(nbtCompound)), - (nbtCompound, value) -> serializer.write(TagWriter.fromCompound(nbtCompound), value)); + nbtCompound -> serializer.read(TagReadable.fromCompound(nbtCompound)), + (nbtCompound, value) -> serializer.write(TagWritable.fromCompound(nbtCompound), value)); } } diff --git a/src/main/java/net/minestom/server/tag/TagHandler.java b/src/main/java/net/minestom/server/tag/TagHandler.java index c5b9632cf..c758ef0ae 100644 --- a/src/main/java/net/minestom/server/tag/TagHandler.java +++ b/src/main/java/net/minestom/server/tag/TagHandler.java @@ -3,5 +3,5 @@ package net.minestom.server.tag; /** * Represents an element which can read and write {@link Tag tags}. */ -public interface TagHandler extends TagReader, TagWriter { +public interface TagHandler extends TagReadable, TagWritable { } diff --git a/src/main/java/net/minestom/server/tag/TagReader.java b/src/main/java/net/minestom/server/tag/TagReadable.java similarity index 83% rename from src/main/java/net/minestom/server/tag/TagReader.java rename to src/main/java/net/minestom/server/tag/TagReadable.java index 79338c0df..18deb2f02 100644 --- a/src/main/java/net/minestom/server/tag/TagReader.java +++ b/src/main/java/net/minestom/server/tag/TagReadable.java @@ -7,7 +7,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound; /** * Represents an element which can read {@link Tag tags}. */ -public interface TagReader { +public interface TagReadable { /** * Reads the specified tag. @@ -30,10 +30,10 @@ public interface TagReader { * Converts an nbt compound to a tag reader. * * @param compound the compound to convert - * @return a {@link TagReader} capable of reading {@code compound} + * @return a {@link TagReadable} capable of reading {@code compound} */ - static @NotNull TagReader fromCompound(@NotNull NBTCompound compound) { - return new TagReader() { + static @NotNull TagReadable fromCompound(@NotNull NBTCompound compound) { + return new TagReadable() { @Override public @Nullable T getTag(@NotNull Tag tag) { return tag.read(compound); diff --git a/src/main/java/net/minestom/server/tag/TagSerializer.java b/src/main/java/net/minestom/server/tag/TagSerializer.java index 151d1de0e..03318bfdf 100644 --- a/src/main/java/net/minestom/server/tag/TagSerializer.java +++ b/src/main/java/net/minestom/server/tag/TagSerializer.java @@ -11,18 +11,18 @@ import org.jetbrains.annotations.Nullable; public interface TagSerializer { /** - * Reads the custom tag from a {@link TagReader}. + * Reads the custom tag from a {@link TagReadable}. * * @param reader the reader * @return the deserialized value */ - @Nullable T read(@NotNull TagReader reader); + @Nullable T read(@NotNull TagReadable reader); /** - * Writes the custom tag to a {@link TagWriter}. + * Writes the custom tag to a {@link TagWritable}. * * @param writer the writer * @param value the value to serialize */ - void write(@NotNull TagWriter writer, @NotNull T value); + void write(@NotNull TagWritable writer, @NotNull T value); } diff --git a/src/main/java/net/minestom/server/tag/TagWriter.java b/src/main/java/net/minestom/server/tag/TagWritable.java similarity index 78% rename from src/main/java/net/minestom/server/tag/TagWriter.java rename to src/main/java/net/minestom/server/tag/TagWritable.java index 8b85d5151..fe0c2962b 100644 --- a/src/main/java/net/minestom/server/tag/TagWriter.java +++ b/src/main/java/net/minestom/server/tag/TagWritable.java @@ -7,7 +7,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound; /** * Represents an element which can write {@link Tag tags}. */ -public interface TagWriter { +public interface TagWritable { /** * Writes the specified type. @@ -22,10 +22,10 @@ public interface TagWriter { * Converts an nbt compound to a tag writer. * * @param compound the compound to convert - * @return a {@link TagWriter} capable of writing {@code compound} + * @return a {@link TagWritable} capable of writing {@code compound} */ - static @NotNull TagWriter fromCompound(@NotNull NBTCompound compound) { - return new TagWriter() { + static @NotNull TagWritable fromCompound(@NotNull NBTCompound compound) { + return new TagWritable() { @Override public void setTag(@NotNull Tag tag, @Nullable T value) { tag.write(compound, value); From 107e1e3e19653d6cffe7909cfd6a9192e1b61387 Mon Sep 17 00:00:00 2001 From: R0bbyYT Date: Mon, 17 May 2021 19:15:34 +0200 Subject: [PATCH 44/66] Avoid server crash if the character is a metacharacter --- .../net/minestom/server/listener/TabCompleteListener.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/listener/TabCompleteListener.java b/src/main/java/net/minestom/server/listener/TabCompleteListener.java index de2869527..c3a9b34f8 100644 --- a/src/main/java/net/minestom/server/listener/TabCompleteListener.java +++ b/src/main/java/net/minestom/server/listener/TabCompleteListener.java @@ -14,6 +14,7 @@ import net.minestom.server.network.packet.server.play.TabCompletePacket; import net.minestom.server.utils.StringUtils; import java.util.Arrays; +import java.util.regex.PatternSyntaxException; public class TabCompleteListener { @@ -23,8 +24,13 @@ public class TabCompleteListener { String commandString = packet.text.replaceFirst(CommandManager.COMMAND_PREFIX, ""); String[] split = commandString.split(StringUtils.SPACE); String commandName = split[0]; + String args; - String args = commandString.replaceFirst(commandName, ""); + try { + args = commandString.replaceFirst(commandName, ""); + } catch (PatternSyntaxException exception) { + args = commandName.replaceFirst(String.format("\\%s", commandName), ""); + } final CommandQueryResult commandQueryResult = CommandParser.findCommand(commandString); if (commandQueryResult == null) { From 17ce859bdd513dac49b21e3a4ad7ebb5e8a81ff3 Mon Sep 17 00:00:00 2001 From: R0bbyYT Date: Mon, 17 May 2021 20:40:29 +0200 Subject: [PATCH 45/66] Use Pattern#quote instead of `\\` --- .../minestom/server/listener/TabCompleteListener.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/minestom/server/listener/TabCompleteListener.java b/src/main/java/net/minestom/server/listener/TabCompleteListener.java index c3a9b34f8..462978a50 100644 --- a/src/main/java/net/minestom/server/listener/TabCompleteListener.java +++ b/src/main/java/net/minestom/server/listener/TabCompleteListener.java @@ -14,7 +14,7 @@ import net.minestom.server.network.packet.server.play.TabCompletePacket; import net.minestom.server.utils.StringUtils; import java.util.Arrays; -import java.util.regex.PatternSyntaxException; +import java.util.regex.Pattern; public class TabCompleteListener { @@ -24,13 +24,7 @@ public class TabCompleteListener { String commandString = packet.text.replaceFirst(CommandManager.COMMAND_PREFIX, ""); String[] split = commandString.split(StringUtils.SPACE); String commandName = split[0]; - String args; - - try { - args = commandString.replaceFirst(commandName, ""); - } catch (PatternSyntaxException exception) { - args = commandName.replaceFirst(String.format("\\%s", commandName), ""); - } + String args = commandString.replaceFirst(Pattern.quote(commandName), ""); final CommandQueryResult commandQueryResult = CommandParser.findCommand(commandString); if (commandQueryResult == null) { From 0c71030221a40590fd7c61439c7a15acfa12ebbc Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 20:58:36 +0200 Subject: [PATCH 46/66] Do not crash the server when receiving an invalid packet --- .../server/listener/manager/PacketListenerManager.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java index 6471b4f0e..72f944ca0 100644 --- a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java +++ b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java @@ -84,7 +84,12 @@ public final class PacketListenerManager { // Finally execute the listener if (packetListenerConsumer != null) { - packetListenerConsumer.accept(packet, player); + try { + packetListenerConsumer.accept(packet, player); + } catch (Exception e) { + // Packet is likely invalid + MinecraftServer.getExceptionManager().handleException(e); + } } } From 1f30e2af7785cd7acbd2fffd52fe340cba4028ee Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 17 May 2021 21:11:52 +0200 Subject: [PATCH 47/66] TagHandler in beta until a proper name is decided --- src/main/java/net/minestom/server/tag/TagHandler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/net/minestom/server/tag/TagHandler.java b/src/main/java/net/minestom/server/tag/TagHandler.java index c758ef0ae..b53db14a1 100644 --- a/src/main/java/net/minestom/server/tag/TagHandler.java +++ b/src/main/java/net/minestom/server/tag/TagHandler.java @@ -1,7 +1,10 @@ package net.minestom.server.tag; +import com.google.common.annotations.Beta; + /** * Represents an element which can read and write {@link Tag tags}. */ +@Beta public interface TagHandler extends TagReadable, TagWritable { } From 67494255b5832a9696c668f1ae8637e738ed01a7 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 18 May 2021 15:09:03 +0200 Subject: [PATCH 48/66] Count non air blocks in a section. --- .../server/instance/palette/Section.java | 24 +++++++++++++++++++ .../java/net/minestom/server/utils/Utils.java | 9 ++----- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/minestom/server/instance/palette/Section.java b/src/main/java/net/minestom/server/instance/palette/Section.java index b95ae63c7..392a17879 100644 --- a/src/main/java/net/minestom/server/instance/palette/Section.java +++ b/src/main/java/net/minestom/server/instance/palette/Section.java @@ -53,6 +53,8 @@ public class Section implements PublicCloneable

    { private int valuesPerLong; private boolean hasPalette; + private short blockCount = 0; + protected Section(int bitsPerEntry, int bitsIncrement) { this.bitsPerEntry = bitsPerEntry; this.bitsIncrement = bitsIncrement; @@ -74,6 +76,9 @@ public class Section implements PublicCloneable
    { blocks = new long[getSize(valuesPerLong)]; } + // Check if the new block is air, used for counting none air blocks. + final boolean isAir = Block.fromStateId(blockId).isAir(); + // Change to palette value blockId = getPaletteIndex(blockId); @@ -91,6 +96,13 @@ public class Section implements PublicCloneable
    { block ^= clear << bitIndex; block |= (long) blockId << bitIndex; + boolean isCurrentAir = Block.fromStateId(getBlockAt(x, y, z)).isAir(); + if (!isCurrentAir && isAir) { // The old block isn't air & the new block is. + this.blockCount--; + } else if (isCurrentAir && !isAir) { // The old block is air & the new block isn't. + this.blockCount++; + } // If both block are air or not air then don't change the value. + blocks[index] = block; } } @@ -143,6 +155,7 @@ public class Section implements PublicCloneable
    { this.hasPalette = section.hasPalette; this.blocks = section.blocks; + this.blockCount = section.blockCount; } /** @@ -171,12 +184,22 @@ public class Section implements PublicCloneable
    { this.blocks = new long[0]; this.paletteBlockMap = createPaletteBlockMap(); this.blockPaletteMap = createBlockPaletteMap(); + this.blockCount = 0; } public long[] getBlocks() { return blocks; } + /** + * Get the amount of non air blocks in this section. + * + * @return The amount of blocks in this section. + */ + public short getBlockCount() { + return blockCount; + } + public Short2ShortLinkedOpenHashMap getPaletteBlockMap() { return paletteBlockMap; } @@ -288,6 +311,7 @@ public class Section implements PublicCloneable
    { section.blocks = blocks.clone(); section.paletteBlockMap = paletteBlockMap.clone(); section.blockPaletteMap = blockPaletteMap.clone(); + section.blockCount = blockCount; return section; } catch (CloneNotSupportedException e) { MinecraftServer.getExceptionManager().handleException(e); diff --git a/src/main/java/net/minestom/server/utils/Utils.java b/src/main/java/net/minestom/server/utils/Utils.java index a32c1470d..ac694e669 100644 --- a/src/main/java/net/minestom/server/utils/Utils.java +++ b/src/main/java/net/minestom/server/utils/Utils.java @@ -118,16 +118,11 @@ public final class Utils { } public static void writeSectionBlocks(ByteBuf buffer, Section section) { - /*short count = 0; - for (short id : blocksId) - if (id != 0) - count++;*/ + final short blockCount = section.getBlockCount(); final int bitsPerEntry = section.getBitsPerEntry(); - //buffer.writeShort(count); - // TODO count blocks - buffer.writeShort(200); + buffer.writeShort(blockCount); buffer.writeByte((byte) bitsPerEntry); // Palette From c9d0dc62f65a6d55427429d7cc2051e263818cec Mon Sep 17 00:00:00 2001 From: Cp1987 Date: Tue, 18 May 2021 15:12:48 +0200 Subject: [PATCH 49/66] Make isCurrentAir final. --- src/main/java/net/minestom/server/instance/palette/Section.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/instance/palette/Section.java b/src/main/java/net/minestom/server/instance/palette/Section.java index 392a17879..0dde805a2 100644 --- a/src/main/java/net/minestom/server/instance/palette/Section.java +++ b/src/main/java/net/minestom/server/instance/palette/Section.java @@ -96,7 +96,7 @@ public class Section implements PublicCloneable
    { block ^= clear << bitIndex; block |= (long) blockId << bitIndex; - boolean isCurrentAir = Block.fromStateId(getBlockAt(x, y, z)).isAir(); + final boolean isCurrentAir = Block.fromStateId(getBlockAt(x, y, z)).isAir(); if (!isCurrentAir && isAir) { // The old block isn't air & the new block is. this.blockCount--; } else if (isCurrentAir && !isAir) { // The old block is air & the new block isn't. From cc97062dfaeae59b7e13c5badd7796a6c2d1ff32 Mon Sep 17 00:00:00 2001 From: TheMode Date: Tue, 18 May 2021 16:18:51 +0200 Subject: [PATCH 50/66] Remove soft values --- .../java/net/minestom/server/utils/cache/TemporaryCache.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/net/minestom/server/utils/cache/TemporaryCache.java b/src/main/java/net/minestom/server/utils/cache/TemporaryCache.java index e14a34d84..da2e64a23 100644 --- a/src/main/java/net/minestom/server/utils/cache/TemporaryCache.java +++ b/src/main/java/net/minestom/server/utils/cache/TemporaryCache.java @@ -26,7 +26,6 @@ public class TemporaryCache { public TemporaryCache(long duration, TimeUnit timeUnit, RemovalListener removalListener) { this.cache = CacheBuilder.newBuilder() .expireAfterWrite(duration, timeUnit) - .softValues() .removalListener(removalListener) .build(); } From 8a2845b91dd371265387c9810c086563fbcfa1b4 Mon Sep 17 00:00:00 2001 From: JesFot Date: Tue, 18 May 2021 14:06:28 +0200 Subject: [PATCH 51/66] Update github workflow to decide which files to clear --- .github/workflows/javadoc.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml index d3b71f032..0f9012ddb 100644 --- a/.github/workflows/javadoc.yml +++ b/.github/workflows/javadoc.yml @@ -25,3 +25,4 @@ jobs: BRANCH: javadoc FOLDER: docs GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CLEAR_GLOBS_FILE: ".github/javadoc-publish-clear" From 25a8f5a0cb040b14823e5bc91d353b615f754aaf Mon Sep 17 00:00:00 2001 From: JesFot Date: Tue, 18 May 2021 14:07:45 +0200 Subject: [PATCH 52/66] Add old javadoc removal selector --- .github/javadoc-publish-clear | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/javadoc-publish-clear diff --git a/.github/javadoc-publish-clear b/.github/javadoc-publish-clear new file mode 100644 index 000000000..b090753c1 --- /dev/null +++ b/.github/javadoc-publish-clear @@ -0,0 +1,2 @@ +**/* +!CNAME From b49fb9cacf0581a364ba1806fe37ce2dfd229a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=ABsFot?= Date: Tue, 18 May 2021 21:34:25 +0200 Subject: [PATCH 53/66] Upgrade gradle version to 7.0.2 --- build.gradle | 12 +++++++----- gradle/wrapper/gradle-wrapper.properties | 2 +- minestom_checks.xml | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 3ce127ef8..2b26a2602 100644 --- a/build.gradle +++ b/build.gradle @@ -2,9 +2,7 @@ import org.gradle.internal.os.OperatingSystem plugins { id 'java-library' - id 'java' id 'maven-publish' - id 'net.ltgt.apt' version '0.10' id 'org.jetbrains.kotlin.jvm' version '1.5.0' id 'checkstyle' } @@ -12,7 +10,7 @@ plugins { group 'net.minestom.server' version '1.0' -sourceCompatibility = 1.11 +sourceCompatibility = 11 project.ext.lwjglVersion = "3.2.3" switch (OperatingSystem.current()) { @@ -53,7 +51,7 @@ allprojects { // see https://stackoverflow.com/a/56641766 doLast { // Append the fix to the file - def searchScript = new File(destinationDir.getAbsolutePath() + '/search.js') + def searchScript = new File(destinationDir, '/search.js') searchScript.append '\n\n' + 'getURLPrefix = function(ui) {\n' + ' return \'\';\n' + @@ -62,7 +60,7 @@ allprojects { } checkstyle { - toolVersion "8.37" + toolVersion "8.42" configFile file("${projectDir}/minestom_checks.xml") } } @@ -114,6 +112,10 @@ test { useJUnitPlatform() } +tasks.withType(Zip).configureEach { + duplicatesStrategy DuplicatesStrategy.EXCLUDE +} + dependencies { // Junit Testing Framework testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 28ff446a2..0f80bbf51 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/minestom_checks.xml b/minestom_checks.xml index eb513ae72..082918382 100644 --- a/minestom_checks.xml +++ b/minestom_checks.xml @@ -277,7 +277,7 @@ value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/> - + From 7ed83e7b75a8c3514d44f2b403819bfdd057856c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=ABsFot?= Date: Tue, 18 May 2021 21:40:49 +0200 Subject: [PATCH 54/66] Upgrade checkstyle version to match gradle --- .github/workflows/check-pr-style.yml | 6 +++--- .github/workflows/javadoc.yml | 2 +- .github/workflows/tests.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/check-pr-style.yml b/.github/workflows/check-pr-style.yml index 7ac69d24b..2efc6f6b2 100644 --- a/.github/workflows/check-pr-style.yml +++ b/.github/workflows/check-pr-style.yml @@ -14,9 +14,9 @@ jobs: - name: Set up JDK 11 uses: actions/setup-java@v1 with: - java-version: 1.11 + java-version: 11 - name: Run java checkstyle - uses: nikitasavinov/checkstyle-action@d87d526a914fc5cb0b003908e35038dbb2d6e1b7 + uses: nikitasavinov/checkstyle-action@0.3.1 with: # Report level for reviewdog [info,warning,error] level: info @@ -28,4 +28,4 @@ jobs: fail_on_error: false # Checkstyle config file checkstyle_config: minestom_checks.xml - checkstyle_version: "8.37" + checkstyle_version: "8.42" diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml index d3b71f032..b43d2298c 100644 --- a/.github/workflows/javadoc.yml +++ b/.github/workflows/javadoc.yml @@ -14,7 +14,7 @@ jobs: - name: Set up JDK 11 uses: actions/setup-java@v1 with: - java-version: 1.11 + java-version: 11 - name: Build javadoc run: gradle javadoc diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c6d8bda7c..176c7e3cb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: - name: Set up JDK 11 uses: actions/setup-java@v1 with: - java-version: 1.11 + java-version: 11 - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Setup gradle cache From d7b37c7c7009ee900b1ef4a80ee4a90f900433f1 Mon Sep 17 00:00:00 2001 From: TheMode Date: Wed, 19 May 2021 12:28:42 +0200 Subject: [PATCH 55/66] Update javadoc-publish-clear --- .github/javadoc-publish-clear | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/javadoc-publish-clear b/.github/javadoc-publish-clear index b090753c1..1a5d6285a 100644 --- a/.github/javadoc-publish-clear +++ b/.github/javadoc-publish-clear @@ -1,2 +1,3 @@ **/* +!.git !CNAME From ef51a3765bb0d8c724525024367ace125a24c312 Mon Sep 17 00:00:00 2001 From: Anders Date: Wed, 19 May 2021 13:42:57 +0200 Subject: [PATCH 56/66] Use the block value to find the current block --- .../java/net/minestom/server/instance/palette/Section.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/instance/palette/Section.java b/src/main/java/net/minestom/server/instance/palette/Section.java index 0dde805a2..1976b930f 100644 --- a/src/main/java/net/minestom/server/instance/palette/Section.java +++ b/src/main/java/net/minestom/server/instance/palette/Section.java @@ -92,11 +92,14 @@ public class Section implements PublicCloneable
    { { final long clear = MAGIC_MASKS[bitsPerEntry]; + final long value = block >> bitIndex & clear; + final boolean isCurrentAir = Block.fromStateId( + hasPalette ? paletteBlockMap.get((short) value) : (short) value).isAir(); + block |= clear << bitIndex; block ^= clear << bitIndex; block |= (long) blockId << bitIndex; - final boolean isCurrentAir = Block.fromStateId(getBlockAt(x, y, z)).isAir(); if (!isCurrentAir && isAir) { // The old block isn't air & the new block is. this.blockCount--; } else if (isCurrentAir && !isAir) { // The old block is air & the new block isn't. From 51409705e1cbf066e0059e9c3cdd6ee6c45ab248 Mon Sep 17 00:00:00 2001 From: Matt Worzala Date: Thu, 20 May 2021 22:26:35 -0400 Subject: [PATCH 57/66] Stop using reflection, update to latest --- .../extensions/DiscoveredExtension.java | 12 ++ .../minestom/server/extensions/Extension.java | 124 ++++++++++++++++++ .../server/extensions/ExtensionManager.java | 14 ++ 3 files changed, 150 insertions(+) diff --git a/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java b/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java index 6318e3de7..03a25a774 100644 --- a/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java +++ b/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java @@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.net.URL; +import java.nio.file.Path; import java.util.LinkedList; import java.util.List; @@ -75,6 +76,8 @@ public final class DiscoveredExtension { /** The original jar this is from. */ transient private File originalJar; + transient private Path dataDirectory; + /** The class loader that powers it. */ transient private MinestomExtensionClassLoader minestomExtensionClassLoader; @@ -130,6 +133,15 @@ public final class DiscoveredExtension { return originalJar; } + @NotNull + public Path getDataDirectory() { + return dataDirectory; + } + + public void setDataDirectory(@NotNull Path dataDirectory) { + this.dataDirectory = dataDirectory; + } + MinestomExtensionClassLoader removeMinestomExtensionClassLoader() { MinestomExtensionClassLoader oldClassLoader = getMinestomExtensionClassLoader(); setMinestomExtensionClassLoader(null); diff --git a/src/main/java/net/minestom/server/extensions/Extension.java b/src/main/java/net/minestom/server/extensions/Extension.java index cd9b52028..cd43cfe44 100644 --- a/src/main/java/net/minestom/server/extensions/Extension.java +++ b/src/main/java/net/minestom/server/extensions/Extension.java @@ -1,11 +1,19 @@ package net.minestom.server.extensions; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; +import java.io.IOException; +import java.io.InputStream; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -77,6 +85,122 @@ public abstract class Extension { return logger; } + @NotNull + public Path getDataDirectory() { + return getOrigin().getDataDirectory(); + } + + /** + * Gets a resource from the extension directory, or from inside the jar if it does not + * exist in the extension directory. + *

    + * If it does not exist in the extension directory, it will be copied from inside the jar. + *

    + * The caller is responsible for closing the returned {@link InputStream}. + * + * @param fileName The file to read + * @return The file contents, or null if there was an issue reading the file. + */ + @Nullable + public InputStream getResource(@NotNull String fileName) { + return getResource(Paths.get(fileName)); + } + + /** + * Gets a resource from the extension directory, or from inside the jar if it does not + * exist in the extension directory. + *

    + * If it does not exist in the extension directory, it will be copied from inside the jar. + *

    + * The caller is responsible for closing the returned {@link InputStream}. + * + * @param target The file to read + * @return The file contents, or null if there was an issue reading the file. + */ + @Nullable + public InputStream getResource(@NotNull Path target) { + final Path targetFile = getDataDirectory().resolve(target); + try { + // Copy from jar if the file does not exist in the extension data directory. + if (!Files.exists(targetFile)) { + savePackagedResource(target); + } + + return Files.newInputStream(targetFile); + } catch (IOException ex) { + getLogger().info("Failed to read resource {}.", target, ex); + return null; + } + } + + /** + * Gets a resource from inside the extension jar. + *

    + * The caller is responsible for closing the returned {@link InputStream}. + * + * @param fileName The file to read + * @return The file contents, or null if there was an issue reading the file. + */ + public InputStream getPackagedResource(@NotNull String fileName) { + return getPackagedResource(Paths.get(fileName)); + } + + /** + * Gets a resource from inside the extension jar. + *

    + * The caller is responsible for closing the returned {@link InputStream}. + * + * @param target The file to read + * @return The file contents, or null if there was an issue reading the file. + */ + @Nullable + public InputStream getPackagedResource(@NotNull Path target) { + try { + final URL url = getOrigin().getMinestomExtensionClassLoader().getResource(target.toString()); + if (url == null) { + getLogger().debug("Resource not found: {}", target); + return null; + } + + return url.openConnection().getInputStream(); + } catch (IOException ex) { + getLogger().debug("Failed to load resource {}.", target, ex); + return null; + } + } + + /** + * Copies a resource file to the extension directory, replacing any existing copy. + * + * @param fileName The resource to save + * @return True if the resource was saved successfully, null otherwise + */ + public boolean savePackagedResource(@NotNull String fileName) { + return savePackagedResource(Paths.get(fileName)); + } + + /** + * Copies a resource file to the extension directory, replacing any existing copy. + * + * @param target The resource to save + * @return True if the resource was saved successfully, null otherwise + */ + public boolean savePackagedResource(@NotNull Path target) { + final Path targetFile = getDataDirectory().resolve(target); + try (InputStream is = getPackagedResource(target)) { + if (is == null) { + return false; + } + + Files.createDirectories(targetFile.getParent()); + Files.copy(is, targetFile, StandardCopyOption.REPLACE_EXISTING); + return true; + } catch (IOException ex) { + getLogger().debug("Failed to save resource {}.", target, ex); + return false; + } + } + /** * Adds a new observer to this extension. * Will be kept as a WeakReference. diff --git a/src/main/java/net/minestom/server/extensions/ExtensionManager.java b/src/main/java/net/minestom/server/extensions/ExtensionManager.java index 2de27ece5..b9ad3b0b9 100644 --- a/src/main/java/net/minestom/server/extensions/ExtensionManager.java +++ b/src/main/java/net/minestom/server/extensions/ExtensionManager.java @@ -24,6 +24,8 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; import java.util.zip.ZipFile; @@ -44,6 +46,7 @@ public class ExtensionManager { private final File extensionFolder = new File("extensions"); private final File dependenciesFolder = new File(extensionFolder, ".libs"); + private Path extensionDataRoot = extensionFolder.toPath(); private boolean loaded; // Option @@ -336,6 +339,7 @@ public class ExtensionManager { DiscoveredExtension extension = GSON.fromJson(reader, DiscoveredExtension.class); extension.files.add(new File(extensionClasses).toURI().toURL()); extension.files.add(new File(extensionResources).toURI().toURL()); + extension.setDataDirectory(getExtensionDataRoot().resolve(extension.getName())); // Verify integrity and ensure defaults DiscoveredExtension.verifyIntegrity(extension); @@ -365,6 +369,7 @@ public class ExtensionManager { DiscoveredExtension extension = GSON.fromJson(reader, DiscoveredExtension.class); extension.setOriginalJar(file); extension.files.add(file.toURI().toURL()); + extension.setDataDirectory(getExtensionDataRoot().resolve(extension.getName())); // Verify integrity and ensure defaults DiscoveredExtension.verifyIntegrity(extension); @@ -569,6 +574,15 @@ public class ExtensionManager { return extensionFolder; } + @NotNull + public Path getExtensionDataRoot() { + return extensionDataRoot; + } + + public void setExtensionDataRoot(@NotNull Path dataRoot) { + this.extensionDataRoot = dataRoot; + } + @NotNull public Collection getExtensions() { return immutableExtensions.values(); From a749f07a3f1480a7aee070f2c473c897275ba02f Mon Sep 17 00:00:00 2001 From: Matt Worzala Date: Fri, 21 May 2021 08:56:30 -0400 Subject: [PATCH 58/66] Inline nullable and nonnull annotations --- .../server/extensions/DiscoveredExtension.java | 3 +-- .../net/minestom/server/extensions/Extension.java | 14 +++++--------- .../server/extensions/ExtensionManager.java | 3 +-- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java b/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java index 03a25a774..04f779880 100644 --- a/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java +++ b/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java @@ -133,8 +133,7 @@ public final class DiscoveredExtension { return originalJar; } - @NotNull - public Path getDataDirectory() { + public @NotNull Path getDataDirectory() { return dataDirectory; } diff --git a/src/main/java/net/minestom/server/extensions/Extension.java b/src/main/java/net/minestom/server/extensions/Extension.java index cd43cfe44..1272751cc 100644 --- a/src/main/java/net/minestom/server/extensions/Extension.java +++ b/src/main/java/net/minestom/server/extensions/Extension.java @@ -85,8 +85,7 @@ public abstract class Extension { return logger; } - @NotNull - public Path getDataDirectory() { + public @NotNull Path getDataDirectory() { return getOrigin().getDataDirectory(); } @@ -101,8 +100,7 @@ public abstract class Extension { * @param fileName The file to read * @return The file contents, or null if there was an issue reading the file. */ - @Nullable - public InputStream getResource(@NotNull String fileName) { + public @Nullable InputStream getResource(@NotNull String fileName) { return getResource(Paths.get(fileName)); } @@ -117,8 +115,7 @@ public abstract class Extension { * @param target The file to read * @return The file contents, or null if there was an issue reading the file. */ - @Nullable - public InputStream getResource(@NotNull Path target) { + public @Nullable InputStream getResource(@NotNull Path target) { final Path targetFile = getDataDirectory().resolve(target); try { // Copy from jar if the file does not exist in the extension data directory. @@ -141,7 +138,7 @@ public abstract class Extension { * @param fileName The file to read * @return The file contents, or null if there was an issue reading the file. */ - public InputStream getPackagedResource(@NotNull String fileName) { + public @Nullable InputStream getPackagedResource(@NotNull String fileName) { return getPackagedResource(Paths.get(fileName)); } @@ -153,8 +150,7 @@ public abstract class Extension { * @param target The file to read * @return The file contents, or null if there was an issue reading the file. */ - @Nullable - public InputStream getPackagedResource(@NotNull Path target) { + public @Nullable InputStream getPackagedResource(@NotNull Path target) { try { final URL url = getOrigin().getMinestomExtensionClassLoader().getResource(target.toString()); if (url == null) { diff --git a/src/main/java/net/minestom/server/extensions/ExtensionManager.java b/src/main/java/net/minestom/server/extensions/ExtensionManager.java index b9ad3b0b9..95ca6452e 100644 --- a/src/main/java/net/minestom/server/extensions/ExtensionManager.java +++ b/src/main/java/net/minestom/server/extensions/ExtensionManager.java @@ -574,8 +574,7 @@ public class ExtensionManager { return extensionFolder; } - @NotNull - public Path getExtensionDataRoot() { + public @NotNull Path getExtensionDataRoot() { return extensionDataRoot; } From 60c1b2c4e9a5c11e22e06487e772f0a22b5ad6da Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 28 May 2021 16:19:58 +0200 Subject: [PATCH 59/66] Change Tag#Custom to only affect an external compound, allow tag mapping --- .../java/net/minestom/server/tag/Tag.java | 68 ++++++++++++++++--- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index c60dfbf73..6a31f845f 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -1,6 +1,7 @@ package net.minestom.server.tag; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBT; @@ -23,28 +24,64 @@ public class Tag { private final String key; private final Function readFunction; private final BiConsumer writeConsumer; - private volatile Supplier defaultValue; + + private final Supplier defaultValue; protected Tag(@NotNull String key, - @NotNull Function readFunction, - @NotNull BiConsumer writeConsumer) { + @NotNull Function readFunction, + @NotNull BiConsumer writeConsumer, + @Nullable Supplier defaultValue) { this.key = key; this.readFunction = readFunction; this.writeConsumer = writeConsumer; + this.defaultValue = defaultValue; + } + + protected Tag(@NotNull String key, + @NotNull Function readFunction, + @NotNull BiConsumer writeConsumer) { + this(key, readFunction, writeConsumer, null); } public @NotNull String getKey() { return key; } + @Contract(value = "_ -> new", pure = true) public Tag defaultValue(@NotNull Supplier defaultValue) { - this.defaultValue = defaultValue; - return this; + return new Tag<>(key, readFunction, writeConsumer, defaultValue); } + @Contract(value = "_ -> new", pure = true) public Tag defaultValue(@NotNull T defaultValue) { - defaultValue(() -> defaultValue); - return this; + return new Tag<>(key, readFunction, writeConsumer, () -> defaultValue); + } + + @Contract(value = "_, _ -> new", pure = true) + public Tag map(@NotNull Function readMap, + @NotNull Function writeMap) { + return new Tag(key, + // Read + nbtCompound -> { + final var old = readFunction.apply(nbtCompound); + if (old == null) { + return null; + } + return readMap.apply(old); + }, + // Write + (nbtCompound, r) -> { + var n = writeMap.apply(r); + writeConsumer.accept(nbtCompound, n); + }, + // Default value + () -> { + if (defaultValue == null) { + return null; + } + var old = defaultValue.get(); + return readMap.apply(old); + }); } public @Nullable T read(@NotNull NBTCompound nbtCompound) { @@ -141,7 +178,20 @@ public class Tag { public static @NotNull Tag Custom(@NotNull String key, @NotNull TagSerializer serializer) { return new Tag<>(key, - nbtCompound -> serializer.read(TagReadable.fromCompound(nbtCompound)), - (nbtCompound, value) -> serializer.write(TagWritable.fromCompound(nbtCompound), value)); + nbtCompound -> { + final var compound = nbtCompound.getCompound(key); + if (compound == null) { + return null; + } + return serializer.read(TagReadable.fromCompound(compound)); + }, + (nbtCompound, value) -> { + var compound = nbtCompound.getCompound(key); + if (compound == null) { + compound = new NBTCompound(); + nbtCompound.set(key, compound); + } + serializer.write(TagWritable.fromCompound(compound), value); + }); } } From 9a1062b0284c837e5c517e419424f561d680f7ec Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 28 May 2021 16:21:54 +0200 Subject: [PATCH 60/66] Simplify Tag#defaultValue --- src/main/java/net/minestom/server/tag/Tag.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 6a31f845f..63e054446 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -54,7 +54,7 @@ public class Tag { @Contract(value = "_ -> new", pure = true) public Tag defaultValue(@NotNull T defaultValue) { - return new Tag<>(key, readFunction, writeConsumer, () -> defaultValue); + return defaultValue(() -> defaultValue); } @Contract(value = "_, _ -> new", pure = true) From d4fc6a094a59f145095c8e60041cb93ef1fb2e96 Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 28 May 2021 17:00:48 +0200 Subject: [PATCH 61/66] Make ItemStack TagReadable --- .../java/net/minestom/server/item/ItemStack.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index f1e1b7f7b..6fedeca9a 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -4,6 +4,8 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEventSource; import net.minestom.server.item.rule.VanillaStackingRule; +import net.minestom.server.tag.Tag; +import net.minestom.server.tag.TagReadable; import net.minestom.server.utils.NBTUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -22,7 +24,7 @@ import java.util.function.UnaryOperator; *

    * An item stack cannot be null, {@link ItemStack#AIR} should be used instead. */ -public final class ItemStack implements HoverEventSource { +public final class ItemStack implements TagReadable, HoverEventSource { /** * Constant AIR item. Should be used instead of 'null'. @@ -191,6 +193,16 @@ public final class ItemStack implements HoverEventSource { .stackingRule(stackingRule); } + @Override + public @Nullable T getTag(@NotNull Tag tag) { + return meta.getTag(tag); + } + + @Override + public boolean hasTag(@NotNull Tag tag) { + return meta.hasTag(tag); + } + @Override public @NotNull HoverEvent asHoverEvent(@NotNull UnaryOperator op) { return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.of(this.material, From ffca5eea0099e93f6671a42f217888e1c4c9b3c3 Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 28 May 2021 17:05:14 +0200 Subject: [PATCH 62/66] Added ItemStack#withTag --- src/main/java/net/minestom/server/item/ItemStack.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index 6fedeca9a..b5d6a0a80 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -193,6 +193,11 @@ public final class ItemStack implements TagReadable, HoverEventSource @NotNull ItemStack withTag(@NotNull Tag tag, @Nullable T value) { + return builder().meta(metaBuilder -> metaBuilder.set(tag, value)).build(); + } + @Override public @Nullable T getTag(@NotNull Tag tag) { return meta.getTag(tag); From c080750a884994ba56d0b176d534a088700142bb Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 30 May 2021 16:33:02 +0200 Subject: [PATCH 63/66] Fix trade index in VillagerInventory --- .../net/minestom/server/inventory/type/VillagerInventory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java b/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java index 4812fe9e9..91790d0c5 100644 --- a/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java +++ b/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java @@ -23,7 +23,7 @@ public class VillagerInventory extends Inventory { final int length = oldTrades.length + 1; TradeListPacket.Trade[] trades = new TradeListPacket.Trade[length]; System.arraycopy(oldTrades, 0, trades, 0, oldTrades.length); - trades[length] = trade; + trades[length - 1] = trade; this.tradeListPacket.trades = trades; update(); } From 52d0ef7f535572584e26cad855d7b0220be912ef Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 30 May 2021 16:39:09 +0200 Subject: [PATCH 64/66] Send trade packet for every new viewer --- .../server/inventory/type/VillagerInventory.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java b/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java index 91790d0c5..e7a521376 100644 --- a/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java +++ b/src/main/java/net/minestom/server/inventory/type/VillagerInventory.java @@ -1,9 +1,11 @@ package net.minestom.server.inventory.type; +import net.minestom.server.entity.Player; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.network.packet.server.play.TradeListPacket; import net.minestom.server.utils.ArrayUtils; +import org.jetbrains.annotations.NotNull; public class VillagerInventory extends Inventory { @@ -79,6 +81,15 @@ public class VillagerInventory extends Inventory { sendPacketToViewers(tradeListPacket); // Refresh window } + @Override + public boolean addViewer(@NotNull Player player) { + final boolean result = super.addViewer(player); + if (result) { + player.getPlayerConnection().sendPacket(tradeListPacket); + } + return result; + } + private void setupPacket() { this.tradeListPacket = new TradeListPacket(); this.tradeListPacket.windowId = getWindowId(); From 6764d040c3b88abb131eeb16160366e58b47381f Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 31 May 2021 20:49:33 +0200 Subject: [PATCH 65/66] Fix FakePlayer not being removed from the tablist --- .../server/entity/fakeplayer/FakePlayer.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java index f1b174834..6dc593fd9 100644 --- a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java +++ b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java @@ -124,17 +124,22 @@ public class FakePlayer extends Player implements NavigableEntity { super.setInstance(instance); } + @Override + protected boolean addViewer0(@NotNull Player player) { + final boolean result = super.addViewer0(player); + if (result) { + handleTabList(player.getPlayerConnection()); + } + return result; + } + /** * {@inheritDoc} */ @Override protected void showPlayer(@NotNull PlayerConnection connection) { super.showPlayer(connection); - if (!option.isInTabList()) { - // Remove from tab-list - MinecraftServer.getSchedulerManager().buildTask(() -> connection.sendPacket(getRemovePlayerToList())).delay(20, TimeUnit.TICK).schedule(); - } - + handleTabList(connection); } @NotNull @@ -142,4 +147,11 @@ public class FakePlayer extends Player implements NavigableEntity { public Navigator getNavigator() { return navigator; } + + private void handleTabList(PlayerConnection connection) { + if (!option.isInTabList()) { + // Remove from tab-list + MinecraftServer.getSchedulerManager().buildTask(() -> connection.sendPacket(getRemovePlayerToList())).delay(2, TimeUnit.TICK).schedule(); + } + } } From c105fcc339b3d5805b1cd673ee140c86c1aed227 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 31 May 2021 21:01:28 +0200 Subject: [PATCH 66/66] Wait 20 ticks before removing player from the tablist --- .../java/net/minestom/server/entity/fakeplayer/FakePlayer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java index 6dc593fd9..52acf40c6 100644 --- a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java +++ b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java @@ -151,7 +151,7 @@ public class FakePlayer extends Player implements NavigableEntity { private void handleTabList(PlayerConnection connection) { if (!option.isInTabList()) { // Remove from tab-list - MinecraftServer.getSchedulerManager().buildTask(() -> connection.sendPacket(getRemovePlayerToList())).delay(2, TimeUnit.TICK).schedule(); + MinecraftServer.getSchedulerManager().buildTask(() -> connection.sendPacket(getRemovePlayerToList())).delay(20, TimeUnit.TICK).schedule(); } } }