2025年1月28日火曜日

forge Mod で作成したブロックやアイテムに名前やプロパティを設定する方法

forge Mod で作成したブロックやアイテムに名前やプロパティを設定する方法

概要

デフォルトでは「item.examplemod.laser_gun」のように内部で扱っている名前空間+ID形式で表示されてしまうので適切な名前を設定する方法を紹介します
また武器の場合にはダメージ量などのプロパティ情報も表示したいのでその情報を表示する方法も紹介します

環境

  • macOS 15.2
  • Java 21.0.5
  • forrge MDK 1.20.6-50.1.32
  • minecraft 1.20.6

ローカライズファイルの作成

まずは名前を設定します
各言語のファイルを配置すれば言語ごとに名前の表示を設定できます

  • mkdir -p src/main/resources/assets/examplemod/lang/
  • vim src/main/resources/assets/examplemod/lang/en_us.json
{
    "item.examplemod.laser_gun": "Laser Gun",
    "item.examplemod.laser_gun.damage": "+%s Attack Damage",
    "item.examplemod.laser_gun.description": "A high-tech laser gun capable of dealing massive damage."
}

appendHoverText の実装

名前だけ変えたいのであれば上記の json だけ追加すれば OK です
今回は武器の説明も追加したいので前回追加した LaserGunItem クラスに appendHoverText をオーバライドし説明文を追加します

package com.example.examplemod;

import java.util.List;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;

public class LaserGunItem extends Item {
    private float amountOfdamage = 10.0F; // ダメージ量

    public LaserGunItem(Properties properties) {
        super(properties);
    }

    @Override
    public InteractionResultHolder<ItemStack> use(
            Level world, Player player, InteractionHand hand) {
        // クライアント側のみでエフェクトを表示
        if (world.isClientSide()) {
            // ビームエフェクトを生成
            spawnLaserBeam(player);
        } else {
            // サーバー側でダメージ処理
            fireLaser(world, player);
        }
        return InteractionResultHolder.sidedSuccess(
                player.getItemInHand(hand), world.isClientSide());
    }

    @Override
    public void appendHoverText(
            ItemStack stack,
            Item.TooltipContext context,
            List<Component> tooltip,
            TooltipFlag flag) {
        super.appendHoverText(stack, context, tooltip, flag);
        // ダメージ情報を追加
        tooltip.add(
                Component.translatable("item.examplemod.laser_gun.damage", amountOfdamage)
                        .withStyle(ChatFormatting.GREEN));

        // 他の情報も追加可能
        tooltip.add(
                Component.translatable("item.examplemod.laser_gun.description")
                        .withStyle(ChatFormatting.GRAY));
    }

    @Override
    public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) {
        // 特殊な処理が必要であればここで行う(今回は不要なのでデフォルト動作に任せます)
        // アイテムが q で捨てられたときにアイテムとして残すための設定
        return super.onEntityItemUpdate(stack, entity);
    }

    private void spawnLaserBeam(Player player) {
        // クライアント側エフェクト(例:パーティクル)
        player.level()
                .addParticle(
                        ParticleTypes.END_ROD,
                        player.getX(),
                        player.getEyeY(),
                        player.getZ(),
                        player.getLookAngle().x,
                        player.getLookAngle().y,
                        player.getLookAngle().z);
    }

    private void fireLaser(Level world, Player player) {
        Vec3 start = player.getEyePosition(1.0F);
        Vec3 direction = player.getLookAngle();
        double range = 50.0D; // 50ブロック先をターゲット
        Vec3 end = start.add(direction.scale(range));

        // ブロックとのヒット判定
        HitResult blockHit =
                world.clip(
                        new ClipContext(
                                start,
                                end,
                                ClipContext.Block.OUTLINE,
                                ClipContext.Fluid.NONE,
                                player));
        // エンティティとのヒット判定
        EntityHitResult entityHit =
                ProjectileUtil.getEntityHitResult(
                        world,
                        player,
                        start,
                        end,
                        player.getBoundingBox().expandTowards(direction.scale(range)).inflate(1.0D),
                        entity -> entity instanceof LivingEntity && entity != player);
        // 優先的にエンティティを処理
        if (entityHit != null) {
            System.out.println("Hit entity!");
            Entity hitEntity = entityHit.getEntity();
            if (hitEntity instanceof LivingEntity livingEntity) {
                // 敵にダメージを与える
                livingEntity.hurt(
                        livingEntity.damageSources().playerAttack(player), amountOfdamage);
            }
        } else if (blockHit != null && blockHit.getType() == HitResult.Type.BLOCK) {
            // ブロックにヒットした場合
            System.out.println("Hit block at: " + ((BlockHitResult) blockHit).getBlockPos());
            BlockHitResult blockResult = (BlockHitResult) blockHit;
            BlockPos hitPos = blockResult.getBlockPos();
            // ヒット位置に火をつける例
            world.setBlockAndUpdate(hitPos, Blocks.FIRE.defaultBlockState());
        } else {
            // 何にも当たらなかった場合
            System.out.println("Missed!");
        }
    }
}

追加した部分は appendHoverText の部分でここで先程の json のダメージ文と説明文の情報を取得してプロパティとして設定しています
これでインベントリ内の武器をホバーしたときにダイヤモンドの剣のようにダメージ量などが表示されるようになります

@Override
public void appendHoverText(
        ItemStack stack,
        Item.TooltipContext context,
        List<Component> tooltip,
        TooltipFlag flag) {
    super.appendHoverText(stack, context, tooltip, flag);
    // ダメージ情報を追加
    tooltip.add(
            Component.translatable("item.examplemod.laser_gun.damage", amountOfdamage)
                    .withStyle(ChatFormatting.GREEN));

    // 他の情報も追加可能
    tooltip.add(
            Component.translatable("item.examplemod.laser_gun.description")
                    .withStyle(ChatFormatting.GRAY));
}

動作確認

  • ./gradlew clean && ./gradlew build && ./gradlew runClient

インベントリ内でちゃんと説明文が追加されていることを確認しましょう

最後に

追加したアイテムやブロックに名前そしてプロパティなどの追加文章を追加する方法を紹介しました 余裕があればローカライズファイルを増やして多言語化するといいかなと思います

他のドキュメントを見ると getDefaultAttributeModifiers をオーバライドしてダメージなどを設定することができるようなのですがこのメソッドは 1.20.6 では非推奨になっているので今回は使っていません

参考サイト

0 件のコメント:

コメントを投稿