概要
- マインクラフトに新しいエンチャントを追加します。
- 切った対象にエヴォーカーファングを追尾させる「魔術」を追加します。
コード
新しいエンチャントのクラス作成
Enchantmentを継承して作成します。
ForbiddenSorceryEnchantment
package com.example.examplemod.EditHere.enchant;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.monster.Evoker;
import net.minecraft.world.entity.projectile.EvokerFangs;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentCategory;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.NotNull;
public class ForbiddenSorceryEnchantment extends Enchantment {
public ForbiddenSorceryEnchantment(){
super(Rarity.VERY_RARE, EnchantmentCategory.WEAPON, new EquipmentSlot[]{EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND});
}
// 最小のエンチャントコストを取得するメソッド
@Override
public int getMinCost(int pLevel) {
return super.getMinCost(pLevel);
}
// 最大のエンチャントコストを取得するメソッド
@Override
public int getMaxCost(int pLevel) {
return super.getMaxCost(pLevel);
}
// レアリティを取得するメソッド
@Override
public @NotNull Rarity getRarity() {
return Rarity.VERY_RARE;
}
// 最小のエンチャントレベルを取得するメソッド
@Override
public int getMinLevel() {
return super.getMinLevel();
}
// 最大のエンチャントレベルを取得するメソッド
// 10まではローマ数字で表してくれる
@Override
public int getMaxLevel() {
return 10;
}
// 呪いかどうか。呪いなら赤色になる。
@Override
public boolean isCurse() {
return true;
}
@Override
public void doPostAttack(@NotNull LivingEntity pAttacker, @NotNull Entity pTarget, int pLevel) {
Level level=pAttacker.level;
// サーバーサイドで実行
if(level instanceof ServerLevel){
// プレイヤーの視線のy軸回転(Yaw)を取得
float yaw=pAttacker.getYRot();
// エンチャントレベルに応じて射程を変える
int[] angles={0, -30, 30};
for(int angleOffset:angles){
// 距離1ブロックからエンチャントレベル分のブロック数だけファングを生成
for(int i=1; i<pLevel; i++){
// 角度と距離から座標を計算
double rad=Math.toRadians(yaw+angleOffset+90);
double x=pAttacker.getX()+(double) i*Math.cos(rad);
double z=pAttacker.getZ()+(double) i*Math.sin(rad);
spawnFang(level, x, z, pAttacker.getY(), pAttacker, yaw, i);
}
}
}
}
// 指定されたx, z座標の地面を探し、そこにファングをスポーンさせるメソッド
private void spawnFang(Level level, double x, double z, double attackerY, LivingEntity owner, float yaw, int delay){
BlockPos pos=new BlockPos(x, attackerY, z);
boolean foundGround=false;
double yOffset=0.0D;
// プレイヤーの高さから上下に地面を探す範囲
// 下に掘り下げる
for(int i=0; i>=-2; i--){
BlockPos checkPos=pos.above(i);
BlockState state=level.getBlockState(checkPos);
BlockState belowState=level.getBlockState(checkPos.below());
// 下が頑丈なブロックかつ今の場所が空気や通り抜けられるものなら地面だと判定する
if(belowState.isFaceSturdy(level, checkPos.below(), Direction.UP) && !state.getMaterial().isSolid()){
// 厳密な高さ調整(ハーフブロックや積雪対応)
if(!level.isEmptyBlock(checkPos)){
VoxelShape shape=state.getCollisionShape(level, checkPos);
if(!shape.isEmpty()){
yOffset=shape.max(Direction.Axis.Y);
}
}
pos=checkPos;
foundGround=true;
break;
}
}
// 地面が見つかった場合のみスポーン
if(foundGround){
level.addFreshEntity(new EvokerFangs(level, x, pos.getY()+yOffset, z, yaw, delay, owner));
}
}
}
Example Modでの登録
public static final Enchantment FORBIDDEN_SORCERY=new ForbiddenSorceryEnchantment().setRegistryName(MODID,"forbidden_sorcery");
専用のレジストリに登録。(新しく作る)
@SubscribeEvent
public static void onEnchantmentsRegistry(final RegistryEvent.Register<Enchantment> event){
IForgeRegistry<Enchantment> registry=event.getRegistry();
registry.register(FORBIDDEN_SORCERY);
}
補遺
新しいエンチャントを作ると自動でエンチャントの本も生成される。