| name | hytale-world-gen |
| description | Documents Hytale's procedural world generation systems for plugin development. Covers the Java API (Zones, Biomes, Caves) and the data-driven node/JSON system (Density, Curves, Patterns, Material Providers, Props, Scanners, Positions, Assignments, Vector Providers, Block Masks). Use when creating custom zones, biomes, caves, terrain, world generation features, density fields, asset packs, or working with the Hytale Node Editor. Triggers - world gen, world generation, zone, biome, cave, ZonePatternGenerator, BiomePatternGenerator, CaveGenerator, CaveType, Zone, CustomBiome, TileBiome, ZoneDiscoveryConfig, ZoneGeneratorResult, CaveBiomeMaskFlags, terrain, procedural generation, border transition, biome mask, density, noise, simplex, curves, patterns, material provider, props, prefab, scanner, positions, assignments, vector provider, block mask, asset pack, HytaleGenerator, node editor. |
Hytale World Generation System
Comprehensive reference for Hytale's procedural world generation systems used to create environments, biomes, and structures dynamically as players explore the world.
Related skills: For ECS fundamentals, see hytale-ecs. For persistent data/Codec patterns, see hytale-persistent-data. For entity effects, see hytale-entity-effects.
Official worldgen docs recently removed dedicated directionality coverage. Any remaining directionality notes in this skill are preserved as legacy references and should be re-verified against current server source before relying on them.
Quick Reference
| Task | Approach |
|---|
| Get zone at position | zoneGen.generate(seed, x, z) returns ZoneGeneratorResult |
| Get zone from result | zoneResult.getZone() returns Zone |
| Get biome in zone | zone.biomePatternGenerator().generateBiomeAt(zoneResult, seed, x, z) |
| Get cave generator | zone.caveGenerator() returns CaveGenerator (nullable) |
| Get cave types | caveGen.getCaveTypes() returns CaveType[] |
| Check biome cave mask | CaveBiomeMaskFlags.canGenerate(flags) |
| Get border distance | zoneResult.getBorderDistance() |
| Fade near border | customBiome.getFadeContainer().getMaskFactor(result) |
| Create zone discovery | new ZoneDiscoveryConfig(...) |
| Create biome pattern | new BiomePatternGenerator(points, tileBiomes, customBiomes) |
| Create cave config | new CaveGenerator(caveTypes) |
| Create custom zone | new Zone(id, name, discovery, caveGen, biomeGen, prefabs) |
Overview
Hytale's world generation is organized into three interconnected systems:
World Generation
├── Zones — Large-scale regions defining overall world structure
├── Biomes — Terrain characteristics and environment within zones
└── Caves — Underground structures and networks within zones
These systems are hierarchical: Zones contain Biomes, and both Zones and Biomes influence Cave generation. They work together to produce smooth transitions and coherent regional themes.
Zones
Zones are the largest-scale division in world generation. Each zone defines its own biome patterns, cave configurations, and unique structures (prefabs).
Zone Lookup and Generation
ZonePatternGenerator zoneGen = ;
ZoneGeneratorResult zoneResult = zoneGen.generate(seed, x, z);
Zone zone = zoneResult.getZone();
ZoneGeneratorResult
The result object provides:
| Method | Returns | Description |
|---|
getZone() | Zone | The zone at the queried position |
getBorderDistance() | double | Distance to the nearest zone border |
Zone Class
A Zone encapsulates all generation data for a region:
| Property | Type | Description |
|---|
| ID | int | Unique numeric identifier |
| Name | String | Internal name (e.g., "new_custom_zone") |
| Discovery | ZoneDiscoveryConfig | Player notification on zone entry |
| Cave Generator | CaveGenerator | Cave configuration (nullable) |
| Biome Pattern | BiomePatternGenerator | Biome layout within the zone |
| Unique Prefabs | — | Unique structures placed in the zone |
Creating a Custom Zone
ZoneDiscoveryConfig discovery = new ZoneDiscoveryConfig(
true,
"Custom Zone",
"zone.forest.discover",
"icons/forest.png",
true,
5.0f, 2.0f, 1.5f
);
IPointGenerator biomePoints;
IWeightedMap<TileBiome> tileBiomes;
CustomBiome[] customBiomes;
BiomePatternGenerator biomeGen = new BiomePatternGenerator(
biomePoints,
tileBiomes,
customBiomes
);
CaveType[] caveTypes;
CaveGenerator caveGen = new CaveGenerator(caveTypes);
Zone customZone = new Zone(
100,
"new_custom_zone",
discovery,
caveGen,
biomeGen,
uniquePrefabs
);
ZoneDiscoveryConfig
Controls what the player sees when entering a zone:
| Parameter | Type | Description |
|---|
showNotification | boolean | Whether to display the zone entry notification |
displayName | String | Name shown to the player |
soundEvent | String | Sound played on zone entry |
icon | String | Icon path for the notification |
majorZone | boolean | Whether this is a major zone (affects display) |
duration | float | How long the notification is visible (seconds) |
fadeIn | float | Fade-in duration (seconds) |
fadeOut | float | Fade-out duration (seconds) |
Biomes
Biomes define terrain characteristics, vegetation, and environmental properties within a zone. Each zone has its own BiomePatternGenerator that determines biome layout.
Biome Lookup
Zone zone = zoneResult.getZone();
BiomePatternGenerator biomeGen = zone.biomePatternGenerator();
Biome biome = biomeGen.generateBiomeAt(zoneResult, seed, x, z);
BiomePatternGenerator
Constructs the biome layout from three inputs:
| Parameter | Type | Description |
|---|
biomePoints | IPointGenerator | Point distribution controlling biome placement |
tileBiomes | IWeightedMap<TileBiome> | Weighted map of tile-level biome data |
customBiomes | CustomBiome[] | Custom biome definitions with fade/transition settings |
Biome Properties
Each Biome has at minimum:
| Method | Returns | Description |
|---|
getId() | int | Unique biome identifier |
CustomBiome Fading
Custom biomes support smooth transitions near zone borders via a fade container:
CustomBiome customBiome = ;
FadeContainer fade = customBiome.getFadeContainer();
double maskFadeSum = fade.getMaskFadeSum();
double factor = fade.getMaskFactor(zoneResult);
Caves
Caves are underground structures generated within zones. Each zone optionally has a CaveGenerator with one or more CaveType definitions.
Cave Lookup
Zone zone = ;
CaveGenerator caveGen = zone.caveGenerator();
if (caveGen != null) {
CaveType[] types = caveGen.getCaveTypes();
}
CaveType and Biome Masks
Cave types use biome masks to control where caves can generate:
Int2FlagsCondition biomeMask = caveType.getBiomeMask();
int biomeId = biome.getId();
int flags = biomeMask.eval(biomeId);
if (CaveBiomeMaskFlags.canGenerate(flags)) {
}
| Class | Purpose |
|---|
CaveGenerator | Holds cave type definitions for a zone |
CaveType | Individual cave definition with shape, biome mask, etc. |
Int2FlagsCondition | Evaluates biome ID → flags for cave placement |
CaveBiomeMaskFlags | Utility to interpret biome mask flags (e.g., canGenerate) |
System Integration
Zone → Biome Integration
Each zone defines its own biome pattern. The biome generator requires the zone result (for border distance and zone context):
Zone zone = zoneGen.generate(seed, x, z).getZone();
BiomePatternGenerator biomeGen = zone.biomePatternGenerator();
Biome biome = biomeGen.generateBiomeAt(zoneResult, seed, x, z);
Zone → Cave Integration
Each zone defines its own cave patterns. Not all zones have caves:
Zone zone = ;
CaveGenerator caveGen = zone.caveGenerator();
if (caveGen != null) {
CaveType[] types = caveGen.getCaveTypes();
}
Biome → Cave Integration
Caves use biome masks to restrict generation to specific biomes:
Int2FlagsCondition biomeMask = caveType.getBiomeMask();
int biomeId = biome.getId();
int flags = biomeMask.eval(biomeId);
if (CaveBiomeMaskFlags.canGenerate(flags)) {
}
Border Transitions
All systems respect zone boundaries. Custom biomes fade near borders for smooth transitions:
ZoneGeneratorResult result = zoneGen.generate(seed, x, z);
double borderDistance = result.getBorderDistance();
if (borderDistance < customBiome.getFadeContainer().getMaskFadeSum()) {
double factor = customBiome.getFadeContainer().getMaskFactor(result);
}
Key Classes Summary
| Class | Package Area | Purpose |
|---|
ZonePatternGenerator | worldgen | Generates zones at world positions |
ZoneGeneratorResult | worldgen | Result of zone lookup (zone + border distance) |
Zone | worldgen | Zone definition (biomes, caves, prefabs, discovery) |
ZoneDiscoveryConfig | worldgen | Player notification on zone entry |
BiomePatternGenerator | worldgen | Biome layout within a zone |
Biome | worldgen | Biome data (ID, properties) |
CustomBiome | worldgen | Custom biome with fade/transition support |
TileBiome | worldgen | Tile-level biome data |
IPointGenerator | worldgen | Point distribution for biome placement |
IWeightedMap<T> | worldgen | Weighted map for biome selection |
CaveGenerator | worldgen | Cave configuration for a zone |
CaveType | worldgen | Individual cave type definition |
Int2FlagsCondition | worldgen | Biome mask evaluator for caves |
CaveBiomeMaskFlags | worldgen | Flag utility for cave biome masks |
FadeContainer | worldgen | Border fade/transition controller |
Common Patterns
Full World Position → Zone + Biome + Cave Pipeline
ZonePatternGenerator zoneGen = ;
long seed = ;
int x = ;
int z = ;
ZoneGeneratorResult zoneResult = zoneGen.generate(seed, x, z);
Zone zone = zoneResult.getZone();
BiomePatternGenerator biomeGen = zone.biomePatternGenerator();
Biome biome = biomeGen.generateBiomeAt(zoneResult, seed, x, z);
CaveGenerator caveGen = zone.caveGenerator();
if (caveGen != null) {
for (CaveType caveType : caveGen.getCaveTypes()) {
Int2FlagsCondition biomeMask = caveType.getBiomeMask();
int flags = biomeMask.eval(biome.getId());
if (CaveBiomeMaskFlags.canGenerate(flags)) {
}
}
}
double borderDistance = zoneResult.getBorderDistance();
Zone Entry Notification Setup
ZoneDiscoveryConfig discovery = new ZoneDiscoveryConfig(
true,
"Enchanted Forest",
"zone.forest.discover",
"icons/forest.png",
true,
5.0f, 2.0f, 1.5f
);
Data-Driven World Generation (Node/JSON System)
Beyond the Java plugin API, Hytale's world generation is primarily data-driven through JSON asset files and an in-game Node Editor. Biomes, terrain shapes, materials, and content placement are all defined declaratively.
Detailed references for every node type are in the references/ subdirectory of this skill.
Asset Directory Structure
Server/HytaleGenerator/
├── WorldStructure/ # Generator files defining which biomes spawn together
├── Biomes/ # Biome assets with content configurations
├── Density/ # Reusable density assets referenced by other generation assets
└── Assignments/ # Reusable prop assignment assets referenced by biomes
World Instance Configuration
Instances are separate worlds that players can join. Each instance has an Instance.bson that specifies which generator to use:
{
"WorldGen": {
"Type": "HytaleGenerator",
"WorldStructure": "Basic",
"playerSpawn": {
"X": 123, "Y": 480, "Z": 10000,
"Pitch": 0, "Yaw": 0, "Roll": 0
}
}
}
Instance configs are stored at Server/Instances/. Create custom instances by duplicating the basic config and changing WorldStructure to your asset name.
Previewing World Generation
| Command | Purpose |
|---|
/viewport --radius 5 | Live-reload area around player as you edit |
/instances spawn <instance> | Create a new world with latest changes |
| Fly south | New chunks generate with latest changes |
Biome Asset Structure
Every biome has 5 root components:
| Component | Purpose |
|---|
| Terrain | Density function nodes defining the physical terrain shape |
| Material Provider | Logic nodes determining which block types make up terrain |
| Props | Object nodes placing prefabs, trees, POIs, grass, etc. |
| Environment Provider | Logic nodes determining weather, NPC spawns, sounds per coordinate |
| Tint Provider | Function nodes determining color codes for grasses, soils, etc. |
Each biome is self-contained — it controls everything within its boundaries except Base Heights.
Node System Overview
World generation uses a node-based system of composable JSON assets. Each node type has parameters and inputs:
| Node Category | Purpose | Key Types |
|---|
| Density | 3D decimal value fields for terrain shape | SimplexNoise2D/3D, PositionsCellNoise, Distance, Ellipsoid, Cube, Cylinder, Sum, Multiplier, Mix, CurveMapper, Scale, Rotator, Warp nodes |
| Curves | f(x)=y mappings for value transformation | Manual, DistanceExponential, DistanceS, Ceiling/Floor, SmoothClamp, Clamp, Inverter, Min/Max |
| Patterns | Validate world positions by material/structure | BlockType, BlockSet, Floor, Ceiling, Wall, Surface, Gap, Cuboid, And/Or/Not, FieldFunction |
| Material Providers | Determine block types at positions | Constant, Solidity, Queue, SimpleHorizontal, Striped, Weighted, FieldFunction, SpaceAndDepth (with Layers and Conditions) |
| Positions Provider | Define infinite 3D position fields | Mesh2D, Mesh3D, List, FieldFunction, Occurrence, BaseHeight, Cache |
| Scanners | Scan local world areas for valid positions | Origin, ColumnLinear, ColumnRandom, Area |
| Props | Localized content placed in the world | Box, Density, Prefab, Column, Cluster, Union, Weighted, Queue, PondFiller |
| Assignments | Assign props to positions | Constant, FieldFunction, Sandwich, Weighted |
| Legacy Directionality | Older prop-facing nodes preserved as reference only | Static, Random, Pattern-based |
| Vector Provider | Define 3D vectors procedurally | Constant, DensityGradient, Cache |
| Block Mask | Control which materials can replace others | DontPlace, DontReplace, Advanced rules |
Core Concept: Density Fields
Terrain generation is built on density fields — maps of decimal values (typically -1 to 1) defining terrain shape:
- Positive values → solid terrain
- Negative values → empty space (air)
- Density is calculated from the sum of all nodes:
f(x) = z + y
Common terrain formula: Simplex 2D noise + Y-Curve (height gradient) = basic terrain shape.
Function nodes manipulate density fields: Absolute (ridged shapes), Normalization (rescaling range), Scale (stretch/contract), Rotator (orientation), Warp (distortion), and many more.
Core Concept: Props Pipeline
Props place procedural content (trees, prefabs, grass) using three connected systems:
Positions → Scanner → Pattern → Prop Placement
- Positions provide candidate locations (e.g., Mesh2D grid, BaseHeight offsets)
- Scanner searches around each position (e.g., ColumnLinear scans Y range)
- Pattern validates positions (e.g., Floor pattern checks for solid ground below)
- Prop places content at validated positions (e.g., Prefab placement; older docs also referenced Directionality for facing)
Asset Packs
Asset Packs override or add assets to the base game. Required for world gen customization:
{
"Group": "My Group",
"Name": "Pack Example",
"Version": "1.0.0",
"Description": "An Example Asset Pack",
"Authors": [{"Name": "Me", "Email": "", "Url": ""}],
"Dependencies": {},
"DisabledByDefault": false,
"IncludesAssetPack": false,
"SubPlugins": []
}
- Stored in
C:\Users\<user>\AppData\Roaming\Hytale\UserData\Mods
- Per-world packs stored in
UserData\Saves\<world>\mods
- Asset Packs exist entirely on the server — only the host needs them
- Assets inside packs override base game assets
Import/Export System
Most node types support Imported and Exported nodes for reusability:
- Exported: Makes a node tree available by name, with optional
SingleInstance for shared caching
- Imported: References an exported asset by name
- This enables modular, reusable density fields, curves, patterns, etc.
Notes
- The
worldgen module is a built-in Hytale module. Plugins interact with it through the public API classes listed above.
- Zone IDs must be unique across the world generation configuration.
CaveGenerator is nullable — not all zones have caves.
- Biome masks use a flags-based system (
Int2FlagsCondition) for efficient cave-biome filtering.
- Border transitions use
FadeContainer with getMaskFadeSum() and getMaskFactor() for smooth blending between zones.
- The
--validate-world-gen server launch flag can be used to validate world generation assets.
- World gen examples can be found in
HytaleGenerator/Biomes/Examples/.
- The Hytale Node Editor is accessible in-game from the Content Creation menu (Tab key).
Performance Optimization
World-gen prints a performance report to server logs at configurable sample-size intervals. Open it: right-click world in world selection → open world folder → logs/latest. Use reports with Sample Count ≥ 500 for accuracy.
Key metrics to watch: Content Generation: # ms — the time you have the most control over. Each stage (BiomeStage, TerrainStage, PropStages, TintStage, EnvironmentStage) is listed separately.
Density / Terrain
| Technique | Detail |
|---|
| Use Mix to mask expensive Density | Limit costly density fields to only the regions that need them. Replace areas above max terrain height with Constant(-1) and all-underground with Constant(1). |
| Use YSampled | Reduces vertical sample count for density fields where full resolution isn't visually needed. Recommended SampleDistance: 8 for best performance, 2 for high-detail areas. Mix sampled and non-sampled versions for precision only where needed. |
| Cache nodes | Add Cache on the right side of YOverride nodes, and at the root of ChoiceDensity/CellValue Density. SimplexNoise2d and CellNoise2d already cache automatically. |
| Use Mix over Sum/Min/Max | Mix disables fields where they aren't needed; Sum/Min/Max always evaluate all inputs. |
| Avoid unnecessary Density gradients | Gradients resolve the child 4x per position. Mask them out. Inside Material Providers, use the TerrainDensity node (reuses existing buffers) rather than importing the terrain root density. |
| 2D where possible | Use 3D density only when required. 3D domain warping invalidates 2D caches from all child nodes. |
| WorldStructure tuning | Don't set DefaultTransitionDistance and MaxBiomeEdgeDistance higher than necessary — they affect BiomeStage and TerrainStage output sizes. |
Materials
- Put expensive Material Providers as far right in the tree as possible; cheap limiters go left.
SimpleHorizontal reduces the height range for its children.
SpaceAndDepth reduces the depth range for its children.
- Use
FieldFunction with a cheap density mask to limit an expensive Material Provider to a specific world region.
- Use
TerrainDensity node inside Material Providers when referencing the terrain's density for gradients.
Props
- Keep each Runtime's horizontal size as small as possible — it's determined by the largest Prop in that Runtime.
- Put Props with the largest horizontal size at the lowest Runtime index.
- Pack as many Props into one Runtime as possible. Only create new Runtimes when Props need context from other Props.
- All Biomes in a WorldStructure should use the same Runtime indices to avoid multiplying Runtimes.
- Break large Props into smaller modular pieces assembled at the Prop Distribution level.
Quick Checklist
- Try 2D over 3D everywhere possible.
- Place
Cache on the right side of all YOverride nodes.
- Add
YSampled at the root of each Biome's Density as a first pass.
- Use
Mix (not Sum) to cap terrain above max height and below min height.
- Ensure all Biomes share the same Runtime indices.
- Check
DefaultTransitionDistance and MaxBiomeEdgeDistance in WorldStructure — keep them minimal.
Source: hytalemodding.dev — World Generation Optimization
Source: hytalemodding.dev — World Generation System
Source: HytaleModding/site — Official World Generation Documentation