Hytale's world generation is data-driven and modifier-based. Instead of writing Java code to override terrain generation (like you would in Minecraft), Hytale exposes a WorldGenModifier system with 10 hooks that let you alter biomes, caves, and structures through priority-ordered modifiers. Combined with a JSON codec system for defining blocks, items, and recipes, you can create entirely new content without touching the generation engine itself. This reference is based on Hytale server version 2026.03.26.
WorldGenModifier Overview
A WorldGenModifier is an asset that hooks into the world generation pipeline. Each modifier targets specific generation phases and applies operations in priority order.
// WorldGenModifier structure
public class WorldGenModifier {
String id; // Unique modifier identifier
EventPriority priority; // Execution order
Target target; // What biomes/regions this applies to
Map<EventType, Op[]> content; // Hook → operations mapping
}
Modifiers are registered as assets through your plugin's AssetRegistry. The server applies them in EventPriority order during chunk generation — lower-priority modifiers run first (base terrain), and higher-priority modifiers overlay on top (decorations, overrides).
Tip: Use lower priorities for foundational terrain changes (base block layers, fluid levels) and higher priorities for decorative modifications (tints, prefabs, covers). This ensures decorations are applied on top of terrain rather than being overwritten by it.
The 10 WorldGen Hooks
The EventType enum defines exactly which generation phases you can hook into:
Biome Hooks
Biome_Covers
Controls the surface block layers of a biome. This is what determines whether you walk on grass, sand, snow, or custom materials.
Use this hook to replace the top surface layer or add additional cover layers. Each operation specifies which block types to place and under what conditions (altitude, slope, proximity to water).
Biome_Environments
Configures environmental settings like lighting, fog density, weather patterns, and ambient particle effects. This is the hook that makes a swamp feel murky and a desert feel bright.
Environment settings are defined as Environment assets that reference ambient FX, particle systems, and camera effects.
Biome_Fluids
Defines which fluids fill a biome. Beyond water and lava, Hytale supports custom Fluid asset types, so you can create biomes with unique liquid types.
Biome_Dynamic_Layers
Controls terrain layers that change over time. Dynamic layers can shift based on in-game seasons, time of day, or other server-side triggers. This is how biomes can visually evolve without regenerating chunks.
Biome_Static_Layers
Defines the fixed underground terrain composition. Static layers determine what you find when you dig down — stone types, ore distribution, soil depth. These are set at generation time and do not change.
Biome_Prefabs
Controls structure placement within a biome. Prefabs are pre-built structures (villages, ruins, dungeons, trees) placed during generation. Each prefab has placement rules: spacing, altitude range, biome requirements, and a priority that determines which prefabs win when placements overlap.
Biome_Tints
Applies color grading to a biome's foliage, grass, water, and sky. Tints are a lightweight way to visually distinguish biomes without changing block types. A single biome can have different tint palettes for different seasons.
Cave Hooks
Cave_Types
Defines the cave generation algorithms used in a biome. Hytale supports multiple cave shapes per biome — you can combine narrow tunnels, large caverns, and vertical shafts with different frequency and scale parameters.
Cave_Covers
Controls the surface materials inside caves. Similar to Biome_Covers but for underground surfaces. This is how cave walls get mossy stone, crystal formations, or biome-specific materials.
Cave_Prefabs
Places structures inside caves. Underground temples, minecart tracks, ore veins, and other subterranean features are placed through this hook with the same prefab system used above ground.
Warning: When two modifiers at the same priority target the same hook and region, the application order is undefined. Always use distinct priorities when multiple mods modify the same biome's generation. If you're building a mod that other mods might also modify, document which priorities you use so others can layer above or below.
Generation Pipeline
Under the hood, the world generation pipeline works through several components:
IWorldGen Interface
The core generation contract:
public interface IWorldGen {
CompletableFuture<GeneratedChunk[]> generate(
int x, long seed, int width, int height,
LongPredicate shouldGenerate
);
ISpawnProvider getSpawnPoints(long seed);
}
Generation is asynchronous — chunks are generated on worker threads and returned as CompletableFuture results. Each GeneratedChunk contains block state data, entity data, and section metadata.
Populators
After base terrain is generated, populators add detail:
| Populator | What It Does |
|---|---|
BlockPopulator | Places individual blocks (ores, flowers, surface scatter) |
CavePopulator | Carves cave systems using the Cave_Types algorithms |
PrefabPopulator | Places prefab structures from Biome_Prefabs and Cave_Prefabs |
WaterPopulator | Fills bodies of water and applies fluid rules |
Each populator processes chunks after the ChunkGenerator produces base terrain. The BlockPriorityModifier system ensures block placements from different populators resolve correctly when they overlap.
Custom World Gen Providers
You can register entirely custom world generators by implementing IWorldGenProvider:
public interface IWorldGenProvider {
IWorldGen createWorldGen(WorldGenConfig config);
}
Hytale includes several built-in providers:
FlatWorldGenProvider— generates flat worlds (useful for testing)VoidWorldGenProvider— generates empty worldsDummyWorldGenProvider— placeholder for development
Data-Driven Content: JSON Codec Assets
Hytale defines game content through a codec system that validates JSON assets at load time. This means you can add new blocks, items, recipes, and effects by writing JSON files rather than Java code.
Custom Block Definition
Blocks are defined as BlockType assets with extensive configuration:
{
"id": "crystal_block",
"group": "crystal",
"drawType": "CUBE",
"opacity": "SOLID",
"material": "STONE",
"textures": [
{
"side": "ALL",
"texture": "blocks/crystal_block"
}
],
"light": {
"r": 100,
"g": 180,
"b": 255
},
"blockParticleSetId": "crystal_sparkle",
"blockBreakingDecalId": "stone_breaking"
}
Key BlockType configuration options:
| Property | Description |
|---|---|
drawType | Rendering mode: CUBE, CUSTOM_MODEL, CROSS (vegetation), etc. |
opacity | SOLID, TRANSPARENT, or translucent with alpha blending |
material | Physics material: STONE, WOOD, METAL, etc. Affects sound and tool interactions. |
textures | Per-face texture assignments |
light | RGB light emission values |
tickProcedure | Logic that runs each tick (for animated or interactive blocks) |
randomTickProcedure | Logic that runs on random ticks (for growth, decay, etc.) |
connectedBlockRuleSet | Rules for connected textures (fences, glass panes, walls) |
customModel | Path to a custom 3D model instead of a cube |
randomRotation / variantRotation | Visual variety through random or variant-based rotation |
Note: The codec system validates your JSON at load time. If a required field is missing or a value is the wrong type, the server logs a clear error message with the file path and field name. You don't need to debug silent failures — check the server log for asset loading errors.
Custom Crafting Recipe
Recipes are CraftingRecipe assets with inputs, outputs, and requirements:
{
"id": "crystal_sword_recipe",
"input": [
{ "material": "crystal_shard", "quantity": 3 },
{ "material": "iron_ingot", "quantity": 1 }
],
"primaryOutput": {
"material": "crystal_sword",
"quantity": 1
},
"benchRequirement": [
{ "type": "Crafting", "tierLevel": 2 }
],
"timeSeconds": 5.0,
"knowledgeRequired": true,
"requiredMemoriesLevel": 1
}
| Property | Description |
|---|---|
input | Array of MaterialQuantity (material ID + quantity) |
primaryOutput | The main item produced |
outputs | Additional output items (byproducts) |
benchRequirement | Required crafting station and tier. Types: Crafting, DiagramCrafting, Fieldcraft. |
timeSeconds | How long the craft takes |
knowledgeRequired | Whether the player must discover the recipe first |
requiredMemoriesLevel | Memory/progression level needed to craft |
Other Asset Types
The codec system also supports:
- Item — item definitions with categories, tool types, and utility functions
- SoundEvent — sound definitions with volume, pitch, and attenuation
- EntityEffect — status effects with duration, strength, and visual indicators
- ParticleSystem — particle emitter configurations
- BlockSoundSet / BlockParticleSet — sound and particle bundles for blocks
- ItemDropList / ItemDropContainer — loot table definitions with weighted random drops
- ResourceType — raw material definitions
Portal System
Hytale supports cross-world transfer through PortalType assets. Each portal defines a destination instance, gameplay configuration, and UI metadata:
{
"id": "crystal_caverns_portal",
"instanceId": "crystal_caverns",
"description": {
"displayNameKey": "portal.crystal_caverns.name",
"flavorTextKey": "portal.crystal_caverns.flavor",
"themeColor": { "r": 100, "g": 180, "b": 255 },
"objectivesKeys": [
"portal.crystal_caverns.objective.explore",
"portal.crystal_caverns.objective.boss"
],
"wisdomKeys": [
"portal.crystal_caverns.wisdom.light"
]
},
"gameplayConfig": "Portal"
}
Portals reference instances stored in Assets/Server/Instances/. The DiscoverInstanceEvent.Display event fires when a player approaches a portal, and it's cancellable — you can control when and whether the portal UI appears.
Example: Crystal Caverns Biome Modifier
Here's how you'd create a custom biome that adds crystal formations underground:
1. Define the crystal block asset (JSON codec):
crystal_blockwith light emission, custom particle set, stone material
2. Create a WorldGenModifier targeting the desired region:
// Register in your plugin's setup()
WorldGenModifier crystalCaverns = new WorldGenModifier("crystal_caverns");
crystalCaverns.setPriority(EventPriority.NORMAL);
crystalCaverns.setTarget(Target.biome("underground_caves"));
// Hook into Cave_Covers to place crystal blocks on cave surfaces
crystalCaverns.setOperations(EventType.Cave_Covers, new Op[] {
Op.replace("stone", "crystal_block", 0.15f) // 15% replacement chance
});
// Hook into Cave_Prefabs to place crystal formation structures
crystalCaverns.setOperations(EventType.Cave_Prefabs, new Op[] {
Op.placePrefab("crystal_cluster", spacing(8), altitude(20, 60))
});
// Hook into Biome_Tints to add a blue glow
crystalCaverns.setOperations(EventType.Biome_Tints, new Op[] {
Op.setTint("cave_ambient", new Color(100, 180, 255, 40))
});
3. Define the crafting recipe for a crystal sword using the crystal materials.
4. Register a portal that takes players into a dedicated Crystal Caverns instance with PortalType.
Custom biome checklist
- Define block assets as JSON codec files (BlockType with textures, materials, light)
- Create a WorldGenModifier with a unique ID and appropriate priority
- Implement the relevant hooks: covers, tints, prefabs, cave types, etc.
- Set the modifier target to the correct biome or region
- Define crafting recipes for any new items using the materials
- Define loot tables (ItemDropList) for new block/entity drops
- If creating an instance: define a PortalType asset with UI metadata
- Register all assets through your plugin's AssetRegistry in setup()
- Test with a fresh world to verify generation output