Posted January 24, 201510 yr 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
January 24, 201510 yr 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!
January 24, 201510 yr 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!
January 24, 201510 yr Author Thanks, I'll take a look The project is at https://github.com/TheGreyGhost/MinecraftByExample -TGG
January 24, 201510 yr 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. http://i.imgur.com/NdrFdld.png[/img]
January 25, 201510 yr TheGreyGhost, lord of coding...how could you? Just kidding; it's not too hard to learn how to code an entity. This tutorial should help you. Maker of the Craft++ mod.
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.