Skip to content

Commit 02943e4

Browse files
authored
feat: display entity API docs (#394)
1 parent 54e08ee commit 02943e4

File tree

7 files changed

+249
-2
lines changed

7 files changed

+249
-2
lines changed

config/sidebar.paper.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ const paper: SidebarsConfig = {
125125
"dev/api/event-api/chat-event",
126126
],
127127
},
128+
{
129+
type: "category",
130+
label: "Entity API",
131+
collapsed: true,
132+
items: ["dev/api/entity-api/entity-teleport", "dev/api/entity-api/display-entities"],
133+
},
128134
{
129135
type: "category",
130136
label: "Component API (Adventure)",
@@ -139,7 +145,6 @@ const paper: SidebarsConfig = {
139145
"dev/api/custom-inventory-holder",
140146
"dev/api/commands",
141147
"dev/api/scheduler",
142-
"dev/api/entity-teleport",
143148
"dev/api/plugin-messaging",
144149
"dev/api/plugin-configs",
145150
"dev/api/lifecycle",
127 KB
Loading
94.4 KB
Loading
61.8 KB
Loading
78.6 KB
Loading
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
---
2+
slug: /dev/display-entities
3+
description: The display entity API and how to use it.
4+
---
5+
6+
# Display Entities
7+
8+
Added in 1.19.4, [display entities](https://minecraft.wiki/w/Display) are a powerful way to display
9+
various things in the world, like blocks, items and text.
10+
11+
By default, these entities have no hitbox, don't move, make sounds or take damage,
12+
making them the perfect for all kinds of applications, like holograms.
13+
14+
## Types
15+
16+
### Text
17+
18+
Text can be displayed via a <Javadoc name={"org.bukkit.entity.TextDisplay"}>`TextDisplay`</Javadoc>
19+
entity.
20+
21+
```java
22+
TextDisplay display = world.spawn(location, TextDisplay.class, entity -> {
23+
// customize the entity!
24+
entity.text(Component.text("Some awesome content", NamedTextColor.BLACK));
25+
entity.setBillboard(Display.Billboard.VERTICAL); // pivot only around the vertical axis
26+
entity.setBackgroundColor(Color.RED); // make the background red
27+
28+
// see the Display and TextDisplay Javadoc, there are many more options
29+
});
30+
```
31+
32+
### Blocks
33+
34+
Blocks can be displayed via a <Javadoc name={"org.bukkit.entity.BlockDisplay"}>`BlockDisplay`</Javadoc>
35+
entity.
36+
37+
```java
38+
BlockDisplay display = world.spawn(location, BlockDisplay.class, entity -> {
39+
// customize the entity!
40+
entity.setBlock(Material.GRASS_BLOCK.createBlockData());
41+
});
42+
```
43+
44+
### Items
45+
46+
Items can be displayed via an <Javadoc name={"org.bukkit.entity.ItemDisplay"}>`ItemDisplay`</Javadoc>
47+
entity.
48+
49+
Despite its name, an _item_ display can also display _blocks_, with the difference being the
50+
position in the model - an item display has its position in the center, whereas a block display has
51+
its position in the corner of the block (this can be seen with the hitbox debug mode - F3+B).
52+
53+
```java
54+
ItemDisplay display = world.spawn(location, ItemDisplay.class, entity -> {
55+
// customize the entity!
56+
entity.setItemStack(new ItemStack(Material.SKELETON_SKULL));
57+
});
58+
```
59+
60+
## Transformation
61+
62+
Displays can have an arbitrary affine transformation applied to them, allowing you to position and
63+
warp them as you choose in 3D space.
64+
65+
Transformations are applied to the display in this order:
66+
67+
```mermaid
68+
flowchart LR;
69+
translation[Translation]-->left_rotation[Left rotation];
70+
left_rotation-->scale[Scale];
71+
scale-->right_rotation[Right rotation];
72+
```
73+
74+
:::tip[Visualizing transformations]
75+
76+
Use the [Transformation Visualizer](https://misode.github.io/transformation/) website to visualize
77+
a transformation for quick prototyping!
78+
79+
:::
80+
81+
### Scale
82+
83+
The most basic transformation is scaling, let's take a grass block and scale it up:
84+
85+
```java
86+
world.spawn(location, BlockDisplay.class, entity -> {
87+
entity.setBlock(Material.GRASS_BLOCK.createBlockData());
88+
entity.setTransformation(
89+
new Transformation(
90+
new Vector3f(), // no translation
91+
new AxisAngle4f(), // no left rotation
92+
new Vector3f(2, 2, 2), // scale up by a factor of 2 on all axes
93+
new AxisAngle4f() // no right rotation
94+
)
95+
);
96+
// or set a raw transformation matrix from JOML
97+
// entity.setTransformationMatrix(
98+
// new Matrix4f()
99+
// .scale(2) // scale up by a factor of 2 on all axes
100+
// );
101+
});
102+
```
103+
104+
![Scaling example](./assets/display-scale.png)
105+
106+
### Rotation
107+
108+
You can also rotate it, let's tip it on its corner:
109+
110+
```java
111+
world.spawn(location, BlockDisplay.class, entity -> {
112+
entity.setBlock(Material.GRASS_BLOCK.createBlockData());
113+
entity.setTransformation(
114+
new Transformation(
115+
new Vector3f(), // no translation
116+
// highlight-next-line
117+
new AxisAngle4f((float) -Math.toRadians(45), 1, 0, 0), // rotate -45 degrees on the X axis
118+
new Vector3f(2, 2, 2), // scale up by a factor of 2 on all axes
119+
// highlight-next-line
120+
new AxisAngle4f((float) Math.toRadians(45), 0, 0, 1) // rotate +45 degrees on the Z axis
121+
)
122+
);
123+
// or set a raw transformation matrix from JOML
124+
// entity.setTransformationMatrix(
125+
// new Matrix4f()
126+
// .scale(2) // scale up by a factor of 2 on all axes
127+
// highlight-start
128+
// .rotateXYZ(
129+
// (float) Math.toRadians(360 - 45), // rotate -45 degrees on the X axis
130+
// 0,
131+
// (float) Math.toRadians(45) // rotate +45 degrees on the Z axis
132+
// )
133+
// highlight-end
134+
// );
135+
});
136+
```
137+
138+
![Rotation example](./assets/display-rotation.png)
139+
140+
### Translation
141+
142+
Finally, we can also apply a translation transformation (position offset) to the display, for example:
143+
144+
```java
145+
world.spawn(location, BlockDisplay.class, entity -> {
146+
entity.setBlock(Material.GRASS_BLOCK.createBlockData());
147+
entity.setTransformation(
148+
new Transformation(
149+
// highlight-next-line
150+
new Vector3f(0.5F, 0.5F, 0.5F), // offset by half a block on all axes
151+
new AxisAngle4f((float) -Math.toRadians(45), 1, 0, 0), // rotate -45 degrees on the X axis
152+
new Vector3f(2, 2, 2), // scale up by a factor of 2 on all axes
153+
new AxisAngle4f((float) Math.toRadians(45), 0, 0, 1) // rotate +45 degrees on the Z axis
154+
)
155+
);
156+
// or set a raw transformation matrix from JOML
157+
// entity.setTransformationMatrix(
158+
// new Matrix4f()
159+
// highlight-next-line
160+
// .translate(0.5F, 0.5F, 0.5F) // offset by half a block on all axes
161+
// .scale(2) // scale up by a factor of 2 on all axes
162+
// .rotateXYZ(
163+
// (float) Math.toRadians(360 - 45), // rotate -45 degrees on the X axis
164+
// 0,
165+
// (float) Math.toRadians(45) // rotate +45 degrees on the Z axis
166+
// )
167+
// );
168+
});
169+
```
170+
171+
![Translation example](./assets/display-trans.png)
172+
173+
## Interpolation
174+
175+
A transformation can be linearly interpolated by the client to create a smooth animation,
176+
switching from one transformation to the next.
177+
178+
An example of this would be smoothly rotating a block/item/text in-place. In conjunction with the
179+
[Scheduler API](../scheduler.mdx), the animation can be restarted after it's done,
180+
making the display spin indefinitely:
181+
182+
```java
183+
ItemDisplay display = location.getWorld().spawn(location, ItemDisplay.class, entity -> {
184+
entity.setItemStack(new ItemStack(Material.GOLDEN_SWORD));
185+
});
186+
187+
int duration = 5 * 20; // duration of half a revolution (5 * 20 ticks = 5 seconds)
188+
189+
Matrix4f mat = new Matrix4f().scale(0.5F); // scale to 0.5x - smaller item
190+
Bukkit.getScheduler().runTaskTimer(plugin, task -> {
191+
if (!display.isValid()) { // display was removed from the world, abort task
192+
task.cancel();
193+
return;
194+
}
195+
196+
display.setTransformationMatrix(mat.rotateY(((float) Math.toRadians(180)) + 0.1F /* prevent the client from interpolating in reverse */));
197+
display.setInterpolationDelay(0); // no delay to the interpolation
198+
display.setInterpolationDuration(duration); // set the duration of the interpolated rotation
199+
}, 1 /* delay the initial transformation by one tick from display creation */, duration);
200+
```
201+
202+
![Interpolation example](./assets/display-interp.gif)
203+
204+
## Use cases
205+
206+
Displays have many different use cases, ranging from stationary decoration to complex animation.
207+
208+
A popular, simple use case is to make a decoration that's visible to only specific players,
209+
which can be achieved using standard entity API - <Javadoc name={"org.bukkit.entity.Entity#setVisibleByDefault(boolean)"}>`Entity#setVisibleByDefault()`</Javadoc>
210+
and <Javadoc name={"org.bukkit.entity.Player#showEntity(org.bukkit.plugin.Plugin,org.bukkit.entity.Entity)"}>`Player#showEntity()`</Javadoc>/
211+
<Javadoc name={"org.bukkit.entity.Player#hideEntity(org.bukkit.plugin.Plugin,org.bukkit.entity.Entity)"}>`Player#hideEntity()`</Javadoc>.
212+
213+
:::warning
214+
215+
If the display is only used temporarily, its persistence can be disabled with
216+
<Javadoc name={"org.bukkit.entity.Entity#setPersistent(boolean)"}>`Entity#setPersistent()`</Javadoc>,
217+
meaning it will disappear when the chunk unloads.
218+
219+
_However, if the display is located in a chunk that never unloads, i.e. a spawn chunk, it will never
220+
be removed, creating a resource leak. Make sure to remove the display afterward with
221+
<Javadoc name={"org.bukkit.entity.Entity#remove()"}>`Entity#remove()`</Javadoc>._
222+
223+
:::
224+
225+
They can also be added as passengers to entities with the
226+
<Javadoc name={"org.bukkit.entity.Entity#addPassenger(org.bukkit.entity.Entity)"}>`Entity#addPassenger()`</Javadoc>/
227+
<Javadoc name={"org.bukkit.entity.Entity#removePassenger(org.bukkit.entity.Entity)"}>`Entity#removePassenger()`</Javadoc>
228+
methods, useful for making styled name tags!
229+
230+
```java
231+
TextDisplay display = world.spawn(location, TextDisplay.class, entity -> {
232+
// ...
233+
234+
entity.setVisibleByDefault(false); // hide it for everyone
235+
entity.setPersistent(false); // don't save the display, it's temporary
236+
});
237+
238+
entity.addPassenger(display); // mount it on top of an entity's head
239+
player.showEntity(plugin, display); // show it to a player
240+
// ...
241+
display.remove(); // done with the display
242+
```

docs/paper/dev/api/entity-teleport.mdx renamed to docs/paper/dev/api/entity-api/entity-teleport.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ slug: /dev/entity-teleport
33
description: The entity teleportation API and how to use it.
44
---
55

6-
# Entity Teleportation
6+
# Teleportation
77

88
Entities can be instantaneously teleported to specific positions, synchronously and asynchronously with the
99
<Javadoc name={"org.bukkit.entity.Entity#teleport(org.bukkit.Location)"}>`teleport`</Javadoc> and

0 commit comments

Comments
 (0)