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

Agravaine

Команда форума
Сообщения
4,599
Лучшие ответы
197
Симпатии
653
#1
Версия Minecraft
1.7.10
Подтверждение
Я максимально подробно описал проблему, включая исходный код файлов, краш лог, изображения и другую информацию, которая может помочь пользователям форума решить мой вопрос!
После смерти игрока спавню труп:
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);
 

JKLEM

Каменная лига
Сообщения
197
Лучшие ответы
6
Симпатии
16
#2
Ещё дополню(так как у меня такая же проблема). Если ентити получит какой либо урон, будь то лава или урон от падения, то он становится рабочим, если до этого он был не юзабельным.
 

Black_Maestro

Каменная лига
Сообщения
42
Лучшие ответы
1
Симпатии
6
#3
Хммм в моде Erebus есть то что вам надо, там при смерти спавнятся кости с вещами игрока
 

Black_Maestro

Каменная лига
Сообщения
42
Лучшие ответы
1
Симпатии
6
#5
блок то с тайлом в который все засовывается на ура и хранится до прибытия хозяина
Ну суть то та же в тайл засовывается инвентарь а ля тоже тело в выпавшими вещами

Где-то еще было что-то подобное вроде в витчери в ритуале можно возвращать вещи и грейвстоун
 

Agravaine

Команда форума
Сообщения
4,599
Лучшие ответы
197
Симпатии
653
#6
Тайл и энтити - это вообще разные вещи.
 

SuperCatMaster

Каменная лига
Сообщения
595
Лучшие ответы
26
Симпатии
71
#7
Скорее всего проблема на сервере. Значит труп надо обновить, попробуй написать свой метод updateEntity(Entity ent), там придумай что-нить. Либо нанеси урон в рзамере 1.0F (или 1.0D, у меня под рукой IDE нет) от сурса игрока или другого энтити, т. к.
Ещё дополню(так как у меня такая же проблема). Если ентити получит какой либо урон, будь то лава или урон от падения, то он становится рабочим, если до этого он был не юзабельным.
Воть, моя идея.
 

Ivasik

Porting GrandBombaster
Команда форума
Сообщения
2,683
Лучшие ответы
76
Симпатии
261
#8
При смерти, включи показ баундБокса, и глянь куда реальная энтити улетает.
 

Agravaine

Команда форума
Сообщения
4,599
Лучшие ответы
197
Симпатии
653
#9
А вот включал, все на своем месте. Поэтому и не пойму чего за фигня.
 

Agravaine

Команда форума
Сообщения
4,599
Лучшие ответы
197
Симпатии
653
#10
Ап.
 

Ivasik

Porting GrandBombaster
Команда форума
Сообщения
2,683
Лучшие ответы
76
Симпатии
261
#11
А зачем тебе такой код?:
Java:
while (!worldObj.getCollidingBoundingBoxes(this, boundingBox).isEmpty()){
    setPosition(posX, posY + 1.0D, posZ);
}
Ты в конструкторе так делаешь и в update.
 

hohserg1

Алмазная лига
Сообщения
3,663
Лучшие ответы
92
Симпатии
434
#12

Agravaine

Команда форума
Сообщения
4,599
Лучшие ответы
197
Симпатии
653
#13
Ты в конструкторе так делаешь и в update.
Чтобы если поставят блок в труп, то он не застрял там.
Это нормально, что туда передается ссылка на сущность игрока которая скоро должна удалиться?
Я же не сохраняю ее, а просто беру оттуда параметры и все.
 

Agravaine

Команда форума
Сообщения
4,599
Лучшие ответы
197
Симпатии
653
#15
Да, я уже все что можно убирал и тестил. Все равно лажа...
 

hohserg1

Алмазная лига
Сообщения
3,663
Лучшие ответы
92
Симпатии
434
#16
У баккит разработчиков есть такой метод решения проблем: делать действие в следующий тик или через несколько тиков.
Может, во время обработки PlayerDropsEvent просто неудачный момент спавна сущностей? Попробуй заспунить какие-нить ванильные
 

Agravaine

Команда форума
Сообщения
4,599
Лучшие ответы
197
Симпатии
653
#17
Почему тогда другие энтити, которые заспавнились фиг знает когда, при появлении нового трупа перестают работать?
 

Agravaine

Команда форума
Сообщения
4,599
Лучшие ответы
197
Симпатии
653
#18
Ап.
 
Сверху