Проблема при взаимодействии предметом по Entity

Версия Minecraft
1.19.2
API
Forge
10
1
0
Всем здравия и доброго времени суток.
Делаю свой первый мод. Тема - пивоварение. Решил добавить ему возможность добавлять в кружку не только пиво, но и молоко. В общем, скопировал код из класса коровы, на заполнение предмета, получилось вот так:
Java:
    @Override
    public InteractionResult interactLivingEntity(ItemStack itemStack, Player player, LivingEntity entity, InteractionHand hand) {
        Level level = player.getLevel();
        if (entity instanceof Cow && !entity.isBaby()) {
            player.playSound(SoundEvents.COW_MILK, 1.0f, 1.0f);
            ItemStack item = ItemUtils.createFilledResult(itemStack, player, ModItems.MILK_MUG.get().getDefaultInstance());
            player.setItemInHand(hand, item);
            return InteractionResult.sidedSuccess(level.isClientSide);
        } else {
            return super.interactLivingEntity(itemStack, player, entity, hand);
        }
    }
В итоге всё работает, но когда использую последнюю кружку, то она просто исчезает. Залез в ItemUtils, посмотрел createFilledResult и вроде всё должно работать как надо, даже если предмет последний, но почему-то оно не работает :/
Вот код самого createFilledResult:
Java:
    public static ItemStack createFilledResult(ItemStack itemStack1, Player player, ItemStack itemStack2, boolean p_41821_) {
        boolean $$4 = player.getAbilities().instabuild;
        if (p_41821_ && $$4) {
            if (!player.getInventory().contains(itemStack2)) {
                player.getInventory().add(itemStack2);
            }

            return itemStack1;
        } else {
            if (!$$4) {
                itemStack1.shrink(1);
            }
           
            if (itemStack1.isEmpty()) {
                return itemStack2;
            } else {
                if (!player.getInventory().add(itemStack2)) {
                    player.drop(itemStack2, false);
                }

                return itemStack1;
            }
        }
    }
   
    //То что я вызываю
    public static ItemStack createFilledResult(ItemStack itemStack1, Player player, ItemStack itemStack2) {
        return createFilledResult(itemStack1, player, itemStack2, true);
    }

Если что, то вот так выглядит код в классе коровы:
Java:
    public InteractionResult mobInteract(Player player, InteractionHand hand) {
        ItemStack $$2 = player.getItemInHand(hand);
        if ($$2.is(Items.BUCKET) && !this.isBaby()) {
            player.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F);
            ItemStack $$3 = ItemUtils.createFilledResult($$2, player, Items.MILK_BUCKET.getDefaultInstance());
            player.setItemInHand(hand, $$3);
            return InteractionResult.sidedSuccess(this.level.isClientSide);
        } else {
            return super.mobInteract(player, hand);
        }
    }

Заранее благодарю за помощь
 
Решение
Проблема решена.
Итоговый код взаимодействия:
Java:
@Override
public InteractionResult interactLivingEntity(ItemStack itemStack, Player player, LivingEntity entity, InteractionHand hand) {
    if (entity instanceof Cow && !entity.isBaby()) {
        player.playSound(SoundEvents.COW_MILK, 1.0f, 1.0f);
        ItemStack item = ItemUtils.createFilledResult(itemStack, player, ModItems.MILK_MUG.get().getDefaultInstance(), false);
        player.setItemInHand(hand, item);
    }
    return super.interactLivingEntity(itemStack, player, entity, hand);
}
Проблема была из-за того, что я писал (внимание на выделенные строки):
Java:
@Override
public InteractionResult interactLivingEntity(ItemStack itemStack, Player player, LivingEntity entity...
10
1
0
Код Milk_mug сейчас:
Java:
public class Milk_mug extends Item {
    public Milk_mug() {
        super(new Item.Properties().tab(BrewingTab.BREWING_TAB).stacksTo(2).food(new FoodProperties.Builder().alwaysEat().build()));
    }

    public ItemStack finishUsingItem(ItemStack itemStack, Level level, LivingEntity entity) {
        if (!level.isClientSide()) {
            entity.removeAllEffects();
        }

        if (entity instanceof ServerPlayer serverplayer) {
            CriteriaTriggers.CONSUME_ITEM.trigger(serverplayer, itemStack);
            serverplayer.awardStat(Stats.ITEM_USED.get(this));
        }

        if (entity instanceof Player && !((Player)entity).getAbilities().instabuild) {
            Player player = (Player) entity;
            itemStack.shrink(1);
            if (itemStack.isEmpty()) {
                new ItemStack(ModItems.EMPTY_MUG.get());
            } else {
                assert entity instanceof Player;
                new ItemStack(ModItems.EMPTY_MUG.get());
                if (player.getInventory().add(itemStack)) {
                    player.getInventory().add(itemStack);
                } else {
                    player.drop(itemStack, false);
                }
            }
        }
        return itemStack;
    }

    public UseAnim getUseAnimation(ItemStack itemStack) {
        return UseAnim.DRINK;
    }
}
Не обращайте внимания на "хлам" который я тут понаписал, это из-за того что его максимальный стек = 2. До сих пор пытаюсь как-то сделать это рабочим (костыль?)
А вообще я попытался изменить код на вид MilkBucketItem, но тогда если кружки 2 то 1 просто пропадает, а если 1 то выдаётся (ну в принципе логично)

UPD: заметил лишнюю строчку assert entity instanceof Player;, это осталось от прошлого вида кода, не обращайте внимания
UPD2: посмотрел на свой finishUsingItem и понимаю что я тут написал ряльно какое-то де... Крч, исправлять надо
 
Последнее редактирование:
116
13
13
Java:
if (!level.isClientSide()) {
    entity.removeAllEffects();
}
Код вызывается и на клиенте, и на сервере. Делай в начале проверку на клиента - если да, то выходи (если не нужны какая-то клиентская обработка)
Java:
if (player.getInventory().add(itemStack)) {
    player.getInventory().add(itemStack);
}
Оно вызывается 2 раза. Зачем?
Java:
new ItemStack(ModItems.EMPTY_MUG.get());
Смысла от его вызова - 0
который я тут понаписал, это из-за того что его максимальный стек = 2
Ну и что? Если нужно обработать ItemStack, в котором несколько элементов, то для этого вызывается ItemStack#shrink
 
1,371
112
241
Код Milk_mug сейчас:
Java:
public class Milk_mug extends Item {
    public Milk_mug() {
        super(new Item.Properties().tab(BrewingTab.BREWING_TAB).stacksTo(2).food(new FoodProperties.Builder().alwaysEat().build()));
    }

    public ItemStack finishUsingItem(ItemStack itemStack, Level level, LivingEntity entity) {
        if (!level.isClientSide()) {
            entity.removeAllEffects();
        }

        if (entity instanceof ServerPlayer serverplayer) {
            CriteriaTriggers.CONSUME_ITEM.trigger(serverplayer, itemStack);
            serverplayer.awardStat(Stats.ITEM_USED.get(this));
        }

        if (entity instanceof Player && !((Player)entity).getAbilities().instabuild) {
            Player player = (Player) entity;
            itemStack.shrink(1);
            if (itemStack.isEmpty()) {
                new ItemStack(ModItems.EMPTY_MUG.get());
            } else {
                assert entity instanceof Player;
                new ItemStack(ModItems.EMPTY_MUG.get());
                if (player.getInventory().add(itemStack)) {
                    player.getInventory().add(itemStack);
                } else {
                    player.drop(itemStack, false);
                }
            }
        }
        return itemStack;
    }

    public UseAnim getUseAnimation(ItemStack itemStack) {
        return UseAnim.DRINK;
    }
}
Не обращайте внимания на "хлам" который я тут понаписал, это из-за того что его максимальный стек = 2. До сих пор пытаюсь как-то сделать это рабочим (костыль?)
А вообще я попытался изменить код на вид MilkBucketItem, но тогда если кружки 2 то 1 просто пропадает, а если 1 то выдаётся (ну в принципе логично)

UPD: заметил лишнюю строчку assert entity instanceof Player;, это осталось от прошлого вида кода, не обращайте внимания
UPD2: посмотрел на свой finishUsingItem и понимаю что я тут написал ряльно какое-то де... Крч, исправлять надо
1. Код действительно дерьмо.
2. Вместо
&& !((Player)entity).getAbilities().instabuild
В вызов запихай просто false в последний аргумент.
3.
Вот так переменные в Java не именуются. Будь добр, называй переменные нормально.
4. Ты createFilledItem даже не вызываешь, откуда там браться нормальному результату?
5. И, наконец,
Можно заменить на entity instanceof Player player, таким образом
и
Player player = (Player) entity;
будут не нужны.
 
10
1
0
Вот так переменные в Java не именуются. Будь добр, называй переменные нормально.
Если вы про $$4, то это ванильный код майна если что. Я просто вставил, чтобы сразу было то, что я брал с ванили.
Ты createFilledItem даже не вызываешь, откуда там браться нормальному результату?
??? Простите, не понял
Можно заменить на entity instanceof Player player, таким образом
Понял, спасибо
 
Последнее редактирование:
10
1
0
Итоговый код:
Java:
    public ItemStack finishUsingItem(ItemStack itemStack, Level level, LivingEntity entity) {
        if (!level.isClientSide()) {
            entity.removeAllEffects();
            itemStack.shrink(1);
            if (entity instanceof ServerPlayer serverplayer) {
                CriteriaTriggers.CONSUME_ITEM.trigger(serverplayer, itemStack);
                serverplayer.awardStat(Stats.ITEM_USED.get(this));
            }

            if (entity instanceof Player && !((Player)entity).getAbilities().instabuild) {
                Player player = (Player) entity;
                if (itemStack.isEmpty()) {
                    return new ItemStack(ModItems.EMPTY_MUG.get());
                } else {
                    ItemStack item = new ItemStack(ModItems.EMPTY_MUG.get());
                    if (!player.getInventory().add(item)) {
                        player.drop(item, false);
                    }
                }
            }
        }
        return itemStack;
    }
Код вызывается и на клиенте, и на сервере. Делай в начале проверку на клиента - если да, то выходи (если не нужны какая-то клиентская обработка)
Надеюсь я правильно понял... Просто поскольку ему нужен результат (ведь он не void) я немного потупил. Был ещё другой вариант, но я решил так.
Оно вызывается 2 раза. Зачем?
Ну... Дурачок маленька 😅

Ну, с тем как я сейчас сделал, код кружки с молоком начал работать, а вот пустая кружка всё так и не пополняется, когда остаётся одна единственная
 
Последнее редактирование:
10
1
0
Код пустой кружки:
Java:
public class Empty_mug extends Item {
    private final float attackDamage = (float) 2;
    private final float attackSpeed = (float) -1.3;
    private final Multimap<Attribute, AttributeModifier> defaultModifiers;

    public Empty_mug() {
        super(new Item.Properties().tab(BrewingTab.BREWING_TAB).defaultDurability(-1).setNoRepair());
        ImmutableMultimap.Builder<Attribute, AttributeModifier> builder = ImmutableMultimap.builder();
        builder.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Weapon modifier", this.attackDamage, AttributeModifier.Operation.ADDITION));
        builder.put(Attributes.ATTACK_SPEED, new AttributeModifier(BASE_ATTACK_SPEED_UUID, "Weapon modifier", this.attackSpeed, AttributeModifier.Operation.ADDITION));
        this.defaultModifiers = builder.build();
    }

    @Override
    public InteractionResult interactLivingEntity(ItemStack itemStack, Player player, LivingEntity entity, InteractionHand hand) {
        Level level = player.getLevel();
        if (entity instanceof Cow && !entity.isBaby()) {
            player.playSound(SoundEvents.COW_MILK, 1.0f, 1.0f);
            ItemStack item = ItemUtils.createFilledResult(itemStack, player, ModItems.MILK_MUG.get().getDefaultInstance(), false);
            player.setItemInHand(hand, item);
            return InteractionResult.sidedSuccess(level.isClientSide);
        } else {
            return super.interactLivingEntity(itemStack, player, entity, hand);
        }
    }

    @Override
    public int getMaxStackSize(ItemStack stack) {
        return 16;
    }

    @Override
    public boolean isEnchantable(ItemStack itemStack) {
        return false;
    }



    @Override
    public Multimap<Attribute, AttributeModifier> getDefaultAttributeModifiers(EquipmentSlot slot) {
        return slot == EquipmentSlot.MAINHAND ? this.defaultModifiers : super.getDefaultAttributeModifiers(slot);
    }

}
Тут он весь, не как в начале, где только интеракт. Ну и тут теперь прямое обращение к createFilledResult, который
public static ItemStack createFilledResult(ItemStack itemStack1, Player player, ItemStack itemStack2, boolean p_41821_) { boolean $$4 = player.getAbilities().instabuild; if (p_41821_ && $$4) { if (!player.getInventory().contains(itemStack2)) { player.getInventory().add(itemStack2); } return itemStack1; } else { if (!$$4) { itemStack1.shrink(1); } if (itemStack1.isEmpty()) { return itemStack2; } else { if (!player.getInventory().add(itemStack2)) { player.drop(itemStack2, false); } return itemStack1; } } }
Подумал что так будет лучше, да и по итогу возымел возможность вечно пополнять кружки в креативе, а не как было раньше.
 
Последнее редактирование:
1,371
112
241
Ну хз, у меня вот такой код отрабатывает исправно:
Java:
        @Override
        public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
            if(!level.isClientSide)
                player.setItemInHand(hand, ItemUtils.createFilledResult(player.getItemInHand(hand), player, Items.ENCHANTED_CORE.get().getDefaultInstance()));
            return super.use(level, player, hand);
        }

И да, у тебя куча лишних вещей в классе.
 
10
1
0
Ну хз, у меня вот такой код отрабатывает исправно:
Щас буду значит "экспериментировать"
И да, у тебя куча лишних вещей в классе.
Абсолютно не удивлён. Ну что с новичка взять, когда-нибудь буду понимать лучше. Спасибо за помощь и подсказки. Если найду выход отпишусь
 
10
1
0
Проблема решена.
Итоговый код взаимодействия:
Java:
@Override
public InteractionResult interactLivingEntity(ItemStack itemStack, Player player, LivingEntity entity, InteractionHand hand) {
    if (entity instanceof Cow && !entity.isBaby()) {
        player.playSound(SoundEvents.COW_MILK, 1.0f, 1.0f);
        ItemStack item = ItemUtils.createFilledResult(itemStack, player, ModItems.MILK_MUG.get().getDefaultInstance(), false);
        player.setItemInHand(hand, item);
    }
    return super.interactLivingEntity(itemStack, player, entity, hand);
}
Проблема была из-за того, что я писал (внимание на выделенные строки):
Java:
@Override
public InteractionResult interactLivingEntity(ItemStack itemStack, Player player, LivingEntity entity, InteractionHand hand) {
    Level level = player.getLevel();
    if (entity instanceof Cow && !entity.isBaby()) {
    player.playSound(SoundEvents.COW_MILK, 1.0f, 1.0f);
        ItemStack item = ItemUtils.createFilledResult(itemStack, player, ModItems.MILK_MUG.get().getDefaultInstance());
        player.setItemInHand(hand, item);
        return InteractionResult.sidedSuccess(level.isClientSide);
    } else {
        return super.interactLivingEntity(itemStack, player, entity, hand);
    }
}
Проще говоря, просто убрал InteractionResult.sidedSuccess(level.isClientSide); и оставил только return super.interactLivingEntity(itemStack, player, entity, hand);

Благодарю всех, кто писал. SupCM, ваш ответ
Ну хз, у меня вот такой код отрабатывает исправно:
Java:
        @Override
        public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
            if(!level.isClientSide)
                player.setItemInHand(hand, ItemUtils.createFilledResult(player.getItemInHand(hand), player, Items.ENCHANTED_CORE.get().getDefaultInstance()));
            return super.use(level, player, hand);
        }
всё-таки помог, я бы ещё долго думал убрать эту лишнюю часть
 
Последнее редактирование:
Сверху