9
0
mirror of https://github.com/Samsuik/Sakura.git synced 2025-12-30 04:09:09 +00:00

Add /mechanic command to view server mechanics

This commit is contained in:
Samsuik
2025-10-12 21:34:40 +01:00
parent b6f120fc0c
commit 081feaa2de
5 changed files with 115 additions and 1 deletions

View File

@@ -26,6 +26,7 @@ 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"));
COMMANDS.put("mechanic", new MechanicCommand("mechanic"));
SUB_COMMANDS.addAll(COMMANDS.values());
SUB_COMMANDS.add(new DebugCommand("debug"));
// "sakura" isn't a subcommand

View File

@@ -0,0 +1,96 @@
package me.samsuik.sakura.command.subcommands;
import me.samsuik.sakura.command.PlayerOnlySubCommand;
import me.samsuik.sakura.configuration.GlobalConfiguration;
import me.samsuik.sakura.configuration.local.CachedLocalConfiguration;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.minecraft.core.BlockPos;
import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.entity.Entity;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.entity.EntitySpawnEvent;
import org.bukkit.util.Vector;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.List;
@NullMarked
public final class MechanicCommand extends PlayerOnlySubCommand {
private static final String MECHANIC_INFORMATION_MESSAGE = """
Mechanic Version: <yellow><mechanic_version></yellow>
Height Parity: <yellow><height_parity></yellow>
Tnt Spread: <yellow><tnt_spread></yellow>
Tnt Flow: <yellow><tnt_flow></yellow>
Redstone Implementation: <yellow><redstone_implementation></yellow>
"optimize-explosions": <yellow><broken_explosion_behaviour></yellow>
Consistent Radius: <yellow><consistent_radius></yellow>
Lava Flow Speed: <yellow><lava_flow_speed></yellow>""";
public MechanicCommand(final String name) {
super(name);
this.setAliases(List.of("mechanics", "mech"));
this.description = "Displays information related to cannon mechanics";
}
@Override
public void execute(final Player player, final String[] args) {
final Location location = player.getLocation();
final BlockPos blockPos = CraftLocation.toBlockPosition(location);
final CraftWorld craftWorld = ((CraftWorld) location.getWorld());
final CachedLocalConfiguration config = craftWorld.getHandle().localConfig().at(blockPos);
player.sendMessage(GlobalConfiguration.get().messages.mechanicInformationComponent(
MiniMessage.miniMessage().deserialize(
MECHANIC_INFORMATION_MESSAGE,
Placeholder.unparsed("mechanic_version", config.mechanicsTarget.toString()),
Placeholder.unparsed("height_parity", String.valueOf(this.hasHeightParity(location))),
Placeholder.unparsed("tnt_spread", this.getTntSpread(location)),
Placeholder.unparsed("tnt_flow", String.valueOf(this.hasTntFlow(location))),
Placeholder.unparsed("redstone_implementation", config.redstoneBehaviour.implementation().getFriendlyName()),
Placeholder.unparsed("broken_explosion_behaviour", String.valueOf(craftWorld.getHandle().paperConfig().environment.optimizeExplosions)),
Placeholder.unparsed("consistent_radius", String.valueOf(config.consistentExplosionRadius)),
Placeholder.unparsed("lava_flow_speed", String.valueOf(config.lavaFlowSpeed))
)
));
}
private boolean hasHeightParity(final Location location) {
final FallingBlock fallingBlock = this.createTestEntity(location, FallingBlock.class);
return fallingBlock != null && fallingBlock.getHeightParity();
}
private String getTntSpread(final Location location) {
final TNTPrimed tnt = this.createTestEntity(location, TNTPrimed.class);
if (tnt == null) {
return "unknown";
}
final Vector velocity = tnt.getVelocity();
final String spread;
if (velocity.getX() != 0.0 && velocity.getY() != 0.0) {
spread = "ALL";
} else if (velocity.getY() != 0.0) {
spread = "Y";
} else {
spread = "NONE";
}
return spread;
}
private boolean hasTntFlow(final Location location) {
final TNTPrimed tnt = this.createTestEntity(location, TNTPrimed.class);
return tnt == null || tnt.isPushedByFluid();
}
private <T extends Entity> @Nullable T createTestEntity(final Location location, final Class<T> type) {
final T entity = location.getWorld().createEntity(location, type);
return new EntitySpawnEvent(entity).callEvent() ? entity : null;
}
}

View File

@@ -5,8 +5,11 @@ import io.papermc.paper.configuration.Configuration;
import io.papermc.paper.configuration.ConfigurationPart;
import io.papermc.paper.configuration.type.number.IntOr;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.Material;
import org.slf4j.Logger;
import org.spongepowered.configurate.objectmapping.meta.Comment;
@@ -34,6 +37,7 @@ public final class GlobalConfiguration extends ConfigurationPart {
public class Messages extends ConfigurationPart {
public String durableBlockInteraction = "<dark_gray>(<light_purple>S</light_purple>) <white>This block has <gray><remaining></gray> of <gray><durability>";
public String fpsSettingChange = "<dark_gray>(<light_purple>S</light_purple>) <gray><state> <yellow><name>";
public String mechanicInformation = "<dark_gray>(<light_purple>S</light_purple>) <white>For mechanic information: <yellow><information><hover here></information>";
public boolean tpsShowEntityAndChunkCount = true;
public Component fpsSettingChangeComponent(final String name, final String state) {
@@ -51,6 +55,13 @@ public final class GlobalConfiguration extends ConfigurationPart {
Placeholder.unparsed("durability", String.valueOf(durability))
);
}
public Component mechanicInformationComponent(final Component hoverComponent) {
return MiniMessage.miniMessage().deserialize(
this.mechanicInformation,
TagResolver.resolver("information", Tag.styling(HoverEvent.showText(hoverComponent)))
);
}
}
public Fps fps;