feat(04-02): add GravityFlipCommand root + wand subcommand (CMD-01)

- GravityFlipCommand extends AbstractCommandCollection (pattern: TeleportCommand)
- GravityFlipWandSubCommand extends AbstractPlayerCommand (pattern: GiveCommand)
- resolves 'gravityflip_wand' via Item.getAssetMap().getAsset, giveItem, chat feedback
- null-safe on asset miss + inventory-full remainder check
This commit is contained in:
2026-04-24 14:07:21 +02:00
parent 14538f875d
commit c172d4f84d
2 changed files with 98 additions and 0 deletions
@@ -0,0 +1,30 @@
package com.mythlane.gravityflip.command;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractCommandCollection;
import com.mythlane.gravityflip.GravityFlipPlugin;
/**
* Root command {@code /gravityflip}. Aggregates all Gravity Flip sub-commands.
*
* <p>Extends {@link AbstractCommandCollection} — pattern sourced from
* {@code builtin/teleport/commands/teleport/TeleportCommand} and
* {@code modules/debug/commands/DebugCommand}. When invoked without a
* sub-command, the base class emits a usage message listing registered
* sub-commands (no extra work required here).
*
* <p>The plugin reference is stored for future sub-commands (04-03 define,
* 04-04 list/delete/toggle/tp) that need {@code plugin.wandSelections()} or
* {@code plugin.configHolder()}.
*/
public final class GravityFlipCommand extends AbstractCommandCollection {
public GravityFlipCommand(GravityFlipPlugin plugin) {
super("gravityflip", "Commandes de gestion des zones Gravity Flip");
this.addSubCommand(new GravityFlipWandSubCommand());
// 04-03 will addSubCommand(new GravityFlipDefineSubCommand(plugin));
// 04-04 will addSubCommand(new GravityFlipListSubCommand(plugin));
// addSubCommand(new GravityFlipDeleteSubCommand(plugin));
// addSubCommand(new GravityFlipToggleSubCommand(plugin));
// addSubCommand(new GravityFlipTpSubCommand(plugin));
}
}
@@ -0,0 +1,68 @@
package com.mythlane.gravityflip.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.asset.type.item.config.Item;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction;
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 javax.annotation.Nonnull;
/**
* {@code /gravityflip wand} — donne un Gravity Flip Wand au joueur appelant.
*
* <p>Pattern copié ligne-à-ligne sur
* {@code com.hypixel.hytale.server.core.command.commands.player.inventory.GiveCommand}
* (cf. GiveCommand.java:47-76). La seule différence : l'item est résolu par
* constante ({@link #WAND_ITEM_ID}) au lieu d'un {@code RequiredArg<Item>}.
*
* <p>L'item {@code gravityflip_wand} est enregistré via le JSON bundle
* {@code src/main/resources/Items/gravityflip_wand.json} (Phase 04-01).
* Si l'asset n'est pas chargé (JSON absent / pas picked-up par l'AssetStore
* core), le lookup renvoie {@code null} et la commande envoie un message
* d'erreur clair au lieu de crasher (T-04-02 scope).
*/
public final class GravityFlipWandSubCommand extends AbstractPlayerCommand {
/** ItemID du wand défini dans {@code Items/gravityflip_wand.json} (Phase 04-01). */
private static final String WAND_ITEM_ID = "gravityflip_wand";
public GravityFlipWandSubCommand() {
super("wand", "Obtenir un Gravity Flip Wand");
}
@Override
protected void execute(@Nonnull CommandContext context,
@Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world) {
Item item = Item.getAssetMap().getAsset(WAND_ITEM_ID);
if (item == null) {
context.sendMessage(Message.raw(
"[gravityflip] Item '" + WAND_ITEM_ID
+ "' introuvable — asset pas chargé ?"));
return;
}
Player playerComponent = store.getComponent(ref, Player.getComponentType());
if (playerComponent == null) {
context.sendMessage(Message.raw("[gravityflip] Player component manquant."));
return;
}
ItemStack stack = new ItemStack(item.getId(), 1, null);
ItemStackTransaction transaction = playerComponent.giveItem(stack, ref, store);
ItemStack remainder = transaction.getRemainder();
if (remainder == null || remainder.isEmpty()) {
context.sendMessage(Message.raw("[gravityflip] Wand ajouté à ton inventaire."));
} else {
context.sendMessage(Message.raw(
"[gravityflip] Inventaire plein — impossible d'ajouter le wand."));
}
}
}