Skip to content

Custom biome API, mappings, and generated Bedrock visuals - #6658

Open
darkcupid412 wants to merge 18 commits into
GeyserMC:feature/26.50from
darkcupid412:feat/custom-biome-api
Open

darkcupid412 wants to merge 18 commits into
GeyserMC:feature/26.50from
darkcupid412:feat/custom-biome-api

Conversation

@darkcupid412

Copy link
Copy Markdown
Contributor

Addresses #3645.

This PR adds two ways to register custom biomes: through GeyserDefineCustomBiomesEvent from an extension, or through a biomes section in a custom mappings file.

Mappings use the same effects and attributes keys as Java data pack biomes, so most existing biome JSON copies straight over. Bedrock-specific values go under geyser, which takes priority when both define the same value.

A mappings file can also reference a manually provided resource pack using a top-level pack_uuid next to format_version. Biomes from that file are styled by the referenced pack instead of Geyser's generated one, so appearance values are rejected. Geyser also warns at startup if no registered pack matches the UUID.

When bedrock_identifier is omitted, Geyser derives one. Java identifiers that are already valid on Bedrock are reused as-is. Anything else gets a digest-based identifier, since Java allows characters such as / and simply flattening them can cause collisions.

Example

{
  "format_version": 1,
  "biomes": {
    "my_datapack:cave/crystal_caves": {
      "effects": {
        "water_color": "#3F76E4",
        "grass_color": "#5F9F45",
        "foliage_color": "#4F8F3F"
      },
      "attributes": {
        "minecraft:visual/sky_color": "#78A7FF",
        "minecraft:visual/fog_color": "#C0D8FF",
        "minecraft:visual/water_fog_color": "#050533",
        "minecraft:visual/water_fog_end_distance": 48.0
      },
      "geyser": {
        "water_surface_opacity": 0.55,
        "precipitation": {
          "type": "blue_spores",
          "density": 0.25
        }
      }
    }
  }
}

The same biome registered through the API:

@Subscribe
public void onDefineBiomes(GeyserDefineCustomBiomesEvent event) {
    event.register(Identifier.of("my_datapack", "cave/crystal_caves"),
        CustomBiomeDefinition.builder(Identifier.of("my_datapack", "crystal_caves"))
            .appearance(CustomBiomeAppearance.builder()
                .skyColor(new Color(0x78A7FF))
                .grassColor(new Color(0x5F9F45))
                .waterSurfaceColor(new Color(0x3F76E4)))
            .build());
}

Custom definitions are appended to the vanilla BiomeDefinitionListPacket with sequential IDs starting at 30000, Bedrock's custom biome range.

Climate values come from the live Java registry. When no grass or foliage color is provided, Bedrock's colormap tint stays within 1/255 of Java's.

Colors and fog require a resource pack on Bedrock, so Geyser generates a small custom_biomes.mcpack from the registered appearances.

Limitations

Vibrant Visuals still ignores or reinterprets several fields as of Bedrock 1.26.44:

  • Sky color only affects the daytime zenith. The horizon remains vanilla. This should be fixable in a follow-up.
  • Air fog color is not applied.
  • Water fog color does not tint the underwater haze. Nearby submerged surfaces still pick it up, and the end distance works.
  • Surface color is blended into the water instead of being applied directly.
  • Surface opacity is not applied.

The classic renderer supports all of these fields.

Testing

Tested on Bedrock 1.26.44 against Paper 1.26.2 using both the classic and Vibrant Visuals renderers:

  • Every supported color and fog field
  • All four precipitation types
  • Grass and foliage tint parity beside a Java client
  • Identifier derivation

This PR also changes the shared NodeReader.ofEnum and NodeReader.ofMap helpers to use Locale.ROOT for case conversion. With a default locale such as Turkish, keys containing i otherwise fail to parse, including this PR's white_ash precipitation type.

@kayvdlans

Copy link
Copy Markdown

Overall looks pretty clean, definitely better than my attempt at implementing this.

A few questions though:

What's the reason for not using the visual/water_fog_start_distance attribute when we do use the end distance?

Why not implement the fog_start/end_distance as well? Is it due to the default being render-relative, or because the weather fog is handled differently between Java and Bedrock, or..?

@darkcupid412

Copy link
Copy Markdown
Contributor Author

Overall looks pretty clean, definitely better than my attempt at implementing this.

A few questions though:

What's the reason for not using the visual/water_fog_start_distance attribute when we do use the end distance?

Why not implement the fog_start/end_distance as well? Is it due to the default being render-relative, or because the weather fog is handled differently between Java and Bedrock, or..?

Water fog: Java's start defaults to -8 and isn't range-limited like the end is, and vanilla Bedrock always uses 0 for water, so there's nothing worth mapping.

Air fog: Bedrock's air/weather fog is render-distance relative, Java's is absolute blocks, so mapping it means going fixed and losing the scaling. It's on my follow-up list with cloud color and grass color modifier.

@kayvdlans

Copy link
Copy Markdown

Water fog: Java's start defaults to -8 and isn't range-limited like the end is, and vanilla Bedrock always uses 0 for water, so there's nothing worth mapping.

By default Bedrock uses 0 for water, but you can adjust it as well, including into the negative range. Im not sure im following why there is nothing worth mapping, unless we're only looking at vanilla biomes, rather than custom biomes.

Air fog: Bedrock's air/weather fog is render-distance relative, Java's is absolute blocks, so mapping it means going fixed and losing the scaling. It's on my follow-up list with cloud color and grass color modifier.

Fair enough, thought that would be the case ^^.

@darkcupid412

darkcupid412 commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor Author

By default Bedrock uses 0 for water, but you can adjust it as well, including into the negative range. Im not sure im following why there is nothing worth mapping, unless we're only looking at vanilla biomes, rather than custom biomes.

Okay. I'll add water fog to the follow-up list ;p

Comment thread core/src/test/resources/configuration/custom-biomes-packed.json Outdated
Comment thread core/src/test/resources/configuration/custom-biomes.json Outdated
@Novampr Novampr added API The issue/feature request relates to the Geyser API PR: Future API Addition An API addition which is planned for the next version of Geyser labels Sep 3, 2026
@Novampr
Novampr changed the base branch from master to feature/26.50 September 3, 2026 11:18
@eclipseisoffline eclipseisoffline mentioned this pull request Sep 16, 2026
30 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API The issue/feature request relates to the Geyser API PR: Future API Addition An API addition which is planned for the next version of Geyser

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants