Back to Knowledge Base

Hytale World Generation: WorldGenModifier Hooks and Data-Driven Content

A guide to Hytale's data-driven world generation system — 10 WorldGenModifier hooks for biomes and caves, plus JSON codec-based content definitions for blocks, items, and recipes.

Player Games··hytale

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:

PopulatorWhat It Does
BlockPopulatorPlaces individual blocks (ores, flowers, surface scatter)
CavePopulatorCarves cave systems using the Cave_Types algorithms
PrefabPopulatorPlaces prefab structures from Biome_Prefabs and Cave_Prefabs
WaterPopulatorFills 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 worlds
  • DummyWorldGenProvider — 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:

PropertyDescription
drawTypeRendering mode: CUBE, CUSTOM_MODEL, CROSS (vegetation), etc.
opacitySOLID, TRANSPARENT, or translucent with alpha blending
materialPhysics material: STONE, WOOD, METAL, etc. Affects sound and tool interactions.
texturesPer-face texture assignments
lightRGB light emission values
tickProcedureLogic that runs each tick (for animated or interactive blocks)
randomTickProcedureLogic that runs on random ticks (for growth, decay, etc.)
connectedBlockRuleSetRules for connected textures (fences, glass panes, walls)
customModelPath to a custom 3D model instead of a cube
randomRotation / variantRotationVisual 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
}
PropertyDescription
inputArray of MaterialQuantity (material ID + quantity)
primaryOutputThe main item produced
outputsAdditional output items (byproducts)
benchRequirementRequired crafting station and tier. Types: Crafting, DiagramCrafting, Fieldcraft.
timeSecondsHow long the craft takes
knowledgeRequiredWhether the player must discover the recipe first
requiredMemoriesLevelMemory/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_block with 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