Skip to content

Commit 4283507

Browse files
chore: improve setup item organization (#78)
* feat(setup): add HotBarLayout class * chore(setup): move test classes * chore(setup): update imports * chore(setup): add package info file * feat(setup): add new layout for the page setup * test(setup): add new item case --------- Co-authored-by: theEvilReaper <theEvilReaper@users.noreply.github.com>
1 parent a966ca0 commit 4283507

8 files changed

Lines changed: 208 additions & 21 deletions

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package net.onelitefeather.cygnus.setup.item;
2+
3+
import net.minestom.server.entity.Player;
4+
import net.minestom.server.item.ItemStack;
5+
6+
import java.util.Arrays;
7+
8+
/**
9+
* Represents a hotbar layout consisting of nine item slots (indices 0–8).
10+
* Each slot is initially filled with {@link ItemStack#AIR} and can be
11+
* overwritten individually via {@link #set(int, ItemStack)}.
12+
* <p>
13+
* Use {@link #apply(Player)} to write the layout into a player's inventory.
14+
*
15+
* @author theEvilReaper
16+
* @version 1.0.0
17+
* @since 0.1.0
18+
*/
19+
public final class HotBarLayout {
20+
21+
private static final int HOTBAR_SIZE = 9;
22+
23+
private final ItemStack[] items = new ItemStack[HOTBAR_SIZE];
24+
25+
/**
26+
* Creates a new layout with all slots set to {@link ItemStack#AIR}.
27+
*/
28+
public HotBarLayout() {
29+
Arrays.fill(items, ItemStack.AIR);
30+
}
31+
32+
/**
33+
* Places the given item at the specified hotbar slot.
34+
*
35+
* @param slot the slot index (0–8)
36+
* @param item the item to place
37+
* @return this layout, for chaining
38+
* @throws IndexOutOfBoundsException if the slot is not in range 0–8
39+
*/
40+
public HotBarLayout set(int slot, ItemStack item) {
41+
if (slot < 0 || slot >= HOTBAR_SIZE) {
42+
throw new IndexOutOfBoundsException("Slot must be between 0 and 8, got: " + slot);
43+
}
44+
items[slot] = item;
45+
return this;
46+
}
47+
48+
/**
49+
* Returns the item at the given hotbar slot.
50+
*
51+
* @param slot the slot index (0–8)
52+
* @return the item at the slot
53+
* @throws IndexOutOfBoundsException if the slot is not in range 0–8
54+
*/
55+
public ItemStack get(int slot) {
56+
if (slot < 0 || slot >= HOTBAR_SIZE) {
57+
throw new IndexOutOfBoundsException("Slot must be between 0 and 8, got: " + slot);
58+
}
59+
return items[slot];
60+
}
61+
62+
/**
63+
* Writes this layout into the player's inventory (slots 0–8).
64+
*
65+
* @param player the player whose hotbar is updated
66+
*/
67+
public void apply(Player player) {
68+
for (int i = 0; i < items.length; i++) {
69+
player.getInventory().setItemStack(i, items[i]);
70+
}
71+
}
72+
}

setup/src/main/java/net/onelitefeather/cygnus/setup/util/SetupItems.java renamed to setup/src/main/java/net/onelitefeather/cygnus/setup/item/SetupItems.java

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
package net.onelitefeather.cygnus.setup.util;
1+
package net.onelitefeather.cygnus.setup.item;
22

33
import net.kyori.adventure.text.Component;
44
import net.kyori.adventure.text.format.NamedTextColor;
55
import net.minestom.server.entity.Player;
66
import net.minestom.server.item.ItemStack;
77
import net.minestom.server.item.Material;
88
import net.onelitefeather.cygnus.common.Tags;
9-
import org.jetbrains.annotations.NotNull;
109

1110
/**
1211
* The class holds the {@link ItemStack} references which have some functionality during a setup process from an map.
@@ -21,33 +20,45 @@ public final class SetupItems {
2120
public static final byte ZERO_INDEX = (byte) 0x00;
2221
public static final byte FOURTH_INDEX = (byte) 0x04;
2322

24-
private static final ItemStack mapSelection;
23+
private static final HotBarLayout selectionLayout;
24+
private static final HotBarLayout mapLayout;
25+
private static final HotBarLayout pageLayout;
2526

26-
private static final ItemStack dataItem;
27-
private static final ItemStack saveData;
28-
29-
static {
30-
mapSelection = ItemStack.builder(Material.CHEST)
27+
static {
28+
selectionLayout = new HotBarLayout();
29+
selectionLayout.set(FOURTH_INDEX, ItemStack.builder(Material.CHEST)
3130
.customName(Component.text("Map selection", NamedTextColor.GREEN))
3231
.set(Tags.ITEM_TAG, ZERO_INDEX)
33-
.build();
34-
saveData = ItemStack.builder(Material.BELL)
32+
.build()
33+
);
34+
ItemStack saveItem = ItemStack.builder(Material.BELL)
3535
.customName(Component.text("Save data", NamedTextColor.RED))
3636
.set(Tags.ITEM_TAG, (byte) 0x01)
3737
.build();
38-
dataItem = ItemStack.builder(Material.COMPASS)
38+
mapLayout = new HotBarLayout();
39+
mapLayout.set(2, ItemStack.builder(Material.COMPASS)
3940
.customName(Component.text("Data", NamedTextColor.AQUA))
4041
.set(Tags.ITEM_TAG, (byte) 0x02)
41-
.build();
42+
.build()
43+
);
44+
mapLayout.set(6, saveItem);
45+
46+
pageLayout = new HotBarLayout();
47+
pageLayout.set(2, ItemStack.builder(Material.BARRIER)
48+
.customName(Component.text("Cancel", NamedTextColor.RED))
49+
.set(Tags.ITEM_TAG, (byte) 0x03)
50+
.build()
51+
);
52+
pageLayout.set(6, saveItem);
4253
}
4354

4455
/**
4556
* Set's the {@link ItemStack} which represents the map selection into an inventory.
4657
*
4758
* @param player the player who should receive the item
4859
*/
49-
public static void setMapSelection(@NotNull Player player) {
50-
player.getInventory().setItemStack(FOURTH_INDEX, mapSelection);
60+
public static void setMapSelection(Player player) {
61+
selectionLayout.apply(player);
5162
player.setHeldItemSlot(FOURTH_INDEX);
5263
}
5364

@@ -56,9 +67,18 @@ public static void setMapSelection(@NotNull Player player) {
5667
*
5768
* @param player the player who should receive the item
5869
*/
59-
public static void setSaveData(@NotNull Player player) {
60-
player.getInventory().setItemStack(2, dataItem);
61-
player.getInventory().setItemStack(6, saveData);
70+
public static void setSaveData(Player player) {
71+
mapLayout.apply(player);
72+
player.setHeldItemSlot(ZERO_INDEX);
73+
}
74+
75+
/**
76+
* Set's the {@link ItemStack} which are required for the page setup.
77+
*
78+
* @param player the player who should receive the item
79+
*/
80+
public static void setPageItems(Player player) {
81+
pageLayout.apply(player);
6282
player.setHeldItemSlot(ZERO_INDEX);
6383
}
6484

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@NotNullByDefault
2+
package net.onelitefeather.cygnus.setup.item;
3+
4+
import org.jetbrains.annotations.NotNullByDefault;

setup/src/main/java/net/onelitefeather/cygnus/setup/listener/InstanceAddListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import net.minestom.server.MinecraftServer;
44
import net.minestom.server.entity.Player;
55
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
6-
import net.onelitefeather.cygnus.setup.util.SetupItems;
6+
import net.onelitefeather.cygnus.setup.item.SetupItems;
77

88
import java.time.Duration;
99
import java.time.temporal.ChronoUnit;

setup/src/main/java/net/onelitefeather/cygnus/setup/listener/PlayerSpawnListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import net.minestom.server.entity.GameMode;
55
import net.minestom.server.entity.Player;
66
import net.minestom.server.event.player.PlayerSpawnEvent;
7-
import net.onelitefeather.cygnus.setup.util.SetupItems;
7+
import net.onelitefeather.cygnus.setup.item.SetupItems;
88

99
import java.util.function.Consumer;
1010

setup/src/main/java/net/onelitefeather/cygnus/setup/listener/SetupItemListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import net.onelitefeather.cygnus.common.Tags;
77
import net.onelitefeather.cygnus.setup.inventory.MapSetupInventory;
88
import net.onelitefeather.cygnus.setup.util.SetupData;
9-
import net.onelitefeather.cygnus.setup.util.SetupItems;
9+
import net.onelitefeather.cygnus.setup.item.SetupItems;
1010
import net.onelitefeather.cygnus.setup.util.SetupTags;
1111

1212
import java.util.function.Consumer;
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package net.onelitefeather.cygnus.setup.item;
2+
3+
import net.minestom.server.item.ItemStack;
4+
import net.minestom.server.item.Material;
5+
import org.junit.jupiter.api.Test;
6+
import org.junit.jupiter.params.ParameterizedTest;
7+
import org.junit.jupiter.params.provider.ValueSource;
8+
9+
import static org.junit.jupiter.api.Assertions.assertEquals;
10+
import static org.junit.jupiter.api.Assertions.assertThrows;
11+
12+
class HotBarLayoutTest {
13+
14+
@Test
15+
void testDefaultSlotsAreAir() {
16+
var layout = new HotBarLayout();
17+
for (int i = 0; i < 9; i++) {
18+
assertEquals(ItemStack.AIR, layout.get(i), "Slot " + i + " should default to AIR");
19+
}
20+
}
21+
22+
@Test
23+
void testSetAndGet() {
24+
var item = ItemStack.of(Material.DIAMOND);
25+
var layout = new HotBarLayout().set(4, item);
26+
assertEquals(item, layout.get(4));
27+
}
28+
29+
@Test
30+
void testSetIsChainable() {
31+
var first = ItemStack.of(Material.COMPASS);
32+
var second = ItemStack.of(Material.CLOCK);
33+
var layout = new HotBarLayout()
34+
.set(7, first)
35+
.set(8, second);
36+
37+
assertEquals(first, layout.get(7));
38+
assertEquals(second, layout.get(8));
39+
}
40+
41+
@Test
42+
void testSetOverwritesPreviousItem() {
43+
var original = ItemStack.of(Material.STONE);
44+
var replacement = ItemStack.of(Material.DIAMOND);
45+
46+
var layout = new HotBarLayout()
47+
.set(0, original)
48+
.set(0, replacement);
49+
50+
assertEquals(replacement, layout.get(0));
51+
}
52+
53+
@Test
54+
void testUntouchedSlotsRemainAir() {
55+
var layout = new HotBarLayout()
56+
.set(3, ItemStack.of(Material.COMPASS))
57+
.set(8, ItemStack.of(Material.CLOCK));
58+
59+
for (int i = 0; i < 9; i++) {
60+
if (i != 3 && i != 8) {
61+
assertEquals(ItemStack.AIR, layout.get(i), "Slot " + i + " should still be AIR");
62+
}
63+
}
64+
}
65+
66+
@ParameterizedTest(name = "Invalid slot index: {0}")
67+
@ValueSource(ints = {-1, 9, 10, -100, Integer.MAX_VALUE})
68+
void testSetWithInvalidSlotThrows(int slot) {
69+
var layout = new HotBarLayout();
70+
assertThrows(IndexOutOfBoundsException.class, () -> layout.set(slot, ItemStack.AIR));
71+
}
72+
73+
@ParameterizedTest(name = "Invalid get index: {0}")
74+
@ValueSource(ints = {-1, 9, 10, -100, Integer.MAX_VALUE})
75+
void testGetWithInvalidSlotThrows(int slot) {
76+
var layout = new HotBarLayout();
77+
assertThrows(IndexOutOfBoundsException.class, () -> layout.get(slot));
78+
}
79+
}

setup/src/test/java/net/onelitefeather/cygnus/setup/util/SetupItemsTest.java renamed to setup/src/test/java/net/onelitefeather/cygnus/setup/item/SetupItemsTest.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package net.onelitefeather.cygnus.setup.util;
1+
package net.onelitefeather.cygnus.setup.item;
22

33
import net.minestom.server.entity.Player;
44
import net.minestom.server.instance.Instance;
@@ -42,6 +42,18 @@ void testSaveDataItemSet(@NotNull Env env) {
4242
env.destroyInstance(instance, true);
4343
}
4444

45+
@Test
46+
void testPageItemSet(@NotNull Env env) {
47+
Instance instance = env.createFlatInstance();
48+
Player player = env.createPlayer(instance);
49+
50+
SetupItems.setPageItems(player);
51+
assertItem(player, 2, (byte) 0x03);
52+
assertItem(player, 6, (byte) 0x01);
53+
54+
env.destroyInstance(instance, true);
55+
}
56+
4557
/**
4658
* Asserts that the item in the specified slot of the player's inventory matches the expected item ID.
4759
*

0 commit comments

Comments
 (0)