Reputation: 43
In my Minecraft Forge mod for 1.7.10. I am aware that this version is arguably old news, but it is my favorite version and all of my modding experience is with this version.
I am creating a custom TNT block. The issue is the primed version is not rendering. When ignited, the TNT disappears, and then shortly later there is an explosion. If the TNT was placed in the air, the explosion is below like it should be due to the primed TNT falling. The issue is that it is not rendering. When I use fn+f3+b to show hitboxes, no hitbox is shown.
The issue is the entity being spawned on the server does not replicate to the client. I know this because:
Switching out the entity renderer with the default RenderTNTPrimed
still fails to render at all instead of rendering the default TNT hence my custom renderer class cannot be the issue.
Switching out my custom entity class with the copy paste vanilla EntityTNTPrimed
code also does not solve the problem. If the problem was with my custom entity class then using bona fide vanilla code would fix the problem but it doesnt.
The entity and its renderer are being registered using RenderingRegistry.registerEntityRenderingHandler()
from the client proxy and EntityRegistry.registerGlobalEntityID()
then EntityRegistry.registerModEntity()
in init()
(I had tested the client proxy with System.out.println()
and the client proxy works).
Though the largest evidence of the problem being the TNT spawing on the server but not the client is the fact that removing if(world.isRemote) return;
from the handlers in my BlockTNT
class causes the TNT to render. However I am not supposed to handle igniting the TNT on the client so I am not supposed to have to remove if(world.isRemote) return;
. Besides doing this is a pseudo fix, because the entity is still invisible when /summon
ed.
The constructor for TNTPrimedCharged
is only being called from the server, and onUpdate()
for TNTPrimed
and thus TNTPrimedCharged
is also only being called by the server, as demostrated by adding print statements and the logs only show them printed from the SERVER thread.
The BlockTNT
class (much of this is derived from vanilla code, but has been designed to take the corresponding custom primed TNT entity class while instantiating, the problem is not here because instantiating a default EntityTNTPrimed
instead of the provided primed
class does render correctly, but I have included this because this code helped demonstrate the origin of the problem):
class BlockTNT extends net.minecraft.block.BlockTNT {
private final Class primed;
public BlockTNT(final Class primed) {
this.primed = primed;
stepSound = net.minecraft.block.Block.soundTypeGrass;
}
protected EntityTNTPrimed getPrimed(final World world, final int x, final int y, final int z, final EntityLivingBase igniter) {
try {
return (EntityTNTPrimed)primed.getDeclaredConstructor(World.class, double.class, double.class, double.class, EntityLivingBase.class).newInstance(world, (double)((float)x+0.5F), (double)((float)y+0.5F), (double)((float)z+0.5F), igniter);
} catch (Exception exception) {
return null;
}
}
@Override public void onBlockDestroyedByExplosion(final World world, final int x, final int y, final int z, final Explosion explosion) {
if(world.isRemote)
return;
final EntityTNTPrimed tnt = getPrimed(world, x, y, z, explosion.getExplosivePlacedBy());
tnt.fuse = world.rand.nextInt(tnt.fuse>>2)+(tnt.fuse>>3);
world.spawnEntityInWorld(tnt);
}
@Override public void func_150114_a(final World world, final int x, final int y, final int z, final int meta, final EntityLivingBase igniter) {
if(world.isRemote || (meta&1) == 0)
return;
final EntityTNTPrimed tnt = getPrimed(world, x, y, z, igniter);
world.spawnEntityInWorld(tnt);
world.playSoundAtEntity(tnt, "game.tnt.primed", 1.0F, 1.0F);
}
}
Inside the main mod class I register the entities:
@Instance public static ExampleMod instance;
@SidedProxy(clientSide="com.examplemod.ClientProxy", serverSide="com.examplemod.CommonProxy") public static com.examplemod.CommonProxy proxy;
private static void registerTnt(final Class primed, String name, final int id) {
proxy.registerTntRenderer(primed, registerBlock(new BlockTNT(primed), name.toLowerCase()+"_tnt"));
EntityRegistry.registerGlobalEntityID(primed, name = "PrimedTnt"+name, EntityRegistry.findGlobalUniqueEntityId());
EntityRegistry.registerModEntity(primed, name, id, instance, 160, 10, true);
}
@EventHandler public void init(FMLInitializationEvent event) {
registerTnt(com.examplemod.TNTPrimedCharged.class, "Charged", 0);
// ...
}
And we register the renderer in the client proxy (again tested and works):
@Override public void registerTntRenderer(final Class primed, final Block block) {
RenderingRegistry.registerEntityRenderingHandler(primed, new com.examplemod.RenderTNTPrimed(block));
}
Here is the class for the custom entities:
public abstract class TNTPrimed extends net.minecraft.entity.item.EntityTNTPrimed {
public TNTPrimed(final World world, final double x, final double y, final double z, final EntityLivingBase igniter) {
super(world, x, y, z, igniter);
}
public TNTPrimed(final World world) {
super(world);
}
@Override public void onUpdate() {
prevPosX = posX;
prevPosY = posY;
prevPosZ = posZ;
moveEntity(motionX, motionY -= 0.04D, motionZ);
motionX *= 0.98D;
motionY *= 0.98D;
motionZ *= 0.98D;
if(onGround) {
motionX *= 0.7D;
motionZ *= 0.7D;
motionY *= -0.5D;
}
if(fuse-- <= 0) {
setDead();
if(!worldObj.isRemote)
explode();
} else
worldObj.spawnParticle("smoke", posX, posY+0.5D, posZ, 0.0D, 0.0D, 0.0D);
}
protected abstract void explode();
}
public class TNTPrimedCharged extends com.examplemod.TNTPrimed {
public TNTPrimedCharged(final World world, final double x, final double y, final double z, final EntityLivingBase igniter) {
super(world, x, y, z, igniter);
}
public TNTPrimedCharged(final World world) {
super(world);
}
@Override protected void explode() {
worldObj.newExplosion(this, posX, posY, posZ, 8, false, true);
}
}
Though I can state categorically that the custom entity renderer class is not the culprit, I am providing it for reference:
class RenderTNTPrimed extends net.minecraft.client.renderer.entity.RenderTNTPrimed {
private final RenderBlocks renderer = new RenderBlocks();
private final Block block;
public RenderTNTPrimed(final Block block) {
super();
this.block = block;
}
@Override public void doRender(final EntityTNTPrimed entity, final double x, final double y, final double z, final float yaw, final float tick) {
GL11.glPushMatrix();
GL11.glTranslatef((float)x, (float)y, (float)z);
float var0 = entity.fuse-tick+1.0F;
if (var0 < 10.0F) {
final float scale = (float)Math.pow(Math.max(Math.min(1-var0/10, 1.0F), 0.0F), 4.0F)*0.3F+1.0F;
GL11.glScalef(scale, scale, scale);
}
bindEntityTexture(entity);
renderer.renderBlockAsItem(block, 0, entity.getBrightness(tick));
if (((entity.fuse/5)&1) == 0) {
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_DST_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, (1.0F-var0/100.0F)*0.8F);
renderer.renderBlockAsItem(block, 0, 1.0F);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glDisable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_TEXTURE_2D);
}
GL11.glPopMatrix();
}
}
So when the server calls world.spawnEntityInWorld()
on my custom entity why does it fail to spawn it on the client as well? How can I fix this because the TNT just disappearing when being ignited is undesirable and I have no idea what else to try. How can I make the custom primed TNT show up on the client?
Upon reverse engineering other similar mods (specifically the Too Much TNT mod), their TNT primed entities successfully render when /summon
is used, and they do check for clientside in their TNT block classes. After investigation, I cannot tell what they are doing differently that would cause their entities to render but not mine.
I have spent several unfruitful hours researching this problem, and given that as of this edit this question is second hit for Googling basic search terms like 'Minecraft Forge 1.7.10 Entity Not Rendering' and third for 'Minecraft Forge 1.7.10 Entity Invisible,' it is very likely that further research will be in vain.
The problem is simply that when my mod added entity is spawned on the server thread, it is not also spawned on the client thread, even though it should be. How do I fix this? I tried everything.
Upvotes: 2
Views: 997
Reputation: 43
It turns out the problem was actually not the entity not spawning on the client. The issue was that the fuse
property was being set to 0 on the client even though it is set to 80 on the server. And thus the client side TNT is instantly setDead()
ing itself. Implementing cpw.mods.fml.common.registry.IEntityAdditionalSpawnData
and then setting the fuse property to the correct value in readSpawnData
seems to have solved the problem.
Upvotes: 2