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

Agravaine

Алмазная лига
Сообщения
4,408
Лучшие ответы
182
Симпатии
577
#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

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

Black_Maestro

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

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

Agravaine

Алмазная лига
Сообщения
4,408
Лучшие ответы
182
Симпатии
577
#6
Тайл и энтити - это вообще разные вещи.
 

SuperCatMaster

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

Ivasik

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

Agravaine

Алмазная лига
Сообщения
4,408
Лучшие ответы
182
Симпатии
577
#9
А вот включал, все на своем месте. Поэтому и не пойму чего за фигня.
 

Agravaine

Алмазная лига
Сообщения
4,408
Лучшие ответы
182
Симпатии
577
#10
Ап.
 

Ivasik

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

hohserg

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

Agravaine

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

Agravaine

Алмазная лига
Сообщения
4,408
Лучшие ответы
182
Симпатии
577
#15
Да, я уже все что можно убирал и тестил. Все равно лажа...
 

hohserg

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

Agravaine

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

Agravaine

Алмазная лига
Сообщения
4,408
Лучшие ответы
182
Симпатии
577
#18
Ап.
 
Сверху