From 901cb0d294b0c4f114bb247fbd7d6f97e7484f3c Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:21:33 +0200 Subject: Import pollution mixins from hodgepodge (#3395) Co-authored-by: Martin Robertz Co-authored-by: boubou19 --- src/main/java/gregtech/common/GTClient.java | 4 +- src/main/java/gregtech/common/GTProxy.java | 1 + src/main/java/gregtech/common/Pollution.java | 507 -------------------- src/main/java/gregtech/common/config/Gregtech.java | 127 ----- .../common/entities/EntityFXPollution.java | 59 --- .../gregtech/common/misc/GTClientPollutionMap.java | 140 ------ src/main/java/gregtech/common/misc/GTCommand.java | 2 +- .../gregtech/common/pollution/BlockMatcher.java | 96 ++++ .../common/pollution/ColorOverrideType.java | 28 ++ .../common/pollution/EntityFXPollution.java | 59 +++ .../common/pollution/GTClientPollutionMap.java | 140 ++++++ .../java/gregtech/common/pollution/Pollution.java | 533 +++++++++++++++++++++ .../gregtech/common/pollution/PollutionConfig.java | 397 +++++++++++++++ .../common/pollution/PollutionRenderer.java | 249 ++++++++++ .../common/pollution/PollutionTooltip.java | 108 +++++ .../gregtech/common/render/PollutionRenderer.java | 251 ---------- .../common/tileentities/boilers/MTEBoiler.java | 2 +- .../tileentities/boilers/MTEBoilerBronze.java | 2 +- .../machines/multi/MTECharcoalPit.java | 2 +- .../machines/multi/MTEPrimitiveBlastFurnace.java | 2 +- 20 files changed, 1619 insertions(+), 1090 deletions(-) delete mode 100644 src/main/java/gregtech/common/Pollution.java delete mode 100644 src/main/java/gregtech/common/entities/EntityFXPollution.java delete mode 100644 src/main/java/gregtech/common/misc/GTClientPollutionMap.java create mode 100644 src/main/java/gregtech/common/pollution/BlockMatcher.java create mode 100644 src/main/java/gregtech/common/pollution/ColorOverrideType.java create mode 100644 src/main/java/gregtech/common/pollution/EntityFXPollution.java create mode 100644 src/main/java/gregtech/common/pollution/GTClientPollutionMap.java create mode 100644 src/main/java/gregtech/common/pollution/Pollution.java create mode 100644 src/main/java/gregtech/common/pollution/PollutionConfig.java create mode 100644 src/main/java/gregtech/common/pollution/PollutionRenderer.java create mode 100644 src/main/java/gregtech/common/pollution/PollutionTooltip.java delete mode 100644 src/main/java/gregtech/common/render/PollutionRenderer.java (limited to 'src/main/java/gregtech/common') diff --git a/src/main/java/gregtech/common/GTClient.java b/src/main/java/gregtech/common/GTClient.java index 844731e82f..7cd673c001 100644 --- a/src/main/java/gregtech/common/GTClient.java +++ b/src/main/java/gregtech/common/GTClient.java @@ -92,6 +92,8 @@ import gregtech.client.GTMouseEventHandler; import gregtech.client.SeekingOggCodec; import gregtech.common.blocks.BlockFrameBox; import gregtech.common.blocks.ItemMachines; +import gregtech.common.pollution.Pollution; +import gregtech.common.pollution.PollutionRenderer; import gregtech.common.render.BlackholeRenderer; import gregtech.common.render.DroneRender; import gregtech.common.render.FlaskRenderer; @@ -101,7 +103,6 @@ import gregtech.common.render.GTRendererBlock; import gregtech.common.render.LaserRenderer; import gregtech.common.render.MetaGeneratedToolRenderer; import gregtech.common.render.MultiTileRenderer; -import gregtech.common.render.PollutionRenderer; import gregtech.common.render.WormholeRenderer; import gregtech.common.render.items.DataStickRenderer; import gregtech.common.render.items.InfiniteSprayCanRenderer; @@ -670,6 +671,7 @@ public class GTClient extends GTProxy implements Runnable { .forEach(CoverBehaviorBase::reloadColorOverride); } }); + Pollution.onPostInitClient(); } @Override diff --git a/src/main/java/gregtech/common/GTProxy.java b/src/main/java/gregtech/common/GTProxy.java index 643811234d..e7cb627c91 100644 --- a/src/main/java/gregtech/common/GTProxy.java +++ b/src/main/java/gregtech/common/GTProxy.java @@ -167,6 +167,7 @@ import gregtech.common.items.MetaGeneratedTool01; import gregtech.common.misc.GlobalEnergyWorldSavedData; import gregtech.common.misc.GlobalMetricsCoverDatabase; import gregtech.common.misc.spaceprojects.SpaceProjectWorldSavedData; +import gregtech.common.pollution.Pollution; import gregtech.common.tileentities.machines.multi.drone.MTEDroneCentre; import gregtech.nei.GTNEIDefaultHandler; diff --git a/src/main/java/gregtech/common/Pollution.java b/src/main/java/gregtech/common/Pollution.java deleted file mode 100644 index 4245a0ef12..0000000000 --- a/src/main/java/gregtech/common/Pollution.java +++ /dev/null @@ -1,507 +0,0 @@ -package gregtech.common; - -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; -import gregtech.common.render.PollutionRenderer; - -public class Pollution { - - private static final Storage STORAGE = new Storage(); - /** - * Pollution dispersion until effects start: Calculation: ((Limit * 0.01) + 2000) * (4 <- spreading rate) - *

- * 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 - *

- * 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) - *

- * Large Diesel Engine(320) Electric Blast Furnace(100) Implosion Compressor(2000) Large Boiler(240) Large Gas - * Turbine(160) Multi Smelter(100) Pyrolyse Oven(400) - *

- * Machine Explosion(100,000) - *

- * Other Random Shit: lots and lots - *

- * 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 pollutionList = new ArrayList<>(); // chunks left to process in this cycle - - private final Set 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)); - } - - 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 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 mutator, - @Nullable Set 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); - } - - 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 GTChunkAssociatedData { - - private Storage() { - super("Pollution", ChunkData.class, 64, (byte) 0, false); - } - - @Override - protected void writeElement(DataOutput output, ChunkData element, World world, int chunkX, int chunkZ) - throws IOException { - output.writeInt(element.getAmount()); - } - - @Override - protected ChunkData readElement(DataInput input, int version, World world, int chunkX, int chunkZ) - throws IOException { - if (version != 0) throw new IOException("Region file corrupted"); - ChunkData data = new ChunkData(input.readInt()); - if (data.getAmount() > 0) - getPollutionManager(world).pollutedChunks.add(new ChunkCoordIntPair(chunkX, chunkZ)); - return data; - } - - @Override - protected ChunkData createElement(World world, int chunkX, int chunkZ) { - return new ChunkData(); - } - - @Override - public void loadAll(World w) { - super.loadAll(w); - } - - public boolean isCreated(World world, ChunkCoordIntPair coord) { - return isCreated(world.provider.dimensionId, coord.chunkXPos, coord.chunkZPos); - } - } - - private static final class ChunkData implements GTChunkAssociatedData.IData { - - public int amount; - - private ChunkData() { - this(0); - } - - private ChunkData(int amount) { - this.amount = Math.max(0, amount); - } - - /** - * Current pollution amount. - */ - public int getAmount() { - return amount; - } - - public void setAmount(int amount) { - this.amount = Math.max(amount, 0); - } - - public void changeAmount(int delta) { - this.amount = Math.max(GTUtility.safeInt(amount + (long) delta, 0), 0); - } - - @Override - public boolean isSameAsDefault() { - return amount == 0; - } - } -} diff --git a/src/main/java/gregtech/common/config/Gregtech.java b/src/main/java/gregtech/common/config/Gregtech.java index a293b6cba7..e852a6b022 100644 --- a/src/main/java/gregtech/common/config/Gregtech.java +++ b/src/main/java/gregtech/common/config/Gregtech.java @@ -27,9 +27,6 @@ public class Gregtech { @Config.Comment("Ore drop behavior section") public static final OreDropBehavior oreDropBehavior = new OreDropBehavior(); - @Config.Comment("Pollution section") - public static final Pollution pollution = new Pollution(); - @Config.LangKey("GT5U.gui.config.gregtech.debug") public static class Debug { @@ -558,128 +555,4 @@ public class Gregtech { @Config.RequiresMcRestart public GTProxy.OreDropSystem setting = GTProxy.OreDropSystem.FortuneItem; } - - @Config.LangKey("GT5U.gui.config.gregtech.pollution") - public static class Pollution { - - @Config.Comment("if true, enables pollution in the game.") - @Config.DefaultBoolean(true) - @Config.RequiresMcRestart - public boolean pollution; - - @Config.Comment("Controls the threshold starting from which you can see fog.") - @Config.DefaultInt(550_000) - @Config.RequiresMcRestart - public int pollutionSmogLimit; - @Config.Comment("Controls the threshold starting from which players get poison effect.") - @Config.DefaultInt(750_000) - @Config.RequiresMcRestart - public int pollutionPoisonLimit; - @Config.Comment("Controls the threshold starting from which vegetation starts to be killed.") - @Config.DefaultInt(1_000_000) - @Config.RequiresMcRestart - public int pollutionVegetationLimit; - @Config.Comment("Controls the threshold starting from which if it rains, will turn cobblestone into gravel and gravel into sand.") - @Config.DefaultInt(2_000_000) - @Config.RequiresMcRestart - public int pollutionSourRainLimit; - @Config.Comment("Controls the pollution released by an explosion.") - @Config.DefaultInt(100_000) - @Config.RequiresMcRestart - public int pollutionOnExplosion; - @Config.Comment("Controls the pollution released per second by the bricked blast furnace.") - @Config.DefaultInt(200) - @Config.RequiresMcRestart - public int pollutionPrimitveBlastFurnacePerSecond; - @Config.Comment("Controls the pollution released per second by the charcoal pile igniter.") - @Config.DefaultInt(100) - @Config.RequiresMcRestart - public int pollutionCharcoalPitPerSecond; - @Config.Comment("Controls the pollution released per second by the EBF.") - @Config.DefaultInt(400) - @Config.RequiresMcRestart - public int pollutionEBFPerSecond; - @Config.Comment("Controls the pollution released per second by the large combustion engine.") - @Config.DefaultInt(480) - @Config.RequiresMcRestart - public int pollutionLargeCombustionEnginePerSecond; - @Config.Comment("Controls the pollution released per second by the extreme combustion engine.") - @Config.DefaultInt(3_840) - @Config.RequiresMcRestart - public int pollutionExtremeCombustionEnginePerSecond; - @Config.Comment("Controls the pollution released per second by the implosion compressor.") - @Config.DefaultInt(10_000) - @Config.RequiresMcRestart - public int pollutionImplosionCompressorPerSecond; - @Config.Comment("Controls the pollution released per second by the large bronze boiler.") - @Config.DefaultInt(1_000) - @Config.RequiresMcRestart - public int pollutionLargeBronzeBoilerPerSecond; - @Config.Comment("Controls the pollution released per second by the large steel boiler.") - @Config.DefaultInt(2_000) - @Config.RequiresMcRestart - public int pollutionLargeSteelBoilerPerSecond; - @Config.Comment("Controls the pollution released per second by the large titanium boiler.") - @Config.DefaultInt(3_000) - @Config.RequiresMcRestart - public int pollutionLargeTitaniumBoilerPerSecond; - @Config.Comment("Controls the pollution released per second by the large tungstensteel boiler.") - @Config.DefaultInt(4_000) - @Config.RequiresMcRestart - public int pollutionLargeTungstenSteelBoilerPerSecond; - @Config.Comment("Controls the pollution reduction obtained with each increment of the circuit when throttling large boilers.") - @Config.DefaultFloat(1.0f / 24.0f) // divided by 24 because there are 24 circuit configs. - @Config.RequiresMcRestart - public float pollutionReleasedByThrottle; - @Config.Comment("Controls the pollution released per second by the large gas turbine.") - @Config.DefaultInt(300) - @Config.RequiresMcRestart - public int pollutionLargeGasTurbinePerSecond; - @Config.Comment("Controls the pollution released per second by the multi smelter.") - @Config.DefaultInt(400) - @Config.RequiresMcRestart - public int pollutionMultiSmelterPerSecond; - @Config.Comment("Controls the pollution released per second by the pyrolyse oven.") - @Config.DefaultInt(300) - @Config.RequiresMcRestart - public int pollutionPyrolyseOvenPerSecond; - @Config.Comment("Controls the pollution released per second by the small coil boiler.") - @Config.DefaultInt(20) - @Config.RequiresMcRestart - public int pollutionSmallCoalBoilerPerSecond; - @Config.Comment("Controls the pollution released per second by the high pressure lava boiler.") - @Config.DefaultInt(20) - @Config.RequiresMcRestart - public int pollutionHighPressureLavaBoilerPerSecond; - @Config.Comment("Controls the pollution released per second by the high pressure coil boiler.") - @Config.DefaultInt(30) - @Config.RequiresMcRestart - public int pollutionHighPressureCoalBoilerPerSecond; - - @Config.Comment("Controls the pollution released per second by the base diesel generator.") - @Config.DefaultInt(40) - @Config.RequiresMcRestart - public int pollutionBaseDieselGeneratorPerSecond; - - // reading double as strings, not perfect, but better than nothing - @Config.Comment({ - "Pollution released by tier, with the following formula: PollutionBaseDieselGeneratorPerSecond * PollutionDieselGeneratorReleasedByTier[Tier]", - "The first entry has meaning as it is here to since machine tier with array index: LV is 1, etc." }) - @Config.DefaultDoubleList({ 0.1, 1.0, 0.9, 0.8 }) - @Config.RequiresMcRestart - public double[] pollutionDieselGeneratorReleasedByTier; - - @Config.Comment("Controls the pollution released per second by the base gas turbine.") - @Config.DefaultInt(40) - @Config.RequiresMcRestart - public int pollutionBaseGasTurbinePerSecond; - - // reading double as strings, not perfect, but better than nothing - @Config.Comment({ - "Pollution released by tier, with the following formula: PollutionBaseGasTurbinePerSecond * PollutionGasTurbineReleasedByTier[Tier]", - "The first entry has meaning as it is here to since machine tier with array index: LV is 1, etc." }) - @Config.DefaultDoubleList({ 0.1, 1.0, 0.9, 0.8, 0.7, 0.6 }) - @Config.RequiresMcRestart - public double[] pollutionGasTurbineReleasedByTier; - } } diff --git a/src/main/java/gregtech/common/entities/EntityFXPollution.java b/src/main/java/gregtech/common/entities/EntityFXPollution.java deleted file mode 100644 index facd3d3364..0000000000 --- a/src/main/java/gregtech/common/entities/EntityFXPollution.java +++ /dev/null @@ -1,59 +0,0 @@ -package gregtech.common.entities; - -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/misc/GTClientPollutionMap.java b/src/main/java/gregtech/common/misc/GTClientPollutionMap.java deleted file mode 100644 index 546f8e8d12..0000000000 --- a/src/main/java/gregtech/common/misc/GTClientPollutionMap.java +++ /dev/null @@ -1,140 +0,0 @@ -package gregtech.common.misc; - -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/misc/GTCommand.java b/src/main/java/gregtech/common/misc/GTCommand.java index f1590ec792..e6fbe12144 100644 --- a/src/main/java/gregtech/common/misc/GTCommand.java +++ b/src/main/java/gregtech/common/misc/GTCommand.java @@ -25,8 +25,8 @@ import gregtech.api.enums.GTValues; import gregtech.api.objects.GTChunkManager; import gregtech.api.util.GTMusicSystem; import gregtech.api.util.GTUtility; -import gregtech.common.Pollution; import gregtech.common.misc.spaceprojects.SpaceProjectManager; +import gregtech.common.pollution.Pollution; public final class GTCommand extends CommandBase { 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, ColorOverrideType> whiteList = Maps.newHashMap(); + public Set> blackList = Sets.newHashSet(); + public Map 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 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) + *

+ * 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 + *

+ * 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) + *

+ * Large Diesel Engine(320) Electric Blast Furnace(100) Implosion Compressor(2000) Large Boiler(240) Large Gas + * Turbine(160) Multi Smelter(100) Pyrolyse Oven(400) + *

+ * Machine Explosion(100,000) + *

+ * Other Random Shit: lots and lots + *

+ * 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 pollutionList = new ArrayList<>(); // chunks left to process in this cycle + + private final Set 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 tEntitys = world.getEntitiesWithinAABB(EntityLivingBase.class, chunk); + for (EntityLivingBase tEnt : tEntitys) { + if (tEnt instanceof EntityPlayerMP && ((EntityPlayerMP) tEnt).