@Override
  public float getModifierTickCostFactor(DimletType modifierType, DimletKey key) {
    TerrainType terrainType = DimletObjectMapping.getTerrain(key);

    if (modifierType == DimletType.DIMLET_MATERIAL) {
      return materialTickCostFactor * terrainType.getMaterialCostFactor();
    } else if (modifierType == DimletType.DIMLET_LIQUID) {
      return liquidTickCostFactor * terrainType.getLiquidCostFactor();
    } else {
      return 1.0f;
    }
  }
  @Override
  public void constructDimension(
      List<Pair<DimletKey, List<DimletKey>>> dimlets,
      Random random,
      DimensionInformation dimensionInformation) {
    dimlets = DimensionInformation.extractType(DimletType.DIMLET_TERRAIN, dimlets);
    List<DimletKey> modifiers;
    TerrainType terrainType = TerrainType.TERRAIN_VOID;
    if (dimlets.isEmpty()) {
      // Pick a random terrain type with a seed that is generated from all the
      // dimlets so we always get the same random value for these dimlets.
      DimletKey key = DimletRandomizer.getRandomTerrain(random);
      dimensionInformation.updateCostFactor(key);
      terrainType = DimletObjectMapping.getTerrain(key);
      modifiers = Collections.emptyList();
    } else {
      int index = random.nextInt(dimlets.size());
      DimletKey key = dimlets.get(index).getLeft();
      terrainType = DimletObjectMapping.getTerrain(key);
      modifiers = dimlets.get(index).getRight();
    }

    List<IBlockState> blocks = new ArrayList<>();
    List<Block> fluids = new ArrayList<>();
    DimensionInformation.getMaterialAndFluidModifiers(modifiers, blocks, fluids);
    dimensionInformation.setTerrainType(terrainType);

    IBlockState baseBlockForTerrain;
    if (dimensionInformation.isPatreonBitSet(Patreons.PATREON_LAYEREDMETA)) {
      baseBlockForTerrain = Blocks.stone.getDefaultState();
      //            baseBlockForTerrain = new BlockMeta(Blocks.wool, 127);
      // @todo
    } else {
      if (!blocks.isEmpty()) {
        baseBlockForTerrain = blocks.get(random.nextInt(blocks.size()));
        if (baseBlockForTerrain == null) {
          baseBlockForTerrain =
              Blocks.stone.getDefaultState(); // This is the default in case None was specified.
        }
      } else {
        // Nothing was specified. With a relatively big chance we use stone. But there is also a
        // chance that the material will be something else.
        // Note that in this particular case we disallow randomly selecting 'expensive' blocks like
        // glass.
        // If the terrain type is void we always pick stone as a random material.
        if (terrainType == TerrainType.TERRAIN_VOID) {
          baseBlockForTerrain = Blocks.stone.getDefaultState();
        } else if (random.nextFloat() < WorldgenConfiguration.randomBaseBlockChance) {
          DimletKey key = DimletRandomizer.getRandomMaterialBlock(random);
          if (key != null) {
            dimensionInformation.updateCostFactor(key);
            baseBlockForTerrain = DimletObjectMapping.getBlock(key);
          } else {
            baseBlockForTerrain = Blocks.stone.getDefaultState();
          }
        } else {
          baseBlockForTerrain = Blocks.stone.getDefaultState();
        }
      }
    }
    dimensionInformation.setBaseBlockForTerrain(baseBlockForTerrain);

    Block fluidForTerrain;
    if (!fluids.isEmpty()) {
      fluidForTerrain = fluids.get(random.nextInt(fluids.size()));
      if (fluidForTerrain == null) {
        fluidForTerrain = Blocks.water; // This is the default.
      }
    } else {
      // If the terrain type is void we always pick water as the random liquid.
      if (terrainType == TerrainType.TERRAIN_VOID) {
        fluidForTerrain = Blocks.water;
      } else if (random.nextFloat() < WorldgenConfiguration.randomOceanLiquidChance) {
        DimletKey key = DimletRandomizer.getRandomFluidBlock(random);
        if (key != null) {
          dimensionInformation.updateCostFactor(key);
          fluidForTerrain = DimletObjectMapping.getFluid(key);
        } else {
          fluidForTerrain = Blocks.water;
        }
      } else {
        fluidForTerrain = Blocks.water;
      }
    }
    dimensionInformation.setFluidForTerrain(fluidForTerrain);
  }