PerfectPortals
Two plugins in one: colored portal pads with warp system and server transfer, plus a server hub with live selector UI, per-backend queue, and pre-connect fallback. All driven by one JAR.
| Version | 2.4 (Hub Update) |
|---|---|
| Platform | Hytale Server Plugin |
| Java | 21 |
| Dependencies | None |
Installation
v2.4 hub mode runs on every instance in your network. Install the JAR on the hub AND each backend you want to list. This is a change from v2.3.
- Download
PerfectPortals-2.4.jar - Place it in
UserData/Mods/on every server (hub + backends) - Start each server once so
proxy.jsonauto-generates atUserData/Saves/MODDING/mods/KatsuyaTV_PerfectPortals/proxy.json - Edit the hub's
proxy.jsonto list every backend (see Hub Config below) - Open
statusHttpPort(default 5540) between the hub and each backend in your firewall - Restart or run
/pportals reload
Portal Types
6 colors x 2 styles = 12 unique portals. Each has its own texture, particles, and icon.
Light Variants (colored glow)
| Portal | Color | Light |
|---|---|---|
| Portal_Red | Red | Red glow (2 block radius) |
| Portal_Green | Green | Green glow |
| Portal_Purple | Purple | Purple glow |
| Portal_Orange | Orange | Orange glow |
| Portal_Pink | Pink | Pink glow |
| Portal_Yellow | Yellow | Yellow glow |
Dark Variants (no light)
Same textures and particles, no light emission: Portal_Red_Dark, Portal_Green_Dark, Portal_Purple_Dark, Portal_Orange_Dark, Portal_Pink_Dark, Portal_Yellow_Dark
Warp System
Link any two portals together for instant bidirectional teleportation.
- Place two portals anywhere in the world
- Open
/pportals— the admin UI shows all placed portals - Click portal A in the list, then portal B
- Click "Link A - B"
- Walk up to either portal and press [F] to teleport
Links are bidirectional. Breaking a linked portal auto-cleans the link.
Server Selector UI (new in v2.4)
Command: /pportals servers (permission perfectportals.servers).
Opens a browsable list of your configured backends. Each row shows:
- Display name (from
proxy.json) - Live online/offline state (queried via HTTP every
pollIntervalMs) - Current player count and max (if
maxPlayersis set) - A JOIN button that transfers the player using
referToServer
When a backend is full (count >= maxPlayers), the player is queued on the origin server. Chat shows their position every 5 sec. When a slot frees up, they are auto-transferred.
When a backend is offline and fallbackHub is set, the player is redirected to the fallback instead of failing.
Hub Config (v2.4)
Edit UserData/Saves/MODDING/mods/KatsuyaTV_PerfectPortals/proxy.json:
{
"enabled": true,
"fallbackHub": "lobby",
"statusHttpPort": 5540,
"statusToken": "your-shared-secret",
"pollIntervalMs": 5000,
"httpTimeoutMs": 2000,
"backends": {
"lobby": {
"host": "hub.yourdomain.com",
"port": 5520,
"statusPort": 5540,
"displayName": "Main Hub",
"maxPlayers": 0,
"hidden": false
},
"survival": {
"host": "survival.yourdomain.com",
"port": 5520,
"statusPort": 5540,
"displayName": "Survival",
"maxPlayers": 30,
"hidden": false
}
}
}
Root fields
enabled— start the hub services on this instancefallbackHub— backend name used when a selected backend is offlinestatusHttpPort— port this server exposes for the/statusendpointstatusToken— shared secret across all instances. Keep it privatepollIntervalMs— how often the hub polls backends (default 5000)httpTimeoutMs— per-request timeout for HTTP polling
Per-backend fields
host/port— address the player's client connects to. Must be public and reachable from the client, not just the hubstatusPort— HTTP/statusport on that backenddisplayName— shown in the selector UImaxPlayers— 0 disables the queue for that backendhidden— hide from the selector UI
Architecture
+----------+ HTTP /status +-----------+
| Hub |-------------------->| Backend |
| (5520) |<--------------------| (5520) |
+----+-----+ {online, players} +-----------+
|
| referToServer(backendHost, 5520) (direct, no proxy)
v
Client
Server Transfer (portal)
A portal pad can be configured to transfer players to another Hytale server (outside the selector UI).
- Open
/pportals, select a portal - Go to Server tab
- Set Label to a backend name in
proxy.json(e.g.survival) - Set Countdown if you want a delay
- Walk into / interact with the portal to get transferred (with queue + fallback if applicable)
If the label does not match a backend in proxy.json, the fields Host/Port in the portal config are used directly (raw referToServer without queue or fallback).
Commands
| Command | Permission | Description |
|---|---|---|
/pportals servers | perfectportals.servers | Open the server selector UI |
/pportals or /pportals menu | perfectportals.admin | Open the admin portal UI |
/pportals list | perfectportals.admin | List all portals in chat |
/pportals reload | perfectportals.admin | Reload portals + proxy.json |
/pportals help | - | Show help |
Limitations
- Mid-session fallback is not supported. If a backend crashes while a player is already in-world, the client will disconnect and needs to reconnect manually. Hytale's current plugin API has no packet to tell the client to reconnect elsewhere from a dying server. This will ship the day Hypixel adds it.
- Internal IP masking is not provided. Clients connect directly to each backend's public address. If you need this, a UDP/QUIC reverse proxy would be required (out of scope for the plugin).
- TLS on the status endpoint is not provided. Keep
statusHttpPorton a trusted network or firewall it to the hub's IP.
FAQ
Do backend servers need PerfectPortals?
Yes, in v2.4. Each backend runs PerfectPortals to expose its /status HTTP endpoint so the hub can query its state. This changed from v2.3 (which had a TCP proxy that never actually worked with Hytale's QUIC/UDP traffic).
Why not a TCP proxy like v2.3?
Hytale uses QUIC over UDP for all gameplay traffic. A TCP proxy cannot forward QUIC. The v2.3 "built-in reverse proxy" was non-functional in practice. v2.4 uses direct referToServer with an HTTP sidecar for status data, which is a clean, working architecture.
What does the status endpoint return?
GET /status?token=YOUR_TOKEN returns {"online":true,"players":N,"version":"2.4"}. Request without a token or with the wrong one returns 403.
Can I use portals for same-server teleportation AND server transfer?
Yes. Portals without a server label act as local warps. Portals with a server label matching a backend in proxy.json route through the hub (with queue/fallback). Portals with a server label that doesn't match trigger a raw transfer.
The UI shows a backend as OFFLINE but the backend is running.
The /status HTTP call is failing. Check: (1) statusHttpPort is reachable from the hub, (2) statusToken matches on both ends, (3) no firewall is blocking.
JOIN gives "connection aborted" / "failed to connect".
The host in the backend config must be reachable from the client's machine, not just the hub. Use a public hostname or IP, never 127.0.0.1 / localhost.
How to upgrade from v2.3?
Replace the JAR on every server, edit each proxy.json to the new schema (the old listenPort/target fields are gone), open the statusHttpPort in your firewall, restart.