Fixed Rifts Spreading through Walls

Fixed the issue of rifts spreading through walls. We tried using
raytracing but rifts would always "leak" out of unbreakable enclosures.
With this latest change, rifts spread with the same logic that
determines which blocks are reachable to them.
This commit is contained in:
SenseiKiwi 2014-03-12 05:08:49 -04:00
parent 836eb8a7e0
commit 73cb5ccb6c
3 changed files with 73 additions and 63 deletions

View file

@ -7,7 +7,6 @@ import java.util.Queue;
import java.util.Random; import java.util.Random;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.BlockFlowing; import net.minecraft.block.BlockFlowing;
import net.minecraft.block.BlockFluid; import net.minecraft.block.BlockFluid;
import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.ITileEntityProvider;
@ -27,6 +26,7 @@ import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDimClient.ClosingRiftFX; import StevenDimDoors.mod_pocketDimClient.ClosingRiftFX;
import StevenDimDoors.mod_pocketDimClient.GoggleRiftFX; import StevenDimDoors.mod_pocketDimClient.GoggleRiftFX;
import StevenDimDoors.mod_pocketDimClient.RiftFX; import StevenDimDoors.mod_pocketDimClient.RiftFX;
@ -38,7 +38,7 @@ public class BlockRift extends Block implements ITileEntityProvider
{ {
private static final float MIN_IMMUNE_RESISTANCE = 5000.0F; private static final float MIN_IMMUNE_RESISTANCE = 5000.0F;
private static final int BLOCK_DESTRUCTION_RANGE = 4; private static final int BLOCK_DESTRUCTION_RANGE = 4;
private static final int BLOCK_DESTRUCTION_VOLUME = (int) Math.pow(2 * BLOCK_DESTRUCTION_RANGE + 1, 3); private static final int RIFT_SPREAD_RANGE = 5;
private static final int MAX_BLOCK_SEARCH_CHANCE = 100; private static final int MAX_BLOCK_SEARCH_CHANCE = 100;
private static final int BLOCK_SEARCH_CHANCE = 50; private static final int BLOCK_SEARCH_CHANCE = 50;
private static final int MAX_BLOCK_DESTRUCTION_CHANCE = 100; private static final int MAX_BLOCK_DESTRUCTION_CHANCE = 100;
@ -164,11 +164,30 @@ public class BlockRift extends Block implements ITileEntityProvider
private void destroyNearbyBlocks(World world, int x, int y, int z, Random random) private void destroyNearbyBlocks(World world, int x, int y, int z, Random random)
{ {
HashMap<Point3D, Integer> pointDistances = new HashMap<Point3D, Integer>(BLOCK_DESTRUCTION_VOLUME); // Find reachable blocks that are vulnerable to rift damage (ignoring air, of course)
Queue<Point3D> points = new LinkedList<Point3D>(); ArrayList<Point3D> targets = findReachableBlocks(world, x, y, z, BLOCK_DESTRUCTION_RANGE, false);
//Perform a breadth-first search outwards from the point at which the rift is located. Record the distances // For each block, randomly decide whether to destroy it.
//of the points we visit to stop the search at its maximum range. // The randomness makes it so the destroyed area appears "noisy" if the rift is exposed to a large surface.
for (Point3D target : targets)
{
if (random.nextInt(MAX_BLOCK_DESTRUCTION_CHANCE) < BLOCK_DESTRUCTION_CHANCE)
{
spawnWorldThread(world.getBlockId(target.getX(), target.getY(), target.getZ()), world, x, y, z, random);
world.destroyBlock(target.getX(), target.getY(), target.getZ(), false);
}
}
}
private ArrayList<Point3D> findReachableBlocks(World world, int x, int y, int z, int range, boolean includeAir)
{
int searchVolume = (int) Math.pow(2 * range + 1, 3);
HashMap<Point3D, Integer> pointDistances = new HashMap<Point3D, Integer>(searchVolume);
Queue<Point3D> points = new LinkedList<Point3D>();
ArrayList<Point3D> targets = new ArrayList<Point3D>();
// Perform a breadth-first search outwards from the point at which the rift is located.
// Record the distances of the points we visit to stop the search at its maximum range.
pointDistances.put(new Point3D(x, y, z), 0); pointDistances.put(new Point3D(x, y, z), 0);
addAdjacentBlocks(x, y, z, 0, pointDistances, points); addAdjacentBlocks(x, y, z, 0, pointDistances, points);
while (!points.isEmpty()) while (!points.isEmpty())
@ -176,9 +195,13 @@ public class BlockRift extends Block implements ITileEntityProvider
Point3D current = points.remove(); Point3D current = points.remove();
int distance = pointDistances.get(current); int distance = pointDistances.get(current);
//If the current block is air, continue searching. Otherwise, try destroying the block. // If the current block is air, continue searching. Otherwise, add the block to our list.
if (world.isAirBlock(current.getX(), current.getY(), current.getZ())) if (world.isAirBlock(current.getX(), current.getY(), current.getZ()))
{ {
if (includeAir)
{
targets.add(current);
}
// Make sure we stay within the search range // Make sure we stay within the search range
if (distance < BLOCK_DESTRUCTION_RANGE) if (distance < BLOCK_DESTRUCTION_RANGE)
{ {
@ -187,16 +210,14 @@ public class BlockRift extends Block implements ITileEntityProvider
} }
else else
{ {
//Check if the current block is immune to destruction by rifts. If not, randomly decide whether to destroy it. // Check if the current block is immune to destruction by rifts. If not, add it to our list.
//The randomness makes it so the destroyed area appears "noisy" if the rift is exposed to a large surface. if (!isBlockImmune(world, current.getX(), current.getY(), current.getZ()))
if (!isBlockImmune(world, current.getX(), current.getY(), current.getZ()) &&
random.nextInt(MAX_BLOCK_DESTRUCTION_CHANCE) < BLOCK_DESTRUCTION_CHANCE)
{ {
this.spawnWorldThread(world.getBlockId(current.getX(), current.getY(), current.getZ()), world, x, y, z, random); targets.add(current);
world.destroyBlock(current.getX(), current.getY(), current.getZ(), false);
} }
} }
} }
return targets;
} }
private void spawnWorldThread(int blockID, World world, int x, int y, int z, Random random) private void spawnWorldThread(int blockID, World world, int x, int y, int z, Random random)
@ -236,11 +257,40 @@ public class BlockRift extends Block implements ITileEntityProvider
if (!this.isBlockImmune(world, x, y, z) && world.getChunkProvider().chunkExists(x >> 4, z >> 4)) if (!this.isBlockImmune(world, x, y, z) && world.getChunkProvider().chunkExists(x >> 4, z >> 4))
{ {
int blockID = world.getBlockId(x, y, z); int blockID = world.getBlockId(x, y, z);
world.setBlock(x, y, z, properties.RiftBlockID); if (world.setBlock(x, y, z, properties.RiftBlockID))
this.spawnWorldThread(blockID, world, x, y, z, random); spawnWorldThread(blockID, world, x, y, z, random);
} }
} }
public boolean spreadRift(NewDimData dimension, DimLink parent, World world, Random random)
{
int x, y, z, blockID;
Point4D source = parent.source();
// Find reachable blocks that are vulnerable to rift damage and include air
ArrayList<Point3D> targets = findReachableBlocks(world, source.getX(), source.getY(), source.getZ(),
RIFT_SPREAD_RANGE, true);
if (!targets.isEmpty())
{
// Choose randomly from among the possible locations where we can spawn a new rift
Point3D target = targets.get( random.nextInt(targets.size()) );
x = target.getX();
y = target.getY();
z = target.getZ();
// Create a child, replace the block with a rift, and consider dropping World Thread
blockID = world.getBlockId(x, y, z);
if (world.setBlock(x, y, z, properties.RiftBlockID))
{
dimension.createChildLink(x, y, z, parent);
spawnWorldThread(blockID, world, x, y, z, random);
return true;
}
}
return false;
}
/** /**
* Lets pistons push through rifts, destroying them * Lets pistons push through rifts, destroying them
*/ */

View file

@ -15,7 +15,6 @@ import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack;
import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher; import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
@SuppressWarnings("deprecation")
public abstract class NewDimData public abstract class NewDimData
{ {
private static class InnerDimLink extends DimLink private static class InnerDimLink extends DimLink

View file

@ -35,8 +35,6 @@ import StevenDimDoors.mod_pocketDim.util.Point4D;
public class TileEntityRift extends TileEntity public class TileEntityRift extends TileEntity
{ {
private static final int MAX_SPREAD_ATTEMPTS = 3;
private static final int MAX_SEARCH_ATTEMPTS = 50;
private static final int MAX_ANCESTOR_LINKS = 3; private static final int MAX_ANCESTOR_LINKS = 3;
private static final int ENDERMAN_SPAWNING_CHANCE = 1; private static final int ENDERMAN_SPAWNING_CHANCE = 1;
private static final int MAX_ENDERMAN_SPAWNING_CHANCE = 32; private static final int MAX_ENDERMAN_SPAWNING_CHANCE = 32;
@ -100,7 +98,7 @@ public class TileEntityRift extends TileEntity
//This code should execute once every 10 seconds //This code should execute once every 10 seconds
if (updateTimer > 200) if (updateTimer > 200)
{ {
this.spawnEndermen(); //this.spawnEndermen();
this.grow(mod_pocketDim.properties); this.grow(mod_pocketDim.properties);
updateTimer = 0; updateTimer = 0;
} }
@ -334,53 +332,16 @@ public class TileEntityRift extends TileEntity
return; return;
} }
// The probability of rifts trying to spread increases if more rifts are nearby // The probability of rifts trying to spread increases if more rifts are nearby.
// Players should see rifts spread faster within clusters than at the edges of clusters // Players should see rifts spread faster within clusters than at the edges of clusters.
// Also, single rifts CANNOT spread. // Also, single rifts CANNOT spread.
int nearRifts = dimension.findRiftsInRange(this.worldObj, 5, xCoord, yCoord, zCoord).size(); int nearRifts = dimension.findRiftsInRange(worldObj, 5, xCoord, yCoord, zCoord).size();
if (nearRifts == 0 || random.nextInt(nearRifts) == 0) if (nearRifts == 0 || random.nextInt(nearRifts) == 0)
{ {
return; return;
} }
int x, y, z; hasGrownRifts = mod_pocketDim.blockRift.spreadRift(dimension, link, worldObj, random);
int spreadAttempts = 0;
for (int searchAttempts = 0; searchAttempts < MAX_SEARCH_ATTEMPTS; searchAttempts++)
{
x = xCoord + MathHelper.getRandomIntegerInRange(random, -6, 6);
y = yCoord + MathHelper.getRandomIntegerInRange(random, -4, 4);
z = zCoord + MathHelper.getRandomIntegerInRange(random, -6, 6);
if (y >= 0 && y < worldObj.getActualHeight() && worldObj.isAirBlock(x, y, z))
{
Vec3 position = worldObj.getWorldVec3Pool().getVecFromPool(xCoord, yCoord, zCoord);
Vec3 spreadTarget = worldObj.getWorldVec3Pool().getVecFromPool(x, y, z);
MovingObjectPosition hit = worldObj.clip(position, spreadTarget, false);
if (hit == null || !mod_pocketDim.blockRift.isBlockImmune(worldObj, hit.blockX, hit.blockY, hit.blockZ))
{
if(hit!=null)
{
dimension.createChildLink(hit.blockX, hit.blockY, hit.blockZ, link);
this.worldObj.setBlock(hit.blockX, hit.blockY, hit.blockZ, mod_pocketDim.blockRift.blockID);
}
else
{
dimension.createChildLink(x,y,z,link);
this.worldObj.setBlock(x,y,z, mod_pocketDim.blockRift.blockID);
}
hasGrownRifts = true;
break;
}
else
{
spreadAttempts++;
if (spreadAttempts >= MAX_SPREAD_ATTEMPTS)
{
break;
}
}
}
}
} }
@Override @Override