2525 */
2626public class Item extends VisualizerEntity {
2727
28+ /**
29+ * Rendering presentation for one logical item.
30+ *
31+ * <p>{@link #DROPPED} preserves the Furnace/Sparrow fake-item path. The
32+ * remaining modes use a fixed Paper ItemDisplay while sharing the same
33+ * logical lifecycle, viewer filtering, updates, and removal API.</p>
34+ */
35+ public enum RenderMode {
36+ DROPPED ,
37+ ITEM ,
38+ BLOCK ,
39+ LOW_BLOCK ,
40+ TOOL ,
41+ STANDING ,
42+ BANNER ,
43+ FRAME ;
44+
45+ public boolean isFixedDisplay () {
46+ return this != DROPPED ;
47+ }
48+ }
49+
2850 private ItemStack item ;
51+ private RenderMode renderMode ;
52+ private int frameRotation ;
2953 private boolean gravity ;
3054 private boolean glowing ;
3155 private int pickupDelay ;
@@ -36,12 +60,53 @@ public class Item extends VisualizerEntity {
3660 private Vector velocity ;
3761
3862 public Item (Location location ) {
63+ this (location , RenderMode .DROPPED );
64+ }
65+
66+ public Item (Location location , RenderMode renderMode ) {
3967 super (location );
40- this .item = ItemStack .of (Material .STONE );
68+ this .renderMode = java .util .Objects .requireNonNull (renderMode , "renderMode" );
69+ this .item = renderMode .isFixedDisplay () ? ItemStack .empty () : ItemStack .of (Material .STONE );
4170 this .gravity = false ;
4271 this .velocity = new Vector ();
4372 }
4473
74+ public RenderMode getRenderMode () {
75+ return renderMode ;
76+ }
77+
78+ public void setRenderMode (RenderMode renderMode ) {
79+ if (lock ) {
80+ return ;
81+ }
82+ RenderMode value = java .util .Objects .requireNonNull (renderMode , "renderMode" );
83+ if (this .renderMode != value ) {
84+ this .renderMode = value ;
85+ if (!value .isFixedDisplay () && item .isEmpty ()) {
86+ item = ItemStack .of (Material .STONE );
87+ }
88+ markDirty ();
89+ }
90+ }
91+
92+ public boolean isFixedDisplay () {
93+ return renderMode .isFixedDisplay ();
94+ }
95+
96+ public int getFrameRotation () {
97+ return frameRotation ;
98+ }
99+
100+ public void setFrameRotation (int frameRotation ) {
101+ if (frameRotation < 0 || frameRotation > 7 ) {
102+ throw new IllegalArgumentException ("Item frame rotation must be between 0 and 7" );
103+ }
104+ if (!lock && this .frameRotation != frameRotation ) {
105+ this .frameRotation = frameRotation ;
106+ markDirty ();
107+ }
108+ }
109+
45110 public Component getCustomName () {
46111 return customName ;
47112 }
@@ -115,7 +180,9 @@ public void setItemStack(ItemStack item) {
115180 }
116181
117182 private void setItemInternal (ItemStack value ) {
118- ItemStack normalized = value == null || value .isEmpty () ? ItemStack .of (Material .STONE ) : value .clone ();
183+ ItemStack normalized = value == null || value .isEmpty ()
184+ ? (renderMode .isFixedDisplay () ? ItemStack .empty () : ItemStack .of (Material .STONE ))
185+ : value .clone ();
119186 if (!item .equals (normalized )) {
120187 item = normalized ;
121188 markDirty ();
@@ -163,6 +230,7 @@ public void setPickupDelay(int pickupDelay) {
163230
164231 @ Override
165232 public double getHeight () {
166- return 0.25 ;
233+ return renderMode == RenderMode .BANNER ? 1.5
234+ : (renderMode == RenderMode .FRAME ? 0.75 : (renderMode .isFixedDisplay () ? 0.5 : 0.25 ));
167235 }
168236}
0 commit comments