package mcjty.deepresonance.radiation; import com.google.common.collect.Sets; import elec332.core.util.RegistryHelper; import elec332.core.world.WorldHelper; import mcjty.deepresonance.blocks.ModBlocks; import mcjty.deepresonance.items.armor.ItemRadiationSuit; import mcjty.deepresonance.varia.QuadTree; import mcjty.lib.varia.GlobalCoordinate; import mcjty.lib.varia.Logging; import net.minecraft.block.Block; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.registry.IRegistry; import net.minecraft.world.World; import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.IPlantable; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.registry.FMLControlledNamespacedRegistry; import net.minecraftforge.fml.common.registry.ForgeRegistries; import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.fml.common.registry.IForgeRegistry; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; public class RadiationTickEvent { public static final int MAXTICKS = 10; private int counter = MAXTICKS; private static Random random = new Random(); private static final int EFFECTS_MAX = 18; private int counterEffects = EFFECTS_MAX; public static Potion harm; public static Potion hunger; public static Potion moveSlowdown; public static Potion weakness; public static Potion poison; public static Potion wither; @SubscribeEvent public void onTick(TickEvent.WorldTickEvent evt) { if (evt.phase == TickEvent.Phase.START) { return; } if (evt.world.provider.getDimension() != 0) { return; } counter--; if (counter <= 0) { counter = MAXTICKS; counterEffects--; boolean doEffects = false; if (counterEffects <= 0) { counterEffects = EFFECTS_MAX; doEffects = true; } serverTick(evt.world, doEffects); } } // @SubscribeEvent // public void onServerTick(TickEvent.ServerTickEvent evt) { // if (evt.phase == TickEvent.Phase.START) { // return; // } // counter--; // if (counter <= 0) { // counter = MAXTICKS; // // counterEffects--; // boolean doEffects = false; // if (counterEffects <= 0) { // counterEffects = EFFECTS_MAX; // doEffects = true; // } // serverTick(doEffects); // } // } private void serverTick(World entityWorld, boolean doEffects) { // // @todo improve // MinecraftServer server = FMLServerHandler.instance().getServer(); // if (server == null) { // return; // } // World entityWorld = server.getEntityWorld(); DRRadiationManager radiationManager = DRRadiationManager.getManager(entityWorld); Set<GlobalCoordinate> toRemove = Sets.newHashSet(); boolean dirty = false; for (Map.Entry<GlobalCoordinate, DRRadiationManager.RadiationSource> source : radiationManager.getRadiationSources().entrySet()) { GlobalCoordinate coordinate = source.getKey(); World world = DimensionManager.getWorld(coordinate.getDimension()); if (world != null) { if (WorldHelper.chunkLoaded(world, coordinate.getCoordinate())) { // The world is loaded and the chunk containing the radiation source is also loaded. DRRadiationManager.RadiationSource radiationSource = source.getValue(); float strength = radiationSource.getStrength(); strength -= RadiationConfiguration.strengthDecreasePerTick * MAXTICKS; dirty = true; if (strength <= 0) { toRemove.add(coordinate); } else { radiationSource.setStrength(strength); if (doEffects) { handleRadiationEffects(world, coordinate, radiationSource); } if (strength > RadiationConfiguration.radiationDestructionEventLevel && random.nextFloat() < RadiationConfiguration.destructionEventChance) { handleDestructionEvent(world, coordinate, radiationSource); } } } } } if (dirty) { for (GlobalCoordinate coordinate : toRemove) { radiationManager.deleteRadiationSource(coordinate); Logging.logDebug("Removed radiation source at: " + coordinate.getCoordinate().toString() + " (" + coordinate.getDimension() + ")"); } radiationManager.save(entityWorld); } } private void handleDestructionEvent(World world, GlobalCoordinate coordinate, DRRadiationManager.RadiationSource radiationSource) { int cx = coordinate.getCoordinate().getX(); int cy = coordinate.getCoordinate().getY(); int cz = coordinate.getCoordinate().getZ(); double centerx = cx; double centery = cy; double centerz = cz; double radius = radiationSource.getRadius(); double theta = random.nextDouble() * Math.PI * 2.0; double phi = random.nextDouble() * Math.PI - Math.PI / 2.0; double dist = random.nextDouble() * radius; double cosphi = Math.cos(phi); double destx = centerx + dist * Math.cos(theta) * cosphi; double destz = centerz + dist * Math.sin(theta) * cosphi; double desty; if (random.nextFloat() > 0.5f) { desty = world.getTopSolidOrLiquidBlock(new BlockPos((int) destx, world.getActualHeight(),(int) destz)).getY(); } else { desty = centery + dist * Math.sin(phi); } Logging.logDebug("Destruction event at: " + destx + "," + desty + "," + destz); float baseStrength = radiationSource.getStrength(); double distanceSq = (centerx-destx) * (centerx-destx) + (centery-desty) * (centery-desty) + (centerz-destz) * (centerz-destz); double distance = Math.sqrt(distanceSq); float strength = (float) (baseStrength * (radius-distance) / radius); QuadTree radiationTree = radiationSource.getRadiationTree(world, cx, cy, cz); strength = strength * (float) radiationTree.factor(cx, cy, cz, (int) destx, (int) desty, (int) destz); int eventradius = 8; int damage; float poisonBlockChance; float removeLeafChance; float setOnFireChance; if (strength > RadiationConfiguration.radiationDestructionEventLevel/2) { // Worst destruction event damage = 30; poisonBlockChance = 0.9f; removeLeafChance = 9.0f; setOnFireChance = 0.03f; } else if (strength > RadiationConfiguration.radiationDestructionEventLevel/3) { // Moderate damage = 5; poisonBlockChance = 0.6f; removeLeafChance = 4.0f; setOnFireChance = 0.001f; } else if (strength > RadiationConfiguration.radiationDestructionEventLevel/4) { // Minor damage = 1; poisonBlockChance = 0.3f; removeLeafChance = 1.2f; setOnFireChance = 0.0f; } else { return; } List<EntityLivingBase> list = world.getEntitiesWithinAABB(EntityLivingBase.class, new AxisAlignedBB(destx - eventradius, desty - eventradius, destz - eventradius, destx + eventradius, desty + eventradius, destz + eventradius), null); for (EntityLivingBase entityLivingBase : list) { getPotions(); entityLivingBase.addPotionEffect(new PotionEffect(harm, 10, damage)); } BlockPos.MutableBlockPos currentPos = new BlockPos.MutableBlockPos(); for (int x = (int) (destx-eventradius); x <= destx+eventradius ; x++) { for (int y = (int) (desty-eventradius); y <= desty+eventradius ; y++) { for (int z = (int) (destz-eventradius); z <= destz+eventradius ; z++) { double dSq = (x-destx) * (x-destx) + (y-desty) * (y-desty) + (z-destz) * (z-destz); double d = Math.sqrt(dSq); double str = (eventradius-d) / eventradius; currentPos = currentPos.set(x, y, z); Block block = WorldHelper.getBlockAt(world, currentPos); if (block == Blocks.DIRT || block == Blocks.FARMLAND || block == Blocks.GRASS) { if (random.nextFloat() < poisonBlockChance * str) { WorldHelper.setBlockState(world, currentPos, ModBlocks.poisonedDirtBlock.getDefaultState(), 2); } } else if (block.isLeaves(world.getBlockState(currentPos), world, currentPos) || block instanceof IPlantable) { if (random.nextFloat() < removeLeafChance * str) { world.setBlockToAir(currentPos); } } if (random.nextFloat() < setOnFireChance * str) { // @todo temporarily disabled fire because it causes 'TickNextTick list out of synch' for some reason // if ((!world.isAirBlock(currentPos))){ // currentPos.set(x, y+1, z); // if(world.isAirBlock(currentPos)) { // Logging.logDebug("Set fire at: " + x + "," + y + "," + z); // System.out.println("RadiationTickEvent.handleDestructionEvent: FIRE"); // System.out.flush(); // WorldHelper.setBlockState(world, currentPos, Blocks.fire.getDefaultState(), 2); // } // } } } } } } private static void getPotions() { IForgeRegistry<Potion> potionRegistry = ForgeRegistries.POTIONS; if (harm == null) { harm = potionRegistry.getValue(new ResourceLocation("instant_damage")); hunger = potionRegistry.getValue(new ResourceLocation("hunger")); moveSlowdown = potionRegistry.getValue(new ResourceLocation("slowness")); weakness = potionRegistry.getValue(new ResourceLocation("weakness")); poison = potionRegistry.getValue(new ResourceLocation("poison")); wither = potionRegistry.getValue(new ResourceLocation("wither")); } } private void handleRadiationEffects(World world, GlobalCoordinate coordinate, DRRadiationManager.RadiationSource radiationSource) { int cx = coordinate.getCoordinate().getX(); int cy = coordinate.getCoordinate().getY(); int cz = coordinate.getCoordinate().getZ(); double centerx = cx; double centery = cy; double centerz = cz; double radius = radiationSource.getRadius(); double radiusSq = radius * radius; float baseStrength = radiationSource.getStrength(); List<EntityLivingBase> list = world.getEntitiesWithinAABB(EntityLivingBase.class, new AxisAlignedBB(centerx - radius, centery - radius, centerz - radius, centerx + radius, centery + radius, centerz + radius), null); for (EntityLivingBase entityLivingBase : list) { float protection = ItemRadiationSuit.getRadiationProtection(entityLivingBase); double distanceSq = entityLivingBase.getDistanceSq(centerx, centery, centerz); if (distanceSq < radiusSq) { double distance = Math.sqrt(distanceSq); QuadTree radiationTree = radiationSource.getRadiationTree(world, cx, cy, cz); float strength = (float) (baseStrength * (radius-distance) / radius); strength = strength * (1.0f-protection); strength = strength * (float) radiationTree.factor2(cx, cy, cz, (int) entityLivingBase.posX, (int) entityLivingBase.posY+1, (int) entityLivingBase.posZ); getPotions(); if (strength < RadiationConfiguration.radiationEffectLevelNone) { } else if (strength < RadiationConfiguration.radiationEffectLevel0) { entityLivingBase.addPotionEffect(new PotionEffect(hunger, EFFECTS_MAX * MAXTICKS, 0, true, true)); } else if (strength < RadiationConfiguration.radiationEffectLevel1) { entityLivingBase.addPotionEffect(new PotionEffect(hunger, EFFECTS_MAX * MAXTICKS, 1, true, true)); } else if (strength < RadiationConfiguration.radiationEffectLevel2) { entityLivingBase.addPotionEffect(new PotionEffect(hunger, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(moveSlowdown, EFFECTS_MAX * MAXTICKS, 1, true, true)); } else if (strength < RadiationConfiguration.radiationEffectLevel3) { entityLivingBase.addPotionEffect(new PotionEffect(hunger, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(moveSlowdown, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(weakness, EFFECTS_MAX * MAXTICKS, 1, true, true)); } else if (strength < RadiationConfiguration.radiationEffectLevel4) { entityLivingBase.addPotionEffect(new PotionEffect(hunger, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(moveSlowdown, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(weakness, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(poison, EFFECTS_MAX * MAXTICKS, 1, true, true)); } else if (strength < RadiationConfiguration.radiationEffectLevel5) { entityLivingBase.addPotionEffect(new PotionEffect(hunger, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(moveSlowdown, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(weakness, EFFECTS_MAX * MAXTICKS, 3, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(poison, EFFECTS_MAX * MAXTICKS, 2, true, true)); } else { entityLivingBase.addPotionEffect(new PotionEffect(hunger, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(moveSlowdown, EFFECTS_MAX * MAXTICKS, 2, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(weakness, EFFECTS_MAX * MAXTICKS, 3, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(poison, EFFECTS_MAX * MAXTICKS, 3, true, true)); entityLivingBase.addPotionEffect(new PotionEffect(wither, EFFECTS_MAX * MAXTICKS, 2, true, true)); } } } } }