Jump to content

[1.7.10] Questions about rendering thrown entities


CactusCoffee

Recommended Posts

In my project I have an entity that behaves like a thrown item, a magic spell entity created using a staff (the entity itself is not an item). I also want to have the entity's texture reflect the spell's type (a red projectile for fire, blue for water, etc.). Currently I have the rendering class set up to use default icons for each type, eventually I'll use my own textures. I have a couple questions regarding how to implement these behaviors.

 

1) - I would like to avoid creating an item class for the entity, as it is not created by throwing an item. I have looked at the code in RenderSnowball and similar classes and have been unable to find an IIcon that does not require a base item. Is it possible to get an IIcon for an entity without an item to go with it? Is there any way to register the icons in the entity/render classes?

 

2) - I have a switch statement set up to get an icon based on the rendered entity's type. This takes place in the doRender method, by casting the Entity parameter to my custom entity class and using a getter for the type, then performing a switch on that value. This should return a unique icon for each type, or a default for a null type. Looking at the code for getting potion damage, this should work, but it doesn't, it returns the icon indicating the null type instead. I have considered creating a subclass for entities of each type, but I am confident there is a more practical way to accomplish this goal. While the only differences between the entity textures I have set up are the colors, I would rather not use a coloration of a single texture (like thrown potions use). Is it possible to do this? If so, how?

Link to comment
Share on other sites

Here's the relevant code for the renderer.

[...]
public class RenderMagicOrb extends Render
{
    private int element;

    public RenderMagicOrb(int data)
    {
        this.element = data;
    }

    public RenderMagicOrb()
    {
        this(0);
    }

    public void doRender(Entity entity, double x, double y, double z, float f, float f1)
    {
    		IIcon iicon = getIcon(((EntityMagicOrb)entity).getElement());
    		
            GL11.glPushMatrix();
            GL11.glTranslatef((float)x, (float)y, (float)z);
            GL11.glEnable(GL12.GL_RESCALE_NORMAL);
            GL11.glScalef(0.5F, 0.5F, 0.5F);
            bindEntityTexture(entity);
            Tessellator tessellator = Tessellator.instance;
            func_77026_a(tessellator, iicon);
            GL11.glDisable(GL12.GL_RESCALE_NORMAL);
            GL11.glPopMatrix();
    }

    private void func_77026_a(Tessellator t, IIcon iicon)
    {
    (Same as RenderSnowball)
    }
    
    private IIcon getIcon(int e) //Returns the icon based on the element value
    {
    	Item t = Items.nether_star;
    	switch(e)
    	{
    	case 1: t = Items.fire_charge;
    	case 2: t = Items.magma_cream;
    	case 3: t = Items.slime_ball;
    	case 4: t = Items.clay_ball;
    	case 5: t = Items.ender_pearl;
    	case 6: t = Items.snowball;
    	}
    	return t.getIconFromDamage(0);
    }

@Override
protected ResourceLocation getEntityTexture(Entity p_110775_1_) 
{
	return TextureMap.locationItemsTexture;
}
}

 

All it requires from the entity is the element, which is an integer from 1-6. Here's the relevant bits of the entity class:

[...]
public class EntityMagicOrb extends EntityThrowable
{	
public int spell;
public int element;

public EntityMagicOrb(World world)
{
	super(world);
}
public EntityMagicOrb(World world, int sp, int e)
{
	super(world);
	spell = sp;
	element = e;
}
    public EntityMagicOrb(World world, EntityLivingBase entity, int sp, int e)
    {
        super(world, entity);
        spell = sp;
        element = e;
    }

    [...]

    public int getElement()
    {
    	return element;
    }
}

Link to comment
Share on other sites

1)

Looking at what I'd need to do to get a TextureStitchEvent working, I think it'd probably be easier to just make a hidden item class that handles the icons, unless that's bad practice or something. Thanks for your help.

2)

So I added the IAdditionalSpawnData implementation:

	@Override
public void writeSpawnData(ByteBuf buffer) 
{
	buffer.writeInt(element);
	System.out.println("Spawn data written");
}
@Override
public void readSpawnData(ByteBuf additionalData) 
{
	element = additionalData.readInt();
	System.out.println("Spawn data read");
}

Tried it out and the methods are being called but it still isn't affecting the entity icon. I don't know if that's a problem with the renderer or with the additional spawn data implementation. I'm probably missing something blindingly obvious but this is an entirely new thing to me. Whatever the case, thanks for your help.

Link to comment
Share on other sites

Did you put 'break;' in each of your switch cases as diesieben pointed out? If they are missing, each case simply falls through to the next and you end up returning the snowball icon.

 

As an alternative to break, you could simply return the icon directly in each case, effectively breaking out of the switch that way.

 

Re: #1, you don't need to make a hidden item to render a texture, you can bind your ResourceLocation and then draw it using the Tessellator.

Link to comment
Share on other sites

I put the breaks in.

Not sure how to bind the resourcelocation / use tessellator.

Basically like this:

public YourClass extends Render {
public void doRender(Entity entity, double x, double y, double z, float yaw, float partialTick) {
// probably call GL pushMatrix here
bindTexture(yourTextureResourceLocation);
// you'll probably want some rotate and / or translates here to get everything looking right
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 1.0F, 0.0F);
// then add all the vertices - you'll need to change the numbers to match your texture
tessellator.addVertexWithUV(-0.5D, -0.25D, 0.0D, 0, 1);
tessellator.addVertexWithUV(0.5D, -0.25D, 0.0D, 1, 1);
tessellator.addVertexWithUV(0.5D, 0.75D, 0.0D, 1, 0);
tessellator.addVertexWithUV(-0.5D, 0.75D, 0.0D, 0, 0);
tessellator.draw();
// pop the matrix if you pushed
}
}

You'll probably want to search on Google for information about Tessellator and addVertexWithUV to better understand what's going on.

Link to comment
Share on other sites

I did some tinkering with your suggestion and got it to use the texture. Here's the render class as it is now:

(package)

(imports)

public class RenderMagicOrb extends Render
{
    private int element;
    
    private static final ResourceLocation texRed = new ResourceLocation(SimplyMagicMod.MODID, "textures/entity/magicorb_red.png");
    private static final ResourceLocation texYel = new ResourceLocation(SimplyMagicMod.MODID, "textures/entity/magicorb_yellow.png");
    private static final ResourceLocation texGrn = new ResourceLocation(SimplyMagicMod.MODID, "textures/entity/magicorb_green.png");
    private static final ResourceLocation texBlu = new ResourceLocation(SimplyMagicMod.MODID, "textures/entity/magicorb_blue.png");
    private static final ResourceLocation texBlk = new ResourceLocation(SimplyMagicMod.MODID, "textures/entity/magicorb_black.png");
    private static final ResourceLocation texWhi = new ResourceLocation(SimplyMagicMod.MODID, "textures/entity/magicorb_white.png");

    public RenderMagicOrb(int data)
    {
        this.element = data;
    }

    public RenderMagicOrb()
    {
        this(0);
    }

    public void doRender(Entity entity, double x, double y, double z, float yaw, float partialTick)
    {
    	bindTexture(chooseTexture(((EntityMagicOrb)entity).getElement()));
    	GL11.glPushMatrix();
    	GL11.glTranslatef((float)x, (float)y, (float)z);
        GL11.glEnable(GL12.GL_RESCALE_NORMAL);
        GL11.glScalef(0.5F, 0.5F, 0.5F);
        Tessellator tessellator = Tessellator.instance;
        GL11.glRotatef(180.0F - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
        GL11.glRotatef(-renderManager.playerViewX, 1.0F, 0.0F, 0.0F);
        tessellator.startDrawingQuads();
        tessellator.setNormal(0.0F, 1.0F, 0.0F);
        tessellator.addVertexWithUV(-0.5D, -0.25D, 0.0D, 0, 1);
        tessellator.addVertexWithUV(0.5D, -0.25D, 0.0D, 1, 1);
tessellator.addVertexWithUV(0.5D, 0.75D, 0.0D, 1, 0);
tessellator.addVertexWithUV(-0.5D, 0.75D, 0.0D, 0, 0);
tessellator.draw();
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
    }
    
private ResourceLocation chooseTexture(int element) 
{
	switch (element)
	{
	case 1: return texRed;
	case 2: return texYel;
	case 3: return texGrn;
	case 4: return texBlu;
	case 5: return texBlk;
	case 6: return texWhi;
	default: return texWhi;
	}
}

@Override
protected ResourceLocation getEntityTexture(Entity p_110775_1_) 
{
	return TextureMap.locationItemsTexture;
}
}

I still need to figure out how to get the additional spawn data to work, as it's always using the default white texture. So far I haven't found any useful tutorials or other mod support regarding that, I need to do some more digging. Thanks for your help.

Link to comment
Share on other sites

IEntityAdditionalSpawnData is very simple: it lets you add extra data to the spawn packet (on the server) that gets sent to the client, and then read your extra data on the client. You just have to implement it, then make sure that whatever data you need is set BEFORE you spawn the entity in the world; usually onSpawnWithEgg is a good place to do that, or, since it's a magic spell, just call setElement(int) before you spawn the entity.

Link to comment
Share on other sites

I've taken a look at some other mod support requests, and so far I've implemented IEntityAdditionalSpawnData in the entity class and added the writeSpawnData and ReadSpawnData methods:

@Override
public void writeSpawnData(ByteBuf buffer) 
{
	buffer.writeInt(element);
}
@Override
public void readSpawnData(ByteBuf additionalData) 
{
	element = additionalData.readInt();
}

If I'm understanding this correctly, this should let the renderer as it is use the correct texture. The entity's element value is set in its constructer, and I've also tried using setElement before spawning the entity in the world. It's still just using the default texture. To my understanding, nothing more is required from this, so I've buggered up something, and I don't know how to find out what, or what I did wrong.

 

EDIT: So I did a System.out.println and found that it's not writing. One mystery solved, but I still don't understand why that's occuring.

Link to comment
Share on other sites

Entity registry:

int randomId = EntityRegistry.findGlobalUniqueEntityId();
EntityRegistry.registerGlobalEntityID(EntityMagicOrb.class, "Magic Orb", randomId);
EntityRegistry.registerModEntity(EntityMagicOrb.class, "Magic Orb", randomId, this.instance, 64, 1, true);

 

Method in staff item that spawns entity:

private void spawnProjectile(ItemStack itemStack, World world, EntityPlayer player)
{
if (!world.isRemote)
{
	world.spawnEntityInWorld(new EntityMagicOrb(world, player, itemStack.stackTagCompound.getInteger("SpellID"), itemStack.stackTagCompound.getInteger("Element")));
}
}

 

System out when spawning entity:

[11:03:39] [server thread/INFO] [sTDOUT]: [com.finneyt.simplymagic.entity.EntityMagicOrb:writeSpawnData:390]: Write: 0
[11:03:39] [Client thread/INFO] [sTDOUT]: [com.finneyt.simplymagic.entity.EntityMagicOrb:readSpawnData:396]: Read: 0

Link to comment
Share on other sites

You shouldn't use global entity ID - ONLY use registerModEntity, especially if your entity does not need a spawn egg.

 

Are you sure that the ItemStack NBT tag has the appropriate data when creating your entity? Print that out, too. This is basic debugging, and something you should become more familiar with if you wish to solve problems on your own.

Link to comment
Share on other sites

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.



×
×
  • Create New...

Important Information

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