feat(04-04): add tp subcommand teleporting to region AABB center (CMD-06)

- AbstractPlayerCommand (tp only makes sense for a player caller)
- Pattern mirrors TeleportToCoordinatesCommand:48-68 (read Transform+HeadRotation,
  build Teleport.createForPlayer(pos, bodyRotation).setHeadRotation(headRotation),
  store.addComponent)
- Center computed componentwise: c = (min+max)/2
- Preserves caller body+head rotation (teleport in place, no look change)
- Clear error on unknown region name
This commit is contained in:
2026-04-24 14:55:12 +02:00
parent bfc53972b7
commit c42ebbe0e9
@@ -0,0 +1,104 @@
package com.mythlane.gravityflip.command;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
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.AbstractPlayerCommand;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport;
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 com.mythlane.gravityflip.GravityFlipPlugin;
import com.mythlane.gravityflip.region.GravityFlipRegion;
import javax.annotation.Nonnull;
/**
* {@code /gravityflip tp <name>} — téléporte le joueur appelant au centre de
* l'AABB d'une région Gravity Flip. Outil debug/builder (CMD-06).
*
* <p>Étend {@link AbstractPlayerCommand} : tp ne fait sens que pour un joueur,
* la base class gère automatiquement le message "must be player" pour un appel console.
*
* <p>Pattern Teleport copié ligne-à-ligne sur
* {@code com.hypixel.hytale.builtin.teleport.commands.teleport.variant.TeleportToCoordinatesCommand}
* (lignes 48-68) :
* <ol>
* <li>Lire {@link TransformComponent} (rotation corps) et {@link HeadRotation}
* (rotation tête) pour préserver l'orientation du joueur.</li>
* <li>Calculer le centre componentwise : {@code c = (min + max) / 2}.</li>
* <li>Construire via {@code Teleport.createForPlayer(pos, rotation).setHeadRotation(...)}.</li>
* <li>{@code store.addComponent(ref, Teleport.getComponentType(), teleport)} —
* le {@code TeleportSystem} du core consomme le composant au prochain tick.</li>
* </ol>
*
* <p>T-04-04-02 : permission auto-générée {@code mythlane.gravityflip.command.gravityflip.tp}
* sert de gate. Pas de restriction GameMode v1 (builder tool).
*/
public final class GravityFlipTpSubCommand extends AbstractPlayerCommand {
private final GravityFlipPlugin plugin;
private final RequiredArg<String> nameArg =
this.withRequiredArg("name", "Nom de la région cible", ArgTypes.STRING);
public GravityFlipTpSubCommand(GravityFlipPlugin plugin) {
super("tp", "Téléporte au centre d'une région Gravity Flip");
this.plugin = plugin;
}
@Override
protected void execute(@Nonnull CommandContext ctx,
@Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world) {
String name = nameArg.get(ctx);
GravityFlipRegion target = null;
for (GravityFlipRegion r : plugin.regions().all()) {
if (r.getName().equals(name)) {
target = r;
break;
}
}
if (target == null) {
ctx.sendMessage(Message.raw("[gravityflip] Région '" + name + "' introuvable."));
return;
}
Vector3d mn = target.getMin();
Vector3d mx = target.getMax();
double cx = (mn.x + mx.x) / 2.0;
double cy = (mn.y + mx.y) / 2.0;
double cz = (mn.z + mx.z) / 2.0;
TransformComponent tc = store.getComponent(ref, TransformComponent.getComponentType());
if (tc == null) {
ctx.sendMessage(Message.raw(
"[gravityflip] TransformComponent manquant — tp impossible."));
return;
}
HeadRotation hr = store.getComponent(ref, HeadRotation.getComponentType());
// Préserve l'orientation courante : body rotation depuis Transform, head rotation
// si disponible (sinon on laisse la default côté Teleport.createForPlayer).
Vector3f bodyRotation = tc.getRotation().clone();
Teleport teleport = Teleport.createForPlayer(
new Vector3d(cx, cy, cz), bodyRotation);
if (hr != null) {
teleport = teleport.setHeadRotation(hr.getRotation().clone());
}
store.addComponent(ref, Teleport.getComponentType(), teleport);
ctx.sendMessage(Message.raw(String.format(
"[gravityflip] Téléporté au centre de '%s' : (%.0f,%.0f,%.0f)",
name, cx, cy, cz)));
}
}