Init
This commit is contained in:
904
content/world/entities/player-api.fr.md
Normal file
904
content/world/entities/player-api.fr.md
Normal file
@@ -0,0 +1,904 @@
|
||||
---
|
||||
title: Player API
|
||||
type: docs
|
||||
weight: 4
|
||||
---
|
||||
|
||||
The Player class provides extensive APIs for player management, including communication, health, inventory, permissions, and more.
|
||||
|
||||
## API Overview
|
||||
|
||||
{{< cards cols="3" >}}
|
||||
{{< card link="#identity--connection" title="Identity & Connection" subtitle="Name, UUID, network" >}}
|
||||
{{< card link="#communication" title="Communication" subtitle="Messages, titles, sounds" >}}
|
||||
{{< card link="#health--combat" title="Health & Combat" subtitle="HP, damage, effects" >}}
|
||||
{{< card link="#inventory-api" title="Inventory" subtitle="Items, slots, armor" >}}
|
||||
{{< card link="#permissions" title="Permissions" subtitle="Access control" >}}
|
||||
{{< card link="#movement--teleportation" title="Movement" subtitle="Teleport, position" >}}
|
||||
{{< /cards >}}
|
||||
|
||||
---
|
||||
|
||||
## Identity & Connection
|
||||
|
||||
### Basic Information
|
||||
|
||||
{{< tabs items="Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
|
||||
| Method | Return Type | Description |
|
||||
|--------|-------------|-------------|
|
||||
| `getUuid()` | `UUID` | Unique player identifier |
|
||||
| `getDisplayName()` | `String` | Display name (from PlayerRef username) |
|
||||
| `getClientViewRadius()` | `int` | Player's view radius in chunks |
|
||||
| `getViewRadius()` | `int` | Effective view radius (min of client and server) |
|
||||
| `hasPermission(String)` | `boolean` | Check permission |
|
||||
| `sendMessage(Message)` | `void` | Send message to player |
|
||||
| `getInventory()` | `Inventory` | Player's inventory |
|
||||
| `getGameMode()` | `GameMode` | Current game mode |
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Get entity reference from command context
|
||||
Ref<EntityStore> ref = context.senderAsPlayerRef();
|
||||
|
||||
// Access Player component via ref.getStore()
|
||||
Player player = ref.getStore().getComponent(ref, Player.getComponentType());
|
||||
|
||||
UUID uuid = player.getUuid();
|
||||
String displayName = player.getDisplayName();
|
||||
int viewRadius = player.getViewRadius();
|
||||
GameMode mode = player.getGameMode();
|
||||
|
||||
// Check permission
|
||||
if (player.hasPermission("myplugin.admin")) {
|
||||
player.sendMessage(Message.raw("You are an admin!"));
|
||||
}
|
||||
|
||||
// Get PlayerRef for more info
|
||||
PlayerRef playerRef = ref.getStore().getComponent(ref, PlayerRef.getComponentType());
|
||||
String username = playerRef.getUsername();
|
||||
String language = playerRef.getLanguage();
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
### PlayerRef (Thread-Safe Reference)
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Important:** `PlayerRef` is a component that provides thread-safe access to player data. It's stored in the entity component system and manages the player's connection, position, and various managers.
|
||||
{{< /callout >}}
|
||||
|
||||
{{< tabs items="Methods,Entity Reference,Connection & Messaging,Server Transfer" >}}
|
||||
{{< tab >}}
|
||||
|
||||
| Method | Return Type | Description |
|
||||
|--------|-------------|-------------|
|
||||
| `getUuid()` | `UUID` | Player's unique identifier |
|
||||
| `getUsername()` | `String` | Player's username |
|
||||
| `getLanguage()` | `String` | Player's language setting |
|
||||
| `setLanguage(String)` | `void` | Update language |
|
||||
| `getReference()` | `Ref<EntityStore>` | Entity reference (null if not in world) |
|
||||
| `getHolder()` | `Holder<EntityStore>` | Entity holder (when not in store) |
|
||||
| `isValid()` | `boolean` | Whether reference or holder exists |
|
||||
| `getTransform()` | `Transform` | Current position and rotation |
|
||||
| `getHeadRotation()` | `Vector3f` | Head rotation |
|
||||
| `getPacketHandler()` | `PacketHandler` | Network handler |
|
||||
| `getChunkTracker()` | `ChunkTracker` | Chunk loading tracker |
|
||||
| `getHiddenPlayersManager()` | `HiddenPlayersManager` | Player visibility manager |
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Get entity reference from command context
|
||||
Ref<EntityStore> ref = context.senderAsPlayerRef();
|
||||
|
||||
// Get PlayerRef via ref.getStore()
|
||||
PlayerRef playerRef = ref.getStore().getComponent(ref, PlayerRef.getComponentType());
|
||||
|
||||
// Check if player is valid
|
||||
if (playerRef != null && playerRef.isValid()) {
|
||||
UUID uuid = playerRef.getUuid();
|
||||
String username = playerRef.getUsername();
|
||||
|
||||
// Get entity reference
|
||||
Ref<EntityStore> entityRef = playerRef.getReference();
|
||||
if (entityRef != null) {
|
||||
// Player is in a world - access via entityRef.getStore()
|
||||
Player player = entityRef.getStore().getComponent(entityRef, Player.getComponentType());
|
||||
}
|
||||
}
|
||||
|
||||
// Get component from PlayerRef (convenience method)
|
||||
Player playerComponent = playerRef.getComponent(Player.getComponentType());
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Send message to player
|
||||
playerRef.sendMessage(Message.translation("welcome.message"));
|
||||
|
||||
// Get packet handler for more advanced operations
|
||||
PacketHandler handler = playerRef.getPacketHandler();
|
||||
|
||||
// Get player position info
|
||||
Transform transform = playerRef.getTransform();
|
||||
Vector3d position = transform.getPosition();
|
||||
Vector3f rotation = transform.getRotation();
|
||||
Vector3f headRotation = playerRef.getHeadRotation();
|
||||
|
||||
// Update position (called internally by systems)
|
||||
playerRef.updatePosition(world, transform, headRotation);
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Transfer player to another server (for server networks)
|
||||
playerRef.referToServer("play.example.com", 25565);
|
||||
|
||||
// With custom data payload
|
||||
byte[] referralData = serializePlayerData(playerRef);
|
||||
playerRef.referToServer("play.example.com", 25565, referralData);
|
||||
|
||||
// Note: Max referral data size is 4096 bytes
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Communication
|
||||
|
||||
### Sending Messages
|
||||
|
||||
{{< tabs items="Chat Messages,Translation Messages,Notifications" >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Get entity reference from command context
|
||||
Ref<EntityStore> ref = context.senderAsPlayerRef();
|
||||
|
||||
// Send chat message via PlayerRef
|
||||
PlayerRef playerRef = ref.getStore().getComponent(ref, PlayerRef.getComponentType());
|
||||
|
||||
// Simple message
|
||||
playerRef.sendMessage(Message.raw("Hello, World!"));
|
||||
|
||||
// Raw message
|
||||
playerRef.sendMessage(Message.raw("Plain text message"));
|
||||
|
||||
// Using Message interface (IMessageReceiver)
|
||||
Player player = ref.getStore().getComponent(ref, Player.getComponentType());
|
||||
player.sendMessage(Message.raw("Message via Player interface"));
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Using translation keys
|
||||
playerRef.sendMessage(Message.translation("welcome.message"));
|
||||
|
||||
// With parameters
|
||||
playerRef.sendMessage(
|
||||
Message.translation("greeting.message")
|
||||
.param("name", playerRef.getUsername())
|
||||
);
|
||||
|
||||
// With color
|
||||
playerRef.sendMessage(
|
||||
Message.translation("server.warning")
|
||||
.color("#ff5555")
|
||||
);
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Hytale uses Notifications instead of titles/action bars
|
||||
PacketHandler handler = playerRef.getPacketHandler();
|
||||
|
||||
// Simple notification
|
||||
NotificationUtil.sendNotification(handler, "Welcome to the server!");
|
||||
|
||||
// Notification with style
|
||||
NotificationUtil.sendNotification(handler,
|
||||
Message.raw("Achievement Unlocked!"),
|
||||
NotificationStyle.Default
|
||||
);
|
||||
|
||||
// With secondary message
|
||||
NotificationUtil.sendNotification(handler,
|
||||
Message.raw("Quest Complete"),
|
||||
Message.raw("You earned 100 XP"),
|
||||
NotificationStyle.Default
|
||||
);
|
||||
|
||||
// With icon
|
||||
NotificationUtil.sendNotification(handler,
|
||||
Message.raw("New Item"),
|
||||
"icon_name",
|
||||
NotificationStyle.Default
|
||||
);
|
||||
|
||||
// With item display
|
||||
NotificationUtil.sendNotification(handler,
|
||||
Message.raw("You received:"),
|
||||
Message.raw("Diamond x10"),
|
||||
itemWithMetadata,
|
||||
NotificationStyle.Default
|
||||
);
|
||||
|
||||
// Send to all players in universe
|
||||
NotificationUtil.sendNotificationToUniverse(
|
||||
Message.raw("Server restarting in 5 minutes!")
|
||||
);
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
### Playing Sounds
|
||||
|
||||
```java
|
||||
// Play 3D sound to player
|
||||
SoundUtil.playSoundEvent3dToPlayer(
|
||||
playerRef,
|
||||
TempAssetIdUtil.getSoundEventIndex("SFX_UI_Notification"),
|
||||
SoundCategory.UI,
|
||||
position,
|
||||
componentAccessor
|
||||
);
|
||||
|
||||
// Play 2D sound (no position)
|
||||
SoundUtil.playSoundEvent2d(
|
||||
ref,
|
||||
TempAssetIdUtil.getSoundEventIndex("SFX_Player_Pickup_Item"),
|
||||
SoundCategory.UI,
|
||||
componentAccessor
|
||||
);
|
||||
|
||||
// Play sound via world
|
||||
world.playSound(soundEvent, position, volume, pitch);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Health & Stats
|
||||
|
||||
{{< callout type="info" >}}
|
||||
Hytale uses an **EntityStats system** for managing health and other stats. Stats are managed via `EntityStatComponent` and include Health, Oxygen, Stamina, Mana, SignatureEnergy, and Ammo.
|
||||
{{< /callout >}}
|
||||
|
||||
### Entity Stats System
|
||||
|
||||
{{< tabs items="Available Stats,Accessing Stats,Modifying Stats" >}}
|
||||
{{< tab >}}
|
||||
|
||||
| Stat | Description |
|
||||
|------|-------------|
|
||||
| `Health` | Entity health points |
|
||||
| `Oxygen` | Breath/oxygen level |
|
||||
| `Stamina` | Physical stamina |
|
||||
| `Mana` | Magical energy |
|
||||
| `SignatureEnergy` | Special ability energy |
|
||||
| `Ammo` | Ammunition count |
|
||||
|
||||
These stats are defined via asset configuration and indexed at runtime.
|
||||
|
||||
```java
|
||||
// Get stat indices (from DefaultEntityStatTypes)
|
||||
int healthIndex = DefaultEntityStatTypes.getHealth();
|
||||
int staminaIndex = DefaultEntityStatTypes.getStamina();
|
||||
int manaIndex = DefaultEntityStatTypes.getMana();
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Get entity reference from command context
|
||||
Ref<EntityStore> ref = context.senderAsPlayerRef();
|
||||
|
||||
// Get EntityStatComponent from entity via ref.getStore()
|
||||
EntityStatComponent statsComponent = ref.getStore().getComponent(
|
||||
ref,
|
||||
EntityStatComponent.getComponentType()
|
||||
);
|
||||
|
||||
// Get specific stat value
|
||||
int healthIndex = DefaultEntityStatTypes.getHealth();
|
||||
float currentHealth = statsComponent.getValue(healthIndex);
|
||||
float maxHealth = statsComponent.getMaxValue(healthIndex);
|
||||
|
||||
// Check percentage
|
||||
float healthPercent = currentHealth / maxHealth;
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Modify stat values through the stats system
|
||||
// Stats are typically modified through the EntityStatsModule
|
||||
// and related systems (DamageSystems, HealSystems, etc.)
|
||||
|
||||
// Example: Apply damage via component
|
||||
// The DamageSystems handle damage application
|
||||
ref.getStore().putComponent(ref, Damage.getComponentType(),
|
||||
new Damage(damageAmount, damageSource));
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
### Invulnerability
|
||||
|
||||
```java
|
||||
// Get entity reference from command context
|
||||
Ref<EntityStore> ref = context.senderAsPlayerRef();
|
||||
|
||||
// Make player invulnerable (adds Invulnerable component)
|
||||
ref.getStore().putComponent(ref, Invulnerable.getComponentType(), Invulnerable.INSTANCE);
|
||||
|
||||
// Remove invulnerability
|
||||
ref.getStore().tryRemoveComponent(ref, Invulnerable.getComponentType());
|
||||
|
||||
// Check invulnerability
|
||||
boolean isInvulnerable = ref.getStore().getArchetype(ref)
|
||||
.contains(Invulnerable.getComponentType());
|
||||
|
||||
// Note: Creative mode automatically sets Invulnerable
|
||||
```
|
||||
|
||||
### Spawn Protection
|
||||
|
||||
```java
|
||||
// Get entity reference from command context
|
||||
Ref<EntityStore> ref = context.senderAsPlayerRef();
|
||||
|
||||
// Players have temporary invulnerability after spawning
|
||||
Player player = ref.getStore().getComponent(ref, Player.getComponentType());
|
||||
|
||||
// Check if player has spawn protection (3 seconds after spawn)
|
||||
if (player.hasSpawnProtection()) {
|
||||
// Player is temporarily invulnerable
|
||||
}
|
||||
|
||||
// Check if waiting for client ready
|
||||
if (player.isWaitingForClientReady()) {
|
||||
// Player hasn't finished loading yet
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Inventory API
|
||||
|
||||
### Basic Inventory Operations
|
||||
|
||||
{{< tabs items="Get Items,Set Items,Utility Methods" >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Get inventory
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
|
||||
// Get item in hand
|
||||
ItemStack heldItem = player.getHeldItem();
|
||||
ItemStack mainHand = player.getMainHandItem();
|
||||
ItemStack offHand = player.getOffHandItem();
|
||||
|
||||
// Get specific slot
|
||||
ItemStack slot5 = inventory.getItem(5);
|
||||
|
||||
// Get armor
|
||||
ArmorInventory armor = player.getArmor();
|
||||
ItemStack helmet = armor.getHelmet();
|
||||
ItemStack chestplate = armor.getChestplate();
|
||||
ItemStack leggings = armor.getLeggings();
|
||||
ItemStack boots = armor.getBoots();
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Set held item
|
||||
ItemStack sword = new ItemStack(ItemTypes.DIAMOND_SWORD);
|
||||
player.setHeldItem(sword);
|
||||
|
||||
// Set specific slot
|
||||
inventory.setItem(0, new ItemStack(ItemTypes.APPLE, 64));
|
||||
|
||||
// Set armor
|
||||
armor.setHelmet(new ItemStack(ItemTypes.DIAMOND_HELMET));
|
||||
armor.setChestplate(new ItemStack(ItemTypes.DIAMOND_CHESTPLATE));
|
||||
armor.setLeggings(new ItemStack(ItemTypes.DIAMOND_LEGGINGS));
|
||||
armor.setBoots(new ItemStack(ItemTypes.DIAMOND_BOOTS));
|
||||
|
||||
// Clear slot
|
||||
inventory.setItem(5, null);
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Give item (finds empty slot)
|
||||
ItemStack diamond = new ItemStack(ItemTypes.DIAMOND, 64);
|
||||
boolean success = player.giveItem(diamond);
|
||||
|
||||
if (!success) {
|
||||
// Inventory full, drop at feet
|
||||
player.dropItem(diamond);
|
||||
}
|
||||
|
||||
// Check for item
|
||||
if (inventory.contains(ItemTypes.DIAMOND)) {
|
||||
getLogger().at(Level.INFO).log("Player has diamonds");
|
||||
}
|
||||
|
||||
// Remove item
|
||||
inventory.remove(ItemTypes.DIAMOND, 10);
|
||||
|
||||
// Clear inventory
|
||||
inventory.clear();
|
||||
|
||||
// Count items
|
||||
int diamondCount = inventory.countItem(ItemTypes.DIAMOND);
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
### Advanced Inventory
|
||||
|
||||
```java
|
||||
// Open another inventory (chest, custom UI)
|
||||
Inventory chest = world.getBlockEntity(chestPos).getInventory();
|
||||
player.openInventory(chest);
|
||||
|
||||
// Create custom inventory
|
||||
Inventory customInv = new Inventory(27, "Shop"); // 27 slots
|
||||
customInv.setItem(13, new ItemStack(ItemTypes.DIAMOND, 1));
|
||||
player.openInventory(customInv);
|
||||
|
||||
// Close open inventory
|
||||
player.closeInventory();
|
||||
|
||||
// Get cursor item (what player is holding with mouse)
|
||||
ItemStack cursor = player.getCursorItem();
|
||||
player.setCursorItem(null);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Permissions
|
||||
|
||||
### Permission Checking
|
||||
|
||||
{{< tabs items="Basic Checks,Permission Levels,Custom Permissions" >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Check single permission
|
||||
if (player.hasPermission("myplugin.admin")) {
|
||||
player.sendMessage("You are an admin!");
|
||||
}
|
||||
|
||||
// Check operator status
|
||||
if (player.isOp()) {
|
||||
player.sendMessage("You are an operator!");
|
||||
}
|
||||
|
||||
// Multiple permission check
|
||||
if (player.hasPermission("myplugin.fly") ||
|
||||
player.hasPermission("myplugin.admin")) {
|
||||
enableFlight(player);
|
||||
}
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Permission hierarchy example
|
||||
public boolean hasMinimumRank(Player player, String rank) {
|
||||
switch (rank) {
|
||||
case "owner":
|
||||
return player.hasPermission("rank.owner");
|
||||
case "admin":
|
||||
return player.hasPermission("rank.admin") ||
|
||||
player.hasPermission("rank.owner");
|
||||
case "mod":
|
||||
return player.hasPermission("rank.mod") ||
|
||||
player.hasPermission("rank.admin") ||
|
||||
player.hasPermission("rank.owner");
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Grant permission
|
||||
player.addPermission("myplugin.vip");
|
||||
|
||||
// Revoke permission
|
||||
player.removePermission("myplugin.vip");
|
||||
|
||||
// Get all permissions
|
||||
Set<String> permissions = player.getPermissions();
|
||||
for (String perm : permissions) {
|
||||
getLogger().at(Level.INFO).log("Has permission: " + perm);
|
||||
}
|
||||
|
||||
// Set operator status
|
||||
player.setOp(true);
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Movement & Teleportation
|
||||
|
||||
### Position & Movement
|
||||
|
||||
{{< tabs items="Position Methods,Movement State,Velocity" >}}
|
||||
{{< tab >}}
|
||||
| Method | Return Type | Description |
|
||||
|--------|-------------|-------------|
|
||||
| `getPosition()` | `Vector3d` | Current position |
|
||||
| `setPosition(Vector3d)` | `void` | Set position |
|
||||
| `getEyePosition()` | `Vector3d` | Eye level position |
|
||||
| `getRotation()` | `Vector3f` | Look direction |
|
||||
| `setRotation(Vector3f)` | `void` | Set look direction |
|
||||
| `getEyeDirection()` | `Vector3d` | Normalized look vector |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
| Method | Return Type | Description |
|
||||
|--------|-------------|-------------|
|
||||
| `isOnGround()` | `boolean` | Whether on solid ground |
|
||||
| `isSprinting()` | `boolean` | Whether sprinting |
|
||||
| `setSprinting(boolean)` | `void` | Set sprint state |
|
||||
| `isSneaking()` | `boolean` | Whether sneaking |
|
||||
| `setSneaking(boolean)` | `void` | Set sneak state |
|
||||
| `isFlying()` | `boolean` | Whether flying |
|
||||
| `setFlying(boolean)` | `void` | Set flying state |
|
||||
| `isSwimming()` | `boolean` | Whether swimming |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Get velocity
|
||||
Vector3d velocity = player.getVelocity();
|
||||
|
||||
// Set velocity (launch player)
|
||||
player.setVelocity(new Vector3d(0, 1.5, 0));
|
||||
|
||||
// Add to velocity
|
||||
player.addVelocity(new Vector3d(1, 0, 0));
|
||||
|
||||
// Apply knockback
|
||||
player.knockback(new Vector3d(-0.5, 0.5, -0.5));
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
### Teleportation
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
Hytale uses a **component-based teleportation system**. You don't call `player.teleport()` directly. Instead, you add a `Teleport` component to the entity, and the system handles the teleportation.
|
||||
{{< /callout >}}
|
||||
|
||||
{{< tabs items="Basic Usage,Cross-World,Options,System Details" >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Get player reference from command context
|
||||
Ref<EntityStore> playerRef = context.senderAsPlayerRef();
|
||||
|
||||
// Teleport to position in same world
|
||||
Teleport teleport = new Teleport(
|
||||
new Vector3d(100, 64, 100), // position
|
||||
new Vector3f(0, 90, 0) // rotation (pitch, yaw, roll)
|
||||
);
|
||||
|
||||
// Add the teleport component to trigger teleportation
|
||||
playerRef.getStore().putComponent(playerRef, Teleport.getComponentType(), teleport);
|
||||
|
||||
// Using Transform
|
||||
Transform destination = new Transform(position, rotation);
|
||||
Teleport teleportFromTransform = new Teleport(destination);
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Get player reference from command context
|
||||
Ref<EntityStore> playerRef = context.senderAsPlayerRef();
|
||||
|
||||
// Teleport to another world
|
||||
World targetWorld = Universe.get().getWorld("other_world");
|
||||
|
||||
Teleport teleport = new Teleport(
|
||||
targetWorld, // target world
|
||||
new Vector3d(0, 64, 0), // position
|
||||
new Vector3f(0, 0, 0) // rotation
|
||||
);
|
||||
|
||||
playerRef.getStore().putComponent(playerRef, Teleport.getComponentType(), teleport);
|
||||
|
||||
// The TeleportSystems.PlayerMoveSystem handles:
|
||||
// - Same world: Direct position update
|
||||
// - Different world: Player removal and re-addition to target world
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Teleport with options using fluent builder
|
||||
Teleport teleport = new Teleport(targetWorld, position, rotation)
|
||||
.withHeadRotation(new Vector3f(0, 45, 0)) // Set head rotation
|
||||
.withResetRoll() // Reset roll to 0
|
||||
.withoutVelocityReset(); // Keep current velocity
|
||||
|
||||
// By default:
|
||||
// - resetVelocity = true (player stops moving)
|
||||
// - headRotation = same as body rotation
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
The teleportation flow:
|
||||
|
||||
1. **Add Teleport component** to entity
|
||||
2. **TeleportSystems.PlayerMoveSystem** detects the component
|
||||
3. System sends `ClientTeleport` packet to player
|
||||
4. **PendingTeleport** component tracks the teleport
|
||||
5. When client confirms, position is updated
|
||||
6. **Teleport component is removed** automatically
|
||||
|
||||
```java
|
||||
// Internal packet sent:
|
||||
ClientTeleport packet = new ClientTeleport(
|
||||
teleportId,
|
||||
new ModelTransform(position, direction, headRotation),
|
||||
resetVelocity
|
||||
);
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Game Mode
|
||||
|
||||
{{< callout type="info" >}}
|
||||
Hytale currently has **two game modes**: `Adventure` and `Creative`. These differ from Minecraft's game modes.
|
||||
{{< /callout >}}
|
||||
|
||||
{{< tabs items="Available Modes,Getting/Setting,Creative Features" >}}
|
||||
{{< tab >}}
|
||||
|
||||
| Mode | Value | Description |
|
||||
|------|-------|-------------|
|
||||
| `GameMode.Adventure` | 0 | Standard gameplay with survival mechanics |
|
||||
| `GameMode.Creative` | 1 | Creative mode with building freedom |
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
```java
|
||||
// Get current game mode
|
||||
GameMode mode = player.getGameMode();
|
||||
|
||||
// Check game mode
|
||||
if (mode == GameMode.Creative) {
|
||||
// Creative mode logic
|
||||
} else if (mode == GameMode.Adventure) {
|
||||
// Adventure mode logic
|
||||
}
|
||||
|
||||
// Set game mode (requires component accessor)
|
||||
// Note: This is typically done through systems/commands
|
||||
Player.setGameMode(playerRef, GameMode.Creative, componentAccessor);
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
|
||||
When in Creative mode:
|
||||
- Player is marked as `Invulnerable`
|
||||
- `canFly` is enabled in MovementManager
|
||||
- `canDecreaseItemStackDurability` returns false
|
||||
- `canApplyItemStackPenalties` returns false
|
||||
- Permission groups from GameModeType are applied
|
||||
|
||||
```java
|
||||
// GameMode affects these behaviors automatically:
|
||||
// - Flight enabled/disabled
|
||||
// - Invulnerability
|
||||
// - Item durability loss
|
||||
// - Block placement restrictions
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Server Actions
|
||||
|
||||
### Disconnecting Players
|
||||
|
||||
```java
|
||||
// Get entity reference from command context
|
||||
Ref<EntityStore> ref = context.senderAsPlayerRef();
|
||||
|
||||
// Disconnect player via PacketHandler
|
||||
PlayerRef playerRef = ref.getStore().getComponent(ref, PlayerRef.getComponentType());
|
||||
|
||||
// Disconnect with reason
|
||||
playerRef.getPacketHandler().disconnect("You have been kicked!");
|
||||
|
||||
// Disconnect with translation message
|
||||
playerRef.getPacketHandler().disconnect(
|
||||
Message.translation("server.kick.reason").toString()
|
||||
);
|
||||
```
|
||||
|
||||
### Player Lookup
|
||||
|
||||
```java
|
||||
// Get all online players through Universe
|
||||
Universe universe = Universe.get();
|
||||
|
||||
// Players are accessed through world contexts
|
||||
World world = universe.getWorld("main");
|
||||
|
||||
// Iterate players in world via entity store
|
||||
// Players are entities with PlayerRef component
|
||||
world.getEntityStore().forEach((ref, store) -> {
|
||||
PlayerRef playerRef = store.getComponent(ref, PlayerRef.getComponentType());
|
||||
if (playerRef != null) {
|
||||
String username = playerRef.getUsername();
|
||||
UUID uuid = playerRef.getUuid();
|
||||
// Process player...
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Server Transfer
|
||||
|
||||
```java
|
||||
// Get entity reference from command context
|
||||
Ref<EntityStore> ref = context.senderAsPlayerRef();
|
||||
|
||||
// Transfer player to another server (for server networks)
|
||||
PlayerRef playerRef = ref.getStore().getComponent(ref, PlayerRef.getComponentType());
|
||||
|
||||
// Redirect player to another server
|
||||
playerRef.referToServer("play.example.com", 25565);
|
||||
|
||||
// With custom data (max 4096 bytes)
|
||||
byte[] playerData = serializePlayerState(playerRef);
|
||||
playerRef.referToServer("play.example.com", 25565, playerData);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Practical Examples
|
||||
|
||||
### Welcome Plugin
|
||||
|
||||
```java
|
||||
public class WelcomePlugin extends ServerPlugin {
|
||||
|
||||
@Override
|
||||
public void setup(PluginSetup pluginSetup) {
|
||||
// Register event listeners
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Subscribe to player connect event
|
||||
HytaleServer.get().getEventBus()
|
||||
.subscribe(PlayerConnectEvent.class, this::onPlayerConnect);
|
||||
}
|
||||
|
||||
private void onPlayerConnect(PlayerConnectEvent event) {
|
||||
String username = event.getUsername();
|
||||
UUID uuid = event.getUuid();
|
||||
|
||||
getLogger().at(Level.INFO).log("Player connected: " + username + " (" + uuid + ")");
|
||||
|
||||
// Send welcome message after player is ready
|
||||
// Note: PlayerReadyEvent has String key, so use registerGlobal
|
||||
getEventRegistry().registerGlobal(PlayerReadyEvent.class, readyEvent -> {
|
||||
Player player = readyEvent.getPlayer();
|
||||
player.sendMessage(Message.raw("Welcome to the server, " + username + "!"));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
// Cleanup
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Permission Check Example
|
||||
|
||||
```java
|
||||
public class PermissionPlugin extends ServerPlugin {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
CommandRegistry registry = getCommandRegistry();
|
||||
|
||||
registry.register("admin", context -> {
|
||||
CommandSender sender = context.getSource();
|
||||
|
||||
// Check permission
|
||||
if (sender instanceof Player player) {
|
||||
if (!player.hasPermission("myplugin.admin")) {
|
||||
player.sendMessage(Message.raw("No permission!"));
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendMessage(Message.raw("You are an admin!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Inventory Management
|
||||
|
||||
```java
|
||||
// Get entity reference from command context
|
||||
Ref<EntityStore> ref = context.senderAsPlayerRef();
|
||||
|
||||
// Working with player inventory
|
||||
Player player = ref.getStore().getComponent(ref, Player.getComponentType());
|
||||
Inventory inventory = player.getInventory();
|
||||
|
||||
// Add item to inventory
|
||||
ItemStack itemStack = new ItemStack(itemType, amount);
|
||||
inventory.addItem(itemStack);
|
||||
|
||||
// Send inventory update to client
|
||||
player.sendInventory();
|
||||
|
||||
// Access hotbar
|
||||
HotbarManager hotbar = player.getHotbarManager();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Player API Guidelines:**
|
||||
- Use `PlayerRef` to get thread-safe player information
|
||||
- Check `isValid()` before operations on stored references
|
||||
- Use permissions via `player.hasPermission()` for access control
|
||||
- Understand the component system: players are entities with components
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Component System:** Players in Hytale are entities managed by an ECS. Access player data via `ref.getStore()` and appropriate component types (`Player.getComponentType()`, `PlayerRef.getComponentType()`).
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="error" >}}
|
||||
**Critical:** Never store `Ref<EntityStore>` or `Player` references directly in static fields. Use `UUID` for storage and retrieve references via the component system when needed.
|
||||
{{< /callout >}}
|
||||
|
||||
Reference in New Issue
Block a user