Jump to content

Recommended Posts

Posted

My mod adds a new potion, but for reasons, the splash version doesn't extend EntityPotion; it just extends EntityThrowable and re-implements many of the methods that EntityPotion would. Almost everything works: the items render, the potion effect works, etc. The only thing that isn't working is that the thrown splash potion isn't rendering. It'll render as an item in my hand and inventory, and the particles render when it hits the ground, but while in the air, it's invisible.

 

I'm piggybacking on RenderSnowball, like most throwable entities do, with this in my mod's main init() method:

 

RenderingRegistry.registerEntityRenderingHandler(EntityPotionLifelock.class, new RenderSnowball(WeaponTweaks.itemSplashPotionLifelock));

 

itemSplashPotionLifelock is an instance of ItemPotionLifelock (code below) with "splash" set to true:

 

package com.IceMetalPunk.weapontweaks.items;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.IceMetalPunk.weapontweaks.WeaponTweaks;
import com.IceMetalPunk.weapontweaks.entities.EntityPotionLifelock;
import com.IceMetalPunk.weapontweaks.potions.PotionLifelock;
import com.google.common.collect.HashMultimap;

import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.IAttribute;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.EnumAction;
import net.minecraft.item.Item;
import net.minecraft.item.ItemPotion;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
import net.minecraft.util.StatCollector;
import net.minecraft.util.StringUtils;
import net.minecraft.world.World;

public class ItemPotionLifelock extends Item {

public boolean isSplash;
public IIcon icon, iconSplash, iconOverlay;
public int level, duration;

public ItemPotionLifelock(boolean splash) {
	this.setMaxStackSize(1);
	this.setMaxDamage(0);
	this.setCreativeTab(CreativeTabs.tabBrewing);
	this.isSplash = splash;
	this.level = 0;
	this.duration = 600;
}

public ItemPotionLifelock() {
	this(false);
}

/* Override onEaten to make drinking this apply the appropriate effect */
@Override
public ItemStack onEaten(ItemStack item, World world, EntityPlayer player) {
	if (!player.capabilities.isCreativeMode) {
		--item.stackSize;
	}

	if (!world.isRemote) {
		/* Arguments: potion_ID, duration, level, ambient */
		player.addPotionEffect(new PotionEffect(WeaponTweaks.potionLifeLock.id, this.duration, this.level, false));
	}

	if (!player.capabilities.isCreativeMode) {
		if (item.stackSize <= 0) {
			return new ItemStack(Items.glass_bottle);
		}

		player.inventory.addItemStackToInventory(new ItemStack(Items.glass_bottle));
	}

	return item;
}

@Override
public int getMaxItemUseDuration(ItemStack item) {
	return 32;
}

@Override
public EnumAction getItemUseAction(ItemStack item) {
	return EnumAction.drink;
}

@Override
public ItemStack onItemRightClick(ItemStack item, World world, EntityPlayer player) {
	if (isSplash) {
		if (!player.capabilities.isCreativeMode) {
			--item.stackSize;
		}

		world.playSoundAtEntity(player, "random.bow", 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));

		if (!world.isRemote) {
			world.spawnEntityInWorld(new EntityPotionLifelock(world, player, item));
		}

		return item;
	} else {
		player.setItemInUse(item, this.getMaxItemUseDuration(item));
		return item;
	}
}

@Override
public boolean onItemUse(ItemStack item, EntityPlayer player, World world, int x, int y, int z, int side, float px,
		float py, float pz) {
	return false;
}

@Override
public IIcon getIconFromDamage(int damage) {
	return (this.isSplash ? this.iconSplash : this.icon);
}

@SideOnly(Side.CLIENT)
@Override
public IIcon getIconFromDamageForRenderPass(int damage, int pass) {
	return pass == 0 ? this.iconOverlay : super.getIconFromDamageForRenderPass(damage, pass);
}

@SideOnly(Side.CLIENT)
public int getColorFromDamage(int damage) {
	return PotionLifelock.liquidColor;
}

@SideOnly(Side.CLIENT)
public int getColorFromItemStack(ItemStack item, int damage) {
	return damage > 0 ? 16777215 : this.getColorFromDamage(item.getItemDamage());
}

@SideOnly(Side.CLIENT)
@Override
public boolean requiresMultipleRenderPasses() {
	return true;
}

@Override
public String getItemStackDisplayName(ItemStack item) {
	String s = "";

	if (this.isSplash) {
		s = StatCollector.translateToLocal("potion.prefix.grenade").trim() + " ";
	}

	String s1 = "lifeLock.postfix";
	return s + StatCollector.translateToLocal(s1).trim();

}

@Override
@SideOnly(Side.CLIENT)
public void addInformation(ItemStack item, EntityPlayer player, List textLines, boolean boolParam) {
	HashMultimap hashmultimap = HashMultimap.create();
	Iterator iterator1;

	String s1 = StatCollector.translateToLocal("potion.lifeLock").trim();
	Potion potion = WeaponTweaks.potionLifeLock;
	Map map = potion.func_111186_k();

	if (map != null && map.size() > 0) {
		Iterator iterator = map.entrySet().iterator();

		while (iterator.hasNext()) {
			Entry entry = (Entry) iterator.next();
			AttributeModifier attributemodifier = (AttributeModifier) entry.getValue();
			AttributeModifier attributemodifier1 = new AttributeModifier(attributemodifier.getName(),
					potion.func_111183_a(this.level, attributemodifier), attributemodifier.getOperation());
			hashmultimap.put(((IAttribute) entry.getKey()).getAttributeUnlocalizedName(), attributemodifier1);
		}
	}

	s1 += " " + StatCollector.translateToLocal("potion.potency." + this.level).trim();

	s1 += " (" + StringUtils.ticksToElapsedTime(this.duration) + ")";

	if (potion.isBadEffect()) {
		textLines.add(EnumChatFormatting.RED + s1);
	} else {
		textLines.add(EnumChatFormatting.GRAY + s1);
	}

	if (!hashmultimap.isEmpty()) {
		textLines.add("");
		textLines.add(EnumChatFormatting.DARK_PURPLE + StatCollector.translateToLocal("potion.effects.whenDrank"));
		iterator1 = hashmultimap.entries().iterator();

		while (iterator1.hasNext()) {
			Entry entry1 = (Entry) iterator1.next();
			AttributeModifier attributemodifier2 = (AttributeModifier) entry1.getValue();
			double d0 = attributemodifier2.getAmount();
			double d1;

			if (attributemodifier2.getOperation() != 1 && attributemodifier2.getOperation() != 2) {
				d1 = attributemodifier2.getAmount();
			} else {
				d1 = attributemodifier2.getAmount() * 100.0D;
			}

			if (d0 > 0.0D) {
				textLines
						.add(EnumChatFormatting.BLUE + StatCollector.translateToLocalFormatted(
								"attribute.modifier.plus." + attributemodifier2
										.getOperation(),
						new Object[] { ItemStack.field_111284_a.format(d1),
								StatCollector.translateToLocal("attribute.name." + (String) entry1.getKey()) }));
			} else if (d0 < 0.0D) {
				d1 *= -1.0D;
				textLines
						.add(EnumChatFormatting.RED + StatCollector.translateToLocalFormatted(
								"attribute.modifier.take." + attributemodifier2
										.getOperation(),
						new Object[] { ItemStack.field_111284_a.format(d1),
								StatCollector.translateToLocal("attribute.name." + (String) entry1.getKey()) }));
			}
		}
	}
}

public boolean hasEffect(int damage) {
	return true;
}

@SideOnly(Side.CLIENT)
@Override
public void registerIcons(IIconRegister register) {
	this.icon = ItemPotion.func_94589_d("bottle_drinkable");
	this.iconSplash = ItemPotion.func_94589_d("bottle_splash");
	this.iconOverlay = ItemPotion.func_94589_d("overlay");
}

}

 

In the registerIcons method, I originally re-registered the icons, but after it wouldn't render, I thought maybe just grabbing a reference to the original potion icons would help (since there's that line in RenderSnowball that compares the icons directly instead of with .equals()), but it didn't fix the problem.

 

And here's the EntityPotionLifelock class itself:

 

package com.IceMetalPunk.weapontweaks.entities;

import java.util.Iterator;
import java.util.List;

import com.IceMetalPunk.weapontweaks.WeaponTweaks;
import com.IceMetalPunk.weapontweaks.items.ItemPotionLifelock;

import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.projectile.EntityThrowable;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;

public class EntityPotionLifelock extends EntityThrowable {

public ItemStack stack;
public int duration, level;

public EntityPotionLifelock(World world, int duration, int level) {
	super(world);
	this.duration = duration;
	this.level = level;
}

public EntityPotionLifelock(World world, EntityLivingBase player, ItemStack item) {
	super(world, player);
	this.stack = item;
	this.duration = ((ItemPotionLifelock) item.getItem()).duration;
	this.level = ((ItemPotionLifelock) item.getItem()).level;
}

@Override
protected float getGravityVelocity() {
	return 0.05F;
}

@Override
protected float func_70182_d() {
	return 0.5F;
}

@Override
protected float func_70183_g() {
	return -20.0F;
}

public int getPotionDamage() {
	return 0;
}

@Override
protected void onImpact(MovingObjectPosition raytrace) {
	if (!this.worldObj.isRemote) {

		AxisAlignedBB axisalignedbb = this.boundingBox.expand(4.0D, 2.0D, 4.0D);
		List list1 = this.worldObj.getEntitiesWithinAABB(EntityLivingBase.class, axisalignedbb);

		Iterator iterator = list1.iterator();

		while (iterator.hasNext()) {
			EntityLivingBase entitylivingbase = (EntityLivingBase) iterator.next();
			double d0 = this.getDistanceSqToEntity(entitylivingbase);

			if (d0 < 16.0D) {
				double d1 = 1.0D - Math.sqrt(d0) / 4.0D;

				if (entitylivingbase == raytrace.entityHit) {
					d1 = 1.0D;
				}

				int j = (int) (d1 * (double) this.duration + 0.5D);

				if (j > 20) {
					entitylivingbase
							.addPotionEffect(new PotionEffect(WeaponTweaks.potionLifeLock.id, j, this.level));
				}
			}
		}

		this.worldObj.playAuxSFX(2002, (int) Math.round(this.posX), (int) Math.round(this.posY),
				(int) Math.round(this.posZ), this.getPotionDamage());
		this.setDead();
	}
}

}

 

What am I doing wrong? As far as I understand it, the code should work, but it doesn't. I even tried copying the RenderSnowball code into a custom class and registering that instead, so I could add some debug output, and while the class was instantiated, its doRender() method was never called.

Whatever Minecraft needs, it is most likely not yet another tool tier.

Posted

Make sure your Entity class has a constructor that takes a single World argument:

public EntityPotionLifelock(World world) {
  super(world);
}

That is the constructor that gets called on the client side to construct the entity for rendering; if it is missing (which it is), then perhaps the client is failing to properly construct your entity and thus it is not able to render.

 

That's just a guess, though, so let us know if that fixes the problem for you ;)

Posted

Nope. I added that, and still no rendering occurs while the potion is in flight. Eclipse didn't find that particular constructor being called from anywhere, which is why I left it out. Regardless, adding it didn't fix the problem. Any other ideas?

Whatever Minecraft needs, it is most likely not yet another tool tier.

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.