Нубовопрос по таймеру "в рендере"

Версия Minecraft
1.7.10
API
Forge
341
14
113
Делаю сундука-мимика - когда к нему подходит игрок, он меняет текстуру с моделью(в рендере начинаются приколюхи вроде партиклов и т.п.) и наносит плееру урон.
Под "подходит игрок" подразумевается событие, в результате которого в мобе некий параметр N принимает значение true, что и стоит в условии появления эффектов в рендере.
Одна проблема - хочется, чтобы эти приколюхи были не бесконечными, а, скажем, шли десять секунд.

Т.е. когда в рендере некий параметр N == true и, если с того момента, как он стал истинным, не прошло десять секунд, рендерится одно. Если прошло - независимо от значения N, то другое. При этом, если событие снова сработало, и N снова стал true, то снова нужно запустить таймер*, и т.д.

Сегодня пытался это реализовать, но окончательно закопался. Я слишком слаб для моддинга. Не подскажете нужную инструкцию по проверке этого условия, или то, что я хочу, требует какой-то слишком сложной реализации или больших деталей?
*Ждать, пока либо N не обратится в false, либо не пройдет время, выполняя определенную инструкцию.
 
Решение
Не знаю, насколько это правильно с точки зрения возможной реализации, но вот как подобное действие выполняю я:
У меня есть предмет, который, скажем, можно активировать нажатием ПКМ. Затем, спустя 10 секунд после активации предмет нужно автоматически деактивировать.
Для достижения этой цели я засовываю в предмет НБТ-тэг, при использовании итема ставлю ему значение 0, а затем в методе onUpdate() задаю, что:
Если предмет активирован, и если НБТ-тэг времени меньше 10 - добавлять к значению единицу. Затем от условия на время пишу else, и в этом блоке уже указываю, что НБТ времени нужно установить на 0 (не обязательно, но на всякий случай), а сам предмет деактивировать.
В твоем случае у тебя моб, а-ка энтить. По аналогии с моей реализацией ты...
205
12
103
Не знаю, насколько это правильно с точки зрения возможной реализации, но вот как подобное действие выполняю я:
У меня есть предмет, который, скажем, можно активировать нажатием ПКМ. Затем, спустя 10 секунд после активации предмет нужно автоматически деактивировать.
Для достижения этой цели я засовываю в предмет НБТ-тэг, при использовании итема ставлю ему значение 0, а затем в методе onUpdate() задаю, что:
Если предмет активирован, и если НБТ-тэг времени меньше 10 - добавлять к значению единицу. Затем от условия на время пишу else, и в этом блоке уже указываю, что НБТ времени нужно установить на 0 (не обязательно, но на всякий случай), а сам предмет деактивировать.
В твоем случае у тебя моб, а-ка энтить. По аналогии с моей реализацией ты вводишь в метод обновления таймер, и ежесекундно его изменяешь при необходимых тебе условиях, а уже в зависимости от них возвращаешь true/false для того, что ты хотел бы реализовать.

Вот тебе пример из моего итема (под 1.16.4). Аналогичные методы для энтити в 1.7 найдешь, думаю, ибо принцип там похожий, за исключением процесса установки.

SpatialSignItem:
package it.hurts.sskirillss.relics.items;

import it.hurts.sskirillss.relics.init.ItemRegistry;
import it.hurts.sskirillss.relics.utils.EntityUtils;
import it.hurts.sskirillss.relics.utils.NBTUtils;
import it.hurts.sskirillss.relics.utils.RelicsConfig;
import it.hurts.sskirillss.relics.utils.RelicsTab;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

import javax.annotation.Nullable;
import java.util.List;

public class SpatialSignItem extends Item {
    public static final String TAG_POSITION = "position";
    public static final String TAG_TIME = "time";

    public SpatialSignItem() {
        super(new Item.Properties()
                .group(RelicsTab.RELICS_TAB));
    }

    @Override
    public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) {
        ItemStack itemStack = playerIn.getHeldItem(handIn);
        if (NBTUtils.getString(itemStack, TAG_POSITION, "").equals("")) {
            if (!playerIn.isSneaking()) {
                NBTUtils.setString(itemStack, TAG_POSITION, Math.round(playerIn.getPosX()) + "," + Math.round(playerIn.getPosY()) + "," + Math.round(playerIn.getPosZ()));
                NBTUtils.setInt(itemStack, TAG_TIME, RelicsConfig.SpatialSign.timeBeforeActivation * 20);
            }
        } else {
            if (playerIn.isSneaking()) {
                activateSign(itemStack, playerIn, false);
                itemStack.damageItem(1, playerIn, (player) -> playerIn.sendBreakAnimation(handIn));
            }
        }
        return super.onItemRightClick(worldIn, playerIn, handIn);
    }

    @Override
    public void inventoryTick(ItemStack stack, World worldIn, Entity entityIn, int itemSlot, boolean isSelected) {
        PlayerEntity player = (PlayerEntity) entityIn;
        if (!NBTUtils.getString(stack, TAG_POSITION, "").equals("") && player.ticksExisted % 20 == 0) {
            int time = NBTUtils.getInt(stack, TAG_TIME, -1);
            if (time > 0) {
                NBTUtils.setInt(stack, TAG_TIME, time - 1);
            } else {
                stack.damageItem(1, player, (playerIn) -> player.sendBreakAnimation(player.getActiveHand()));
                NBTUtils.setInt(stack, TAG_TIME, RelicsConfig.SpatialSign.timeBeforeActivation * 20);
                NBTUtils.setString(stack, TAG_POSITION, "");
            }
        }
        super.inventoryTick(stack, worldIn, entityIn, itemSlot, isSelected);
    }

    @Override
    public void addInformation(ItemStack stack, @Nullable World worldIn, List<ITextComponent> tooltip, ITooltipFlag flagIn) {
        if (!NBTUtils.getString(stack, TAG_POSITION, "").equals("")) {
            String[] position = NBTUtils.getString(stack, TAG_POSITION, "").split(",");
            tooltip.add(new StringTextComponent("Hold shift and right-click to initiate teleporting"));
            tooltip.add(new StringTextComponent(""));
            tooltip.add(new StringTextComponent("Stored destination:"));
            tooltip.add(new StringTextComponent("X: " + position[0] + " Y: " + position[1] + " Z: " + position[2]));
            tooltip.add(new StringTextComponent(""));
            tooltip.add(new StringTextComponent("Time before returning:"));
            tooltip.add(new StringTextComponent(String.valueOf(NBTUtils.getInt(stack, TAG_TIME, 0))));
        } else {
            tooltip.add(new StringTextComponent("Right-click to save current position"));
        }
    }

    @Override
    public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) {
        return slotChanged;
    }

    @Override
    public boolean hasEffect(ItemStack stack) {
        return !NBTUtils.getString(stack, TAG_POSITION, "").equals("");
    }

    public static void activateSign(ItemStack itemStack, PlayerEntity player, boolean shouldBreak) {
        if (!NBTUtils.getString(itemStack, TAG_POSITION, "").equals("")) {
            String[] position = NBTUtils.getString(itemStack, TAG_POSITION, "").split(",");
            player.setPositionAndUpdate(Double.parseDouble(position[0]), Double.parseDouble(position[1]), Double.parseDouble(position[2]));
            player.setMotion(0, 0, 0);
            player.setHealth(1.0F);
            player.getFoodStats().setFoodLevel(1);
            NBTUtils.setString(itemStack, TAG_POSITION, "");
            if (player.isOnePlayerRiding()) {
                player.dismount();
                player.getRidingEntity().setPositionAndUpdate(Double.parseDouble(position[0]), Double.parseDouble(position[1]), Double.parseDouble(position[2]));
                player.startRiding(player.getRidingEntity());
            }
            if (shouldBreak) itemStack.shrink(1);
        }
    }

    @Mod.EventBusSubscriber
    public static class SpatialSignServerEvents {
        @SubscribeEvent
        public static void onEntityHurt(LivingHurtEvent event) {
            if (event.getEntity() instanceof PlayerEntity) {
                PlayerEntity player = (PlayerEntity) event.getEntity();
                if (player.getHealth() < event.getAmount() && EntityUtils.getSlotWithItem(player, ItemRegistry.SPATIAL_SIGN.get()) != -1) {
                    activateSign(player.inventory.getStackInSlot(EntityUtils.getSlotWithItem(player, ItemRegistry.SPATIAL_SIGN.get())), player, true);
                    event.setCanceled(true);
                }
            } else if (event.getEntity() instanceof LivingEntity && event.getEntity().isBeingRidden()) {
                LivingEntity mount = (LivingEntity) event.getEntity();
                if (mount.getRidingEntity() instanceof PlayerEntity) {
                    PlayerEntity player = (PlayerEntity) mount.getRidingEntity();
                    if (EntityUtils.getSlotWithItem(player, ItemRegistry.SPATIAL_SIGN.get()) != -1) {
                        ItemStack itemStack = player.inventory.getStackInSlot(EntityUtils.getSlotWithItem(player, ItemRegistry.SPATIAL_SIGN.get()));
                        String[] position = NBTUtils.getString(itemStack, TAG_POSITION, "").split(",");
                        itemStack.damageItem(1, player, (playerIn) -> player.sendBreakAnimation(player.getActiveHand()));
                        player.dismount();
                        mount.setPositionAndUpdate(Double.parseDouble(position[0]), Double.parseDouble(position[1]), Double.parseDouble(position[2]));
                        mount.setMotion(0, 0, 0);
                    }
                }
            }
        }
    }
}
 
Последнее редактирование:
Сверху