2121import com .loohp .interactionvisualizer .managers .PerformanceMetrics ;
2222import com .loohp .interactionvisualizer .objectholders .EntryKey ;
2323import com .loohp .interactionvisualizer .utils .ChatColorUtils ;
24- import com .loohp .interactionvisualizer .utils .ComponentFont ;
2524import com .loohp .interactionvisualizer .utils .ItemNameUtils ;
25+ import com .loohp .interactionvisualizer .utils .LegacyTextComponentCache ;
2626import com .loohp .interactionvisualizer .scheduler .ScheduledRunnable ;
2727import com .loohp .interactionvisualizer .scheduler .ScheduledTask ;
2828import com .loohp .interactionvisualizer .scheduler .Scheduler ;
2929import net .kyori .adventure .text .Component ;
3030import net .kyori .adventure .text .TextReplacementConfig ;
3131import net .kyori .adventure .text .format .NamedTextColor ;
32- import net .kyori .adventure .text .serializer .legacy .LegacyComponentSerializer ;
3332import net .kyori .adventure .text .serializer .plain .PlainTextComponentSerializer ;
3433import org .bukkit .Bukkit ;
3534import org .bukkit .Color ;
@@ -81,6 +80,7 @@ public final class DroppedItemDisplay extends VisualizerRunnableDisplay implemen
8180 private final Map <UUID , Item > trackedItems = new HashMap <>();
8281 private final Map <UUID , TextDisplay > labels = new HashMap <>();
8382 private final Set <UUID > eligibleViewers = new HashSet <>();
83+ private final Map <UUID , Player > desiredViewers = new HashMap <>();
8484 private final Map <UUID , VisibilityState > visibilityStates = new HashMap <>();
8585
8686 private String regularFormatting ;
@@ -95,6 +95,7 @@ public final class DroppedItemDisplay extends VisualizerRunnableDisplay implemen
9595 private int ticksUntilUpdate ;
9696 private int despawnTicks = 6000 ;
9797 private DroppedItemVisibilityPolicy visibilityPolicy = DroppedItemVisibilityPolicy .legacyDefaults ();
98+ private boolean visibilityQueuesPending ;
9899 private boolean stripColorBlacklist ;
99100 private DroppedItemBlacklist blacklist = DroppedItemBlacklist .compile (List .of (), DroppedItemDisplay ::warn );
100101
@@ -448,30 +449,32 @@ private static void setLabelVerticalTranslation(TextDisplay label, float targetY
448449 }
449450
450451 private Collection <Player > reconcileEligibleViewers () {
451- Map < UUID , Player > desired = new HashMap <> ();
452+ desiredViewers . clear ();
452453 for (Player player : InteractionVisualizerAPI .getPlayerModuleList (Modules .HOLOGRAM , KEY )) {
453454 if (player .isOnline ()) {
454- desired .put (player .getUniqueId (), player );
455+ desiredViewers .put (player .getUniqueId (), player );
455456 }
456457 }
457- for (UUID uuid : new HashSet <>(eligibleViewers )) {
458- if (!desired .containsKey (uuid )) {
458+ Iterator <UUID > eligibleIterator = eligibleViewers .iterator ();
459+ while (eligibleIterator .hasNext ()) {
460+ UUID uuid = eligibleIterator .next ();
461+ if (!desiredViewers .containsKey (uuid )) {
459462 Player player = Bukkit .getPlayer (uuid );
460463 if (visibilityPolicy .controlsPerViewerVisibility ()) {
461464 removeVisibilityState (uuid , player );
462465 } else if (player != null ) {
463466 setAllLabelsVisible (player , false );
464467 }
465- eligibleViewers .remove (uuid );
468+ eligibleIterator .remove ();
466469 }
467470 }
468- for (Map .Entry <UUID , Player > entry : desired .entrySet ()) {
471+ for (Map .Entry <UUID , Player > entry : desiredViewers .entrySet ()) {
469472 if (eligibleViewers .add (entry .getKey ())
470473 && !visibilityPolicy .controlsPerViewerVisibility ()) {
471474 setAllLabelsVisible (entry .getValue (), true );
472475 }
473476 }
474- return desired .values ();
477+ return desiredViewers .values ();
475478 }
476479
477480 private void switchVisibilityMode (boolean controlled ) {
@@ -485,6 +488,7 @@ private void switchVisibilityMode(boolean controlled) {
485488 state .pending .clear ();
486489 }
487490 visibilityStates .clear ();
491+ visibilityQueuesPending = false ;
488492 }
489493
490494 private void showToEligibleViewers (TextDisplay label ) {
@@ -519,7 +523,8 @@ private void reconcileLabelVisibility(Collection<Player> viewers, List<TrackedIt
519523 UUID playerId = player .getUniqueId ();
520524 VisibilityState state = visibilityStates .computeIfAbsent (playerId ,
521525 ignored -> new VisibilityState (visibilityPolicy .bucketSize ()));
522- Set <UUID > desired = new HashSet <>();
526+ Set <UUID > desired = state .nextDesired ;
527+ desired .clear ();
523528 Location playerLocation = player .getLocation ();
524529 int trackingDistance = InteractionVisualizer .playerTrackingRange
525530 .getOrDefault (player .getWorld (), DEFAULT_TRACKING_DISTANCE );
@@ -546,49 +551,65 @@ private void reconcileLabelVisibility(Collection<Player> viewers, List<TrackedIt
546551 }
547552 }
548553
549- for (UUID itemId : new HashSet <>(state .shown )) {
554+ Iterator <UUID > shownIterator = state .shown .iterator ();
555+ while (shownIterator .hasNext ()) {
556+ UUID itemId = shownIterator .next ();
550557 if (!desired .contains (itemId )) {
551558 TextDisplay label = labels .get (itemId );
552559 if (label != null && label .isValid ()) {
553560 setLabelVisible (player , label , false );
554561 }
555- state . shown . remove (itemId );
562+ shownIterator . remove ();
556563 }
557564 }
558565 for (UUID itemId : state .desired ) {
559566 if (!desired .contains (itemId )) {
560567 state .pending .cancel (itemId );
561568 }
562569 }
570+ state .nextDesired = state .desired ;
563571 state .desired = desired ;
564572 for (UUID itemId : desired ) {
565573 if (!state .shown .contains (itemId )) {
566574 state .pending .request (itemId );
575+ visibilityQueuesPending = true ;
567576 }
568577 }
569578 }
570579 }
571580
572581 private void drainVisibilityQueues () {
582+ if (!visibilityQueuesPending ) {
583+ return ;
584+ }
585+ boolean stillPending = false ;
573586 for (Map .Entry <UUID , VisibilityState > entry : visibilityStates .entrySet ()) {
574587 Player player = Bukkit .getPlayer (entry .getKey ());
575588 VisibilityState state = entry .getValue ();
576589 if (player == null || !player .isOnline () || !eligibleViewers .contains (entry .getKey ())) {
590+ state .pending .clear ();
577591 continue ;
578592 }
579- List <UUID > ready = visibilityPolicy .rateLimitEnabled ()
580- ? state .pending .drain (
581- visibilityPolicy .bucketSize (), visibilityPolicy .restorePerTick (),
582- id -> isPendingVisibilityWanted (state , id ))
583- : state .pending .drainAll (id -> isPendingVisibilityWanted (state , id ));
593+ List <UUID > ready = state .ready ;
594+ ready .clear ();
595+ if (visibilityPolicy .rateLimitEnabled ()) {
596+ state .pending .drainInto (
597+ visibilityPolicy .bucketSize (), visibilityPolicy .restorePerTick (),
598+ id -> isPendingVisibilityWanted (state , id ), ready );
599+ } else {
600+ state .pending .drainAllInto (id -> isPendingVisibilityWanted (state , id ), ready );
601+ }
584602 for (UUID itemId : ready ) {
585603 TextDisplay label = labels .get (itemId );
586604 if (label != null && label .isValid ()) {
587605 setLabelVisible (player , label , true );
588606 state .shown .add (itemId );
589607 }
590608 }
609+ ready .clear ();
610+ stillPending |= state .pending .hasPending ();
591611 }
612+ visibilityQueuesPending = stillPending ;
592613 }
593614
594615 private boolean isPendingVisibilityWanted (VisibilityState state , UUID itemId ) {
@@ -627,7 +648,7 @@ private Component format(ItemStack stack, int ticksLeft) {
627648 template = amount == 1 ? singularFormatting : regularFormatting ;
628649 }
629650 String rendered = template .replace ("{Amount}" , Integer .toString (amount )).replace ("{Timer}" , timer );
630- Component component = ComponentFont . parseFont ( LegacyComponentSerializer . legacySection (). deserialize ( rendered ) );
651+ Component component = LegacyTextComponentCache . parse ( rendered );
631652 return component .replaceText (TextReplacementConfig .builder ()
632653 .matchLiteral ("{Item}" )
633654 .replacement (ItemNameUtils .getDisplayName (stack ))
@@ -708,8 +729,10 @@ private record TrackedItem(UUID itemId, Item item, UUID worldId, Location locati
708729 private static final class VisibilityState {
709730
710731 private Set <UUID > desired = new HashSet <>();
732+ private Set <UUID > nextDesired = new HashSet <>();
711733 private final Set <UUID > shown = new HashSet <>();
712734 private final VisibilityTokenBucket <UUID > pending ;
735+ private final List <UUID > ready = new ArrayList <>();
713736
714737 private VisibilityState (int initialTokens ) {
715738 this .pending = new VisibilityTokenBucket <>(initialTokens );
0 commit comments