Skip to content

Commit 2fc773e

Browse files
committed
improve usability
1 parent af73147 commit 2fc773e

File tree

12 files changed

+345
-69
lines changed

12 files changed

+345
-69
lines changed

api/src/main/java/net/labymod/serverapi/api/model/component/ServerAPIBaseComponent.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.ArrayList;
3131
import java.util.EnumMap;
3232
import java.util.List;
33+
import java.util.Objects;
3334

3435
public class ServerAPIBaseComponent<T extends ServerAPIBaseComponent<?>>
3536
implements ServerAPIComponent {
@@ -178,4 +179,23 @@ public String toString() {
178179
", children=" + this.children +
179180
'}';
180181
}
182+
183+
@Override
184+
public boolean equals(Object o) {
185+
if (this == o) {
186+
return true;
187+
}
188+
189+
if (!(o instanceof ServerAPIBaseComponent<?> that)) {
190+
return false;
191+
}
192+
193+
return Objects.equals(this.textColor, that.textColor) && Objects.equals(
194+
this.decorations, that.decorations) && Objects.equals(this.children, that.children);
195+
}
196+
197+
@Override
198+
public int hashCode() {
199+
return Objects.hash(this.textColor, this.decorations, this.children);
200+
}
181201
}

api/src/main/java/net/labymod/serverapi/api/model/component/ServerAPITextComponent.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,26 @@ public String toString() {
5353
"text='" + this.text + '\'' +
5454
"} " + super.toString();
5555
}
56+
57+
@Override
58+
public boolean equals(Object o) {
59+
if (this == o) {
60+
return true;
61+
}
62+
63+
if (!(o instanceof ServerAPITextComponent that)) {
64+
return false;
65+
}
66+
67+
if (!super.equals(o)) {
68+
return false;
69+
}
70+
71+
return Objects.equals(this.text, that.text);
72+
}
73+
74+
@Override
75+
public int hashCode() {
76+
return Objects.hash(super.hashCode(), this.text);
77+
}
5678
}

core/src/main/java/net/labymod/serverapi/core/AbstractLabyModPlayer.java

Lines changed: 206 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,38 @@
3030
import net.labymod.serverapi.api.packet.Packet;
3131
import net.labymod.serverapi.core.integration.LabyModIntegrationPlayer;
3232
import net.labymod.serverapi.core.integration.LabyModProtocolIntegration;
33+
import net.labymod.serverapi.core.model.display.EconomyDisplay;
3334
import net.labymod.serverapi.core.model.display.Subtitle;
35+
import net.labymod.serverapi.core.model.display.TabListFlag;
3436
import net.labymod.serverapi.core.model.feature.DiscordRPC;
3537
import net.labymod.serverapi.core.model.feature.InteractionMenuEntry;
3638
import net.labymod.serverapi.core.model.moderation.Permission;
39+
import net.labymod.serverapi.core.model.moderation.RecommendedAddon;
3740
import net.labymod.serverapi.core.model.supplement.InputPrompt;
3841
import net.labymod.serverapi.core.model.supplement.ServerSwitchPrompt;
42+
import net.labymod.serverapi.core.packet.clientbound.game.display.EconomyDisplayPacket;
3943
import net.labymod.serverapi.core.packet.clientbound.game.display.SubtitlePacket;
4044
import net.labymod.serverapi.core.packet.clientbound.game.display.TabListBannerPacket;
45+
import net.labymod.serverapi.core.packet.clientbound.game.display.TabListFlagPacket;
4146
import net.labymod.serverapi.core.packet.clientbound.game.feature.DiscordRPCPacket;
4247
import net.labymod.serverapi.core.packet.clientbound.game.feature.InteractionMenuPacket;
4348
import net.labymod.serverapi.core.packet.clientbound.game.feature.PlayingGameModePacket;
49+
import net.labymod.serverapi.core.packet.clientbound.game.feature.marker.AddMarkerPacket;
50+
import net.labymod.serverapi.core.packet.clientbound.game.feature.marker.MarkerPacket;
51+
import net.labymod.serverapi.core.packet.clientbound.game.moderation.AddonRecommendationPacket;
4452
import net.labymod.serverapi.core.packet.clientbound.game.moderation.PermissionPacket;
4553
import net.labymod.serverapi.core.packet.clientbound.game.supplement.InputPromptPacket;
4654
import net.labymod.serverapi.core.packet.clientbound.game.supplement.ServerSwitchPromptPacket;
55+
import net.labymod.serverapi.core.packet.serverbound.game.moderation.AddonRecommendationResponsePacket;
4756
import net.labymod.serverapi.core.packet.serverbound.game.supplement.InputPromptResponsePacket;
4857
import net.labymod.serverapi.core.packet.serverbound.game.supplement.ServerSwitchPromptResponsePacket;
4958
import org.jetbrains.annotations.NotNull;
5059
import org.jetbrains.annotations.Nullable;
5160

5261
import java.util.ArrayList;
62+
import java.util.HashMap;
5363
import java.util.List;
64+
import java.util.Map;
5465
import java.util.Objects;
5566
import java.util.UUID;
5667
import java.util.function.Consumer;
@@ -62,7 +73,10 @@ public abstract class AbstractLabyModPlayer<P extends AbstractLabyModPlayer<?>>
6273
protected final String labyModVersion;
6374
private final AbstractLabyModProtocolService protocolService;
6475
private final List<LabyModIntegrationPlayer> integrationPlayers = new ArrayList<>();
76+
private final Map<String, EconomyDisplay> economies = new HashMap<>(2);
77+
6578
private Subtitle subtitle;
79+
private TabListFlag flag;
6680

6781
protected AbstractLabyModPlayer(
6882
AbstractLabyModProtocolService protocolService,
@@ -125,69 +139,195 @@ protected AbstractLabyModPlayer(
125139
/**
126140
* @return the currently set subtitle
127141
*/
128-
public @Nullable Subtitle getSubtitle() {
142+
public @NotNull Subtitle subtitle() {
143+
if (this.subtitle == null) {
144+
this.subtitle = Subtitle.create(this.uniqueId, null);
145+
}
146+
129147
return this.subtitle;
130148
}
131149

150+
/**
151+
* @return whether the player has a subtitle set
152+
*/
153+
public boolean hasSubtitle() {
154+
return this.subtitle != null && this.subtitle.getText() != null;
155+
}
156+
157+
/**
158+
* Updates the text of the subtitle
159+
*
160+
* @param text The text to set as subtitle
161+
*/
162+
public void updateSubtitle(@NotNull ServerAPIComponent text) {
163+
this.updateSubtitle(subtitle -> subtitle.text(text));
164+
}
165+
132166
/**
133167
* Sets the subtitle of the player and sends it to all other online players
134168
*
135-
* @param component The component to set as subtitle
169+
* @param text The component to set as subtitle
170+
* @param size The size of the subtitle
136171
*/
137-
public void setSubtitle(@NotNull ServerAPIComponent component) {
138-
this.setSubtitle(Subtitle.create(this.uniqueId, component));
172+
public void updateSubtitle(@NotNull ServerAPIComponent text, double size) {
173+
this.updateSubtitle(subtitle -> subtitle.text(text).size(size));
139174
}
140175

141-
public void setSubtitle(@Nullable Subtitle subtitle) {
142-
if (Objects.equals(this.subtitle, subtitle)) {
143-
return;
144-
}
176+
/**
177+
* Resets the subtitle of the player and sends it to all other online players
178+
*/
179+
public void resetSubtitle() {
180+
this.updateSubtitle(subtitle -> subtitle.text(null));
181+
}
145182

146-
this.subtitle = subtitle;
183+
/**
184+
* Updates or creates a new subtitle and calls the consumer
185+
*
186+
* @param consumer The consumer to call
187+
*/
188+
public void updateSubtitle(Consumer<Subtitle> consumer) {
189+
if (this.subtitle == null) {
190+
this.subtitle = Subtitle.create(this.uniqueId, null);
191+
}
147192

148-
List<Subtitle> subtitles = new ArrayList<>();
149-
if (subtitle == null) {
150-
subtitle = Subtitle.create(this.uniqueId, null);
151-
subtitles.add(subtitle);
193+
ServerAPIComponent prevText = this.subtitle.getText();
194+
double prevSize = this.subtitle.getSize();
195+
consumer.accept(this.subtitle);
196+
if (this.subtitle.getSize() == prevSize && Objects.equals(prevText, this.subtitle.getText())) {
197+
return;
152198
}
153199

154200
LabyModProtocol labyModProtocol = this.protocolService.labyModProtocol();
155-
SubtitlePacket packet = new SubtitlePacket(subtitle);
201+
SubtitlePacket packet = new SubtitlePacket(this.subtitle);
156202
for (AbstractLabyModPlayer<?> player : this.protocolService.getPlayers()) {
157-
Subtitle playerSubtitle = player.getSubtitle();
158-
if (playerSubtitle != null) {
159-
subtitles.add(playerSubtitle);
160-
}
203+
labyModProtocol.sendPacket(player.getUniqueId(), packet);
204+
}
205+
}
161206

162-
if (player.equals(this)) {
163-
continue;
164-
}
207+
/**
208+
* Gives LabyMod the instruction to send placed markers by the player as
209+
* {@link net.labymod.serverapi.core.packet.serverbound.game.feature.marker.ClientAddMarkerPacket}
210+
*
211+
* @param sendType the way the client will send markers. See {@link MarkerPacket.MarkerSendType}
212+
*/
213+
public void sendMarkerSendType(MarkerPacket.MarkerSendType sendType) {
214+
this.sendPacket(new MarkerPacket(sendType));
215+
}
216+
217+
/**
218+
* Sends a marker to the player
219+
*
220+
* @param sender The unique identifier of the sender
221+
* @param x The x coordinate of the marker
222+
* @param y The y coordinate of the marker
223+
* @param z The z coordinate of the marker
224+
* @param large Whether the marker should be large
225+
* @param target The unique identifier of the target player or null
226+
*/
227+
public void sendMarker(
228+
@NotNull UUID sender,
229+
int x,
230+
int y,
231+
int z,
232+
boolean large,
233+
@Nullable UUID target
234+
) {
235+
this.sendPacket(new AddMarkerPacket(sender, x, y, z, large, target));
236+
}
237+
238+
/**
239+
* @return the tab list flag of the player or null if not set
240+
*/
241+
public @Nullable TabListFlag getTabListFlag() {
242+
return this.flag;
243+
}
165244

245+
/**
246+
* Sets the country code for the
247+
* {@link net.labymod.serverapi.core.packet.clientbound.game.display.TabListFlagPacket}. This
248+
* will send the country code to every player on the server.
249+
*
250+
* @param countryCode the country code to send
251+
*/
252+
public void setTabListFlag(@NotNull TabListFlag.TabListFlagCountryCode countryCode) {
253+
this.flag = TabListFlag.create(this.uniqueId, countryCode);
254+
LabyModProtocol labyModProtocol = this.protocolService.labyModProtocol();
255+
TabListFlagPacket packet = new TabListFlagPacket(this.flag);
256+
for (AbstractLabyModPlayer<?> player : this.protocolService.getPlayers()) {
166257
labyModProtocol.sendPacket(player.getUniqueId(), packet);
167258
}
259+
}
168260

169-
if (subtitles.isEmpty()) {
170-
return;
171-
}
261+
/**
262+
* @return The display for the bank economy
263+
*/
264+
public @NotNull EconomyDisplay bankEconomy() {
265+
return this.economies.computeIfAbsent("bank", EconomyDisplay::new);
266+
}
172267

173-
this.sendLabyModPacket(new SubtitlePacket(subtitles));
268+
/**
269+
* @return The display for the cash economy
270+
*/
271+
public @NotNull EconomyDisplay cashEconomy() {
272+
return this.economies.computeIfAbsent("cash", EconomyDisplay::new);
174273
}
175274

176275
/**
177-
* Sets the subtitle of the player and sends it to all other online players
276+
* Gets the economy display for the provided key
178277
*
179-
* @param component The component to set as subtitle
180-
* @param size The size of the subtitle
278+
* @param key The key of the economy display
279+
* @return The economy display or null if not found
181280
*/
182-
public void setSubtitle(@NotNull ServerAPIComponent component, double size) {
183-
this.setSubtitle(Subtitle.create(this.uniqueId, component, size));
281+
public @Nullable EconomyDisplay getEconomy(@NotNull String key) {
282+
Objects.requireNonNull(key, "Key cannot be null");
283+
return this.economies.get(key);
184284
}
185285

186286
/**
187-
* Resets the subtitle of the player and sends it to all other online players
287+
* Gets or creates the economy display for the provided key, calls the consumer and sends
288+
* {@link EconomyDisplayPacket} to the player
289+
*
290+
* @param key The key of the economy display
291+
* @param consumer The consumer to call
188292
*/
189-
public void resetSubtitle() {
190-
this.setSubtitle((Subtitle) null);
293+
public void updateEconomy(@NotNull String key, @NotNull Consumer<EconomyDisplay> consumer) {
294+
Objects.requireNonNull(key, "Key cannot be null");
295+
Objects.requireNonNull(consumer, "Consumer cannot be null");
296+
297+
EconomyDisplay display = this.economies.computeIfAbsent(key, EconomyDisplay::new);
298+
consumer.accept(display);
299+
this.sendLabyModPacket(new EconomyDisplayPacket(display));
300+
}
301+
302+
/**
303+
* Gets or creates the display for the bank economy, calls the consumer and sends
304+
* {@link EconomyDisplayPacket} to the player
305+
*
306+
* @param consumer The consumer to call
307+
*/
308+
public void updateBankEconomy(@NotNull Consumer<EconomyDisplay> consumer) {
309+
this.updateEconomy("bank", consumer);
310+
}
311+
312+
/**
313+
* Gets or creates the display for the cash economy, calls the consumer and sends
314+
* {@link EconomyDisplayPacket} to the player
315+
*
316+
* @param consumer The consumer to call
317+
*/
318+
public void updateCashEconomy(@NotNull Consumer<EconomyDisplay> consumer) {
319+
this.updateEconomy("cash", consumer);
320+
}
321+
322+
/**
323+
* Sends the provided economy display to the player and stores it, so that it can be accessed
324+
* via {@link #getEconomy(String)}
325+
*
326+
* @param display The economy display to send
327+
*/
328+
public void sendEconomy(EconomyDisplay display) {
329+
this.economies.put(display.getKey(), display);
330+
this.sendLabyModPacket(new EconomyDisplayPacket(display));
191331
}
192332

193333
/**
@@ -328,11 +468,42 @@ public void openServerSwitchPrompt(
328468
);
329469
}
330470

331-
private void sendLabyModPacket(@NotNull Packet packet) {
471+
/**
472+
* Sends the provided recommended addons to the player
473+
*
474+
* @param addons The recommended addons
475+
*/
476+
public void sendAddonRecommendations(@NotNull List<RecommendedAddon> addons) {
477+
this.sendLabyModPacket(new AddonRecommendationPacket(addons));
478+
}
479+
480+
/**
481+
* Sends the provided recommended addons to the player and handle the response via the provided
482+
* consumer
483+
*
484+
* @param addons The recommended addons
485+
* @param responseConsumer The consumer for the response
486+
*/
487+
public void sendAddonRecommendations(
488+
@NotNull List<RecommendedAddon> addons,
489+
@NotNull Consumer<AddonRecommendationResponsePacket> responseConsumer
490+
) {
491+
Objects.requireNonNull(responseConsumer, "Response consumer cannot be null");
492+
this.sendLabyModPacket(
493+
new AddonRecommendationPacket(addons),
494+
AddonRecommendationResponsePacket.class,
495+
response -> {
496+
responseConsumer.accept(response);
497+
return response.isInitial();
498+
}
499+
);
500+
}
501+
502+
protected void sendLabyModPacket(@NotNull Packet packet) {
332503
this.protocolService.labyModProtocol.sendPacket(this.uniqueId, packet);
333504
}
334505

335-
private <T extends IdentifiablePacket> void sendLabyModPacket(
506+
protected <T extends IdentifiablePacket> void sendLabyModPacket(
336507
@NotNull IdentifiablePacket packet,
337508
@NotNull Class<T> responseClass,
338509
@NotNull Predicate<T> responseConsumer

0 commit comments

Comments
 (0)