From 1353def97e98fdeb6139aebb65abab7f2128db8a Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 22 Jul 2026 22:43:19 +0200 Subject: [PATCH 1/5] feat(kit): improve annotation handling --- src/main/java/net/theevilreaper/xerus/api/kit/Kit.java | 7 +++---- .../java/net/theevilreaper/xerus/api/kit/package-info.java | 4 ++++ 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 src/main/java/net/theevilreaper/xerus/api/kit/package-info.java diff --git a/src/main/java/net/theevilreaper/xerus/api/kit/Kit.java b/src/main/java/net/theevilreaper/xerus/api/kit/Kit.java index 578e9af..de97399 100644 --- a/src/main/java/net/theevilreaper/xerus/api/kit/Kit.java +++ b/src/main/java/net/theevilreaper/xerus/api/kit/Kit.java @@ -3,13 +3,12 @@ import net.kyori.adventure.key.Key; import net.minestom.server.entity.Player; import net.theevilreaper.xerus.api.component.Componentable; -import org.jetbrains.annotations.NotNull; /** * The {@link Kit} interface provides all basic methods that a kit should have. * * @author theEvilReaper - * @version 2.0.0 + * @version 2.1.0 * @since 1.2.0 **/ public interface Kit extends Componentable { @@ -19,12 +18,12 @@ public interface Kit extends Componentable { * * @param player the player to apply the kit to */ - void apply(@NotNull Player player); + void apply(Player player); /** * Returns the identifier of the kit. * * @return the underlying value */ - @NotNull Key key(); + Key key(); } diff --git a/src/main/java/net/theevilreaper/xerus/api/kit/package-info.java b/src/main/java/net/theevilreaper/xerus/api/kit/package-info.java new file mode 100644 index 0000000..ffb4c87 --- /dev/null +++ b/src/main/java/net/theevilreaper/xerus/api/kit/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package net.theevilreaper.xerus.api.kit; + +import org.jetbrains.annotations.NotNullByDefault; \ No newline at end of file From aca171099cbcfbee3310edf259a4c9826a3574f4 Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 22 Jul 2026 22:44:37 +0200 Subject: [PATCH 2/5] feat(kit): improve annotation handling for the event part --- .../xerus/api/kit/event/PlayerKitChangeEvent.java | 9 ++++----- .../theevilreaper/xerus/api/kit/event/package-info.java | 4 ++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 src/main/java/net/theevilreaper/xerus/api/kit/event/package-info.java diff --git a/src/main/java/net/theevilreaper/xerus/api/kit/event/PlayerKitChangeEvent.java b/src/main/java/net/theevilreaper/xerus/api/kit/event/PlayerKitChangeEvent.java index 37582db..ae00845 100644 --- a/src/main/java/net/theevilreaper/xerus/api/kit/event/PlayerKitChangeEvent.java +++ b/src/main/java/net/theevilreaper/xerus/api/kit/event/PlayerKitChangeEvent.java @@ -4,7 +4,6 @@ import net.minestom.server.entity.Player; import net.minestom.server.event.trait.CancellableEvent; import net.minestom.server.event.trait.PlayerEvent; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -16,7 +15,7 @@ public final class PlayerKitChangeEvent implements PlayerEvent, CancellableEvent { private final Player player; - private final Kit currentKit; + private final @Nullable Kit currentKit; private final Kit newKit; private boolean cancelled; @@ -26,7 +25,7 @@ public final class PlayerKitChangeEvent implements PlayerEvent, CancellableEvent * @param currentKit The current kit of the player * @param newKit The new kit of the player */ - public PlayerKitChangeEvent(@NotNull Player player, @Nullable Kit currentKit, @NotNull Kit newKit) { + public PlayerKitChangeEvent(Player player, @Nullable Kit currentKit, Kit newKit) { this.player = player; this.currentKit = currentKit; this.newKit = newKit; @@ -37,7 +36,7 @@ public PlayerKitChangeEvent(@NotNull Player player, @Nullable Kit currentKit, @N * @return the involved player */ @Override - public @NotNull Player getPlayer() { + public Player getPlayer() { return player; } @@ -75,7 +74,7 @@ public boolean isCancelled() { * Returns the new kit for a player * @return the new kit */ - public @NotNull Kit getNewKit() { + public Kit getNewKit() { return newKit; } } \ No newline at end of file diff --git a/src/main/java/net/theevilreaper/xerus/api/kit/event/package-info.java b/src/main/java/net/theevilreaper/xerus/api/kit/event/package-info.java new file mode 100644 index 0000000..ea70117 --- /dev/null +++ b/src/main/java/net/theevilreaper/xerus/api/kit/event/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package net.theevilreaper.xerus.api.kit.event; + +import org.jetbrains.annotations.NotNullByDefault; \ No newline at end of file From 06bd191d2e2e331b24e3a711f07aa08e94312016 Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 22 Jul 2026 22:45:30 +0200 Subject: [PATCH 3/5] chore(kit): improve data storage and optional handling --- .../theevilreaper/xerus/api/kit/BaseKit.java | 19 +++++----- .../xerus/api/kit/DefaultKitService.java | 37 +++++++------------ .../xerus/api/kit/KitService.java | 13 +++---- 3 files changed, 28 insertions(+), 41 deletions(-) diff --git a/src/main/java/net/theevilreaper/xerus/api/kit/BaseKit.java b/src/main/java/net/theevilreaper/xerus/api/kit/BaseKit.java index 3018572..3246509 100644 --- a/src/main/java/net/theevilreaper/xerus/api/kit/BaseKit.java +++ b/src/main/java/net/theevilreaper/xerus/api/kit/BaseKit.java @@ -2,18 +2,17 @@ import net.kyori.adventure.key.Key; import net.theevilreaper.xerus.api.component.ObjectComponent; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * The {@link BaseKit} is an abstract layer implementation of the {@link Kit} interface. * It contains the general structure of a kit and can be used to define custom implementations. * * @author theEvilReaper - * @version 1.0.0 + * @version 1.1.0 * @since 1.2.0 **/ public abstract class BaseKit implements Kit { @@ -24,16 +23,16 @@ public abstract class BaseKit implements Kit { /** * Creates a new instance of the {@link BaseKit}. */ - protected BaseKit(@NotNull Key key) { + protected BaseKit(Key key) { this.key = key; - this.components = new HashMap<>(); + this.components = new ConcurrentHashMap<>(); } /** * {@inheritDoc} */ @Override - public void add(@NotNull Class componentClass, @NotNull T component) { + public void add(Class componentClass, T component) { this.components.computeIfAbsent(componentClass, k -> component); } @@ -41,7 +40,7 @@ public void add(@NotNull Class componentClass, @N * {@inheritDoc} */ @Override - public boolean has(@NotNull Class componentClass) { + public boolean has(Class componentClass) { return this.components.containsKey(componentClass); } @@ -49,7 +48,7 @@ public boolean has(@NotNull Class componentClass) * {@inheritDoc}} */ @Override - public @Nullable T get(@NotNull Class componentClass) { + public @Nullable T get(Class componentClass) { return componentClass.cast(this.components.get(componentClass)); } @@ -57,7 +56,7 @@ public boolean has(@NotNull Class componentClass) * {@inheritDoc} */ @Override - public @Nullable T remove(@NotNull Class componentClass) { + public @Nullable T remove(Class componentClass) { return componentClass.cast(this.components.remove(componentClass)); } @@ -65,7 +64,7 @@ public boolean has(@NotNull Class componentClass) * {@inheritDoc} */ @Override - public @NotNull Key key() { + public Key key() { return this.key; } } diff --git a/src/main/java/net/theevilreaper/xerus/api/kit/DefaultKitService.java b/src/main/java/net/theevilreaper/xerus/api/kit/DefaultKitService.java index 01d5191..35b9a26 100644 --- a/src/main/java/net/theevilreaper/xerus/api/kit/DefaultKitService.java +++ b/src/main/java/net/theevilreaper/xerus/api/kit/DefaultKitService.java @@ -2,16 +2,14 @@ import net.kyori.adventure.key.Key; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.UnmodifiableView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; /** * The class represents a default implementation of the {@link KitService} interface. @@ -19,19 +17,19 @@ * If your use case doesn't fit into this please implement your own {@link KitService} implementation. * * @author theEvilReaper - * @version 1.1.0 + * @version 1.2.0 * @since 1.2.0 **/ public final class DefaultKitService implements KitService { private static final Logger KIT_LOGGER = LoggerFactory.getLogger(DefaultKitService.class); - private final List kits; + private final Map kits; /** * Creates a new instance of the {@link DefaultKitService}. */ DefaultKitService() { - this.kits = new ArrayList<>(); + this.kits = new ConcurrentHashMap<>(); } /** @@ -47,34 +45,27 @@ public void clear() { * {@inheritDoc} */ @Override - public void add(@NotNull Kit kit) { - if (kits.contains(kit)) { + public void add(Kit kit) { + if (this.kits.containsKey(kit.key())) { KIT_LOGGER.info("Overwriting existing kit!"); } - this.kits.add(kit); + this.kits.put(kit.key(), kit); } /** * {@inheritDoc} */ @Override - public boolean remove(@NotNull Key identifier) { - return this.kits.removeIf(iKit -> iKit.key().equals(identifier)); + public boolean remove(Key identifier) { + return this.kits.remove(identifier) != null; } /** * {@inheritDoc} */ @Override - public @NotNull Optional<@Nullable Kit> getKit(@NotNull Key name) { - Kit kit = null; - for (int i = 0; i < kits.size() && kit == null; i++) { - if (kits.get(i).key().equals(name)) { - kit = kits.get(i); - } - } - - return Optional.ofNullable(kit); + public Optional getKit(Key name) { + return Optional.ofNullable(this.kits.get(name)); } /** @@ -82,7 +73,7 @@ public boolean remove(@NotNull Key identifier) { */ @Contract(pure = true) @Override - public @NotNull @UnmodifiableView List getKits() { - return Collections.unmodifiableList(this.kits); + public @UnmodifiableView List getKits() { + return List.copyOf(this.kits.values()); } } diff --git a/src/main/java/net/theevilreaper/xerus/api/kit/KitService.java b/src/main/java/net/theevilreaper/xerus/api/kit/KitService.java index da9a0b5..243522a 100644 --- a/src/main/java/net/theevilreaper/xerus/api/kit/KitService.java +++ b/src/main/java/net/theevilreaper/xerus/api/kit/KitService.java @@ -2,8 +2,6 @@ import net.kyori.adventure.key.Key; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.UnmodifiableView; import java.util.List; @@ -15,7 +13,7 @@ * So he must implement the interface by self and can add additional method to the service. * * @author theEvilReaper - * @version 1.0.0 + * @version 1.1.0 * @since 1.2.0 **/ public interface KitService { @@ -26,7 +24,7 @@ public interface KitService { * @return the new instance */ @Contract(pure = true) - static @NotNull KitService of() { + static KitService of() { return new DefaultKitService(); } @@ -35,7 +33,7 @@ public interface KitService { * * @param kit that should be added */ - void add(@NotNull Kit kit); + void add(Kit kit); /** * Remove a kit by the identifier from the kit. @@ -43,7 +41,7 @@ public interface KitService { * @param identifier the identifier from the kit * @return true when the kit can be removed otherwise false */ - boolean remove(@NotNull Key identifier); + boolean remove(Key identifier); /** * Clears the underlying data structure. @@ -56,14 +54,13 @@ public interface KitService { * @param name the name of the kit * @return the fetched kit in an optional */ - @NotNull Optional<@Nullable Kit> getKit(@NotNull Key name); + Optional getKit(Key name); /** * Returns a list with all current available kits. * * @return the underlying list */ - @NotNull @UnmodifiableView @Contract(pure = true) List getKits(); From a9325d07e380a4da288e045baa06115d606f8c2c Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 22 Jul 2026 22:50:37 +0200 Subject: [PATCH 4/5] chore(kit): improve test part --- .../xerus/api/kit/KitServiceTest.java | 38 ++++++++++++++++ .../api/kit/PlayerKitIntegrationTest.java | 44 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/test/java/net/theevilreaper/xerus/api/kit/PlayerKitIntegrationTest.java diff --git a/src/test/java/net/theevilreaper/xerus/api/kit/KitServiceTest.java b/src/test/java/net/theevilreaper/xerus/api/kit/KitServiceTest.java index 80aec50..df2feb3 100644 --- a/src/test/java/net/theevilreaper/xerus/api/kit/KitServiceTest.java +++ b/src/test/java/net/theevilreaper/xerus/api/kit/KitServiceTest.java @@ -62,4 +62,42 @@ void testKitGetNonExisting() { Optional fetchedKit = kitService.getKit(Key.key("xerus", "test_kit")); assertFalse(fetchedKit.isPresent()); } + + @Test + void testDuplicateKitAddition() { + assertTrue(kitService.getKits().isEmpty()); + + Kit kit1 = new TestKit(); + Kit kit2 = new TestKit(); + + kitService.add(kit1); + assertEquals(1, kitService.getKits().size()); + + // Adding kit with same key must replace existing without duplicating size + kitService.add(kit2); + assertEquals(1, kitService.getKits().size()); + assertEquals(kit2, kitService.getKit(kit1.key()).orElse(null)); + } + + @Test + void testRemoveNonExisting() { + assertFalse(kitService.remove(Key.key("xerus", "non_existing_kit"))); + } + + @Test + void testClearMultipleKits() { + kitService.add(new TestKit(Key.key("xerus", "kit_1"))); + kitService.add(new TestKit(Key.key("xerus", "kit_2"))); + assertEquals(2, kitService.getKits().size()); + + kitService.clear(); + assertTrue(kitService.getKits().isEmpty()); + } + + @Test + void testUnmodifiableKitsList() { + kitService.add(new TestKit()); + var kitsList = kitService.getKits(); + assertThrows(UnsupportedOperationException.class, () -> kitsList.add(new TestKit(Key.key("xerus", "other")))); + } } diff --git a/src/test/java/net/theevilreaper/xerus/api/kit/PlayerKitIntegrationTest.java b/src/test/java/net/theevilreaper/xerus/api/kit/PlayerKitIntegrationTest.java new file mode 100644 index 0000000..b2a5550 --- /dev/null +++ b/src/test/java/net/theevilreaper/xerus/api/kit/PlayerKitIntegrationTest.java @@ -0,0 +1,44 @@ +package net.theevilreaper.xerus.api.kit; + +import net.kyori.adventure.key.Key; +import net.minestom.server.entity.Player; +import net.minestom.server.event.EventDispatcher; +import net.minestom.server.event.EventFilter; + +import net.minestom.server.instance.Instance; +import net.minestom.testing.Collector; +import net.minestom.testing.Env; +import net.minestom.testing.extension.MicrotusExtension; +import net.theevilreaper.xerus.api.kit.event.PlayerKitChangeEvent; +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.assertFalse; + +@ExtendWith(MicrotusExtension.class) +class PlayerKitIntegrationTest { + + @Test + void testPlayerKitChangeEventFiring(Env env) { + Instance instance = env.createFlatInstance(); + Player player = env.createPlayer(instance); + + Kit oldKit = new TestKit(Key.key("xerus", "old_kit")); + Kit newKit = new TestKit(Key.key("xerus", "new_kit")); + + Collector collector = env.trackEvent(PlayerKitChangeEvent.class, EventFilter.PLAYER, player); + + PlayerKitChangeEvent event = new PlayerKitChangeEvent(player, oldKit, newKit); + EventDispatcher.call(event); + + collector.assertSingle(e -> { + assertEquals(player, e.getPlayer()); + assertEquals(oldKit, e.getCurrentKit()); + assertEquals(newKit, e.getNewKit()); + assertFalse(e.isCancelled()); + }); + + env.destroyInstance(instance, true); + } +} From b5c5ac73a612227349d55b598f8af56526c4b6ee Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 22 Jul 2026 22:59:42 +0200 Subject: [PATCH 5/5] test(kit): improve variable naming --- .../xerus/api/kit/PlayerKitIntegrationTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/net/theevilreaper/xerus/api/kit/PlayerKitIntegrationTest.java b/src/test/java/net/theevilreaper/xerus/api/kit/PlayerKitIntegrationTest.java index b2a5550..c22415a 100644 --- a/src/test/java/net/theevilreaper/xerus/api/kit/PlayerKitIntegrationTest.java +++ b/src/test/java/net/theevilreaper/xerus/api/kit/PlayerKitIntegrationTest.java @@ -32,11 +32,11 @@ void testPlayerKitChangeEventFiring(Env env) { PlayerKitChangeEvent event = new PlayerKitChangeEvent(player, oldKit, newKit); EventDispatcher.call(event); - collector.assertSingle(e -> { - assertEquals(player, e.getPlayer()); - assertEquals(oldKit, e.getCurrentKit()); - assertEquals(newKit, e.getNewKit()); - assertFalse(e.isCancelled()); + collector.assertSingle(firedEvent -> { + assertEquals(player, firedEvent.getPlayer()); + assertEquals(oldKit, firedEvent.getCurrentKit()); + assertEquals(newKit, firedEvent.getNewKit()); + assertFalse(firedEvent.isCancelled()); }); env.destroyInstance(instance, true);