Skip to content

伤害类型与伤害来源

字数
1627 字
阅读时间
7 分钟

伤害类型与伤害来源

伤害类型表示对实体施加的伤害类型——物理伤害、火焰伤害、溺水伤害、魔法伤害、虚空伤害等。伤害类型的区分用于各种免疫(例如烈焰人不会受到火焰伤害)、附魔(例如爆炸保护仅对爆炸伤害有效)以及更多用例。

伤害类型可以说是伤害来源的模板。换句话说,伤害来源可以被视为伤害类型的实例。伤害类型在代码中以 ResourceKey 的形式存在,但其所有属性都在数据包中定义。另一方面,伤害来源是根据数据包文件中的值在需要时由游戏创建的。它们可以保存额外的上下文,例如攻击实体。

创建伤害类型

首先,您需要创建自己的 DamageTypeDamageType 是一个数据包注册表,因此新的 DamageType 不是在代码中注册的,而是在添加相应文件时自动注册的。然而,我们仍然需要为代码提供一个获取伤害来源的入口。我们通过指定一个资源键来实现这一点:

java
public static final ResourceKey<DamageType> EXAMPLE_DAMAGE =
        ResourceKey.create(Registries.DAMAGE_TYPE, ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "example"));

现在我们可以从代码中引用它,让我们在数据文件中指定一些属性。我们的数据文件位于 data/examplemod/damage_type/example.json(将 examplemodexample 替换为 Mod ID 和资源位置的名称),并包含以下内容:

json
{
    // 伤害类型的死亡消息 ID。完整的死亡消息翻译键将是 "death.examplemod.example"(替换为相应的 Mod ID 和名称)。
    "message_id": "example",
    // 此伤害类型的伤害值是否随难度变化。有效的原版值为:
    // - "never":伤害值在任何难度下保持不变。通常用于玩家造成的伤害类型。
    // - "when_caused_by_living_non_player":如果伤害是由某种生物(包括间接造成的,例如骷髅射出的箭)但不是玩家造成的,则伤害值会缩放。
    // - "always":伤害值总是缩放。通常用于类似爆炸的伤害。
    "scaling": "when_caused_by_living_non_player",
    // 受到此类伤害时消耗的饥饿值。
    "exhaustion": 0.1,
    // 受到此类伤害时应用的伤害效果(目前仅为音效)。可选。
    // 有效的原版值为 "hurt"(默认)、"thorns"、"drowning"、"burning"、"poking" 和 "freezing"。
    "effects": "hurt",
    // 死亡消息类型。决定死亡消息的构建方式。可选。
    // 有效的原版值为 "default"(默认)、"fall_variants" 和 "intentional_game_design"。
    "death_message_type": "default"
}

提示scalingeffectsdeath_message_type 字段在内部分别由枚举 DamageScalingDamageEffectsDeathMessageType 控制。如果需要,可以扩展这些枚举以添加自定义值。

相同的格式也用于原版的伤害类型,如果需要,包开发者可以更改这些值。

创建和使用伤害来源

DamageSource 通常在调用 Entity#hurt 时动态创建。请注意,由于伤害类型是数据包注册表,您需要 RegistryAccess 来查询它们,可以通过 Level#registryAccess 获取。要创建 DamageSource,请调用 DamageSource 构造函数,最多接受四个参数:

java
DamageSource damageSource = new DamageSource(
        // 要使用的伤害类型持有者。从注册表中查询。这是唯一必需的参数。
        registryAccess.registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(EXAMPLE_DAMAGE),
        // 直接实体。例如,如果骷髅射中了你,骷髅将是造成伤害的实体(= 上面的参数),而箭将是直接实体(= 此参数)。与造成伤害的实体类似,这并不总是适用,因此可以为空。可选,默认为 null。
        null,
        // 造成伤害的实体。这并不总是适用(例如,当从世界掉落时),因此可以为空。可选,默认为 null。
        null,
        // 伤害来源的位置。这很少使用,一个例子是故意游戏设计(= 下界床爆炸)。可为空且可选,默认为 null。
        null
);

警告DamageSources#sourcenew DamageSource 的包装器,它交换了第二个和第三个参数(直接实体和造成伤害的实体)。请确保您将正确的值传递给正确的参数。

如果 DamageSource 没有任何实体或位置上下文,将其缓存在字段中是有意义的。对于具有实体或位置上下文的 DamageSource,通常会添加辅助方法,如下所示:

java
public static DamageSource exampleDamage(Entity causer) {
    return new DamageSource(
            causer.level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(EXAMPLE_DAMAGE),
            causer);
}

提示:原版的 DamageSource 工厂可以在 DamageSources 中找到,原版的 DamageType 资源键可以在 DamageTypes 中找到。

伤害来源的首要用例是 Entity#hurt。每当实体受到伤害时,都会调用此方法。要使用我们自己的伤害类型伤害实体,我们只需自己调用 Entity#hurt

java
// 第二个参数是伤害量,以半颗心为单位。
entity.hurt(exampleDamage(player), 10);

其他伤害类型特定的行为,例如无敌检查,通常通过伤害类型标签运行。这些标签由 Minecraft 和 NeoForge 添加,可以分别在 DamageTypeTagsTags.DamageTypes 中找到。

数据生成

有关更多信息,请参见 数据包注册表的数据生成

伤害类型 JSON 文件可以数据生成。由于伤害类型是数据包注册表,我们将 DatapackBuiltinEntriesProvider 添加到 GatherDataEvent 中,并将我们的伤害类型放入 RegistrySetBuilder 中:

java
// 在您的数据生成类中
@SubscribeEvent
public static void onGatherData(GatherDataEvent event) {
    CompletableFuture<HolderLookup.Provider> lookupProvider = event.getLookupProvider();
    event.getGenerator().addProvider(
            event.includeServer(),
            output -> new DatapackBuiltinEntriesProvider(output, lookupProvider, new RegistrySetBuilder()
                    // 为伤害类型添加数据包内置条目提供者。如果此 lambda 变得更长,
                    // 为了可读性,应将其提取到单独的方法中。
                    .add(Registries.DAMAGE_TYPE, bootstrap -> {
                        // 使用 new DamageType() 创建伤害类型的代码表示。
                        // 参数按上述顺序映射到 JSON 文件的值。
                        // 除了消息 ID 和饥饿值之外的所有参数都是可选的。
                        bootstrap.register(EXAMPLE_DAMAGE, new DamageType(EXAMPLE_DAMAGE.location(),
                                DamageScaling.WHEN_CAUSED_BY_LIVING_NON_PLAYER,
                                0.1f,
                                DamageEffects.HURT,
                                DeathMessageType.DEFAULT))
                    })
                    // 如果适用,添加其他数据包条目的数据包提供者。
                    .add(...),
                    Set.of(ExampleMod.MOD_ID)
            )
    );
}

贡献者

The avatar of contributor named as 小飘 小飘

文件历史