mirror of
https://github.com/HbmMods/Hbm-s-Nuclear-Tech-GIT.git
synced 2026-01-25 10:32:49 +00:00
Merge pull request #494 from MartinTheDragon/fast-fallout
Backport the faster fallout algorithm
This commit is contained in:
commit
bcb8d87326
@ -23,7 +23,7 @@ public class BombConfig {
|
|||||||
public static int mk4 = 1024;
|
public static int mk4 = 1024;
|
||||||
public static int blastSpeed = 1024;
|
public static int blastSpeed = 1024;
|
||||||
public static int falloutRange = 100;
|
public static int falloutRange = 100;
|
||||||
public static int fSpeed = 256;
|
public static int fDelay = 4;
|
||||||
public static int limitExplosionLifespan = 0;
|
public static int limitExplosionLifespan = 0;
|
||||||
|
|
||||||
public static void loadFromConfig(Configuration config) {
|
public static void loadFromConfig(Configuration config) {
|
||||||
@ -80,17 +80,16 @@ public class BombConfig {
|
|||||||
Property propBlastSpeed = config.get(CATEGORY_NUKE, "6.01_blastSpeed", 1024);
|
Property propBlastSpeed = config.get(CATEGORY_NUKE, "6.01_blastSpeed", 1024);
|
||||||
propBlastSpeed.comment = "Base speed of MK3 system (old and schrabidium) detonations (Blocks / tick)";
|
propBlastSpeed.comment = "Base speed of MK3 system (old and schrabidium) detonations (Blocks / tick)";
|
||||||
blastSpeed = propBlastSpeed.getInt();
|
blastSpeed = propBlastSpeed.getInt();
|
||||||
// fallout range
|
// new explosion speed
|
||||||
Property propFalloutRange = config.get(CATEGORY_NUKE, "6.02_blastSpeedNew", 1024);
|
Property propFalloutRange = config.get(CATEGORY_NUKE, "6.02_blastSpeedNew", 1024);
|
||||||
propFalloutRange.comment = "Base speed of MK4 system (new) detonations (Blocks / tick)";
|
propFalloutRange.comment = "Base speed of MK4 system (new) detonations (Blocks / tick)";
|
||||||
mk4 = propFalloutRange.getInt();
|
mk4 = propFalloutRange.getInt();
|
||||||
// fallout speed
|
// fallout range
|
||||||
Property falloutRangeProp = config.get(CATEGORY_NUKE, "6.03_falloutRange", 100);
|
Property falloutRangeProp = config.get(CATEGORY_NUKE, "6.03_falloutRange", 100);
|
||||||
falloutRangeProp.comment = "Radius of fallout area (base radius * value in percent)";
|
falloutRangeProp.comment = "Radius of fallout area (base radius * value in percent)";
|
||||||
falloutRange = falloutRangeProp.getInt();
|
falloutRange = falloutRangeProp.getInt();
|
||||||
// new explosion speed
|
Property falloutDelayProp = config.get(CATEGORY_NUKE, "6.04_falloutDelay", 4);
|
||||||
Property falloutSpeed = config.get(CATEGORY_NUKE, "6.04_falloutSpeed", 256);
|
falloutDelayProp.comment = "How many ticks to wait for the next fallout chunk computation";
|
||||||
falloutSpeed.comment = "Blocks processed per tick by the fallout rain";
|
fDelay = falloutDelayProp.getInt();
|
||||||
fSpeed = falloutSpeed.getInt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,20 +5,20 @@ import com.hbm.config.BombConfig;
|
|||||||
import com.hbm.config.RadiationConfig;
|
import com.hbm.config.RadiationConfig;
|
||||||
import com.hbm.config.VersatileConfig;
|
import com.hbm.config.VersatileConfig;
|
||||||
import com.hbm.saveddata.AuxSavedData;
|
import com.hbm.saveddata.AuxSavedData;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.material.Material;
|
import net.minecraft.block.material.Material;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.init.Blocks;
|
import net.minecraft.init.Blocks;
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
import net.minecraft.util.Vec3;
|
import net.minecraft.util.Vec3;
|
||||||
|
import net.minecraft.world.ChunkCoordIntPair;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.util.ForgeDirection;
|
import net.minecraftforge.common.util.ForgeDirection;
|
||||||
|
|
||||||
public class EntityFalloutRain extends Entity {
|
import java.util.*;
|
||||||
|
|
||||||
public int revProgress;
|
public class EntityFalloutRain extends Entity {
|
||||||
public int radProgress;
|
private boolean firstTick = true; // Of course Vanilla has it private in Entity...
|
||||||
|
|
||||||
public EntityFalloutRain(World p_i1582_1_) {
|
public EntityFalloutRain(World p_i1582_1_) {
|
||||||
super(p_i1582_1_);
|
super(p_i1582_1_);
|
||||||
@ -33,50 +33,38 @@ public class EntityFalloutRain extends Entity {
|
|||||||
this.isImmuneToFire = true;
|
this.isImmuneToFire = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int tickDelay = BombConfig.fDelay;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpdate() {
|
public void onUpdate() {
|
||||||
|
|
||||||
if(!worldObj.isRemote) {
|
if(!worldObj.isRemote) {
|
||||||
|
if (firstTick) {
|
||||||
|
if (chunksToProcess.isEmpty() && outerChunksToProcess.isEmpty()) gatherChunks();
|
||||||
|
firstTick = false;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < BombConfig.fSpeed; i++) {
|
if (tickDelay == 0) {
|
||||||
|
tickDelay = BombConfig.fDelay;
|
||||||
|
if (!chunksToProcess.isEmpty()) {
|
||||||
|
long chunkPos = chunksToProcess.remove(chunksToProcess.size() - 1); // Just so it doesn't shift the whole list every time
|
||||||
|
int chunkPosX = (int) (chunkPos & Integer.MAX_VALUE);
|
||||||
|
int chunkPosZ = (int) (chunkPos >> 32 & Integer.MAX_VALUE);
|
||||||
|
for (int x = chunkPosX << 4; x <= (chunkPosX << 4) + 16; x++) for (int z = chunkPosZ << 4; z <= (chunkPosZ << 4) + 16; z++)
|
||||||
|
stomp(x, z, Math.hypot(x - posX, z - posZ) * 100 / getScale());
|
||||||
|
} else if (!outerChunksToProcess.isEmpty()) {
|
||||||
|
long chunkPos = outerChunksToProcess.remove(outerChunksToProcess.size() - 1);
|
||||||
|
int chunkPosX = (int) (chunkPos & Integer.MAX_VALUE);
|
||||||
|
int chunkPosZ = (int) (chunkPos >> 32 & Integer.MAX_VALUE);
|
||||||
|
for (int x = chunkPosX << 4; x <= (chunkPosX << 4) + 16; x++) for (int z = chunkPosZ << 4; z <= (chunkPosZ << 4) + 16; z++) {
|
||||||
|
double distance = Math.hypot(x - posX, z - posZ);
|
||||||
|
if (distance <= getScale()) stomp(x, z, distance * 100 / getScale());
|
||||||
|
}
|
||||||
|
} else setDead();
|
||||||
|
}
|
||||||
|
|
||||||
Vec3 vec = Vec3.createVectorHelper(radProgress * 0.5, 0, 0);
|
tickDelay--;
|
||||||
double circum = radProgress * 2 * Math.PI * 2;
|
|
||||||
|
|
||||||
///
|
if(this.isDead) {
|
||||||
if(circum == 0)
|
|
||||||
circum = 1;
|
|
||||||
///
|
|
||||||
|
|
||||||
double part = 360D / circum;
|
|
||||||
|
|
||||||
vec.rotateAroundY((float) (part * revProgress));
|
|
||||||
|
|
||||||
int x = (int) (posX + vec.xCoord);
|
|
||||||
int z = (int) (posZ + vec.zCoord);
|
|
||||||
|
|
||||||
//int y = worldObj.getHeightValue(x, z) - 1;
|
|
||||||
|
|
||||||
//if(worldObj.getBlock(x, y, z) == Blocks.grass)
|
|
||||||
// worldObj.setBlock(x, y, z, ModBlocks.waste_earth);
|
|
||||||
|
|
||||||
double dist = radProgress * 100 / getScale() * 0.5;
|
|
||||||
|
|
||||||
stomp(x, z, dist);
|
|
||||||
|
|
||||||
revProgress++;
|
|
||||||
|
|
||||||
if(revProgress > circum) {
|
|
||||||
revProgress = 0;
|
|
||||||
radProgress++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(radProgress > getScale() * 2D) {
|
|
||||||
this.setDead();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.isDead) {
|
|
||||||
if(RadiationConfig.rain > 0 && getScale() > 150) {
|
if(RadiationConfig.rain > 0 && getScale() > 150) {
|
||||||
worldObj.getWorldInfo().setRaining(true);
|
worldObj.getWorldInfo().setRaining(true);
|
||||||
worldObj.getWorldInfo().setThundering(true);
|
worldObj.getWorldInfo().setThundering(true);
|
||||||
@ -88,6 +76,36 @@ public class EntityFalloutRain extends Entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final List<Long> chunksToProcess = new ArrayList<>();
|
||||||
|
private final List<Long> outerChunksToProcess = new ArrayList<>();
|
||||||
|
|
||||||
|
// Is it worth the effort to split this into a method that can be called over multiple ticks? I'd say it's fast enough anyway...
|
||||||
|
private void gatherChunks() {
|
||||||
|
Set<Long> chunks = new LinkedHashSet<>(); // LinkedHashSet preserves insertion order
|
||||||
|
Set<Long> outerChunks = new LinkedHashSet<>();
|
||||||
|
int outerRange = getScale();
|
||||||
|
// Basically defines something like the step size, but as indirect proportion. The actual angle used for rotation will always end up at 360° for angle == adjustedMaxAngle
|
||||||
|
// So yea, I mathematically worked out that 20 is a good value for this, with the minimum possible being 18 in order to reach all chunks
|
||||||
|
int adjustedMaxAngle = 20 * outerRange / 32; // step size = 20 * chunks / 2
|
||||||
|
for (int angle = 0; angle <= adjustedMaxAngle; angle++) {
|
||||||
|
Vec3 vector = Vec3.createVectorHelper(outerRange, 0, 0);
|
||||||
|
vector.rotateAroundY((float) (angle * Math.PI / 180.0 / (adjustedMaxAngle / 360.0))); // Ugh, mutable data classes (also, ugh, radians; it uses degrees in 1.18; took me two hours to debug)
|
||||||
|
outerChunks.add(ChunkCoordIntPair.chunkXZ2Int((int) (posX + vector.xCoord) >> 4, (int) (posZ + vector.zCoord) >> 4));
|
||||||
|
}
|
||||||
|
for (int distance = 0; distance <= outerRange; distance += 8) for (int angle = 0; angle <= adjustedMaxAngle; angle++) {
|
||||||
|
Vec3 vector = Vec3.createVectorHelper(distance, 0, 0);
|
||||||
|
vector.rotateAroundY((float) (angle * Math.PI / 180.0 / (adjustedMaxAngle / 360.0)));
|
||||||
|
long chunkCoord = ChunkCoordIntPair.chunkXZ2Int((int) (posX + vector.xCoord) >> 4, (int) (posZ + vector.zCoord) >> 4);
|
||||||
|
if (!outerChunks.contains(chunkCoord)) chunks.add(chunkCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
chunksToProcess.addAll(chunks);
|
||||||
|
outerChunksToProcess.addAll(outerChunks);
|
||||||
|
Collections.reverse(chunksToProcess); // So it starts nicely from the middle
|
||||||
|
Collections.reverse(outerChunksToProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO cache chunks?
|
||||||
private void stomp(int x, int z, double dist) {
|
private void stomp(int x, int z, double dist) {
|
||||||
|
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
@ -103,7 +121,7 @@ public class EntityFalloutRain extends Entity {
|
|||||||
|
|
||||||
if(b != ModBlocks.fallout && (ab == Blocks.air || (ab.isReplaceable(worldObj, x, y + 1, z) && !ab.getMaterial().isLiquid()))) {
|
if(b != ModBlocks.fallout && (ab == Blocks.air || (ab.isReplaceable(worldObj, x, y + 1, z) && !ab.getMaterial().isLiquid()))) {
|
||||||
|
|
||||||
double d = (double) radProgress / (double) getScale() * 0.5;
|
double d = dist / 100;
|
||||||
|
|
||||||
double chance = 0.05 - Math.pow((d - 0.6) * 0.5, 2);
|
double chance = 0.05 - Math.pow((d - 0.6) * 0.5, 2);
|
||||||
|
|
||||||
@ -145,7 +163,7 @@ public class EntityFalloutRain extends Entity {
|
|||||||
return;
|
return;
|
||||||
} else if(b == Blocks.sand) {
|
} else if(b == Blocks.sand) {
|
||||||
|
|
||||||
if(rand.nextInt(60) == 0)
|
if(rand.nextInt(20) == 0)
|
||||||
worldObj.setBlock(x, y, z, meta == 0 ? ModBlocks.waste_trinitite : ModBlocks.waste_trinitite_red);
|
worldObj.setBlock(x, y, z, meta == 0 ? ModBlocks.waste_trinitite : ModBlocks.waste_trinitite_red);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -162,9 +180,9 @@ public class EntityFalloutRain extends Entity {
|
|||||||
|
|
||||||
else if (b == Blocks.coal_ore) {
|
else if (b == Blocks.coal_ore) {
|
||||||
int ra = rand.nextInt(150);
|
int ra = rand.nextInt(150);
|
||||||
if (ra < 7) {
|
if (ra < 20) {
|
||||||
worldObj.setBlock(x, y, z, Blocks.diamond_ore);
|
worldObj.setBlock(x, y, z, Blocks.diamond_ore);
|
||||||
} else if (ra < 10) {
|
} else if (ra < 30) {
|
||||||
worldObj.setBlock(x, y, z, Blocks.emerald_ore);
|
worldObj.setBlock(x, y, z, Blocks.emerald_ore);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -219,33 +237,50 @@ public class EntityFalloutRain extends Entity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void entityInit() {
|
protected void entityInit() {
|
||||||
this.dataWatcher.addObject(16, Integer.valueOf(0));
|
this.dataWatcher.addObject(16, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void readEntityFromNBT(NBTTagCompound p_70037_1_) {
|
protected void readEntityFromNBT(NBTTagCompound tag) {
|
||||||
setScale(p_70037_1_.getInteger("scale"));
|
setScale(tag.getInteger("scale"));
|
||||||
revProgress = p_70037_1_.getInteger("revProgress");
|
chunksToProcess.addAll(readChunksFromIntArray(tag.getIntArray("chunks")));
|
||||||
radProgress = p_70037_1_.getInteger("radProgress");
|
outerChunksToProcess.addAll(readChunksFromIntArray(tag.getIntArray("outerChunks")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Long> readChunksFromIntArray(int[] data) {
|
||||||
|
List<Long> coords = new ArrayList<>();
|
||||||
|
boolean firstPart = true;
|
||||||
|
int x = 0;
|
||||||
|
for (int coord : data) {
|
||||||
|
if (firstPart) x = coord;
|
||||||
|
else coords.add(ChunkCoordIntPair.chunkXZ2Int(x, coord));
|
||||||
|
firstPart = !firstPart;
|
||||||
|
}
|
||||||
|
return coords;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void writeEntityToNBT(NBTTagCompound p_70014_1_) {
|
protected void writeEntityToNBT(NBTTagCompound tag) {
|
||||||
p_70014_1_.setInteger("scale", getScale());
|
tag.setInteger("scale", getScale());
|
||||||
p_70014_1_.setInteger("revProgress", revProgress);
|
tag.setIntArray("chunks", writeChunksToIntArray(chunksToProcess));
|
||||||
p_70014_1_.setInteger("radProgress", radProgress);
|
tag.setIntArray("outerChunks", writeChunksToIntArray(outerChunksToProcess));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] writeChunksToIntArray(List<Long> coords) {
|
||||||
|
int[] data = new int[coords.size() * 2];
|
||||||
|
for (int i = 0; i < coords.size(); i++) {
|
||||||
|
data[i * 2] = (int) (coords.get(i) & Integer.MAX_VALUE);
|
||||||
|
data[i * 2 + 1] = (int) (coords.get(i) >> 32 & Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setScale(int i) {
|
public void setScale(int i) {
|
||||||
|
this.dataWatcher.updateObject(16, i);
|
||||||
this.dataWatcher.updateObject(16, Integer.valueOf(i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getScale() {
|
public int getScale() {
|
||||||
|
|
||||||
int scale = this.dataWatcher.getWatchableObjectInt(16);
|
int scale = this.dataWatcher.getWatchableObjectInt(16);
|
||||||
|
|
||||||
return scale == 0 ? 1 : scale;
|
return scale == 0 ? 1 : scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user