diff --git a/.github/workflows/main-build.yml b/.github/workflows/main-build.yml index acf57a5f..4dbbcebc 100644 --- a/.github/workflows/main-build.yml +++ b/.github/workflows/main-build.yml @@ -20,7 +20,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v6 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v5 + uses: gradle/actions/wrapper-validation@v6 - name: Setup Java uses: actions/setup-java@v5 with: diff --git a/build.gradle.kts b/build.gradle.kts index 1ebe9b1a..3188d3bc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "net.theevilreaper" -version = "1.13.0" +version = "1.13.1" description = "Aves" java { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f8e1ee31..d997cfc6 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4eac4a84..c82ad3ff 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index adff685a..739907df 100755 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/settings.gradle.kts b/settings.gradle.kts index 21b1ce7e..a8864146 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,7 +21,7 @@ dependencyResolutionManagement { } versionCatalogs { create("libs") { - version("bom", "1.6.0") + version("bom", "1.6.4") library("mycelium.bom", "net.onelitefeather", "mycelium-bom").versionRef("bom") library("minestom","net.minestom", "minestom").withoutVersion() library("adventure", "net.kyori", "adventure-text-minimessage").withoutVersion() diff --git a/src/main/java/net/theevilreaper/aves/inventory/BaseInventoryBuilderImpl.java b/src/main/java/net/theevilreaper/aves/inventory/BaseInventoryBuilderImpl.java index 2bbb9309..56fcf3cf 100644 --- a/src/main/java/net/theevilreaper/aves/inventory/BaseInventoryBuilderImpl.java +++ b/src/main/java/net/theevilreaper/aves/inventory/BaseInventoryBuilderImpl.java @@ -42,11 +42,11 @@ protected BaseInventoryBuilderImpl(@NotNull InventoryType type) { @Override public void register() { this.checkListenerState(this.openListener, this.closeListener, this.clickListener); - if (this.openFunction == null) { + if (this.openFunction != null) { this.openListener = registerOpen(this, holder); } - if (this.closeFunction == null) { + if (this.closeFunction != null) { this.closeListener = registerClose(this, holder); } diff --git a/src/main/java/net/theevilreaper/aves/inventory/InventoryListenerHandler.java b/src/main/java/net/theevilreaper/aves/inventory/InventoryListenerHandler.java index f5b15ea5..5479e8b5 100644 --- a/src/main/java/net/theevilreaper/aves/inventory/InventoryListenerHandler.java +++ b/src/main/java/net/theevilreaper/aves/inventory/InventoryListenerHandler.java @@ -137,9 +137,9 @@ default EventListener registerClick( if (event.getInventory() instanceof CustomInventory customInventory && customInventory.getHolder() == holder) { Consumer result = click -> { switch (click) { - case ClickHolder.CancelClick ignored1 -> event.setCancelled(true); + case ClickHolder.CancelClick _ -> event.setCancelled(true); case ClickHolder.MinestomClick(@NotNull Click minestomClick) -> event.setClick(minestomClick); - case ClickHolder.NOPClick ignored -> { + case ClickHolder.NOPClick _ -> { // No operation } } diff --git a/src/main/java/net/theevilreaper/aves/util/Players.java b/src/main/java/net/theevilreaper/aves/util/Players.java index 35717225..1797f340 100644 --- a/src/main/java/net/theevilreaper/aves/util/Players.java +++ b/src/main/java/net/theevilreaper/aves/util/Players.java @@ -16,7 +16,6 @@ import net.minestom.server.item.Material; import net.minestom.server.network.packet.server.play.SetCooldownPacket; import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/net/theevilreaper/aves/util/Strings.java b/src/main/java/net/theevilreaper/aves/util/Strings.java index c325fcdd..7ca15d36 100644 --- a/src/main/java/net/theevilreaper/aves/util/Strings.java +++ b/src/main/java/net/theevilreaper/aves/util/Strings.java @@ -2,7 +2,8 @@ import org.jetbrains.annotations.Contract; -import java.util.StringJoiner; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; /** * The class contains some useful methods for string manipulation. @@ -14,8 +15,11 @@ */ public final class Strings { - private static final String INT_FORMAT = "%02d"; - private static final int TIME_DIVIDER = 60; + private static final DateTimeFormatter HH_MM_SS = + DateTimeFormatter.ofPattern("HH:mm:ss"); + + private static final DateTimeFormatter MM_SS = + DateTimeFormatter.ofPattern("mm:ss"); public static final String SPACE = " "; public static final String UTF_8_HEART = "\u2665"; @@ -55,24 +59,22 @@ public static String centerText(String text, int lineLength) { * @param time the time who should be converted * @return the converted time */ - @Contract(pure = true) + @Contract(pure = true, value = "_, _ -> new") public static String getTimeString(TimeFormat timeFormat, int time) { if (time <= 0) { return timeFormat.getDefaultFormat(); } - int minutes = time / TIME_DIVIDER; - int seconds = time % TIME_DIVIDER; + int seconds = time % 60; + int totalMinutes = time / 60; + int minutes = totalMinutes % 60; + int hours = totalMinutes / 60; - StringJoiner stringJoiner = new StringJoiner(":"); + LocalTime localTime = LocalTime.of(hours, minutes, seconds); - if (timeFormat == TimeFormat.HH_MM_SS) { - int hours = minutes / TIME_DIVIDER; - minutes = minutes % TIME_DIVIDER; - stringJoiner.add(String.format(INT_FORMAT, hours)); - } - stringJoiner.add(String.format(INT_FORMAT, minutes)); - stringJoiner.add(String.format(INT_FORMAT, seconds)); - return stringJoiner.toString(); + return switch (timeFormat) { + case HH_MM_SS -> localTime.format(HH_MM_SS); + case MM_SS -> localTime.format(MM_SS); + }; } } \ No newline at end of file diff --git a/src/main/java/net/theevilreaper/aves/util/TimeFormat.java b/src/main/java/net/theevilreaper/aves/util/TimeFormat.java index 135731d0..f6028c67 100644 --- a/src/main/java/net/theevilreaper/aves/util/TimeFormat.java +++ b/src/main/java/net/theevilreaper/aves/util/TimeFormat.java @@ -13,29 +13,18 @@ public enum TimeFormat { /** * Indicates a format which contains minutes and seconds. */ - MM_SS("00:00"), + MM_SS, /** * Indicates a format which contains hours, minutes and seconds. */ - HH_MM_SS("00:00:00"); - - private final String defaultFormat; + HH_MM_SS; /** - * Creates a new entry from the {@link TimeFormat} with the given format. + * Returns the default format for the given enum entry. * - * @param defaultFormat the format to set - */ - TimeFormat(String defaultFormat) { - this.defaultFormat = defaultFormat; - } - - /** - * Returns the default format from the specific format. - * - * @return the given format + * @return the default format */ public String getDefaultFormat() { - return defaultFormat; + return this == HH_MM_SS ? "00:00:00" : "00:00"; } } diff --git a/src/main/java/net/theevilreaper/aves/util/functional/ItemStackBiFunction.java b/src/main/java/net/theevilreaper/aves/util/functional/ItemStackBiFunction.java index 7d23d4c7..bdc9f7ef 100644 --- a/src/main/java/net/theevilreaper/aves/util/functional/ItemStackBiFunction.java +++ b/src/main/java/net/theevilreaper/aves/util/functional/ItemStackBiFunction.java @@ -1,7 +1,6 @@ package net.theevilreaper.aves.util.functional; import net.minestom.server.item.ItemStack; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.function.Function; diff --git a/src/test/java/net/theevilreaper/aves/inventory/BaseInventoryBuilderImplIntegrationTest.java b/src/test/java/net/theevilreaper/aves/inventory/BaseInventoryBuilderImplIntegrationTest.java new file mode 100644 index 00000000..8d10bbce --- /dev/null +++ b/src/test/java/net/theevilreaper/aves/inventory/BaseInventoryBuilderImplIntegrationTest.java @@ -0,0 +1,130 @@ +package net.theevilreaper.aves.inventory; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import net.minestom.server.entity.Player; +import net.minestom.server.event.EventFilter; +import net.minestom.server.event.inventory.InventoryCloseEvent; +import net.minestom.server.event.inventory.InventoryOpenEvent; +import net.minestom.server.instance.Instance; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.network.packet.server.play.SystemChatPacket; +import net.minestom.testing.Collector; +import net.minestom.testing.Env; +import net.minestom.testing.TestConnection; +import net.minestom.testing.extension.MicrotusExtension; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@ExtendWith(MicrotusExtension.class) +class BaseInventoryBuilderImplIntegrationTest { + + private static final Component TITLE_COMPONENT = Component.text("Test"); + + private Instance instance; + private TestConnection testConnection; + private Player player; + + @BeforeEach + void setup(Env env) { + instance = env.createFlatInstance(); + testConnection = env.createConnection(); + player = testConnection.connect(instance); + } + + @AfterEach + void teardown(Env env) { + env.destroyInstance(instance, true); + } + + @Test + void testCloseFunctionCall(Env env) { + GlobalInventoryBuilder testInventory = buildInventory(); + testInventory.setCloseFunction(event -> + event.getPlayer().sendMessage(Component.text("Closed")) + ); + testInventory.register(); + + assertNotNull(testInventory.getInventory()); + + player.openInventory(testInventory.getInventory()); + assertNotNull(player.getOpenInventory()); + assertInstanceOf(CustomInventory.class, player.getOpenInventory()); + + Collector chatCollector = testConnection.trackIncoming(SystemChatPacket.class); + Collector closeTracker = env.trackEvent(InventoryCloseEvent.class, EventFilter.INVENTORY, testInventory.getInventory()); + + player.closeInventory(); + + closeTracker.assertSingle(event -> { + assertInstanceOf(CustomInventory.class, event.getInventory()); + CustomInventory inventory = (CustomInventory) event.getInventory(); + assertEquals("Test", PlainTextComponentSerializer.plainText().serialize(inventory.getTitle())); + }); + + env.tick(); + assertSingleChatMessage(chatCollector, "Closed"); + } + + @Test + void testOpenFunctionCall(Env env) { + GlobalInventoryBuilder testInventory = buildInventory(); + testInventory.setOpenFunction(event -> + event.getPlayer().sendMessage(Component.text("Opened")) + ); + testInventory.register(); + + assertNotNull(testInventory.getInventory()); + + Collector chatCollector = testConnection.trackIncoming(SystemChatPacket.class); + Collector openTracker = env.trackEvent(InventoryOpenEvent.class, EventFilter.INVENTORY, testInventory.getInventory()); + + player.openInventory(testInventory.getInventory()); + assertNotNull(player.getOpenInventory()); + assertInstanceOf(CustomInventory.class, player.getOpenInventory()); + + openTracker.assertSingle(event -> { + assertInstanceOf(CustomInventory.class, event.getInventory()); + CustomInventory inventory = (CustomInventory) event.getInventory(); + assertEquals("Test", PlainTextComponentSerializer.plainText().serialize(inventory.getTitle())); + }); + + env.tick(); + assertSingleChatMessage(chatCollector, "Opened"); + } + + /** + * Creates a pre-configured {@link GlobalInventoryBuilder} with {@link #TITLE_COMPONENT} + * as title and {@link InventoryType#ANVIL} as type, including a matching layout. + * + * @return a new {@link GlobalInventoryBuilder} ready for use in tests + */ + private GlobalInventoryBuilder buildInventory() { + GlobalInventoryBuilder builder = new GlobalInventoryBuilder(TITLE_COMPONENT, InventoryType.ANVIL); + builder.setLayout(InventoryLayout.fromType(builder.getType())); + return builder; + } + + /** + * Asserts that the given {@link Collector} contains exactly one {@link SystemChatPacket} + * whose first component matches the expected plain-text message. + * + * @param collector the packet collector to assert against + * @param expected the expected plain-text message + */ + private void assertSingleChatMessage(Collector collector, String expected) { + collector.assertSingle(packet -> { + assertNotNull(packet.components()); + assertEquals(1, packet.components().size()); + Component first = packet.components().iterator().next(); + assertNotNull(first); + assertEquals(expected, PlainTextComponentSerializer.plainText().serialize(first)); + }); + } +} \ No newline at end of file diff --git a/src/test/java/net/theevilreaper/aves/util/StringsTest.java b/src/test/java/net/theevilreaper/aves/util/StringsTest.java index 688ec922..5cf0fbc5 100644 --- a/src/test/java/net/theevilreaper/aves/util/StringsTest.java +++ b/src/test/java/net/theevilreaper/aves/util/StringsTest.java @@ -14,8 +14,6 @@ class StringsTest { private static final Stream TIME_ARGUMENTS = Stream.of( Arguments.of("00:00", Strings.getTimeString(TimeFormat.MM_SS, 0)), Arguments.of("01:00", Strings.getTimeString(TimeFormat.MM_SS, 60)), - Arguments.of("70:00", Strings.getTimeString(TimeFormat.MM_SS, 4200)), - Arguments.of("70:55", Strings.getTimeString(TimeFormat.MM_SS, 4255)), Arguments.of("01:00:00", Strings.getTimeString(TimeFormat.HH_MM_SS, 3600)), Arguments.of("00:59:59", Strings.getTimeString(TimeFormat.HH_MM_SS, 3599)), Arguments.of("01:01:39", Strings.getTimeString(TimeFormat.HH_MM_SS, 3699)),