Signed-off-by: Minecon724 <minecon724@noreply.git.m724.eu>
This commit is contained in:
		
					parent
					
						
							
								a8e67dbe26
							
						
					
				
			
			
				commit
				
					
						e3f34ec46f
					
				
			
		
					 8 changed files with 244 additions and 158 deletions
				
			
		| 
						 | 
				
			
			@ -6,70 +6,77 @@
 | 
			
		|||
 | 
			
		||||
package eu.m724.tweaks.module.pomodoro;
 | 
			
		||||
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
public class PlayerPomodoro {
 | 
			
		||||
    private int pomodori = 0;
 | 
			
		||||
    private int intervalsDone = 0;
 | 
			
		||||
 | 
			
		||||
    private boolean isBreak = false;
 | 
			
		||||
    // this is for both break and not break
 | 
			
		||||
    private long intervalStart = -1;
 | 
			
		||||
    private boolean breaktime = false;
 | 
			
		||||
    private long currentIntervalStartedAtNanos = -1;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A "pomodoro" is the 25-minute cycle you take breaks after<br>
 | 
			
		||||
     * This returns how many cycles already elapsed, so if this is the first cycle this is 0<br>
 | 
			
		||||
     * The break after the "pomodoro," so if it's breaktime after the first "pomodoro" it stays at 0
 | 
			
		||||
     */
 | 
			
		||||
    public int getPomodori() {
 | 
			
		||||
        return pomodori;
 | 
			
		||||
    public int getIntervalsDone() {
 | 
			
		||||
        return intervalsDone;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isBreaktime() {
 | 
			
		||||
        return breaktime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isLongBreak() {
 | 
			
		||||
        return (intervalsDone + 1) % PomodoroModule.INTERVALS_BEFORE_LONG_BREAK == 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * When did the current interval start<br>
 | 
			
		||||
     * Or when did the break start
 | 
			
		||||
     *
 | 
			
		||||
     * @see PlayerPomodoro#isBreak()
 | 
			
		||||
     * @return The time the current interval or break started, in milliseconds
 | 
			
		||||
     */
 | 
			
		||||
    public long getIntervalStart() {
 | 
			
		||||
        return intervalStart;
 | 
			
		||||
    public long getCurrentIntervalStartedAtNanos() {
 | 
			
		||||
        return currentIntervalStartedAtNanos;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getCycleDurationSeconds() {
 | 
			
		||||
        return isBreak ? (pomodori < 3 ? 300 : 1200) : 1500;
 | 
			
		||||
    public int getCurrentIntervalDurationSeconds() {
 | 
			
		||||
        if (breaktime) {
 | 
			
		||||
            if (isLongBreak()) {
 | 
			
		||||
                return PomodoroModule.LONG_BREAK_DURATION_SECONDS;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return PomodoroModule.SHORT_BREAK_DURATION_SECONDS;
 | 
			
		||||
        } else {
 | 
			
		||||
            return PomodoroModule.INTERVAL_DURATION_SECONDS;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public long getRemainingSeconds(long now) {
 | 
			
		||||
        return getCycleDurationSeconds() - (now - getIntervalStart()) / 1000000000;
 | 
			
		||||
    public long getCurrentIntervalDurationNanos() {
 | 
			
		||||
        return TimeUnit.SECONDS.toNanos(getCurrentIntervalDurationSeconds());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Is it a break currently
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isBreak() {
 | 
			
		||||
        return isBreak;
 | 
			
		||||
    public long getCurrentIntervalRemainingNanos(long nowNanos) {
 | 
			
		||||
        long elapsed = nowNanos - getCurrentIntervalStartedAtNanos();
 | 
			
		||||
        return getCurrentIntervalDurationNanos() - elapsed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isCycleComplete() {
 | 
			
		||||
        return intervalStart + getCycleDurationSeconds() * 1000000000L < System.nanoTime();
 | 
			
		||||
    public boolean isIntervalComplete(long nowNanos) {
 | 
			
		||||
        return currentIntervalStartedAtNanos + getCurrentIntervalDurationNanos() < nowNanos;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Resets and starts the timer
 | 
			
		||||
     */
 | 
			
		||||
    public void start() {
 | 
			
		||||
        this.pomodori = 0;
 | 
			
		||||
        this.isBreak = false;
 | 
			
		||||
        this.intervalStart = System.nanoTime();
 | 
			
		||||
        this.intervalsDone = 0;
 | 
			
		||||
        this.breaktime = false;
 | 
			
		||||
        this.currentIntervalStartedAtNanos = System.nanoTime();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Completes a cycle
 | 
			
		||||
     */
 | 
			
		||||
    public void next() {
 | 
			
		||||
        if (isBreak) { // from break to interval
 | 
			
		||||
            this.pomodori++;
 | 
			
		||||
            this.pomodori %= 4;
 | 
			
		||||
    public void startBreakOrNextInterval() {
 | 
			
		||||
        if (breaktime) { // from break to interval
 | 
			
		||||
            this.intervalsDone++;
 | 
			
		||||
            this.intervalsDone %= PomodoroModule.INTERVALS_BEFORE_LONG_BREAK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.intervalStart = System.nanoTime();
 | 
			
		||||
        isBreak = !isBreak;
 | 
			
		||||
        this.currentIntervalStartedAtNanos = System.nanoTime();
 | 
			
		||||
        breaktime = !breaktime;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (C) 2025  Minecon724
 | 
			
		||||
 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
 | 
			
		||||
 * in the project root for the full license text.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package eu.m724.tweaks.module.pomodoro;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
public class PlayerPomodoroTracker {
 | 
			
		||||
    static final Map<UUID, PlayerPomodoro> timers = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    public static PlayerPomodoro get(Player player) {
 | 
			
		||||
        return timers.get(player.getUniqueId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static PlayerPomodoro create(Player player) {
 | 
			
		||||
        return timers.computeIfAbsent(player.getUniqueId(), (k) -> new PlayerPomodoro());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean remove(Player player) {
 | 
			
		||||
        return timers.remove(player.getUniqueId()) != null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -6,6 +6,9 @@
 | 
			
		|||
 | 
			
		||||
package eu.m724.tweaks.module.pomodoro;
 | 
			
		||||
 | 
			
		||||
import eu.m724.tweaks.Language;
 | 
			
		||||
import eu.m724.tweaks.config.TweaksConfig;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandExecutor;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
| 
						 | 
				
			
			@ -18,25 +21,34 @@ public class PomodoroCommands implements CommandExecutor {
 | 
			
		|||
        Player player = (Player) sender;
 | 
			
		||||
        String action = args.length > 0 ? args[0] : null;
 | 
			
		||||
 | 
			
		||||
        PlayerPomodoro pomodoro = Pomodoros.get(player);
 | 
			
		||||
        PlayerPomodoro pomodoro = PlayerPomodoroTracker.get(player);
 | 
			
		||||
 | 
			
		||||
        long now = System.nanoTime();
 | 
			
		||||
 | 
			
		||||
        if (pomodoro != null) {
 | 
			
		||||
            if ("stop".equals(action)) {
 | 
			
		||||
                Pomodoros.remove(player);
 | 
			
		||||
                sender.sendMessage("Pomodoro disabled");
 | 
			
		||||
                PlayerPomodoroTracker.remove(player);
 | 
			
		||||
                sender.spigot().sendMessage(Language.getComponent("pomodoroStopped", ChatColor.GREEN, label));
 | 
			
		||||
            } else {
 | 
			
		||||
                if (pomodoro.isCycleComplete()) {
 | 
			
		||||
                    pomodoro.next();
 | 
			
		||||
                if (pomodoro.isIntervalComplete(now)) {
 | 
			
		||||
                    pomodoro.startBreakOrNextInterval();
 | 
			
		||||
 | 
			
		||||
                    if (pomodoro.isBreaktime() && TweaksConfig.getConfig().pomodoroForce()) {
 | 
			
		||||
                        player.kickPlayer(PomodoroModule.formatTimer(pomodoro, now).toLegacyText());
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                sender.spigot().sendMessage(Pomodoros.formatTimer(pomodoro, pomodoro.getRemainingSeconds(System.nanoTime())));
 | 
			
		||||
 | 
			
		||||
                sender.spigot().sendMessage(PomodoroModule.formatTimer(pomodoro, now));
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if ("start".equals(action)) {
 | 
			
		||||
                pomodoro = Pomodoros.create(player);
 | 
			
		||||
                pomodoro = PlayerPomodoroTracker.create(player);
 | 
			
		||||
                pomodoro.start();
 | 
			
		||||
                sender.spigot().sendMessage(Pomodoros.formatTimer(pomodoro, pomodoro.getCycleDurationSeconds()));
 | 
			
		||||
 | 
			
		||||
                sender.spigot().sendMessage(PomodoroModule.formatTimer(pomodoro, now));
 | 
			
		||||
            } else {
 | 
			
		||||
                sender.sendMessage("Start pomodoro with /pom start");
 | 
			
		||||
                // TODO help?
 | 
			
		||||
                sender.spigot().sendMessage(Language.getComponent("pomodoroStart", ChatColor.GOLD, label));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,56 +7,68 @@
 | 
			
		|||
package eu.m724.tweaks.module.pomodoro;
 | 
			
		||||
 | 
			
		||||
import eu.m724.tweaks.config.TweaksConfig;
 | 
			
		||||
import net.md_5.bungee.api.chat.ComponentBuilder;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.player.*;
 | 
			
		||||
import org.bukkit.event.player.PlayerLoginEvent;
 | 
			
		||||
import org.bukkit.event.player.PlayerQuitEvent;
 | 
			
		||||
import org.bukkit.event.player.PlayerToggleSneakEvent;
 | 
			
		||||
 | 
			
		||||
public class PomodoroListener implements Listener {
 | 
			
		||||
    private final boolean force = TweaksConfig.getConfig().pomodoroForce();
 | 
			
		||||
    private final TweaksConfig config = TweaksConfig.getConfig();
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPlayerLogin(PlayerLoginEvent event) {
 | 
			
		||||
        // Joining ends break
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
        PlayerPomodoro pomodoro = Pomodoros.get(player);
 | 
			
		||||
        PlayerPomodoro pomodoro = PlayerPomodoroTracker.get(player);
 | 
			
		||||
        if (pomodoro == null) return;
 | 
			
		||||
 | 
			
		||||
        long remaining = pomodoro.getRemainingSeconds(System.nanoTime());
 | 
			
		||||
        long now = System.nanoTime();
 | 
			
		||||
        long remaining = pomodoro.getCurrentIntervalRemainingNanos(now);
 | 
			
		||||
 | 
			
		||||
        if (pomodoro.isBreak()) {
 | 
			
		||||
            if (pomodoro.isCycleComplete()) {
 | 
			
		||||
                pomodoro.next();
 | 
			
		||||
        if (pomodoro.isBreaktime()) {
 | 
			
		||||
            if (remaining > 0 && config.pomodoroForce()) {
 | 
			
		||||
                player.kickPlayer(PomodoroModule.formatTimer(pomodoro, now).toLegacyText());
 | 
			
		||||
            } else {
 | 
			
		||||
                if (force) {
 | 
			
		||||
                    event.getPlayer().kickPlayer(
 | 
			
		||||
                            new ComponentBuilder()
 | 
			
		||||
                                    .append(Pomodoros.formatTimer(pomodoro, remaining))
 | 
			
		||||
                                    .build().toLegacyText()
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                pomodoro.startBreakOrNextInterval();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPlayerQuit(PlayerQuitEvent event) {
 | 
			
		||||
        // Quitting starts break
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
        PlayerPomodoro pomodoro = Pomodoros.get(player);
 | 
			
		||||
        PlayerPomodoro pomodoro = PlayerPomodoroTracker.get(player);
 | 
			
		||||
        if (pomodoro == null) return;
 | 
			
		||||
 | 
			
		||||
        if (!pomodoro.isBreak() && pomodoro.isCycleComplete()) {
 | 
			
		||||
            pomodoro.next();
 | 
			
		||||
        if (pomodoro.isBreaktime()) return;
 | 
			
		||||
 | 
			
		||||
        long now = System.nanoTime();
 | 
			
		||||
        long remaining = pomodoro.getCurrentIntervalRemainingNanos(now);
 | 
			
		||||
 | 
			
		||||
        if (remaining <= 0) {
 | 
			
		||||
            pomodoro.startBreakOrNextInterval();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPlayerMove(PlayerMoveEvent event) {
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
        PlayerPomodoro timer = Pomodoros.get(player);
 | 
			
		||||
        if (timer == null) return;
 | 
			
		||||
    public void onPlayerToggleSneak(PlayerToggleSneakEvent event) {
 | 
			
		||||
        // Sneaking ends break
 | 
			
		||||
        if (!event.isSneaking()) return;
 | 
			
		||||
 | 
			
		||||
        if (timer.isBreak() && timer.getRemainingSeconds(System.nanoTime()) <= 0)
 | 
			
		||||
            timer.next(); // resume timer if break ended
 | 
			
		||||
        Player player = event.getPlayer();
 | 
			
		||||
        PlayerPomodoro pomodoro = PlayerPomodoroTracker.get(player);
 | 
			
		||||
        if (pomodoro == null) return;
 | 
			
		||||
 | 
			
		||||
        if (!pomodoro.isBreaktime()) return;
 | 
			
		||||
 | 
			
		||||
        long now = System.nanoTime();
 | 
			
		||||
        long remaining = pomodoro.getCurrentIntervalRemainingNanos(now);
 | 
			
		||||
 | 
			
		||||
        if (remaining <= 0) {
 | 
			
		||||
            pomodoro.startBreakOrNextInterval();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,9 +6,23 @@
 | 
			
		|||
 | 
			
		||||
package eu.m724.tweaks.module.pomodoro;
 | 
			
		||||
 | 
			
		||||
import eu.m724.tweaks.Language;
 | 
			
		||||
import eu.m724.tweaks.config.TweaksConfig;
 | 
			
		||||
import eu.m724.tweaks.module.TweaksModule;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import net.md_5.bungee.api.chat.BaseComponent;
 | 
			
		||||
import net.md_5.bungee.api.chat.ComponentBuilder;
 | 
			
		||||
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
public class PomodoroModule extends TweaksModule {
 | 
			
		||||
    static final int INTERVAL_DURATION_SECONDS = 10;
 | 
			
		||||
    static final int SHORT_BREAK_DURATION_SECONDS = (int) TimeUnit.MINUTES.toSeconds(5);
 | 
			
		||||
    static final int LONG_BREAK_DURATION_SECONDS = (int) TimeUnit.MINUTES.toSeconds(20);
 | 
			
		||||
    static final int INTERVALS_BEFORE_LONG_BREAK = 4;
 | 
			
		||||
 | 
			
		||||
    static final int KICK_DELAY_SECONDS = 60;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onInit() {
 | 
			
		||||
        registerEvents(new PomodoroListener());
 | 
			
		||||
| 
						 | 
				
			
			@ -16,4 +30,66 @@ public class PomodoroModule extends TweaksModule {
 | 
			
		|||
 | 
			
		||||
        registerCommand("pomodoro", new PomodoroCommands());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a formatted timer for a player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pomodoro the player's {@link PlayerPomodoro} instance
 | 
			
		||||
     * @param nowNanos unix now timestamp in nanoseconds
 | 
			
		||||
     * @return the timer as {@link BaseComponent}
 | 
			
		||||
     */
 | 
			
		||||
    static BaseComponent formatTimer(PlayerPomodoro pomodoro, long nowNanos) {
 | 
			
		||||
        ComponentBuilder builder = new ComponentBuilder();
 | 
			
		||||
 | 
			
		||||
        long remainingNanos = pomodoro.getCurrentIntervalRemainingNanos(nowNanos);
 | 
			
		||||
        long remainingSeconds = TimeUnit.NANOSECONDS.toSeconds(remainingNanos);
 | 
			
		||||
 | 
			
		||||
        if (pomodoro.isBreaktime()) {
 | 
			
		||||
            if (pomodoro.isLongBreak()) {
 | 
			
		||||
                builder.append(Language.getComponent("pomodoroLongBreak", ChatColor.LIGHT_PURPLE));
 | 
			
		||||
            } else {
 | 
			
		||||
                builder.append(Language.getComponent("pomodoroShortBreak", ChatColor.LIGHT_PURPLE));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (remainingNanos > 0) {
 | 
			
		||||
                builder.append(" %02d:%02d".formatted(remainingSeconds / 60, remainingSeconds % 60))
 | 
			
		||||
                        .color(ChatColor.GOLD);
 | 
			
		||||
            } else {
 | 
			
		||||
                builder.append(" 00:00")
 | 
			
		||||
                        .color(ChatColor.GREEN);
 | 
			
		||||
 | 
			
		||||
                if (!TweaksConfig.getConfig().pomodoroForce()) {
 | 
			
		||||
                    builder.append( "/pom").color(ChatColor.GOLD);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (remainingNanos > 0) {
 | 
			
		||||
                builder
 | 
			
		||||
                        .append("%02d:%02d".formatted(remainingSeconds / 60, remainingSeconds % 60))
 | 
			
		||||
                        .color(ChatColor.GRAY);
 | 
			
		||||
            } else {
 | 
			
		||||
                builder
 | 
			
		||||
                        .append("00:00")
 | 
			
		||||
                        .color(remainingSeconds % 2 == 0 ? ChatColor.RED : ChatColor.GRAY);
 | 
			
		||||
 | 
			
		||||
                if (!TweaksConfig.getConfig().pomodoroForce()) {
 | 
			
		||||
                    builder.append( "/pom").color(ChatColor.GOLD);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        for (int i=0; i<INTERVALS_BEFORE_LONG_BREAK; i++) {
 | 
			
		||||
            ChatColor color = ChatColor.GRAY;
 | 
			
		||||
            if (i == pomodoro.getIntervalsDone()) {
 | 
			
		||||
                color = ChatColor.LIGHT_PURPLE;
 | 
			
		||||
            } else if (i > pomodoro.getIntervalsDone()) {
 | 
			
		||||
                color = ChatColor.DARK_GRAY;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            builder.append(" o").color(color);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return builder.build();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,34 +9,49 @@ package eu.m724.tweaks.module.pomodoro;
 | 
			
		|||
import eu.m724.tweaks.TweaksPlugin;
 | 
			
		||||
import eu.m724.tweaks.config.TweaksConfig;
 | 
			
		||||
import net.md_5.bungee.api.ChatMessageType;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.Sound;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.plugin.Plugin;
 | 
			
		||||
import org.bukkit.scheduler.BukkitRunnable;
 | 
			
		||||
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
public class PomodoroRunnable extends BukkitRunnable {
 | 
			
		||||
    private final boolean force = TweaksConfig.getConfig().pomodoroForce();
 | 
			
		||||
    private final TweaksConfig config = TweaksConfig.getConfig();
 | 
			
		||||
    private final Plugin plugin = TweaksPlugin.getInstance(); // used only to kick
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
        long now = System.nanoTime();
 | 
			
		||||
 | 
			
		||||
        Bukkit.getOnlinePlayers().forEach(player -> {
 | 
			
		||||
            PlayerPomodoro pomodoro = Pomodoros.get(player);
 | 
			
		||||
            if (pomodoro == null) return;
 | 
			
		||||
        PlayerPomodoroTracker.timers.forEach((uuid, pomodoro) -> {
 | 
			
		||||
            long remainingNanos = pomodoro.getCurrentIntervalRemainingNanos(now);
 | 
			
		||||
            long remainingSecs = TimeUnit.NANOSECONDS.toSeconds(remainingNanos);
 | 
			
		||||
 | 
			
		||||
            long remaining = pomodoro.getRemainingSeconds(now);
 | 
			
		||||
            // TODO make not always on
 | 
			
		||||
            player.spigot().sendMessage(ChatMessageType.ACTION_BAR, Pomodoros.formatTimer(pomodoro, remaining));
 | 
			
		||||
            // TODO optimize?
 | 
			
		||||
            Player player = plugin.getServer().getPlayer(uuid);
 | 
			
		||||
 | 
			
		||||
            if (remaining <= 0) {
 | 
			
		||||
                player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_FALL, 1.0f, 0.5f);
 | 
			
		||||
                if (remaining < -60 && force) {
 | 
			
		||||
                    plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
 | 
			
		||||
                        pomodoro.next();
 | 
			
		||||
                        player.kickPlayer(Pomodoros.formatTimer(pomodoro, pomodoro.getRemainingSeconds(now)).toLegacyText());
 | 
			
		||||
                    });
 | 
			
		||||
            if (player != null && player.isOnline()) {
 | 
			
		||||
                // TODO make not always on
 | 
			
		||||
                player.spigot().sendMessage(ChatMessageType.ACTION_BAR, PomodoroModule.formatTimer(pomodoro, now));
 | 
			
		||||
 | 
			
		||||
                if (remainingNanos <= 0) {
 | 
			
		||||
                    player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_FALL, 1.0f, 0.5f);
 | 
			
		||||
 | 
			
		||||
                    if (remainingSecs < -PomodoroModule.KICK_DELAY_SECONDS && config.pomodoroForce()) {
 | 
			
		||||
                        pomodoro.startBreakOrNextInterval();
 | 
			
		||||
 | 
			
		||||
                        plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () ->
 | 
			
		||||
                                player.kickPlayer(PomodoroModule.formatTimer(pomodoro, now).toLegacyText())
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if (remainingNanos <= 0) {
 | 
			
		||||
                    // Start break automatically if the player is offline
 | 
			
		||||
                    if (!pomodoro.isBreaktime()) {
 | 
			
		||||
                        pomodoro.startBreakOrNextInterval();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,71 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (C) 2025  Minecon724
 | 
			
		||||
 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
 | 
			
		||||
 * in the project root for the full license text.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package eu.m724.tweaks.module.pomodoro;
 | 
			
		||||
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
import net.md_5.bungee.api.chat.BaseComponent;
 | 
			
		||||
import net.md_5.bungee.api.chat.ComponentBuilder;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
public class Pomodoros {
 | 
			
		||||
    static final Map<UUID, PlayerPomodoro> timers = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    public static PlayerPomodoro get(Player player) {
 | 
			
		||||
        return timers.get(player.getUniqueId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static PlayerPomodoro create(Player player) {
 | 
			
		||||
        return timers.computeIfAbsent(player.getUniqueId(), (k) -> new PlayerPomodoro());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean remove(Player player) {
 | 
			
		||||
        return timers.remove(player.getUniqueId()) != null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static BaseComponent formatTimer(PlayerPomodoro pomodoro, long remaining) {
 | 
			
		||||
        ComponentBuilder builder = new ComponentBuilder();
 | 
			
		||||
 | 
			
		||||
        if (pomodoro.isBreak()) {
 | 
			
		||||
            builder.append("Break ").color(ChatColor.LIGHT_PURPLE);
 | 
			
		||||
            if (remaining > 0) {
 | 
			
		||||
                builder.append("%02d:%02d".formatted(remaining / 60, remaining % 60))
 | 
			
		||||
                        .color(ChatColor.GOLD);
 | 
			
		||||
            } else {
 | 
			
		||||
                builder.append("00:00")
 | 
			
		||||
                        .color(ChatColor.GREEN);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (remaining > 0) {
 | 
			
		||||
                builder
 | 
			
		||||
                        .append("%02d:%02d".formatted(remaining / 60, remaining % 60))
 | 
			
		||||
                        .color(ChatColor.GRAY);
 | 
			
		||||
            } else {
 | 
			
		||||
                builder
 | 
			
		||||
                        .append("00:00")
 | 
			
		||||
                        .color(remaining % 2 == 0 ? ChatColor.RED : ChatColor.YELLOW);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        for (int i=0; i<4; i++) {
 | 
			
		||||
            ChatColor color = ChatColor.GRAY;
 | 
			
		||||
            if (i == pomodoro.getPomodori()) {
 | 
			
		||||
                color = ChatColor.LIGHT_PURPLE;
 | 
			
		||||
            } else if (i > pomodoro.getPomodori()) {
 | 
			
		||||
                color = ChatColor.DARK_GRAY;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            builder.append(" o").color(color);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return builder.build();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ chatAlreadyHere = You're already in this room.
 | 
			
		|||
authKickWrongKey = You're connecting to the wrong server address. You must connect to the one you're registered to.
 | 
			
		||||
# If force is enabled and player is not registered. Changing this reveals you're using this plugin
 | 
			
		||||
authKickUnregistered = You are not whitelisted on this server!
 | 
			
		||||
authKickError = An error occured. Please try again. If this persists, contact an administrator.
 | 
			
		||||
authKickError = An error occurred. Please try again. If this persists, contact an administrator.
 | 
			
		||||
 | 
			
		||||
redstoneGatewayItem = Redstone gateway
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,4 +44,10 @@ durabilityDisabled = Disabled durability alert
 | 
			
		|||
wordCoordsPlayerOnly = Only players can execute this command without arguments.
 | 
			
		||||
wordCoordsOutOfRange = Those coordinates are invalid.
 | 
			
		||||
wordCoordsInvalidWord = Invalid word: "%s"
 | 
			
		||||
wordCoordsNoWords = Please provide the Z coordinate.
 | 
			
		||||
wordCoordsNoWords = Please provide the Z coordinate.
 | 
			
		||||
 | 
			
		||||
# /pomodoro
 | 
			
		||||
pomodoroStopped = Pomodoro stopped. Restart it with /%s start
 | 
			
		||||
pomodoroStart = Start pomodoro with /%s start
 | 
			
		||||
pomodoroShortBreak = Short break
 | 
			
		||||
pomodoroLongBreak = Long break
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue