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

tox1cozZ

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

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

tox1cozZ

aka Agravaine
Модератор
Сообщения
6,820
Лучшие ответы
412
Реакции
1,901
Тайл и энтити - это вообще разные вещи.
 
Сообщения
690
Лучшие ответы
29
Реакции
93
Скорее всего проблема на сервере. Значит труп надо обновить, попробуй написать свой метод updateEntity(Entity ent), там придумай что-нить. Либо нанеси урон в рзамере 1.0F (или 1.0D, у меня под рукой IDE нет) от сурса игрока или другого энтити, т. к.
Ещё дополню(так как у меня такая же проблема). Если ентити получит какой либо урон, будь то лава или урон от падения, то он становится рабочим, если до этого он был не юзабельным.
Воть, моя идея.
 

Ivasik

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

tox1cozZ

aka Agravaine
Модератор
Сообщения
6,820
Лучшие ответы
412
Реакции
1,901
А вот включал, все на своем месте. Поэтому и не пойму чего за фигня.
 

Ivasik

Porting GrandBombaster
Администратор
Сообщения
3,148
Лучшие ответы
82
Реакции
418
А зачем тебе такой код?:
Java:
while (!worldObj.getCollidingBoundingBoxes(this, boundingBox).isEmpty()){
    setPosition(posX, posY + 1.0D, posZ);
}
Ты в конструкторе так делаешь и в update.
 
Сообщения
5,135
Лучшие ответы
160
Реакции
877

tox1cozZ

aka Agravaine
Модератор
Сообщения
6,820
Лучшие ответы
412
Реакции
1,901
Ты в конструкторе так делаешь и в update.
Чтобы если поставят блок в труп, то он не застрял там.
Это нормально, что туда передается ссылка на сущность игрока которая скоро должна удалиться?
Я же не сохраняю ее, а просто беру оттуда параметры и все.
 

tox1cozZ

aka Agravaine
Модератор
Сообщения
6,820
Лучшие ответы
412
Реакции
1,901
Да, я уже все что можно убирал и тестил. Все равно лажа...
 
Сообщения
5,135
Лучшие ответы
160
Реакции
877
У баккит разработчиков есть такой метод решения проблем: делать действие в следующий тик или через несколько тиков.
Может, во время обработки PlayerDropsEvent просто неудачный момент спавна сущностей? Попробуй заспунить какие-нить ванильные
 

tox1cozZ

aka Agravaine
Модератор
Сообщения
6,820
Лучшие ответы
412
Реакции
1,901
Почему тогда другие энтити, которые заспавнились фиг знает когда, при появлении нового трупа перестают работать?
 
Сообщения
1
Лучшие ответы
0
Реакции
0
Времени много прошло, фикс был найден или все же нет?
 
Сверху