Lightning Shenanigans

  • The FTB Forum is now read-only, and is here as an archive. To participate in our community discussions, please join our Discord! https://ftb.team/discord

Type1Ninja

New Member
Jul 29, 2019
1,393
-7
0
THIS WORKS NOW! WHOOT!

I'm working on my mod, and I'd like to add a "Lightning Creator" block. I have the spawning of lightning working, including redstone and right-click behavior, but apparently Minecraft's code is terrible and the redstone method doesn't actually have clients render the lightning. From the way this block is set up, I *think* that this is because the redstone method is never passed a player object, while the right-click method is passed a player object. The odd thing about that, though, is that the right-click method doesn't use the player object; it isn't used in any variable or anything. I'm not actively asking for help on this (yet), but it'd be nice to have some advice. Does anyone remember which mods add stuff that does lightning properly? Open source mods or mods where the author would respond quickly to questions about the lightning code?
For the curious, here's the code I'm using:
Code:
public class BlockLightningCreator extends BlockXF {
    public static int[] metas = {0, 1};
   
    public static double lightningYOffset = 5.0D;
   
    public BlockLightningCreator(String unlocalizedName) {
        super(unlocalizedName);
    }
   
    //Create Lightning
    //TODO - works, but lightning isn't rendered. -_-
    public void spawnLightning(World world, int x, int y, int z) {
        EntityLightningBolt lightning = new EntityLightningBolt(world, x, y + lightningYOffset, z);
        world.spawnEntityInWorld(lightning);
        //Make the Minecraft client spawn the lightning as well
        forceClientSpawnLightning(lightning);
    }
   
    //Create lightning if right-clicked
    @Override
    public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int p_149727_6_, float p_149727_7_, float p_149727_8_, float p_149727_9_) {
        spawnLightning(world, x, y, z);
        return true;
    }
   
    //Create lightning if powered by redstone
    public void onNeighborBlockChange(World world, int x, int y, int z, Block neighbor) {
        if (!world.isRemote) {
            if (world.isBlockIndirectlyGettingPowered(x, y, z)) {           
                //The way this check works: 
                if (world.getBlockMetadata(x, y, z) == metas[0]) {
                    spawnLightning(world, x, y, z);
                    world.setBlockMetadataWithNotify(x, y, z, metas[1], 3);
                }
            } else {
                //If it ISN'T powered, set whether it's been powered recently to false
                world.setBlockMetadataWithNotify(x, y, z, metas[0], 3);
            }
        }
    }
   
    //Get the minecraft client and make that spawn lightning as well
    @SideOnly(Side.CLIENT)
    public void forceClientSpawnLightning(EntityLightningBolt lightning) {
        Minecraft.getMinecraft().theWorld.spawnEntityInWorld(lightning);
    }
}

Here's github for the entire project: https://github.com/type1ninja/ExtraFeatures
(I haven't got a .gitignore, so it's a bit messy with all my eclipse settings. Can anyone tell me how a .gitignore works? My one programmer friend is terrible at explaining it)

EDIT: SOLVED! Not sure if it works server side yet; I'll test later.
 
Last edited:

Strikingwolf

New Member
Jul 29, 2019
3,709
-26
1
I'm working on my mod, and I'd like to add a "Lightning Creator" block. I have the spawning of lightning working, including redstone and right-click behavior, but apparently Minecraft's code is terrible and the redstone method doesn't actually have clients render the lightning. From the way this block is set up, I *think* that this is because the redstone method is never passed a player object, while the right-click method is passed a player object. The odd thing about that, though, is that the right-click method doesn't use the player object; it isn't used in any variable or anything. I'm not actively asking for help on this (yet), but it'd be nice to have some advice. Does anyone remember which mods add stuff that does lightning properly? Open source mods or mods where the author would respond quickly to questions about the lightning code?
For the curious, here's the code I'm using:
Code:
//Package declaration and imports

public class BlockLightningCreator extends BlockXF {
    public static double lightningYOffset = 5.0D;
  
    public boolean hadRedstoneSignal = false;
  
    public BlockLightningCreator(String unlocalizedName) {
        super(unlocalizedName);
    }
  
    //Create Lightning
    public void spawnLightning(World world, int x, int y, int z) {
        EntityLightningBolt lightning = new EntityLightningBolt(world, x, y + lightningYOffset, z);
        world.spawnEntityInWorld(lightning);
        //TODO- MAKE THE FORCE LIGHTNING RENDER CODE WORK
        //If uncommented, this code causes a crash. Apparently, I'm missing an OpenGL context.
        //forceRenderLightning(lightning, x, y, z);
    }
  
    //Create lightning if right-clicked
    @Override
    public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int p_149727_6_, float p_149727_7_, float p_149727_8_, float p_149727_9_) {
        spawnLightning(world, x, y, z);
        return true;
    }
  
    //Create lightning if powered by redstone
    //TODO - works, but lightning isn't rendered. -_-
    public void onNeighborBlockChange(World world, int x, int y, int z, Block neighbor) {
        if (!world.isRemote) {
            if (world.isBlockIndirectlyGettingPowered(x, y, z)) {          
                if (!hadRedstoneSignal) {
                    spawnLightning(world, x, y, z);
                    hadRedstoneSignal = true;
                }
            } else {
                //If it ISN'T powered, set whether it's been powered recently to false
                hadRedstoneSignal = false;
            }
        }
    }
  
    //This is needed to force the lightning to be rendered by all clients
    //It isn't currently working. If you uncomment it in the spawnLightning() method, it crashes
    @SideOnly(Side.CLIENT)
    public void forceRenderLightning(EntityLightningBolt lightning, int x, int y, int z) {
        RenderManager.instance.func_147939_a(lightning, x, y, z, 0f, 0f, false);
        LogHelper.info("Rendering Lightning");
    }
}

Here's github for the entire project: https://github.com/type1ninja/ExtraFeatures
(I haven't got a .gitignore, so it's a bit messy with all my eclipse settings. Can anyone tell me how a .gitignore works? My one programmer friend is terrible at explaining it)
That isn't quite right :p

Minecraft uses the same instance of the block class for all of the blocks so you can't just make it a variable, you have to store it in metadata

Also, use https://gitignore.io to get your .gitignore files ;)
 

Type1Ninja

New Member
Jul 29, 2019
1,393
-7
0
That isn't quite right :p

Minecraft uses the same instance of the block class for all of the blocks so you can't just make it a variable, you have to store it in metadata

Also, use https://gitignore.io to get your .gitignore files ;)
... Wut XD
Please explain!
I'll look into the gitignore later. :p
EDIT: I lied, I got the gitignore working. :p
 

Strikingwolf

New Member
Jul 29, 2019
3,709
-26
1
... Wut XD
Please explain!
So whenever you add a block to the game you do blah.blah.register(new BlockClass([args])). Well, that creates a new instance of the block class, mc uses this same instance for all the blocks that occur in the world. In your example when you charged one of your blocks with redstone all of them would fire. You probably can't see this to well because lightning isn't rendering. The solution is to use something called metadata, this is a number stored on the actual block in the world from 0-15 that you can use to store state. If you need more values you use a tile entity.
 
  • Like
Reactions: Type1Ninja

Type1Ninja

New Member
Jul 29, 2019
1,393
-7
0
So whenever you add a block to the game you do blah.blah.register(new BlockClass([args])). Well, that creates a new instance of the block class, mc uses this same instance for all the blocks that occur in the world. In your example when you charged one of your blocks with redstone all of them would fire. You probably can't see this to well because lightning isn't rendering. The solution is to use something called metadata, this is a number stored on the actual block in the world from 0-15 that you can use to store state. If you need more values you use a tile entity.
Hmm. I'll try that later. How do you change the metadata? :p
I can haz noob. ;)
 

Strikingwolf

New Member
Jul 29, 2019
3,709
-26
1
Hmm. I'll try that later. How do you change the metadata? :p
I can haz noob. ;)
world.setBlockMetadataWithNotify(x, y, z, newMeta, 3);
world.getBlockMetadata(x, y, z);

That should be all you need. You don't need to be able to get the powered version right? And it doesn't need a different name or anything?
 

Type1Ninja

New Member
Jul 29, 2019
1,393
-7
0
world.setBlockMetadataWithNotify(x, y, z, newMeta, 3);
world.getBlockMetadata(x, y, z);

That should be all you need. You don't need to be able to get the powered version right? And it doesn't need a different name or anything?
Actually, it doesn't seem to need the meta code. Because lightning only strikes when a neighbor is updated, and that event passes the coordinates of the block that happens to, and I'm using those coordinates, the meta code is unneeded (I think; lightning rendering is iffy at best :p). So, back to the issue: how does the lightning rendering work, and can anybody figure out how to force it to render (or something)?
 

Strikingwolf

New Member
Jul 29, 2019
3,709
-26
1
Actually, it doesn't seem to need the meta code. Because lightning only strikes when a neighbor is updated, and that event passes the coordinates of the block that happens to, and I'm using those coordinates, the meta code is unneeded (I think; lightning rendering is iffy at best:p ). So, back to the issue: how does the lightning rendering work, and can anybody figure out how to force it to render (or something)?
Still doesn't work. Let's say I activated Block A, it strikes lightning at Block A's position. I leave Block A activated. Now when I try to activate Block B to make it strike lightning it doesn't strike because hadRedstoneSignal is true
 
  • Like
Reactions: Type1Ninja

Type1Ninja

New Member
Jul 29, 2019
1,393
-7
0
Still doesn't work. Let's say I activated Block A, it strikes lightning at Block A's position. I leave Block A activated. Now when I try to activate Block B to make it strike lightning it doesn't strike because hadRedstoneSignal is true
Ah. I'll try to fix that, then...
EDIT: Updated code in the OP. Will that work? I haven't tested it yet.
 
Last edited:

Type1Ninja

New Member
Jul 29, 2019
1,393
-7
0
Do you think it might work if I made a copy of the EntityLightning class, then spawned one of those? I guess I'll look into entity stuff and try to figure that out.
EDIT: Maybe I'll try spawning the lightning a second time with the Client.
 
Last edited:

Type1Ninja

New Member
Jul 29, 2019
1,393
-7
0
IIIIIII DID IT
Final code:
Code:
//Imports 'n' package 'n' stuffs

public class BlockLightningCreator extends BlockXF {
    public static int[] metas = {0, 1};
  
    public static double lightningYOffset = 5.0D;
  
    public BlockLightningCreator(String unlocalizedName) {
        super(unlocalizedName);
    }
  
    //Create Lightning
    //TODO - works, but lightning isn't rendered. -_-
    public void spawnLightning(World world, int x, int y, int z) {
        EntityLightningBolt lightning = new EntityLightningBolt(world, x, y + lightningYOffset, z);
        world.spawnEntityInWorld(lightning);
        //Make the minecraft client spawn the lightning as well
        forceClientSpawnLightning(lightning);
    }
  
    //Create lightning if right-clicked
    @Override
    public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int p_149727_6_, float p_149727_7_, float p_149727_8_, float p_149727_9_) {
        spawnLightning(world, x, y, z);
        return true;
    }
  
    //Create lightning if powered by redstone
    public void onNeighborBlockChange(World world, int x, int y, int z, Block neighbor) {
        if (!world.isRemote) {
            if (world.isBlockIndirectlyGettingPowered(x, y, z)) {          
                //The way this check works:
                if (world.getBlockMetadata(x, y, z) == metas[0]) {
                    spawnLightning(world, x, y, z);
                    world.setBlockMetadataWithNotify(x, y, z, metas[1], 3);
                }
            } else {
                //If it ISN'T powered, set whether it's been powered recently to false
                world.setBlockMetadataWithNotify(x, y, z, metas[0], 3);
            }
        }
    }
    //Get the minecraft client and make that spawn lightning as well
    @SideOnly(Side.CLIENT)
    public void forceClientSpawnLightning(EntityLightningBolt lightning) {
        Minecraft.getMinecraft().theWorld.spawnEntityInWorld(lightning);
    }
}
I added a single method with a single line: forceClientSpawnLightning(), which contains: Minecraft.getMinecraft().theWorld.spawnEntityInWorld(lightning); called in the spawnLightning() method.
This effectively forces the Minecraft client to spawn lightning on it's own side as well. I added a @SideOnly(Side.CLIENT) annotation to that method in the hopes that it will work on a server as well. Haven't tested that yet. :p
 

Strikingwolf

New Member
Jul 29, 2019
3,709
-26
1
IIIIIII DID IT
Final code:
Code:
//Imports 'n' package 'n' stuffs

public class BlockLightningCreator extends BlockXF {
    public static int[] metas = {0, 1};
 
    public static double lightningYOffset = 5.0D;
 
    public BlockLightningCreator(String unlocalizedName) {
        super(unlocalizedName);
    }
 
    //Create Lightning
    //TODO - works, but lightning isn't rendered. -_-
    public void spawnLightning(World world, int x, int y, int z) {
        EntityLightningBolt lightning = new EntityLightningBolt(world, x, y + lightningYOffset, z);
        world.spawnEntityInWorld(lightning);
        //Make the minecraft client spawn the lightning as well
        forceClientSpawnLightning(lightning);
    }
 
    //Create lightning if right-clicked
    @Override
    public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int p_149727_6_, float p_149727_7_, float p_149727_8_, float p_149727_9_) {
        spawnLightning(world, x, y, z);
        return true;
    }
 
    //Create lightning if powered by redstone
    public void onNeighborBlockChange(World world, int x, int y, int z, Block neighbor) {
        if (!world.isRemote) {
            if (world.isBlockIndirectlyGettingPowered(x, y, z)) {         
                //The way this check works:
                if (world.getBlockMetadata(x, y, z) == metas[0]) {
                    spawnLightning(world, x, y, z);
                    world.setBlockMetadataWithNotify(x, y, z, metas[1], 3);
                }
            } else {
                //If it ISN'T powered, set whether it's been powered recently to false
                world.setBlockMetadataWithNotify(x, y, z, metas[0], 3);
            }
        }
    }
    //Get the minecraft client and make that spawn lightning as well
    @SideOnly(Side.CLIENT)
    public void forceClientSpawnLightning(EntityLightningBolt lightning) {
        Minecraft.getMinecraft().theWorld.spawnEntityInWorld(lightning);
    }
}
I added a single method with a single line: forceClientSpawnLightning(), which contains: Minecraft.getMinecraft().theWorld.spawnEntityInWorld(lightning); called in the spawnLightning() method.
This effectively forces the Minecraft client to spawn lightning on it's own side as well. I added a @SideOnly(Side.CLIENT) annotation to that method in the hopes that it will work on a server as well. Haven't tested that yet. :p
You could also do a world.isRemote() check in an if-statement to make sure you're on client
 
  • Like
Reactions: Type1Ninja

Type1Ninja

New Member
Jul 29, 2019
1,393
-7
0
You could also do a world.isRemote() check in an if-statement to make sure you're on client
I'll test it on a server later, and I'll use that if it doesn't work properly. :)
Thanks for posting here (even though you said a while ago that you wouldn't touch the lightning code :p)!