the great over-engineered vanilla-like explosion code

This commit is contained in:
Boblet 2022-02-10 16:57:49 +01:00
parent 949ca4010e
commit 53264514f4
11 changed files with 305 additions and 0 deletions

View File

@ -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<ChunkPosition> allocate(ExplosionVNT explosion, World world, double x, double y, double z, float size) {
HashSet<ChunkPosition> 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;
}
}

View File

@ -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<ChunkPosition> 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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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<ChunkPosition> affectedBlocks = null;
HashMap<Entity, Vec3> 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;
}
}

View File

@ -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<ChunkPosition> allocate(ExplosionVNT explosion, World world, double x, double y, double z, float size);
}

View File

@ -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<ChunkPosition> affectedBlocks);
}

View File

@ -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);
}

View File

@ -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<Entity, Vec3> allocate(ExplosionVNT explosion, World world, double x, double y, double z, float size);
}

View File

@ -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<Entity, Vec3> affectedBlocks);
}

View File

@ -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);
}