---
title: Portal Components
type: docs
weight: 1
---

Portal components define the data structures for portal devices, portal worlds, and void events.

**Package:** `com.hypixel.hytale.builtin.portals.components`

## PortalDevice

A chunk-level component representing a portal block device.

```java
public class PortalDevice implements Component<ChunkStore> {
    // Configuration for portal states
    private PortalDeviceConfig config;

    // Block type key for the portal device
    private String baseBlockTypeKey;

    // UUID of the destination world (if active)
    private UUID destinationWorldUuid;
}
```

### Accessing Portal Devices

```java
// Get portal device at block position
PortalDevice portal = BlockModule.get().getComponent(
    PortalDevice.getComponentType(),
    world, x, y, z
);

if (portal != null) {
    // Portal exists at this location
    BlockType blockType = portal.getBaseBlockType();
    World destination = portal.getDestinationWorld();
}
```

### Destination World

```java
// Set destination when activating portal
portal.setDestinationWorld(targetWorld);

// Get destination (null if inactive or world closed)
World destination = portal.getDestinationWorld();
if (destination == null || !destination.isAlive()) {
    // Portal destination invalid
}
```

## PortalDeviceConfig

Configuration for portal device visual states.

```java
public class PortalDeviceConfig {
    // State when instance is being created
    private String spawningState = "Spawning";

    // State when portal is active
    private String onState = "Active";

    // State when portal is inactive
    private String offState = "default";

    // Block placed at spawn point in portal world
    private String returnBlock;
}
```

### State Validation

```java
// Verify all states exist on block type
PortalDeviceConfig config = portal.getConfig();
if (config.areBlockStatesValid(baseBlockType)) {
    // All states (on, off, spawning) are valid
}
```

### State Names

| State | Description | Default |
|-------|-------------|---------|
| `spawningState` | Transition from off to on | "Spawning" |
| `onState` | Portal is active | "Active" |
| `offState` | Portal is inactive | "default" |

## PortalWorld

A resource attached to worlds created by portals.

```java
public class PortalWorld implements Resource<EntityStore> {
    // Portal type configuration ID
    private String portalTypeId;

    // Time limit in seconds
    private int timeLimitSeconds;

    // Removal condition handler
    private PortalRemovalCondition worldRemovalCondition;

    // Players who died in this world
    private Set<UUID> diedInWorld;

    // Players currently seeing the UI
    private Set<UUID> seesUi;

    // Spawn point transform
    private Transform spawnPoint;

    // Reference to active void event
    private Ref<EntityStore> voidEventRef;
}
```

### Checking Portal World

```java
// Get portal world resource
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());

// Check if this is a valid portal world
if (portalWorld.exists()) {
    PortalType type = portalWorld.getPortalType();
    int timeLimit = portalWorld.getTimeLimitSeconds();
}
```

### Time Management

```java
// Get elapsed and remaining time
double elapsed = portalWorld.getElapsedSeconds(world);
double remaining = portalWorld.getRemainingSeconds(world);

// Modify remaining time (e.g., extend timer)
portalWorld.setRemainingSeconds(world, 300.0); // 5 minutes
```

### Death Tracking

```java
// Check if player died in this world
if (portalWorld.getDiedInWorld().contains(playerUuid)) {
    // Cannot re-enter - died here
}

// Track a death
portalWorld.getDiedInWorld().add(playerUuid);
```

### UI State

```java
// Track players seeing the portal UI
portalWorld.getSeesUi().add(playerUuid);
portalWorld.getSeesUi().remove(playerUuid);
```

## VoidEvent

Component for void invasion events in portal worlds.

```java
public class VoidEvent implements Component<EntityStore> {
    // Minimum distance between spawners
    public static final double MIN_BLOCKS_BETWEEN_SPAWNERS = 62.0;

    // Spatial grid of void spawners
    private SpatialHashGrid<Ref<EntityStore>> voidSpawners;

    // Current active stage
    private VoidEventStage activeStage;
}
```

### Void Event Access

```java
// Check if void event is active
Ref<EntityStore> voidRef = portalWorld.getVoidEventRef();
if (portalWorld.isVoidEventActive()) {
    VoidEvent voidEvent = store.getComponent(voidRef, VoidEvent.getComponentType());
    VoidEventStage stage = voidEvent.getActiveStage();
}
```

### Void Spawner Grid

```java
// Get spawner grid
SpatialHashGrid<Ref<EntityStore>> spawners = voidEvent.getVoidSpawners();

// Spawners maintain minimum distance of 62 blocks
```

## VoidEventConfig

Configuration for void events.

```java
public class VoidEventConfig {
    // Duration of void event in seconds
    private int durationSeconds;

    // Stages of the void event
    private List<VoidEventStage> stages;
}
```

## VoidEventStage

Single stage in a void event progression.

```java
public class VoidEventStage {
    // When this stage starts (seconds from event start)
    private int startTime;

    // Spawners to activate
    private List<VoidSpawnerConfig> spawners;
}
```

## VoidSpawner

Entity component for void invasion spawners.

```java
public class VoidSpawner implements Component<EntityStore> {
    // Spawner configuration
    // Tracks active spawning state
}
```

## Component Registration

Components are registered in PortalsPlugin setup:

```java
// In PortalsPlugin.setup()
this.portalDeviceComponentType = this.getChunkStoreRegistry()
    .registerComponent(PortalDevice.class, "Portal", PortalDevice.CODEC);

this.voidEventComponentType = this.getEntityStoreRegistry()
    .registerComponent(VoidEvent.class, VoidEvent::new);

this.voidPortalComponentType = this.getEntityStoreRegistry()
    .registerComponent(VoidSpawner.class, VoidSpawner::new);
```

## Serialization

PortalDevice uses BuilderCodec for persistence:

```java
public static final BuilderCodec<PortalDevice> CODEC = BuilderCodec.builder(...)
    .append(new KeyedCodec<>("Config", PortalDeviceConfig.CODEC), ...)
    .append(new KeyedCodec<>("BaseBlockType", Codec.STRING), ...)
    .append(new KeyedCodec<>("DestinationWorld", Codec.UUID_BINARY), ...)
    .build();
```
