In this particular tutorial, not a whole lot. I think I just removed the item ID parameter from the Item class constructor, but read the tutorial and compare your code to it if you are having trouble.
Where do you tell your entity what texture to use?
What line of code
That depends. If you are using RenderSnowball, then the texture used is the icon of the Item that you put in the constructor when you register your render; if you are using a custom render, then the texture is retrieved using ResourceLocation and usually getEntityTexture(Entity) method in the render class, but since it's custom, you can do it however you want.
That depends. If you are using RenderSnowball, then the texture used is the icon of the Item that you put in the constructor when you register your render; if you are using a custom render, then the texture is retrieved using ResourceLocation and usually getEntityTexture(Entity) method in the render class, but since it's custom, you can do it however you want.
Where do I put the name of the texture? @Override protected ResourceLocation getEntityTexture(Entity entity) { returnnull; }}
See that 'return null' in there? Null means 'nothing', and you want to change that to your texture. Generally, it looks something like this:
// you create a ResourceLocation for your texture here:
private static final ResourceLocation texture = new ResourceLocation("modid", "textures/entity/yourtexture.png");
// other code
@Override
protected ResourceLocation getEntityTexture(Entity entity) {
// and return your texture here:
return texture;
}
public renderplasmabolt(Item par1Item, int par2) { this.field_94151_a = par1Item; this.field_94150_f = par2; }
public renderplasmabolt(Item par1Item) { this(par1Item, 0); }
/** * Actually renders the given argument. This is a synthetic bridge method, always casting down its argument and then * handing it off to a worker function which does the actual work. In all probabilty, the class Render is generic * (Render<T extends Entity) and this method has signature public void doRender(T entity, double d, double d1, * double d2, float f, float f1). But JAD is pre 1.5 so doesn't do that. */ publicvoid doRender(Entity par1Entity, double par2, double par4, double par6, float par8, float par9) { IIcon icon = this.field_94151_a.getIconFromDamage(this.field_94150_f);
if (icon != null) { GL11.glPushMatrix(); GL11.glTranslatef((float)par2, (float)par4, (float)par6); GL11.glEnable(GL12.GL_RESCALE_NORMAL); GL11.glScalef(0.5F, 0.5F, 0.5F); // this.func_110777_b(par1Entity); // worked in Forge 804, but no longer; use this: this.bindEntityTexture(par1Entity); Tessellator tessellator = Tessellator.instance;
// You can remove this whole section if you want, it's just for Potions if (icon == ItemPotion.func_94589_d("bottle_splash")) { int i = PotionHelper.func_77915_a(((EntityPotion)par1Entity).getPotionDamage(), false); float f2 = (float)(i >> 16 & 255) / 255.0F; float f3 = (float)(i >> 8 & 255) / 255.0F; float f4 = (float)(i & 255) / 255.0F; GL11.glColor3f(f2, f3, f4); GL11.glPushMatrix(); this.func_77026_a(tessellator, ItemPotion.func_94589_d("overlay")); GL11.glPopMatrix(); GL11.glColor3f(1.0F, 1.0F, 1.0F); }
Now I the entity is a small white cube and not using my entities texture. I have tried a few things. I guess I'm missing something.
Any help is appreciated.
Did you register your custom render class for your entity? I'm pretty sure you can only get a white cube to render when you haven't assigned a render class, otherwise your entity would be either invisible (problem in the actual render code) or purple and black checker-board (problem with the texture path).
Also, make sure your "doRender" method signature is correct by putting @Override above it.
I'm trying to make an item that when right clicked, launches a projectile which is neither affected by gravity nor slowed by water. My problem is that is i shoot them and if they don't hit anything, they slow to a stop after a couple hundred blocks, then get stuck in midair without any means of destroying them. I stopped the gravity by overriding the getGravityVelocity method in snowball and returning 0 so it never drops, and the not slowed by water was just overriding the boolean isInWater and setting the return to false also. Is there any way to set a range or limit to how long they can be in flight?
I'm trying to make an item that when right clicked, launches a projectile which is neither affected by gravity nor slowed by water. My problem is that is i shoot them and if they don't hit anything, they slow to a stop after a couple hundred blocks, then get stuck in midair without any means of destroying them. I stopped the gravity by overriding the getGravityVelocity method in snowball and returning 0 so it never drops, and the not slowed by water was just overriding the boolean isInWater and setting the return to false also. Is there any way to set a range or limit to how long they can be in flight?
Any help is appreciated
-Deaths3n3my2
That's sort of a limitation of Minecraft - if there are no players around, the projectile will eventually go out of update range and just stop. If you chase it fast enough, you may be able to extend its range
On a more serious note, though, it's not really a good idea to have your projectile not affected by gravity at all unless you implement some other means of limiting its lifespan, such as "if (ticksExisted > 20) { setDead(); }" in the onUpdate method - I do this in several of my projectiles; otherwise, you will have a projectile just flying off forever, and they are not really meant to do that. I've had decent success with gravity values of as little as 0.02F or so.
How do you make the projectile create a fire on impact to a player or block?
Use the entity.setFire(time) method for the player, or when impacting a check if the block at blockY+1 is air / flammable and then set it to a fire block.
The Meaning of Life, the Universe, and Everything.
Join Date:
6/11/2014
Posts:
59
Member Details
I'm adapting your Throwing Rock code and I've run into a couple of interesting issues. I'm hoping you know more about them than me.
First, I've set it up such that when the projectile collides with a block, the block is set to air. It appears to work fine until I try to walk over the holes made in the ground. At which point, I get stuck, the screen jitters, and I'm unable to turn left or right. I can only get out by jumping or flying. I thought it might be an issue with the WorldObj, so tried this:
World world = FMLClientHandler.instance().getServer().worldServerForDimension(0);
It appears to fix the problem, but I'd like to understand why. Is this the proper solution?
Second, my projectile breaks blocks inconsistently. Sometimes it will just break one, but more often it will break the first block and then the block behind it and sometimes the block behind that one. How can I correct this?
Here is my overridden "onImpact()" method inside my "ThrowingRockEntity" class.
//===========================================================================
/**
* Called when hits block or entity.
*/
@Override
protected void onImpact(MovingObjectPosition mop) {
int x = mop.blockX;
int y = mop.blockY;
int z = mop.blockZ;
Block block = this.worldObj.getBlock(x, y, z);
int metadata = this.worldObj.getBlockMetadata(x, y, z);
World world = FMLClientHandler.instance().getServer().worldServerForDimension(0);
world.setBlockToAir(x, y, z);
if(!this.worldObj.isRemote) {
setDead();
}
}
The Meaning of Life, the Universe, and Everything.
Join Date:
6/11/2014
Posts:
59
Member Details
Well it seems I've solved both problems by simply placing the "setBlockToAir()" within the "if(!worldObj.isRemote)". The alternate world isn't necessary after all. Here is the functioning code:
However, if someone could give a detailed explanation of the different world objects, specifically server versus client, I think a lot of modders might find that useful.
But I ran into a small wrinkle. A boolean is returned by setBlockToAir() because it isn't always successful. Specifically, I've noticed that if I aim at a mob's feet, neither the mob will be hit, nor will the block be set to air. Unfortunately, the sound doesn't know that and so plays anyway.
I tried making the sound conditional upon the return from setBlockToAir(), but that return is only ever received by the server instance due to the "!world.isRemote" condition, and as stated above, the serve doesn't play sound. Thus my solution has been to post a custom event on the server upon a successful setBlocktoAir(). That in turn updates the client, allowing me to play sound from a custom event handler.
It works, but here's my question. Is this the appropriate approach or could this somehow be better handled by the proxy? I get what the proxy is for, I just haven't completely wrapped my head around when it should be used.
I apologize if I've gotten too far off the tutorial topic. If there is a better thread for this question, I'll happy repost it there. Thanks in advance.
However, if someone could give a detailed explanation of the different world objects, specifically server versus client, I think a lot of modders might find that useful.
Basically there are two threads, the client thread and the server thread; the server does almost all of the work maintaining the game world's state (including blocks, entities, etc.), while the client concerns itself mainly with rendering the world and letting the server know about client key input.
In terms of the World object specifically, usually the method you are in has one, and if not, you can always get one from an entity. If the method or section of code you are in happens to be called on both sides (which is usually the case), then you should use the world.isRemote check where applicable.
In your particular case, you found that sometimes the client thinks it's okay to remove a block, but the server doesn't agree, so when you ran setBlockToAir on both sides, you ended up with a ghost block - one that the client thinks is gone so it doesn't render, but the server knows is still there, so prevents you from moving through it. This is why it is critical to only run setBlock type statements on the server side, and luckily, the server will generally let the client know about changes in block state automatically.
For sounds, player.playSound is client side only, but there are methods in the World class that will broadcast them to all nearby players, from the server side: use world.playSoundAtEntity(player, ...) or world.playSoundEffect(x, y, z ...), and you can do so from within your if statement checking that the block was indeed set to air.
What would be the best way for the server to inform the client that "isAir" is true or false?
Depending on the geometry, mostly close to the mob's physical edge, sometimes the server returns false from setBlockToAir(), even if the mob in the way wasn't actually hit/damaged. I'm not sure why that would be, since onImpact() should only execute if the raytrace falls on either a block or a mob, and it should fall on one or the other. Is it a disagreement between client and server regarding mob placement/orientation/geometry?
Thanks again for your input. I find your tutorials useful.
What would be the best way for the server to inform the client that "isAir" is true or false?
Ideally, you wouldn't have to:
if (!world.isRemote && world.setBlockToAir(x, y, z)) {
// do whatever you want to do, but do it on the server:
world.playSoundEffect(x, y, z, 'random.pop', 1.0F, 1.0F); // server plays sound for all nearby
EDIT: or, since you are in an entity already:
world.playSoundAtEntity(this, 'random.pop', 1.0F, 1.0F);
}
That is what I would recommend, based on what you have explained of your situation, but if you REALLY want to tell the client that the block was set to air by the entity, the best way is to store that boolean value as a class field in your entity class, or rather, in your entity's DataWatcher field. What that does is whenever the value of 'hasSetBlock' changes on the server, DataWatcher sends a packet behind the scenes to update the client with the new value. But if all you want to do is play a sound, do it like in my example.
In this particular tutorial, not a whole lot. I think I just removed the item ID parameter from the Item class constructor, but read the tutorial and compare your code to it if you are having trouble.
What line of code
Edit: woops typed wrong
That depends. If you are using RenderSnowball, then the texture used is the icon of the Item that you put in the constructor when you register your render; if you are using a custom render, then the texture is retrieved using ResourceLocation and usually getEntityTexture(Entity) method in the render class, but since it's custom, you can do it however you want.
Thank you good sir!
@Override
protected ResourceLocation getEntityTexture(Entity entity) {
return null;
}}
See that 'return null' in there? Null means 'nothing', and you want to change that to your texture. Generally, it looks something like this:
package entities;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.entity.Entity;
import net.minecraft.entity.projectile.EntityPotion;
import net.minecraft.item.Item;
import net.minecraft.item.ItemPotion;
import net.minecraft.potion.PotionHelper;
import net.minecraft.util.IIcon;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import FutureWeapons.Reference;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class renderplasmabolt extends Render
{
private Item field_94151_a;
private int field_94150_f;
public renderplasmabolt(Item par1Item, int par2)
{
this.field_94151_a = par1Item;
this.field_94150_f = par2;
}
public renderplasmabolt(Item par1Item)
{
this(par1Item, 0);
}
/**
* Actually renders the given argument. This is a synthetic bridge method, always casting down its argument and then
* handing it off to a worker function which does the actual work. In all probabilty, the class Render is generic
* (Render<T extends Entity) and this method has signature public void doRender(T entity, double d, double d1,
* double d2, float f, float f1). But JAD is pre 1.5 so doesn't do that.
*/
public void doRender(Entity par1Entity, double par2, double par4, double par6, float par8, float par9)
{
IIcon icon = this.field_94151_a.getIconFromDamage(this.field_94150_f);
if (icon != null)
{
GL11.glPushMatrix();
GL11.glTranslatef((float)par2, (float)par4, (float)par6);
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glScalef(0.5F, 0.5F, 0.5F);
// this.func_110777_b(par1Entity); // worked in Forge 804, but no longer; use this:
this.bindEntityTexture(par1Entity);
Tessellator tessellator = Tessellator.instance;
// You can remove this whole section if you want, it's just for Potions
if (icon == ItemPotion.func_94589_d("bottle_splash"))
{
int i = PotionHelper.func_77915_a(((EntityPotion)par1Entity).getPotionDamage(), false);
float f2 = (float)(i >> 16 & 255) / 255.0F;
float f3 = (float)(i >> 8 & 255) / 255.0F;
float f4 = (float)(i & 255) / 255.0F;
GL11.glColor3f(f2, f3, f4);
GL11.glPushMatrix();
this.func_77026_a(tessellator, ItemPotion.func_94589_d("overlay"));
GL11.glPopMatrix();
GL11.glColor3f(1.0F, 1.0F, 1.0F);
}
this.func_77026_a(tessellator, icon);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
}
}
// For Forge 804:
/*
protected ResourceLocation func_110775_a(Entity par1Entity)
{
return TextureMap.field_110576_c;
}
*/
// For Forge 871:
private void func_77026_a(Tessellator par1Tessellator, IIcon iIcon)
{
float f = iIcon.getMinU();
float f1 = iIcon.getMaxU();
float f2 = iIcon.getMinV();
float f3 = iIcon.getMaxV();
float f4 = 1.0F;
float f5 = 0.5F;
float f6 = 0.25F;
GL11.glRotatef(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(-this.renderManager.playerViewX, 1.0F, 0.0F, 0.0F);
par1Tessellator.startDrawingQuads();
par1Tessellator.setNormal(0.0F, 1.0F, 0.0F);
par1Tessellator.addVertexWithUV((double)(0.0F - f5), (double)(0.0F - f6), 0.0D, (double)f, (double)f3);
par1Tessellator.addVertexWithUV((double)(f4 - f5), (double)(0.0F - f6), 0.0D, (double)f1, (double)f3);
par1Tessellator.addVertexWithUV((double)(f4 - f5), (double)(f4 - f6), 0.0D, (double)f1, (double)f2);
par1Tessellator.addVertexWithUV((double)(0.0F - f5), (double)(f4 - f6), 0.0D, (double)f, (double)f2);
par1Tessellator.draw();
}
private static final ResourceLocation texture = new ResourceLocation("futureweapons",
"textures/entities/plasma_bolt.png");
@Override
protected ResourceLocation getEntityTexture(Entity entity) {
return getCustomTexture((entityplasmabolt) entity);
}
private ResourceLocation getCustomTexture(Entity entity) {
// TODO Auto-generated method stub
return texture;
}}
Any help is appreciated.
Did you register your custom render class for your entity? I'm pretty sure you can only get a white cube to render when you haven't assigned a render class, otherwise your entity would be either invisible (problem in the actual render code) or purple and black checker-board (problem with the texture path).
Also, make sure your "doRender" method signature is correct by putting @Override above it.
package FutureWeapons;
import net.minecraft.client.renderer.entity.RenderSnowball;
import cpw.mods.fml.client.registry.RenderingRegistry;
import entities.entityplasmabolt;
import entities.renderplasmabolt;
public class ClientProxy extends CommonProxy {
public void registerRenderers() {
RenderingRegistry.registerEntityRenderingHandler(entityplasmabolt.class, new renderplasmabolt
(FutureWeaponsMain.Plasma_Rifle));
}
}
Any help is appreciated
-Deaths3n3my2
That's sort of a limitation of Minecraft - if there are no players around, the projectile will eventually go out of update range and just stop. If you chase it fast enough, you may be able to extend its range
On a more serious note, though, it's not really a good idea to have your projectile not affected by gravity at all unless you implement some other means of limiting its lifespan, such as "if (ticksExisted > 20) { setDead(); }" in the onUpdate method - I do this in several of my projectiles; otherwise, you will have a projectile just flying off forever, and they are not really meant to do that. I've had decent success with gravity values of as little as 0.02F or so.
Use the entity.setFire(time) method for the player, or when impacting a check if the block at blockY+1 is air / flammable and then set it to a fire block.
First, I've set it up such that when the projectile collides with a block, the block is set to air. It appears to work fine until I try to walk over the holes made in the ground. At which point, I get stuck, the screen jitters, and I'm unable to turn left or right. I can only get out by jumping or flying. I thought it might be an issue with the WorldObj, so tried this:
It appears to fix the problem, but I'd like to understand why. Is this the proper solution?
Second, my projectile breaks blocks inconsistently. Sometimes it will just break one, but more often it will break the first block and then the block behind it and sometimes the block behind that one. How can I correct this?
Here is my overridden "onImpact()" method inside my "ThrowingRockEntity" class.
See that up arrow?
*edit*
However, if someone could give a detailed explanation of the different world objects, specifically server versus client, I think a lot of modders might find that useful.
See that up arrow?
I want to play a sound when the block is set to air, but it seems sounds only play on the client. That's easy enough to do with this:
But I ran into a small wrinkle. A boolean is returned by setBlockToAir() because it isn't always successful. Specifically, I've noticed that if I aim at a mob's feet, neither the mob will be hit, nor will the block be set to air. Unfortunately, the sound doesn't know that and so plays anyway.
I tried making the sound conditional upon the return from setBlockToAir(), but that return is only ever received by the server instance due to the "!world.isRemote" condition, and as stated above, the serve doesn't play sound. Thus my solution has been to post a custom event on the server upon a successful setBlocktoAir(). That in turn updates the client, allowing me to play sound from a custom event handler.
It works, but here's my question. Is this the appropriate approach or could this somehow be better handled by the proxy? I get what the proxy is for, I just haven't completely wrapped my head around when it should be used.
I apologize if I've gotten too far off the tutorial topic. If there is a better thread for this question, I'll happy repost it there. Thanks in advance.
See that up arrow?
Basically there are two threads, the client thread and the server thread; the server does almost all of the work maintaining the game world's state (including blocks, entities, etc.), while the client concerns itself mainly with rendering the world and letting the server know about client key input.
In terms of the World object specifically, usually the method you are in has one, and if not, you can always get one from an entity. If the method or section of code you are in happens to be called on both sides (which is usually the case), then you should use the world.isRemote check where applicable.
In your particular case, you found that sometimes the client thinks it's okay to remove a block, but the server doesn't agree, so when you ran setBlockToAir on both sides, you ended up with a ghost block - one that the client thinks is gone so it doesn't render, but the server knows is still there, so prevents you from moving through it. This is why it is critical to only run setBlock type statements on the server side, and luckily, the server will generally let the client know about changes in block state automatically.
For sounds, player.playSound is client side only, but there are methods in the World class that will broadcast them to all nearby players, from the server side: use world.playSoundAtEntity(player, ...) or world.playSoundEffect(x, y, z ...), and you can do so from within your if statement checking that the block was indeed set to air.
So in the case of:
What would be the best way for the server to inform the client that "isAir" is true or false?
Depending on the geometry, mostly close to the mob's physical edge, sometimes the server returns false from setBlockToAir(), even if the mob in the way wasn't actually hit/damaged. I'm not sure why that would be, since onImpact() should only execute if the raytrace falls on either a block or a mob, and it should fall on one or the other. Is it a disagreement between client and server regarding mob placement/orientation/geometry?
Thanks again for your input. I find your tutorials useful.
See that up arrow?
Ideally, you wouldn't have to:
That is what I would recommend, based on what you have explained of your situation, but if you REALLY want to tell the client that the block was set to air by the entity, the best way is to store that boolean value as a class field in your entity class, or rather, in your entity's DataWatcher field. What that does is whenever the value of 'hasSetBlock' changes on the server, DataWatcher sends a packet behind the scenes to update the client with the new value. But if all you want to do is play a sound, do it like in my example.