# 了解自定义特征规则

在第六章中,我们已经初步学期了如何通过编辑器制作一个特征规则Feature Rule,又译地物规则)。在本节中,我们将从JSON的层面更详细地了解特征规则。

# 了解特征规则文件

我们先来查看我们之前使用编辑器制作的那个特征规则的代码:

{
  "format_version": "1.14.0",
  "minecraft:feature_rules": {
    "description": {
      "identifier": "tutorial_demo:demo_feature_rules",
      "places_feature": "tutorial_demo:demo_feature"
    },
    "conditions": {
      "placement_pass": "surface_pass"
    },
    "distribution": {
      "coordinate_eval_order": "xzy",
      "iterations": 1,
      "scatter_chance": 10,
      "x": {
        "distribution": "uniform",
        "extent": [
          0,
          16
        ]
      },
      "y": "query.get_height_at(variable.originx,variable.originz)-3",
      "z": {
        "distribution": "uniform",
        "extent": [
          0,
          16
        ]
      }
    }
  }
}

我们可以看到,特征规则是可以放在netease_feature_rules文件夹中的,使用的模式标识符皆为minecraft:feature_rules,并且在这里我们使用的是1.14.0的格式版本。事实上,我们也可以使用1.13.01.16.0的格式版本。

在模式标识符下有三个字段,分别是descriptionconditionsdistribution,分别是该特征规则的描述、条件和分布。其中,我们可以看到分布对象distribution中的内容非常地熟悉。没错,这里和散植特征的格式是完全一致的。其实,每一个已定义的特征规则都会在游戏生成生物群系的不同阶段上逐区块地执行一次类似于散植特征的逻辑。简单地说,在每个区块上,特征规则都会随机选取一个点,然后以该点为起始点做一次散植,因此,我们可以在distribution对象中定义一套与散植特征相同格式的字段。唯一的不同是,散植特征中的places_feature字段在这里被移动到了描述对象description中。

条件对象conditions则用于定义特征规则放置特征的条件,其中placement_pass便是我们之前在第六章中便接触过的特征放置阶段Placement Pass)的定义。这里我们使用了surface_pass来代表在生成器生成地形中的地表阶段放置。

在我们这个示例中,三个轴向的坐标的串演算顺序为xzy。同时,我们可以看到y字段中使用了获得X轴和Z轴起始点处的世界高度的Molang查询函数。如果Y轴先于X、Z轴演算,则我们无法通过变量得到X和Z轴的起始点坐标。那么我们目前的逻辑就会失效,这也是为什么我们将串演算顺序调整成了xzy的原因。

我们再来看一个原版特征规则的示例:

{
  "format_version": "1.13.0",
  "minecraft:feature_rules": {
    "description": {
      "identifier": "minecraft:bamboo_jungle_after_surface_bamboo_feature",
      "places_feature": "minecraft:bamboo_then_podzol_feature"
    },
    "conditions": {
      "placement_pass": "after_surface_pass",
      "minecraft:biome_filter": [
        {
          "test": "has_biome_tag",
          "operator": "==",
          "value": "bamboo"
        },
        {
          "test": "has_biome_tag",
          "operator": "==",
          "value": "jungle"
        }
      ]
    },
    "distribution": {
      "iterations": "math.clamp(math.trunc(math.ceil((query.noise(math.trunc(variable.originx / 80), math.trunc(variable.originz / 80)) + 0.3) * 160)), 15, 160)",
      "x": {
        "distribution": "uniform",
        "extent": [ 0, 16 ]
      },
      "y": "query.heightmap(variable.worldx, variable.worldz)",
      "z": {
        "distribution": "uniform",
        "extent": [ 0, 16 ]
      }
    }
  }
}

这里我们可以看到,conditions字段下多了一个minecraft:biome_filter条件。这个条件是用于过滤生物群系的。通过一个或多个过滤器的线性排列或逻辑组合,我们可以使特征规则仅在特定的生物群系下放置特征,这实现了规则驱动的特征放置,这样放置出的特征也正是我们先前所说的自动型特征Automatic Feature,又译自动型地物),即隐式特征Implicit Feature,又译隐式地物)。

所以,从宏观上看,我们有两种放置特征的方式,一种是通过特征规则通过条件自动控制放置的隐式特征,另一种是通过生物群系的定义强制放置的显式特征。

至此,我们便基本学习了特征和特征规则的写法。接下来的几个小节,我们一起通过各种演示亲自操作,将各种特征的定义与生成的编写落到实处。