mirror of
https://github.com/FancyInnovations/FancyPlugins.git
synced 2025-12-06 07:43:36 +00:00
Add FancyHolograms sources
This commit is contained in:
@@ -0,0 +1,313 @@
|
||||
package de.oliver.fancyholograms;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import de.oliver.fancyholograms.api.HologramManager;
|
||||
import de.oliver.fancyholograms.api.data.DisplayHologramData;
|
||||
import de.oliver.fancyholograms.api.data.HologramData;
|
||||
import de.oliver.fancyholograms.api.data.TextHologramData;
|
||||
import de.oliver.fancyholograms.api.events.HologramsLoadedEvent;
|
||||
import de.oliver.fancyholograms.api.events.HologramsUnloadedEvent;
|
||||
import de.oliver.fancyholograms.api.hologram.Hologram;
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnmodifiableView;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The FancyHologramsManager class is responsible for managing holograms in the FancyHolograms plugin.
|
||||
* It provides methods for adding, removing, and retrieving holograms, as well as other related operations.
|
||||
*/
|
||||
public final class HologramManagerImpl implements HologramManager {
|
||||
|
||||
private final @NotNull FancyHolograms plugin;
|
||||
/**
|
||||
* The adapter function used to create holograms from hologram data.
|
||||
*/
|
||||
private final @NotNull Function<HologramData, Hologram> adapter;
|
||||
/**
|
||||
* A map of hologram names to their corresponding hologram instances.
|
||||
*/
|
||||
private final Map<String, Hologram> holograms = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* Whether holograms are loaded or not
|
||||
*/
|
||||
private boolean isLoaded = false;
|
||||
|
||||
HologramManagerImpl(@NotNull final FancyHolograms plugin, @NotNull final Function<HologramData, Hologram> adapter) {
|
||||
this.plugin = plugin;
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A read-only collection of loaded holograms.
|
||||
*/
|
||||
@Override
|
||||
public @NotNull
|
||||
@UnmodifiableView Collection<Hologram> getHolograms() {
|
||||
return Collections.unmodifiableCollection(this.holograms.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a read-only view of the currently loaded persistent holograms.
|
||||
*
|
||||
* @return A read-only collection of holograms.
|
||||
*/
|
||||
@Override
|
||||
public @NotNull
|
||||
@UnmodifiableView Collection<Hologram> getPersistentHolograms() {
|
||||
return this.holograms.values().stream().filter(hologram -> hologram.getData().isPersistent()).toList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds a hologram by name.
|
||||
*
|
||||
* @param name The name of the hologram to lookup.
|
||||
* @return An optional containing the found hologram, or empty if not found.
|
||||
*/
|
||||
public @NotNull Optional<Hologram> getHologram(@NotNull final String name) {
|
||||
return Optional.ofNullable(this.holograms.get(name.toLowerCase(Locale.ROOT)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a hologram to this manager.
|
||||
*
|
||||
* @param hologram The hologram to add.
|
||||
*/
|
||||
public void addHologram(@NotNull final Hologram hologram) {
|
||||
this.holograms.put(hologram.getData().getName().toLowerCase(Locale.ROOT), hologram);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a hologram from this manager.
|
||||
*
|
||||
* @param hologram The hologram to remove.
|
||||
*/
|
||||
public void removeHologram(@NotNull final Hologram hologram) {
|
||||
removeHologram(hologram.getData().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a hologram from this manager by name.
|
||||
*
|
||||
* @param name The name of the hologram to remove.
|
||||
* @return An optional containing the removed hologram, or empty if not found.
|
||||
*/
|
||||
public @NotNull Optional<Hologram> removeHologram(@NotNull final String name) {
|
||||
Optional<Hologram> optionalHologram = Optional.ofNullable(this.holograms.remove(name.toLowerCase(Locale.ROOT)));
|
||||
|
||||
optionalHologram.ifPresent(hologram -> {
|
||||
for (UUID viewer : hologram.getViewers()) {
|
||||
Player player = Bukkit.getPlayer(viewer);
|
||||
if (player != null) {
|
||||
FancyHolograms.get().getHologramThread().submit(() -> hologram.forceHideHologram(player));
|
||||
}
|
||||
}
|
||||
|
||||
FancyHolograms.get().getHologramThread().submit(() -> plugin.getHologramStorage().delete(hologram));
|
||||
}
|
||||
);
|
||||
|
||||
return optionalHologram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new hologram with the specified hologram data.
|
||||
*
|
||||
* @param data The hologram data for the new hologram.
|
||||
* @return The created hologram.
|
||||
*/
|
||||
public @NotNull Hologram create(@NotNull final HologramData data) {
|
||||
Hologram hologram = this.adapter.apply(data);
|
||||
hologram.createHologram();
|
||||
return hologram;
|
||||
}
|
||||
|
||||
public void saveHolograms() {
|
||||
if (!isLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.getHologramStorage().saveBatch(getPersistentHolograms(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadHolograms() {
|
||||
List<Hologram> allLoaded = new ArrayList<>();
|
||||
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
Collection<Hologram> loaded = plugin.getHologramStorage().loadAll(world.getName());
|
||||
loaded.forEach(this::addHologram);
|
||||
|
||||
allLoaded.addAll(loaded);
|
||||
}
|
||||
isLoaded = true;
|
||||
|
||||
FancyHolograms.get().getHologramThread().submit(() -> Bukkit.getPluginManager().callEvent(new HologramsLoadedEvent(ImmutableList.copyOf(allLoaded))));
|
||||
|
||||
FancyHolograms.get().getFancyLogger().info(String.format("Loaded %d holograms for all loaded worlds", allLoaded.size()));
|
||||
}
|
||||
|
||||
public void loadHolograms(String world) {
|
||||
ImmutableList<Hologram> loaded = ImmutableList.copyOf(plugin.getHologramStorage().loadAll(world));
|
||||
loaded.forEach(this::addHologram);
|
||||
|
||||
isLoaded = true;
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new HologramsLoadedEvent(ImmutableList.copyOf(loaded)));
|
||||
|
||||
FancyHolograms.get().getFancyLogger().info(String.format("Loaded %d holograms for world %s", loaded.size(), world));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes tasks for managing holograms, such as loading and refreshing them.
|
||||
* <p>
|
||||
* This method is intended to be called internally by the plugin.
|
||||
*/
|
||||
void initializeTasks() {
|
||||
ScheduledExecutorService hologramThread = plugin.getHologramThread();
|
||||
hologramThread.submit(() -> {
|
||||
loadHolograms();
|
||||
|
||||
hologramThread.scheduleAtFixedRate(() -> {
|
||||
for (final Hologram hologram : this.plugin.getHologramsManager().getHolograms()) {
|
||||
for (final Player player : Bukkit.getOnlinePlayers()) {
|
||||
hologram.forceUpdateShownStateFor(player);
|
||||
}
|
||||
}
|
||||
}, 0, plugin.getHologramConfiguration().getUpdateVisibilityInterval() * 50, TimeUnit.MILLISECONDS);
|
||||
});
|
||||
|
||||
final var updateTimes = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(Duration.ofMinutes(5))
|
||||
.<String, Long>build();
|
||||
|
||||
hologramThread.scheduleAtFixedRate(() -> {
|
||||
final var time = System.currentTimeMillis();
|
||||
|
||||
for (final var hologram : getHolograms()) {
|
||||
HologramData data = hologram.getData();
|
||||
if (data.hasChanges()) {
|
||||
hologram.forceUpdate();
|
||||
hologram.refreshForViewersInWorld();
|
||||
data.setHasChanges(false);
|
||||
|
||||
if (data instanceof TextHologramData) {
|
||||
updateTimes.put(hologram.getData().getName(), time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 50, 1000, TimeUnit.MILLISECONDS);
|
||||
|
||||
hologramThread.scheduleWithFixedDelay(() -> {
|
||||
final var time = System.currentTimeMillis();
|
||||
|
||||
for (final var hologram : getHolograms()) {
|
||||
if (hologram.getData() instanceof TextHologramData textData) {
|
||||
final var interval = textData.getTextUpdateInterval();
|
||||
if (interval < 1) {
|
||||
continue; // doesn't update
|
||||
}
|
||||
|
||||
final var lastUpdate = updateTimes.asMap().get(textData.getName());
|
||||
if (lastUpdate != null && time < (lastUpdate + interval)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lastUpdate == null || time > (lastUpdate + interval)) {
|
||||
hologram.refreshForViewersInWorld();
|
||||
updateTimes.put(textData.getName(), time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 50, 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads holograms by clearing the existing holograms and loading them again from the plugin's configuration.
|
||||
*/
|
||||
public void reloadHolograms() {
|
||||
unloadHolograms();
|
||||
loadHolograms();
|
||||
}
|
||||
|
||||
public void unloadHolograms() {
|
||||
FancyHolograms.get().getHologramThread().submit(() -> {
|
||||
List<Hologram> unloaded = new ArrayList<>();
|
||||
|
||||
for (final var hologram : this.getPersistentHolograms()) {
|
||||
this.holograms.remove(hologram.getName());
|
||||
unloaded.add(hologram);
|
||||
|
||||
for (UUID viewer : hologram.getViewers()) {
|
||||
Player player = Bukkit.getPlayer(viewer);
|
||||
if (player != null) {
|
||||
hologram.forceHideHologram(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new HologramsUnloadedEvent(ImmutableList.copyOf(unloaded)));
|
||||
});
|
||||
}
|
||||
|
||||
public void unloadHolograms(String world) {
|
||||
final var online = List.copyOf(Bukkit.getOnlinePlayers());
|
||||
|
||||
FancyHolograms.get().getHologramThread().submit(() -> {
|
||||
List<Hologram> h = getPersistentHolograms().stream()
|
||||
.filter(hologram -> hologram.getData().getLocation().getWorld().getName().equals(world))
|
||||
.toList();
|
||||
|
||||
FancyHolograms.get().getHologramStorage().saveBatch(h, false);
|
||||
|
||||
for (final Hologram hologram : h) {
|
||||
this.holograms.remove(hologram.getName());
|
||||
online.forEach(hologram::forceHideHologram);
|
||||
}
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new HologramsUnloadedEvent(ImmutableList.copyOf(h)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs a hologram with its linked NPC, if any.
|
||||
*
|
||||
* @param hologram The hologram to sync.
|
||||
*/
|
||||
public void syncHologramWithNpc(@NotNull final Hologram hologram) {
|
||||
final var linkedNpcName = hologram.getData().getLinkedNpcName();
|
||||
if (linkedNpcName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var npc = FancyNpcsPlugin.get().getNpcManager().getNpc(linkedNpcName);
|
||||
if (npc == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
npc.getData().setDisplayName("<empty>");
|
||||
npc.getData().setShowInTab(false);
|
||||
npc.updateForAll();
|
||||
|
||||
final var npcScale = npc.getData().getScale();
|
||||
|
||||
if (hologram.getData() instanceof DisplayHologramData displayData) {
|
||||
displayData.setScale(new Vector3f(npcScale));
|
||||
}
|
||||
|
||||
final var location = npc.getData().getLocation().clone().add(0, (npc.getEyeHeight() * npcScale) + (0.5 * npcScale), 0);
|
||||
hologram.getData().setLocation(location);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user