package dev.projectcapture.hytale.command; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg; import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes; import com.hypixel.hytale.server.core.command.system.basecommands.AbstractCommandCollection; import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import dev.projectcapture.hytale.gameplay.MultiplayerCreatureService; import java.util.UUID; /** Registers the server-authoritative playable multiplayer vertical-slice commands. */ public final class ProjectCaptureCommands { private ProjectCaptureCommands() { } public static void register(JavaPlugin plugin, MultiplayerCreatureService service) { plugin.getCommandRegistry().registerCommand(new RootCommand(service)); } private static final class RootCommand extends AbstractCommandCollection { private RootCommand(MultiplayerCreatureService service) { super("projectcapture", "ProjectCapture creature commands"); addAliases("pc"); addSubCommand(new PartyCommand(service)); addSubCommand(new CompanionCommand(service)); addSubCommand(new CaptureCommand(service)); addSubCommand(new EncounterCommand(service)); addSubCommand(new GrantCapsulesCommand(service)); } } private abstract static class PlayerCommand extends AbstractPlayerCommand { protected final MultiplayerCreatureService service; private PlayerCommand(String name, String description, MultiplayerCreatureService service) { super(name, description); this.service = service; } protected final UUID playerId(PlayerRef player) { return player.getUuid(); } protected final void message(CommandContext context, String text) { context.sendMessage(Message.raw("[ProjectCapture] " + text)); } } private static final class PartyCommand extends PlayerCommand { private PartyCommand(MultiplayerCreatureService service) { super("party", "Show your ProjectCapture party", service); } @Override protected void execute( CommandContext context, Store store, Ref playerRef, PlayerRef player, World world ) { MultiplayerCreatureService.PartyView party = service.party(playerId(player)); String creatures = party.creatures().isEmpty() ? "empty" : party.creatures().stream() .map(creature -> creature.speciesId() + " Lv." + creature.level()) .collect(java.util.stream.Collectors.joining(", ")); message(context, "Party: " + creatures + " | Field capsules: " + party.fieldCapsules() + " | Companion: " + party.activeCompanionId().map(UUID::toString).orElse("none")); } } private static final class CompanionCommand extends PlayerCommand { private final RequiredArg creatureId = withRequiredArg("creatureId", "UUID from /pc party", ArgTypes.UUID); private CompanionCommand(MultiplayerCreatureService service) { super("companion", "Set a captured party creature as your companion", service); } @Override protected void execute( CommandContext context, Store store, Ref playerRef, PlayerRef player, World world ) { UUID id = context.get(creatureId); service.setCompanion(playerId(player), id); message(context, "Companion saved: " + id); } } private static final class CaptureCommand extends PlayerCommand { private CaptureCommand(MultiplayerCreatureService service) { super("capture", "Throw one crafted field capsule at your active encounter", service); } @Override protected void execute( CommandContext context, Store store, Ref playerRef, PlayerRef player, World world ) { MultiplayerCreatureService.CaptureOutcome outcome = service.capture(playerId(player), System.nanoTime()); if (outcome.captured()) { message(context, "Captured " + outcome.creatureId().orElseThrow() + " (" + Math.round(outcome.probability() * 100) + "% chance)." + (outcome.addedToParty() ? " Added to your party." : " Your party is full; stored safely.")); } else { message(context, "The creature broke free (" + Math.round(outcome.probability() * 100) + "% chance). Try again with another capsule."); } } } private static final class EncounterCommand extends PlayerCommand { private final RequiredArg speciesId = withRequiredArg("speciesId", "Namespaced species ID", ArgTypes.STRING); private EncounterCommand(MultiplayerCreatureService service) { super("encounter", "Development command: open a personal wild encounter", service); requirePermission("projectcapture.debug.encounter"); } @Override protected void execute( CommandContext context, Store store, Ref playerRef, PlayerRef player, World world ) { MultiplayerCreatureService.EncounterView encounter = service.openEncounter( playerId(player), context.get(speciesId), 5, System.nanoTime()); message(context, "Personal wild encounter: " + encounter.speciesId() + " Lv." + encounter.level()); } } private static final class GrantCapsulesCommand extends PlayerCommand { private final RequiredArg amount = withRequiredArg("amount", "Number of field capsules", ArgTypes.INTEGER); private GrantCapsulesCommand(MultiplayerCreatureService service) { super("grantcapsules", "Development command: grant crafted field-capsule test inventory", service); requirePermission("projectcapture.debug.grantcapsules"); } @Override protected void execute( CommandContext context, Store store, Ref playerRef, PlayerRef player, World world ) { int requested = context.get(amount); service.grantFieldCapsules(playerId(player), requested); message(context, "Added " + requested + " field capsules to your server-authoritative test inventory."); } } }