mirror of
https://github.com/Samsuik/Sakura.git
synced 2025-12-24 01:09:16 +00:00
Add sakura debug command
This commit is contained in:
@@ -2,16 +2,14 @@ package me.samsuik.sakura.command;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
@NullMarked
|
||||
public abstract class BaseSubCommand extends Command {
|
||||
public BaseSubCommand(String name) {
|
||||
super(name);
|
||||
@@ -34,7 +32,6 @@ public abstract class BaseSubCommand extends Command {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
|
||||
List<String> completions = new ArrayList<>(0);
|
||||
|
||||
|
||||
@@ -7,9 +7,7 @@ import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -17,7 +15,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
@NullMarked
|
||||
public final class SakuraCommand extends Command {
|
||||
private static final Component HEADER_MESSAGE = MiniMessage.miniMessage().deserialize("""
|
||||
<dark_purple>.</dark_purple>
|
||||
@@ -37,7 +35,7 @@ public final class SakuraCommand extends Command {
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||
if (args.length > 0) {
|
||||
List<Command> commands = new ArrayList<>(SakuraCommands.COMMANDS.values());
|
||||
List<Command> commands = new ArrayList<>(SakuraCommands.SUB_COMMANDS);
|
||||
|
||||
// This part is copied from the VersionCommand SubCommand in paper
|
||||
Command internalVersion = MinecraftServer.getServer().server.getCommandMap().getCommand("version");
|
||||
@@ -59,7 +57,7 @@ public final class SakuraCommand extends Command {
|
||||
private void sendHelpMessage(CommandSender sender) {
|
||||
sender.sendMessage(HEADER_MESSAGE);
|
||||
|
||||
Stream<Command> uniqueCommands = SakuraCommands.COMMANDS.values()
|
||||
Stream<Command> uniqueCommands = SakuraCommands.SUB_COMMANDS
|
||||
.stream()
|
||||
.filter(command -> command != this);
|
||||
|
||||
@@ -70,14 +68,13 @@ public final class SakuraCommand extends Command {
|
||||
sender.sendMessage(Component.text("'", NamedTextColor.DARK_PURPLE));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
|
||||
if (!this.testPermissionSilent(sender)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return SakuraCommands.COMMANDS.values().stream()
|
||||
return SakuraCommands.SUB_COMMANDS.stream()
|
||||
.filter(command -> command != this)
|
||||
.map(Command::getName)
|
||||
.filter(name -> args.length <= 1 || name.startsWith(args[args.length - 1]))
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
package me.samsuik.sakura.command;
|
||||
|
||||
import me.samsuik.sakura.command.subcommands.ConfigCommand;
|
||||
import me.samsuik.sakura.command.subcommands.TPSCommand;
|
||||
import me.samsuik.sakura.command.subcommands.FPSCommand;
|
||||
import me.samsuik.sakura.command.subcommands.VisualCommand;
|
||||
import me.samsuik.sakura.command.subcommands.*;
|
||||
import me.samsuik.sakura.player.visibility.VisibilityTypes;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@NullMarked
|
||||
public final class SakuraCommands {
|
||||
static final Map<String, Command> COMMANDS = new HashMap<>();
|
||||
static final Set<Command> SUB_COMMANDS = new HashSet<>();
|
||||
|
||||
static {
|
||||
COMMANDS.put("sakura", new SakuraCommand("sakura"));
|
||||
COMMANDS.put("config", new ConfigCommand("config"));
|
||||
@@ -20,11 +23,13 @@ public final class SakuraCommands {
|
||||
COMMANDS.put("fps", new FPSCommand("fps"));
|
||||
COMMANDS.put("tntvisibility", new VisualCommand(VisibilityTypes.TNT, "tnttoggle"));
|
||||
COMMANDS.put("sandvisibility", new VisualCommand(VisibilityTypes.SAND, "sandtoggle"));
|
||||
SUB_COMMANDS.addAll(COMMANDS.values());
|
||||
SUB_COMMANDS.add(new DebugCommand("debug"));
|
||||
}
|
||||
|
||||
public static void registerCommands(MinecraftServer server) {
|
||||
COMMANDS.forEach((s, command) -> {
|
||||
server.server.getCommandMap().register(s, "sakura", command);
|
||||
COMMANDS.forEach((name, command) -> {
|
||||
server.server.getCommandMap().register(name, "sakura", command);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,13 @@ import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
@NullMarked
|
||||
public final class ConfigCommand extends BaseSubCommand {
|
||||
public ConfigCommand(String name) {
|
||||
super(name);
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package me.samsuik.sakura.command.subcommands;
|
||||
|
||||
import me.samsuik.sakura.command.BaseSubCommand;
|
||||
import me.samsuik.sakura.redstone.RedstoneNetwork;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.util.CraftLocation;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@NullMarked
|
||||
public final class DebugCommand extends BaseSubCommand {
|
||||
public DebugCommand(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (!(sender instanceof Player player) || args.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle();
|
||||
if (args[0].equalsIgnoreCase("redstone-cache")) {
|
||||
this.showCachedWires(player, nmsPlayer.level());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tabComplete(List<String> list, String[] args) throws IllegalArgumentException {
|
||||
list.add("redstone-cache");
|
||||
}
|
||||
|
||||
private void showCachedWires(Player player, Level level) {
|
||||
Set<Location> locations = new HashSet<>();
|
||||
for (RedstoneNetwork network : level.redstoneWireCache.getNetworkCache().values()) {
|
||||
byte randomColour = (byte) ThreadLocalRandom.current().nextInt(16);
|
||||
DyeColor dyeColour = DyeColor.getByWoolData(randomColour);
|
||||
Material material = Material.matchMaterial(dyeColour.name() + "_WOOL");
|
||||
|
||||
if (!network.isRegistered()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (BlockPos pos : network.getWirePositions()) {
|
||||
Location location = CraftLocation.toBukkit(pos, level);
|
||||
if (player.getLocation().distance(location) >= 64.0) {
|
||||
continue;
|
||||
}
|
||||
player.sendBlockChange(location, material.createBlockData());
|
||||
locations.add(location);
|
||||
}
|
||||
}
|
||||
|
||||
player.sendRichMessage("<red>Displaying %dx cached redstone wires".formatted(locations.size()));
|
||||
|
||||
level.levelTickScheduler.delayedTask(() -> {
|
||||
for (Location loc : locations) {
|
||||
player.sendBlockChange(loc, loc.getBlock().getBlockData());
|
||||
}
|
||||
}, 1200);
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,9 @@ import me.samsuik.sakura.command.BaseSubCommand;
|
||||
import me.samsuik.sakura.player.visibility.VisibilityGui;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
@NullMarked
|
||||
public final class FPSCommand extends BaseSubCommand {
|
||||
private final VisibilityGui visibilityGui = new VisibilityGui();
|
||||
|
||||
|
||||
@@ -8,12 +8,11 @@ import me.samsuik.sakura.player.visibility.VisibilityType;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
@NullMarked
|
||||
public final class VisualCommand extends BaseSubCommand {
|
||||
private final VisibilityType type;
|
||||
|
||||
|
||||
@@ -7,13 +7,30 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
|
||||
@NullMarked
|
||||
public final class LevelTickScheduler {
|
||||
private final Int2ObjectMap<List<TickTask>> tickTasks = new Int2ObjectLinkedOpenHashMap<>();
|
||||
private final Object2IntMap<TickTask> taskIntervals = new Object2IntOpenHashMap<>();
|
||||
private final Deque<TickTask> removeLater = new ArrayDeque<>();
|
||||
|
||||
public void delayedTask(Runnable runnable, int delay) {
|
||||
this.registerNewTask(new TickTask() {
|
||||
private int cycles = 0;
|
||||
|
||||
@Override
|
||||
public void run(long tick) {
|
||||
if (this.cycles++ >= delay) {
|
||||
runnable.run();
|
||||
LevelTickScheduler.this.removeLater.add(this);
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public void registerNewTask(Runnable runnable, int interval) {
|
||||
this.registerNewTask(tick -> runnable.run(), interval);
|
||||
@@ -23,7 +40,24 @@ public final class LevelTickScheduler {
|
||||
int safeInterval = Math.max(interval + 1, 1);
|
||||
this.tickTasks.computeIfAbsent(safeInterval, i -> new ArrayList<>())
|
||||
.add(task);
|
||||
this.taskIntervals.put(task, Math.max(safeInterval + 1, 1));
|
||||
this.taskIntervals.put(task, safeInterval);
|
||||
}
|
||||
|
||||
private void removeTasks() {
|
||||
TickTask tickTask;
|
||||
while ((tickTask = this.removeLater.poll()) != null) {
|
||||
this.removeTask(tickTask);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeTask(TickTask task) {
|
||||
int interval = this.taskIntervals.removeInt(task);
|
||||
if (interval > 0) {
|
||||
this.tickTasks.computeIfPresent(interval, (i, tasks) -> {
|
||||
tasks.remove(task);
|
||||
return tasks.isEmpty() ? null : tasks;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void runTasks(List<TickTask> tasks, long gameTime) {
|
||||
@@ -39,6 +73,7 @@ public final class LevelTickScheduler {
|
||||
this.runTasks(this.tickTasks.get(interval), gameTime);
|
||||
}
|
||||
}
|
||||
this.removeTasks();
|
||||
}
|
||||
|
||||
public interface TickTask {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.samsuik.sakura.redstone;
|
||||
|
||||
import io.papermc.paper.configuration.WorldConfiguration;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.*;
|
||||
import me.samsuik.sakura.utils.TickExpiry;
|
||||
@@ -41,11 +42,17 @@ public final class RedstoneNetwork {
|
||||
return newBlock.getBlock() != oldBlock.getBlock();
|
||||
}
|
||||
|
||||
public List<BlockPos> getWirePositions() {
|
||||
return this.wireUpdates.stream()
|
||||
.map(RedstoneWireUpdate::getPosition)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public TickExpiry getExpiry() {
|
||||
return this.expiry;
|
||||
}
|
||||
|
||||
private boolean isRegistered() {
|
||||
public boolean isRegistered() {
|
||||
return !this.listeners.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ public final class RedstoneWireCache {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public Map<RedstoneNetworkSource, RedstoneNetwork> getNetworkCache() {
|
||||
return this.networkCache;
|
||||
}
|
||||
|
||||
public boolean isWireUpdating(BlockPos pos) {
|
||||
return this.updatingNetwork != null && this.updatingNetwork.hasWire(pos);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user