Странное поведение энтити на клиенте

Версия Minecraft
1.7.10

tox1cozZ

aka Agravaine
8,454
598
2,890
После смерти игрока спавню труп:
Java:
@SubscribeEvent
    public void onPlayerDrops(PlayerDropsEvent e){
        if(!e.entityLiving.worldObj.isRemote && e.entityLiving instanceof EntityPlayer){
            EntityPlayer player = (EntityPlayer)e.entityLiving;
            EntityCorpse corpse = new EntityCorpse(player.worldObj, player);
            corpse.fillDrops(e.drops.stream().map(entity -> entity.getEntityItem()).collect(Collectors.toList()));
            player.worldObj.spawnEntityInWorld(corpse);
           
            e.setCanceled(true);
        }
    }
Его видно, все хорошо. Но не могу никак с ним взаимодействовать вообще. Ни ударить ни ПКМ нажать. После перезахода все нормально. Так же если умираю еще раз и спавнится еще один труп - иногда предыдущий перестает работать.
Выяснил что когда навожу курсор на лаганый труп, Minecraft#objectMouserOver нулл. Первый раз встречаюсь с такой магией. Может кто знает в чем проблема?
Java:
package ua.agravaine.corpses;

import java.util.List;

import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.world.World;

public class EntityCorpse extends Entity implements IEntityAdditionalSpawnData{

    public NBTTagCompound data;
    public InventoryBase inventory;
    public long lifeTime;

    public EntityCorpse(World world){
        super(world);
        setSize(2.0F, 0.5F);
    }

    public EntityCorpse(World world, EntityPlayer owner){
        super(world);
        setSize(2.0F, 0.5F);
        setPosition(owner.posX, owner.posY, owner.posZ);
        while(!worldObj.getCollidingBoundingBoxes(this, boundingBox).isEmpty()){
            setPosition(posX, posY + 1.0D, posZ);
        }
        data.setString("owner", owner.getGameProfile().getName());
        data.setLong("id1", owner.getGameProfile().getId().getMostSignificantBits());
        data.setLong("id2", owner.getGameProfile().getId().getLeastSignificantBits());
    }
   
    @Override
    protected void entityInit(){
        rotationYaw = (float)(Math.random() * 360);
        data = new NBTTagCompound();
        inventory = new InventoryBase("Corpse", false, 56){
            @Override
            public void closeInventory(){
                int itemsCount = 0;
                for(ItemStack item : inventory){
                    if(item != null){
                        itemsCount++;
                    }
                }

                if(itemsCount < 3){
                    lifeTime = worldObj.getTotalWorldTime() + (2 * 20);
                }
            }
        };
        lifeTime = worldObj.getTotalWorldTime() + (5 * 60 * 20);
       
        dataWatcher.addObject(20, (byte)5);
    }

    @Override
    public boolean interactFirst(EntityPlayer player){
        if(!worldObj.isRemote){
            player.displayGUIChest(inventory);
        }
        return super.interactFirst(player);
    }

    @Override
    public boolean attackEntityFrom(DamageSource source, float damage){
        if(!isEntityInvulnerable()){
            setBeenAttacked();
            setHealth(getHealth() - 1);
            if(getHealth() <= 0){
                setDead();
            }
        }
        return false;
    }

    public void fillFromPlayer(EntityPlayer player){
        for(int i = 0; i < inventory.getSizeInventory(); i++){
            if(i < player.inventory.getSizeInventory()){
                inventory.setInventorySlotContents(i, ItemStack.copyItemStack(player.inventory.getStackInSlot(i)));
            }else{
                inventory.setInventorySlotContents(i, null);
            }
        }
       
        int itemsCount = 0;
        for(ItemStack item : inventory){
            if(item != null){
                itemsCount++;
            }
        }

        if(itemsCount < 3){
            lifeTime = worldObj.getTotalWorldTime() + (2 * 20);
        }
    }
   
    public void fillDrops(List<ItemStack> drops){
        for(int i = 0; i < inventory.getSizeInventory(); i++){
            if(i < drops.size()){
                inventory.setInventorySlotContents(i, ItemStack.copyItemStack(drops.get(i)));
            }else{
                inventory.setInventorySlotContents(i, null);
            }
        }

        if(drops.size() < 3){
            lifeTime = worldObj.getTotalWorldTime() + (2 * 20);
        }
    }

    @Override
    public void onUpdate(){
        super.onUpdate();
       
        if(!worldObj.isRemote){
            if(worldObj.getTotalWorldTime() >= lifeTime){
                setDead();
            }
        }
       
        if(ticksExisted % 40 == 0){
            while(!worldObj.getCollidingBoundingBoxes(this, boundingBox).isEmpty()){
                setPosition(posX, posY + 1.0D, posZ);
            }
        }
       
        prevPosX = posX;
        prevPosY = posY;
        prevPosZ = posZ;
        motionY -= 0.03999999910593033D;
       
        moveEntity(0, motionY, 0);

        motionY *= 0.9800000190734863D;

        if(onGround){
            motionY *= -0.5D;
        }
    }

    @Override
    public boolean canBeCollidedWith(){
        return true;
    }

    public byte getHealth(){
        return dataWatcher.getWatchableObjectByte(20);
    }
   
    public void setHealth(int health){
        dataWatcher.updateObject(20, (byte)health);
    }

    @Override
    public void writeSpawnData(ByteBuf buffer){
        ByteBufUtils.writeTag(buffer, data);
    }

    @Override
    public void readSpawnData(ByteBuf buffer){
        data = ByteBufUtils.readTag(buffer);
    }

    @Override
    protected void readEntityFromNBT(NBTTagCompound nbt){
        data = nbt.getCompoundTag("data");
        inventory.readFromNBT(nbt);
        lifeTime = nbt.getLong("lifeTime");
        setHealth(nbt.getByte("corpseHealth"));
    }

    @Override
    protected void writeEntityToNBT(NBTTagCompound nbt){
        nbt.setTag("data", data);
        inventory.writeToNBT(nbt);
        nbt.setLong("lifeTime", lifeTime);
        nbt.setByte("corpseHealth", getHealth());
    }
}
Java:
EntityRegistry.registerModEntity(EntityCorpse.class, "Corpse", 0, INSTANCE, 128, 40, true);
 
212
8
29
Ещё дополню(так как у меня такая же проблема). Если ентити получит какой либо урон, будь то лава или урон от падения, то он становится рабочим, если до этого он был не юзабельным.
 
блок то с тайлом в который все засовывается на ура и хранится до прибытия хозяина
Ну суть то та же в тайл засовывается инвентарь а ля тоже тело в выпавшими вещами

Где-то еще было что-то подобное вроде в витчери в ритуале можно возвращать вещи и грейвстоун
 
1,329
104
225
Скорее всего проблема на сервере. Значит труп надо обновить, попробуй написать свой метод updateEntity(Entity ent), там придумай что-нить. Либо нанеси урон в рзамере 1.0F (или 1.0D, у меня под рукой IDE нет) от сурса игрока или другого энтити, т. к.
Ещё дополню(так как у меня такая же проблема). Если ентити получит какой либо урон, будь то лава или урон от падения, то он становится рабочим, если до этого он был не юзабельным.
Воть, моя идея.
 
7,099
324
1,509

tox1cozZ

aka Agravaine
8,454
598
2,890
Ты в конструкторе так делаешь и в update.
Чтобы если поставят блок в труп, то он не застрял там.
Это нормально, что туда передается ссылка на сущность игрока которая скоро должна удалиться?
Я же не сохраняю ее, а просто беру оттуда параметры и все.
 
7,099
324
1,509
У баккит разработчиков есть такой метод решения проблем: делать действие в следующий тик или через несколько тиков.
Может, во время обработки PlayerDropsEvent просто неудачный момент спавна сущностей? Попробуй заспунить какие-нить ванильные
 
Сверху