PersonTheCat / pangaea

A highly configurable terrain generator for Minecraft with light scripting support
GNU Lesser General Public License v2.1
1 stars 0 forks source link

Implement Density Controller #18

Closed PersonTheCat closed 1 month ago

PersonTheCat commented 2 months ago

One of the goals for Pangaea is to reduce the barrier to entry for creating custom terrain in Minecraft over data packs. In #3, a handful of solutions to this problem were determined, one of which was to provide simplified or highly-specialized density functions which replace existing patterns in the vanilla data packs, providing labels that make them easier to configure. The first one we'll implement is the Density Controller. This can essentially replace the final_density value in most dimensions.

Here's what it should provide:

PersonTheCat commented 2 months ago

Progress on this story is well underway. Additionally, I am planning to add smaller, less-specialized density functions from some of these steps. For example, a "cutoff" density function, which describes how to gradually reduce cave output at certain y-levels, as well as fancy list functions that are specifically designed for caves. I will update here as this design becomes a little more solid.

PersonTheCat commented 2 months ago

Here's what I'm thinking for the cavern portion. The user creates density functions as usual and then lists them by name in a recursive min/max list structure.

underground_caverns: {
  max: [
    {
      min: [ 
        'overworld/entrances',
        'overworld/cheese',
        'overworld/sphaghetti',
      ],
    },
    'overworld/pillars',
  ],
},
global_caverns: 'overworld/noodles',

Since each of these strings is just a density function, it's just as powerful as regular data packs, but I'm hoping this will make it easier to see how the different patterns are combined. (not to mention, less work to add / remove values)

PersonTheCat commented 2 months ago

Here's an updated schema which I believe covers everything most final_density functions would do (at least in vanilla).

{
  surface: 'overworld/sloped_cheese',
  entrances: {
    mul: 5.0,
    times: 'overworld/caves/entrances',
  },
  upper_cutoff: {
    range: [ 240, 256 ],
    harshness: 0.078125,
  },
  lower_cutoff: {
    range: [ -64, -40 ],
    harshness: 0.1171875,
  },
  underground_caverns: [
    'pg:cheese_caves',
    'overworld/caves/entrances',
    {
      add: 'overworld/caves/spaghetti_2d',
      plus: 'overworld/caves/spaghetti_roughness_function',
    },
  ],
  underground_filler: 'overworld/caves/pillars',
  global_caverns: 'overworld/caves/noodle',
}

This example features what is essentially a list of caverns, which was my original goal with this story. underground_caverns is a min list, the smallest value is your cave output. underground_filler is a max list. If the max value is greater filler_threshold (default=0.3) and greater than underground_caverns, it will be your final density underground.

It also makes use of the new pg:structural density codecs, which I will detail in a follow-up story.

Also note that I've simply moved some of these settings into a different file, pg:cheese_caves. Its contents are exactly the same as what used to be there in vanilla:

{
  sum: [
    {
      mul: 4,
      times: {
        square: {
          type: 'noise',
          noise: 'cave_layer',
          xz_scale: 1,
          y_scale: 8,
        },
      },
    },
    {
      clamp: [ -1, 1 ],
      add: 0.27,
      plus: {
        type: 'noise',
        noise: 'cave_cheese',
        xz_scale: 1,
        y_scale: 0.6666666666666666,
      },
    },
    {
      clamp: [ 0, 0.5 ]
      add: 1.5,
      plus: {
        mul: -0.64,
        times: 'overworld/sloped_cheese',
      },
    }
  ]
}

I'm still in the process of confirming that nothing has changed with this story. To correctly test it, I'll need to begin working on the data injectors from #4.

PersonTheCat commented 1 month ago

I have completed testing this and confirmed parity with original vanilla behavior, as well as convenient ways to modify and or disable individual components of the original underground terrain generation. Here's an example of a data injector replacing the final density value of the minecraft:overworld noise generator settings.

{
  "overworld": {
    "surface": "overworld/sloped_cheese",
    "entrances": {
      "mul": 5.0,
      "times": "overworld/caves/entrances"
    },
    "upper_cutoff": {
      "range": [ 240, 256 ],
      "harshness": 0.078125
    },
    "lower_cutoff": {
      "range": [ -64, -40 ],
      "harshness": 0.1171875
    },
    "underground_caverns": [
      "pangaea:overworld/caves/cheese",
      "overworld/caves/entrances",
      "pangaea:overworld/caves/spaghetti"
    ],
    "global_caverns": [
      "overworld/caves/noodle"
    ],
    "underground_filler": [
      "overworld/caves/pillars"
    ]
  }
}

This can be any density function, but defaults to a pangaea:density_controller. Note that entrances is also technically an array (or a DensityList$Min / pangaea:min), but I am writing it as a single object for readability in this case. Either format is tolerated by the codec.