Jump to content

Recommended Posts

Posted (edited)

Hey all,

I'm pretty new to modding and am having trouble learning all the basics. I've figured out how to register and create my own blocks/items as well as how to give them custom properties and such. However, I'm having trouble figuring out how to get started with creating and registering entities. Does anyone have any examples they can post on how to register and create custom entities in 1.13.2? 

Thank you!

Edited by iLaysChipz
Posted

You would subscribe to a registry event that fires for the EntityType registry, then register your EntityType into said registry.

That's it. Nothing else changed from 1.12 or earlier.

Posted
On 5/6/2019 at 2:14 AM, V0idWa1k3r said:

You would subscribe to a registry event that fires for the EntityType registry

This is now on the mod event bus

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted (edited)

Can I get an example for what the register event should look like? Right now I have something that looks like

Register Event

@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD)
public static class RegistryEvents
{	
    @SubscribeEvent
    public static void registerEntities(final RegistryEvent.Register<EntityType<?>> event)
    {
        event.getRegistry().registerAll
        (
		EntityList.test = EntityType.Builder.create(EntityTest.class, i_have_no_idea_what_goes_here);
        );
    }
}

Entity Class

public class EntityTest extends EntityLiving implements IMob
{
	protected EntityTest(EntityType<?> type, World world)
	{
		super(type, world);
	}

	@Override
	protected void registerAttributes()
	{
		super.registerAttributes();
		this.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(0.0D);
		this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.0D);
		this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(0.0D);
		this.getAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(1.0D);
		this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(30.0D);
	}
	
	@Override
	public boolean isAIDisabled()
	{
		return true;
	}
	
	@Override
	public boolean canBeCollidedWith()
	{
		return true;
	}
}

Model Class

@OnlyIn(Dist.CLIENT)
public class ModelTest extends ModelBase
{
	protected ModelRenderer test_cube;
	
	public ModelTest(float scale)
	{
		test_cube = new ModelRenderer(this);
		test_cube.addBox(-4.0F, 16.0F, -4.0F, 8, 8, 8);
		test_cube.setRotationPoint(0f, 8f, 0f);
	}
	
	@Override
	public void render(Entity entity, float f1, float f2, float f3, float f4, float f5, float scale)
	{
		this.setRotationAngles(f1, f2, f3, f4, f5, scale, entity);
		test_cube.render(scale);
	}
}

Render Class

@OnlyIn(Dist.CLIENT)
public class RenderTest extends RenderLiving<EntityTest>
{
	private static final ResourceLocation TEST_TEXTURES = new ResourceLocation("textures/entity/slime/slime.png");
	
	public RenderTest(RenderManager renderer)
	{
		super(renderer, new ModelTest(16), 0.25f);
	}
	
	protected ResourceLocation getEntityTexture(EntityTest entity)
	{
		return TEST_TEXTURES;
	}
}

Class holding entity declaration

public class EntityList
{
	public static EntityType<EntitySilkNest> silk_nest;
}

 

Also, I'm a little lost on how to connect the renderer, model, and entity together

Edited by iLaysChipz
Posted (edited)

I edited the last post with all the relevant code. All I'm trying to create for now is a cube that can be attacked and defeated like any other mob. If I can get to that point I think I can handle everything else I need from there. Any resources on where I can find this information on my own would be really helpful. I'm sorry for all the trouble as I know this is a lot to ask. Thank you all for your input so far. I do appreciate it.

Edited by iLaysChipz
Posted

Entity registration code (1.12.2, but nothing changed except that the event is now fired on the mod event bus) (you’ll need to scroll down a bit) https://gist.github.com/Cadiboo/b825d62fb46538e7b7b262c5612d62aa

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted

Hey Cadiboo, thank you so much for replying!

I couldn't find EntityEntry, but based on the post here, I think it's been updated to EntityType<T>.

It seems the create method needs a class (Class<? extends T> entityClassIn) and world (Function<? super World, ? extends T> factoryIn).

So far I've been able to get this to run:

@SubscribeEvent
    public static void registerEntities(final RegistryEvent.Register<EntityType<?>> event)
    {
        event.getRegistry().registerAll
        (
        	EntityList.test = EntityType.Builder.create(EntityTest.class, null).build("test").setRegistryName(MODID,"test")
        );
    }

However, I can't summon the mob, and I can't find how to make a new spawn egg. Could you point me in the right direction on where to look?

Again, thank you so much for taking the time to help me out :)

 

Posted
2 hours ago, iLaysChipz said:

EntityType.Builder.create(EntityTest.class, null)

You set your factory (the function that makes instances of your entity) to null.

Example:

EntityType.Builder.create(EntityButterfly.class, EntityButterfly::new).tracker(200, 1, true).build("common_butterfly1").setRegistryName(MOD_ID, "common_butterfly1")

 

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted (edited)

I thought so, but I'm getting an error I'm not sure how to resolve.

It says The type EntityTest does not define EntityTest(World) that is applicable here.

If I look to EntitySlime, I see it's constructors defined as: 

protected EntitySlime(EntityType<?> p_i48552_1_, World p_i48552_2_) {
	super(p_i48552_1_, p_i48552_2_);
	this.moveHelper = new EntitySlime.SlimeMoveHelper(this);
}

public EntitySlime(World worldIn) {
	this(EntityType.SLIME, worldIn);
}

where SLIME is defined in EntityType as a constant as:

public static final EntityType<EntityTest> TEST = EntityType.register("test", EntityType.Builder.create(EntityTest.class, EntityTest::new));

 

So now I have my code looking like:

public class EntityList {
	public static final EntityType<EntityTest> TEST = EntityType.register("test", EntityType.Builder.create(EntityTest.class, EntityTest::new));
}
// =============================================================================================================================================
//...
  protected EntityTest(World world) {
      this(EntityList.TEST,world);
  }

  protected EntityTest(EntityType<?> type, World world) {
      super(type, world);
      this.moveHelper = new EntityMoveHelper(this);
  }
//...

 

I'm sorry if these are dumb questions, I've always learned best by example, and I'm having a lot of trouble trying to extrapolate the in-between bits on my own. Am I supposed to be casting the function as a factory somehow? Or is there extra parts needed in the constructor? 

Edited by iLaysChipz
Posted
21 minutes ago, iLaysChipz said:

public static final EntityType<EntityTest> TEST = EntityType.register("test", EntityType.Builder.create(EntityTest.class, EntityTest::new));

No. Don't ever do that. Don't use static initializers for registry entries, this can and WILL break stuff.

 

There are many ways to get the reference to your EntityType, like the ObjectHolder annotation or simply a field.

Posted (edited)

Gotcha, thank you for letting me know! I honestly had no idea. I think I'm going to try and create a universal setup method like I saw in Cadiboo's example. 

 

I'm still getting an error with this second argument for the method EntityType.Builder.create(entityClassIn, factoryIn). I think the problem is because I'm not sure what to pass for the first argument of the constructor, which is asking for an EntityType. All the vanilla mobs pass in final static instances of themselves which is hella confusing to me. Does anyone know what the first argument for EntityLivingBase should be for a custom entity that extends it?

Edited by iLaysChipz
Posted
28 minutes ago, iLaysChipz said:

I think the problem is because I'm not sure what to pass for the first argument of the constructor, which is asking for an EntityType. All the vanilla mobs pass in final static instances of themselves which is hella confusing to me.

Pass your EntityType, obviously, that's what it is asking of you.

Don't use a static initializer for it.

Use the ObjectHolder annotation to get the reference to your EntityType, or store it in a field and pass said field.

  • 4 weeks later...
Posted

I too am having problems adding a custom entity (that I had previously working under 12.2)

I have an entity (extended from EntityChicken + some code borrowed from vanilla horse class) with a custom renderer and model.

 

It looks like the entity gets registered as it I can do a "/summon chicken_mod:protochicken" in-game, but what I get is a normal vanilla chicken (as identified when targeted in debug screen), albeit with some of the behaviors I'm trying to add (for instance riding like a saddled horse)

 

My code in its entirety can be found here: https://github.com/pchonacky/randombits.git, but I will include the important bits below for brevity.

 

Any help is appreciated.

/Philip

 

Rendering Registration:

    private void setup(final FMLCommonSetupEvent event)
    {
    	DistExecutor.runWhenOn(
                Dist.CLIENT, () -> () -> 
                RenderingRegistry.registerEntityRenderingHandler(EntityProtoChicken.class,RenderProtoChicken :: new)
                );
    }

 

Entity Registration (edited sightly for brevity):

    @Mod.EventBusSubscriber(modid=ChickenMod.MODID, bus=Mod.EventBusSubscriber.Bus.MOD)
    @ObjectHolder(ChickenMod.MODID)
    public static class RegistryEvents {

  
    	//Register Entities
    	@SubscribeEvent
    	public static void onEntitiesRegistry(final RegistryEvent.Register<EntityType<?>> entityRegistryEvent) {	
    		entityRegistryEvent.getRegistry().registerAll(		    	
    		    EntityType.Builder.create(EntityProtoChicken.class, EntityProtoChicken::new)
    		    	.tracker(60, 24, true).disableSerialization().build("protochicken").setRegistryName(MODID, "protochicken")
    			);	
    	}
    
    }  //RegistryEvents class

 

Custom Entity:

package net.chonacky.minecraft.mod.chicken_mod;

import javax.annotation.Nullable;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.passive.EntityChicken;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;

public class EntityProtoChicken extends EntityChicken 
{

	public EntityProtoChicken(World worldIn) {
		super(worldIn);

		this.setSize(2.5F, 5.0F);
		this.setBoundingBox(this.getBoundingBox().offset(0, 0, 25));
		this.stepHeight = 2.1F;
//		this.jumpPower = 0.0F;
//		this.isJumping = false;
	}
	
	@Override
	public float getEyeHeight() {
	
		return super.getEyeHeight()-0.5F;
	}

	
	@Override
	public void livingTick()
	    {
	        super.livingTick();
	        if (this.world.isRemote && this.dataManager.isDirty())  {
	            this.dataManager.setClean();
	        }
	    }
	
	@Override 
    public boolean processInteract(EntityPlayer player, EnumHand hand)
	    {
		 this.mountTo(player);
		 super.processInteract(player, hand);
		 return true;
	    }
	
	 
	protected void mountTo(EntityPlayer player)
	    {
	        player.rotationYaw = this.rotationYaw;
	        player.rotationPitch = this.rotationPitch;
	        if (!this.world.isRemote)  player.startRiding(this);
	    }

	@Override
	 public void updatePassenger(Entity passenger)
	    {
	        super.updatePassenger(passenger);
	        float f = MathHelper.sin(this.renderYawOffset * 0.017453292F);
	        float f1 = MathHelper.cos(this.renderYawOffset * 0.017453292F);
//unused	float f2 = 0.1F;
//unused	float f3 = 0.0F;
	        passenger.setPosition(
	        		this.posX + (double)(0.1F * f),
	        		this.posY + (double)(this.height * 0.35F) + passenger.getYOffset() + 0.0D,
	        		this.posZ - (double)(0.1F * f1)													);
	        if (passenger instanceof EntityLivingBase)	((EntityLivingBase)passenger).renderYawOffset = this.renderYawOffset;
	    }

	 

	@Override
	public void travel(float strafe, float vertical, float forward)
	    {	
	        if (this.isBeingRidden() && this.canBeSteered() )	{
	        										//&& this.isHorseSaddled()
	            EntityLivingBase controllingPassenger = (EntityLivingBase)this.getControllingPassenger();
	            this.rotationYaw = controllingPassenger.rotationYaw;
	            this.prevRotationYaw = this.rotationYaw;
	            this.rotationPitch = controllingPassenger.rotationPitch * 0.5F;
	            this.setRotation(this.rotationYaw, this.rotationPitch);
	            this.renderYawOffset = this.rotationYaw;
	            this.rotationYawHead = this.renderYawOffset;
	            strafe = controllingPassenger.moveStrafing * 0.5F;
	            forward = controllingPassenger.moveForward;
	            if (forward <= 0.0F) forward *= 0.25F; 
	            this.jumpMovementFactor = this.getAIMoveSpeed() * 0.1F;
	            if (this.canPassengerSteer()) {
	                this.setAIMoveSpeed((float)this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue());
	                super.travel(strafe, vertical, forward);
	            }
	            else if (controllingPassenger instanceof EntityPlayer)  {
	                this.motionX = 0.0D;
	                this.motionY = 0.0D;
	                this.motionZ = 0.0D;
	            }
	            if (this.onGround)	 this.isJumping = false;
	        }
	        else {
	            this.jumpMovementFactor = 0.02F;
	            super.travel(strafe, vertical, forward);
	        }   
	    }

	@Override    
	public boolean canBeSteered()  
		{
	        return this.getControllingPassenger() instanceof EntityLivingBase;
	    }    
	    
	@Override @Nullable
    public Entity getControllingPassenger()
	    {
	        return this.getPassengers().isEmpty() ? null : (Entity)this.getPassengers().get(0);
	    }

}

 

 

Custom Model:

package net.chonacky.minecraft.mod.chicken_mod;

import net.minecraft.client.renderer.entity.model.ModelBase;
import net.minecraft.client.renderer.entity.model.ModelRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

@OnlyIn(Dist.CLIENT)
public class ModelProtoChicken extends ModelBase
{
    
	public ModelRenderer head;
    public ModelRenderer body;
    public ModelRenderer rightLeg;
    public ModelRenderer leftLeg;
    public ModelRenderer rightShin;
    public ModelRenderer leftShin;
    public ModelRenderer leftFoot;
    public ModelRenderer rightFoot;


    public ModelProtoChicken()
    {
    	
       this.textureWidth = 132;
       this.textureHeight = 64;
       
    	
    	this.head = new ModelRenderer(this, 0, 16);
        this.head.addBox(-8.0F, -8.0F, -8.0F, 16, 8, 16, 5.0F); 
        this.head.setRotationPoint(0.0F, -42.0F, 0.0F);

        this.body = new ModelRenderer(this, 0, 0);
        this.body.addBox(-16.0F, -16.0F, -16.0F, 32, 32, 32, 5.0F); 
        this.body.setRotationPoint(0.0F, -23.0F, 0.0F);

       this.leftLeg = new ModelRenderer(this, 128,32);
       this.leftLeg.addBox(0.0F, 0.5F, 0.0F, 1, 13, 1 , 3.0F); 
       this.leftLeg.setRotationPoint(20.0F, 0.0F, -24.0F);
       this.body.addChild(this.leftLeg);

       this.leftShin = new ModelRenderer(this, 128,32);
       this.leftShin.addBox(0.0F, -0.5F, 0.0F, 1, 13, 1, 3.0F); 
       this.leftShin.setRotationPoint(0.0F, 12.0F, 0.0F);
       this.leftLeg.addChild(this.leftShin);
       
       this.leftFoot = new ModelRenderer(this,128,32);
       this.leftFoot.addBox(0.0F, 1.0F, -0.0F, 1, 4, 1, 3.0F);
       this.leftFoot.setRotationPoint(0.0F, 14.0F, 0.0F);
       this.leftShin.addChild(this.leftFoot);
       

       this.rightLeg = new ModelRenderer(this, 128,32);
       this.rightLeg.addBox(0.0F, 0.5F, 0.0F, 1, 13, 1 , 3.0F); 
       this.rightLeg.setRotationPoint(-20.0F, 0.0F, -24.0F);
       this.body.addChild(this.rightLeg);

       this.rightShin = new ModelRenderer(this, 128,32);
       this.rightShin.addBox(0.0F, -0.5F, 0.0F, 1, 13, 1, 3.0F); 
       this.rightShin.setRotationPoint(0.0F, 12.0F, 0.0F);
       this.rightLeg.addChild(this.rightShin);
      
       this.rightFoot = new ModelRenderer(this,128,32);
       this.rightFoot.addBox(0.0F, 1.0F, -0.0F, 1, 4, 1, 3.0F);
       this.rightFoot.setRotationPoint(0.0F, 14.0F, 0.0F);
       this.rightShin.addChild(this.rightFoot);
      
//        

    }

    /**
     * Sets the models various rotation angles then renders the model.
     */
    @Override
    public void render(Entity entityIn, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scale)
    {
        this.setRotationAngles(limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale, entityIn);
        this.head.render(scale);
        this.body.render(scale);   
    }

    /**
     * Sets the model's various rotation angles. For bipeds, par1 and par2 are used for animating the movement of arms
     * and legs, where par1 represents the time(so that arms and legs swing back and forth) and par2 represents how
     * "far" arms and legs can swing at most.
     */
    @Override
    public void setRotationAngles(float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scaleFactor, Entity entityIn)
    {
        this.head.rotateAngleX = headPitch * 0.017453292F;
        this.head.rotateAngleY = netHeadYaw * 0.017453292F;
        this.body.rotateAngleX = ((float)Math.PI / 2F);
        this.leftLeg.rotateAngleX =  (MathHelper.cos(limbSwing * 0.6662F + (float)Math.PI) * 1.4F * limbSwingAmount) -((float)Math.PI/4);
        this.leftShin.rotateAngleX = -(MathHelper.cos(limbSwing * 0.6662F + (float)Math.PI) * 1.4F * limbSwingAmount) -((float)Math.PI/2);
        this.leftFoot.rotateAngleX = -((float)Math.PI/4) ;
        this.rightLeg.rotateAngleX =  -(MathHelper.cos(limbSwing * 0.6662F + (float)Math.PI) * 1.4F * limbSwingAmount) -((float)Math.PI/4);
        this.rightShin.rotateAngleX = +(MathHelper.cos(limbSwing * 0.6662F + (float)Math.PI) * 1.4F * limbSwingAmount) -((float)Math.PI/2);
        this.rightFoot.rotateAngleX = -((float)Math.PI/4) ;
//        this.rightWing.rotateAngleZ = ageInTicks;
//        this.leftWing.rotateAngleZ = -ageInTicks;
    }
}

 

Custom Renderer:

package net.chonacky.minecraft.mod.chicken_mod;

import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;


@OnlyIn(Dist.CLIENT)
public class RenderProtoChicken extends RenderLiving<EntityProtoChicken>
{

	 private static final ResourceLocation PROTOCHICKEN_TEXTURES = new ResourceLocation(ChickenMod.MODID+":textures/entity/byhut.png");
    																	//"chicken:textures/entity/checker.png"
	 
	 // public RenderLiving(RenderManager rendermanagerIn, ModelBase modelbaseIn, float shadowsizeIn)
    public RenderProtoChicken(RenderManager manager)
    {
    	super(manager, new ModelProtoChicken(), 1.75F);
    }
 
    @Override
	protected ResourceLocation getEntityTexture(EntityProtoChicken entity) {
		
		return PROTOCHICKEN_TEXTURES;
	}

    /**
     * Defines what float the third param in setRotationAngles of ModelBase is
     */
    @Override
    protected float handleRotationFloat(EntityProtoChicken livingBase, float partialTicks)
    {
        float f = livingBase.oFlap + (livingBase.wingRotation - livingBase.oFlap) * partialTicks;
        float f1 = livingBase.oFlapSpeed + (livingBase.destPos - livingBase.oFlapSpeed) * partialTicks;
        return (MathHelper.sin(f) + 1.0F) * f1;
    }

    @Override
    public void doRender(EntityProtoChicken entity, double x, double y, double z, float entityYaw, float partialTicks)
    {
        if (entity.isInWater()) {
          	super.doRender(entity, x, (y-1.0D), z, entityYaw, partialTicks);
        }
        else {
          	super.doRender(entity, x, y, z, entityYaw, partialTicks);
        }
        if (!this.renderOutlines)
        {
            this.renderLeash(entity, x, y, z, entityYaw, partialTicks);
        }
    }
    
	
}

 

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.