diff --git a/src/main/java/com/hbm/explosion/vanillant/BlockAllocatorStandard.java b/src/main/java/com/hbm/explosion/vanillant/BlockAllocatorStandard.java new file mode 100644 index 000000000..21e430136 --- /dev/null +++ b/src/main/java/com/hbm/explosion/vanillant/BlockAllocatorStandard.java @@ -0,0 +1,76 @@ +package com.hbm.explosion.vanillant; + +import java.util.HashSet; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.util.MathHelper; +import net.minecraft.world.ChunkPosition; +import net.minecraft.world.World; + +public class BlockAllocatorStandard implements IBlockAllocator { + + protected int resolution; + + public BlockAllocatorStandard() { + this(16); + } + + public BlockAllocatorStandard(int resolution) { + this.resolution = resolution; + } + + @Override + public HashSet allocate(ExplosionVNT explosion, World world, double x, double y, double z, float size) { + + HashSet affectedBlocks = new HashSet(); + + for(int i = 0; i < this.resolution; ++i) { + for(int j = 0; j < this.resolution; ++j) { + for(int k = 0; k < this.resolution; ++k) { + + if(i == 0 || i == this.resolution - 1 || j == 0 || j == this.resolution - 1 || k == 0 || k == this.resolution - 1) { + + double d0 = (double) ((float) i / ((float) this.resolution - 1.0F) * 2.0F - 1.0F); + double d1 = (double) ((float) j / ((float) this.resolution - 1.0F) * 2.0F - 1.0F); + double d2 = (double) ((float) k / ((float) this.resolution - 1.0F) * 2.0F - 1.0F); + double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2); + + d0 /= d3; + d1 /= d3; + d2 /= d3; + + float powerRemaining = size * (0.7F + world.rand.nextFloat() * 0.6F); + double currentX = x; + double currentY = y; + double currentZ = z; + + for(float stepSize = 0.3F; powerRemaining > 0.0F; powerRemaining -= stepSize * 0.75F) { + + int blockX = MathHelper.floor_double(currentX); + int blockY = MathHelper.floor_double(currentY); + int blockZ = MathHelper.floor_double(currentZ); + + Block block = world.getBlock(blockX, blockY, blockZ); + + if(block.getMaterial() != Material.air) { + float blockResistance = block.getExplosionResistance(explosion.exploder, world, blockX, blockY, blockZ, x, y, z); + powerRemaining -= (blockResistance + 0.3F) * stepSize; + } + + if(powerRemaining > 0.0F) { + affectedBlocks.add(new ChunkPosition(blockX, blockY, blockZ)); + } + + currentX += d0 * (double) stepSize; + currentY += d1 * (double) stepSize; + currentZ += d2 * (double) stepSize; + } + } + } + } + } + + return affectedBlocks; + } +} diff --git a/src/main/java/com/hbm/explosion/vanillant/BlockProcessorStandard.java b/src/main/java/com/hbm/explosion/vanillant/BlockProcessorStandard.java new file mode 100644 index 000000000..45debcd59 --- /dev/null +++ b/src/main/java/com/hbm/explosion/vanillant/BlockProcessorStandard.java @@ -0,0 +1,58 @@ +package com.hbm.explosion.vanillant; + +import java.util.HashSet; +import java.util.Iterator; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.util.MathHelper; +import net.minecraft.world.ChunkPosition; +import net.minecraft.world.World; + +public class BlockProcessorStandard implements IBlockProcessor { + + protected IDropChanceMutator chance; + + public BlockProcessorStandard() { } + + public BlockProcessorStandard(IDropChanceMutator chance) { + this.chance = chance; + } + + @Override + public void process(ExplosionVNT explosion, World world, double x, double y, double z, HashSet affectedBlocks) { + + Iterator iterator = affectedBlocks.iterator(); + float dropChance = 1.0F / explosion.size; + + while(iterator.hasNext()) { + ChunkPosition chunkposition = (ChunkPosition) iterator.next(); + int blockX = chunkposition.chunkPosX; + int blockY = chunkposition.chunkPosY; + int blockZ = chunkposition.chunkPosZ; + Block block = world.getBlock(blockX, blockY, blockZ); + + if(block.getMaterial() != Material.air) { + if(block.canDropFromExplosion(null)) { + + if(chance != null) { + dropChance = chance.mutateDropChance(explosion, block, blockX, blockY, blockZ, dropChance); + } + + block.dropBlockAsItemWithChance(world, blockX, blockY, blockZ, world.getBlockMetadata(blockX, blockY, blockZ), dropChance, 0); + } + + block.onBlockExploded(world, blockX, blockY, blockZ, null); + } + } + } + + public BlockProcessorStandard setNoDrop() { + this.chance = new DropChanceNever(); + return this; + } + public BlockProcessorStandard setAllDrop() { + this.chance = new DropChanceAlways(); + return this; + } +} diff --git a/src/main/java/com/hbm/explosion/vanillant/DropChanceAlways.java b/src/main/java/com/hbm/explosion/vanillant/DropChanceAlways.java new file mode 100644 index 000000000..017e4b7fd --- /dev/null +++ b/src/main/java/com/hbm/explosion/vanillant/DropChanceAlways.java @@ -0,0 +1,16 @@ +package com.hbm.explosion.vanillant; + +import net.minecraft.block.Block; + +/** + * Now it's getting ridiculously over-engineered + * @author hbm + * + */ +public class DropChanceAlways implements IDropChanceMutator { + + @Override + public float mutateDropChance(ExplosionVNT explosion, Block block, int x, int y, int z, float chance) { + return 1F; + } +} diff --git a/src/main/java/com/hbm/explosion/vanillant/DropChanceNever.java b/src/main/java/com/hbm/explosion/vanillant/DropChanceNever.java new file mode 100644 index 000000000..12842fd7e --- /dev/null +++ b/src/main/java/com/hbm/explosion/vanillant/DropChanceNever.java @@ -0,0 +1,11 @@ +package com.hbm.explosion.vanillant; + +import net.minecraft.block.Block; + +public class DropChanceNever implements IDropChanceMutator { + + @Override + public float mutateDropChance(ExplosionVNT explosion, Block block, int x, int y, int z, float chance) { + return 0; + } +} diff --git a/src/main/java/com/hbm/explosion/vanillant/ExplosionVNT.java b/src/main/java/com/hbm/explosion/vanillant/ExplosionVNT.java index 443587c0f..324b3bc03 100644 --- a/src/main/java/com/hbm/explosion/vanillant/ExplosionVNT.java +++ b/src/main/java/com/hbm/explosion/vanillant/ExplosionVNT.java @@ -1,5 +1,87 @@ package com.hbm.explosion.vanillant; +import java.util.HashMap; +import java.util.HashSet; + +import net.minecraft.entity.Entity; +import net.minecraft.util.Vec3; +import net.minecraft.world.ChunkPosition; +import net.minecraft.world.World; + +/** + * Time to over-engineer this into fucking oblivion so that I never have to write a vanilla-esque explosion class ever again + * @author hbm + * + */ public class ExplosionVNT { + //explosions only need one of these, in the unlikely event that we do need to combine different types we can just write a wrapper that acts as a chainloader + private IBlockAllocator blockAllocator; + private IEntityAllocator entityAllocator; + private IBlockProcessor blockProcessor; + private IEntityProcessor entityProcessor; + //since we want to reduce each effect to the bare minimum (sound, particles, etc. being separate) we definitely need multiple most of the time + private IExplosionSFX[] sfx; + + protected World world; + protected double posX; + protected double posY; + protected double posZ; + protected float size; + public Entity exploder; + + public ExplosionVNT(World world, double x, double y, double z, float size) { + this(world, x, y, z, size, null); + } + + public ExplosionVNT(World world, double x, double y, double z, float size, Entity exploder) { + this.world = world; + this.posX = x; + this.posY = y; + this.posZ = z; + this.size = size; + this.exploder = exploder; + } + + public void explode() { + + boolean processBlocks = blockAllocator != null && blockProcessor != null; + boolean processEntities = entityAllocator != null && entityProcessor != null; + + HashSet affectedBlocks = null; + HashMap affectedEntities = null; + + if(processBlocks) affectedBlocks = blockAllocator.allocate(this, world, posX, posY, posZ, size); + if(processEntities) affectedEntities = entityAllocator.allocate(this, world, posX, posY, posZ, size); + + if(processBlocks) blockProcessor.process(this, world, posX, posY, posZ, affectedBlocks); + if(processEntities) entityProcessor.process(this, world, posX, posY, posZ, affectedEntities); + + if(sfx != null) { + for(IExplosionSFX fx : sfx) { + fx.doEffect(this, world, posX, posY, posZ, size); + } + } + } + + public ExplosionVNT setBlockAllocator(IBlockAllocator blockAllocator) { + this.blockAllocator = blockAllocator; + return this; + } + public ExplosionVNT setEntityAllocator(IEntityAllocator entityAllocator) { + this.entityAllocator = entityAllocator; + return this; + } + public ExplosionVNT setBlockProcessor(IBlockProcessor blockProcessor) { + this.blockProcessor = blockProcessor; + return this; + } + public ExplosionVNT setEntityprocessor(IEntityProcessor entityProcessor) { + this.entityProcessor = entityProcessor; + return this; + } + public ExplosionVNT setSFX(IExplosionSFX... sfx) { + this.sfx = sfx; + return this; + } } diff --git a/src/main/java/com/hbm/explosion/vanillant/IBlockAllocator.java b/src/main/java/com/hbm/explosion/vanillant/IBlockAllocator.java index f3cb51590..2407a3960 100644 --- a/src/main/java/com/hbm/explosion/vanillant/IBlockAllocator.java +++ b/src/main/java/com/hbm/explosion/vanillant/IBlockAllocator.java @@ -1,5 +1,11 @@ package com.hbm.explosion.vanillant; +import java.util.HashSet; + +import net.minecraft.world.ChunkPosition; +import net.minecraft.world.World; + public interface IBlockAllocator { + public HashSet allocate(ExplosionVNT explosion, World world, double x, double y, double z, float size); } diff --git a/src/main/java/com/hbm/explosion/vanillant/IBlockProcessor.java b/src/main/java/com/hbm/explosion/vanillant/IBlockProcessor.java new file mode 100644 index 000000000..0b0d93cbd --- /dev/null +++ b/src/main/java/com/hbm/explosion/vanillant/IBlockProcessor.java @@ -0,0 +1,11 @@ +package com.hbm.explosion.vanillant; + +import java.util.HashSet; + +import net.minecraft.world.ChunkPosition; +import net.minecraft.world.World; + +public interface IBlockProcessor { + + public void process(ExplosionVNT explosion, World world, double x, double y, double z, HashSet affectedBlocks); +} diff --git a/src/main/java/com/hbm/explosion/vanillant/IDropChanceMutator.java b/src/main/java/com/hbm/explosion/vanillant/IDropChanceMutator.java new file mode 100644 index 000000000..107358af8 --- /dev/null +++ b/src/main/java/com/hbm/explosion/vanillant/IDropChanceMutator.java @@ -0,0 +1,8 @@ +package com.hbm.explosion.vanillant; + +import net.minecraft.block.Block; + +public interface IDropChanceMutator { + + public float mutateDropChance(ExplosionVNT explosion, Block block, int x, int y, int z, float chance); +} diff --git a/src/main/java/com/hbm/explosion/vanillant/IEntityAllocator.java b/src/main/java/com/hbm/explosion/vanillant/IEntityAllocator.java new file mode 100644 index 000000000..997afa96f --- /dev/null +++ b/src/main/java/com/hbm/explosion/vanillant/IEntityAllocator.java @@ -0,0 +1,12 @@ +package com.hbm.explosion.vanillant; + +import java.util.HashMap; + +import net.minecraft.entity.Entity; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; + +public interface IEntityAllocator { + + public HashMap allocate(ExplosionVNT explosion, World world, double x, double y, double z, float size); +} diff --git a/src/main/java/com/hbm/explosion/vanillant/IEntityProcessor.java b/src/main/java/com/hbm/explosion/vanillant/IEntityProcessor.java new file mode 100644 index 000000000..c9416aed3 --- /dev/null +++ b/src/main/java/com/hbm/explosion/vanillant/IEntityProcessor.java @@ -0,0 +1,14 @@ +package com.hbm.explosion.vanillant; + +import java.util.HashMap; +import java.util.HashSet; + +import net.minecraft.entity.Entity; +import net.minecraft.util.Vec3; +import net.minecraft.world.ChunkPosition; +import net.minecraft.world.World; + +public interface IEntityProcessor { + + public void process(ExplosionVNT explosion, World world, double x, double y, double z, HashMap affectedBlocks); +} diff --git a/src/main/java/com/hbm/explosion/vanillant/IExplosionSFX.java b/src/main/java/com/hbm/explosion/vanillant/IExplosionSFX.java new file mode 100644 index 000000000..2b4846e2e --- /dev/null +++ b/src/main/java/com/hbm/explosion/vanillant/IExplosionSFX.java @@ -0,0 +1,11 @@ +package com.hbm.explosion.vanillant; + +import java.util.HashSet; + +import net.minecraft.world.ChunkPosition; +import net.minecraft.world.World; + +public interface IExplosionSFX { + + public void doEffect(ExplosionVNT explosion, World world, double x, double y, double z, float size); +}