---
title: All Registries
type: docs
weight: 2
---

Complete reference of all registries available in the Hytale Plugin API.

## Registry Overview

Registries are accessed through `PluginBase` methods:

```java
public class MyPlugin extends PluginBase {
    @Override
    public void start() {
        EventRegistry events = getEventRegistry();
        CommandRegistry commands = getCommandRegistry();
        TaskRegistry tasks = getTaskRegistry();
        AssetRegistry assets = getAssetRegistry();
        BlockStateRegistry blocks = getBlockStateRegistry();
        CodecRegistry codecs = getCodecRegistry();
        EntityRegistry entities = getEntityRegistry();
    }
}
```

## EventRegistry

Manages event listeners and dispatching.

### Methods

| Method | Description |
|--------|-------------|
| `register(Class, Consumer)` | Register event handler |
| `register(EventPriority, Class, Consumer)` | Register with priority |
| `registerGlobal(Class, Consumer)` | Register global handler |
| `registerAsync(Class, Function)` | Register async handler |
| `unregister(listener)` | Remove listener |

### Example

```java
import com.hypixel.hytale.event.EventRegistry;
import com.hypixel.hytale.event.EventPriority;
import com.hypixel.hytale.server.core.event.events.player.PlayerConnectEvent;
import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.Message;
import java.util.logging.Level;

EventRegistry events = getEventRegistry();

// Use getPlayerRef() - getPlayer() is deprecated
events.register(PlayerConnectEvent.class, event -> {
    PlayerRef playerRef = event.getPlayerRef();
    playerRef.sendMessage(Message.raw("Welcome!"));
});

events.register(EventPriority.FIRST, PlayerDisconnectEvent.class, event -> {
    PlayerRef playerRef = event.getPlayerRef();
    getLogger().at(Level.INFO).log(playerRef.getUsername() + " left");
});
```

## CommandRegistry

Manages command registration and execution.

### Methods

| Method | Description |
|--------|-------------|
| `registerCommand(AbstractCommand)` | Register a command |

### Example

```java
import com.hypixel.hytale.server.core.command.system.AbstractCommand;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.CommandRegistry;
import com.hypixel.hytale.server.core.Message;
import java.util.concurrent.CompletableFuture;

CommandRegistry commands = getCommandRegistry();

// Register a command - AbstractCommand.execute() returns CompletableFuture<Void>
commands.registerCommand(new AbstractCommand("hello", "my_plugin.commands.hello.description") {
    @Override
    protected CompletableFuture<Void> execute(CommandContext ctx) {
        ctx.sender().sendMessage(Message.raw("Hello, World!"));
        return null; // Return null for synchronous completion
    }
});
```

{{< callout type="info" >}}
**Note:** Create a dedicated command class by extending `AbstractCommand` for complex commands. See [Creating Commands](/commands/creating-commands/) for details.
{{< /callout >}}

## TaskRegistry

Tracks asynchronous tasks for cleanup during plugin shutdown.

{{< callout type="warning" >}}
**Important:** TaskRegistry does NOT have `runAsync()`, `runSync()`, `runLater()`, or `runRepeating()` methods. Use Java's standard concurrency APIs instead.
{{< /callout >}}

### Methods

| Method | Description |
|--------|-------------|
| `registerTask(CompletableFuture<Void>)` | Register a CompletableFuture for tracking |
| `registerTask(ScheduledFuture<Void>)` | Register a ScheduledFuture for tracking |

### Example

```java
// Async operation
CompletableFuture<Void> task = CompletableFuture.runAsync(() -> {
    // Background work
    Data result = heavyComputation();

    world.execute(() -> {
        playerRef.sendMessage(Message.raw("Done: " + result));
    });
});
getTaskRegistry().registerTask(task);

// Delayed operation (3 seconds)
CompletableFuture.delayedExecutor(3, TimeUnit.SECONDS)
    .execute(() -> {
        world.execute(() -> {
            getLogger().at(Level.INFO).log("3 seconds passed!");
        });
    });

// Repeating operation
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> repeating = scheduler.scheduleAtFixedRate(() -> {
    broadcastTime();
}, 0, 5, TimeUnit.MINUTES);
getTaskRegistry().registerTask((ScheduledFuture<Void>) repeating);
```

## AssetRegistry

Registers custom asset stores with the game.

**Package:** `com.hypixel.hytale.server.core.plugin.registry`

{{< callout type="warning" >}}
**Important:** `AssetRegistry` does NOT provide `getItem()`, `getBlockType()`, etc. methods. To access assets, use the asset class's static methods directly.
{{< /callout >}}

### Methods

| Method | Description |
|--------|-------------|
| `register(AssetStore)` | Register a custom AssetStore |

### Accessing Assets

Assets are accessed via their class's static methods, not through AssetRegistry:

```java
import com.hypixel.hytale.assetstore.map.DefaultAssetMap;
import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;

// Get items by string ID directly (DefaultAssetMap)
DefaultAssetMap<String, Item> itemMap = Item.getAssetMap();
Item sword = itemMap.getAsset("iron_sword");

// Get block types
DefaultAssetMap<String, BlockType> blockMap = BlockType.getAssetMap();
BlockType stone = blockMap.getAsset("stone");
```

{{< callout type="info" >}}
**Note:** Most assets like `Item` and `BlockType` use `DefaultAssetMap` where you can access by string key directly. Some assets like `Interaction` use `IndexedLookupTableAssetMap` which requires getting the index first.
{{< /callout >}}

### Custom Asset Store Registration

```java
AssetRegistry assets = getAssetRegistry();

// Register a custom asset store
assets.register(MyCustomAsset.getAssetStore());
```

## BlockStateRegistry

Manages block states and their properties.

### Methods

| Method | Description |
|--------|-------------|
| `getBlockState(BlockType)` | Get default state |
| `getBlockState(BlockType, Properties)` | Get state with properties |

### Example

```java
BlockStateRegistry blocks = getBlockStateRegistry();

BlockState stone = blocks.getBlockState(stoneType);
world.setBlockState(x, y, z, stone);
```

## Codec Registration

**Package:** `com.hypixel.hytale.server.core.plugin.registry`

{{< callout type="warning" >}}
**Important:** There is no simple `CodecRegistry` class. Instead, use the typed `getCodecRegistry()` methods with codec map parameters.
{{< /callout >}}

### Methods

| Method | Description |
|--------|-------------|
| `getCodecRegistry(StringCodecMapCodec)` | Get CodecMapRegistry for string-keyed codecs |
| `getCodecRegistry(AssetCodecMapCodec)` | Get CodecMapRegistry.Assets for asset codecs |
| `getCodecRegistry(MapKeyMapCodec)` | Get MapKeyMapRegistry for map-keyed codecs |

### Example

```java
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.server.core.plugin.registry.CodecMapRegistry;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction;

// Register a custom interaction type using the Interaction CODEC
CodecMapRegistry.Assets<Interaction, ?> registry =
    getCodecRegistry(Interaction.CODEC);

registry.register("MyCustomInteraction", MyCustomInteraction.class, MyCustomInteraction.CODEC);
```

For simple data serialization, use `BuilderCodec` directly:

```java
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.Codec;

// Define a codec for your data class
public static final BuilderCodec<PlayerData> CODEC = BuilderCodec.builder(PlayerData.class, PlayerData::new)
    .append(new KeyedCodec<>("name", Codec.STRING),
            (obj, val) -> obj.name = val,
            obj -> obj.name)
    .add()
    .build();
```

## EntityRegistry

Registers custom entity types with the game.

**Package:** `com.hypixel.hytale.server.core.modules.entity`

{{< callout type="warning" >}}
**Important:** `EntityRegistry` is for registering custom entity types, NOT for spawning entities. To spawn entities, use `World.spawnEntity()`.
{{< /callout >}}

### Methods

| Method | Description |
|--------|-------------|
| `registerEntity(String, Class, Function, Codec)` | Register a custom entity type |

### Registering Custom Entities

```java
import com.hypixel.hytale.server.core.entity.Entity;
import com.hypixel.hytale.codec.DirectDecodeCodec;

EntityRegistry entities = getEntityRegistry();

// Register a custom entity type
entities.registerEntity(
    "my_custom_entity",
    MyCustomEntity.class,
    world -> new MyCustomEntity(world),
    MyCustomEntity.CODEC
);
```

### Spawning Entities

To spawn entities at runtime, use `World`:

```java
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.entity.Entity;

World world = player.getWorld();

// Spawn an entity
Entity entity = world.spawnEntity(entityClass, position);
```

## Registry Access Patterns

### Lazy Initialization

```java
public class MyPlugin extends PluginBase {
    private EventRegistry events;
    private CommandRegistry commands;

    @Override
    public void start() {
        this.events = getEventRegistry();
        this.commands = getCommandRegistry();

        registerEvents();
        registerCommands();
    }

    private void registerEvents() {
        events.register(PlayerConnectEvent.class, this::onJoin);
    }

    private void registerCommands() {
        commands.register(new MyCommand());
    }
}
```

### Helper Methods

```java
public class MyPlugin extends JavaPlugin {
    public void runOnWorldThread(World world, Runnable task) {
        world.execute(task);
    }

    public void runAsync(Runnable task) {
        CompletableFuture.runAsync(task);
    }

    public Item getItem(String id) {
        return getAssetRegistry().getItem(id);
    }
}
```

## Thread Safety

{{< callout type="warning" >}}
**Registry Thread Safety:**
- Most registries are designed for world thread access
- Each World runs on its own dedicated thread
- Use `world.execute()` when accessing from async code
- TaskRegistry is thread-safe for task registration
{{< /callout >}}

```java
// Safe async pattern
World world = player.getWorld();
PlayerRef playerRef = player.getPlayerRef();

CompletableFuture.runAsync(() -> {
    // Background work
    Data result = compute();

    // Return to world thread for game state changes
    world.execute(() -> {
        // Access other registries here safely
        EventRegistry events = getEventRegistry();
        playerRef.sendMessage(Message.raw("Result: " + result));
    });
});
```
