--- 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 { // Called when player enters portal world @Override public void onEntityAdded(Ref ref, AddReason reason, Store store, CommandBuffer 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 ref, RemoveReason reason, Store store, CommandBuffer commandBuffer) { // Clear UI state playerRef.getPacketHandler().write(new UpdatePortal(null, null)); portalWorld.getSeesUi().remove(playerRef.getUuid()); } @Override public Query getQuery() { return Query.and(Player.getComponentType(), PlayerRef.getComponentType()); } } ``` ### UiTickingSystem Updates portal UI every second: ```java public class UiTickingSystem extends DelayedEntitySystem { public UiTickingSystem() { super(1.0f); // Tick every 1 second } @Override public void tick(float dt, int index, ArchetypeChunk archetypeChunk, Store store, CommandBuffer 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 { // Close the destination world } // When portal block entity is removed public class EntityRemoved extends System { // Close the destination world } ``` ## Void Event Systems ### VoidEventRefSystem Manages void event entity references: ```java public class VoidEventRefSystem extends System { // Tracks void event entity lifecycle // Updates PortalWorld.voidEventRef } ``` ### VoidEventStagesSystem Progresses through void event stages: ```java public class VoidEventStagesSystem extends System { // 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 { // Creates void spawner entities // Uses spatial hash grid to maintain minimum distance } ``` ### VoidSpawnerSystems.Instantiate Instantiates void spawner entities: ```java public class Instantiate extends System { // Creates spawner entity from config // Adds to VoidEvent's spatial grid } ``` ### StartVoidEventInFragmentSystem Initiates void events in portal fragments: ```java public class StartVoidEventInFragmentSystem extends System { // 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 { // 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 { // 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 { // 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); ```