2121import org .bukkit .Bukkit ;
2222import org .bukkit .Location ;
2323import org .bukkit .Material ;
24+ import org .bukkit .World ;
2425import org .bukkit .entity .Player ;
2526import org .bukkit .inventory .ItemStack ;
2627import org .bukkit .util .Vector ;
@@ -40,6 +41,7 @@ public final class PerformanceScene {
4041 private static final int MAX_ITEMS = 8_192 ;
4142 private static final long MAX_LIFETIME_TICKS = 12_000L ;
4243 private static final Map <UUID , Set <VisualizerEntity >> scenes = new HashMap <>();
44+ private static final Map <UUID , Set <org .bukkit .entity .Item >> droppedScenes = new HashMap <>();
4345
4446 private PerformanceScene () {
4547 }
@@ -121,6 +123,44 @@ public static int spawnDisplay(Player owner, boolean text, int requestedCount,
121123 return count ;
122124 }
123125
126+ /** Creates real Paper Item entities for the dropped-label runtime factor. */
127+ public static int spawnDroppedItems (Player owner , int requestedCount ,
128+ long requestedLifetimeTicks ) {
129+ int count = Math .max (1 , Math .min (MAX_ITEMS , requestedCount ));
130+ long lifetimeTicks = Math .max (1L , Math .min (MAX_LIFETIME_TICKS , requestedLifetimeTicks ));
131+ clear (owner );
132+
133+ World world = owner .getWorld ();
134+ Location center = owner .getLocation ().add (0.0D , 1.5D , 0.0D );
135+ int width = (int ) Math .ceil (Math .sqrt (count ));
136+ double spacing = 1.25D ;
137+ double offset = (width - 1 ) * spacing / 2.0D ;
138+ Set <org .bukkit .entity .Item > items = new HashSet <>(count );
139+ for (int index = 0 ; index < count ; index ++) {
140+ double x = center .getX () + index % width * spacing - offset ;
141+ double z = center .getZ () + index / width * spacing - offset ;
142+ Location location = new Location (world , x , center .getY (), z );
143+ location .getChunk ().load ();
144+ ItemStack stack = new ItemStack (Material .STONE , index % 64 + 1 );
145+ int ordinal = index ;
146+ stack .editMeta (meta -> meta .customName (Component .text ("iv-dropped-benchmark-" + ordinal )));
147+ org .bukkit .entity .Item item = world .dropItem (location , stack , entity -> {
148+ entity .setGravity (false );
149+ entity .setVelocity (new Vector ());
150+ entity .setPickupDelay (Short .MAX_VALUE - 1 );
151+ entity .setUnlimitedLifetime (true );
152+ entity .setPersistent (false );
153+ });
154+ items .add (item );
155+ }
156+
157+ UUID ownerId = owner .getUniqueId ();
158+ droppedScenes .put (ownerId , items );
159+ Scheduler .runTaskLater (InteractionVisualizer .plugin ,
160+ () -> expireDropped (ownerId , items ), lifetimeTicks , owner .getLocation ());
161+ return count ;
162+ }
163+
124164 public static void clear (Player owner ) {
125165 clear (owner .getUniqueId ());
126166 }
@@ -131,6 +171,10 @@ public static void clear(UUID ownerId) {
131171 if (previous != null ) {
132172 removeEntities (previous );
133173 }
174+ Set <org .bukkit .entity .Item > dropped = droppedScenes .remove (ownerId );
175+ if (dropped != null ) {
176+ removeDroppedItems (dropped );
177+ }
134178 }
135179
136180 /** Deterministically removes every disposable benchmark scene. */
@@ -140,10 +184,15 @@ public static void shutdown() {
140184 for (Set <VisualizerEntity > entities : remaining ) {
141185 removeEntities (entities );
142186 }
187+ List <Set <org .bukkit .entity .Item >> remainingDropped = new ArrayList <>(droppedScenes .values ());
188+ droppedScenes .clear ();
189+ for (Set <org .bukkit .entity .Item > items : remainingDropped ) {
190+ removeDroppedItems (items );
191+ }
143192 }
144193
145194 public static int retainedStateCount () {
146- return scenes .size ();
195+ return scenes .size () + droppedScenes . size () ;
147196 }
148197
149198 private static void expire (UUID ownerId , Set <VisualizerEntity > entities ) {
@@ -152,6 +201,12 @@ private static void expire(UUID ownerId, Set<VisualizerEntity> entities) {
152201 }
153202 }
154203
204+ private static void expireDropped (UUID ownerId , Set <org .bukkit .entity .Item > items ) {
205+ if (droppedScenes .remove (ownerId , items )) {
206+ removeDroppedItems (items );
207+ }
208+ }
209+
155210 private static void removeEntities (Set <VisualizerEntity > entities ) {
156211 for (VisualizerEntity entity : entities ) {
157212 if (entity instanceof Item item ) {
@@ -161,4 +216,12 @@ private static void removeEntities(Set<VisualizerEntity> entities) {
161216 }
162217 }
163218 }
219+
220+ private static void removeDroppedItems (Set <org .bukkit .entity .Item > items ) {
221+ for (org .bukkit .entity .Item item : items ) {
222+ if (item .isValid ()) {
223+ item .remove ();
224+ }
225+ }
226+ }
164227}
0 commit comments