mirror of
https://github.com/HbmMods/Hbm-s-Nuclear-Tech-GIT.git
synced 2026-01-25 10:32:49 +00:00
382 lines
13 KiB
Java
382 lines
13 KiB
Java
package com.hbm.handler.pollution;
|
|
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.util.HashMap;
|
|
import java.util.Locale;
|
|
import java.util.Map.Entry;
|
|
import java.util.UUID;
|
|
|
|
import com.hbm.config.MobConfig;
|
|
import com.hbm.config.RadiationConfig;
|
|
|
|
import com.hbm.entity.mob.EntityGlyphidDigger;
|
|
import com.hbm.entity.mob.EntityGlyphidScout;
|
|
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
|
import cpw.mods.fml.common.gameevent.TickEvent;
|
|
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
|
|
import cpw.mods.fml.relauncher.Side;
|
|
import net.minecraft.entity.EntityLivingBase;
|
|
import net.minecraft.entity.EnumCreatureType;
|
|
import net.minecraft.entity.SharedMonsterAttributes;
|
|
import net.minecraft.entity.ai.attributes.AttributeModifier;
|
|
import net.minecraft.entity.monster.IMob;
|
|
import net.minecraft.nbt.CompressedStreamTools;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.nbt.NBTTagList;
|
|
import net.minecraft.util.MathHelper;
|
|
import net.minecraft.util.Vec3;
|
|
import net.minecraft.world.ChunkCoordIntPair;
|
|
import net.minecraft.world.World;
|
|
import net.minecraft.world.WorldServer;
|
|
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
|
|
import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent;
|
|
import net.minecraftforge.event.world.WorldEvent;
|
|
|
|
public class PollutionHandler {
|
|
|
|
public static final String fileName = "hbmpollution.dat";
|
|
public static HashMap<World, PollutionPerWorld> perWorld = new HashMap();
|
|
|
|
/** Baserate of soot generation for a furnace-equivalent machine per second */
|
|
public static final float SOOT_PER_SECOND = 1F / 25F;
|
|
/** Baserate of heavy metal generation, balanced around the soot values of combustion engines */
|
|
public static final float HEAVY_METAL_PER_SECOND = 1F / 50F;
|
|
public static Vec3 targetCoords;
|
|
|
|
///////////////////////
|
|
/// UTILITY METHODS ///
|
|
///////////////////////
|
|
public static void incrementPollution(World world, int x, int y, int z, PollutionType type, float amount) {
|
|
|
|
if(!RadiationConfig.enablePollution) return;
|
|
|
|
PollutionPerWorld ppw = perWorld.get(world);
|
|
if(ppw == null) return;
|
|
ChunkCoordIntPair pos = new ChunkCoordIntPair(x >> 6, z >> 6);
|
|
PollutionData data = ppw.pollution.get(pos);
|
|
if(data == null) {
|
|
data = new PollutionData();
|
|
ppw.pollution.put(pos, data);
|
|
}
|
|
data.pollution[type.ordinal()] = MathHelper.clamp_float((float) (data.pollution[type.ordinal()] + amount * MobConfig.pollutionMult), 0F, 10_000F);
|
|
}
|
|
|
|
public static void decrementPollution(World world, int x, int y, int z, PollutionType type, float amount) {
|
|
incrementPollution(world, x, y, z, type, -amount);
|
|
}
|
|
|
|
public static void setPollution(World world, int x, int y, int z, PollutionType type, float amount) {
|
|
|
|
if(!RadiationConfig.enablePollution) return;
|
|
|
|
PollutionPerWorld ppw = perWorld.get(world);
|
|
if(ppw == null) return;
|
|
ChunkCoordIntPair pos = new ChunkCoordIntPair(x >> 6, z >> 6);
|
|
PollutionData data = ppw.pollution.get(pos);
|
|
if(data == null) {
|
|
data = new PollutionData();
|
|
ppw.pollution.put(pos, data);
|
|
}
|
|
data.pollution[type.ordinal()] = amount;
|
|
}
|
|
|
|
public static float getPollution(World world, int x, int y, int z, PollutionType type) {
|
|
|
|
if(!RadiationConfig.enablePollution) return 0;
|
|
|
|
PollutionPerWorld ppw = perWorld.get(world);
|
|
if(ppw == null) return 0F;
|
|
ChunkCoordIntPair pos = new ChunkCoordIntPair(x >> 6, z >> 6);
|
|
PollutionData data = ppw.pollution.get(pos);
|
|
if(data == null) return 0F;
|
|
return data.pollution[type.ordinal()];
|
|
}
|
|
|
|
public static PollutionData getPollutionData(World world, int x, int y, int z) {
|
|
|
|
if(!RadiationConfig.enablePollution) return null;
|
|
|
|
PollutionPerWorld ppw = perWorld.get(world);
|
|
if(ppw == null) return null;
|
|
ChunkCoordIntPair pos = new ChunkCoordIntPair(x >> 6, z >> 6);
|
|
PollutionData data = ppw.pollution.get(pos);
|
|
return data;
|
|
}
|
|
|
|
//////////////////////
|
|
/// EVENT HANDLING ///
|
|
//////////////////////
|
|
@SubscribeEvent
|
|
public void onWorldLoad(WorldEvent.Load event) {
|
|
if(!event.world.isRemote && RadiationConfig.enablePollution) {
|
|
WorldServer world = (WorldServer) event.world;
|
|
String dirPath = getDataDir(world);
|
|
|
|
try {
|
|
File pollutionFile = new File(dirPath, fileName);
|
|
|
|
if(pollutionFile != null) {
|
|
|
|
if(pollutionFile.exists()) {
|
|
FileInputStream io = new FileInputStream(pollutionFile);
|
|
NBTTagCompound data = CompressedStreamTools.readCompressed(io);
|
|
io.close();
|
|
perWorld.put(event.world, new PollutionPerWorld(data));
|
|
} else {
|
|
perWorld.put(event.world, new PollutionPerWorld());
|
|
}
|
|
}
|
|
} catch(Exception ex) {
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public void onWorldUnload(WorldEvent.Unload event) {
|
|
if(!event.world.isRemote) perWorld.remove(event.world);
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public void onWorldSave(WorldEvent.Save event) {
|
|
if(!event.world.isRemote) {
|
|
WorldServer world = (WorldServer) event.world;
|
|
String dirPath = getDataDir(world);
|
|
File pollutionFile = new File(dirPath, fileName);
|
|
|
|
try {
|
|
if(!pollutionFile.getParentFile().exists()) pollutionFile.getParentFile().mkdirs();
|
|
if(!pollutionFile.exists()) pollutionFile.createNewFile();
|
|
PollutionPerWorld ppw = perWorld.get(world);
|
|
if(ppw != null) {
|
|
NBTTagCompound data = ppw.writeToNBT();
|
|
CompressedStreamTools.writeCompressed(data, new FileOutputStream(pollutionFile));
|
|
}
|
|
} catch(Exception ex) {
|
|
System.out.println("Failed to write " + pollutionFile.getAbsolutePath());
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
public String getDataDir(WorldServer world) {
|
|
String dir = world.getSaveHandler().getWorldDirectory().getAbsolutePath();
|
|
// Crucible and probably Thermos provide dimId by themselves
|
|
String dimId = File.separator + "DIM" + world.provider.dimensionId;
|
|
if(world.provider.dimensionId != 0 && !dir.endsWith(dimId)) {
|
|
dir += dimId;
|
|
}
|
|
dir += File.separator + "data";
|
|
return dir;
|
|
}
|
|
|
|
//////////////////////////
|
|
/// SYSTEM UPDATE LOOP ///
|
|
//////////////////////////
|
|
int eggTimer = 0;
|
|
@SubscribeEvent
|
|
public void updateSystem(TickEvent.ServerTickEvent event) {
|
|
|
|
if(event.side == Side.SERVER && event.phase == Phase.END) {
|
|
|
|
eggTimer++;
|
|
if(eggTimer < 60) return;
|
|
eggTimer = 0;
|
|
|
|
for(Entry<World, PollutionPerWorld> entry : perWorld.entrySet()) {
|
|
HashMap<ChunkCoordIntPair, PollutionData> newPollution = new HashMap();
|
|
|
|
for(Entry<ChunkCoordIntPair, PollutionData> chunk : entry.getValue().pollution.entrySet()) {
|
|
int x = chunk.getKey().chunkXPos;
|
|
int z = chunk.getKey().chunkZPos;
|
|
PollutionData data = chunk.getValue();
|
|
|
|
float[] pollutionForNeightbors = new float[PollutionType.values().length];
|
|
int S = PollutionType.SOOT.ordinal();
|
|
int H = PollutionType.HEAVYMETAL.ordinal();
|
|
int P = PollutionType.POISON.ordinal();
|
|
|
|
/* CALCULATION */
|
|
if(data.pollution[S] > 15) {
|
|
pollutionForNeightbors[S] = (float) (data.pollution[S] * 0.05F);
|
|
data.pollution[S] *= 0.8F;
|
|
} else {
|
|
data.pollution[S] *= 0.99F;
|
|
}
|
|
|
|
data.pollution[H] *= 0.9995F;
|
|
|
|
if(data.pollution[P] > 10) {
|
|
pollutionForNeightbors[P] = data.pollution[P] * 0.025F;
|
|
data.pollution[P] *= 0.9F;
|
|
} else {
|
|
data.pollution[P] *= 0.995F;
|
|
}
|
|
|
|
/* SPREADING */
|
|
//apply new data to self
|
|
PollutionData newData = newPollution.get(chunk.getKey());
|
|
if(newData == null) newData = new PollutionData();
|
|
|
|
boolean shouldPut = false;
|
|
for(int i = 0; i < newData.pollution.length; i++) {
|
|
newData.pollution[i] += data.pollution[i];
|
|
if(newData.pollution[i] > 0) shouldPut = true;
|
|
}
|
|
if(shouldPut) newPollution.put(chunk.getKey(), newData);
|
|
|
|
//apply neighbor data to neighboring chunks
|
|
int[][] offsets = new int[][] {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
|
|
for(int[] offset : offsets) {
|
|
ChunkCoordIntPair offPos = new ChunkCoordIntPair(x + offset[0], z + offset[1]);
|
|
PollutionData offsetData = newPollution.get(offPos);
|
|
if(offsetData == null) offsetData = new PollutionData();
|
|
|
|
shouldPut = false;
|
|
for(int i = 0; i < offsetData.pollution.length; i++) {
|
|
offsetData.pollution[i] += pollutionForNeightbors[i];
|
|
if(offsetData.pollution[i] > 0) shouldPut = true;
|
|
}
|
|
if(shouldPut) newPollution.put(offPos, offsetData);
|
|
}
|
|
}
|
|
|
|
entry.getValue().pollution.clear();
|
|
entry.getValue().pollution.putAll(newPollution);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////
|
|
/// DATA STRUCTURE ///
|
|
//////////////////////
|
|
public static class PollutionPerWorld {
|
|
public HashMap<ChunkCoordIntPair, PollutionData> pollution = new HashMap();
|
|
|
|
public PollutionPerWorld() { }
|
|
|
|
public PollutionPerWorld(NBTTagCompound data) {
|
|
|
|
NBTTagList list = data.getTagList("entries", 10);
|
|
|
|
for(int i = 0; i < list.tagCount(); i++) {
|
|
NBTTagCompound nbt = list.getCompoundTagAt(i);
|
|
int chunkX = nbt.getInteger("chunkX");
|
|
int chunkZ = nbt.getInteger("chunkZ");
|
|
pollution.put(new ChunkCoordIntPair(chunkX, chunkZ), PollutionData.fromNBT(nbt));
|
|
}
|
|
}
|
|
|
|
public NBTTagCompound writeToNBT() {
|
|
|
|
NBTTagCompound data = new NBTTagCompound();
|
|
|
|
NBTTagList list = new NBTTagList();
|
|
|
|
for(Entry<ChunkCoordIntPair, PollutionData> entry : pollution.entrySet()) {
|
|
NBTTagCompound nbt = new NBTTagCompound();
|
|
nbt.setInteger("chunkX", entry.getKey().chunkXPos);
|
|
nbt.setInteger("chunkZ", entry.getKey().chunkZPos);
|
|
entry.getValue().toNBT(nbt);
|
|
list.appendTag(nbt);
|
|
}
|
|
|
|
data.setTag("entries", list);
|
|
|
|
return data;
|
|
}
|
|
}
|
|
|
|
public static class PollutionData {
|
|
public float[] pollution = new float[PollutionType.values().length];
|
|
|
|
public static PollutionData fromNBT(NBTTagCompound nbt) {
|
|
PollutionData data = new PollutionData();
|
|
|
|
for(int i = 0; i < PollutionType.values().length; i++) {
|
|
data.pollution[i] = nbt.getFloat(PollutionType.values()[i].name().toLowerCase(Locale.US));
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
public void toNBT(NBTTagCompound nbt) {
|
|
for(int i = 0; i < PollutionType.values().length; i++) {
|
|
nbt.setFloat(PollutionType.values()[i].name().toLowerCase(Locale.US), pollution[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static enum PollutionType {
|
|
SOOT, POISON, HEAVYMETAL, FALLOUT;
|
|
}
|
|
|
|
///////////////////
|
|
/// MOB EFFECTS ///
|
|
///////////////////
|
|
|
|
public static final UUID maxHealth = UUID.fromString("25462f6c-2cb2-4ca8-9b47-3a011cc61207");
|
|
public static final UUID attackDamage = UUID.fromString("8f442d7c-d03f-49f6-a040-249ae742eed9");
|
|
|
|
@SubscribeEvent
|
|
public void decorateMob(LivingSpawnEvent event) {
|
|
|
|
if(!RadiationConfig.enablePollution) return;
|
|
|
|
World world = event.world;
|
|
if(world.isRemote) return;
|
|
EntityLivingBase living = event.entityLiving;
|
|
|
|
PollutionData data = getPollutionData(world, (int) Math.floor(event.x), (int) Math.floor(event.y), (int) Math.floor(event.z));
|
|
if(data == null) return;
|
|
|
|
if(living instanceof IMob) {
|
|
|
|
if(data.pollution[PollutionType.SOOT.ordinal()] > RadiationConfig.buffMobThreshold) {
|
|
if(living.getEntityAttribute(SharedMonsterAttributes.maxHealth) != null && living.getEntityAttribute(SharedMonsterAttributes.maxHealth).getModifier(maxHealth) == null) living.getEntityAttribute(SharedMonsterAttributes.maxHealth).applyModifier(new AttributeModifier(maxHealth, "Soot Anger Health Increase", 1D, 1));
|
|
if(living.getEntityAttribute(SharedMonsterAttributes.attackDamage) != null && living.getEntityAttribute(SharedMonsterAttributes.attackDamage).getModifier(attackDamage) == null) living.getEntityAttribute(SharedMonsterAttributes.attackDamage).applyModifier(new AttributeModifier(attackDamage, "Soot Anger Damage Increase", 1.5D, 1));
|
|
living.heal(living.getMaxHealth());
|
|
}
|
|
}
|
|
}
|
|
///RAMPANT MODE STUFFS///
|
|
|
|
@SubscribeEvent
|
|
public void rampantTargetSetter(PlayerSleepInBedEvent event){
|
|
if (MobConfig.rampantGlyphidGuidance) targetCoords = Vec3.createVectorHelper(event.x, event.y, event.z);
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public void rampantScoutPopulator(WorldEvent.PotentialSpawns event){
|
|
//yell at me if this vertical formatting hurts your brain
|
|
if(MobConfig.rampantNaturalScoutSpawn
|
|
&& !event.world.isRemote
|
|
&& event.world.provider.dimensionId == 0
|
|
&& event.type == EnumCreatureType.monster
|
|
&& event.world.canBlockSeeTheSky(event.x, event.y, event.z)
|
|
&& !event.isCanceled()) {
|
|
|
|
if (event.world.rand.nextInt(MobConfig.rampantScoutSpawnChance) == 0) {
|
|
|
|
float soot = PollutionHandler.getPollution(event.world, event.x, event.y, event.z, PollutionType.SOOT);
|
|
|
|
if (soot >= MobConfig.rampantScoutSpawnThresh) {
|
|
EntityGlyphidScout scout = new EntityGlyphidScout(event.world);
|
|
if(scout.isValidLightLevel()) {
|
|
//escort for the scout, which can also deal with obstacles
|
|
EntityGlyphidDigger digger = new EntityGlyphidDigger(event.world);
|
|
scout.setLocationAndAngles(event.x, event.y, event.z, event.world.rand.nextFloat() * 360.0F, 0.0F);
|
|
digger.setLocationAndAngles(event.x, event.y, event.z, event.world.rand.nextFloat() * 360.0F, 0.0F);
|
|
event.world.spawnEntityInWorld(scout);
|
|
event.world.spawnEntityInWorld(digger);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|