Skip to content

Commit cee72aa

Browse files
committed
added hologram support
1 parent 2166d19 commit cee72aa

3 files changed

Lines changed: 259 additions & 1 deletion

File tree

src/main/java/com/stemcraft/STEMCraftLib.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public void onEnable() {
9595
extractFile("prices.yml");
9696
SCItem.loadPricesFromConfig(new File(instance.getDataFolder(), "prices.yml"));
9797

98-
SCHologram.loadFromConfig(new File(instance.getDataFolder(), "holograms.yml"));
98+
SCHologram.load();
9999

100100
SCTabCompletion.register("player", () -> Bukkit.getServer().getOnlinePlayers().stream()
101101
.map(Player::getName)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.stemcraft.listener;
2+
3+
import com.stemcraft.util.SCHologram;
4+
import org.bukkit.Chunk;
5+
import org.bukkit.event.EventHandler;
6+
import org.bukkit.event.Listener;
7+
import org.bukkit.event.world.ChunkLoadEvent;
8+
9+
public class ChunkLoadListener implements Listener {
10+
@EventHandler
11+
public void onChunkLoad(ChunkLoadEvent event) {
12+
Chunk chunk = event.getChunk();
13+
14+
SCHologram.updateChunk(chunk);
15+
}
16+
}
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
package com.stemcraft.util;
2+
3+
import com.stemcraft.STEMCraftLib;
4+
import lombok.Getter;
5+
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
6+
import org.bukkit.Bukkit;
7+
import org.bukkit.Chunk;
8+
import org.bukkit.Location;
9+
import org.bukkit.configuration.file.YamlConfiguration;
10+
import org.bukkit.entity.ArmorStand;
11+
import org.bukkit.entity.Entity;
12+
import org.bukkit.entity.EntityType;
13+
import org.bukkit.scheduler.BukkitRunnable;
14+
15+
import java.io.File;
16+
import java.io.IOException;
17+
import java.util.HashMap;
18+
import java.util.Map;
19+
import java.util.Objects;
20+
import java.util.UUID;
21+
import java.util.concurrent.atomic.AtomicBoolean;
22+
import java.util.logging.Level;
23+
24+
public class SCHologram {
25+
private static final Map<String, HologramItem> holograms = new HashMap<>();
26+
private static File hologramConfigFile = null;
27+
private static YamlConfiguration hologramConfig = null;
28+
private static BukkitRunnable saveTask;
29+
30+
@Getter
31+
static class HologramItem {
32+
private ArmorStand stand = null;
33+
private Location location;
34+
private String text;
35+
private String id;
36+
private boolean dirty;
37+
38+
public HologramItem(String id, Location location, String text) {
39+
this.id = id;
40+
this.location = location;
41+
this.text = text;
42+
this.dirty = false;
43+
}
44+
45+
public void setLocation(Location location) {
46+
this.dirty = true;
47+
this.location = location;
48+
if(stand != null && stand.isValid()) {
49+
stand.customName(LegacyComponentSerializer.legacyAmpersand().deserialize(text));
50+
}
51+
}
52+
53+
public void setText(String text) {
54+
this.dirty = true;
55+
this.text = text;
56+
if(stand != null && stand.isValid()) {
57+
stand.teleport(location);
58+
}
59+
}
60+
61+
public boolean update() {
62+
if(stand == null || !stand.isValid()) {
63+
if (!location.isChunkLoaded()) {
64+
return false;
65+
}
66+
67+
Entity entity = location.getWorld().getEntity(UUID.fromString(id));
68+
if (entity instanceof ArmorStand && entity.isValid() && entity.getUniqueId().toString().equals(id)) {
69+
stand = (ArmorStand) entity;
70+
} else {
71+
for (Entity e : location.getChunk().getEntities()) {
72+
if (e instanceof ArmorStand && e.isValid() && e.getUniqueId().toString().equals(id)) {
73+
stand = (ArmorStand) e;
74+
break;
75+
}
76+
}
77+
78+
if (stand == null || !stand.isValid()) {
79+
stand = (ArmorStand) location.getWorld().spawnEntity(location, EntityType.ARMOR_STAND);
80+
stand.setVisible(false);
81+
stand.setCustomNameVisible(true);
82+
stand.customName(LegacyComponentSerializer.legacyAmpersand().deserialize(text));
83+
stand.setGravity(false);
84+
85+
this.id = stand.getUniqueId().toString();
86+
this.dirty = true;
87+
return true;
88+
}
89+
}
90+
}
91+
92+
stand.teleport(location);
93+
stand.customName(LegacyComponentSerializer.legacyAmpersand().deserialize(text));
94+
95+
return false;
96+
}
97+
98+
public void despawn() {
99+
if(stand != null && stand.isValid()) {
100+
stand.remove();
101+
stand = null;
102+
}
103+
}
104+
}
105+
106+
/**
107+
* Load the holograms from the configuration file
108+
*/
109+
public static void load() {
110+
holograms.clear();
111+
112+
hologramConfigFile = new File(STEMCraftLib.getInstance().getDataFolder(), "holograms.yml");
113+
if(hologramConfigFile.exists()) {
114+
hologramConfig = YamlConfiguration.loadConfiguration(hologramConfigFile);
115+
116+
if (hologramConfig.contains("holograms")) {
117+
for (String id : Objects.requireNonNull(hologramConfig.getConfigurationSection("holograms")).getKeys(false)) {
118+
String worldName = hologramConfig.getString("holograms." + id + ".world");
119+
double x = hologramConfig.getDouble("holograms." + id + ".x");
120+
double y = hologramConfig.getDouble("holograms." + id + ".y");
121+
double z = hologramConfig.getDouble("holograms." + id + ".z");
122+
String text = hologramConfig.getString("holograms." + id + ".text");
123+
124+
if (worldName != null && SCWorld.isLoaded(worldName)) {
125+
Location location = new Location(Bukkit.getWorld(worldName), x, y, z);
126+
127+
HologramItem hologram = new HologramItem(id, location, text);
128+
hologram.update();
129+
holograms.put(hologram.getId(), hologram);
130+
} else {
131+
STEMCraftLib.log(Level.WARNING, "World " + worldName + " for hologram " + id + " does not exist.");
132+
}
133+
}
134+
}
135+
}
136+
}
137+
138+
private synchronized void saveAll() {
139+
saveAll(false);
140+
}
141+
142+
private static synchronized void saveAll(boolean now) {
143+
if(!now) {
144+
if (saveTask != null) {
145+
saveTask.cancel();
146+
}
147+
148+
saveTask = new BukkitRunnable() {
149+
@Override
150+
public void run() {
151+
saveAll(true);
152+
}
153+
};
154+
155+
saveTask.runTaskLater(STEMCraftLib.getInstance(), 100);
156+
return;
157+
}
158+
159+
AtomicBoolean dirty = new AtomicBoolean(false);
160+
161+
holograms.forEach((id, hologram) -> {
162+
if(hologram.isDirty()) {
163+
dirty.set(true);
164+
165+
String newId = hologram.getId();
166+
if(!id.equals(newId)) {
167+
holograms.put(newId, hologram);
168+
holograms.remove(id);
169+
170+
hologramConfig.set("holograms." + id, null);
171+
172+
hologramConfig.set("holograms." + newId + ".world", hologram.getLocation().getWorld().getName());
173+
hologramConfig.set("holograms." + newId + ".x", hologram.getLocation().getX());
174+
hologramConfig.set("holograms." + newId + ".y", hologram.getLocation().getY());
175+
hologramConfig.set("holograms." + newId + ".z", hologram.getLocation().getZ());
176+
hologramConfig.set("holograms." + newId + ".text", hologram.getText());
177+
}
178+
}
179+
});
180+
181+
if(dirty.get()) {
182+
try {
183+
hologramConfig.save(hologramConfigFile);
184+
} catch (IOException e) {
185+
STEMCraftLib.log(Level.SEVERE, "Failed to save the holograms configuration file", e);
186+
}
187+
}
188+
}
189+
190+
/**
191+
* Deletes an existing hologram by its ID.
192+
*
193+
* @param id The unique ID of the hologram.
194+
*/
195+
public static void delete(String id) {
196+
if (holograms.containsKey(id)) {
197+
holograms.get(id).despawn();
198+
holograms.remove(id);
199+
}
200+
201+
if(hologramConfig.contains("holograms." + id)) {
202+
hologramConfig.set("holograms." + id, null);
203+
204+
try {
205+
hologramConfig.save(hologramConfigFile);
206+
} catch (IOException e) {
207+
STEMCraftLib.log(Level.SEVERE, "Failed to save the holograms configuration file", e);
208+
}
209+
}
210+
}
211+
212+
/**
213+
* Update the holograms in a specified chunk
214+
* @param chunk The chunk to update.
215+
*/
216+
public static void updateChunk(Chunk chunk) {
217+
if(chunk.isLoaded()) {
218+
holograms.forEach((id, hologram) -> {
219+
if(hologram.location.getChunk().equals(chunk)) {
220+
hologram.update();
221+
}
222+
});
223+
}
224+
}
225+
226+
/**
227+
* Updates a hologram to function like a scoreboard with multiple lines.
228+
*
229+
* @param id The unique ID of the hologram.
230+
* @param location The base location of the hologram.
231+
* @param lines The lines to display, top to bottom.
232+
*/
233+
// public void createOrUpdateScoreboardHologram(String id, Location location, String... lines) {
234+
// deleteHologram(id); // Remove existing hologram if it exists.
235+
//
236+
// Location currentLocation = location.clone();
237+
// for (String line : lines) {
238+
// createOrUpdateHologram(id + "_" + UUID.randomUUID(), currentLocation, line);
239+
// currentLocation.subtract(0, 0.3, 0); // Adjust spacing for next line.
240+
// }
241+
// }
242+
}

0 commit comments

Comments
 (0)