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

Agravaine

Модератор
Сообщения
5,082
Лучшие ответы
233
Реакции
874
Версия 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);
 
Сообщения
197
Лучшие ответы
6
Реакции
16
Ещё дополню(так как у меня такая же проблема). Если ентити получит какой либо урон, будь то лава или урон от падения, то он становится рабочим, если до этого он был не юзабельным.
 
Сообщения
42
Лучшие ответы
1
Реакции
6
Хммм в моде Erebus есть то что вам надо, там при смерти спавнятся кости с вещами игрока
 
Сообщения
42
Лучшие ответы
1
Реакции
6
блок то с тайлом в который все засовывается на ура и хранится до прибытия хозяина
Ну суть то та же в тайл засовывается инвентарь а ля тоже тело в выпавшими вещами

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

Agravaine

Модератор
Сообщения
5,082
Лучшие ответы
233
Реакции
874
Тайл и энтити - это вообще разные вещи.
 
Сообщения
687
Лучшие ответы
29
Реакции
91
Скорее всего проблема на сервере. Значит труп надо обновить, попробуй написать свой метод updateEntity(Entity ent), там придумай что-нить. Либо нанеси урон в рзамере 1.0F (или 1.0D, у меня под рукой IDE нет) от сурса игрока или другого энтити, т. к.
Ещё дополню(так как у меня такая же проблема). Если ентити получит какой либо урон, будь то лава или урон от падения, то он становится рабочим, если до этого он был не юзабельным.
Воть, моя идея.
 

Ivasik

Porting GrandBombaster
Администратор
Сообщения
2,825
Лучшие ответы
76
Реакции
298
При смерти, включи показ баундБокса, и глянь куда реальная энтити улетает.
 

Agravaine

Модератор
Сообщения
5,082
Лучшие ответы
233
Реакции
874
А вот включал, все на своем месте. Поэтому и не пойму чего за фигня.
 

Ivasik

Porting GrandBombaster
Администратор
Сообщения
2,825
Лучшие ответы
76
Реакции
298
А зачем тебе такой код?:
Java:
while (!worldObj.getCollidingBoundingBoxes(this, boundingBox).isEmpty()){
    setPosition(posX, posY + 1.0D, posZ);
}
Ты в конструкторе так делаешь и в update.
 
Сообщения
4,191
Лучшие ответы
109
Реакции
564

Agravaine

Модератор
Сообщения
5,082
Лучшие ответы
233
Реакции
874
Ты в конструкторе так делаешь и в update.
Чтобы если поставят блок в труп, то он не застрял там.
Это нормально, что туда передается ссылка на сущность игрока которая скоро должна удалиться?
Я же не сохраняю ее, а просто беру оттуда параметры и все.
 

Agravaine

Модератор
Сообщения
5,082
Лучшие ответы
233
Реакции
874
Да, я уже все что можно убирал и тестил. Все равно лажа...
 
Сообщения
4,191
Лучшие ответы
109
Реакции
564
У баккит разработчиков есть такой метод решения проблем: делать действие в следующий тик или через несколько тиков.
Может, во время обработки PlayerDropsEvent просто неудачный момент спавна сущностей? Попробуй заспунить какие-нить ванильные
 

Agravaine

Модератор
Сообщения
5,082
Лучшие ответы
233
Реакции
874
Почему тогда другие энтити, которые заспавнились фиг знает когда, при появлении нового трупа перестают работать?
 
Сверху