Skip to content

Commit

Permalink
feat: add /schedulerestart and related features
Browse files Browse the repository at this point in the history
  • Loading branch information
acrylic-style committed Sep 14, 2023
1 parent bfe9ead commit ab9f18e
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 26 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {
}

group = "net.azisaba"
version = "6.6.13"
version = "6.7.0"

java {
toolchain.languageVersion.set(JavaLanguageVersion.of(8))
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/com/github/mori01231/lifecore/LifeCore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.github.mori01231.lifecore.config.*
import com.github.mori01231.lifecore.gui.DropProtectScreen
import com.github.mori01231.lifecore.listener.*
import com.github.mori01231.lifecore.listener.item.GlassHammerItemListener
import com.github.mori01231.lifecore.listener.item.LavaSpongeItemListener
import com.github.mori01231.lifecore.listener.item.OreOnlyItemListener
import com.github.mori01231.lifecore.listener.item.WandItemListener
import com.github.mori01231.lifecore.network.PacketHandler
Expand All @@ -31,7 +32,7 @@ import java.util.concurrent.Executor
import java.util.concurrent.Executors

class LifeCore : JavaPlugin() {
private val gcListener = GCListener(this)
val gcListener = GCListener(this)
@JvmField
val ngWordsCache = NGWordsCache()
private val executorService = Executors.newFixedThreadPool(2)
Expand Down Expand Up @@ -124,6 +125,8 @@ class LifeCore : JavaPlugin() {
registerCommand("fixtime", FixTimeCommand)
registerCommand("lifecoreconfig", LifeCoreConfigCommand(this))
registerCommand("townconfig", TownConfigCommand(this))
registerCommand("schedulerestart", ScheduleRestartCommand(this))
registerCommand("gclistenerrestartextendtimecommand", GCListenerRestartExtendTimeCommand(this))
registerCommand("respawn") { _, _, _, args ->
args.getOrNull(0)?.let { Bukkit.getPlayerExact(it)?.spigot()?.respawn() }
true
Expand Down Expand Up @@ -253,6 +256,7 @@ class LifeCore : JavaPlugin() {
// Items
pm.registerEvents(OreOnlyItemListener(), this)
pm.registerEvents(GlassHammerItemListener(), this)
pm.registerEvents(LavaSpongeItemListener(), this)
if (config.getBoolean("destroy-experience-orb-on-chunk-load", false)) {
pm.registerEvents(DestroyExperienceOrbListener(), this)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.github.mori01231.lifecore.command;

import com.github.mori01231.lifecore.LifeCore;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class GCListenerRestartExtendTimeCommand implements TabExecutor {
private final LifeCore plugin;
private final Set<UUID> players = new HashSet<>();

public GCListenerRestartExtendTimeCommand(@NotNull LifeCore plugin) {
this.plugin = plugin;
}

@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!plugin.getGcListener().isTriggered()) return true;
if (!(sender instanceof Player)) {
return true;
}
Player player = (Player) sender;
players.add(player.getUniqueId());
sender.sendMessage(ChatColor.GREEN + "投票しました。");
if (sender.hasPermission("lifecore.extend-time-immediately") || players.size() == 5) {
ScheduleRestartCommand.schedule(30);
}
return true;
}

@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package com.github.mori01231.lifecore.command;

import com.github.mori01231.lifecore.LifeCore;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class ScheduleRestartCommand implements TabExecutor {
private static final Map<Integer, Set<Action>> ACTIONS = new HashMap<>();
private static final List<BukkitTask> tasks = new ArrayList<>();
private final LifeCore plugin;

public ScheduleRestartCommand(@NotNull LifeCore plugin) {
this.plugin = plugin;
}

@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 0) {
sender.sendMessage(ChatColor.RED + "/schedulerestart <minutes>");
return true;
}
if (args[0].equalsIgnoreCase("gc")) {
plugin.getGcListener().triggerNow();
return true;
}
int minutes = Integer.parseInt(args[0]);
schedule(minutes);
return true;
}

public static void schedule(int minutes) {
for (BukkitTask task : tasks) {
task.cancel();
}
tasks.clear();
Bukkit.broadcastMessage("§6[§dお知らせ§6] §aこのサーバーは§d" + minutes + "分後" + "§aに再起動されます。");
int maxTicks = minutes * 60 * 20;
ACTIONS.forEach((seconds, actions) -> {
if (seconds < minutes * 60) {
BukkitTask task = Bukkit.getScheduler().runTaskLater(LifeCore.getPlugin(LifeCore.class), () -> {
for (Action action : actions) {
action.execute(seconds);
}
}, maxTicks - seconds * 20);
tasks.add(task);
}
});
}

@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
return Collections.singletonList("gc");
}

public enum Action {
BROADCAST {
@Override
public void execute(int seconds) {
if (seconds >= 60) {
int minutes = seconds / 60;
Bukkit.broadcastMessage("§6[§dお知らせ§6] §aこのサーバーは§d" + minutes + "分後" + "§aに再起動されます。");
} else {
Bukkit.broadcastMessage("§6[§dお知らせ§6] §aこのサーバーは§c" + seconds + "秒後" + "§aに再起動されます。");
}
}
},
ENABLE_WHITELIST {
@Override
public void execute(int seconds) {
Bukkit.setWhitelist(true);
}
},
SAVE_AND_KICK_ALL_PLAYERS {
@Override
public void execute(int seconds) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "mpdb saveAndKick");
for (Player player : Bukkit.getOnlinePlayers()) {
player.kickPlayer("Server closed");
}
}
},
SCHEDULE_SHUTDOWN_SERVER {
@Override
public void execute(int seconds) {
Bukkit.getScheduler().runTaskLater(LifeCore.getPlugin(LifeCore.class), Bukkit::shutdown, 20 * 60);
}
},
;

public abstract void execute(int seconds);
}

@NotNull
@Contract("_ -> new")
private static Set<Action> setOf(@NotNull Action... actions) {
return new HashSet<>(Arrays.asList(actions));
}

static {
ACTIONS.put(60 * 60, setOf(Action.BROADCAST));
ACTIONS.put(55 * 60, setOf(Action.BROADCAST));
ACTIONS.put(50 * 60, setOf(Action.BROADCAST));
ACTIONS.put(45 * 60, setOf(Action.BROADCAST));
ACTIONS.put(40 * 60, setOf(Action.BROADCAST));
ACTIONS.put(35 * 60, setOf(Action.BROADCAST));
ACTIONS.put(30 * 60, setOf(Action.BROADCAST));
ACTIONS.put(25 * 60, setOf(Action.BROADCAST));
ACTIONS.put(20 * 60, setOf(Action.BROADCAST));
ACTIONS.put(15 * 60, setOf(Action.BROADCAST));
ACTIONS.put(10 * 60, setOf(Action.BROADCAST));
ACTIONS.put(5 * 60, setOf(Action.BROADCAST));
ACTIONS.put(4 * 60, setOf(Action.BROADCAST));
ACTIONS.put(3 * 60, setOf(Action.BROADCAST));
ACTIONS.put(2 * 60, setOf(Action.BROADCAST, Action.ENABLE_WHITELIST));
ACTIONS.put(60, setOf(Action.BROADCAST));
ACTIONS.put(30, setOf(Action.BROADCAST));
ACTIONS.put(10, setOf(Action.BROADCAST));
ACTIONS.put(5, setOf(Action.BROADCAST));
ACTIONS.put(4, setOf(Action.BROADCAST));
ACTIONS.put(3, setOf(Action.BROADCAST));
ACTIONS.put(2, setOf(Action.BROADCAST));
ACTIONS.put(1, setOf(Action.BROADCAST));
ACTIONS.put(0, setOf(Action.SAVE_AND_KICK_ALL_PLAYERS, Action.SCHEDULE_SHUTDOWN_SERVER));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.github.mori01231.lifecore.listener.item;

import com.github.mori01231.lifecore.util.ItemUtil;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.util.RayTraceResult;

public class LavaSpongeItemListener implements Listener {
private static final String ITEM_ID = "56fabea9-e1f9-4e7f-ae78-83e07e8b8767";

@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerInteract(PlayerInteractEvent e) {
if (e.getAction() != Action.RIGHT_CLICK_AIR && e.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
if (e.getAction() == Action.RIGHT_CLICK_BLOCK && e.useItemInHand() == Event.Result.DENY) return;
RayTraceResult result = e.getPlayer().rayTraceBlocks(4, FluidCollisionMode.ALWAYS);
if (result == null || result.getHitBlock() == null) {
return;
}
if (!ITEM_ID.equals(ItemUtil.getStringTag(e.getItem(), "LifeItemId"))) {
// wrong item
return;
}
int affected = 0;
int radius = 2;
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
for (int dz = -radius; dz <= radius; dz++) {
Location loc = result.getHitBlock().getLocation().clone().add(dx, dy, dz);
Block block = loc.getBlock();
if (block.getType() != Material.LAVA && block.getType() != Material.WATER) {
// wrong block
continue;
}
if (new BlockBreakEvent(block, e.getPlayer()).callEvent()) {
block.setType(Material.AIR, true);
affected++;
}
}
}
}
if (affected > 0 && e.getPlayer().getGameMode() != GameMode.CREATIVE) {
// TODO: reduce durability
}
}
}
72 changes: 48 additions & 24 deletions src/main/java/com/github/mori01231/lifecore/util/GCListener.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.github.mori01231.lifecore.util;

import com.github.mori01231.lifecore.LifeCore;
import com.github.mori01231.lifecore.command.ScheduleRestartCommand;
import com.sun.management.GarbageCollectionNotificationInfo;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;

import javax.management.ListenerNotFoundException;
Expand All @@ -17,7 +21,7 @@ public class GCListener implements NotificationListener {
private final LifeCore plugin;
private long lastGcTime = 0L;
private int count = 0;

public GCListener(LifeCore plugin) {
this.plugin = plugin;
}
Expand Down Expand Up @@ -52,9 +56,13 @@ public void unregister() {
}
}

public boolean isTriggered() {
return count < 0;
}

public synchronized void handleGc() {
if (count < 0) {
// exceeded max count
if (isTriggered()) {
// exceeded max count or triggered manually
return;
}
long minutes = (System.currentTimeMillis() - lastGcTime) / 1000 / 60;
Expand All @@ -66,29 +74,45 @@ public synchronized void handleGc() {
return;
}
if (count >= plugin.getConfig().getInt("gc-threshold-count", 10)) {
count = -1;
for (String command : plugin.getConfig().getStringList("gc-triggered-command")) {
try {
if (command.startsWith("@delay ")) {
try {
int delayTicks = Integer.parseInt(command.substring(7, command.indexOf(' ', 7)));
String actualCommand = command.substring(command.indexOf(' ', 7) + 1);
Bukkit.getScheduler().runTaskLater(
plugin,
() -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), actualCommand),
delayTicks);
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Invalid @delay: " + command);
e.printStackTrace();
}
} else {
Bukkit.getScheduler().runTask(plugin, () ->
Bukkit.dispatchCommand(plugin.getServer().getConsoleSender(), command));
triggerNow();
}
}

public synchronized void triggerNow() {
if (isTriggered()) return;
count = -1;
for (String command : plugin.getConfig().getStringList("gc-triggered-command")) {
try {
if (command.startsWith("@delay ")) {
try {
int delayTicks = Integer.parseInt(command.substring(7, command.indexOf(' ', 7)));
String actualCommand = command.substring(command.indexOf(' ', 7) + 1);
Bukkit.getScheduler().runTaskLater(
plugin,
() -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), actualCommand),
delayTicks);
} catch (IllegalArgumentException e) {
plugin.getSLF4JLogger().warn("Invalid @delay: " + command, e);
}
} else if (command.startsWith("@schedulerestart ")) {
try {
int delayMinutes = Integer.parseInt(command.substring("@schedulerestart ".length()));
ScheduleRestartCommand.schedule(delayMinutes);
TextComponent component = new TextComponent("再起動までの時間を延長するには、このメッセージをクリックしてください。");
component.setColor(ChatColor.AQUA);
component.setUnderlined(true);
component.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/gclistenerrestartextendtimecommand"));
Bukkit.broadcast(component);
Bukkit.broadcastMessage("§a5人が上のメッセージをクリックすると、30分に延長されます。");
} catch (IllegalArgumentException e) {
plugin.getSLF4JLogger().warn("Invalid @schedulerestart: " + command, e);
}
} catch (Exception e) {
plugin.getLogger().warning("Failed to process command: " + command);
e.printStackTrace();
} else {
Bukkit.getScheduler().runTask(plugin, () ->
Bukkit.dispatchCommand(plugin.getServer().getConsoleSender(), command));
}
} catch (Exception e) {
plugin.getSLF4JLogger().warn("Failed to process command: " + command, e);
}
}
}
Expand Down
Loading

0 comments on commit ab9f18e

Please sign in to comment.