24package com.dreamfirestudios.dreamcore.DreamHologram;
26import com.dreamfirestudios.dreamcore.DreamChat.DreamMessageFormatter;
27import com.dreamfirestudios.dreamcore.DreamChat.DreamMessageSettings;
28import com.dreamfirestudios.dreamcore.DreamCore;
29import com.dreamfirestudios.dreamcore.DreamJava.DreamClassID;
31import net.kyori.adventure.text.Component;
32import org.bukkit.Bukkit;
33import org.bukkit.Location;
34import org.bukkit.World;
35import org.bukkit.entity.ArmorStand;
36import org.jetbrains.annotations.NotNull;
37import org.jetbrains.annotations.Nullable;
39import java.util.ArrayList;
42import java.util.function.Consumer;
43import java.util.function.Function;
58 private final List<ArmorStand> armorStands =
new ArrayList<>();
60 @Getter
private String hologramName;
61 @Getter
private Location startLocation;
63 @Getter
private boolean visible =
false;
64 @Getter
private boolean customNameVisible =
true;
65 @Getter
private boolean useGravity =
false;
71 @Getter
private float gapBetweenLines = -0.5f;
77 private Function<Integer, Component> lineGenerator;
88 return armorStands.contains(armorStand);
95 return armorStands.size();
105 public Component
line(
int index) {
106 if (index < 0 || index >= armorStands.size())
return null;
107 return armorStands.get(index).customName();
123 if (index < 0 || index > armorStands.size())
124 throw new IllegalArgumentException(
"Index out of bounds: " + index);
125 if (startLocation ==
null)
return;
126 final World world = startLocation.getWorld();
127 if (world ==
null)
return;
130 final Component name = formatLine(index);
133 final Location spawnLoc = lineLocation(index);
134 ArmorStand stand = world.spawn(spawnLoc, ArmorStand.class, configureArmorStand(name));
137 armorStands.add(index, stand);
152 if (index < 0 || index >= armorStands.size())
153 throw new IllegalArgumentException(
"Invalid line index: " + index);
155 final Component name = formatLine(index);
156 ArmorStand stand = armorStands.get(index);
157 stand.customName(name);
158 stand.setCustomNameVisible(customNameVisible);
171 if (index < 0 || index >= armorStands.size())
return;
173 ArmorStand stand = armorStands.remove(index);
196 for (
int i = 0; i < armorStands.size(); i++) {
207 for (ArmorStand stand : armorStands) {
219 private void restackFrom(
int startIndex) {
220 if (startLocation ==
null)
return;
221 for (
int i = startIndex; i < armorStands.size(); i++) {
222 ArmorStand stand = armorStands.get(i);
223 stand.teleport(lineLocation(i));
224 stand.setCustomNameVisible(customNameVisible);
225 stand.setGravity(useGravity);
226 stand.setInvisible(!visible);
231 private Location lineLocation(
int index) {
232 return startLocation.clone().add(0.0, index * gapBetweenLines, 0.0);
236 private Component formatLine(
int index) {
237 Component generated = lineGenerator !=
null
238 ? lineGenerator.apply(index)
240 return DreamMessageFormatter.format(generated, DreamMessageSettings.all());
244 private Consumer<ArmorStand> configureArmorStand(Component name) {
247 stand.setMarker(
true);
248 stand.setInvisible(!visible);
249 stand.setGravity(useGravity);
250 stand.setCustomNameVisible(customNameVisible);
251 stand.customName(name);
252 stand.setSmall(
true);
253 stand.setPersistent(
true);
255 stand.setBasePlate(
false);
256 stand.setArms(
false);
257 stand.setCanMove(
false);
261 private static void ensureMainThread() {
262 if (!Bukkit.isPrimaryThread()) {
263 throw new IllegalStateException(
"Hologram mutations must run on the server main thread.");
275 private String hologramName = UUID.randomUUID().toString();
276 private boolean visible =
false;
277 private boolean customNameVisible =
true;
278 private boolean useGravity =
false;
279 private float gapBetweenLines = -0.5f;
280 private int linesToAdd = 0;
283 this.hologramName = hologramName;
288 if (linesToAdd < 0)
throw new IllegalArgumentException(
"linesToAdd cannot be negative");
289 this.linesToAdd = linesToAdd;
294 this.visible = visible;
299 this.customNameVisible = customNameVisible;
304 this.useGravity = useGravity;
309 this.gapBetweenLines = gapBetweenLines;
321 @NotNull Function<Integer, Component> lineGenerator) {
323 World world = location.getWorld();
324 if (world ==
null)
throw new IllegalArgumentException(
"Location must have a world");
327 hologram.hologramName = hologramName;
328 hologram.startLocation = location.clone();
329 hologram.visible = visible;
330 hologram.customNameVisible = customNameVisible;
331 hologram.useGravity = useGravity;
332 hologram.gapBetweenLines = gapBetweenLines;
333 hologram.lineGenerator = lineGenerator;
335 for (
int i = 0; i < linesToAdd; i++) {
static final LinkedHashMap< UUID, DreamHologram > DreamHolograms
Fluent builder for DreamHologram.
HologramBuilder lines(int linesToAdd)
HologramBuilder useGravity(boolean useGravity)
HologramBuilder visible(boolean visible)
HologramBuilder gapBetweenLines(float gapBetweenLines)
DreamHologram create(@NotNull Location location, @NotNull Function< Integer, Component > lineGenerator)
Creates and spawns a new hologram at the given location.
HologramBuilder hologramName(@NotNull String hologramName)
HologramBuilder customNameVisible(boolean customNameVisible)
A multi-line Adventure Component hologram backed by stacked ArmorStands.
void addNewLine(int index)
Inserts a new line at the given index and spawns a configured ArmorStand.
void displayNextFrame()
Re-applies the line generator to all lines (useful for animated text).
void updateHologram()
Teleports all line ArmorStands to their correct stacked positions from top to bottom.
void deleteHologram()
Deletes the entire hologram and removes all ArmorStands.
void removeLine(int index)
Removes a line at the specified index and deletes its ArmorStand.
Component line(int index)
Returns the Component name of a line.
boolean isArmorStand(@NotNull ArmorStand armorStand)
void editLine(int index)
Updates the content (custom name) of an existing line.
Event fired after a hologram line has been inserted and its ArmorStand spawned.
static void fire(@NotNull DreamHologram hologram, @NotNull Component line)
Convenience helper to create and call this event via the plugin manager.
Event fired after a hologram has been deleted and all ArmorStands removed.
static void fire(@NotNull DreamHologram hologram)
Fires this event through the Bukkit plugin manager.
Event fired after a hologram line's content (custom name) has been updated.
static void fire(@NotNull DreamHologram hologram, int index, @NotNull Component line)
Fires this event via the plugin manager.
Event fired after a line has been removed from a hologram.
static void fire(@NotNull DreamHologram hologram, int index)
Fires this event via the Bukkit plugin manager.
Event fired after a hologram has been created and its initial lines spawned.
static void fire(@NotNull DreamHologram hologram)
Fires this event via the Bukkit plugin manager.
Event fired after a hologram has been collectively updated (e.g., re-stack/teleport,...
static void fire(@NotNull DreamHologram hologram)
Fires this event via the Bukkit plugin manager.