diff options
| author | Alexdoru <57050655+Alexdoru@users.noreply.github.com> | 2024-10-21 21:21:33 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-21 19:21:33 +0000 |
| commit | 901cb0d294b0c4f114bb247fbd7d6f97e7484f3c (patch) | |
| tree | fd4900d59f98ec34c9119c2003f79f7467abddf0 /src/main/java/gregtech/common/pollution | |
| parent | e741976ea6a6fa5dbcb45813fd1e2ca368331ba5 (diff) | |
| download | GT5-Unofficial-901cb0d294b0c4f114bb247fbd7d6f97e7484f3c.tar.gz GT5-Unofficial-901cb0d294b0c4f114bb247fbd7d6f97e7484f3c.tar.bz2 GT5-Unofficial-901cb0d294b0c4f114bb247fbd7d6f97e7484f3c.zip | |
Import pollution mixins from hodgepodge (#3395)
Co-authored-by: Martin Robertz <dream-master@gmx.net>
Co-authored-by: boubou19 <miisterunknown@gmail.com>
Diffstat (limited to 'src/main/java/gregtech/common/pollution')
8 files changed, 1610 insertions, 0 deletions
diff --git a/src/main/java/gregtech/common/pollution/BlockMatcher.java b/src/main/java/gregtech/common/pollution/BlockMatcher.java new file mode 100644 index 0000000000..a701d323bd --- /dev/null +++ b/src/main/java/gregtech/common/pollution/BlockMatcher.java @@ -0,0 +1,96 @@ +package gregtech.common.pollution; + +import java.util.Map; +import java.util.Set; + +import net.minecraft.block.Block; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraftforge.event.world.WorldEvent; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.registry.FMLControlledNamespacedRegistry; +import cpw.mods.fml.common.registry.GameData; +import gregtech.GTMod; + +// Shamelessly Taken from BetterFoliage by octarine-noise +public class BlockMatcher { + + public Map<Class<?>, ColorOverrideType> whiteList = Maps.newHashMap(); + public Set<Class<?>> blackList = Sets.newHashSet(); + public Map<Integer, ColorOverrideType> blockIDs = Maps.newHashMap(); + + public ColorOverrideType matchesID(int blockId) { + return blockIDs.get(blockId); + } + + public ColorOverrideType matchesID(Block block) { + return blockIDs.get(Block.blockRegistry.getIDForObject(block)); + } + + public void updateClassList(String[] cfg) { + whiteList.clear(); + blackList.clear(); + for (String line : cfg) { + GTMod.GT_FML_LOGGER.info("Checking for block:" + line); + String[] lines = line.split(":"); + ColorOverrideType type = null; + if (lines.length > 1) { + try { + type = ColorOverrideType.fromName(lines[1].trim()); + } catch (NumberFormatException e) { + GTMod.GT_FML_LOGGER.error(String.format("Invalid type [%s]", line)); + continue; + } + } + + if (lines[0].startsWith("-")) { + try { + blackList.add(Class.forName(lines[0].substring(1))); + GTMod.GT_FML_LOGGER.info("\t added blacklist:" + lines[0].substring(1)); + } catch (ClassNotFoundException ignored) {} + } else { + if (type == null) { + GTMod.GT_FML_LOGGER.error(String.format("Invalid type [%s]", line)); + continue; + } + + try { + whiteList.put(Class.forName(lines[0]), type); + GTMod.GT_FML_LOGGER.info("\t added whitelist:" + lines[0]); + } catch (ClassNotFoundException ignored) {} + } + } + // updateBlockIDs(); + } + + private void updateBlockIDs() { + blockIDs.clear(); + FMLControlledNamespacedRegistry<Block> blockRegistry = GameData.getBlockRegistry(); + for (Block block : blockRegistry.typeSafeIterable()) { + ColorOverrideType t = matchesClass(block); + if (t != null) blockIDs.put(Block.blockRegistry.getIDForObject(block), t); + } + } + + private ColorOverrideType matchesClass(Block block) { + for (Class<?> clazz : blackList) if (clazz.isAssignableFrom(block.getClass())) return null; + for (Class<?> clazz : whiteList.keySet()) + if (clazz.isAssignableFrom(block.getClass())) return whiteList.get(clazz); + return null; + } + + /** + * Caches block IDs on world load for fast lookup + * + * @param event + */ + @SubscribeEvent + public void handleWorldLoad(WorldEvent.Load event) { + if (event.world instanceof WorldClient) { + updateBlockIDs(); + } + } +} diff --git a/src/main/java/gregtech/common/pollution/ColorOverrideType.java b/src/main/java/gregtech/common/pollution/ColorOverrideType.java new file mode 100644 index 0000000000..de0a44a835 --- /dev/null +++ b/src/main/java/gregtech/common/pollution/ColorOverrideType.java @@ -0,0 +1,28 @@ +package gregtech.common.pollution; + +public enum ColorOverrideType { + + FLOWER, + GRASS, + LEAVES, + LIQUID; + + public static ColorOverrideType fromName(String name) { + return switch (name) { + case "FLOWER" -> FLOWER; + case "GRASS" -> GRASS; + case "LEAVES" -> LEAVES; + case "LIQUID" -> LIQUID; + default -> throw new RuntimeException(); + }; + } + + public int getColor(int oColor, int x, int z) { + return switch (this) { + case FLOWER -> PollutionRenderer.colorFoliage(oColor, x, z); + case GRASS -> PollutionRenderer.colorGrass(oColor, x, z); + case LEAVES -> PollutionRenderer.colorLeaves(oColor, x, z); + case LIQUID -> PollutionRenderer.colorLiquid(oColor, x, z); + }; + } +} diff --git a/src/main/java/gregtech/common/pollution/EntityFXPollution.java b/src/main/java/gregtech/common/pollution/EntityFXPollution.java new file mode 100644 index 0000000000..f1a1f18447 --- /dev/null +++ b/src/main/java/gregtech/common/pollution/EntityFXPollution.java @@ -0,0 +1,59 @@ +package gregtech.common.pollution; + +import java.util.Random; + +import net.minecraft.client.particle.EntityFX; +import net.minecraft.world.World; + +public class EntityFXPollution extends EntityFX { + + public EntityFXPollution(World world, double x, double y, double z) { + super(world, x, y, z, 0, 0, 0); + + this.particleRed = 0.25F; + this.particleGreen = 0.2F; + this.particleBlue = 0.25F; + + this.motionX *= 0.1D; + this.motionY *= -0.1D; + this.motionZ *= 0.1F; + + Random random = world.rand; + this.motionX += random.nextFloat() * -1.9D * random.nextFloat() * 0.1D; + this.motionY += random.nextFloat() * -0.5D * random.nextFloat() * 0.1D * 5.0D; + this.motionZ += random.nextFloat() * -1.9D * random.nextFloat() * 0.1D; + + this.particleTextureIndexX = 0; + this.particleTextureIndexY = 0; + + this.particleMaxAge = (int) ((double) 20 / ((double) random.nextFloat() * 0.8D + 0.2D)); + + this.particleScale *= 0.75F; + this.noClip = true; + } + + @Override + public void onUpdate() { + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + + if (this.particleAge++ >= this.particleMaxAge) { + this.setDead(); + } else { + this.motionY -= 5.0E-4D; + this.moveEntity(this.motionX, this.motionY, this.motionZ); + if (this.posY == this.prevPosY) { + this.motionX *= 1.1D; + this.motionZ *= 1.1D; + } + this.motionX *= 0.96D; + this.motionY *= 0.96D; + this.motionZ *= 0.96D; + if (this.onGround) { + this.motionX *= 0.7D; + this.motionZ *= 0.7D; + } + } + } +} diff --git a/src/main/java/gregtech/common/pollution/GTClientPollutionMap.java b/src/main/java/gregtech/common/pollution/GTClientPollutionMap.java new file mode 100644 index 0000000000..0fd1da309b --- /dev/null +++ b/src/main/java/gregtech/common/pollution/GTClientPollutionMap.java @@ -0,0 +1,140 @@ +package gregtech.common.pollution; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityClientPlayerMP; +import net.minecraft.util.MathHelper; + +public class GTClientPollutionMap { + + private static final byte RADIUS = 24; + private static final byte DISTANCE_RELOAD_MAP = 5; // When player moved x chunks, shift the map to new center. + private static final byte SIZE = RADIUS * 2 + 1; // Area to keep stored. + + private int x0, z0; + private int dim; + + private boolean initialized = false; + + private static short[][] chunkMatrix; // short because reasons. + + public GTClientPollutionMap() {} + + public void reset() { + initialized = false; + } + + private void initialize(int playerChunkX, int playerChunkZ, int dimension) { + initialized = true; + chunkMatrix = new short[SIZE][SIZE]; + x0 = playerChunkX; + z0 = playerChunkZ; + dim = dimension; + } + + public void addChunkPollution(int chunkX, int chunkZ, int pollution) { + EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer; + if (player == null || player.worldObj == null) return; + + int playerXChunk = MathHelper.floor_double(player.posX) >> 4; + int playerZChunk = MathHelper.floor_double(player.posZ) >> 4; // posX/Z seems to be always loaded, + + if (!initialized) { + initialize(playerXChunk, playerZChunk, player.dimension); + } + + if (dim != player.dimension) { + initialize(playerXChunk, playerZChunk, player.dimension); + } + + if (Math.abs(x0 - playerXChunk) > DISTANCE_RELOAD_MAP || Math.abs(z0 - playerZChunk) > DISTANCE_RELOAD_MAP) + shiftCenter(playerXChunk, playerZChunk); + + int relX = chunkX - x0 + RADIUS; + if (relX >= SIZE || relX < 0) // out of bounds + return; + int relZ = chunkZ - z0 + RADIUS; + if (relZ >= SIZE || relZ < 0) // out of bounds + return; + + pollution = pollution / 225; + if (pollution > Short.MAX_VALUE) // Sanity + chunkMatrix[relX][relZ] = Short.MAX_VALUE; // Max pollution = 7,3mill + else if (pollution < 0) chunkMatrix[relX][relZ] = 0; + else chunkMatrix[relX][relZ] = (short) (pollution); + } + + // xy interpolation, between 4 chunks as corners, unknown treated as 0. + public int getPollution(double fx, double fz) { + if (!initialized) return 0; + int x = MathHelper.floor_double(fx); + int z = MathHelper.floor_double(fz); + int xDiff = ((x - 8) >> 4) - x0; + int zDiff = ((z - 8) >> 4) - z0; + + if (xDiff < -RADIUS || zDiff < -RADIUS || xDiff >= RADIUS || zDiff >= RADIUS) return 0; + + // coordinates in shifted chunk. + x = (x - 8) % 16; + z = (z - 8) % 16; + if (x < 0) x = 16 + x; + if (z < 0) z = 16 + z; + + int xi = 15 - x; + int zi = 15 - z; + + // read pollution in 4 corner chunks + int offsetX = RADIUS + xDiff; + int offsetZ = RADIUS + zDiff; + + int c00 = chunkMatrix[offsetX][offsetZ]; + int c10 = chunkMatrix[offsetX + 1][offsetZ]; + int c01 = chunkMatrix[offsetX][offsetZ + 1]; + int c11 = chunkMatrix[offsetX + 1][offsetZ + 1]; + + // Is divided by 15*15 but is handled when storing chunk data. + return c00 * xi * zi + c10 * x * zi + c01 * xi * z + c11 * x * z; + } + + // shift the matrix to fit new center + private void shiftCenter(int chunkX, int chunkZ) { + int xDiff = chunkX - x0; + int zDiff = chunkZ - z0; + boolean[] allEmpty = new boolean[SIZE]; // skip check z row if its empty. + if (xDiff > 0) for (byte x = 0; x < SIZE; x++) { + int xOff = x + xDiff; + if (xOff < SIZE) { + chunkMatrix[x] = chunkMatrix[xOff].clone(); + } else { + chunkMatrix[x] = new short[SIZE]; + allEmpty[x] = true; + } + } + else if (xDiff < 0) for (byte x = SIZE - 1; x >= 0; x--) { + int xOff = x + xDiff; + if (xOff > 0) { + chunkMatrix[x] = chunkMatrix[xOff].clone(); + } else { + chunkMatrix[x] = new short[SIZE]; + allEmpty[x] = true; + } + } + + if (zDiff > 0) for (byte x = 0; x < SIZE; x++) { + if (allEmpty[x]) continue; + for (int z = 0; z < SIZE; z++) { + int zOff = z + zDiff; + chunkMatrix[x][z] = (zOff < SIZE) ? chunkMatrix[x][zOff] : 0; + } + } + else if (zDiff < 0) for (byte x = 0; x < SIZE; x++) { + if (allEmpty[x]) continue; + for (int z = SIZE - 1; z >= 0; z--) { + int zOff = z + zDiff; + chunkMatrix[x][z] = (zOff > 0) ? chunkMatrix[x][zOff] : 0; + } + } + + x0 = chunkX; + z0 = chunkZ; + } +} diff --git a/src/main/java/gregtech/common/pollution/Pollution.java b/src/main/java/gregtech/common/pollution/Pollution.java new file mode 100644 index 0000000000..10b8ffcfa7 --- /dev/null +++ b/src/main/java/gregtech/common/pollution/Pollution.java @@ -0,0 +1,533 @@ +package gregtech.common.pollution; + +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; +import static gregtech.common.GTProxy.dimensionWisePollution; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.ChunkPosition; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.ChunkDataEvent; +import net.minecraftforge.event.world.ChunkWatchEvent; +import net.minecraftforge.event.world.WorldEvent; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; +import cpw.mods.fml.common.network.NetworkRegistry; +import gregtech.GTMod; +import gregtech.api.enums.GTValues; +import gregtech.api.interfaces.ICleanroom; +import gregtech.api.interfaces.ICleanroomReceiver; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.net.GTPacketPollution; +import gregtech.api.util.GTChunkAssociatedData; +import gregtech.api.util.GTUtility; + +public class Pollution { + + private static final Storage STORAGE = new Storage(); + /** + * Pollution dispersion until effects start: Calculation: ((Limit * 0.01) + 2000) * (4 <- spreading rate) + * <p> + * SMOG(500k) 466.7 pollution/sec Poison(750k) 633,3 pollution/sec Dying Plants(1mio) 800 pollution/sec Sour + * Rain(1.5mio) 1133.3 pollution/sec + * <p> + * Pollution producers (pollution/sec) Bronze Boiler(20) Lava Boiler(20) High Pressure Boiler(20) Bronze Blast + * Furnace(50) Diesel Generator(40/80/160) Gas Turbine(20/40/80) Charcoal Pile(100) + * <p> + * Large Diesel Engine(320) Electric Blast Furnace(100) Implosion Compressor(2000) Large Boiler(240) Large Gas + * Turbine(160) Multi Smelter(100) Pyrolyse Oven(400) + * <p> + * Machine Explosion(100,000) + * <p> + * Other Random Shit: lots and lots + * <p> + * Muffler Hatch Pollution reduction: ** inaccurate ** LV (0%), MV (30%), HV (52%), EV (66%), IV (76%), LuV (84%), + * ZPM (89%), UV (92%), MAX (95%) + */ + private List<ChunkCoordIntPair> pollutionList = new ArrayList<>(); // chunks left to process in this cycle + + private final Set<ChunkCoordIntPair> pollutedChunks = new HashSet<>(); // a global list of all chunks with positive + // pollution + private int operationsPerTick = 0; // how much chunks should be processed in each cycle + private static final short cycleLen = 1200; + private final World world; + private boolean blank = true; + public static int mPlayerPollution; + + private static final int POLLUTIONPACKET_MINVALUE = 1000; + + private static GT_PollutionEventHandler EVENT_HANDLER; + + public Pollution(World world) { + this.world = world; + + if (EVENT_HANDLER == null) { + EVENT_HANDLER = new GT_PollutionEventHandler(); + MinecraftForge.EVENT_BUS.register(EVENT_HANDLER); + } + } + + public static void onWorldTick(TickEvent.WorldTickEvent aEvent) { // called from proxy + // return if pollution disabled + if (!GTMod.gregtechproxy.mPollution) return; + if (aEvent.phase == TickEvent.Phase.START) return; + final Pollution pollutionInstance = dimensionWisePollution.get(aEvent.world.provider.dimensionId); + if (pollutionInstance == null) return; + pollutionInstance.tickPollutionInWorld((int) (aEvent.world.getTotalWorldTime() % cycleLen)); + } + + public static BlockMatcher standardBlocks; + public static BlockMatcher liquidBlocks; + public static BlockMatcher doublePlants; + public static BlockMatcher crossedSquares; + public static BlockMatcher blockVine; + + public static void onPostInitClient() { + if (PollutionConfig.pollution) { + standardBlocks = new BlockMatcher(); + liquidBlocks = new BlockMatcher(); + doublePlants = new BlockMatcher(); + crossedSquares = new BlockMatcher(); + blockVine = new BlockMatcher(); + standardBlocks.updateClassList(PollutionConfig.renderStandardBlock); + liquidBlocks.updateClassList(PollutionConfig.renderBlockLiquid); + doublePlants.updateClassList(PollutionConfig.renderBlockDoublePlant); + crossedSquares.updateClassList(PollutionConfig.renderCrossedSquares); + blockVine.updateClassList(PollutionConfig.renderblockVine); + MinecraftForge.EVENT_BUS.register(standardBlocks); + MinecraftForge.EVENT_BUS.register(liquidBlocks); + MinecraftForge.EVENT_BUS.register(doublePlants); + MinecraftForge.EVENT_BUS.register(crossedSquares); + MinecraftForge.EVENT_BUS.register(blockVine); + MinecraftForge.EVENT_BUS.register(new PollutionTooltip()); + } + } + + private void tickPollutionInWorld(int aTickID) { // called from method above + // gen data set + if (aTickID == 0 || blank) { + // make a snapshot of what to work on + pollutionList = new ArrayList<>(pollutedChunks); + // set operations per tick + if (!pollutionList.isEmpty()) operationsPerTick = Math.max(1, pollutionList.size() / cycleLen); + else operationsPerTick = 0; // SANity + blank = false; + } + + for (int chunksProcessed = 0; chunksProcessed < operationsPerTick; chunksProcessed++) { + if (pollutionList.isEmpty()) break; // no more stuff to do + ChunkCoordIntPair actualPos = pollutionList.remove(pollutionList.size() - 1); // faster + // get pollution + ChunkData currentData = STORAGE.get(world, actualPos); + int tPollution = currentData.getAmount(); + // remove some + tPollution = (int) (0.9945f * tPollution); + + if (tPollution > 400000) { // Spread Pollution + + ChunkCoordIntPair[] tNeighbors = new ChunkCoordIntPair[4]; // array is faster + tNeighbors[0] = (new ChunkCoordIntPair(actualPos.chunkXPos + 1, actualPos.chunkZPos)); + tNeighbors[1] = (new ChunkCoordIntPair(actualPos.chunkXPos - 1, actualPos.chunkZPos)); + tNeighbors[2] = (new ChunkCoordIntPair(actualPos.chunkXPos, actualPos.chunkZPos + 1)); + tNeighbors[3] = (new ChunkCoordIntPair(actualPos.chunkXPos, actualPos.chunkZPos - 1)); + for (ChunkCoordIntPair neighborPosition : tNeighbors) { + ChunkData neighbor = STORAGE.get(world, neighborPosition); + int neighborPollution = neighbor.getAmount(); + if (neighborPollution * 6 < tPollution * 5) { // MATHEMATICS... + int tDiff = tPollution - neighborPollution; + tDiff = tDiff / 20; + neighborPollution = GTUtility.safeInt((long) neighborPollution + tDiff); // tNPol += tDiff; + tPollution -= tDiff; + setChunkPollution(neighborPosition, neighborPollution); + } + } + + // Create Pollution effects + // Smog filter TODO + if (tPollution > GTMod.gregtechproxy.mPollutionSmogLimit) { + AxisAlignedBB chunk = AxisAlignedBB.getBoundingBox( + actualPos.chunkXPos << 4, + 0, + actualPos.chunkZPos << 4, + (actualPos.chunkXPos << 4) + 16, + 256, + (actualPos.chunkZPos << 4) + 16); + List<EntityLivingBase> tEntitys = world.getEntitiesWithinAABB(EntityLivingBase.class, chunk); + for (EntityLivingBase tEnt : tEntitys) { + if (tEnt instanceof EntityPlayerMP && ((EntityPlayerMP) tEnt).capabilities.isCreativeMode) + continue; + if (!(GTUtility.isWearingFullGasHazmat(tEnt))) { + switch (XSTR_INSTANCE.nextInt(3)) { + default: + tEnt.addPotionEffect( + new PotionEffect( + Potion.digSlowdown.id, + Math.min(tPollution / 1000, 1000), + tPollution / 400000)); + case 1: + tEnt.addPotionEffect( + new PotionEffect( + Potion.weakness.id, + Math.min(tPollution / 1000, 1000), + tPollution / 400000)); + case 2: + tEnt.addPotionEffect( + new PotionEffect( + Potion.moveSlowdown.id, + Math.min(tPollution / 1000, 1000), + tPollution / 400000)); + } + } + } + + // Poison effects + if (tPollution > GTMod.gregtechproxy.mPollutionPoisonLimit) { + for (EntityLivingBase tEnt : tEntitys) { + if (tEnt instanceof EntityPlayerMP && ((EntityPlayerMP) tEnt).capabilities.isCreativeMode) + continue; + if (!GTUtility.isWearingFullGasHazmat(tEnt)) { + switch (XSTR_INSTANCE.nextInt(4)) { + default: + tEnt.addPotionEffect(new PotionEffect(Potion.hunger.id, tPollution / 500000)); + case 1: + tEnt.addPotionEffect( + new PotionEffect( + Potion.confusion.id, + Math.min(tPollution / 2000, 1000), + 1)); + case 2: + tEnt.addPotionEffect( + new PotionEffect( + Potion.poison.id, + Math.min(tPollution / 4000, 1000), + tPollution / 500000)); + case 3: + tEnt.addPotionEffect( + new PotionEffect( + Potion.blindness.id, + Math.min(tPollution / 2000, 1000), + 1)); + } + } + } + + // killing plants + if (tPollution > GTMod.gregtechproxy.mPollutionVegetationLimit) { + int f = 20; + for (; f < (tPollution / 25000); f++) { + int x = (actualPos.chunkXPos << 4) + XSTR_INSTANCE.nextInt(16); + int y = 60 + (-f + XSTR_INSTANCE.nextInt(f * 2 + 1)); + int z = (actualPos.chunkZPos << 4) + XSTR_INSTANCE.nextInt(16); + damageBlock(world, x, y, z, tPollution > GTMod.gregtechproxy.mPollutionSourRainLimit); + } + } + } + } + } + // Write new pollution to Hashmap !!! + setChunkPollution(actualPos, tPollution); + + // Send new value to players nearby + if (tPollution > POLLUTIONPACKET_MINVALUE) { + NetworkRegistry.TargetPoint point = new NetworkRegistry.TargetPoint( + world.provider.dimensionId, + (actualPos.chunkXPos << 4), + 64, + (actualPos.chunkZPos << 4), + 256); + GTValues.NW.sendToAllAround(new GTPacketPollution(actualPos, tPollution), point); + } + } + } + + private void setChunkPollution(ChunkCoordIntPair coord, int pollution) { + mutatePollution(world, coord.chunkXPos, coord.chunkZPos, c -> c.setAmount(pollution), pollutedChunks); + } + + private static void damageBlock(World world, int x, int y, int z, boolean sourRain) { + if (world.isRemote) return; + Block tBlock = world.getBlock(x, y, z); + int tMeta = world.getBlockMetadata(x, y, z); + if (tBlock == Blocks.air || tBlock == Blocks.stone || tBlock == Blocks.sand || tBlock == Blocks.deadbush) + return; + + if (tBlock == Blocks.leaves || tBlock == Blocks.leaves2 || tBlock.getMaterial() == Material.leaves) + world.setBlockToAir(x, y, z); + if (tBlock == Blocks.reeds) { + tBlock.dropBlockAsItem(world, x, y, z, tMeta, 0); + world.setBlockToAir(x, y, z); + } + if (tBlock == Blocks.tallgrass) world.setBlock(x, y, z, Blocks.deadbush); + if (tBlock == Blocks.vine) { + tBlock.dropBlockAsItem(world, x, y, z, tMeta, 0); + world.setBlockToAir(x, y, z); + } + if (tBlock == Blocks.waterlily || tBlock == Blocks.wheat + || tBlock == Blocks.cactus + || tBlock.getMaterial() == Material.cactus + || tBlock == Blocks.melon_block + || tBlock == Blocks.melon_stem) { + tBlock.dropBlockAsItem(world, x, y, z, tMeta, 0); + world.setBlockToAir(x, y, z); + } + if (tBlock == Blocks.red_flower || tBlock == Blocks.yellow_flower + || tBlock == Blocks.carrots + || tBlock == Blocks.potatoes + || tBlock == Blocks.pumpkin + || tBlock == Blocks.pumpkin_stem) { + tBlock.dropBlockAsItem(world, x, y, z, tMeta, 0); + world.setBlockToAir(x, y, z); + } + if (tBlock == Blocks.sapling || tBlock.getMaterial() == Material.plants) + world.setBlock(x, y, z, Blocks.deadbush); + if (tBlock == Blocks.cocoa) { + tBlock.dropBlockAsItem(world, x, y, z, tMeta, 0); + world.setBlockToAir(x, y, z); + } + if (tBlock == Blocks.mossy_cobblestone) world.setBlock(x, y, z, Blocks.cobblestone); + if (tBlock == Blocks.grass || tBlock.getMaterial() == Material.grass) world.setBlock(x, y, z, Blocks.dirt); + if (tBlock == Blocks.farmland || tBlock == Blocks.dirt) { + world.setBlock(x, y, z, Blocks.sand); + } + + if (sourRain && world.isRaining() + && (tBlock == Blocks.gravel || tBlock == Blocks.cobblestone) + && world.getBlock(x, y + 1, z) == Blocks.air + && world.canBlockSeeTheSky(x, y, z)) { + if (tBlock == Blocks.cobblestone) { + world.setBlock(x, y, z, Blocks.gravel); + } else { + world.setBlock(x, y, z, Blocks.sand); + } + } + } + + private static Pollution getPollutionManager(World world) { + return dimensionWisePollution.computeIfAbsent(world.provider.dimensionId, i -> new Pollution(world)); + } + + /** @see #addPollution(TileEntity, int) */ + public static void addPollution(IGregTechTileEntity te, int aPollution) { + addPollution((TileEntity) te, aPollution); + } + + /** + * Also pollutes cleanroom if {@code te} is an instance of {@link ICleanroomReceiver}. + * + * @see #addPollution(World, int, int, int) + */ + public static void addPollution(TileEntity te, int aPollution) { + if (!GTMod.gregtechproxy.mPollution || aPollution == 0 || te.getWorldObj().isRemote) return; + + if (aPollution > 0 && te instanceof ICleanroomReceiver receiver) { + ICleanroom cleanroom = receiver.getCleanroom(); + if (cleanroom != null && cleanroom.isValidCleanroom()) { + cleanroom.pollute(); + } + } + + addPollution(te.getWorldObj(), te.xCoord >> 4, te.zCoord >> 4, aPollution); + } + + /** @see #addPollution(World, int, int, int) */ + public static void addPollution(Chunk ch, int aPollution) { + addPollution(ch.worldObj, ch.xPosition, ch.zPosition, aPollution); + } + + /** + * Add some pollution to given chunk. Can pass in negative to remove pollution. Will clamp the final pollution + * number to 0 if it would be changed into negative. + * + * @param w world to modify. do nothing if it's a client world + * @param chunkX chunk coordinate X, i.e. blockX >> 4 + * @param chunkZ chunk coordinate Z, i.e. blockZ >> 4 + * @param aPollution desired delta. Positive means the pollution in chunk would go higher. + */ + public static void addPollution(World w, int chunkX, int chunkZ, int aPollution) { + if (!GTMod.gregtechproxy.mPollution || aPollution == 0 || w.isRemote) return; + mutatePollution(w, chunkX, chunkZ, d -> d.changeAmount(aPollution), null); + } + + private static void mutatePollution(World world, int x, int z, Consumer<ChunkData> mutator, + @Nullable Set<ChunkCoordIntPair> chunks) { + ChunkData data = STORAGE.get(world, x, z); + boolean hadPollution = data.getAmount() > 0; + mutator.accept(data); + boolean hasPollution = data.getAmount() > 0; + if (hasPollution != hadPollution) { + if (chunks == null) chunks = getPollutionManager(world).pollutedChunks; + if (hasPollution) chunks.add(new ChunkCoordIntPair(x, z)); + else chunks.remove(new ChunkCoordIntPair(x, z)); + } + } + + /** @see #getPollution(World, int, int) */ + public static int getPollution(IGregTechTileEntity te) { + return getPollution(te.getWorld(), te.getXCoord() >> 4, te.getZCoord() >> 4); + } + + /** @see #getPollution(World, int, int) */ + public static int getPollution(Chunk ch) { + return getPollution(ch.worldObj, ch.xPosition, ch.zPosition); + } + + /** + * Get the pollution in specified chunk + * + * @param w world to look in. can be a client world, but that limits the knowledge to what server side send us + * @param chunkX chunk coordinate X, i.e. blockX >> 4 + * @param chunkZ chunk coordinate Z, i.e. blockZ >> 4 + * @return pollution amount. may be 0 if pollution is disabled, or if it's a client world and server did not send us + * info about this chunk + */ + public static int getPollution(World w, int chunkX, int chunkZ) { + if (!GTMod.gregtechproxy.mPollution) return 0; + if (w.isRemote) + // it really should be querying the client side stuff instead + return PollutionRenderer.getKnownPollution(chunkX << 4, chunkZ << 4); + return STORAGE.get(w, chunkX, chunkZ) + .getAmount(); + } + + @Deprecated + public static int getPollution(ChunkCoordIntPair aCh, int aDim) { + return getPollution(DimensionManager.getWorld(aDim), aCh.chunkXPos, aCh.chunkZPos); + } + + public static boolean hasPollution(Chunk ch) { + if (!GTMod.gregtechproxy.mPollution) return false; + return STORAGE.isCreated(ch.worldObj, ch.getChunkCoordIntPair()) && STORAGE.get(ch) + .getAmount() > 0; + } + + // Add compatibility with old code + @Deprecated /* Don't use it... too weird way of passing position */ + public static void addPollution(World aWorld, ChunkPosition aPos, int aPollution) { + // The abuse of ChunkPosition to store block position and dim... + // is just bad especially when that is both used to store ChunkPos and BlockPos depending on context + addPollution(aWorld.getChunkFromBlockCoords(aPos.chunkPosX, aPos.chunkPosZ), aPollution); + } + + public static void migrate(ChunkDataEvent.Load e) { + addPollution( + e.getChunk(), + e.getData() + .getInteger("GTPOLLUTION")); + } + + public static class GT_PollutionEventHandler { + + @SubscribeEvent + public void chunkWatch(ChunkWatchEvent.Watch event) { + if (!GTMod.gregtechproxy.mPollution) return; + World world = event.player.worldObj; + if (STORAGE.isCreated(world, event.chunk)) { + int pollution = STORAGE.get(world, event.chunk) + .getAmount(); + if (pollution > POLLUTIONPACKET_MINVALUE) + GTValues.NW.sendToPlayer(new GTPacketPollution(event.chunk, pollution), event.player); + } + } + + @SubscribeEvent + public void onWorldLoad(WorldEvent.Load e) { + // super class loads everything lazily. We force it to load them all. + if (!e.world.isRemote) STORAGE.loadAll(e.world); + } + } + + @ParametersAreNonnullByDefault + private static final class Storage extends GTChunkAsso |
