package com.tiedup.remake.commands.subcommands; 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.commands.CommandHelper; import com.tiedup.remake.entities.EntityMaster; import com.tiedup.remake.entities.ModEntities; import com.tiedup.remake.entities.ai.master.MasterState; import com.tiedup.remake.state.PlayerBindState; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.MobSpawnType; /** * Master/pet-play test sub-commands for /tiedup. * Handles: mastertest, masterchair, mastertask */ @SuppressWarnings("null") public class MasterTestSubCommand { public static void register( LiteralArgumentBuilder root ) { // /tiedup mastertest root.then( Commands.literal("mastertest") .requires(CommandHelper.REQUIRES_OP) .executes(MasterTestSubCommand::mastertest) ); // /tiedup masterchair root.then( Commands.literal("masterchair") .requires(CommandHelper.REQUIRES_OP) .executes(MasterTestSubCommand::masterchair) ); // /tiedup mastertask root.then( Commands.literal("mastertask") .requires(CommandHelper.REQUIRES_OP) .then( Commands.argument("task", StringArgumentType.word()) .suggests((ctx, builder) -> { for (MasterState s : MasterState.values()) { builder.suggest(s.name().toLowerCase()); } return builder.buildFuture(); }) .executes(MasterTestSubCommand::mastertask) ) ); } // Command Implementations /** * /tiedup mastertest * * Spawn a Master NPC nearby and immediately become its pet. * For testing the pet play system without going through capture. */ private static int mastertest(CommandContext context) throws CommandSyntaxException { ServerPlayer player = context.getSource().getPlayerOrException(); ServerLevel level = context.getSource().getLevel(); double x = player.getX() + player.getLookAngle().x * 2; double y = player.getY(); double z = player.getZ() + player.getLookAngle().z * 2; EntityMaster master = ModEntities.MASTER.get().create(level); if (master == null) { context .getSource() .sendFailure( Component.literal("Failed to create Master entity") ); return 0; } master.moveTo(x, y, z, player.getYRot() + 180F, 0.0F); master.finalizeSpawn( level, level.getCurrentDifficultyAt(master.blockPosition()), MobSpawnType.COMMAND, null, null ); level.addFreshEntity(master); master.setPetPlayer(player); master.putPetCollar(player); CommandHelper.syncPlayerState( player, PlayerBindState.getInstance(player) ); String masterName = master.getNpcName(); if (masterName == null || masterName.isEmpty()) masterName = "Master"; String finalName = masterName; context .getSource() .sendSuccess( () -> Component.literal( "Spawned Master '" + finalName + "' \u2014 you are now their pet." ), true ); return 1; } /** * /tiedup masterchair * * Force the nearest Master NPC into HUMAN_CHAIR state. * Requires the player to be that Master's pet. */ private static int masterchair(CommandContext context) throws CommandSyntaxException { ServerPlayer player = context.getSource().getPlayerOrException(); EntityMaster master = findNearestMaster(player); if (master == null) { context .getSource() .sendFailure( Component.literal("No Master NPC found within 20 blocks") ); return 0; } if (!master.hasPet()) { master.setPetPlayer(player); master.putPetCollar(player); CommandHelper.syncPlayerState( player, PlayerBindState.getInstance(player) ); } master.setMasterState(MasterState.HUMAN_CHAIR); String masterName = master.getNpcName(); if (masterName == null || masterName.isEmpty()) masterName = "Master"; String finalName = masterName; context .getSource() .sendSuccess( () -> Component.literal( "Forced " + finalName + " into HUMAN_CHAIR state" ), true ); return 1; } /** * /tiedup mastertask * * Force the nearest Master NPC into any MasterState. * Useful for testing specific master behaviors. */ private static int mastertask(CommandContext context) throws CommandSyntaxException { ServerPlayer player = context.getSource().getPlayerOrException(); String taskName = StringArgumentType.getString(context, "task"); MasterState targetState; try { targetState = MasterState.valueOf(taskName.toUpperCase()); } catch (IllegalArgumentException e) { context .getSource() .sendFailure( Component.literal("Unknown MasterState: " + taskName) ); return 0; } EntityMaster master = findNearestMaster(player); if (master == null) { context .getSource() .sendFailure( Component.literal("No Master NPC found within 20 blocks") ); return 0; } if (!master.hasPet()) { master.setPetPlayer(player); master.putPetCollar(player); CommandHelper.syncPlayerState( player, PlayerBindState.getInstance(player) ); } master.setMasterState(targetState); String masterName = master.getNpcName(); if (masterName == null || masterName.isEmpty()) masterName = "Master"; String finalName = masterName; context .getSource() .sendSuccess( () -> Component.literal( "Forced " + finalName + " into " + targetState.name() + " state" ), true ); return 1; } /** * Find the nearest EntityMaster within 20 blocks of a player. */ @javax.annotation.Nullable private static EntityMaster findNearestMaster(ServerPlayer player) { var masters = player .level() .getEntitiesOfClass( EntityMaster.class, player.getBoundingBox().inflate(20.0), m -> m.isAlive() ); if (masters.isEmpty()) return null; return masters .stream() .min((a, b) -> Double.compare(a.distanceToSqr(player), b.distanceToSqr(player)) ) .orElse(null); } }