Спавн сундука с лутом игрока

Версия Minecraft
1.12.2
API
Forge
20
1
Добрый вечер. Делаю механику выпадения предметов при смерти в могилу

Могилу реализовал как сундук по гайдам HarryTechRevs (Его реализация CopperChest). В соответствии со своими целями написал EventHandler, и подключился к событию PlayerDropsEvent. Всё хорошо, сундук спавнится. Однако лут не хочет записываться в него, (код будет ниже) моя догадка в том, что не происходит записи в compound, однако как такое реализовать я, увы, не знаю. Хотел бы услышать совет по правильной реализации.

Код:
TileEntityCopse и EventHandler

Ошибка выкидываемая при смерти - java.lang.UnsupportedOperationException: null
 

necauqua

когда-то был anti344
Администратор
1,216
27
172
Ну, очевидной проблемы в глаза не бросается, понатыкай везде принтов, шо
Разве что TileEntityLockableLoot это для сундуков с луттейблами, тебе оно вроде не нужно, хотя работает (или пока нет xd) и ладно
Код лучше прямо в форуме в блоки кода вставлять, пожалуйста)
И крашлог больше одной строчки тоже очень помог-бы, откуда там могло взяться UnsupportedOperationException так сразу не видно тоже
 
122
4
6
я реализовывал подобную механику, но вместо простого сундука была сущность
Java:
public class EntityMirrorVessel extends Entity implements IInventory {
    final static byte VACUUM_TIMELIMIT = 20;
    final static int VACUUM_RADIUS = 5;

    private final NonNullList<ItemStack> mainInventory = NonNullList.withSize(200, ItemStack.EMPTY);
    private final Deque<ItemStack> auxInventory = new LinkedList<>();
    private byte vacuumTime = 0;

    private static final DataParameter<ItemStack> ITEM = EntityDataManager.<ItemStack>createKey(EntityMirrorVessel.class, DataSerializers.ITEM_STACK);
    private int age;
    private int pickupDelay;
    private int health = 5;
    private String thrower;
    private String owner;

    public final float hoverStart = (float)(Math.random() * Math.PI * 2.0D);

    public EntityMirrorVessel(World world) {
        super(world);
        this.setSize(0.9F, 0.9F);
    }

    public EntityMirrorVessel(World world, double x, double y, double z) {
        super(world);
        this.setPosition(x, y, z);
        this.rotationYaw = this.rand.nextFloat() * 360.0F;
        this.setSize(0.9F, 0.9F);

        setNoGravity(true);
    }

    public EntityMirrorVessel(World world, double x, double y, double z, ItemStack stack) {
        this(world, x, y, z);
        this.setSize(0.9F, 0.9F);
        this.setItem(stack);

        this.markDirty();
    }

    protected boolean canTriggerWalking() { return false; }
    protected void entityInit() { this.getDataManager().register(ITEM, ItemStack.EMPTY); }

    protected boolean canDespawn() { return false; }

    public void onUpdate() {
        if (this.getItem().isEmpty()) {
            this.dropAllItems();
            this.setDead();
        } else {
            super.onUpdate();
            if (this.pickupDelay > 0 && this.pickupDelay != 32767) --this.pickupDelay;
            this.prevPosX = this.posX;
            this.prevPosY = this.posY;
            this.prevPosZ = this.posZ;
            double d0 = this.motionX;
            double d1 = this.motionY;
            double d2 = this.motionZ;


            if (!this.hasNoGravity()) this.motionY -= 0.04d;
            if (this.world.isRemote) {
                this.noClip = false;
                world.spawnParticle(EnumParticleTypes.PORTAL, this.posX, this.posY+(this.getEyeHeight()/2), this.posZ, ((Math.random()-0.5)*2.0), ((Math.random()-0.5)*2.0), ((Math.random()-0.5)*2.0));
            }
            ++this.age;
            if (!this.world.isRemote) {
                double d3 = this.motionX - d0;
                double d4 = this.motionY - d1;
                double d5 = this.motionZ - d2;
                double d6 = d3 * d3 + d4 * d4 + d5 * d5;

                if (d6 > 0.01D) this.isAirBorne = true;
            }
            ItemStack item = this.getItem();
            if (item.isEmpty()) this.setDead();
        }

        //inventory--------------------
        final boolean isClient = getEntityWorld().isRemote;
        final boolean isServer = !isClient;

        if (isServer && vacuumTime < VACUUM_TIMELIMIT) {
            vacuumTime++;
            List<EntityItem> items = getEntityWorld().getEntitiesWithinAABB(EntityItem.class, new AxisAlignedBB(
                    posX - VACUUM_RADIUS, posY - VACUUM_RADIUS, posZ - VACUUM_RADIUS,
                    posX + VACUUM_RADIUS, posY + VACUUM_RADIUS, posZ + VACUUM_RADIUS));
            for (EntityItem item : items) { ItemStack stack = item.getItem(); this.addItem(stack); }
            for (EntityItem item : items) getEntityWorld().removeEntity(item);
        }
        if (isServer && vacuumTime >= VACUUM_TIMELIMIT && (this.inWater || this.isInLava() || this.posY < 0)) {
            this.motionY += 2.025D;
            this.motionY *= 1.2;
        }
        if (isServer && isEmpty()) this.setDead();
    }

    protected void dealFireDamage(int amount) { this.attackEntityFrom(DamageSource.IN_FIRE, (float)amount); }

    @Override
    public boolean attackEntityFrom(DamageSource source, float amount) {
        if (this.world.isRemote || !this.isEntityAlive()) return false;
        if (source.isDamageAbsolute()) return false; else return false;
    }

    public static void registerFixesItem(DataFixer fixer) { fixer.registerWalker(FixTypes.ENTITY, new ItemStackData(EntityItem.class, new String[] {"Item"})); }

    public void writeEntityToNBT(NBTTagCompound compound) {
        compound.setShort("Health", (short)this.health);
        compound.setShort("Age", (short)this.age);
        compound.setShort("PickupDelay", (short)this.pickupDelay);

        if (this.getThrower() != null) compound.setString("Thrower", this.thrower);
        if (this.getOwner() != null) compound.setString("Owner", this.owner);
        if (!this.getItem().isEmpty()) compound.setTag("Item", this.getItem().writeToNBT(new NBTTagCompound()));

        //inventory---------------------------
        final NBTTagList equipmentListTag = new NBTTagList();
        for (int i = 0; i < this.getSizeInventory(); i++) {
            ItemStack item = this.getStackInSlot(i);
            if (!item.isEmpty()) {
                NBTTagCompound slotTag = new NBTTagCompound();
                slotTag.setByte("Slot", (byte)i);
                item.writeToNBT(slotTag);
                equipmentListTag.appendTag(slotTag);
            }
        }
        compound.setTag("Equipment", equipmentListTag);

        if (!this.auxInventory.isEmpty()) {
            final NBTTagList nbtauxtaglist = new NBTTagList();
            Iterator<ItemStack> iter = this.auxInventory.iterator();
            while (iter.hasNext()) {
                ItemStack i = iter.next();
                if (i.isEmpty()) continue;
                final NBTTagCompound nbttagcompound1 = new NBTTagCompound();
                i.writeToNBT(nbttagcompound1);
                nbtauxtaglist.appendTag(nbttagcompound1);
            }
            compound.setTag("Aux", nbtauxtaglist);
        }
        if (vacuumTime < VACUUM_TIMELIMIT) compound.setByte("Vac", vacuumTime);
    }

    public void readEntityFromNBT(NBTTagCompound compound) {
        this.health = compound.getShort("Health");
        this.age = compound.getShort("Age");

        if (compound.hasKey("PickupDelay")) this.pickupDelay = compound.getShort("PickupDelay");
        if (compound.hasKey("Owner")) this.owner = compound.getString("Owner");
        if (compound.hasKey("Thrower")) this.thrower = compound.getString("Thrower");

        NBTTagCompound nbttagcompound = compound.getCompoundTag("Item");
        this.setItem(new ItemStack(nbttagcompound));

        if (this.getItem().isEmpty()) this.setDead();

        //inventory---------------------------
        if (compound.hasKey("Equipment", 9)) {
            final NBTTagList nbttaglist = compound.getTagList("Equipment", 10);
            for (int i = 0; i < nbttaglist.tagCount(); ++i) {
                NBTTagCompound slotTag = nbttaglist.getCompoundTagAt(i);
                int slot = slotTag.getByte("Slot");
                ItemStack item = new ItemStack(slotTag);
                this.setInventorySlotContents(slot,item);
            }
        }
        if (compound.hasKey("Aux")) {
            final NBTTagList nbttaglist = compound.getTagList("Aux", 10);
            for (int i = 0; i < nbttaglist.tagCount(); ++i) this.auxInventory.addLast(new ItemStack(nbttaglist.getCompoundTagAt(i)));
        }
        if (compound.hasKey("Vac")) this.vacuumTime = compound.getByte("Vac"); else this.vacuumTime = VACUUM_TIMELIMIT;
    }

    @SuppressWarnings("unlikely-arg-type")
    public void onCollideWithPlayer(EntityPlayer player) {
        if (!this.world.isRemote) {
            if (this.pickupDelay > 0) return;
            ItemStack itemstack = this.getItem();
            Item item = itemstack.getItem();
            int i = itemstack.getCount();

            if (player.isSneaking()) if (this.pickupDelay == 0 && (this.owner == null || this.owner.equals(player.getUniqueID()))) {
                this.dropAllItems();
                this.setDead();
            }
        }
    }

    public String getName() { return this.hasCustomName() ? this.getCustomNameTag() : I18n.translateToLocal("item." + this.getItem().getUnlocalizedName()); }

    public boolean canBeAttackedWithItem() { return false; }

    @Nullable
    public Entity changeDimension(int dimensionIn, net.minecraftforge.common.util.ITeleporter teleporter) {
        Entity entity = super.changeDimension(dimensionIn, teleporter);
        return entity;
    }

    public ItemStack getItem() { return (ItemStack)this.getDataManager().get(ITEM); }

    public void setItem(ItemStack stack) { this.getDataManager().set(ITEM, stack); }

    public String getOwner() { return this.owner; }
    public void setOwner(String owner) { this.owner = owner; }

    public String getThrower() { return this.thrower; }
    public void setThrower(String thrower) { this.thrower = thrower; }

    @SideOnly(Side.CLIENT) public int getAge() { return this.age; }

    public void setDefaultPickupDelay() { this.pickupDelay = 10; }

    public void setNoPickupDelay() { this.pickupDelay = 0; }

    public void setInfinitePickupDelay() { this.pickupDelay = 32767; }

    public void setPickupDelay(int ticks) { this.pickupDelay = ticks; }

    public boolean cannotPickup() { return this.pickupDelay > 0; }

    public void makeFakeItem() { this.setInfinitePickupDelay(); }

    //inventory---------------------------
    public void addItem(ItemStack stack) {
        for (int slot = 0; slot < this.getSizeInventory(); slot++) {
            stack = mergeItem(slot,stack);
            if (stack.isEmpty()) return;
        }
        auxInventory.addLast(stack);
    }
    public void initializeItems(NonNullList<ItemStack> inv) {
        for (int i = 0; i < inv.size(); i++) {
            if (i < mainInventory.size()) mainInventory.set(i,inv.get(i));
            else auxInventory.addLast(inv.get(i));
        }
    }
    public ItemStack mergeItem(int slot, ItemStack stack) {
        if (stack.isEmpty()) return ItemStack.EMPTY;
        ItemStack current = this.getStackInSlot(slot);
        final int inventorySizeLimit = Math.min(stack.getMaxStackSize(), this.getInventoryStackLimit());
        if (current.isEmpty()) {
            this.setInventorySlotContents(slot, stack);
            return ItemStack.EMPTY;
        } else if(current.getCount() < inventorySizeLimit && ItemStack.areItemsEqual(stack,current) && ItemStack.areItemStackTagsEqual(stack,current)) {
            int delta = Math.min(stack.getCount(),inventorySizeLimit - current.getCount());
            current.grow(delta);
            stack.shrink(delta);
            this.setInventorySlotContents(slot,current);
            if (stack.getCount() <= 0) return ItemStack.EMPTY;
            return stack;
        }
        return stack;
    }

    @Override public int getSizeInventory() { return mainInventory.size(); }

    public boolean isEmpty() {
        if (!auxInventory.isEmpty()) return false;
        for (int slot = 0; slot < this.getSizeInventory(); slot++) if (!this.getStackInSlot(slot).isEmpty()) return false;
        return true;
    }
    private void dropAllItems() {
        for (ItemStack i : mainInventory) if (!i.isEmpty()) this.getEntityWorld().spawnEntity(new EntityItem(this.getEntityWorld(), posX, posY, posZ, i));
        for (ItemStack i : auxInventory) if (!i.isEmpty()) this.getEntityWorld().spawnEntity(new EntityItem(this.getEntityWorld(), posX, posY, posZ, i));
        this.clear();
    }

    @Override public ItemStack getStackInSlot(int index) { return mainInventory.get(index); }

    @Override public ItemStack decrStackSize(int index, int count) {
        ItemStack i = this.getStackInSlot(index);
        ItemStack result = i.splitStack(count);
        if (i.getCount() <= 0) i = ItemStack.EMPTY;
        this.setInventorySlotContents(index, i);
        return result;
    }

    @Override public ItemStack removeStackFromSlot(int index) { ItemStack i = this.getStackInSlot(index); this.setInventorySlotContents(index,ItemStack.EMPTY); return i; }

    @Override public void setInventorySlotContents(int index, ItemStack stack) { mainInventory.set(index, stack); }

    @Override public int getInventoryStackLimit() { return 64; }

    @Override public void markDirty() {}

    @Override public boolean isUsableByPlayer(EntityPlayer player) { return false; }

    @Override public void openInventory(EntityPlayer player) {}

    @Override public void closeInventory(EntityPlayer player) {}

    @Override public boolean isItemValidForSlot(int index, ItemStack stack) { return true; }

    @Override public int getField(int id) { return 0; }

    @Override public void setField(int id, int value) { }

    @Override public int getFieldCount() { return 0; }

    @Override public void clear() { mainInventory.clear(); auxInventory.clear(); }
}
Java:
@SubscribeEvent
    public void livingDeath(LivingDeathEvent e) {
        EntityLivingBase target = e.getEntityLiving();

        //Test Mirror in the player inventory, to the player y < -34
        if (target instanceof EntityPlayer) {
            EntityPlayer player = (EntityPlayer) target;
            ITrinketItemHandler trinketsHand = TrinketAPI.getTrinketHandler(player);

            for (int i = 0; i < trinketsHand.getSlots(); i++) {
                ItemStack stack = trinketsHand.getStackInSlot(i);
                ITrinket trinket = stack.getCapability(CAPTrinket.INV_CAP_TRINKET_ITEM, null);

                if (!player.world.isRemote && trinket instanceof MirrorVessel && !player.world.getGameRules().getBoolean("keepInventory")) {
                    stack.damageItem(1, player);
                    if (player.posY < -34) player.setPosition(player.posX, 5, player.posZ);
                    player.world.spawnEntity(new EntityMirrorVessel(player.world, player.posX, player.posY + 1.2f, player.posZ, new ItemStack(ItemsInit.MIRROR_VESSEL, 1)));
                    break;
                }
            }
        }
    }
основной принцип не появление предметов в слотах хранилища, а засасывание на подобие вакуумного хранилища из EnderIO
 
Последнее редактирование:
20
1
Ну, очевидной проблемы в глаза не бросается, понатыкай везде принтов, шо
Разве что TileEntityLockableLoot это для сундуков с луттейблами, тебе оно вроде не нужно, хотя работает (или пока нет xd) и ладно
Код лучше прямо в форуме в блоки кода вставлять, пожалуйста)
И крашлог больше одной строчки тоже очень помог-бы, откуда там могло взяться UnsupportedOperationException так сразу не видно тоже
Пока не могу скинуть, но точно помню что ошибка указывала как раз на метод добавления предмета в тайле
 
Сверху