Server documentation
QuantumHy
ActiveHytale • Version 0.4.0
Install, config keys, adaptive chunk and entity radius, expand freeze, pressure governor, and LeanCore coexistence for QuantumHy on Hytale 0.7.
Install, configuration, and runtime behavior for QuantumHy.
Overview
QuantumHy is a server-side FPS mod for Hytale 0.7. The client is native and cannot be modded, but the server decides how much each client has to render, so QuantumHy trims that on a per-player basis. Every few seconds it samples entity density around each player, smooths it, and uses it to shrink the client chunk view radius and per-player entity stream radius. Each player can persistently opt in or out without changing anyone else.
It never inflates a view past what the player asked for. Radius does not snap back the moment density looks open: expand is frozen until load is calm, the density disk is at least half loaded, the player is not flying, and the world is not MSPT-pressured. It helps only where it is installed, never on a remote server you merely join.
Installation
- Download QuantumHy-0.4.0.jar from the CurseForge Files tab
- Place the JAR in your server’s mods/ folder, or on Windows:
%AppData%\Hytale\UserData\Mods - Start the server. Config is generated as QuantumHy.json in the plugin data folder
- Watch the server log for the setup line (see Verifying it works)
Commands
/q status
/q optimize on
/q optimize off
/q help
Aliases: /quantumhy, /qhy. A player sees only their own mode and last decision in /q status. Admins and console see full server diagnostics. /q optimize on|off changes only the player who runs it and stores that preference by UUID.
How it works
Every pass (default 5s) QuantumHy does the per-player work on the owning world’s thread:
- Sample density (sometimes skipped). It counts entities in a disk of
densityScanChunkRadiuschunks (dx²+dz² ≤ r²). The 49-column walk is skipped on the first pass, while flying (2+ chunks/pass), while streaming, on a fresh same-chunk cache hit, and while already at the minimum with expand frozen. A stationary player’s cache expires after 15 seconds. - Smooth it. A valid sample goes through an exponential moving average (
densitySmoothing). - Turn it into a shrink factor. Density uses a smoothstep between
densityLowPerChunkanddensityHighPerChunk. That is combined with chunk-load shrink (loaded + loading sections) and a baseline floor. The combined factor only increases shrink until expand is allowed (ratchet). - Ramp two levers. Chunk view moves at most +1 / −2 per pass (−4 under pressure). Entity stream radius uses the same factor; at full shrink (
[min]) it snaps tominEntityViewBlocksin one write. Writes stop afterworldPassBudgetMsor while streaming.
Expand is allowed only after expandHysteresisPasses calm load passes, a density disk that is at least 50% loaded, no streaming, no fast travel, and no MSPT pressure.
entityLodAggressiveness is separate and global. The default 1.0 leaves engine LOD unchanged. Values above 1.0 are an explicit admin override, and only then can MSPT pressure apply pressureLodMultiplier.
Configuration
Runtime files: QuantumHy.json and PlayerPreferences.json in the plugin data folder, created on first run. New installs get configVersion 8.
| Key | Default | What it does |
|---|---|---|
enabled | true | Master switch. When false, QuantumHy never touches any view radius. |
verboseLog | false | Log every pass with each player’s density and view decision. Off on new installs. |
checkForUpdates | true | On startup, check the QuantumHy page and notify operators or durkz.quantumhy.admin if a newer JAR is listed. |
tickIntervalSeconds | 5 | How often it re-checks each player. |
initialDelaySeconds | 20 | Wait this long after start before the first pass. |
targetClientViewRadius | 0 | Hard cap in chunks. 0 means no cap, just adapt to density. |
minClientViewRadius | 6 | Never pull anyone below this chunk radius. |
maxClientViewRadius | 32 | Ceiling for the hard cap (the player’s own view radius still wins). |
adaptiveTerrainViewEnabled | true | Adapt terrain view radius during normal play. |
emergencyTerrainTrimEnabled | true | Allow temporary terrain trim after sustained visual pressure. |
clientRenderCapEnabled | true | Cap the client’s draw distance and fog to the trimmed radius. Restart required. |
clientStrainEnabled | true | Ease the radius and chunk rate for a client that falls behind. Restart required. |
clientStrainFrameLagLowMs | 25 | Client main-loop lag (ms) where strain starts counting (about 40 FPS). |
clientStrainFrameLagHighMs | 60 | Lag treated as fully strained (about 16 FPS). |
clientStrainQueueLow | 64 | Client packet queue where strain starts counting. |
clientStrainQueueHigh | 512 | Packet queue treated as fully strained. |
effectBudgetEnabled | true | Budget far particles and 3D sounds per player. Restart required. |
effectBudgetPerSecond | 120 | Far effects each player may receive per second. |
effectProtectRadius | 16 | Effects within this many blocks are never dropped. |
effectSoftRadius | 48 | Once half the budget is spent, effects beyond this are dropped first. |
effectMaxDistance | 0 | Hard cut-off in blocks for positional effects. 0 = budget only. |
distantUpdateThrottleEnabled | false | Send position updates for far entities less often. The latest position always arrives. Restart required. |
distantUpdateNearBlocks | 32 | Entities closer than this get every update. |
distantUpdateFarBlocks | 64 | Entities beyond this get every 4th update. |
densityScanChunkRadius | 4 | How many chunks each way to count entities in. |
densityLowPerChunk | 1.0 | Weighted entities per chunk at or below this: no density shrink. |
densityHighPerChunk | 4.0 | Weighted entities per chunk at or above this: pulled to the minimum. |
densityRingWeighting | true | Count center chunks fully, outer scan rings less. |
densityRingEdgeWeight | 0.55 | Ring weight at the scan edge (1.0 = flat count). |
baselineShrinkFraction | 0.10 | Minimum shrink even in “open” density (0 = off). |
chunkLoadShrinkEnabled | true | Extra shrink from loaded + streaming section count. |
chunkLoadLowChunks | 2800 | Loaded + loading sections at or below this: no chunk-load shrink. Also where the view settles when calm (about view 10 on 0.7). |
chunkLoadHighChunks | 5900 | At or above this section count: chunk-load shrink hits full strength (about view 14). |
densitySmoothing | 0.4 | Weight of the newest sample in the EMA, in (0, 1]. 1.0 is off. |
adaptEntityRadius | true | Also shrink the per-player entity stream radius, not just chunks. |
minEntityViewBlocks | 48 | Lower bound for the entity radius, in blocks (16 blocks = 1 chunk). |
entityLodAggressiveness | 1.0 | Explicit global entity LOD override. 1.0 keeps the engine default. |
maxEntityVerticalDistance | 32 | Drop entities too far above/below the player. 0 = off. |
maxVisibleEntitiesPerPlayer | 80 | Cap streamed entities per player in crowds. 0 = off. |
holdSpawnOnLoadingChunks | false | Pause environmental spawning during a heavy section-stream backlog. Global admin control. |
minViewRadiusDelta | 2 | Minimum change (chunks) before an update is sent. Ramped +1 expands still apply. |
maxExpandChunksPerPass | 1 | Max chunks the client view radius may increase in one pass. |
maxShrinkChunksPerPass | 2 | Max chunks it may decrease in one pass (doubled under pressure). |
maxExpandEntityBlocksPerPass | 16 | Max entity-stream blocks the radius may increase in one pass. |
expandHysteresisPasses | 2 | Calm passes required before an expand is allowed. |
worldPassBudgetMs | 8 | Wall-clock budget for radius writes on the world thread. 0 disables. |
pressureExitRequiresLastTick | true | Pressure exits only when both the 10s MSPT average and the last tick are calm. |
respectStreamingGrace | true | Hold cuts while a player is still streaming sections. |
streamingBacklogThreshold | 80 | How many loading sections counts as “still streaming”. |
smoothChunkStreaming | true | Cap how fast sections stream to each managed client. |
maxChunksPerSecond | 128 | Cap on sections streamed per second. 0 keeps the engine default. |
maxChunksPerTick | 8 | Cap on sections streamed per tick (engine default is 40 on 0.6). |
streamCatchUpEnabled | true | Temporarily raise managed caps after fast travel while MSPT is healthy. |
streamCatchUpIntervalMs | 250 | Interval for the lightweight stream controller. |
streamCatchUpPerSecond | 256 | Healthy catch-up cap in sections per second. |
streamCatchUpPerTick | 12 | Healthy catch-up cap in sections per tick. |
streamCatchUpHoldMs | 1500 | Minimum catch-up hold after fast movement. |
leanCoreTakeover | true | If LeanCore is installed, take the view radius over from it. |
yieldToLeanCoreViewRadius | false | Leave the client view radius entirely to LeanCore. |
pressureGovernorEnabled | true | Tighten render levers when world MSPT stays high. |
pressureMsptEnter | 48 | 10s average MSPT at or above this enters pressure mode. |
pressureMsptExit | 43 | MSPT at or below this exits pressure mode. |
pressureSustainSeconds | 4 | How long MSPT must stay high before levers tighten. |
pressureCooldownSeconds | 15 | How long MSPT must stay low before levers restore. |
pressureDensityMultiplier | 1.45 | Under pressure, density thresholds tighten by this factor. |
pressureChunkRateMultiplier | 0.75 | Under pressure, multiply chunk streaming caps. |
pressureLodMultiplier | 1.15 | Pressure multiplier used only with explicit global LOD above 1.0. |
pressureVerticalTrimBlocks | 8 | Under pressure, subtract from maxEntityVerticalDistance. |
pressureWorldLevers | false | Under pressure, pause NPC spawn and block tick (restored on release). |
pressureTrimClientEffects | false | Under pressure, trim bloom/sunshaft (deferred if last tick is a hitch). |
pressureEffectScale | 0.5 | Multiplier for client effect intensities while trimmed. |
pressureItemMerge | false | Under pressure, merge dropped items from farther away so piles collapse into fewer entities. Restart required. |
pressureItemMergeRadius | 4.0 | Merge radius in blocks while that is active (engine default is 2). |
leanCoreMemoryAware | true | With LeanCore, tighten the radius while its heap tier is TIGHT or CRITICAL. Read-only. |
Permissions
| Permission | Who |
|---|---|
durkz.quantumhy.admin | In-game update notices and full /q status. Server operators inherit this through *. |
Running it with LeanCore
QuantumHy and LeanCore can both write the client view radius, and only one should. By default QuantumHy takes it: on startup it detects LeanCore and turns off LeanCore’s view-radius governance (viewRadiusGovernanceEnabled, liteViewRadiusEnabled, motionViewRadiusBoostEnabled), then drives the view radius itself. LeanCore keeps simulation radius, chunk throughput, and memory. No config change is needed on either side. LeanCore is an optional dependency: when it is absent, QuantumHy just runs standalone.
leanCoreTakeover: falseleaves LeanCore alone. Both may then fight over the view radius.yieldToLeanCoreViewRadius: truemakes QuantumHy stay out of the client view radius entirely and lets LeanCore keep it.
Recommended
- Solo or your own server: leave the defaults. You only lose view distance when it is actually crowded or the world is hitching.
- Want FPS everywhere: set
targetClientViewRadiusto 12 to 16 to cap view distance even in the open. - Mob farms / heavy events: keep
adaptEntityRadius: true; this is what holds frames when hundreds of entities are on screen. - Personal choice: use
/q optimize offto restore and stop all player-targeted levers for yourself. Use/q optimize onto re-enable them. - Turn
verboseLogon only while diagnosing; it is off by default. - Leave
checkForUpdateson unless you do not want operators to see a newer-JAR notice.
Verifying it works
- Start the server and look for the setup line:
QuantumHy 0.4.0 setup. config: verboseLog=false tickInterval=5s ... densityLow=1.0/ch densityHigh=4.0/ch baseline=10% ... entityLod=1.00x ... expand=1 shrink=2 ... budget=8ms - Then the runtime start line:
QuantumHy runtime started (interval=5s, hardCap=0, min=6, max=32, scan=4, entityRadius=true). - If LeanCore is present:
LeanCore detected: took over the client view radius (governance turned off).Otherwise:LeanCore not detected after 3 checks: QuantumHy owns the client view radius standalone. - With
verboseLog=true, each pass logs one line per player. Reading it:Durkz_z 32/49ch 0.7/ch~0.5 cl 6=6 ent 48=48 [hold]means 32 entities across 49 chunks, chunk view held at 6, entity radius at 48 blocks, expand frozen (hold). Other common reasons:[min],[pressure],[baseline],[chunk-load],[density]. - Radius does not bounce 6→13 in one pass. While pressured or flying you should see
[pressure]or[hold], not6->7 [baseline].
License
MIT License