Jump to content

Recommended Posts

Posted

Howdy folks

 

have any of you coded up a custom entity I could steal to use for an example code project?

Just the basic stuff like

- registering

- spawning (spawn frequency in biomes)

- simple AI

- simple datawatcher

- base attributes (health, damage, etc)

 

Never coded an entity myself and although it would be fun to learn it'd be a lot faster if I had a good base to start from....

 

The example project is for 1.8 but I figure 1.7 entities will probably work just the same.

 

-TGG

 

Posted

Yeah, i will upload one in a sec. It a little bit special, so I am not sure if this is useful for you.

AND I coded this half a year ago, don't expect too much.

 

Could you maybe send me a link to your example project? I am planning to update my own mod today or tomorrow...

Here could be your advertisement!

Posted

Main mod file:

 

// ENTITIES
public static int entityParasiteMaggotId = 0;


preInit:

         EntityRegistry.registerModEntity(EntityParasiteMaggot.class, "entityParasiteMaggot", entityParasiteMaggotId, this, 80, 1, true);

 

Client Proxy:

	RenderingRegistry.registerEntityRenderingHandler(EntityParasiteMaggot.class, new RenderParasiteMaggot(new ModelParasiteMaggot(), 0.1F));
	// the last argument is the shadowsize

 

Entity:

 

 

package net.dimensionshiftinfectus.mod.entity;

import java.util.Random;

import net.dimensionshift.mod.DimensionShift;
import net.dimensionshift.mod.ai.EntityAIAttackAndInfect;
import net.dimensionshift.mod.ai.EntityAIFood;
import net.dimensionshift.mod.api.IMobContagious;
import net.dimensionshift.mod.api.IMobHungry;
import net.dimensionshiftinfectus.mod.DimensionShiftInfectus;
import net.minecraft.command.IEntitySelector;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.EnumCreatureAttribute;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAIHurtByTarget;
import net.minecraft.entity.ai.EntityAILookIdle;
import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World;

public class EntityParasiteMaggot extends EntityMob implements IMobHungry, IMobContagious {

public int range = 20;
public int hunger = 0;
public int maxHunger = 1000;

public String illnessName = "parasitemaggot.infected";

public int breeding = 0;
public int breedinglayegg = 100;

private static final IEntitySelector attackEntitySelector = new IEntitySelector() {
	/**
	 * Return whether the specified entity is applicable to this filter.
	 */
	@Override
	public boolean isEntityApplicable(Entity par1Entity) {
		return par1Entity instanceof EntityLivingBase && ((EntityLivingBase) par1Entity).getCreatureAttribute() != EnumCreatureAttribute.UNDEAD;
	}
};

public EntityParasiteMaggot(World par1World) {
	super(par1World);

	this.tasks.addTask(5, new EntityAIAttackAndInfect(this, EntityPlayer.class, 1.0D, this.illnessName, 60, true));
	this.tasks.addTask(5, new EntityAIAttackAndInfect(this, EntityLiving.class, 1.0D, this.illnessName, 60, true));

	this.tasks.addTask(6, new EntityAIMoveTowardsRestriction(this, 1.0D));
	this.tasks.addTask(7, new EntityAIWander(this, 0.8D));
	this.tasks.addTask(8, new EntityAILookIdle(this));

	this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true));

	this.targetTasks.addTask(2, new EntityAIFood(this, 20, 1.2D, 70, 1, 2));
	this.targetTasks.addTask(3, new EntityAINearestAttackableTarget(this, EntityLiving.class, 0, false, false, attackEntitySelector));
	this.targetTasks.addTask(4, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 0, false));

	this.setSize(0.55F, 0.25F);
	this.experienceValue = 1;
	this.setHealth((float) this.getEntityAttribute(SharedMonsterAttributes.maxHealth).getAttributeValue());
}

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

/*
 * @Override public boolean attackEntityFrom(DamageSource par1DamageSource,
 * float par2){ if(par2<0.2){ return true; } else { return false; } }
 */

@Override
public void onUpdate() {
	super.onUpdate();

	if (!this.worldObj.isRemote && this.worldObj.difficultySetting == EnumDifficulty.PEACEFUL) {
		this.setDead();
	}
	if (!this.worldObj.isRemote && this.hunger > 0) {
		this.hunger--;
	}

}

@Override
public EnumCreatureAttribute getCreatureAttribute() {
	return EnumCreatureAttribute.UNDEAD;
}

@Override
protected void applyEntityAttributes() {
	super.applyEntityAttributes();
	this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(2.0D);
	this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(0.15D);
	this.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).setBaseValue(0.9D);
}

/*
 * @Override protected String getLivingSound() { return
 * "yourmod:YourSound";//this refers to:yourmod/sound/YourSound }
 * 
 * @Override protected String getHurtSound() { return
 * "yourmod:optionalFile.YourSound";//this refers
 * to:yourmod/sound/optionalFile/YourSound }
 * 
 * @Override protected String getDeathSound() { return
 * "yourmod:optionalFile.optionalFile2.YourSound";//etc. }
 */

@Override
protected float getSoundVolume() {
	return 0.4F;
}

@Override
public int getHunger() {
	return this.hunger;
}

@Override
public void setHunger(int hunger) {
	this.hunger = hunger;
}

@Override
public int getFullHunger() {
	return this.maxHunger;
}

@Override
    public boolean interact(EntityPlayer player){
	if(player.inventory.getCurrentItem().isItemEqual(new ItemStack(DimensionShift.blockGlassJar))){
        
		Random random = new Random();
		if(random.nextInt(20)<=0){
			NBTTagCompound nbt;

			if (player.getEntityData() != null) {
				nbt = player.getEntityData();
			} else {
				nbt = new NBTTagCompound();
			}
			nbt.setBoolean("dimensionshift.infectus.illness." + this.illnessName, true);
			this.setDead();
		} else {
			player.inventory.setInventorySlotContents(player.inventory.currentItem, new ItemStack(DimensionShiftInfectus.blockGlassJarParasiteMaggot));
		}
        return true;
	}
	return false;
}

@Override
    protected void dropFewItems(boolean hitByPlayer, int lootingEnchantmentLevel)
    {
        Item slime_ball = Items.slime_ball;
        Item dead = DimensionShiftInfectus.itemDeadParasiteMaggot;
        Item burned = DimensionShiftInfectus.itemBurnedParasiteMaggot;

            int j = this.rand.nextInt(2);

            if (lootingEnchantmentLevel > 0)
            {
                j += this.rand.nextInt(lootingEnchantmentLevel + 1);
            }

            for (int k = 0; k < j; ++k)
            {
                this.dropItem(slime_ball, 1);
            }
            
            j = this.rand.nextInt(1);
            
            if (lootingEnchantmentLevel > 0)
            {
                j += this.rand.nextInt(lootingEnchantmentLevel + 1);
            }
            
            if(j<this.rand.nextInt(3)){
            	
            	if(this.isBurning()){
            		this.dropItem(burned, 1);
            	} else{
            		this.dropItem(dead, 1);
            	}
            }
            
    }

}

 

 

 

Render

 

 

package net.dimensionshiftinfectus.mod.render;

import net.dimensionshiftinfectus.mod.model.ModelParasiteMaggot;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;

public class RenderParasiteMaggot extends RenderLiving {
private static final ResourceLocation texture = new ResourceLocation("dimensionshiftinfectus:textures/entity/entityParasiteMaggot.png"); // refers
																																			// to:assets/yourmod/textures/entity/yourtexture.png

public RenderParasiteMaggot(ModelParasiteMaggot par1ModelBase, float par2) {
	super(par1ModelBase, par2);
}

@Override
protected ResourceLocation getEntityTexture(Entity par1Entity) {
	return texture;
}
}

 

 

 

Model:

 

 

package net.dimensionshiftinfectus.mod.model;

import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;

import org.lwjgl.opengl.GL11;

public class ModelParasiteMaggot extends ModelBase {
ModelRenderer Head;
ModelRenderer Body;
ModelRenderer Tail;
ModelRenderer TailEnd;

public ModelParasiteMaggot() {
	this.textureHeight = 32;
	this.textureWidth = 32;

	this.Head = new ModelRenderer(this, 0, 11);
	this.Head.addBox(-1.0F, -1.0F, -2.0F, 2, 2, 2);
	this.Head.setRotationPoint(0.0F, 23.0F, -2.0F);

	this.Body = new ModelRenderer(this, 0, 0);
	this.Body.addBox(-1.5F, -2.0F, 0.0F, 3, 3, 4);
	this.Body.setRotationPoint(0.0F, 23.0F, -2.0F);

	this.Tail = new ModelRenderer(this, 0, 7);
	this.Tail.addBox(-1.0F, -1.0F, 0.0F, 2, 2, 2);
	this.Tail.setRotationPoint(0.0F, 23.0F, 2.0F);

	this.TailEnd = new ModelRenderer(this, 8, 7);
	this.TailEnd.addBox(-0.5F, 0.0F, 0.0F, 1, 1, 1);
	this.TailEnd.setRotationPoint(0.0F, 23.0F, 4.0F);
}

@Override
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) {
	setRotationAngles(f, f1, f2, f3, f4, f5, entity);

	GL11.glPushMatrix();
	GL11.glEnable(3042);
	GL11.glTranslatef(0, 0.45F, 0);
	GL11.glBlendFunc(770, 771);

	GL11.glScalef(0.7F, 0.7F, 0.7F + f1 * 2.0F);
	this.Head.render(f5);
	this.Body.render(f5);
	this.Tail.render(f5);
	this.TailEnd.render(f5);
	GL11.glDisable(3042);
	GL11.glPopMatrix();
}


public void renderModel(float f){

	this.Head.render(f);
	this.Body.render(f);
	this.Tail.render(f);
	this.TailEnd.render(f);
}

@Override
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity) {
	super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);

}
}

 

 

 

 

custom AI:

 

 

 

package net.dimensionshift.mod.ai;

import java.util.Random;

import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.pathfinding.PathEntity;
import net.minecraft.pathfinding.PathPoint;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;

public class EntityAIAttackAndInfect extends EntityAIBase {
World worldObj;
EntityCreature attacker;
/**
 * An amount of decrementing ticks that allows the entity to attack once the
 * tick reaches 0.
 */
int attackTick;
/** The speed with which the mob will approach the target */
double speedTowardsTarget;

public String illnessName = "";
public int infectionChance = 0;
public boolean diesAfterInfection = false;

/** The PathEntity of our entity. */
PathEntity entityPathEntity;
Class classTarget;
private int field_75445_i;
private double field_151497_i;
private double field_151495_j;
private double field_151496_k;

private int failedPathFindingPenalty;

public EntityAIAttackAndInfect(EntityCreature par1EntityCreature, Class par2Class, double par3, String illnessName, int infectionChance, boolean diesAfterInfection) {
	this(par1EntityCreature, par3, illnessName, infectionChance, diesAfterInfection);
	this.classTarget = par2Class;
}

public EntityAIAttackAndInfect(EntityCreature par1EntityCreature, double par2, String illnessName, int infectionChance, boolean diesAfterInfection) {
	this.attacker = par1EntityCreature;
	this.worldObj = par1EntityCreature.worldObj;
	this.speedTowardsTarget = par2;
	this.illnessName = illnessName;
	this.infectionChance = infectionChance;
	this.setMutexBits(3);
	this.diesAfterInfection = diesAfterInfection;
}

/**
 * Returns whether the EntityAIBase should begin execution.
 */
@Override
public boolean shouldExecute() {
	EntityLivingBase entitylivingbase = this.attacker.getAttackTarget();

	if (entitylivingbase == null) {
		return false;
	} else if (!entitylivingbase.isEntityAlive()) {
		return false;
	} else if (this.classTarget != null && !this.classTarget.isAssignableFrom(entitylivingbase.getClass())) {
		return false;
	} else {
		if (--this.field_75445_i <= 0) {
			this.entityPathEntity = this.attacker.getNavigator().getPathToEntityLiving(entitylivingbase);
			this.field_75445_i = 4 + this.attacker.getRNG().nextInt(7);
			return this.entityPathEntity != null;
		} else {
			return true;
		}
	}
}

/**
 * Returns whether an in-progress EntityAIBase should continue executing
 */
@Override
public boolean continueExecuting() {
	EntityLivingBase entitylivingbase = this.attacker.getAttackTarget();
	return entitylivingbase == null ? false : (!entitylivingbase.isEntityAlive() ? false : this.attacker.isWithinHomeDistance(MathHelper.floor_double(entitylivingbase.posX), MathHelper.floor_double(entitylivingbase.posY), MathHelper.floor_double(entitylivingbase.posZ)));
}

/**
 * Execute a one shot task or start executing a continuous task
 */
@Override
public void startExecuting() {
	this.attacker.getNavigator().setPath(this.entityPathEntity, this.speedTowardsTarget);
	this.field_75445_i = 0;
}

/**
 * Resets the task
 */
@Override
public void resetTask() {
	this.attacker.getNavigator().clearPathEntity();
}

/**
 * Updates the task
 */
@Override
public void updateTask() {
	EntityLivingBase entitylivingbase = this.attacker.getAttackTarget();
	this.attacker.getLookHelper().setLookPositionWithEntity(entitylivingbase, 30.0F, 30.0F);
	double distanceToTarget = this.attacker.getDistanceSq(entitylivingbase.posX, entitylivingbase.boundingBox.minY, entitylivingbase.posZ);
	double attackDistance = this.attacker.width * 2.0F * this.attacker.width * 2.0F + entitylivingbase.width;
	--this.field_75445_i;

	if ((this.attacker.getEntitySenses().canSee(entitylivingbase)) && this.field_75445_i <= 0 && (this.field_151497_i == 0.0D && this.field_151495_j == 0.0D && this.field_151496_k == 0.0D || entitylivingbase.getDistanceSq(this.field_151497_i, this.field_151495_j, this.field_151496_k) >= 1.0D || this.attacker.getRNG().nextFloat() < 0.05F)) {
		this.field_151497_i = entitylivingbase.posX;
		this.field_151495_j = entitylivingbase.boundingBox.minY;
		this.field_151496_k = entitylivingbase.posZ;
		this.field_75445_i = failedPathFindingPenalty + 4 + this.attacker.getRNG().nextInt(7);

		if (this.attacker.getNavigator().getPath() != null) {
			PathPoint finalPathPoint = this.attacker.getNavigator().getPath().getFinalPathPoint();
			if (finalPathPoint != null && entitylivingbase.getDistanceSq(finalPathPoint.xCoord, finalPathPoint.yCoord, finalPathPoint.zCoord) < 1) {
				failedPathFindingPenalty = 0;
			} else {
				failedPathFindingPenalty += 10;
			}
		} else {
			failedPathFindingPenalty += 10;
		}

		if (distanceToTarget > 1024.0D) {
			this.field_75445_i += 10;
		} else if (distanceToTarget > 256.0D) {
			this.field_75445_i += 5;
		}

		if (!this.attacker.getNavigator().tryMoveToEntityLiving(entitylivingbase, this.speedTowardsTarget)) {
			this.field_75445_i += 15;
		}
	}

	this.attackTick = Math.max(this.attackTick - 1, 0);

	if (distanceToTarget <= attackDistance && this.attackTick <= 20) {
		this.attackTick = 20;

		if (this.attacker.getHeldItem() != null) {
			this.attacker.swingItem();
		}

		this.attacker.attackEntityAsMob(entitylivingbase);

		Random random = new Random();

		if (this.infectionChance >= random.nextInt(100)) {
			NBTTagCompound nbt;

			if (entitylivingbase.getEntityData() != null) {
				nbt = entitylivingbase.getEntityData();
			} else {
				nbt = new NBTTagCompound();
			}
			nbt.setBoolean("dimensionshift.infectus.illness." + this.illnessName, true);

			if (this.diesAfterInfection) {
				this.attacker.setDead();
			}

			// entitylivingbase.writeToNBT(nbt);
		}

	}
}
}

 

 

 

Spawning:

http://www.minecraftforge.net/forum/index.php?topic=6092.0

Here could be your advertisement!

Posted

I made a pretty generic render class - not perfect, but for probably 80-90% of the types of mobs people create, it will work.

 

Example usage:

RenderingRegistry.registerEntityRenderingHandler(EntityDarknut.class, new RenderGenericLiving(
			new ModelDarknut(), 0.5F, 1.5F, ModInfo.ID + ":textures/entity/darknut_standard.png"));

Only thing missing is armor rendering - it renders held items and helmets, though all of that code will have to change drastically for 1.8.

 

I don't have any entity classes that are simple enough for your project, except maybe the NPCs.

 

Jabelar has some good tutorials on custom AI, animations, and probably some other stuff about entities that may help, especially since you have never coded an entity before.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.