PandaLib/pandalib-paper/src/main/java/fr/pandacube/lib/paper/util/AutoUpdatedBossBar.java

199 lines
5.2 KiB
Java

package fr.pandacube.lib.paper.util;
import java.util.Timer;
import java.util.TimerTask;
import java.util.function.Predicate;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import fr.pandacube.lib.chat.Chat;
import fr.pandacube.lib.util.Log;
import fr.pandacube.lib.paper.PandaLibPaper;
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.bossbar.BossBar.Color;
import net.kyori.adventure.text.Component;
public class AutoUpdatedBossBar implements Listener {
public final BossBar bar;
public final BarUpdater updater;
private Timer timer = null;
private BukkitTask bukkitTask = null;
private boolean scheduled = false;
private boolean followPlayerList = false;
private Predicate<Player> playerCondition = null;
public AutoUpdatedBossBar(BossBar bar, BarUpdater updater) {
this.bar = bar;
this.updater = updater;
}
/**
* Schedule the update of this boss bar with synchronisation with the system clock.
* The underlying method called is {@link Timer#schedule(TimerTask, long, long)}.
* The updater is executed in a separate Thread.
* @param msDelay ms before running the first update of this bossbar
* @param msPeriod ms between each call of the updater
*/
public synchronized void scheduleUpdateTimeSyncThreadAsync(long msDelay, long msPeriod) {
if (scheduled)
throw new IllegalStateException("Can't schedule an already scheduled boss bar update");
scheduled = true;
timer = new Timer("Panda BossBarUpdater - " + Chat.chatComponent(bar.name()).getPlainText());
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
updater.update(AutoUpdatedBossBar.this);
} catch(Throwable e) {
Log.severe("Error while updating an AutoUpdatedBossBar", e);
}
}
}, msDelay, msPeriod);
}
/**
* Schedule the update of this boss bar with synchronisation with the main Thread of the
* current Minecraft server (follow the tick count progress).
* The underlying method called is {@link BukkitScheduler#runTaskTimer(org.bukkit.plugin.Plugin, Runnable, long, long)}.
* The updater is executed by the Server Thread.
* @param tickDelay number of server tick before running the first update of this boss bar
* @param tickPeriod number of server tick between each call of the updater
*/
public synchronized void scheduleUpdateTickSyncThreadSync(long tickDelay, long tickPeriod) {
if (scheduled)
throw new IllegalStateException("Can't schedule an already scheduled boss bar update");
scheduled = true;
bukkitTask = Bukkit.getServer().getScheduler()
.runTaskTimer(PandaLibPaper.getPlugin(), () -> {
synchronized (bar) {
try {
updater.update(this);
} catch(Throwable e) {
Log.severe("Error while updating an AutoUpdatedBossBar", e);
}
}
}, tickDelay, tickPeriod);
}
public synchronized void followLoginLogout(Predicate<Player> condition) {
playerCondition = condition;
if (followPlayerList)
return;
followPlayerList = true;
BukkitEvent.register(this);
Bukkit.getServer().getOnlinePlayers().forEach(p -> onPlayerJoin(new PlayerJoinEvent(p, Component.text(""))));
}
public synchronized void unfollowPlayerList() {
if (!followPlayerList)
return;
followPlayerList = false;
playerCondition = null;
PlayerJoinEvent.getHandlerList().unregister(this);
PlayerQuitEvent.getHandlerList().unregister(this);
}
@EventHandler(priority=EventPriority.MONITOR)
public synchronized void onPlayerJoin(PlayerJoinEvent event) {
if (!followPlayerList)
return;
if (playerCondition != null && !playerCondition.test(event.getPlayer()))
return;
synchronized (bar) {
event.getPlayer().showBossBar(bar);
}
}
@EventHandler(priority=EventPriority.HIGH)
public synchronized void onPlayerQuit(PlayerQuitEvent event) {
if (!followPlayerList)
return;
synchronized (bar) {
event.getPlayer().hideBossBar(bar);
}
}
public void removeAll() {
synchronized (bar) {
for (Player p : Bukkit.getOnlinePlayers())
p.hideBossBar(bar);
}
}
public synchronized void cancel() {
if (!scheduled)
return;
scheduled = false;
if (timer != null) {
timer.cancel();
timer = null;
}
if (bukkitTask != null) {
bukkitTask.cancel();
bukkitTask = null;
}
}
@FunctionalInterface
public interface BarUpdater {
void update(AutoUpdatedBossBar bar);
}
/**
* Utility method to update the title of the boss bar without unnecessary packet.
*/
public void setTitle(Chat title) {
synchronized (bar) {
bar.name(title); // already check if the title is the same
}
}
/**
* Utility method to update the color of the boss bar without unnecessary packet.
*/
public void setColor(Color color) {
synchronized (bar) {
bar.color(color);
}
}
/**
* Utility method to update the progress of the boss bar without unnecessary packet.
*/
public void setProgress(double progress) {
synchronized (bar) {
bar.progress((float) progress);
}
}
}