package ar.com.companeros; import ar.com.companeros.runtime.AgentRuntime; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.chat.Component; import net.minecraft.world.phys.AABB; import net.minecraftforge.event.RegisterCommandsEvent; import static net.minecraft.commands.Commands.argument; import static net.minecraft.commands.Commands.literal; /** Comandos de jugadores autónomos y compatibilidad con los compañeros del prototipo. */ public final class Commands { private Commands() { } public static void register(RegisterCommandsEvent event) { var root = literal("raps").requires(source -> !(source.getEntity() instanceof net.minecraftforge.common.util.FakePlayer) && !(source.getEntity() instanceof net.minecraft.server.level.ServerPlayer player && ar.com.companeros.identity.AgentRegistry.get(source.getServer()).find(player.getUUID()).isPresent())); root.executes(context -> { context.getSource().sendSuccess(() -> Component.literal( "Unir uno: /Raps join bot · Unir todos: /Raps join bots · Ver bots: /Raps estado · Ayuda: /Raps ayuda"), false); return 1; }); // Jugadores registrados: el runtime comprueba identidad, permisos y población. root.then(literal("crear").requires(source -> source.hasPermission(2)) .then(argument("nombre", StringArgumentType.word()) .executes(context -> AgentRuntime.create(context.getSource(), name(context))))); root.then(literal("conectar").then(argument("nombre", StringArgumentType.word()) .executes(context -> AgentRuntime.connect(context.getSource(), name(context))))); root.then(literal("join").requires(source -> source.hasPermission(2)) .then(literal("bot").then(argument("nombre", StringArgumentType.word()) .suggests((context, builder) -> net.minecraft.commands.SharedSuggestionProvider.suggest( AgentRuntime.joinableNames(context.getSource().getServer()), builder)) .executes(context -> AgentRuntime.connect(context.getSource(), name(context))))) .then(literal("bots").executes(context -> AgentRuntime.connectAll(context.getSource())))); root.then(literal("ayuda").executes(context -> { for (String line : new String[]{ "/Raps join bot Neon — conecta un bot guardado", "/Raps join bots — conecta todos los bots disponibles", "/Raps crear Nombre — crea un bot nuevo", "/Raps rol Neon investigador · /Raps rol Xenon generalista", "/Raps skin Neon CuentaMinecraft · /Raps skin Neon default", "/Raps autonomo Nombre — permite decidir a la IA cuando esté habilitada", "/Raps estado · /Raps inventario Nombre", "/Raps pausar Nombre — guarda y desconecta", "/Raps tools estado Nombre · /Raps tools proponer Nombre JSON", "/Raps herramienta Nombre create_banner JSON · place_banner JSON", "/Raps mimicer estado · meteorito · infectar Nombre · etapa 0..4 · avanzar · spawn", "/sensitivity mode enabled · /sensitivity mode disabled", "/botmalo Nombre mensaje · /botmalo all mensaje"}) context.getSource().sendSuccess(() -> Component.literal(line), false); return 1; })); root.then(literal("pausar").then(argument("nombre", StringArgumentType.word()) .executes(context -> registered(context) ? AgentRuntime.pause(context.getSource(), name(context)) : changeLegacyMode(context, "quieto")))); // El cuerpo inicial sigue disponible para comparar y mantener mundos anteriores. root.then(literal("crear_prototipo").requires(source -> source.hasPermission(2)) .then(argument("nombre", StringArgumentType.word()) .executes(context -> createPrototype(context, 24)) .then(argument("radio", IntegerArgumentType.integer(8, 32)) .executes(context -> createPrototype(context, IntegerArgumentType.getInteger(context, "radio")))))); root.then(literal("campamento").then(argument("nombre", StringArgumentType.word()).executes(Commands::camp))); root.then(literal("estado").executes(Commands::list)); root.then(literal("inventario").then(argument("nombre", StringArgumentType.word()).executes(Commands::inventory))); root.then(literal("entregar").then(argument("nombre", StringArgumentType.word()).executes(Commands::handOver))); for (String mode : new String[]{"autonomo", "seguir", "quieto"}) { root.then(literal(mode).then(argument("nombre", StringArgumentType.word()).executes(context -> { if (registered(context)) return AgentRuntime.setMode(context.getSource(), name(context), mode); return changeLegacyMode(context, mode); }))); } root.then(literal("retirar").requires(source -> source.hasPermission(2)) .then(argument("nombre", StringArgumentType.word()).executes(Commands::retire))); // Herramientas supervisadas y escalones de población permitidos para las pruebas. root.then(literal("herramientas").executes(context -> { var tools = AgentRuntime.toolNames(context.getSource().getServer()); for (String tool : tools) context.getSource().sendSuccess(() -> Component.literal(tool), false); if (tools.isEmpty()) context.getSource().sendSuccess( () -> Component.literal("Todavía no hay herramientas disponibles."), false); return tools.size(); })); root.then(literal("herramienta").requires(source -> source.hasPermission(2)) .then(argument("nombre", StringArgumentType.word()) .then(argument("herramienta", StringArgumentType.word()) .executes(context -> runTool(context, "{}")) .then(argument("argumentos", StringArgumentType.greedyString()) .executes(context -> runTool(context, StringArgumentType.getString(context, "argumentos"))))))); var population = literal("fase").requires(source -> source.hasPermission(2)); for (int limit : new int[]{2, 4, 6, 10}) population.then(literal(Integer.toString(limit)).executes( context -> AgentRuntime.setPopulationLimit(context.getSource(), limit))); root.then(population); // Controles de aprendizaje: propuestas con autor real, nunca aprobación por chat. root.then(literal("tools").requires(source -> source.hasPermission(2)) .then(literal("estado").then(argument("nombre", StringArgumentType.word()) .executes(context -> AgentRuntime.toolState(context.getSource(), name(context))))) .then(literal("proponer").then(argument("nombre", StringArgumentType.word()) .then(argument("manifiesto", StringArgumentType.greedyString()).executes(context -> AgentRuntime.proposeTool(context.getSource(), name(context), StringArgumentType.getString(context, "manifiesto"))))))); // Especialización guardada; puede asignarse antes de conectar al jugador. root.then(literal("rol").requires(source -> source.hasPermission(2)) .then(argument("nombre", StringArgumentType.word()) .then(literal("investigador").executes(c -> AgentRuntime.setRole(c.getSource(), name(c), ar.com.companeros.identity.AgentRoles.Role.INVESTIGADOR))) .then(literal("generalista").executes(c -> AgentRuntime.setRole(c.getSource(), name(c), ar.com.companeros.identity.AgentRoles.Role.GENERALISTA))))); ar.com.companeros.horror.HorrorModule.registerCommands(root); root.then(literal("skin").requires(source -> source.hasPermission(2)) .then(argument("nombre", StringArgumentType.word()) .executes(c -> ar.com.companeros.identity.SkinProfiles.command(c.getSource(), name(c), null)) .then(argument("cuenta", StringArgumentType.word()).executes(c -> ar.com.companeros.identity.SkinProfiles.command( c.getSource(), name(c), StringArgumentType.getString(c, "cuenta")))))); ar.com.companeros.horror.HorrorModule.registerSensitivity(event.getDispatcher()); var registered = event.getDispatcher().register(root); event.getDispatcher().register(literal("Raps").requires(registered.getRequirement()).executes(registered.getCommand()).redirect(registered)); event.getDispatcher().register(literal("companeros").requires(registered.getRequirement()).executes(registered.getCommand()).redirect(registered)); } private static String name(CommandContext context) { return StringArgumentType.getString(context, "nombre"); } private static boolean registered(CommandContext context) { return AgentRuntime.isRegisteredPlayer(context.getSource().getServer(), name(context)); } private static int runTool(CommandContext context, String json) throws CommandSyntaxException { return AgentRuntime.runTool(context.getSource(), name(context), StringArgumentType.getString(context, "herramienta"), json); } // Adaptación de controles: primero jugadores reales; después el inventario/cuerpo legado. private static int changeLegacyMode(CommandContext context, String mode) throws CommandSyntaxException { Companion bot = owned(context); if (bot == null) return 0; bot.mode = mode; bot.resource = null; bot.miningProgress = 0; bot.getNavigation().stop(); bot.setTarget(null); context.getSource().sendSuccess(() -> Component.literal(bot.getName().getString() + ": " + mode), false); return 1; } private static int handOver(CommandContext context) throws CommandSyntaxException { if (registered(context)) return AgentRuntime.handOver(context.getSource(), name(context)); Companion bot = owned(context); if (bot == null) return 0; var player = context.getSource().getPlayerOrException(); if (bot.distanceToSqr(player) > 16) { context.getSource().sendFailure(Component.literal("Acercate al compañero para recibir sus objetos.")); return 0; } for (int i = 0; i < bot.bag.getContainerSize(); i++) { var stack = bot.bag.removeItemNoUpdate(i); if (!stack.isEmpty()) { var drop = bot.spawnAtLocation(stack); if (drop != null) { drop.setTarget(player.getUUID()); drop.setThrower(player.getUUID()); } } } bot.setItemSlot(net.minecraft.world.entity.EquipmentSlot.MAINHAND, net.minecraft.world.item.ItemStack.EMPTY); context.getSource().sendSuccess(() -> Component.literal("Objetos entregados."), false); return 1; } private static int retire(CommandContext context) throws CommandSyntaxException { if (registered(context)) return AgentRuntime.retire(context.getSource(), name(context)); Companion bot = owned(context); if (bot == null) return 0; bot.releaseInventory(); WorkArea.get(bot.serverLevel()).forget(bot.getUUID()); var registry = ar.com.companeros.identity.AgentRegistry.get(bot.serverLevel().getServer()); registry.find(bot.getUUID()).ifPresent(identity -> registry.markState(identity.id(), ar.com.companeros.identity.AgentState.RETIRED)); bot.discard(); context.getSource().sendSuccess(() -> Component.literal("Compañero retirado."), false); return 1; } private static int createPrototype(CommandContext context, int radius) throws CommandSyntaxException { var player = context.getSource().getPlayerOrException(); var level = player.serverLevel(); String name = StringArgumentType.getString(context, "nombre"); if (!name.matches("[A-Za-z0-9_]{1,16}")) { context.getSource().sendFailure(Component.literal("Usá un nombre de hasta 16 letras, números o guiones bajos.")); return 0; } long existing = WorkArea.get(level).companionCount(); if (AgentRuntime.isRegisteredPlayer(context.getSource().getServer(), name) || existing >= 4 || level.getEntities(Companeros.COMPANION.get(), bot -> bot.getName().getString().equals(name)).size() > 0) { context.getSource().sendFailure(Component.literal("Ya existe ese nombre o hay cuatro compañeros en esta dimensión.")); return 0; } Companion bot = Companeros.COMPANION.get().create(level); if (bot == null) return 0; bot.moveTo(player.getX() + 1.5, player.getY(), player.getZ(), player.getYRot(), 0); if (!level.noCollision(bot) || !level.getFluidState(bot.blockPosition()).isEmpty()) { context.getSource().sendFailure(Component.literal("Necesitás espacio libre a tu lado.")); return 0; } bot.owner = player.getUUID(); bot.home = bot.blockPosition(); bot.radius = radius; bot.mode = "quieto"; bot.activity = "Esperando campamento"; bot.setCustomName(Component.literal(name)); bot.setCustomNameVisible(true); if (!level.addFreshEntity(bot)) return 0; context.getSource().sendSuccess(() -> Component.literal(name + " se sumó a la aventura."), false); return 1; } private static Companion owned(CommandContext context) throws CommandSyntaxException { var player = context.getSource().getPlayerOrException(); String name = StringArgumentType.getString(context, "nombre"); for (Companion bot : player.serverLevel().getEntitiesOfClass(Companion.class, player.getBoundingBox().inflate(96), entity -> entity.getName().getString().equals(name))) { if (player.getUUID().equals(bot.owner) || context.getSource().hasPermission(2)) return bot; } context.getSource().sendFailure(Component.literal("No encontré un compañero tuyo con ese nombre cerca.")); return null; } private static int camp(CommandContext context) throws CommandSyntaxException { if (registered(context)) return AgentRuntime.setCamp(context.getSource(), name(context)); Companion bot = owned(context); if (bot == null) return 0; var home = context.getSource().getPlayerOrException().blockPosition(); if (!bot.serverLevel().getEntitiesOfClass(Companion.class, new AABB(home).inflate(8), other -> other != bot && other.building && other.home != null && other.home.distSqr(home) < 64).isEmpty()) { context.getSource().sendFailure(Component.literal("Separá los campamentos por al menos ocho bloques.")); return 0; } if (!Shelter.clearSite(bot, home)) { context.getSource().sendFailure(Component.literal("Elegí un terreno plano con 5×5 bloques libres y cuatro de altura.")); return 0; } bot.home = home.immutable(); bot.building = true; bot.shelterStep = 0; bot.resource = null; bot.searchCursor = 0; bot.blocked.clear(); bot.mode = "autonomo"; context.getSource().sendSuccess(() -> Component.literal("Campamento de " + bot.getName().getString() + " marcado."), false); return 1; } private static int list(CommandContext context) throws CommandSyntaxException { var server = context.getSource().getServer(); var descriptions = AgentRuntime.describe(server); int total = descriptions.size(); for (String description : descriptions) context.getSource().sendSuccess(() -> Component.literal(description), false); var seen = new java.util.HashSet(); for (var level : server.getAllLevels()) { var bots = level.getEntities(Companeros.COMPANION.get(), bot -> !AgentRuntime.isRegisteredPlayer(server, bot.getName().getString())); for (Companion bot : bots) { if (!seen.add(bot.getUUID())) continue; total++; context.getSource().sendSuccess(() -> Component.literal( bot.getName().getString() + " · " + bot.activity + " · Salud " + (int) bot.getHealth() + "/20 · Comida " + bot.hunger + "/20 · " + bot.blockPosition().toShortString()), false); } } if (total == 0) context.getSource().sendSuccess(() -> Component.literal("No hay compañeros."), false); return total; } private static int inventory(CommandContext context) throws CommandSyntaxException { if (registered(context)) return AgentRuntime.inventory(context.getSource(), name(context)); Companion bot = owned(context); if (bot == null) return 0; java.util.List items = new java.util.ArrayList<>(); for (int i = 0; i < bot.bag.getContainerSize(); i++) { var stack = bot.bag.getItem(i); if (!stack.isEmpty()) items.add(stack.getCount() + " " + stack.getHoverName().getString()); } context.getSource().sendSuccess(() -> Component.literal(bot.getName().getString() + ": " + (items.isEmpty() ? "Inventario vacío" : String.join(", ", items))), false); return 1; } }