This commit is contained in:
2026-01-20 20:33:59 +01:00
commit b16a40e431
583 changed files with 87339 additions and 0 deletions

View File

@@ -0,0 +1,266 @@
---
title: Spawning Entities
type: docs
weight: 3
---
Create and spawn entities into the world by registering entity classes and using the World API.
## Registering Entities
Before spawning entities, register them with the EntityRegistry in your plugin's `start()` method:
```java
@Override
public void start() {
// Register entity with key, class, constructor, and codec
getEntityRegistry().registerEntity(
"my_custom_entity",
CustomEntity.class,
world -> new CustomEntity(world),
CustomEntity.CODEC
);
}
```
### Registration Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| key | `String` | Unique identifier for the entity type |
| clazz | `Class<T>` | The entity class |
| constructor | `Function<World, T>` | Factory function that creates entity instances |
| codec | `DirectDecodeCodec<T>` | Serialization codec for persistence |
## Entity Base Classes
Hytale provides two main entity base classes:
### Entity
Base class for all entities. Implements `Component<EntityStore>`.
```java
public class SimpleEntity extends Entity {
public static final DirectDecodeCodec<SimpleEntity> CODEC =
Entity.CODEC.extend(SimpleEntity.class, SimpleEntity::new);
public SimpleEntity() {
super();
}
public SimpleEntity(World world) {
super(world);
}
}
```
### LivingEntity
Extended base class for entities with health, inventory, and stats.
```java
public class CustomMob extends LivingEntity {
public static final DirectDecodeCodec<CustomMob> CODEC =
LivingEntity.CODEC.extend(CustomMob.class, CustomMob::new);
public CustomMob() {
super();
}
public CustomMob(World world) {
super(world);
}
@Override
protected Inventory createDefaultInventory() {
return new Inventory(36); // 36 slots
}
}
```
## Spawning Entities
Use the World API to spawn registered entities:
```java
// Get the world
World world = player.getWorld();
// Create entity instance
CustomMob mob = new CustomMob(world);
// Define spawn position and rotation
Vector3d position = new Vector3d(100, 64, 200);
Vector3f rotation = new Vector3f(0, 90, 0); // Facing east
// Spawn the entity (deprecated but functional)
world.spawnEntity(mob, position, rotation);
```
### addEntity Method
For more control over spawn reasons, use `addEntity`:
```java
// AddReason options: SPAWN, LOAD, TRANSFER
world.addEntity(mob, position, rotation, AddReason.SPAWN);
```
{{< callout type="warning" >}}
**Deprecation Notice:** Both `spawnEntity` and `addEntity` methods on World are deprecated. The modern approach uses the component-based EntityStore system directly. However, these methods still work and are the simplest way to spawn entities.
{{< /callout >}}
## Entity Lifecycle
### Loading into World
When an entity is added to a world:
```java
// Called automatically when entity is added
entity.loadIntoWorld(world);
// Entity receives network ID
int networkId = entity.getNetworkId();
// Reference is created for component access
Ref<EntityStore> ref = entity.getReference();
```
### Removing Entities
```java
// Remove an entity from the world
boolean removed = entity.remove();
// Check if entity was already removed
if (entity.wasRemoved()) {
// Entity no longer valid
}
```
## Entity Events
### EntityRemoveEvent
Listen for entity removal:
```java
getEventRegistry().register(EntityRemoveEvent.class, event -> {
Entity entity = event.getEntity();
getLogger().at(Level.INFO).log("Entity removed: " + entity.getClass().getSimpleName());
});
```
### LivingEntityInventoryChangeEvent
Track inventory changes on living entities:
```java
getEventRegistry().register(LivingEntityInventoryChangeEvent.class, event -> {
LivingEntity entity = event.getEntity();
// Handle inventory change
});
```
{{< callout type="info" >}}
**No Spawn Event:** Hytale does not have an EntitySpawnEvent. To track spawns, consider implementing custom logic in your entity constructor or using the component system's add callbacks.
{{< /callout >}}
## Complete Example
```java
public class MyPlugin extends JavaPlugin {
@Override
public void start() {
// Register custom entity
getEntityRegistry().registerEntity(
"boss_monster",
BossMonster.class,
world -> new BossMonster(world),
BossMonster.CODEC
);
// Listen for removal
getEventRegistry().register(EntityRemoveEvent.class, this::onEntityRemove);
}
private void onEntityRemove(EntityRemoveEvent event) {
if (event.getEntity() instanceof BossMonster) {
getLogger().at(Level.INFO).log("Boss monster was defeated!");
}
}
public void spawnBoss(Player player) {
World world = player.getWorld();
// Create boss at player's location
BossMonster boss = new BossMonster(world);
// Get player position and add offset
Vector3d spawnPos = player.getTransformComponent().getPosition();
spawnPos = new Vector3d(spawnPos.x + 5, spawnPos.y, spawnPos.z);
// Face the player
Vector3f rotation = new Vector3f(0, 180, 0);
// Spawn
world.spawnEntity(boss, spawnPos, rotation);
}
}
public class BossMonster extends LivingEntity {
public static final DirectDecodeCodec<BossMonster> CODEC =
LivingEntity.CODEC.extend(BossMonster.class, BossMonster::new);
public BossMonster() {
super();
}
public BossMonster(World world) {
super(world);
}
@Override
protected Inventory createDefaultInventory() {
return new Inventory(9); // Small inventory
}
@Override
public boolean isCollidable() {
return true;
}
}
```
## Thread Safety
{{< callout type="error" >}}
**Important:** Entity spawning should be done on the world's ticking thread. If calling from an async context, use the world's executor:
{{< /callout >}}
```java
// Safe spawning from async context
world.execute(() -> {
world.spawnEntity(entity, position, rotation);
});
```
## Spawn Validation
The world validates spawn positions:
```java
// Position requirements:
// - X and Z must be within +/- 33554432
// - Y must be >= -32
// Invalid positions will throw IllegalArgumentException
try {
world.spawnEntity(entity, invalidPosition, rotation);
} catch (IllegalArgumentException e) {
getLogger().warning("Invalid spawn position: " + e.getMessage());
}
```