Files
TiedUp-/src/main/java/com/tiedup/remake/commands/ClothesCommand.java
NotEvil f6466360b6 Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies,
and third-party source dumps. Add proper README, update .gitignore,
clean up Makefile.
2026-04-12 00:51:22 +02:00

312 lines
10 KiB
Java

package com.tiedup.remake.commands;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.tiedup.remake.items.clothes.GenericClothes;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
/**
* Command handler for clothes configuration.
*
* Subcommands:
* /tiedup clothes url set <url> - Set dynamic texture URL on held clothes
* /tiedup clothes url reset - Remove dynamic texture URL
* /tiedup clothes fullskin - Toggle full-skin mode
* /tiedup clothes smallarms - Toggle small arms forcing
* /tiedup clothes keephead - Toggle keep head mode (preserves wearer's head)
* /tiedup clothes layer <part> - Toggle layer visibility
*
* All commands operate on the clothes item held in main hand.
*/
public class ClothesCommand {
/**
* Create the /tiedup clothes ... command tree.
*
* @return The command builder
*/
public static LiteralArgumentBuilder<
CommandSourceStack
> createClothesCommand() {
return Commands.literal("clothes")
// /tiedup clothes url set <url>
// /tiedup clothes url reset
.then(
Commands.literal("url")
.then(
Commands.literal("set").then(
Commands.argument(
"url",
StringArgumentType.greedyString()
).executes(ClothesCommand::setUrl)
)
)
.then(
Commands.literal("reset").executes(
ClothesCommand::resetUrl
)
)
)
// /tiedup clothes fullskin
.then(
Commands.literal("fullskin").executes(
ClothesCommand::toggleFullSkin
)
)
// /tiedup clothes smallarms
.then(
Commands.literal("smallarms").executes(
ClothesCommand::toggleSmallArms
)
)
// /tiedup clothes keephead
.then(
Commands.literal("keephead").executes(
ClothesCommand::toggleKeepHead
)
)
// /tiedup clothes layer <part>
.then(
Commands.literal("layer").then(
Commands.argument("part", StringArgumentType.word())
.suggests((ctx, builder) -> {
builder.suggest("head");
builder.suggest("body");
builder.suggest("leftarm");
builder.suggest("rightarm");
builder.suggest("leftleg");
builder.suggest("rightleg");
return builder.buildFuture();
})
.executes(ClothesCommand::toggleLayer)
)
);
}
/**
* Get the clothes ItemStack from player's main hand.
* Returns null and sends error message if not holding clothes.
*/
private static ItemStack getHeldClothes(
CommandContext<CommandSourceStack> ctx
) throws CommandSyntaxException {
ServerPlayer player = ctx.getSource().getPlayerOrException();
ItemStack held = player.getMainHandItem();
if (held.isEmpty() || !(held.getItem() instanceof GenericClothes)) {
ctx
.getSource()
.sendFailure(
Component.translatable("command.tiedup.clothes.not_holding")
);
return null;
}
return held;
}
/**
* /tiedup clothes url set <url>
*/
private static int setUrl(CommandContext<CommandSourceStack> ctx)
throws CommandSyntaxException {
ItemStack clothes = getHeldClothes(ctx);
if (clothes == null) return 0;
String url = StringArgumentType.getString(ctx, "url");
// Basic URL validation
if (!url.startsWith("https://")) {
ctx
.getSource()
.sendFailure(
Component.translatable(
"command.tiedup.clothes.url_must_https"
)
);
return 0;
}
// Check URL length
if (url.length() > 2048) {
ctx
.getSource()
.sendFailure(
Component.translatable(
"command.tiedup.clothes.url_too_long"
)
);
return 0;
}
GenericClothes item = (GenericClothes) clothes.getItem();
item.setDynamicTextureUrl(clothes, url);
ctx
.getSource()
.sendSuccess(
() -> Component.translatable("command.tiedup.clothes.url_set"),
false
);
return 1;
}
/**
* /tiedup clothes url reset
*/
private static int resetUrl(CommandContext<CommandSourceStack> ctx)
throws CommandSyntaxException {
ItemStack clothes = getHeldClothes(ctx);
if (clothes == null) return 0;
GenericClothes item = (GenericClothes) clothes.getItem();
item.removeDynamicTextureUrl(clothes);
ctx
.getSource()
.sendSuccess(
() ->
Component.translatable("command.tiedup.clothes.url_reset"),
false
);
return 1;
}
/**
* /tiedup clothes fullskin
*/
private static int toggleFullSkin(CommandContext<CommandSourceStack> ctx)
throws CommandSyntaxException {
ItemStack clothes = getHeldClothes(ctx);
if (clothes == null) return 0;
GenericClothes item = (GenericClothes) clothes.getItem();
boolean newState = !item.isFullSkinEnabled(clothes);
item.setFullSkinEnabled(clothes, newState);
String stateKey = newState ? "enabled" : "disabled";
ctx
.getSource()
.sendSuccess(
() ->
Component.translatable(
"command.tiedup.clothes.fullskin_" + stateKey
),
false
);
return 1;
}
/**
* /tiedup clothes smallarms
*/
private static int toggleSmallArms(CommandContext<CommandSourceStack> ctx)
throws CommandSyntaxException {
ItemStack clothes = getHeldClothes(ctx);
if (clothes == null) return 0;
GenericClothes item = (GenericClothes) clothes.getItem();
boolean newState = !item.shouldForceSmallArms(clothes);
item.setForceSmallArms(clothes, newState);
String stateKey = newState ? "enabled" : "disabled";
ctx
.getSource()
.sendSuccess(
() ->
Component.translatable(
"command.tiedup.clothes.smallarms_" + stateKey
),
false
);
return 1;
}
/**
* /tiedup clothes keephead
* When enabled, the wearer's head/hat is preserved instead of being replaced by clothes.
*/
private static int toggleKeepHead(CommandContext<CommandSourceStack> ctx)
throws CommandSyntaxException {
ItemStack clothes = getHeldClothes(ctx);
if (clothes == null) return 0;
GenericClothes item = (GenericClothes) clothes.getItem();
boolean newState = !item.isKeepHeadEnabled(clothes);
item.setKeepHeadEnabled(clothes, newState);
String stateKey = newState ? "enabled" : "disabled";
ctx
.getSource()
.sendSuccess(
() ->
Component.translatable(
"command.tiedup.clothes.keephead_" + stateKey
),
false
);
return 1;
}
/**
* /tiedup clothes layer <part>
*/
private static int toggleLayer(CommandContext<CommandSourceStack> ctx)
throws CommandSyntaxException {
ItemStack clothes = getHeldClothes(ctx);
if (clothes == null) return 0;
String part = StringArgumentType.getString(ctx, "part").toLowerCase();
String layerKey = mapPartToLayerKey(part);
if (layerKey == null) {
ctx
.getSource()
.sendFailure(
Component.translatable(
"command.tiedup.clothes.unknown_layer",
part
)
);
return 0;
}
GenericClothes item = (GenericClothes) clothes.getItem();
boolean newState = !item.isLayerEnabled(clothes, layerKey);
item.setLayerEnabled(clothes, layerKey, newState);
String stateKey = newState ? "visible" : "hidden";
ctx
.getSource()
.sendSuccess(
() ->
Component.translatable(
"command.tiedup.clothes.layer_" + stateKey,
part
),
false
);
return 1;
}
/**
* Map user-friendly part name to NBT layer key.
*/
private static String mapPartToLayerKey(String part) {
return switch (part) {
case "head" -> GenericClothes.LAYER_HEAD;
case "body" -> GenericClothes.LAYER_BODY;
case "leftarm" -> GenericClothes.LAYER_LEFT_ARM;
case "rightarm" -> GenericClothes.LAYER_RIGHT_ARM;
case "leftleg" -> GenericClothes.LAYER_LEFT_LEG;
case "rightleg" -> GenericClothes.LAYER_RIGHT_LEG;
default -> null;
};
}
}