diff --git a/pom.xml b/pom.xml
index 8d29459..9dbefcc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,13 +6,11 @@
eu.m724
tweaks
- 1.0-SNAPSHOT
+ 0.1.0-SNAPSHOT
21
21
- ${maven.build.timestamp}
- dd-MM-yyyy
UTF-8
1.21.1-R0.1-SNAPSHOT
diff --git a/src/main/java/eu/m724/tweaks/TweaksConfig.java b/src/main/java/eu/m724/tweaks/TweaksConfig.java
index 736a93e..1955390 100644
--- a/src/main/java/eu/m724/tweaks/TweaksConfig.java
+++ b/src/main/java/eu/m724/tweaks/TweaksConfig.java
@@ -26,7 +26,10 @@ public record TweaksConfig(
boolean compassEnabled,
int compassWidth,
- int compassPrecision
+ int compassPrecision,
+
+ boolean pomodoroEnabled,
+ boolean pomodoroForce
) {
public static final int CONFIG_VERSION = 1;
private static TweaksConfig config;
@@ -73,6 +76,9 @@ public record TweaksConfig(
int compassWidth = config.getInt("compass.width");
int compassPrecision = config.getInt("compass.precision");
+ boolean pomodoroEnabled = config.getBoolean("pomodoro.enabled");
+ boolean pomodoroForce = config.getBoolean("pomodoro.force");
+
TweaksConfig.config = new TweaksConfig(
isProtocolLib,
hideWorldBorder,
@@ -80,7 +86,8 @@ public record TweaksConfig(
doorEnabled, doorDoubleOpen, doorKnocking,
motdEnabled, motdSet,
chatEnabled, chatLocalEvents, chatDefaultName,
- compassEnabled, compassWidth, compassPrecision
+ compassEnabled, compassWidth, compassPrecision,
+ pomodoroEnabled, pomodoroForce
);
return TweaksConfig.config;
diff --git a/src/main/java/eu/m724/tweaks/TweaksPlugin.java b/src/main/java/eu/m724/tweaks/TweaksPlugin.java
index 7573dda..e38ce93 100644
--- a/src/main/java/eu/m724/tweaks/TweaksPlugin.java
+++ b/src/main/java/eu/m724/tweaks/TweaksPlugin.java
@@ -8,6 +8,8 @@ import eu.m724.tweaks.motd.MotdListener;
import eu.m724.tweaks.ping.F3NameListener;
import eu.m724.tweaks.ping.PingChecker;
import eu.m724.tweaks.ping.PingCommands;
+import eu.m724.tweaks.pomodoro.PomodoroCommands;
+import eu.m724.tweaks.pomodoro.PomodoroManager;
import eu.m724.tweaks.worldborder.WorldBorderManager;
import org.bukkit.plugin.java.JavaPlugin;
@@ -19,8 +21,6 @@ public class TweaksPlugin extends JavaPlugin {
public void onEnable() {
TweaksConfig config = TweaksConfig.load(this);
- new CompassManager(this).init();
-
if (config.chatEnabled()) {
ChatManager chatManager = new ChatManager(this);
chatManager.init();
@@ -60,5 +60,11 @@ public class TweaksPlugin extends JavaPlugin {
if (config.worldborderHide()) {
new WorldBorderManager().init(this);
}
+
+ if (config.pomodoroEnabled()) {
+ new PomodoroManager(this).init();
+ getCommand("pomodoro").setExecutor(new PomodoroCommands());
+ }
+
}
}
diff --git a/src/main/java/eu/m724/tweaks/chat/ChatManager.java b/src/main/java/eu/m724/tweaks/chat/ChatManager.java
index 68ce79e..1b0bc36 100644
--- a/src/main/java/eu/m724/tweaks/chat/ChatManager.java
+++ b/src/main/java/eu/m724/tweaks/chat/ChatManager.java
@@ -28,6 +28,10 @@ public class ChatManager {
}
public void init() {
+ if (plugin.getServer().isEnforcingSecureProfiles()) {
+ throw new RuntimeException("Please disable enforce-secure-profile in server.properties to use chatrooms");
+ }
+
getById(defaultRoom);
plugin.getServer().getPluginManager().registerEvents(new ChatListener(this), plugin);
}
diff --git a/src/main/java/eu/m724/tweaks/playtime/PlaytimeListener.java b/src/main/java/eu/m724/tweaks/playtime/PlaytimeListener.java
deleted file mode 100644
index d51e399..0000000
--- a/src/main/java/eu/m724/tweaks/playtime/PlaytimeListener.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package eu.m724.tweaks.playtime;
-
-public class PlaytimeListener {
-
-}
diff --git a/src/main/java/eu/m724/tweaks/pomodoro/PlayerPomodoro.java b/src/main/java/eu/m724/tweaks/pomodoro/PlayerPomodoro.java
new file mode 100644
index 0000000..ac6bae8
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/pomodoro/PlayerPomodoro.java
@@ -0,0 +1,68 @@
+package eu.m724.tweaks.pomodoro;
+
+public class PlayerPomodoro {
+ private int pomodori = 0;
+
+ private boolean isBreak = false;
+ // this is for both break and not break
+ private long intervalStart = -1;
+
+ /**
+ * A "pomodoro" is the 25-minute cycle you take breaks after
+ * This returns how many cycles already elapsed, so if this is the first cycle this is 0
+ * The break after the "pomodoro," so if it's breaktime after the first "pomodoro" it stays at 0
+ */
+ public int getPomodori() {
+ return pomodori;
+ }
+
+ /**
+ * When did the current interval start
+ * Or when did the break start
+ *
+ * @see PlayerPomodoro#isBreak()
+ */
+ public long getIntervalStart() {
+ return intervalStart;
+ }
+
+ public int getCycleDurationSeconds() {
+ return isBreak ? 300 : 1500;
+ }
+
+ public long getRemainingSeconds(long now) {
+ return getCycleDurationSeconds() - (now - getIntervalStart()) / 1000000000;
+ }
+
+ /**
+ * Is it a break currently
+ */
+ public boolean isBreak() {
+ return isBreak;
+ }
+
+ public boolean isCycleComplete() {
+ return intervalStart + getCycleDurationSeconds() * 1000000000L < System.nanoTime();
+ }
+
+ /**
+ * Resets and starts the timer
+ */
+ public void start() {
+ this.pomodori = 0;
+ this.isBreak = false;
+ this.intervalStart = System.nanoTime();
+ }
+
+ /**
+ * Completes a cycle
+ */
+ public void next() {
+ if (isBreak) { // from break to interval
+ this.pomodori++;
+ }
+
+ this.intervalStart = System.nanoTime();
+ isBreak = !isBreak;
+ }
+}
diff --git a/src/main/java/eu/m724/tweaks/pomodoro/PomodoroCommands.java b/src/main/java/eu/m724/tweaks/pomodoro/PomodoroCommands.java
new file mode 100644
index 0000000..9a640ff
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/pomodoro/PomodoroCommands.java
@@ -0,0 +1,43 @@
+package eu.m724.tweaks.pomodoro;
+
+import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.chat.BaseComponent;
+import net.md_5.bungee.api.chat.ClickEvent;
+import net.md_5.bungee.api.chat.ComponentBuilder;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+public class PomodoroCommands implements CommandExecutor {
+ @Override
+ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
+ Player player = (Player) sender;
+ String action = args.length > 0 ? args[0] : null;
+
+ PlayerPomodoro pomodoro = Pomodoros.get(player);
+
+ if (pomodoro != null) {
+ if ("stop".equals(action)) {
+ Pomodoros.remove(player);
+ sender.sendMessage("Pomodoro disabled");
+ } else {
+ if (pomodoro.isCycleComplete()) {
+ pomodoro.next();
+ }
+ sender.spigot().sendMessage(Pomodoros.formatTimer(pomodoro, pomodoro.getRemainingSeconds(System.nanoTime())));
+ }
+ } else {
+ if ("start".equals(action)) {
+ pomodoro = Pomodoros.create(player);
+ pomodoro.start();
+ sender.spigot().sendMessage(Pomodoros.formatTimer(pomodoro, pomodoro.getCycleDurationSeconds()));
+ } else {
+ sender.sendMessage("Start pomodoro with /pom start");
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/eu/m724/tweaks/pomodoro/PomodoroListener.java b/src/main/java/eu/m724/tweaks/pomodoro/PomodoroListener.java
new file mode 100644
index 0000000..ce2aabf
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/pomodoro/PomodoroListener.java
@@ -0,0 +1,52 @@
+package eu.m724.tweaks.pomodoro;
+
+import net.md_5.bungee.api.ChatColor;
+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.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+public class PomodoroListener implements Listener {
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event) {
+ Player player = event.getPlayer();
+ PlayerPomodoro timer = Pomodoros.get(player);
+ if (timer == null) return;
+
+ if (timer.isBreak()) {
+ if (timer.isCycleComplete()) {
+ timer.next();
+ } else {
+ event.getPlayer().kickPlayer(
+ new ComponentBuilder()
+ .append(Pomodoros.formatTimer(timer, System.nanoTime()))
+ .build().toLegacyText()
+ );
+ }
+ }
+ }
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event) {
+ Player player = event.getPlayer();
+ PlayerPomodoro timer = Pomodoros.timers.get(player);
+ if (timer == null) return;
+
+ if (!timer.isBreak() && timer.isCycleComplete()) {
+ timer.next();
+ }
+ }
+
+ @EventHandler
+ public void onPlayerMove(PlayerMoveEvent event) {
+ Player player = event.getPlayer();
+ PlayerPomodoro timer = Pomodoros.get(player);
+ if (timer == null) return;
+
+ if (timer.isBreak() && timer.getRemainingSeconds(System.nanoTime()) <= 0)
+ timer.next(); // resume timer if break ended
+ }
+}
diff --git a/src/main/java/eu/m724/tweaks/pomodoro/PomodoroManager.java b/src/main/java/eu/m724/tweaks/pomodoro/PomodoroManager.java
new file mode 100644
index 0000000..de3ece0
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/pomodoro/PomodoroManager.java
@@ -0,0 +1,17 @@
+package eu.m724.tweaks.pomodoro;
+
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+public class PomodoroManager {
+ private final Plugin plugin;
+
+ public PomodoroManager(Plugin plugin) {
+ this.plugin = plugin;
+ }
+
+ public void init() {
+ plugin.getServer().getPluginManager().registerEvents(new PomodoroListener(), plugin);
+ new PomodoroRunnable().runTaskTimerAsynchronously(plugin, 0, 20L);
+ }
+}
diff --git a/src/main/java/eu/m724/tweaks/pomodoro/PomodoroRunnable.java b/src/main/java/eu/m724/tweaks/pomodoro/PomodoroRunnable.java
new file mode 100644
index 0000000..9301188
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/pomodoro/PomodoroRunnable.java
@@ -0,0 +1,26 @@
+package eu.m724.tweaks.pomodoro;
+
+import net.md_5.bungee.api.ChatMessageType;
+import net.md_5.bungee.api.chat.ComponentBuilder;
+import org.bukkit.Bukkit;
+import org.bukkit.Sound;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.scheduler.BukkitTask;
+
+public class PomodoroRunnable extends BukkitRunnable {
+ @Override
+ public void run() {
+ long now = System.nanoTime();
+ Bukkit.getOnlinePlayers().forEach(player -> {
+ PlayerPomodoro pomodoro = Pomodoros.get(player);
+ if (pomodoro == null) return;
+
+ long remaining = pomodoro.getRemainingSeconds(now);
+ // TODO make not always on
+ player.spigot().sendMessage(ChatMessageType.ACTION_BAR, Pomodoros.formatTimer(pomodoro, remaining));
+
+ if (remaining <= 0)
+ player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_FALL, 1.0f, 0.5f);
+ });
+ }
+}
diff --git a/src/main/java/eu/m724/tweaks/pomodoro/Pomodoros.java b/src/main/java/eu/m724/tweaks/pomodoro/Pomodoros.java
new file mode 100644
index 0000000..765f496
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/pomodoro/Pomodoros.java
@@ -0,0 +1,65 @@
+package eu.m724.tweaks.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 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("%02d:%02d".formatted(-remaining / 60, -remaining % 60))
+ .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.create();
+ }
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index a23b980..457a2f8 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -44,6 +44,11 @@ compass:
# How many degrees every point
precision: 10
+pomodoro:
+ enabled: true
+ # Players will be unable to join the server during break and will be kicked a short time after pomodoro ends
+ force: true
+
# Finally, thank you for downloading Tweaks724, I hope you enjoy!
# Don't modify unless told to
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 9721320..070b6ad 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -1,5 +1,5 @@
name: Tweaks724
-version: ${project.version}+${timestamp}
+version: ${project.version}
main: eu.m724.tweaks.TweaksPlugin
api-version: 1.21.1
@@ -13,14 +13,23 @@ commands:
aliases: [c, chatroom, cr, room]
chatmanage:
description: Chatroom user management commands
+ permission: tweaks724.chatmanage
aliases: [cm, crm]
ping:
description: Your ping
dkick:
description: Kick a player discreetly
permission: tweaks724.dkick
+ pomodoro:
+ description: Pomodoro management
+ permission: tweaks724.pomodoro
+ aliases: [pom]
permissions:
+ tweaks724.chatmanage:
+ default: true
tweaks724.dkick:
default: op
+ tweaks724.pomodoro:
+ default: true