Lightning Shenanigans

Discussion in 'Mod Development' started by Type1Ninja, Jun 15, 2015.

  1. Type1Ninja

    Type1Ninja New Member

    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: Jun 17, 2015
  2. Strikingwolf

    Strikingwolf New Member

    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 ;)
     
  3. Type1Ninja

    Type1Ninja New Member

    ... Wut XD
    Please explain!
    I'll look into the gitignore later. :p
    EDIT: I lied, I got the gitignore working. :p
     
  4. Strikingwolf

    Strikingwolf New Member

    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.
     
    Type1Ninja likes this.
  5. Type1Ninja

    Type1Ninja New Member

    Hmm. I'll try that later. How do you change the metadata? :p
    I can haz noob. ;)
     
  6. Strikingwolf

    Strikingwolf New Member

    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?
     
  7. Type1Ninja

    Type1Ninja New Member

    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)?
     
  8. Strikingwolf

    Strikingwolf New Member

    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
     
    Type1Ninja likes this.
  9. Type1Ninja

    Type1Ninja New Member

    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: Jun 16, 2015
  10. Type1Ninja

    Type1Ninja New Member

    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: Jun 17, 2015
  11. Type1Ninja

    Type1Ninja New Member

    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
     
  12. Strikingwolf

    Strikingwolf New Member

    You could also do a world.isRemote() check in an if-statement to make sure you're on client
     
    Type1Ninja likes this.
  13. Type1Ninja

    Type1Ninja New Member

    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)!
     

Share This Page