Teleport API
Detailní dokumentace Teleport API pro přesun hráčů a entit.
---
Přehled
Hytale používá komponentový systém pro teleportaci. Přidáním Teleport komponenty k entitě se spustí teleportace na cílovou pozici.
---
Teleport Komponenta
Import
import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport;
import com.hypixel.hytale.math.vector.Transform;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
Z Dekompilovaného Kódu - Teleport.java
public class Teleport implements Component {
@Nullable
private final World world;
@Nonnull
private final Vector3d position = new Vector3d();
@Nonnull
private final Vector3f rotation = new Vector3f();
@Nullable
private Vector3f headRotation;
private boolean resetVelocity = true; // Konstruktory
public Teleport(@Nullable World world, @Nonnull Vector3d position, @Nonnull Vector3f rotation);
public Teleport(@Nonnull Vector3d position, @Nonnull Vector3f rotation);
// Factory metody pro hráče
@Nonnull
public static Teleport createForPlayer(@Nullable World world, @Nonnull Transform transform);
@Nonnull
public static Teleport createForPlayer(@Nullable World world, @Nonnull Vector3d position, @Nonnull Vector3f rotation);
@Nonnull
public static Teleport createForPlayer(@Nonnull Vector3d position, @Nonnull Vector3f rotation);
@Nonnull
public static Teleport createForPlayer(@Nonnull Transform transform);
// Factory metody pro přesnou kontrolu
@Nonnull
public static Teleport createExact(@Nonnull Vector3d position, @Nonnull Vector3f bodyRotation, @Nonnull Vector3f headRotation);
@Nonnull
public static Teleport createExact(@Nonnull Vector3d position, @Nonnull Vector3f bodyRotation);
// Modifikátory
@Nonnull
public Teleport setHeadRotation(@Nonnull Vector3f headRotation);
public Teleport withoutVelocityReset();
// Gettery
@Nullable
public World getWorld();
@Nonnull
public Vector3d getPosition();
@Nonnull
public Vector3f getRotation();
@Nullable
public Vector3f getHeadRotation();
public boolean isResetVelocity();
}
---
Factory Metody
createForPlayer()
Pro teleportaci hráčů. Automaticky nastaví body rotation (jen yaw) a head rotation.
// S cílovým světem
Teleport teleport = Teleport.createForPlayer(targetWorld, transform);// Bez světa (teleport ve stejném světě)
Teleport teleport = Teleport.createForPlayer(transform);
// S pozicí a rotací
Vector3d position = new Vector3d(100, 64, 200);
Vector3f rotation = new Vector3f(0, 90, 0); // pitch, yaw, roll
Teleport teleport = Teleport.createForPlayer(targetWorld, position, rotation);
Implementace createForPlayer (z dekompilovaného kódu)
@Nonnull
public static Teleport createForPlayer(@Nullable World world, @Nonnull Vector3d position, @Nonnull Vector3f rotation) {
Vector3f headRotation = rotation.clone();
// Body rotation má jen yaw (otočení těla)
Vector3f bodyRotation = new Vector3f(0.0F, headRotation.getYaw(), 0.0F);
return new Teleport(world, position, bodyRotation).setHeadRotation(headRotation);
}
createExact()
Pro přesnou kontrolu nad body a head rotací (např. pro NPC).
Vector3d position = new Vector3d(100, 64, 200);
Vector3f bodyRotation = new Vector3f(0, 90, 0);
Vector3f headRotation = new Vector3f(-10, 90, 0); // Hlava se dívá dolůTeleport teleport = Teleport.createExact(position, bodyRotation, headRotation);
---
Provedení Teleportu
Základní Teleportace
// Uvnitř world.execute() - DŮLEŽITÉ pro thread safety!
world.execute(() -> {
Ref ref = playerRef.getReference();
Store store = ref.getStore(); // Vytvoř teleport komponentu
Transform targetTransform = new Transform(position, rotation);
Teleport teleport = Teleport.createForPlayer(world, targetTransform);
// Přidání komponenty spustí teleport
store.addComponent(ref, Teleport.getComponentType(), teleport);
});
Z SpawnCommand (dekompilovaný kód)
@Override
protected void execute(
@Nonnull CommandContext context,
@Nonnull Store store,
@Nonnull Ref ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world
) {
Transform spawnTransform = resolveSpawn(context, world, playerRef, this.spawnIndexArg);
TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType());
HeadRotation headRotationComponent = store.getComponent(ref, HeadRotation.getComponentType()); // Uložení předchozí pozice pro historii
Vector3d previousPos = transformComponent.getPosition().clone();
Vector3f previousRotation = headRotationComponent.getRotation().clone();
TeleportHistory teleportHistoryComponent = store.ensureAndGetComponent(ref, TeleportHistory.getComponentType());
teleportHistoryComponent.append(world, previousPos, previousRotation, "World " + world.getName() + "'s spawn");
// Provedení teleportu
Teleport teleportComponent = Teleport.createForPlayer(world, spawnTransform);
store.addComponent(ref, Teleport.getComponentType(), teleportComponent);
// Zpráva o úspěchu
Vector3d position = spawnTransform.getPosition();
context.sendMessage(
Message.translation("server.commands.spawn.teleported")
.param("x", position.getX())
.param("y", position.getY())
.param("z", position.getZ())
);
}
---
Teleport mezi Světy
Základní Cross-World Teleport
public void teleportToWorld(PlayerRef playerRef, World targetWorld, Transform transform) {
Ref ref = playerRef.getReference();
if (ref == null || !ref.isValid()) {
return;
} Store store = ref.getStore();
World currentWorld = store.getExternalData().getWorld();
currentWorld.execute(() -> {
// Teleport komponenta s cílovým světem
Teleport teleport = Teleport.createForPlayer(targetWorld, transform);
store.addComponent(ref, Teleport.getComponentType(), teleport);
});
}
Jak to Funguje Interně (TeleportSystems.java)
// PlayerMoveSystem.onComponentAdded()
public void onComponentAdded(
@Nonnull Ref ref,
@Nonnull Teleport teleport,
@Nonnull Store store,
@Nonnull CommandBuffer commandBuffer
) {
World targetWorld = teleport.getWorld(); if (targetWorld != null && !targetWorld.equals(store.getExternalData().getWorld())) {
// Cross-world teleport
this.teleportToWorld(ref, teleport, commandBuffer, targetWorld);
} else {
// Same-world teleport
this.teleportToPosition(ref, teleport, commandBuffer);
}
}
private void teleportToWorld(
@Nonnull Ref ref,
@Nonnull Teleport teleport,
@Nonnull CommandBuffer commandBuffer,
@Nonnull World targetWorld
) {
PlayerRef playerRefComponent = commandBuffer.getComponent(ref, this.playerRefComponentType);
commandBuffer.removeComponent(ref, this.teleportComponentType);
commandBuffer.run(s -> {
// Odeber hráče z aktuálního světa
playerRefComponent.removeFromStore();
// Přidej do nového světa
targetWorld.addPlayer(playerRefComponent, new Transform(teleport.getPosition(), teleport.getRotation()));
});
}
---
Teleport bez Resetu Velocity
Pro plynulý přechod bez zastavení pohybu:
Teleport teleport = Teleport.createForPlayer(world, transform)
.withoutVelocityReset();store.addComponent(ref, Teleport.getComponentType(), teleport);
---
Teleport Entity (ne-hráče)
MoveSystem pro Entity
// Z TeleportSystems.MoveSystem - pro entity bez PlayerRef komponenty
public void onComponentAdded(
@Nonnull Ref ref,
@Nonnull Teleport teleport,
@Nonnull Store store,
@Nonnull CommandBuffer commandBuffer
) {
TransformComponent transformComponent = commandBuffer.getComponent(ref, this.transformComponentType); // Teleportace pozice a rotace
transformComponent.teleportPosition(teleport.getPosition());
transformComponent.teleportRotation(teleport.getRotation());
// Head rotation
HeadRotation headRotationComponent = commandBuffer.getComponent(ref, this.headRotationComponentType);
if (headRotationComponent != null) {
headRotationComponent.teleportRotation(teleport.getRotation());
}
// Cross-world teleport pro entity
World targetWorld = teleport.getWorld();
if (targetWorld != null && !targetWorld.equals(store.getExternalData().getWorld())) {
commandBuffer.run(s -> {
Holder holder = s.removeEntity(ref, RemoveReason.UNLOAD);
targetWorld.execute(() ->
targetWorld.getEntityStore().getStore().addEntity(holder, AddReason.LOAD)
);
});
}
// Odeber teleport komponentu
commandBuffer.removeComponent(ref, this.teleportComponentType);
}
---
Teleport Historie
TeleportHistory Komponenta
public class TeleportHistory implements Component {
private static final int MAX_TELEPORT_HISTORY = 100; @Nonnull
private final Deque back = new ArrayDeque<>();
@Nonnull
private final Deque forward = new ArrayDeque<>();
// Přidání záznamu do historie
public void append(@Nonnull World world, @Nonnull Vector3d pos, @Nonnull Vector3f rotation, @Nonnull String key) {
this.back.push(new Waypoint(world.getName(), pos, rotation, key));
this.forward.clear();
while (this.back.size() > 100) {
this.back.removeLast();
}
}
// Navigace zpět
public void back(@Nonnull Ref ref, int count) {
Store store = ref.getStore();
go(store, ref, this.back, this.forward, count, false);
}
// Navigace vpřed
public void forward(@Nonnull Ref ref, int count) {
Store store = ref.getStore();
go(store, ref, this.forward, this.back, count, true);
}
public int getBackSize() { return this.back.size(); }
public int getForwardSize() { return this.forward.size(); }
public static class Waypoint {
private final String world;
private final Vector3d position;
private final Vector3f rotation;
private final String message; // Popis warpu
public Waypoint(String world, Vector3d position, Vector3f rotation, String message) {
this.world = world;
this.position = position;
this.rotation = rotation;
this.message = message;
}
}
}
Použití Historie
// Před teleportem - ulož současnou pozici
TransformComponent transform = store.getComponent(ref, TransformComponent.getComponentType());
HeadRotation headRotation = store.getComponent(ref, HeadRotation.getComponentType());TeleportHistory history = store.ensureAndGetComponent(ref, TeleportHistory.getComponentType());
history.append(
world,
transform.getPosition().clone(),
headRotation.getRotation().clone(),
"Warp 'spawn'"
);
// Teleportace zpět (/back)
history.back(ref, 1); // Vrátí se o 1 krok
// Teleportace vpřed (/forward)
history.forward(ref, 1); // Posune vpřed o 1 krok
---
PendingTeleport
Systém čekajících teleportů pro synchronizaci s klientem.
public class PendingTeleport implements Component {
private final Deque pendingTeleports = new ArrayDeque<>();
private byte lastId; public int queueTeleport(@Nonnull Teleport teleport) {
int id = ++this.lastId;
this.pendingTeleports.addLast(new TeleportInfo(id, teleport));
return id;
}
public void acknowledgeTeleport(int id) {
// Klient potvrdil teleport
this.pendingTeleports.removeIf(t -> t.id == id);
}
}
---
Network Packet
Teleport posílá ClientTeleport packet:
// Z TeleportSystems.PlayerMoveSystem
ClientTeleport teleportPacket = new ClientTeleport(
(byte)id,
new ModelTransform(
PositionUtil.toPositionPacket(transformComponent.getPosition()),
PositionUtil.toDirectionPacket(transformComponent.getRotation()),
headRotationComponent != null
? PositionUtil.toDirectionPacket(headRotationComponent.getRotation())
: PositionUtil.toDirectionPacket(transformComponent.getRotation())
),
teleport.isResetVelocity()
);
playerRefComponent.getPacketHandler().write(teleportPacket);
---
Shrnutí
| Metoda | Použití |
|--------|---------|
| Teleport.createForPlayer(world, transform) | Teleport hráče s cílovým světem |
| Teleport.createForPlayer(transform) | Teleport ve stejném světě |
| Teleport.createExact(pos, bodyRot, headRot) | Přesná kontrola rotací |
| .withoutVelocityReset() | Zachovat rychlost hráče |
| .setHeadRotation(rot) | Nastavit rotaci hlavy |
| store.addComponent(ref, Teleport.getComponentType(), teleport) | Provést teleport |
| TeleportHistory.append() | Uložit do historie |
| TeleportHistory.back(ref, count) | Teleport zpět |