Skip to content

Commit 29ec3fe

Browse files
authored
[#34] Better Notification System (#35)
* [#34] Implement new notification system with tests * [#34] Update demo to use new notification system * [#34] Add deprecation text to old notification system * [#34] Improve javadocs and rename builder implementation * [#34] Improve javadocs and fix tests * [#34] Remove empty lines * [#34] Add package description
1 parent d909f49 commit 29ec3fe

File tree

10 files changed

+335
-18
lines changed

10 files changed

+335
-18
lines changed

demo/src/main/java/net/minestom/demo/PlayerInit.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import net.kyori.adventure.text.Component;
44
import net.minestom.server.MinecraftServer;
55
import net.minestom.server.advancements.FrameType;
6-
import net.minestom.server.advancements.notifications.Notification;
7-
import net.minestom.server.advancements.notifications.NotificationCenter;
86
import net.minestom.server.adventure.MinestomAdventure;
97
import net.minestom.server.adventure.audience.Audiences;
108
import net.minestom.server.coordinate.Pos;
@@ -19,7 +17,15 @@
1917
import net.minestom.server.event.entity.EntityAttackEvent;
2018
import net.minestom.server.event.item.ItemDropEvent;
2119
import net.minestom.server.event.item.PickupItemEvent;
22-
import net.minestom.server.event.player.*;
20+
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
21+
import net.minestom.server.event.player.PlayerBlockInteractEvent;
22+
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
23+
import net.minestom.server.event.player.PlayerDeathEvent;
24+
import net.minestom.server.event.player.PlayerDisconnectEvent;
25+
import net.minestom.server.event.player.PlayerPacketEvent;
26+
import net.minestom.server.event.player.PlayerPacketOutEvent;
27+
import net.minestom.server.event.player.PlayerSpawnEvent;
28+
import net.minestom.server.event.player.PlayerUseItemOnBlockEvent;
2329
import net.minestom.server.event.server.ServerTickMonitorEvent;
2430
import net.minestom.server.instance.Instance;
2531
import net.minestom.server.instance.InstanceContainer;
@@ -33,6 +39,7 @@
3339
import net.minestom.server.item.metadata.BundleMeta;
3440
import net.minestom.server.monitoring.BenchmarkManager;
3541
import net.minestom.server.monitoring.TickMonitor;
42+
import net.minestom.server.notifications.Notification;
3643
import net.minestom.server.utils.MathUtils;
3744
import net.minestom.server.utils.time.TimeUnit;
3845
import net.minestom.server.world.DimensionType;
@@ -115,12 +122,11 @@ public class PlayerInit {
115122
player.getInventory().addItemStack(bundle);
116123

117124
if (event.isFirstSpawn()) {
118-
Notification notification = new Notification(
119-
Component.text("Welcome!"),
120-
FrameType.TASK,
121-
Material.IRON_SWORD
122-
);
123-
NotificationCenter.send(notification, event.getPlayer());
125+
Notification notification = Notification.builder()
126+
.frameType(FrameType.TASK)
127+
.title(Component.text("Welcome!"))
128+
.icon(Material.IRON_SWORD).build();
129+
notification.send(player);
124130
}
125131
})
126132
.addListener(PlayerPacketOutEvent.class, event -> {

demo/src/main/java/net/minestom/demo/commands/NotificationCommand.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22

33
import net.kyori.adventure.text.Component;
44
import net.minestom.server.advancements.FrameType;
5-
import net.minestom.server.advancements.notifications.Notification;
6-
import net.minestom.server.advancements.notifications.NotificationCenter;
75
import net.minestom.server.command.builder.Command;
86
import net.minestom.server.entity.Player;
97
import net.minestom.server.item.Material;
10-
import org.jetbrains.annotations.NotNull;
118

129
public class NotificationCommand extends Command {
1310
public NotificationCommand() {
1411
super("notification");
1512

1613
setDefaultExecutor((sender, context) -> {
1714
var player = (Player) sender;
18-
19-
var notification = new Notification(Component.text("Hello World!"), FrameType.GOAL, Material.DIAMOND_AXE);
20-
NotificationCenter.send(notification, player);
15+
var notification = net.minestom.server.notifications.Notification.builder()
16+
.title(Component.text("Hello World!"))
17+
.frameType(FrameType.GOAL)
18+
.icon(Material.DIAMOND_AXE)
19+
.build();
20+
notification.send(player);
2121
});
2222
}
2323
}

src/main/java/net/minestom/server/advancements/AdvancementTab.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,8 @@ private void addPlayer(@NotNull Player player) {
155155
*/
156156
private void removePlayer(@NotNull Player player) {
157157
final UUID uuid = player.getUuid();
158-
if (!PLAYER_TAB_MAP.containsKey(uuid)) {
159-
return;
160-
}
161158
Set<AdvancementTab> tabs = PLAYER_TAB_MAP.get(uuid);
159+
if (tabs == null) return;
162160
tabs.remove(this);
163161
if (tabs.isEmpty()) {
164162
PLAYER_TAB_MAP.remove(uuid);

src/main/java/net/minestom/server/advancements/notifications/Notification.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88

99
/**
1010
* Represents a message which can be sent using the {@link NotificationCenter}.
11+
* @since 1.0.0
12+
* @deprecated As of Minestom 22a8ccabfae38c53df0605000aa7eed49765c1ab, because the Maintainability is very hard and
13+
* can break everytime from Mojang side because bad api design use {@link net.minestom.server.notifications.Notification#builder()} instead.
1114
*/
15+
@Deprecated(since = "1.4.1", forRemoval = true)
1216
public record Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull ItemStack icon) {
1317
public Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull Material icon) {
1418
this(title, frameType, ItemStack.of(icon));

src/main/java/net/minestom/server/advancements/notifications/NotificationCenter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@
99
import java.util.List;
1010

1111
/**
12+
* @since 1.0.0
1213
* Used to send one or multiples {@link Notification}.
1314
* <p>
1415
* Works by sending a completed advancement and remove it immediately.
1516
* <p>
1617
* You can simply create a {@link Notification} object and call {@link #send(Notification, Player)}.
18+
* @deprecated As of Minestom 22a8ccabfae38c53df0605000aa7eed49765c1ab, because the Maintainability is very hard and
19+
* can break everytime from Mojang side because bad api design use {@link net.minestom.server.notifications.Notification#builder()} instead.
1720
*/
21+
@Deprecated(since = "1.4.1", forRemoval = true)
1822
public final class NotificationCenter {
1923
private static final String IDENTIFIER = "minestom:notification";
2024
private static final AdvancementsPacket REMOVE_PACKET = new AdvancementsPacket(false, List.of(), List.of(IDENTIFIER), List.of());
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package net.minestom.server.notifications;
2+
3+
import net.kyori.adventure.text.Component;
4+
import net.minestom.server.advancements.FrameType;
5+
import net.minestom.server.entity.Player;
6+
import net.minestom.server.item.ItemStack;
7+
import net.minestom.server.item.Material;
8+
import net.minestom.server.network.packet.server.play.AdvancementsPacket;
9+
import org.jetbrains.annotations.Contract;
10+
import org.jetbrains.annotations.NotNull;
11+
12+
import java.util.Collection;
13+
import java.util.List;
14+
15+
/**
16+
* Is used to send temporary advancements to the client, which are called notifications.
17+
* <br>
18+
* Here is an example of its use:
19+
* <pre><code>
20+
* Notification notification = Notification.builder()
21+
* .frameType(FrameType.TASK)
22+
* .title(Component.text("Welcome!"))
23+
* .icon(Material.IRON_SWORD).build();
24+
* notification.send(player);
25+
* </code></pre>
26+
*
27+
* The constant {@link #IDENTIFIER} is used for the advancement packet
28+
* The constant {@link #REMOVE_PACKET} is used to remove previous notifications
29+
* @since 1.4.1
30+
*/
31+
public sealed interface Notification permits NotificationImpl {
32+
33+
String IDENTIFIER = "minestom:notification";
34+
AdvancementsPacket REMOVE_PACKET = new AdvancementsPacket(false, List.of(), List.of(IDENTIFIER), List.of());
35+
36+
/**
37+
* Creates a new builder instance
38+
* @return an instance of the builder
39+
*/
40+
@Contract(pure = true)
41+
static @NotNull Builder builder() {
42+
return new NotificationBuilder();
43+
}
44+
45+
/**
46+
* Send the notification to the client
47+
* @param player to get be sent
48+
*/
49+
void send(@NotNull Player player);
50+
51+
/**
52+
* Send the notification to a collection of clients
53+
* @param players to get be sent
54+
*/
55+
void send(@NotNull Collection<@NotNull Player> players);
56+
57+
/**
58+
* Gets the title of the notification as a {@link Component}
59+
* @return the title {@link Component}
60+
*/
61+
@NotNull Component title();
62+
63+
/**
64+
* Get the {@link FrameType} of the notification
65+
* @return the type
66+
*/
67+
@NotNull FrameType type();
68+
69+
/**
70+
* Get the displayed icon of the notification as {@link ItemStack}
71+
* @return the {@link ItemStack}
72+
*/
73+
@NotNull ItemStack icon();
74+
75+
/**
76+
* @since 1.4.1
77+
*/
78+
sealed interface Builder permits NotificationBuilder {
79+
80+
/**
81+
* Set the title for a notification as component.
82+
*
83+
* If you're using a resource pack you can use {@link Component#translatable(String)}
84+
*
85+
* @param component to get send to the client
86+
* @return the builder
87+
*/
88+
Builder title(@NotNull Component component);
89+
90+
/**
91+
* Set the frame typ of the notification
92+
* @param frameType to showed for the client
93+
* @return the builder
94+
*/
95+
Builder frameType(@NotNull FrameType frameType);
96+
97+
/**
98+
* Set the {@link Material} for the icon
99+
* @param material to be shown to the client
100+
* @return the builder
101+
*/
102+
Builder icon(@NotNull Material material);
103+
104+
/**
105+
* Set the {@link ItemStack} for the icon
106+
* @param itemStack to be shown to the client
107+
* @return the builder
108+
*/
109+
Builder icon(@NotNull ItemStack itemStack);
110+
111+
/**
112+
* Returns an instance of the creation notification
113+
* @return the instance
114+
*/
115+
Notification build();
116+
}
117+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package net.minestom.server.notifications;
2+
3+
import net.kyori.adventure.text.Component;
4+
import net.minestom.server.advancements.FrameType;
5+
import net.minestom.server.item.ItemStack;
6+
import net.minestom.server.item.Material;
7+
import org.jetbrains.annotations.NotNull;
8+
9+
/**
10+
* {@inheritDoc}
11+
*/
12+
final class NotificationBuilder implements Notification.Builder {
13+
private Component title;
14+
private FrameType type;
15+
private ItemStack icon;
16+
17+
/**
18+
* {@inheritDoc}
19+
*/
20+
@Override
21+
public Notification.Builder title(@NotNull Component component) {
22+
this.title = component;
23+
return this;
24+
}
25+
26+
/**
27+
* {@inheritDoc}
28+
*/
29+
@Override
30+
public Notification.Builder frameType(@NotNull FrameType frameType) {
31+
this.type = frameType;
32+
return this;
33+
}
34+
35+
/**
36+
* {@inheritDoc}
37+
*/
38+
@Override
39+
public Notification.Builder icon(@NotNull Material material) {
40+
this.icon = ItemStack.of(material);
41+
return this;
42+
}
43+
44+
/**
45+
* {@inheritDoc}
46+
*/
47+
@Override
48+
public Notification.Builder icon(@NotNull ItemStack itemStack) {
49+
this.icon = itemStack;
50+
return this;
51+
}
52+
53+
/**
54+
* {@inheritDoc}
55+
*/
56+
@Override
57+
public Notification build() {
58+
return new NotificationImpl(title, type, icon);
59+
}
60+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package net.minestom.server.notifications;
2+
3+
import net.kyori.adventure.text.Component;
4+
import net.minestom.server.advancements.FrameType;
5+
import net.minestom.server.entity.Player;
6+
import net.minestom.server.item.ItemStack;
7+
import net.minestom.server.network.packet.server.play.AdvancementsPacket;
8+
import org.jetbrains.annotations.NotNull;
9+
10+
import java.util.Collection;
11+
import java.util.List;
12+
13+
/**
14+
* {@inheritDoc}
15+
*/
16+
record NotificationImpl(@NotNull Component title, @NotNull FrameType type,
17+
@NotNull ItemStack icon) implements Notification {
18+
/**
19+
* {@inheritDoc}
20+
*/
21+
@Override
22+
public void send(@NotNull Player player) {
23+
player.sendPacket(createPacket());
24+
player.sendPacket(REMOVE_PACKET);
25+
}
26+
27+
/**
28+
* {@inheritDoc}
29+
*/
30+
@Override
31+
public void send(@NotNull Collection<@NotNull Player> players) {
32+
players.forEach(this::send);
33+
}
34+
35+
/**
36+
* Create the advancement packet that simulates the notification.
37+
* It's not private because integration tests
38+
* @return the packet
39+
*/
40+
@NotNull AdvancementsPacket createPacket() {
41+
final var displayData = new AdvancementsPacket.DisplayData(
42+
title(), Component.empty(),
43+
icon(), type(),
44+
0x6, null, 0f, 0f);
45+
46+
final var criteria = new AdvancementsPacket.Criteria("minestom:some_criteria",
47+
new AdvancementsPacket.CriterionProgress(System.currentTimeMillis()));
48+
49+
final var advancement = new AdvancementsPacket.Advancement(null, displayData,
50+
List.of(new AdvancementsPacket.Requirement(List.of(criteria.criterionIdentifier()))),
51+
false);
52+
53+
final var mapping = new AdvancementsPacket.AdvancementMapping(IDENTIFIER, advancement);
54+
final var progressMapping = new AdvancementsPacket.ProgressMapping(IDENTIFIER,
55+
new AdvancementsPacket.AdvancementProgress(List.of(criteria)));
56+
return new AdvancementsPacket(false, List.of(mapping), List.of(), List.of(progressMapping));
57+
}
58+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* This module contains logic about notification system for the minecraft client.
3+
* <p>
4+
* It allows developers to show a toast in the right upper corner with 3 different frame types:
5+
* {@link net.minestom.server.advancements.FrameType#GOAL}, {@link net.minestom.server.advancements.FrameType#TASK} or {@link net.minestom.server.advancements.FrameType#CHALLENGE}
6+
* </p>
7+
*
8+
* @since 1.4.1
9+
* @author TheMeinerLP
10+
* @version 1.0
11+
*/
12+
package net.minestom.server.notifications;

0 commit comments

Comments
 (0)