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,147 @@
---
title: Portals
type: docs
weight: 6
---
The portals system provides mechanics for inter-dimensional travel between worlds, including portal devices, void events, and fragment instances.
**Package:** `com.hypixel.hytale.builtin.portals`
## Architecture
```
Portals System
├── Components
│ ├── PortalDevice - Portal block component
│ ├── VoidEvent - Void invasion event
│ └── VoidSpawner - Void spawner entity
├── Resources
│ └── PortalWorld - Portal world data
├── Interactions
│ ├── EnterPortalInteraction - Enter portal
│ └── ReturnPortalInteraction - Return from portal
├── Systems
│ ├── PortalTrackerSystems - UI tracking
│ ├── PortalInvalidDestinationSystem - Destination validation
│ ├── VoidEventStagesSystem - Void event progression
│ └── VoidSpawnerSystems - Spawner management
└── Commands
├── FragmentCommands - Fragment management
├── LeaveCommand - Leave portal world
└── VoidEventCommands - Void event control
```
## Core Concepts
### Portal Device
A portal device is a block-based entity that can transport players to fragment worlds:
```java
// PortalDevice is a ChunkStore component
PortalDevice portal = BlockModule.get().getComponent(
PortalDevice.getComponentType(),
world, x, y, z
);
// Get destination world
World targetWorld = portal.getDestinationWorld();
```
### Portal World
A portal world is a temporary instance created when players activate a portal:
```java
// PortalWorld is an EntityStore resource
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
// Check if this is a portal world
if (portalWorld.exists()) {
Transform spawn = portalWorld.getSpawnPoint();
double remaining = portalWorld.getRemainingSeconds(world);
}
```
### Fragment Instances
Fragments are temporary worlds with:
- Time limit before auto-closure
- Spawn point for returning players
- Death tracking (players who died cannot re-enter)
- Optional void invasion events
## Key Features
### Portal States
Portals have three visual states:
- **Off** - Portal is inactive
- **Spawning** - Instance is being created
- **On/Active** - Portal is ready for travel
### Time Limits
Portal worlds have configurable time limits:
```java
int totalTime = portalWorld.getTimeLimitSeconds();
double elapsed = portalWorld.getElapsedSeconds(world);
double remaining = portalWorld.getRemainingSeconds(world);
```
### Death Tracking
Players who die in a portal world cannot re-enter:
```java
Set<UUID> deaths = portalWorld.getDiedInWorld();
if (deaths.contains(playerUuid)) {
// Player died here - show "DIED_IN_WORLD" state
}
```
### Cursed Items
Items can become "cursed" in portal worlds and are removed on death:
```java
// Uncurse items when returning
CursedItems.uncurseAll(inventory.getCombinedEverything());
```
## Plugin Access
```java
PortalsPlugin portals = PortalsPlugin.getInstance();
// Component types
ComponentType<ChunkStore, PortalDevice> portalDeviceType =
portals.getPortalDeviceComponentType();
ComponentType<EntityStore, VoidEvent> voidEventType =
portals.getVoidEventComponentType();
ComponentType<EntityStore, VoidSpawner> voidSpawnerType =
portals.getVoidPortalComponentType();
// Resource type
ResourceType<EntityStore, PortalWorld> portalWorldType =
portals.getPortalResourceType();
```
## Concurrent Fragments Limit
The system limits concurrent portal fragments:
```java
public static final int MAX_CONCURRENT_FRAGMENTS = 4;
int active = portals.countActiveFragments();
if (active >= MAX_CONCURRENT_FRAGMENTS) {
// Cannot create new fragments
}
```
## Related Topics
{{< cards >}}
{{< card link="portal-components" title="Portal Components" subtitle="PortalDevice, VoidEvent components" >}}
{{< card link="portal-systems" title="Portal Systems" subtitle="ECS systems for portal logic" >}}
{{< card link="portal-commands" title="Portal Commands" subtitle="Admin and player commands" >}}
{{< /cards >}}

View File

@@ -0,0 +1,147 @@
---
title: Portails
type: docs
weight: 6
---
Le systeme de portails fournit des mecaniques de voyage inter-dimensionnel entre les mondes, incluant les dispositifs de portail, les evenements du vide et les instances de fragment.
**Package:** `com.hypixel.hytale.builtin.portals`
## Architecture
```
Systeme Portails
├── Composants
│ ├── PortalDevice - Composant bloc portail
│ ├── VoidEvent - Evenement invasion du vide
│ └── VoidSpawner - Entite spawner du vide
├── Ressources
│ └── PortalWorld - Donnees monde portail
├── Interactions
│ ├── EnterPortalInteraction - Entrer portail
│ └── ReturnPortalInteraction - Retour du portail
├── Systemes
│ ├── PortalTrackerSystems - Suivi UI
│ ├── PortalInvalidDestinationSystem - Validation destination
│ ├── VoidEventStagesSystem - Progression evenement vide
│ └── VoidSpawnerSystems - Gestion spawners
└── Commandes
├── FragmentCommands - Gestion fragments
├── LeaveCommand - Quitter monde portail
└── VoidEventCommands - Controle evenement vide
```
## Concepts Cles
### Dispositif Portail
Un dispositif de portail est une entite basee sur un bloc qui peut transporter les joueurs vers des mondes fragments:
```java
// PortalDevice est un composant ChunkStore
PortalDevice portal = BlockModule.get().getComponent(
PortalDevice.getComponentType(),
world, x, y, z
);
// Obtenir monde de destination
World targetWorld = portal.getDestinationWorld();
```
### Monde Portail
Un monde portail est une instance temporaire creee quand les joueurs activent un portail:
```java
// PortalWorld est une ressource EntityStore
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
// Verifier si c'est un monde portail
if (portalWorld.exists()) {
Transform spawn = portalWorld.getSpawnPoint();
double remaining = portalWorld.getRemainingSeconds(world);
}
```
### Instances Fragment
Les fragments sont des mondes temporaires avec:
- Limite de temps avant fermeture automatique
- Point de spawn pour les joueurs revenant
- Suivi des morts (les joueurs morts ne peuvent pas re-entrer)
- Evenements d'invasion du vide optionnels
## Fonctionnalites Cles
### Etats du Portail
Les portails ont trois etats visuels:
- **Eteint** - Portail inactif
- **Invocation** - Instance en creation
- **Actif** - Portail pret pour le voyage
### Limites de Temps
Les mondes portails ont des limites de temps configurables:
```java
int totalTime = portalWorld.getTimeLimitSeconds();
double elapsed = portalWorld.getElapsedSeconds(world);
double remaining = portalWorld.getRemainingSeconds(world);
```
### Suivi des Morts
Les joueurs morts dans un monde portail ne peuvent pas re-entrer:
```java
Set<UUID> deaths = portalWorld.getDiedInWorld();
if (deaths.contains(playerUuid)) {
// Joueur mort ici - afficher etat "DIED_IN_WORLD"
}
```
### Items Maudits
Les items peuvent devenir "maudits" dans les mondes portails et sont retires a la mort:
```java
// Retirer malediction des items au retour
CursedItems.uncurseAll(inventory.getCombinedEverything());
```
## Acces au Plugin
```java
PortalsPlugin portals = PortalsPlugin.getInstance();
// Types de composants
ComponentType<ChunkStore, PortalDevice> portalDeviceType =
portals.getPortalDeviceComponentType();
ComponentType<EntityStore, VoidEvent> voidEventType =
portals.getVoidEventComponentType();
ComponentType<EntityStore, VoidSpawner> voidSpawnerType =
portals.getVoidPortalComponentType();
// Type de ressource
ResourceType<EntityStore, PortalWorld> portalWorldType =
portals.getPortalResourceType();
```
## Limite Fragments Concurrents
Le systeme limite les fragments portails concurrents:
```java
public static final int MAX_CONCURRENT_FRAGMENTS = 4;
int active = portals.countActiveFragments();
if (active >= MAX_CONCURRENT_FRAGMENTS) {
// Impossible de creer nouveaux fragments
}
```
## Sujets Connexes
{{< cards >}}
{{< card link="portal-components" title="Composants Portail" subtitle="Composants PortalDevice, VoidEvent" >}}
{{< card link="portal-systems" title="Systemes Portail" subtitle="Systemes ECS pour logique portail" >}}
{{< card link="portal-commands" title="Commandes Portail" subtitle="Commandes admin et joueur" >}}
{{< /cards >}}

View File

@@ -0,0 +1,224 @@
---
title: Portal Commands
type: docs
weight: 3
---
Commands for managing portals, fragments, and void events.
**Package:** `com.hypixel.hytale.builtin.portals.commands`
## Player Commands
### /leave
Leave the current portal world and return to the origin world.
```
/leave
```
**Behavior:**
- Only works when inside a portal world
- Uncurses all items in inventory before leaving
- Teleports player back to the portal device location
**Implementation:**
```java
public class LeaveCommand extends AbstractPlayerCommand {
@Override
protected void execute(CommandContext context, Store<EntityStore> store,
Ref<EntityStore> ref, PlayerRef playerRef, World world) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
if (!portalWorld.exists()) {
playerRef.sendMessage(MESSAGE_NOT_IN_PORTAL);
return;
}
// Remove curse from all items
CursedItems.uncurseAll(player.getInventory().getCombinedEverything());
// Exit the instance
InstancesPlugin.exitInstance(ref, store);
}
}
```
## Fragment Commands
### /fragment
Parent command for fragment management.
```
/fragment <subcommand>
```
| Subcommand | Description |
|------------|-------------|
| `timer` | Modify fragment time remaining |
### /fragment timer
Set the remaining time for the current portal fragment.
```
/fragment timer <seconds>
```
**Arguments:**
| Argument | Type | Description |
|----------|------|-------------|
| `seconds` | INTEGER | New remaining time in seconds |
**Example:**
```
/fragment timer 300 # Set 5 minutes remaining
/fragment timer 60 # Set 1 minute remaining
```
**Implementation:**
```java
public class TimerFragmentCommand extends PortalWorldCommandBase {
private final RequiredArg<Integer> remainingSecondsArg;
@Override
protected void execute(CommandContext context, World world,
PortalWorld portalWorld, Store<EntityStore> store) {
int before = (int) portalWorld.getRemainingSeconds(world);
int desired = remainingSecondsArg.get(context);
portalWorld.setRemainingSeconds(world, desired);
// Reports: "Changed from {before} to {after}"
}
}
```
## Void Event Commands
### /voidevent
Parent command for void event management.
```
/voidevent <subcommand>
```
| Subcommand | Description |
|------------|-------------|
| `start` | Start a void event |
### /voidevent start
Start a void invasion event in the current world.
```
/voidevent start [--override]
```
**Flags:**
| Flag | Description |
|------|-------------|
| `--override` | Force start even if not in a portal world |
**Behavior:**
- If already in a portal world with void event active: fails
- If not in portal world without `--override`: fails
- With `--override`: creates temporary portal world configuration
- Sets remaining time to 1 second to trigger void event
**Implementation:**
```java
public class StartVoidEventCommand extends AbstractWorldCommand {
private final FlagArg overrideWorld;
@Override
protected void execute(CommandContext context, World world,
Store<EntityStore> store) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
// Check if already running
if (portalWorld.exists() && portalWorld.isVoidEventActive()) {
context.sendMessage("Void event already running");
return;
}
// If not in portal world, require --override
if (!portalWorld.exists()) {
if (!overrideWorld.get(context)) {
context.sendMessage("Not in portal world");
return;
}
// Set up temporary portal world config
portalWorld.init(portalType, timeLimit, removalCondition, config);
}
// Trigger void event by setting timer to 1 second
portalWorld.setRemainingSeconds(world, 1.0);
}
}
```
## Utility Commands
### /cursehelditem
Mark the currently held item as cursed (debug/testing command).
```
/cursehelditem
```
**Behavior:**
- Adds curse marker to item in main hand
- Cursed items are lost when player dies in portal world
## Command Base Classes
### PortalWorldCommandBase
Base class for commands that require a portal world:
```java
public abstract class PortalWorldCommandBase extends AbstractWorldCommand {
@Override
protected final void execute(CommandContext context, World world,
Store<EntityStore> store) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
if (!portalWorld.exists()) {
context.sendMessage(MESSAGE_NOT_IN_PORTAL);
return;
}
execute(context, world, portalWorld, store);
}
protected abstract void execute(CommandContext context, World world,
PortalWorld portalWorld,
Store<EntityStore> store);
}
```
## Command Registration
Commands are registered in PortalsPlugin setup:
```java
this.getCommandRegistry().registerCommand(new LeaveCommand());
this.getCommandRegistry().registerCommand(new CursedHeldItemCommand());
this.getCommandRegistry().registerCommand(new VoidEventCommands());
this.getCommandRegistry().registerCommand(new FragmentCommands());
```
## Messages
Portal commands use translation keys for messages:
| Key | Description |
|-----|-------------|
| `server.commands.leave.notInPortal` | Not in a portal world |
| `server.commands.leave.uncursedTemp` | Items were uncursed |
| `server.commands.portals.notInPortal` | Not in portal world |
| `server.commands.voidevent.start.alreadyRunning` | Void event active |
| `server.commands.voidevent.start.success` | Void event started |
| `server.commands.fragment.timer.success` | Timer changed |

View File

@@ -0,0 +1,224 @@
---
title: Commandes Portail
type: docs
weight: 3
---
Commandes pour gerer les portails, fragments et evenements du vide.
**Package:** `com.hypixel.hytale.builtin.portals.commands`
## Commandes Joueur
### /leave
Quitter le monde portail actuel et retourner au monde d'origine.
```
/leave
```
**Comportement:**
- Fonctionne uniquement dans un monde portail
- Retire la malediction de tous les items avant de partir
- Teleporte le joueur vers l'emplacement du dispositif portail
**Implementation:**
```java
public class LeaveCommand extends AbstractPlayerCommand {
@Override
protected void execute(CommandContext context, Store<EntityStore> store,
Ref<EntityStore> ref, PlayerRef playerRef, World world) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
if (!portalWorld.exists()) {
playerRef.sendMessage(MESSAGE_NOT_IN_PORTAL);
return;
}
// Retirer malediction de tous items
CursedItems.uncurseAll(player.getInventory().getCombinedEverything());
// Sortir de l'instance
InstancesPlugin.exitInstance(ref, store);
}
}
```
## Commandes Fragment
### /fragment
Commande parente pour gestion fragments.
```
/fragment <sous-commande>
```
| Sous-commande | Description |
|---------------|-------------|
| `timer` | Modifier temps restant fragment |
### /fragment timer
Definir le temps restant pour le fragment portail actuel.
```
/fragment timer <secondes>
```
**Arguments:**
| Argument | Type | Description |
|----------|------|-------------|
| `secondes` | INTEGER | Nouveau temps restant en secondes |
**Exemple:**
```
/fragment timer 300 # Definir 5 minutes restantes
/fragment timer 60 # Definir 1 minute restante
```
**Implementation:**
```java
public class TimerFragmentCommand extends PortalWorldCommandBase {
private final RequiredArg<Integer> remainingSecondsArg;
@Override
protected void execute(CommandContext context, World world,
PortalWorld portalWorld, Store<EntityStore> store) {
int before = (int) portalWorld.getRemainingSeconds(world);
int desired = remainingSecondsArg.get(context);
portalWorld.setRemainingSeconds(world, desired);
// Rapporte: "Change de {before} a {after}"
}
}
```
## Commandes Evenement Vide
### /voidevent
Commande parente pour gestion evenement vide.
```
/voidevent <sous-commande>
```
| Sous-commande | Description |
|---------------|-------------|
| `start` | Demarrer un evenement vide |
### /voidevent start
Demarrer un evenement invasion du vide dans le monde actuel.
```
/voidevent start [--override]
```
**Flags:**
| Flag | Description |
|------|-------------|
| `--override` | Forcer demarrage meme si pas dans monde portail |
**Comportement:**
- Si deja dans monde portail avec evenement vide actif: echoue
- Si pas dans monde portail sans `--override`: echoue
- Avec `--override`: cree configuration monde portail temporaire
- Met temps restant a 1 seconde pour declencher evenement vide
**Implementation:**
```java
public class StartVoidEventCommand extends AbstractWorldCommand {
private final FlagArg overrideWorld;
@Override
protected void execute(CommandContext context, World world,
Store<EntityStore> store) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
// Verifier si deja en cours
if (portalWorld.exists() && portalWorld.isVoidEventActive()) {
context.sendMessage("Evenement vide deja en cours");
return;
}
// Si pas dans monde portail, requiert --override
if (!portalWorld.exists()) {
if (!overrideWorld.get(context)) {
context.sendMessage("Pas dans monde portail");
return;
}
// Configurer monde portail temporaire
portalWorld.init(portalType, timeLimit, removalCondition, config);
}
// Declencher evenement vide en mettant timer a 1 seconde
portalWorld.setRemainingSeconds(world, 1.0);
}
}
```
## Commandes Utilitaires
### /cursehelditem
Marquer l'item tenu comme maudit (commande debug/test).
```
/cursehelditem
```
**Comportement:**
- Ajoute marqueur malediction a l'item en main principale
- Items maudits sont perdus quand joueur meurt dans monde portail
## Classes de Base Commandes
### PortalWorldCommandBase
Classe de base pour commandes necessitant un monde portail:
```java
public abstract class PortalWorldCommandBase extends AbstractWorldCommand {
@Override
protected final void execute(CommandContext context, World world,
Store<EntityStore> store) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
if (!portalWorld.exists()) {
context.sendMessage(MESSAGE_NOT_IN_PORTAL);
return;
}
execute(context, world, portalWorld, store);
}
protected abstract void execute(CommandContext context, World world,
PortalWorld portalWorld,
Store<EntityStore> store);
}
```
## Enregistrement Commandes
Les commandes sont enregistrees dans setup PortalsPlugin:
```java
this.getCommandRegistry().registerCommand(new LeaveCommand());
this.getCommandRegistry().registerCommand(new CursedHeldItemCommand());
this.getCommandRegistry().registerCommand(new VoidEventCommands());
this.getCommandRegistry().registerCommand(new FragmentCommands());
```
## Messages
Les commandes portail utilisent des cles de traduction pour les messages:
| Cle | Description |
|-----|-------------|
| `server.commands.leave.notInPortal` | Pas dans monde portail |
| `server.commands.leave.uncursedTemp` | Items ont ete decursifies |
| `server.commands.portals.notInPortal` | Pas dans monde portail |
| `server.commands.voidevent.start.alreadyRunning` | Evenement vide actif |
| `server.commands.voidevent.start.success` | Evenement vide demarre |
| `server.commands.fragment.timer.success` | Timer modifie |

View File

@@ -0,0 +1,270 @@
---
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();
```

View File

@@ -0,0 +1,270 @@
---
title: Composants Portail
type: docs
weight: 1
---
Les composants portail definissent les structures de donnees pour les dispositifs portail, les mondes portail et les evenements du vide.
**Package:** `com.hypixel.hytale.builtin.portals.components`
## PortalDevice
Un composant au niveau chunk representant un bloc dispositif portail.
```java
public class PortalDevice implements Component<ChunkStore> {
// Configuration pour etats du portail
private PortalDeviceConfig config;
// Cle type de bloc pour le dispositif portail
private String baseBlockTypeKey;
// UUID du monde de destination (si actif)
private UUID destinationWorldUuid;
}
```
### Acceder aux Dispositifs Portail
```java
// Obtenir dispositif portail a position bloc
PortalDevice portal = BlockModule.get().getComponent(
PortalDevice.getComponentType(),
world, x, y, z
);
if (portal != null) {
// Portail existe a cet emplacement
BlockType blockType = portal.getBaseBlockType();
World destination = portal.getDestinationWorld();
}
```
### Monde de Destination
```java
// Definir destination lors activation portail
portal.setDestinationWorld(targetWorld);
// Obtenir destination (null si inactif ou monde ferme)
World destination = portal.getDestinationWorld();
if (destination == null || !destination.isAlive()) {
// Destination portail invalide
}
```
## PortalDeviceConfig
Configuration pour les etats visuels du dispositif portail.
```java
public class PortalDeviceConfig {
// Etat quand instance en creation
private String spawningState = "Spawning";
// Etat quand portail actif
private String onState = "Active";
// Etat quand portail inactif
private String offState = "default";
// Bloc place au point de spawn dans monde portail
private String returnBlock;
}
```
### Validation des Etats
```java
// Verifier que tous les etats existent sur type de bloc
PortalDeviceConfig config = portal.getConfig();
if (config.areBlockStatesValid(baseBlockType)) {
// Tous les etats (on, off, spawning) sont valides
}
```
### Noms des Etats
| Etat | Description | Defaut |
|------|-------------|--------|
| `spawningState` | Transition de eteint a actif | "Spawning" |
| `onState` | Portail actif | "Active" |
| `offState` | Portail inactif | "default" |
## PortalWorld
Une ressource attachee aux mondes crees par les portails.
```java
public class PortalWorld implements Resource<EntityStore> {
// ID configuration type portail
private String portalTypeId;
// Limite temps en secondes
private int timeLimitSeconds;
// Handler condition de suppression
private PortalRemovalCondition worldRemovalCondition;
// Joueurs morts dans ce monde
private Set<UUID> diedInWorld;
// Joueurs voyant actuellement l'UI
private Set<UUID> seesUi;
// Transform point de spawn
private Transform spawnPoint;
// Reference vers evenement vide actif
private Ref<EntityStore> voidEventRef;
}
```
### Verifier Monde Portail
```java
// Obtenir ressource monde portail
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
// Verifier si c'est un monde portail valide
if (portalWorld.exists()) {
PortalType type = portalWorld.getPortalType();
int timeLimit = portalWorld.getTimeLimitSeconds();
}
```
### Gestion du Temps
```java
// Obtenir temps ecoule et restant
double elapsed = portalWorld.getElapsedSeconds(world);
double remaining = portalWorld.getRemainingSeconds(world);
// Modifier temps restant (ex: etendre timer)
portalWorld.setRemainingSeconds(world, 300.0); // 5 minutes
```
### Suivi des Morts
```java
// Verifier si joueur mort dans ce monde
if (portalWorld.getDiedInWorld().contains(playerUuid)) {
// Ne peut pas re-entrer - mort ici
}
// Enregistrer une mort
portalWorld.getDiedInWorld().add(playerUuid);
```
### Etat UI
```java
// Suivre joueurs voyant l'UI portail
portalWorld.getSeesUi().add(playerUuid);
portalWorld.getSeesUi().remove(playerUuid);
```
## VoidEvent
Composant pour evenements invasion du vide dans mondes portail.
```java
public class VoidEvent implements Component<EntityStore> {
// Distance minimum entre spawners
public static final double MIN_BLOCKS_BETWEEN_SPAWNERS = 62.0;
// Grille spatiale des spawners du vide
private SpatialHashGrid<Ref<EntityStore>> voidSpawners;
// Etape active actuelle
private VoidEventStage activeStage;
}
```
### Acces Evenement Vide
```java
// Verifier si evenement vide actif
Ref<EntityStore> voidRef = portalWorld.getVoidEventRef();
if (portalWorld.isVoidEventActive()) {
VoidEvent voidEvent = store.getComponent(voidRef, VoidEvent.getComponentType());
VoidEventStage stage = voidEvent.getActiveStage();
}
```
### Grille Spawners Vide
```java
// Obtenir grille spawners
SpatialHashGrid<Ref<EntityStore>> spawners = voidEvent.getVoidSpawners();
// Spawners maintiennent distance minimum de 62 blocs
```
## VoidEventConfig
Configuration pour evenements du vide.
```java
public class VoidEventConfig {
// Duree evenement vide en secondes
private int durationSeconds;
// Etapes de l'evenement vide
private List<VoidEventStage> stages;
}
```
## VoidEventStage
Etape unique dans progression evenement vide.
```java
public class VoidEventStage {
// Quand cette etape demarre (secondes depuis debut evenement)
private int startTime;
// Spawners a activer
private List<VoidSpawnerConfig> spawners;
}
```
## VoidSpawner
Composant entite pour spawners invasion du vide.
```java
public class VoidSpawner implements Component<EntityStore> {
// Configuration spawner
// Suit etat de spawn actif
}
```
## Enregistrement Composants
Les composants sont enregistres dans setup PortalsPlugin:
```java
// Dans 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);
```
## Serialisation
PortalDevice utilise BuilderCodec pour persistance:
```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();
```

View File

@@ -0,0 +1,280 @@
---
title: Portal Systems
type: docs
weight: 2
---
Portal systems handle the runtime logic for portal tracking, void events, and instance management.
**Package:** `com.hypixel.hytale.builtin.portals.systems`
## Portal Tracker Systems
### TrackerSystem
Tracks players entering and leaving portal worlds:
```java
public class TrackerSystem extends RefSystem<EntityStore> {
// Called when player enters portal world
@Override
public void onEntityAdded(Ref<EntityStore> ref, AddReason reason,
Store<EntityStore> store,
CommandBuffer<EntityStore> commandBuffer) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
if (!portalWorld.exists()) return;
// Send portal UI to player
PlayerRef playerRef = commandBuffer.getComponent(ref, PlayerRef.getComponentType());
UpdatePortal packet = portalWorld.createFullPacket(world);
playerRef.getPacketHandler().write(packet);
}
// Called when player leaves portal world
@Override
public void onEntityRemove(Ref<EntityStore> ref, RemoveReason reason,
Store<EntityStore> store,
CommandBuffer<EntityStore> commandBuffer) {
// Clear UI state
playerRef.getPacketHandler().write(new UpdatePortal(null, null));
portalWorld.getSeesUi().remove(playerRef.getUuid());
}
@Override
public Query<EntityStore> getQuery() {
return Query.and(Player.getComponentType(), PlayerRef.getComponentType());
}
}
```
### UiTickingSystem
Updates portal UI every second:
```java
public class UiTickingSystem extends DelayedEntitySystem<EntityStore> {
public UiTickingSystem() {
super(1.0f); // Tick every 1 second
}
@Override
public void tick(float dt, int index, ArchetypeChunk<EntityStore> archetypeChunk,
Store<EntityStore> store, CommandBuffer<EntityStore> commandBuffer) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
if (!portalWorld.exists()) return;
// Send updated time to player
UpdatePortal packet = portalWorld.createUpdatePacket(world);
playerRef.getPacketHandler().write(packet);
}
}
```
## Portal Destination Systems
### PortalInvalidDestinationSystem
Handles portals with invalid destinations:
```java
public class PortalInvalidDestinationSystem {
// Turns off portals when destination world closes
public static void turnOffPortalsInWorld(World world, World closedWorld) {
// Find all portals pointing to closedWorld
// Set their destination to null
// Update block state to "off"
}
}
```
### CloseWorldWhenBreakingDeviceSystems
Handles portal device destruction:
```java
// When portal device component is removed
public class ComponentRemoved extends System<ChunkStore> {
// Close the destination world
}
// When portal block entity is removed
public class EntityRemoved extends System<ChunkStore> {
// Close the destination world
}
```
## Void Event Systems
### VoidEventRefSystem
Manages void event entity references:
```java
public class VoidEventRefSystem extends System<EntityStore> {
// Tracks void event entity lifecycle
// Updates PortalWorld.voidEventRef
}
```
### VoidEventStagesSystem
Progresses through void event stages:
```java
public class VoidEventStagesSystem extends System<EntityStore> {
// Checks elapsed time
// Activates next stage when time threshold reached
// Updates VoidEvent.activeStage
}
```
### VoidInvasionPortalsSpawnSystem
Spawns invasion portals during void events:
```java
public class VoidInvasionPortalsSpawnSystem extends System<EntityStore> {
// Creates void spawner entities
// Uses spatial hash grid to maintain minimum distance
}
```
### VoidSpawnerSystems.Instantiate
Instantiates void spawner entities:
```java
public class Instantiate extends System<EntityStore> {
// Creates spawner entity from config
// Adds to VoidEvent's spatial grid
}
```
### StartVoidEventInFragmentSystem
Initiates void events in portal fragments:
```java
public class StartVoidEventInFragmentSystem extends System<EntityStore> {
// Checks if void invasion should start
// Creates VoidEvent entity
// Sets up first stage
}
```
## Curse Systems
### DiedInPortalSystem
Tracks player deaths in portal worlds:
```java
public class DiedInPortalSystem extends System<EntityStore> {
// On player death in portal world:
// - Add player UUID to diedInWorld set
// - Prevents re-entry
}
```
### CurseItemDropsSystem
Marks dropped items as cursed:
```java
public class CurseItemDropsSystem extends System<EntityStore> {
// Items dropped in portal world become cursed
// Cursed items are lost on death
}
```
### DeleteCursedItemsOnSpawnSystem
Removes cursed items when player spawns:
```java
public class DeleteCursedItemsOnSpawnSystem extends System<EntityStore> {
// When player respawns after dying in portal
// Remove all cursed items from inventory
}
```
## Portal Interactions
### EnterPortalInteraction
Handles entering a portal:
```java
public class EnterPortalInteraction extends SimpleBlockInteraction {
// Minimum time before allowing portal use
public static final Duration MINIMUM_TIME_IN_WORLD = Duration.ofMillis(3000L);
@Override
protected void interactWithBlock(...) {
// Check portal device exists
// Verify destination world is alive
// Check player hasn't died in target world
// Teleport player to instance
}
}
```
Target world states:
- `OKAY` - Can enter
- `WORLD_DEAD` - Destination closed
- `DIED_IN_WORLD` - Player died there
- `NO_SPAWN_AVAILABLE` - No spawn point
### ReturnPortalInteraction
Handles returning from a portal world:
```java
public class ReturnPortalInteraction extends SimpleBlockInteraction {
// Minimum time before allowing return
public static final Duration MINIMUM_TIME_IN_WORLD = Duration.ofSeconds(15L);
// Warning shown before timer expires
public static final Duration WARNING_TIME = Duration.ofSeconds(4L);
@Override
protected void interactWithBlock(...) {
// Check minimum time elapsed
// Uncurse all items
// Exit instance
}
}
```
## System Registration
All systems are registered in PortalsPlugin setup:
```java
// ChunkStore systems
this.getChunkStoreRegistry().registerSystem(new PortalInvalidDestinationSystem());
this.getChunkStoreRegistry().registerSystem(new CloseWorldWhenBreakingDeviceSystems.ComponentRemoved());
this.getChunkStoreRegistry().registerSystem(new CloseWorldWhenBreakingDeviceSystems.EntityRemoved());
// EntityStore systems
this.getEntityStoreRegistry().registerSystem(new PortalTrackerSystems.TrackerSystem());
this.getEntityStoreRegistry().registerSystem(new PortalTrackerSystems.UiTickingSystem());
this.getEntityStoreRegistry().registerSystem(new DiedInPortalSystem());
this.getEntityStoreRegistry().registerSystem(new CurseItemDropsSystem());
this.getEntityStoreRegistry().registerSystem(new DeleteCursedItemsOnSpawnSystem());
this.getEntityStoreRegistry().registerSystem(new VoidEventRefSystem());
this.getEntityStoreRegistry().registerSystem(new VoidInvasionPortalsSpawnSystem());
this.getEntityStoreRegistry().registerSystem(new VoidSpawnerSystems.Instantiate());
this.getEntityStoreRegistry().registerSystem(new StartVoidEventInFragmentSystem());
this.getEntityStoreRegistry().registerSystem(new VoidEventStagesSystem());
```
## Interaction Registration
Portal interactions are registered as codec types:
```java
this.getCodecRegistry(Interaction.CODEC)
.register("Portal", EnterPortalInteraction.class, EnterPortalInteraction.CODEC)
.register("PortalReturn", ReturnPortalInteraction.class, ReturnPortalInteraction.CODEC);
```

View File

@@ -0,0 +1,280 @@
---
title: Systemes Portail
type: docs
weight: 2
---
Les systemes portail gerent la logique d'execution pour le suivi des portails, les evenements du vide et la gestion des instances.
**Package:** `com.hypixel.hytale.builtin.portals.systems`
## Systemes de Suivi Portail
### TrackerSystem
Suit les joueurs entrant et sortant des mondes portail:
```java
public class TrackerSystem extends RefSystem<EntityStore> {
// Appele quand joueur entre dans monde portail
@Override
public void onEntityAdded(Ref<EntityStore> ref, AddReason reason,
Store<EntityStore> store,
CommandBuffer<EntityStore> commandBuffer) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
if (!portalWorld.exists()) return;
// Envoyer UI portail au joueur
PlayerRef playerRef = commandBuffer.getComponent(ref, PlayerRef.getComponentType());
UpdatePortal packet = portalWorld.createFullPacket(world);
playerRef.getPacketHandler().write(packet);
}
// Appele quand joueur quitte monde portail
@Override
public void onEntityRemove(Ref<EntityStore> ref, RemoveReason reason,
Store<EntityStore> store,
CommandBuffer<EntityStore> commandBuffer) {
// Effacer etat UI
playerRef.getPacketHandler().write(new UpdatePortal(null, null));
portalWorld.getSeesUi().remove(playerRef.getUuid());
}
@Override
public Query<EntityStore> getQuery() {
return Query.and(Player.getComponentType(), PlayerRef.getComponentType());
}
}
```
### UiTickingSystem
Met a jour l'UI portail chaque seconde:
```java
public class UiTickingSystem extends DelayedEntitySystem<EntityStore> {
public UiTickingSystem() {
super(1.0f); // Tick chaque 1 seconde
}
@Override
public void tick(float dt, int index, ArchetypeChunk<EntityStore> archetypeChunk,
Store<EntityStore> store, CommandBuffer<EntityStore> commandBuffer) {
PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType());
if (!portalWorld.exists()) return;
// Envoyer temps mis a jour au joueur
UpdatePortal packet = portalWorld.createUpdatePacket(world);
playerRef.getPacketHandler().write(packet);
}
}
```
## Systemes Destination Portail
### PortalInvalidDestinationSystem
Gere les portails avec destinations invalides:
```java
public class PortalInvalidDestinationSystem {
// Eteint portails quand monde destination ferme
public static void turnOffPortalsInWorld(World world, World closedWorld) {
// Trouver tous portails pointant vers closedWorld
// Mettre leur destination a null
// Mettre a jour etat bloc a "off"
}
}
```
### CloseWorldWhenBreakingDeviceSystems
Gere la destruction du dispositif portail:
```java
// Quand composant dispositif portail supprime
public class ComponentRemoved extends System<ChunkStore> {
// Fermer le monde de destination
}
// Quand entite bloc portail supprimee
public class EntityRemoved extends System<ChunkStore> {
// Fermer le monde de destination
}
```
## Systemes Evenement Vide
### VoidEventRefSystem
Gere les references entites evenement vide:
```java
public class VoidEventRefSystem extends System<EntityStore> {
// Suit cycle de vie entite evenement vide
// Met a jour PortalWorld.voidEventRef
}
```
### VoidEventStagesSystem
Progresse a travers les etapes evenement vide:
```java
public class VoidEventStagesSystem extends System<EntityStore> {
// Verifie temps ecoule
// Active etape suivante quand seuil temps atteint
// Met a jour VoidEvent.activeStage
}
```
### VoidInvasionPortalsSpawnSystem
Fait apparaitre portails invasion pendant evenements vide:
```java
public class VoidInvasionPortalsSpawnSystem extends System<EntityStore> {
// Cree entites spawner vide
// Utilise grille hash spatiale pour maintenir distance minimum
}
```
### VoidSpawnerSystems.Instantiate
Instancie entites spawner vide:
```java
public class Instantiate extends System<EntityStore> {
// Cree entite spawner depuis config
// Ajoute a grille spatiale VoidEvent
}
```
### StartVoidEventInFragmentSystem
Initie evenements vide dans fragments portail:
```java
public class StartVoidEventInFragmentSystem extends System<EntityStore> {
// Verifie si invasion vide devrait demarrer
// Cree entite VoidEvent
// Configure premiere etape
}
```
## Systemes Malediction
### DiedInPortalSystem
Suit les morts joueurs dans mondes portail:
```java
public class DiedInPortalSystem extends System<EntityStore> {
// A la mort joueur dans monde portail:
// - Ajouter UUID joueur a set diedInWorld
// - Empeche re-entree
}
```
### CurseItemDropsSystem
Marque items laches comme maudits:
```java
public class CurseItemDropsSystem extends System<EntityStore> {
// Items laches dans monde portail deviennent maudits
// Items maudits sont perdus a la mort
}
```
### DeleteCursedItemsOnSpawnSystem
Supprime items maudits quand joueur spawn:
```java
public class DeleteCursedItemsOnSpawnSystem extends System<EntityStore> {
// Quand joueur reapparait apres mort dans portail
// Supprimer tous items maudits de l'inventaire
}
```
## Interactions Portail
### EnterPortalInteraction
Gere l'entree dans un portail:
```java
public class EnterPortalInteraction extends SimpleBlockInteraction {
// Temps minimum avant autoriser utilisation portail
public static final Duration MINIMUM_TIME_IN_WORLD = Duration.ofMillis(3000L);
@Override
protected void interactWithBlock(...) {
// Verifier dispositif portail existe
// Verifier monde destination vivant
// Verifier joueur pas mort dans monde cible
// Teleporter joueur vers instance
}
}
```
Etats monde cible:
- `OKAY` - Peut entrer
- `WORLD_DEAD` - Destination fermee
- `DIED_IN_WORLD` - Joueur mort la-bas
- `NO_SPAWN_AVAILABLE` - Pas de point de spawn
### ReturnPortalInteraction
Gere le retour d'un monde portail:
```java
public class ReturnPortalInteraction extends SimpleBlockInteraction {
// Temps minimum avant autoriser retour
public static final Duration MINIMUM_TIME_IN_WORLD = Duration.ofSeconds(15L);
// Avertissement affiche avant expiration timer
public static final Duration WARNING_TIME = Duration.ofSeconds(4L);
@Override
protected void interactWithBlock(...) {
// Verifier temps minimum ecoule
// Retirer malediction tous items
// Sortir instance
}
}
```
## Enregistrement Systemes
Tous les systemes sont enregistres dans setup PortalsPlugin:
```java
// Systemes ChunkStore
this.getChunkStoreRegistry().registerSystem(new PortalInvalidDestinationSystem());
this.getChunkStoreRegistry().registerSystem(new CloseWorldWhenBreakingDeviceSystems.ComponentRemoved());
this.getChunkStoreRegistry().registerSystem(new CloseWorldWhenBreakingDeviceSystems.EntityRemoved());
// Systemes EntityStore
this.getEntityStoreRegistry().registerSystem(new PortalTrackerSystems.TrackerSystem());
this.getEntityStoreRegistry().registerSystem(new PortalTrackerSystems.UiTickingSystem());
this.getEntityStoreRegistry().registerSystem(new DiedInPortalSystem());
this.getEntityStoreRegistry().registerSystem(new CurseItemDropsSystem());
this.getEntityStoreRegistry().registerSystem(new DeleteCursedItemsOnSpawnSystem());
this.getEntityStoreRegistry().registerSystem(new VoidEventRefSystem());
this.getEntityStoreRegistry().registerSystem(new VoidInvasionPortalsSpawnSystem());
this.getEntityStoreRegistry().registerSystem(new VoidSpawnerSystems.Instantiate());
this.getEntityStoreRegistry().registerSystem(new StartVoidEventInFragmentSystem());
this.getEntityStoreRegistry().registerSystem(new VoidEventStagesSystem());
```
## Enregistrement Interactions
Les interactions portail sont enregistrees comme types codec:
```java
this.getCodecRegistry(Interaction.CODEC)
.register("Portal", EnterPortalInteraction.class, EnterPortalInteraction.CODEC)
.register("PortalReturn", ReturnPortalInteraction.class, ReturnPortalInteraction.CODEC);
```