diff --git a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java index 657535b79..760fe23c3 100644 --- a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java +++ b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java @@ -1,44 +1,87 @@ package com.simibubi.create.foundation.command; -import java.util.Collections; -import java.util.function.Predicate; - import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; - import net.minecraft.command.CommandSource; import net.minecraft.command.Commands; import net.minecraft.entity.player.PlayerEntity; +import java.util.Collections; +import java.util.function.Predicate; + public class AllCommands { public static Predicate sourceIsPlayer = (cs) -> cs.getEntity() instanceof PlayerEntity; public static void register(CommandDispatcher dispatcher) { - LiteralCommandNode createRoot = dispatcher.register(Commands.literal("create") - //general purpose - .then(ToggleDebugCommand.register()) - .then(OverlayConfigCommand.register()) - .then(FixLightingCommand.register()) - .then(ReplaceInCommandBlocksCommand.register()) - .then(HighlightCommand.register()) - .then(ToggleExperimentalRenderingCommand.register()) + LiteralCommandNode util = buildUtilityCommands(); - //dev-util - //Comment out for release - .then(ClearBufferCacheCommand.register()) - .then(ChunkUtilCommand.register()) - //.then(KillTPSCommand.register()) + LiteralCommandNode createRoot = dispatcher.register(Commands.literal("create") + .requires(cs -> cs.hasPermissionLevel(0)) + //general purpose + .then(new ToggleExperimentalRenderingCommand().register()) + .then(new ToggleDebugCommand().register()) + .then(OverlayConfigCommand.register()) + .then(FixLightingCommand.register()) + .then(HighlightCommand.register()) + .then(CouplingCommand.register()) + + //utility + .then(util) ); + createRoot.addChild(buildRedirect("u", util)); + CommandNode c = dispatcher.findNode(Collections.singleton("c")); if (c != null) return; - dispatcher.register(Commands.literal("c") - .redirect(createRoot) - ); + dispatcher.getRoot().addChild(buildRedirect("c", createRoot)); + + } + + + private static LiteralCommandNode buildUtilityCommands() { + + return Commands.literal("util") + .then(FlySpeedCommand.register()) + .then(ReplaceInCommandBlocksCommand.register()) + .then(ClearBufferCacheCommand.register()) + .then(ChunkUtilCommand.register()) + //.then(KillTPSCommand.register()) + .build(); + + } + + /** + * ***** + * https://github.com/VelocityPowered/Velocity/blob/8abc9c80a69158ebae0121fda78b55c865c0abad/proxy/src/main/java/com/velocitypowered/proxy/util/BrigadierUtils.java#L38 + * ***** + *

+ * Returns a literal node that redirects its execution to + * the given destination node. + * + * @param alias the command alias + * @param destination the destination node + * + * @return the built node + */ + public static LiteralCommandNode buildRedirect(final String alias, final LiteralCommandNode destination) { + // Redirects only work for nodes with children, but break the top argument-less command. + // Manually adding the root command after setting the redirect doesn't fix it. + // See https://github.com/Mojang/brigadier/issues/46). Manually clone the node instead. + LiteralArgumentBuilder builder = LiteralArgumentBuilder + .literal(alias) + .requires(destination.getRequirement()) + .forward( + destination.getRedirect(), destination.getRedirectModifier(), destination.isFork()) + .executes(destination.getCommand()); + for (CommandNode child : destination.getChildren()) { + builder.then(child); + } + return builder.build(); } } diff --git a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigCommand.java b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigCommand.java new file mode 100644 index 000000000..7937764cb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigCommand.java @@ -0,0 +1,45 @@ +package com.simibubi.create.foundation.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.ArgumentBuilder; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.entity.player.ServerPlayerEntity; + +public abstract class ConfigureConfigCommand { + + protected final String commandLiteral; + + ConfigureConfigCommand(String commandLiteral) { + this.commandLiteral = commandLiteral; + } + + ArgumentBuilder register() { + return Commands.literal(this.commandLiteral) + .requires(cs -> cs.hasPermissionLevel(0)) + .then(Commands.literal("on") + .executes(ctx -> { + ServerPlayerEntity player = ctx.getSource().asPlayer(); + sendPacket(player, String.valueOf(true)); + + return Command.SINGLE_SUCCESS; + }) + ) + .then(Commands.literal("off") + .executes(ctx -> { + ServerPlayerEntity player = ctx.getSource().asPlayer(); + sendPacket(player, String.valueOf(false)); + + return Command.SINGLE_SUCCESS; + }) + ) + .executes(ctx -> { + ServerPlayerEntity player = ctx.getSource().asPlayer(); + sendPacket(player, "info"); + + return Command.SINGLE_SUCCESS; + }); + } + + protected abstract void sendPacket(ServerPlayerEntity player, String option); +} diff --git a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java index a8d174725..692933155 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java +++ b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java @@ -1,23 +1,25 @@ package com.simibubi.create.foundation.command; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; - import com.simibubi.create.content.contraptions.goggles.GoggleConfigScreen; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.networking.SimplePacketBase; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; - import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.network.PacketBuffer; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.ForgeConfig; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.network.NetworkEvent; +import org.apache.logging.log4j.LogManager; + +import java.util.function.Consumer; +import java.util.function.Supplier; public class ConfigureConfigPacket extends SimplePacketBase { @@ -79,23 +81,44 @@ public class ConfigureConfigPacket extends SimplePacketBase { @OnlyIn(Dist.CLIENT) private static void rainbowDebug(String value) { + ClientPlayerEntity player = Minecraft.getInstance().player; + if (player == null || "".equals(value)) return; + + if (value.equals("info")) { + ITextComponent text = new StringTextComponent("Rainbow Debug Utility is currently: ").appendSibling(boolToText(AllConfigs.CLIENT.rainbowDebug.get())); + player.sendStatusMessage(text, false); + return; + } + AllConfigs.CLIENT.rainbowDebug.set(Boolean.parseBoolean(value)); + ITextComponent text = boolToText(AllConfigs.CLIENT.rainbowDebug.get()).appendSibling(new StringTextComponent(" Rainbow Debug Utility").applyTextStyle(TextFormatting.WHITE)); + player.sendStatusMessage(text, false); } @OnlyIn(Dist.CLIENT) private static void experimentalRendering(String value) { - if (!"".equals(value)) { - AllConfigs.CLIENT.experimentalRendering.set(Boolean.parseBoolean(value)); + ClientPlayerEntity player = Minecraft.getInstance().player; + if (player == null || "".equals(value)) return; + + if (value.equals("info")) { + ITextComponent text = new StringTextComponent("Experimental Rendering is currently: ").appendSibling(boolToText(AllConfigs.CLIENT.experimentalRendering.get())); + player.sendStatusMessage(text, false); + return; } + + AllConfigs.CLIENT.experimentalRendering.set(Boolean.parseBoolean(value)); + ITextComponent text = boolToText(AllConfigs.CLIENT.experimentalRendering.get()).appendSibling(new StringTextComponent(" Experimental Rendering").applyTextStyle(TextFormatting.WHITE)); + player.sendStatusMessage(text, false); + FastRenderDispatcher.refresh(); } - + @OnlyIn(Dist.CLIENT) private static void overlayReset(String value) { AllConfigs.CLIENT.overlayOffsetX.set(0); AllConfigs.CLIENT.overlayOffsetY.set(0); } - + @OnlyIn(Dist.CLIENT) private static void overlayScreen(String value) { ScreenOpener.open(new GoggleConfigScreen()); @@ -106,5 +129,11 @@ public class ConfigureConfigPacket extends SimplePacketBase { ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.set(true); Minecraft.getInstance().worldRenderer.loadRenderers(); } + + private static ITextComponent boolToText(boolean b) { + return b + ? new StringTextComponent("enabled").applyTextStyle(TextFormatting.DARK_GREEN) + : new StringTextComponent("disabled").applyTextStyle(TextFormatting.RED); + } } } diff --git a/src/main/java/com/simibubi/create/foundation/command/CouplingCommand.java b/src/main/java/com/simibubi/create/foundation/command/CouplingCommand.java new file mode 100644 index 000000000..8e4512956 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/CouplingCommand.java @@ -0,0 +1,136 @@ +package com.simibubi.create.foundation.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler; +import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; +import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; +import com.simibubi.create.foundation.utility.Iterate; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.arguments.EntityArgument; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.text.StringTextComponent; +import net.minecraftforge.common.util.LazyOptional; + +import java.util.UUID; + +public class CouplingCommand { + + public static final SimpleCommandExceptionType ONLY_MINECARTS_ALLOWED = new SimpleCommandExceptionType(new StringTextComponent("Only Minecarts can be coupled")); + public static final SimpleCommandExceptionType SAME_DIMENSION = new SimpleCommandExceptionType(new StringTextComponent("Minecarts have to be in the same Dimension")); + + public static ArgumentBuilder register() { + + return Commands.literal("coupling") + .requires(cs -> cs.hasPermissionLevel(2)) + .then(Commands.literal("add") + .then(Commands.argument("cart1", EntityArgument.entity()) + .then(Commands.argument("cart2", EntityArgument.entity()) + .executes(ctx -> { + Entity cart1 = EntityArgument.getEntity(ctx, "cart1"); + if (!(cart1 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + Entity cart2 = EntityArgument.getEntity(ctx, "cart2"); + if (!(cart2 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + if (!cart1.getEntityWorld().equals(cart2.getEntityWorld())) + throw SAME_DIMENSION.create(); + + Entity source = ctx.getSource().getEntity(); + + CouplingHandler.tryToCoupleCarts(source instanceof PlayerEntity ? (PlayerEntity) source : null, cart1.getEntityWorld(), cart1.getEntityId(), cart2.getEntityId()); + + return Command.SINGLE_SUCCESS; + }) + ) + ) + ) + .then(Commands.literal("remove") + .then(Commands.argument("cart1", EntityArgument.entity()) + .then(Commands.argument("cart2", EntityArgument.entity()) + .executes(ctx -> { + Entity cart1 = EntityArgument.getEntity(ctx, "cart1"); + if (!(cart1 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + Entity cart2 = EntityArgument.getEntity(ctx, "cart2"); + if (!(cart2 instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + LazyOptional cart1Capability = cart1.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY); + if (!cart1Capability.isPresent()) { + ctx.getSource().sendFeedback(new StringTextComponent("Minecart has no Couplings Attached"), true); + return 0; + } + + MinecartController cart1Controller = cart1Capability.orElse(null); + + int cart1Couplings = (cart1Controller.isConnectedToCoupling() ? 1 : 0) + (cart1Controller.isLeadingCoupling() ? 1 : 0); + if (cart1Couplings == 0) { + ctx.getSource().sendFeedback(new StringTextComponent("Minecart has no Couplings Attached"), true); + return 0; + } + + for (boolean bool : Iterate.trueAndFalse) { + UUID coupledCart = cart1Controller.getCoupledCart(bool); + if (coupledCart == null) + continue; + + if (coupledCart != cart2.getUniqueID()) + continue; + + MinecartController cart2Controller = CapabilityMinecartController.getIfPresent(cart1.getEntityWorld(), coupledCart); + if (cart2Controller == null) + return 0; + + cart1Controller.removeConnection(bool); + cart2Controller.removeConnection(!bool); + return Command.SINGLE_SUCCESS; + } + + ctx.getSource().sendFeedback(new StringTextComponent("The specified Carts are not coupled"), true); + + return 0; + }) + ) + ) + ) + .then(Commands.literal("removeAll") + .then(Commands.argument("cart", EntityArgument.entity()) + .executes(ctx -> { + Entity cart = EntityArgument.getEntity(ctx, "cart"); + if (!(cart instanceof AbstractMinecartEntity)) + throw ONLY_MINECARTS_ALLOWED.create(); + + LazyOptional capability = cart.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY); + if (!capability.isPresent()) { + ctx.getSource().sendFeedback(new StringTextComponent("Minecart has no Couplings Attached"), true); + return 0; + } + + MinecartController controller = capability.orElse(null); + + int couplings = (controller.isConnectedToCoupling() ? 1 : 0) + (controller.isLeadingCoupling() ? 1 : 0); + if (couplings == 0) { + ctx.getSource().sendFeedback(new StringTextComponent("Minecart has no Couplings Attached"), true); + return 0; + } + + controller.decouple(); + + ctx.getSource().sendFeedback(new StringTextComponent("Removed " + couplings + " couplings from the Minecart"), true); + + return couplings; + }) + ) + ); + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/command/FlySpeedCommand.java b/src/main/java/com/simibubi/create/foundation/command/FlySpeedCommand.java new file mode 100644 index 000000000..f34c689d2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/FlySpeedCommand.java @@ -0,0 +1,64 @@ +package com.simibubi.create.foundation.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.FloatArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.arguments.EntityArgument; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.play.server.SPlayerAbilitiesPacket; +import net.minecraft.util.text.StringTextComponent; + +public class FlySpeedCommand { + + public static ArgumentBuilder register() { + return Commands.literal("flySpeed") + .requires(cs -> cs.hasPermissionLevel(2)) + .then(Commands.argument("speed", FloatArgumentType.floatArg(0)) + .then(Commands.argument("target", EntityArgument.player()) + .executes(ctx -> sendFlySpeedUpdate( + ctx, + EntityArgument.getPlayer(ctx, "target"), + FloatArgumentType.getFloat(ctx, "speed") + ) + ) + ) + .executes(ctx -> sendFlySpeedUpdate( + ctx, + ctx.getSource().asPlayer(), + FloatArgumentType.getFloat(ctx, "speed") + ) + ) + ) + .then(Commands.literal("reset") + .then(Commands.argument("target", EntityArgument.player()) + .executes(ctx -> sendFlySpeedUpdate( + ctx, + EntityArgument.getPlayer(ctx, "target"), + 0.05f + ) + ) + ) + .executes(ctx -> sendFlySpeedUpdate( + ctx, + ctx.getSource().asPlayer(), + 0.05f + ) + ) + + ); + } + + private static int sendFlySpeedUpdate(CommandContext ctx, ServerPlayerEntity player, float speed) { + SPlayerAbilitiesPacket packet = new SPlayerAbilitiesPacket(player.abilities); + packet.setFlySpeed(speed); + player.connection.sendPacket(packet); + + ctx.getSource().sendFeedback(new StringTextComponent("Temporarily set " + player.getName().getFormattedText() + "'s Flying Speed to: " + speed), true); + + return Command.SINGLE_SUCCESS; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java b/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java index 918d3dc7c..d8953c8f1 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java @@ -1,38 +1,20 @@ package com.simibubi.create.foundation.command; -import com.mojang.brigadier.Command; -import com.mojang.brigadier.arguments.BoolArgumentType; -import com.mojang.brigadier.builder.ArgumentBuilder; import com.simibubi.create.foundation.networking.AllPackets; - -import net.minecraft.command.CommandSource; -import net.minecraft.command.Commands; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.util.text.StringTextComponent; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.network.PacketDistributor; -public class ToggleDebugCommand { +public class ToggleDebugCommand extends ConfigureConfigCommand { - static ArgumentBuilder register() { - return Commands.literal("toggleDebug") - .requires(cs -> cs.hasPermissionLevel(0)) - .then(Commands.argument("value", BoolArgumentType.bool()) - .executes(ctx -> { - boolean value = BoolArgumentType.getBool(ctx, "value"); - //DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> AllConfigs.CLIENT.rainbowDebug.set(value)); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ConfigureConfigPacket.Actions.rainbowDebug.performAction(String.valueOf(value))); + public ToggleDebugCommand() { + super("rainbowDebug"); + } - DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () -> - AllPackets.channel.send( - PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.rainbowDebug.name(), String.valueOf(value)))); - - ctx.getSource().sendFeedback(new StringTextComponent((value ? "enabled" : "disabled") + " rainbow debug"), true); - - return Command.SINGLE_SUCCESS; - }) - ); + @Override + protected void sendPacket(ServerPlayerEntity player, String option) { + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new ConfigureConfigPacket(ConfigureConfigPacket.Actions.rainbowDebug.name(), option) + ); } } diff --git a/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java b/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java index 25970ac7a..e80862f33 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java @@ -1,36 +1,20 @@ package com.simibubi.create.foundation.command; -import com.mojang.brigadier.arguments.BoolArgumentType; -import com.mojang.brigadier.builder.ArgumentBuilder; import com.simibubi.create.foundation.networking.AllPackets; - -import net.minecraft.command.CommandSource; -import net.minecraft.command.Commands; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.util.text.StringTextComponent; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.network.PacketDistributor; -public class ToggleExperimentalRenderingCommand { +public class ToggleExperimentalRenderingCommand extends ConfigureConfigCommand { - static ArgumentBuilder register() { - return Commands.literal("experimentalRendering") - .requires(cs -> cs.hasPermissionLevel(0)) - .then(Commands.argument("value", BoolArgumentType.bool()) - .executes(ctx -> { - boolean value = BoolArgumentType.getBool(ctx, "value"); - //DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> AllConfigs.CLIENT.rainbowDebug.set(value)); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ConfigureConfigPacket.Actions.experimentalRendering.performAction(String.valueOf(value))); + public ToggleExperimentalRenderingCommand() { + super("experimentalRendering"); + } - DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () -> - AllPackets.channel.send( - PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.experimentalRendering.name(), String.valueOf(value)))); - - ctx.getSource().sendFeedback(new StringTextComponent((value ? "enabled" : "disabled") + " experimental rendering"), true); - - return 1; - })); + @Override + protected void sendPacket(ServerPlayerEntity player, String option) { + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new ConfigureConfigPacket(ConfigureConfigPacket.Actions.experimentalRendering.name(), option) + ); } }