Версия Minecraft
1.12.2
API
Forge
198
1
24
Как можно сделать моба, способного грузить чанк, в котором он находится, и бродить по карте независимо от того, есть ли рядом игрок?
 
198
1
24
Теперь моба нельзя убить, и он не деспавнится сам по себе до тех пор пока сервер включен - но пропадает после перезагрузки сервера. Бродит по карте более-менее. Далеко от точки спавна не уходит, но вполне обходится без игрока.
 
7,099
324
1,510
Добавь ему имя, как от бирки. Мобы с биркой не пропадают никогда
 

sk9zist :l

Исправился
981
18
157
7,099
324
1,510
Предвосхищая этот вопрос от ТС, отвечу: в своем рендере не вызывать super-метод
 
198
1
24
Короче, вот он, просьба ногами не бить...

Java:
import javax.annotation.Nullable;

import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAIAvoidEntity;
import net.minecraft.entity.ai.EntityAIHurtByTarget;
import net.minecraft.entity.ai.EntityAILookIdle;
import net.minecraft.entity.ai.EntityAIMoveIndoors;
import net.minecraft.entity.ai.EntityAIMoveThroughVillage;
import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAIOpenDoor;
import net.minecraft.entity.ai.EntityAIPanic;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.monster.EntityPigZombie;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.common.ForgeChunkManager.Ticket;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraft.util.SoundEvent;
import net.minecraft.init.SoundEvents;

public class Unknown extends EntityMob implements ChunkLoadingEntity {
   
    public static final ResourceLocation LOOT = new ResourceLocation(SecretMob.MODID, "entities/unknown.json");

    public Unknown(World worldIn) {
        super(worldIn);
        setSize(0.6F, 1.95F);
    }

    @Override
    protected void entityInit() {
        super.entityInit();
    }

    @Override
    protected void applyEntityAttributes() {
        super.applyEntityAttributes();
        this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(35.0D);
        this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.50D);
        this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(3.0D);
        this.getEntityAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(50.0D);
    }
   
    @Override
    protected boolean canDespawn(){
        return false;
    }

    @Override
    public boolean isEntityInvulnerable(DamageSource source){
        return true;
    }
   
    protected SoundEvent getAmbientSound()
    {
        return SoundEvents.ENTITY_ENDERMEN_AMBIENT;
    }

    /* Не понадобится - моб неуязвим */
   
    /*
    protected SoundEvent getHurtSound(DamageSource damageSourceIn)
    {
        return SoundEvents.ENTITY_PLAYER_HURT;
    }


    protected SoundEvent getDeathSound()
    {
        return SoundEvents.ENTITY_ENDERDRAGON_GROWL;
    }
    */
   
    protected void playStepSound(BlockPos pos, Block blockIn)
    {
        this.playSound(SoundEvents.ENTITY_ZOMBIE_STEP, 0.15F, 1.0F);
    }
   
    public void onLivingUpdate()
    {
        if (this.ticksExisted % 333 >= 330)
        {
            this.teleportRandomly();
        }

        if (Math.abs(this.posX) > 5000 || Math.abs(this.posY) > 5000)
        {
            this.teleportTo(1234, 256, -1234); //Разбиться не может, пусть падает
        }
       
        this.isJumping = false; // Хз зачем оно, тупо скопировал с эндермена
        super.onLivingUpdate();
    }
   
    protected boolean teleportRandomly()
    {
        double d0 = this.posX + (this.rand.nextDouble() - 0.5D) * 64.0D;
        double d1 = this.posY + (double)(this.rand.nextInt(64) - 32);
        double d2 = this.posZ + (this.rand.nextDouble() - 0.5D) * 64.0D;
        return this.teleportTo(d0, d1, d2);
    }
   
    private boolean teleportTo(double x, double y, double z)
    {
        net.minecraftforge.event.entity.living.EnderTeleportEvent event = new net.minecraftforge.event.entity.living.EnderTeleportEvent(this, x, y, z, 0);
        if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event)) return false;
        boolean flag = this.attemptTeleport(event.getTargetX(), event.getTargetY(), event.getTargetZ());

        if (flag)
        {
            this.world.playSound((EntityPlayer)null, this.prevPosX, this.prevPosY, this.prevPosZ, SoundEvents.ENTITY_ENDERMEN_TELEPORT, this.getSoundCategory(), 1.0F, 1.0F);
            this.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0F);
        }
       
        //Отслеживание телепортации чтобы проверить загрузку чанков
        System.out.printf("Entity teleported! New coordinates: %f, %f, %f\n", this.posX, this.posY, this.posZ);

        return flag;
    }
   
    @Override
    protected void initEntityAI() {
        this.tasks.addTask(1, new EntityAIAvoidEntity(this, EntityPlayer.class, (float) 20, 3, 3));
        this.tasks.addTask(1, new EntityAIAvoidEntity(this, EntityPlayerMP.class, (float) 20, 3, 3));
        this.tasks.addTask(1, new EntityAIWander(this, 1));
        this.tasks.addTask(2, new EntityAILookIdle(this));
        this.tasks.addTask(3, new EntityAISwimming(this));
        this.tasks.addTask(2, new EntityAIOpenDoor(this, true));
        this.tasks.addTask(2, new EntityAIMoveIndoors(this));
        this.tasks.addTask(3, new EntityAIOpenDoor(this, false));
        this.tasks.addTask(10, new EntityAIPanic(this, 10));

    }

    private void applyEntityAI() {
   
    }
   
    @Override
    @Nullable
    protected ResourceLocation getLootTable() {
        return LOOT;
    }

    @Override
    public boolean attackEntityAsMob(Entity entityIn) {
        return false;

    }

    @Override
    protected boolean isValidLightLevel() {
        return true;
    }

    @Override
    public int getMaxSpawnedInChunk() {
        return 0;
    }

    @Override
    public void onAddedTicket(Ticket ticket) {
        // TODO Auto-generated method stub
       
    }

    @Override
    public void onRemovedTicket(Ticket ticket) {
        // TODO Auto-generated method stub
       
    }
}
 
Последнее редактирование модератором:
198
1
24
С загрузкой чанков всё не так гладко. То есть, чанки грузит, например, за 3К блоков от игрока, но только если после рестарта это место посетить. Думаю, надо при остановке сервера сохранять последние известные координаты моба и при запуске загружать этот чанк, а дальше моб уже сам.
 
Последнее редактирование модератором:
Сверху