Fluid System
Scope note: This page only describes behavior that is visible in the decompiled server code.
Where fluids live
Section titled “Where fluids live”Fluids are stored per chunk section in the FluidSection component:
com.hypixel.hytale.server.core.universe.world.chunk.section.FluidSection- Stores a per-block fluid id using an
ISectionPalette(typePalette). - Stores a per-block fluid level as a packed nibble array
levelData(size16384, two 4-bit levels per byte). - Uses a
StampedLockfor concurrent access. - Tracks changed block indices in
changedPositionsfor replication.
- Stores a per-block fluid id using an
Fluid id vs. level
Section titled “Fluid id vs. level”FluidSection.setFluid(int index, int fluidId, byte level) applies these rules:
levelis masked to 4 bits:level & 0xF.- If
level == 0, the fluid id is forced to0. - If
fluidId == 0, the level is forced to0.
This means the “empty” state is always (fluidId=0, level=0).
Builtin fluid plugin and systems
Section titled “Builtin fluid plugin and systems”The builtin plugin com.hypixel.hytale.builtin.fluid.FluidPlugin wires the system together by registering:
FluidSystems.EnsureFluidSection— adds aFluidSectionto section entities missing it.FluidSystems.MigrateFromColumn— migrates legacy per-section fluid data fromBlockSection.takeMigratedFluid().FluidSystems.SetupSection— callsfluidSection.load(x, y, z)when the section entity is added.FluidSystems.LoadPacketGenerator— contributes per-section fluid packets to the “chunk load” packet batch.FluidSystems.ReplicateChanges— sends incremental (or full) updates to players.FluidSystems.Ticking— runs fluid tick logic on blocks that are marked ticking.
Ticking and flow
Section titled “Ticking and flow”What drives fluid ticking
Section titled “What drives fluid ticking”FluidSystems.Ticking runs on chunk-store section entities that have FluidSection and ChunkSection.
It:
- Resolves the owning
BlockChunkfrom the section’s chunk-column reference. - Gets the matching
BlockSectionatfluidSection.getY(). - Early-outs if there are no ticking blocks (
blockSection.getTickingBlocksCountCopy() == 0). - Iterates
blockSection.forEachTicking(...)and, per ticking block:- Reads
fluidId = fluidSection.getFluidId(x, y, z). - If
fluidId == 0, returnsBlockTickStrategy.IGNORED. - Looks up the fluid type:
Fluid.getAssetMap().getAsset(fluidId). - Calls
fluid.getTicker().tick(...).
- Reads
So: fluid simulation is tied to the block ticking bitset in BlockSection.
FluidTicker basics
Section titled “FluidTicker basics”com.hypixel.hytale.server.core.asset.type.fluid.FluidTicker is the abstract base for per-fluid behavior.
Key pieces:
FlowRate(seconds): controls how oftentick(...)runs (it converts to ticks usingworld.getTps()).CanDemote: if true, a fluid may “demote” (reduce level / disappear) when unsupported.SupportedBy: a fluid id key that is treated as “self/support” inisSelfFluid(...).
FluidTicker.process(...) contains shared logic:
- If the current block is “fully solid” (
isFullySolid(BlockType)), the fluid is cleared. - It evaluates
isAlive(...)and either:- spreads (calls the fluid-specific
spread(...)), - demotes (decrements level / clears),
- or waits for adjacent chunk load.
- spreads (calls the fluid-specific
The shape-based blocking tests (blocksFluidFrom(...)) use block hitbox data via BlockBoundingBoxes.
Replication (network updates)
Section titled “Replication (network updates)”FluidSystems.ReplicateChanges sends updates based on fluidSection.getAndClearChangedPositions():
- 1 change: sends
ServerSetFluid(x, y, z, fluidId, level). - 2..1023 changes: sends
ServerSetFluids(sectionX, sectionY, sectionZ, SetFluidCmd[])with indices and values. - >= 1024 changes: sends a cached full-section packet from
fluidSection.getCachedPacket()(built fromSetFluids).
Updates are only sent to players whose ChunkTracker reports the chunk as loaded.
Lighting invalidation on fluid changes
Section titled “Lighting invalidation on fluid changes”On any non-empty change set, ReplicateChanges also schedules:
world.getChunkLighting().invalidateLightInChunkSection(worldChunk, sectionY)
This means fluid edits can force lighting recomputation for the affected section.
Fluid assets and fluid FX
Section titled “Fluid assets and fluid FX”Fluid asset
Section titled “Fluid asset”com.hypixel.hytale.server.core.asset.type.fluid.Fluid is the asset that defines a fluid type.
Fields surfaced by the asset codec include (non-exhaustive):
MaxFluidLevel(default8)Textures(array ofBlockTypeTextures)Effect(array ofShaderType)Opacity/RequiresAlphaBlendingFluidFXId→ resolved tofluidFXIndexviaFluidFX.getAssetMap().getIndex(...)Ticker(FluidTicker)Light(ColorLight) — used by lighting when seeding local lightDamageToEntitiesBlockParticleSetId,ParticleColor,BlockSoundSetIdInteractions(map keyed byInteractionType)
FluidFX asset
Section titled “FluidFX asset”com.hypixel.hytale.server.core.asset.type.fluidfx.config.FluidFX is a separate asset referenced by Fluid.FluidFXId.
It serializes to a protocol FluidFX packet including:
- fog mode/color/distance
- saturation & color filter
- distortion amplitude/frequency
- optional
FluidParticle - optional
FluidFXMovementSettings
FluidParticle itself contains:
SystemId(particle system id)Color(default color override)Scale(defaults to1.0)
Asset replication (types + FX)
Section titled “Asset replication (types + FX)”In addition to per-block fluid state replication, fluid-related assets are also synchronized to clients via dedicated asset packets:
FluidTypePacketGenerator→UpdateFluids(Init / AddOrUpdate / Remove)FluidFXPacketGenerator→UpdateFluidFX(Init / AddOrUpdate / Remove)
Both packet types include a maxId taken from the indexed lookup table’s getNextIndex().
Practical mod patterns (code-backed)
Section titled “Practical mod patterns (code-backed)”Setting a fluid in the world
Section titled “Setting a fluid in the world”The builtin fluid set command demonstrates the minimal pattern:
- Resolve the chunk section reference asynchronously:
world.getChunkStore().getChunkSectionReferenceAsync(cx, cy, cz). - Get
FluidSectionfrom the section store. - Call
fluidSection.setFluid(index, fluid, level). - Mark the owning
WorldChunkdirty (worldChunk.markNeedsSaving()). - Ensure simulation runs by setting ticking (
worldChunk.setTicking(x, y, z, true)).
See com.hypixel.hytale.builtin.fluid.FluidCommand.SetCommand.
Related classes
Section titled “Related classes”com.hypixel.hytale.builtin.fluid.FluidState(pre-generated level/fill states)com.hypixel.hytale.server.core.universe.world.chunk.section.FluidSectioncom.hypixel.hytale.server.core.asset.type.fluid.Fluidcom.hypixel.hytale.server.core.asset.type.fluid.FluidTickercom.hypixel.hytale.builtin.fluid.FluidSystems- Packets:
SetFluids,ServerSetFluid,ServerSetFluids,SetFluidCmd