3030import net .labymod .serverapi .api .packet .Packet ;
3131import net .labymod .serverapi .core .integration .LabyModIntegrationPlayer ;
3232import net .labymod .serverapi .core .integration .LabyModProtocolIntegration ;
33+ import net .labymod .serverapi .core .model .display .EconomyDisplay ;
3334import net .labymod .serverapi .core .model .display .Subtitle ;
35+ import net .labymod .serverapi .core .model .display .TabListFlag ;
3436import net .labymod .serverapi .core .model .feature .DiscordRPC ;
3537import net .labymod .serverapi .core .model .feature .InteractionMenuEntry ;
3638import net .labymod .serverapi .core .model .moderation .Permission ;
39+ import net .labymod .serverapi .core .model .moderation .RecommendedAddon ;
3740import net .labymod .serverapi .core .model .supplement .InputPrompt ;
3841import net .labymod .serverapi .core .model .supplement .ServerSwitchPrompt ;
42+ import net .labymod .serverapi .core .packet .clientbound .game .display .EconomyDisplayPacket ;
3943import net .labymod .serverapi .core .packet .clientbound .game .display .SubtitlePacket ;
4044import net .labymod .serverapi .core .packet .clientbound .game .display .TabListBannerPacket ;
45+ import net .labymod .serverapi .core .packet .clientbound .game .display .TabListFlagPacket ;
4146import net .labymod .serverapi .core .packet .clientbound .game .feature .DiscordRPCPacket ;
4247import net .labymod .serverapi .core .packet .clientbound .game .feature .InteractionMenuPacket ;
4348import 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 ;
4452import net .labymod .serverapi .core .packet .clientbound .game .moderation .PermissionPacket ;
4553import net .labymod .serverapi .core .packet .clientbound .game .supplement .InputPromptPacket ;
4654import net .labymod .serverapi .core .packet .clientbound .game .supplement .ServerSwitchPromptPacket ;
55+ import net .labymod .serverapi .core .packet .serverbound .game .moderation .AddonRecommendationResponsePacket ;
4756import net .labymod .serverapi .core .packet .serverbound .game .supplement .InputPromptResponsePacket ;
4857import net .labymod .serverapi .core .packet .serverbound .game .supplement .ServerSwitchPromptResponsePacket ;
4958import org .jetbrains .annotations .NotNull ;
5059import org .jetbrains .annotations .Nullable ;
5160
5261import java .util .ArrayList ;
62+ import java .util .HashMap ;
5363import java .util .List ;
64+ import java .util .Map ;
5465import java .util .Objects ;
5566import java .util .UUID ;
5667import 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