package mcjty.deepresonance.worldgen;
import elec332.core.world.WorldHelper;
import mcjty.deepresonance.blocks.ModBlocks;
import mcjty.deepresonance.blocks.crystals.ResonatingCrystalTileEntity;
import mcjty.lib.varia.Logging;
import net.minecraft.block.Block;
import net.minecraft.block.state.pattern.BlockMatcher;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkGenerator;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.feature.WorldGenMinable;
import net.minecraftforge.event.world.ChunkDataEvent;
import net.minecraftforge.fml.common.IWorldGenerator;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayDeque;
import java.util.Random;
public class DeepWorldGenerator implements IWorldGenerator {
public static final String RETRO_NAME = "DeepResGen";
public static DeepWorldGenerator instance = new DeepWorldGenerator();
@Override
public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {
generateWorld(random, chunkX, chunkZ, world, true);
}
public void generateWorld(Random random, int chunkX, int chunkZ, World world, boolean newGen) {
if (!newGen && !WorldGenConfiguration.retrogen) {
return;
}
addOreSpawn(ModBlocks.resonatingOreBlock, (byte) 0, Blocks.STONE, world, random, chunkX * 16, chunkZ * 16,
WorldGenConfiguration.minVeinSize, WorldGenConfiguration.maxVeinSize, WorldGenConfiguration.chancesToSpawn, WorldGenConfiguration.minY, WorldGenConfiguration.maxY);
if (WorldGenConfiguration.crystalSpawnChance > 0 && random.nextInt(WorldGenConfiguration.crystalSpawnChance) == 0) {
attemptSpawnCrystal(random, chunkX, chunkZ, world);
}
if (!newGen) {
world.getChunkFromChunkCoords(chunkX, chunkZ).setChunkModified();
}
}
private void attemptSpawnCrystal(Random random, int chunkX, int chunkZ, World world) {
for (int i = 0 ; i < WorldGenConfiguration.crystalSpawnTries ; i++) {
int x = chunkX * 16 + random.nextInt(16);
int z = chunkZ * 16 + random.nextInt(16);
int y = world.getTopSolidOrLiquidBlock(new BlockPos(x, world.provider.getActualHeight(), z)).getY()-1;
boolean air = false;
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(x, y, z);
while (y > 1 && !air) {
if (world.isAirBlock(pos)) {
air = true;
}
y--;
pos.set(x, y, z);
}
if (air) {
while (y > 1 && air) {
if (!world.isAirBlock(pos)) {
air = false;
} else {
y--;
pos.set(x, y, z);
}
}
if (!air) {
if (WorldHelper.getBlockAt(world, pos) == Blocks.STONE) {
if (WorldGenConfiguration.verboseSpawn) {
Logging.log("Spawned a crystal at: " + x + "," + y + "," + z);
}
ResonatingCrystalTileEntity.spawnRandomCrystal(world, random, new BlockPos(pos.set(x, y+1, z)), 0);
return;
}
}
}
}
}
public void addOreSpawn(Block block, byte blockMeta, Block targetBlock, World world, Random random, int blockXPos, int blockZPos, int minVeinSize, int maxVeinSize, int chancesToSpawn, int minY, int maxY) {
WorldGenMinable minable = new WorldGenMinable(block.getStateFromMeta(blockMeta), (minVeinSize - random.nextInt(maxVeinSize - minVeinSize)), BlockMatcher.forBlock(targetBlock));
for (int i = 0 ; i < chancesToSpawn ; i++) {
int posX = blockXPos + random.nextInt(16);
int posY = minY + random.nextInt(maxY - minY);
int posZ = blockZPos + random.nextInt(16);
minable.generate(world, random, new BlockPos(posX, posY, posZ));
}
}
@SubscribeEvent
public void handleChunkSaveEvent(ChunkDataEvent.Save event) {
NBTTagCompound genTag = event.getData().getCompoundTag(RETRO_NAME);
if (!genTag.hasKey("generated")) {
// If we did not have this key then this is a new chunk and we will have proper ores generated.
// Otherwise we are saving a chunk for which ores are not yet generated.
genTag.setBoolean("generated", true);
}
event.getData().setTag(RETRO_NAME, genTag);
}
@SubscribeEvent
public void handleChunkLoadEvent(ChunkDataEvent.Load event) {
int dim = WorldHelper.getDimID(event.getWorld());
boolean regen = false;
NBTTagCompound tag = (NBTTagCompound) event.getData().getTag(RETRO_NAME);
NBTTagList list = null;
Pair<Integer,Integer> cCoord = Pair.of(event.getChunk().xPosition, event.getChunk().zPosition);
if (tag != null) {
boolean generated = WorldGenConfiguration.retrogen && !tag.hasKey("generated");
if (generated) {
if (WorldGenConfiguration.verboseSpawn) {
Logging.log("Queuing Retrogen for chunk: " + cCoord.toString() + ".");
}
regen = true;
}
} else {
regen = WorldGenConfiguration.retrogen;
}
if (regen) {
ArrayDeque<WorldTickHandler.RetroChunkCoord> chunks = WorldTickHandler.chunksToGen.get(dim);
if (chunks == null) {
WorldTickHandler.chunksToGen.put(dim, new ArrayDeque<WorldTickHandler.RetroChunkCoord>(128));
chunks = WorldTickHandler.chunksToGen.get(dim);
}
if (chunks != null) {
chunks.addLast(new WorldTickHandler.RetroChunkCoord(cCoord, list));
WorldTickHandler.chunksToGen.put(dim, chunks);
}
}
}
}