package joshie.harvest.mining.gen; import gnu.trove.map.TIntObjectMap; import gnu.trove.map.TLongObjectMap; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.map.hash.TLongObjectHashMap; import gnu.trove.set.TIntSet; import gnu.trove.set.hash.TIntHashSet; import joshie.harvest.core.HFTrackers; import joshie.harvest.core.helpers.NBTHelper; import joshie.harvest.core.lib.LootStrings; import joshie.harvest.core.util.annotations.HFEvents; import joshie.harvest.mining.HFMining; import joshie.harvest.mining.MiningHelper; import joshie.harvest.npcs.HFNPCs; import joshie.harvest.npcs.NPCHelper; import joshie.harvest.npcs.entity.EntityNPC; import net.minecraft.block.BlockChest; import net.minecraft.block.BlockStandingSign; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.tileentity.TileEntitySign; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraft.world.WorldSavedData; import net.minecraft.world.WorldServer; import javax.annotation.Nonnull; import java.util.Random; import static joshie.harvest.core.helpers.EntityHelper.isSpawnable; import static joshie.harvest.mining.MiningHelper.MAX_FLOORS; import static joshie.harvest.mining.MiningHelper.getFloor; @HFEvents public class MineManager extends WorldSavedData { public static final int CHUNK_BOUNDARY = 10; private static final TLongObjectMap<TIntObjectMap<IBlockState[][]>> generation = new TLongObjectHashMap<>(); private static final TLongObjectMap<int[]> coordinates = new TLongObjectHashMap<>(); private TIntObjectMap<TIntObjectMap<BlockPos>> portalCoordinates = new TIntObjectHashMap<>(); private TIntSet generated = new TIntHashSet(); public MineManager(String string) { super(string); } @Override public void readFromNBT(@Nonnull NBTTagCompound tag) { portalCoordinates = NBTHelper.readPositionCollection(tag.getTagList("PortalCoordinates", 10)); if (tag.hasKey("GeneratedMiner")) { generated = new TIntHashSet(tag.getIntArray("GeneratedMiner")); } } @Override @Nonnull public NBTTagCompound writeToNBT(@Nonnull NBTTagCompound tag) { tag.setTag("PortalCoordinates", NBTHelper.writePositionCollection(portalCoordinates)); tag.setIntArray("GeneratedMiner", generated.toArray()); return tag; } public static BlockPos modifyNPCPosition(WorldServer dim, BlockPos spawn, Entity entity) { IBlockState actual = HFMining.PORTAL.getActualState(dim.getBlockState(spawn), dim, spawn); if (actual.getBlock() == HFMining.PORTAL) { Random rand = dim.rand; for (int i = 0; i < 512; i++) { BlockPos pos = spawn.add(rand.nextInt(51) - 25, 0, rand.nextInt(51) - 25); if (isSpawnable(dim, pos)) return pos; } } return MiningHelper.modifySpawnAndEntityRotation(dim, spawn, entity); } void onTeleportToMine(World world, int mineID) { if (!generated.contains(mineID)) { EntityNPC entity = NPCHelper.getEntityForNPC(world, HFNPCs.MINER); BlockPos pos = modifyNPCPosition((WorldServer)world, getSpawnCoordinateForMine(world, mineID, 1), entity); entity.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); entity.setHeldItem(EnumHand.MAIN_HAND, new ItemStack(Blocks.TORCH)); entity.setHeldItem(EnumHand.OFF_HAND, new ItemStack(Items.IRON_PICKAXE)); boolean foundTorch = false; boolean foundChest = false; boolean foundSign = false; for (int i = 0; i < 128; i++) { BlockPos torch = pos.add(world.rand.nextInt(7) - 3, 0, world.rand.nextInt(7)); if (torch.equals(pos)) continue; if (!foundTorch && isSpawnable(world, torch)) { world.setBlockState(torch, Blocks.TORCH.getDefaultState(), 3); foundTorch = true; } else if (!foundChest && isSpawnable(world, torch)) { EnumFacing facing = EnumFacing.HORIZONTALS[world.rand.nextInt(EnumFacing.HORIZONTALS.length)]; if (!world.isAirBlock(torch.east())) facing = EnumFacing.WEST; else if (!world.isAirBlock(torch.west())) facing = EnumFacing.EAST; else if (!world.isAirBlock(torch.north())) facing = EnumFacing.SOUTH; else if (!world.isAirBlock(torch.south())) facing = EnumFacing.NORTH; world.setBlockState(torch, Blocks.CHEST.getDefaultState().withProperty(BlockChest.FACING, facing)); TileEntity chest = world.getTileEntity(torch); if (chest instanceof TileEntityChest) { ((TileEntityChest)chest).setLootTable(LootStrings.MINING_CHEST, world.rand.nextLong()); } foundChest = true; } else if (!foundSign && isSpawnable(world, torch)) { world.setBlockState(torch, Blocks.STANDING_SIGN.getDefaultState().withProperty(BlockStandingSign.ROTATION, world.rand.nextInt(16))); TileEntity tile = world.getTileEntity(torch); if (tile instanceof TileEntitySign) { TileEntitySign sign = ((TileEntitySign) tile); sign.signText[0] = new TextComponentTranslation("harvestfestival.shop.miner"); sign.signText[1] = new TextComponentTranslation("harvestfestival.shop.miner.sign1"); sign.signText[2] = new TextComponentTranslation("harvestfestival.shop.miner.sign2"); sign.signText[3] = new TextComponentTranslation("harvestfestival.shop.miner.sign3"); sign.markDirty(); IBlockState state = world.getBlockState(sign.getPos()); world.notifyBlockUpdate(sign.getPos(), state, state, 3); } foundSign = true; } if (foundChest && foundTorch && foundSign) break; } world.spawnEntityInWorld(entity); generated.add(mineID); } markDirty(); } static boolean areCoordinatesGenerated(World world, int mineID, int floor) { return HFTrackers.getMineManager(world).getCoordinateMap(mineID).containsKey(floor); } BlockPos getSpawnCoordinateForMine(World world, int mineID, int floor) { BlockPos ret = getCoordinateMap(mineID).get(floor); if (ret == null || getFloor(ret) != floor) { int chunkX = (int) (Math.floor(((double)floor - 1) / MAX_FLOORS) * CHUNK_BOUNDARY * 16); BlockPos pos = new BlockPos(chunkX, (floor - 1) % MAX_FLOORS == 0 ? 247 : 1, mineID * CHUNK_BOUNDARY * 16); for (int x = 0; x < 16 * CHUNK_BOUNDARY; x++) { for (int z = 0; z < 16 * CHUNK_BOUNDARY; z++) { BlockPos toCheck = pos.add(x, 0, z); IBlockState state = world.getBlockState(toCheck); if (state.getBlock() == HFMining.PORTAL && state.getActualState(world, toCheck).getValue(HFMining.PORTAL.property).isCentre()) { getCoordinateMap(mineID).put(floor, ret); return toCheck; } } } return new BlockPos(0, 254, mineID * CHUNK_BOUNDARY * 16); } return ret; } private TIntObjectMap<BlockPos> getCoordinateMap(int mineID) { TIntObjectMap<BlockPos> map = portalCoordinates.get(mineID); if (map == null) { map = new TIntObjectHashMap<>(); portalCoordinates.put(mineID, map); } return map; } void setSpawnForMine(int mineID, int floor, int x, int y, int z) { getCoordinateMap(mineID).putIfAbsent(floor, new BlockPos(x, y, z)); markDirty(); } static TIntObjectMap<IBlockState[][]> getStateMap(long mapIndex) { return MineManager.generation.get(mapIndex); } static void putStateMap(long mapIndex, TIntObjectMap<IBlockState[][]> map) { MineManager.generation.put(mapIndex, map); } static boolean containsStateKey(long mapIndex) { return MineManager.generation.containsKey(mapIndex); } static boolean containsCoordinatesKey(long mapIndex) { return MineManager.coordinates.containsKey(mapIndex); } static void putCoordinates(long mapIndex, int[] coordinates) { MineManager.coordinates.put(mapIndex, coordinates); } static int getCoordinates(long mapIndex, int position) { return MineManager.coordinates.get(mapIndex)[position]; } }