Minecraft 1.12.2 Mod开发笔记——新的附魔类型和状态效果(药水)

新的附魔

我们试着给剑创建一个叫引爆的附魔。

在 moonfan.mymod.enchantment 包下新建类 EnchantmentIgnite.java

public class EnchantmentIgnite extends Enchantment {
    protected EnchantmentIgnite() {
        super(Rarity.COMMON, EnumEnchantmentType.WEAPON, new EntityEquipmentSlot[]{EntityEquipmentSlot.MAINHAND});
        // 设置非本地化名称
        this.setName("ignite_enchantment");
    }
}

来看构造器 protected Enchantment(Enchantment.Rarity rarityIn, EnumEnchantmentType typeIn, EntityEquipmentSlot[] slots)

  • rarityIn 枚举类,表示附魔的稀有程度,有 COMMON、UNCOMMON、RARE 和 VERY_RARE 四种。
  • typeIn 枚举类,表示可以接收该附魔的物品种类,有 ALL、WEAPON、ARMOR 等多种类型。
  • slots 枚举类数组,表示被附魔的物品处于何种状态时附魔生效,有 MAINHAND、OFFHAND、FEET、LEGS、CHEST、HEAD 六种。

附魔和物品一样需要注册:

public class EnchantmentLoader {
    public static Enchantment ignite = new EnchantmentIgnite();

    @SubscribeEvent
    public static void registerEnchantment(RegistryEvent.Register<Enchantment> event){
        event.getRegistry().register(ignite.setRegistryName("mymod:ignite_enchantment"));
    }
}

en_us.lang:

enchantment.ignite_enchantment=Ignite

现在,可以通过 /give 命令或者附魔台得到带有这个附魔的剑了。但附魔本身只规定种类,并不规定其效果,效果的实现需要在需要的地方添加,比如时运和精准采集的效果其实是在 Block 类里判断方块掉落的时候添加的。在进阶部分再作说明。

新的状态效果(药水)

Minecraft 中,状态效果和药水是两个概念,喝了药水可以出现状态效果,而有状态效果不一定要有对应的药水,比如饥饿效果、凋零效果。

我们先创建一个叫类似于中毒的持续扣血效果。

在 moonfan.mymod.potion 包下新建类 PotionInjure.java

public class PotionInjure extends Potion {
    protected PotionInjure() {
        super(true, 0xffffff);
        // 这里是设置的是实际的名称,不是非本地化名称
        setPotionName("injured");
    }
}

构造器 protected Potion(boolean isBadEffectIn, int liquidColorIn)

  • isBadEffectIn 是否是负面效果
  • liquidColorIn 状态效果的气泡以及药水瓶(如果有)的RGB颜色值,比如0xffffff

状态效果和物品一样需要注册:

@Mod.EventBusSubscriber
public class PotionLoader {
    public static Potion injure = new PotionInjure();
    @SubscribeEvent
    public static void registerPotion(RegistryEvent.Register<Potion> event){
        event.getRegistry().register(injure.setRegistryName("mymod:injure"));
    }
}

现在,我们可以用命令 /effect 玩家名 mymod:injure 120 0 来给自己加上Ⅰ级,持续时间120s的 injured 效果了,不知道 harbinger 的教程里是不是把命令打错了。。

药水类型

前面说过,状态效果和药水是两回事,当创建了药水类型后,创造模式药水栏里将会自动添加该药水类型的普通型/喷溅型/滞留型的药水瓶武器栏里会自动添加对应效果的弓箭。喝下一种药水可以获得多种状态效果,因此药水类型可以接收多个状态效果参数:

在PotionLoader里添加事件:

@SubscribeEvent
public static void registerPotionType(RegistryEvent.Register<PotionType> event){
    event.getRegistry().register(new PotionType(new PotionEffect(injure)).setRegistryName("mymod:injuring"));
}

其中药水类型的构造器,乱七八糟的变量名大概是MCP项目没有翻译出来?

public PotionType(@Nullable String p_i46740_1_, PotionEffect... p_i46740_2_)
public PotionType(PotionEffect... p_i46739_1_)
  • String 类型的参数可以省略,相当于非本地化名称,如果省略或者填 null,自动用注册名作为非本地化名称。
  • PotionEffect 类型的参数是一个可变长参数,代表药水触发的一个或多个状态效果。

由于有普通型/喷溅型/滞留型三种药水瓶以及药水效果的弓箭,非本地化键也相应的有 potion.effect./splash_potion.effect./ingering_potion.effect./tipped_arrow.effect. 四个前缀,也就是说创建一个药水类型,在.lang语言文件里要写四条翻译文本。

添加状态效果的实际作用

和附魔不太一样的地方,状态效果并不全都需要在需要的事件监听里独立写逻辑。总结一下,状态效果有三大类:

  • 修改状态属性类,比如迟缓/失明/挖掘疲劳/急迫等等,这些是一种对生物自身属性的更改,在构造器里使用 this.registerPotionAttributeModifier()

    public Potion registerPotionAttributeModifier(IAttribute attribute, String uniqueId, double ammount, int operation)
    • attribute 修改的生物自身属性,可使用 SharedMonsterAttributes 类中的字段
    • uniqueId UUID,暂不清楚,参考原版 net/minecraft/potion/Potion.java (432行) 中写的的参数。
    • ammount 调整数量,比如-1.0D
    • operation 暂不清楚,参考原版 Potion 类中写的的参数。
  • 周期性效果类,比如中毒/凋零,这样的状态效果通过重写 performEffect()isReady() 实现:

    @Override
    public void performEffect(EntityLivingBase entityLivingBaseIn, int amplifier) {
        entityLivingBaseIn.attackEntityFrom(DamageSource.MAGIC, 6.0f);
    }
    @Override
    public boolean isReady(int duration, int amplifier) {
        int j = 25 >> amplifier;
        if (j > 0) { return duration % j == 0;} 
        else { return true;}
    }
    • performEffect() 中写你想周期性触发的任何事情。这里写的意思是生物受到6点魔法(药水)伤害。除了上面写的掉血,你还可以触发爆炸来实现人肉轰炸等等。
    • amplifier 指的是药水等级,0为Ⅰ级
    • isReady() 中控制触发周期,比如上面就是原版的中毒状态的代码
  • 其他效果类,比如 ustc_zzzz 教程中的摔落保护效果,属于事件触发,需要监听事件,这里就不展开了,之后再说。

药水合成表

使用 BrewingRecipeRegistry.addRecipe() 创建,同样可以把这个写在上一篇的 Recipes 类构造器里。

public static boolean addRecipe(ItemStack input, ItemStack ingredient, ItemStack output)
  • input 药水瓶的位置
  • ingredient 地狱疣/火药等配方的位置
  • output 产物
上一篇:理解C++中的头文件和源文件的作用【转】


下一篇:Minecraft正版登录(获取32位token)