package WayofTime.bloodmagic.inversion; import WayofTime.bloodmagic.soul.EnumDemonWillType; import WayofTime.bloodmagic.util.BMLog; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import java.util.*; public class InversionPillarHandler { public static final double farthestDistanceSquared = 16 * 16; public static Map>> pillarMap = new HashMap<>(); public static Map>>> nearPillarMap = new HashMap<>(); public static boolean addPillarToMap(World world, EnumDemonWillType type, BlockPos pos) { int dim = world.provider.getDimension(); if (pillarMap.containsKey(dim)) { Map> willMap = pillarMap.get(dim); if (willMap.containsKey(type)) { if (!willMap.get(type).contains(pos)) { willMap.get(type).add(pos); onPillarAdded(world, type, pos); return true; } else { return false; } } else { List posList = new ArrayList<>(); posList.add(pos); willMap.put(type, posList); onPillarAdded(world, type, pos); return true; } } else { Map> willMap = new HashMap<>(); List posList = new ArrayList<>(); posList.add(pos); willMap.put(type, posList); pillarMap.put(dim, willMap); onPillarAdded(world, type, pos); return true; } } public static boolean removePillarFromMap(World world, EnumDemonWillType type, BlockPos pos) { int dim = world.provider.getDimension(); if (pillarMap.containsKey(dim)) { Map> willMap = pillarMap.get(dim); if (willMap.containsKey(type)) { if (willMap.get(type).contains(pos)) { onPillarRemoved(world, type, pos); return willMap.get(type).remove(pos); } else { return false; } } else { return false; } } else { return false; } } //Assume that it has been added already. private static void onPillarAdded(World world, EnumDemonWillType type, BlockPos pos) { BMLog.DEBUG.info("Adding..."); List closePosList = new ArrayList<>(); int dim = world.provider.getDimension(); if (pillarMap.containsKey(dim)) { Map> willMap = pillarMap.get(dim); if (willMap.containsKey(type)) { List otherPosList = willMap.get(type); for (BlockPos closePos : otherPosList) { if (!closePos.equals(pos) && closePos.distanceSq(pos) <= farthestDistanceSquared) { closePosList.add(closePos); } } } } if (nearPillarMap.containsKey(dim)) { Map>> willMap = nearPillarMap.get(dim); if (willMap.containsKey(type)) { Map> posMap = willMap.get(type); for (BlockPos closePos : closePosList) { List posList = posMap.get(closePos); if (posList != null && !posList.contains(pos)) { posList.add(pos); } else { posList = new ArrayList<>(); posList.add(pos); posMap.put(closePos, posList); } } posMap.put(pos, closePosList); } else { Map> posMap = new HashMap<>(); posMap.put(pos, closePosList); willMap.put(type, posMap); } } else { Map>> willMap = new HashMap<>(); Map> posMap = new HashMap<>(); posMap.put(pos, closePosList); willMap.put(type, posMap); nearPillarMap.put(dim, willMap); } } private static void onPillarRemoved(World world, EnumDemonWillType type, BlockPos pos) { BMLog.DEBUG.info("Removing..."); int dim = world.provider.getDimension(); if (nearPillarMap.containsKey(dim)) { Map>> willMap = nearPillarMap.get(dim); if (willMap.containsKey(type)) { Map> posMap = willMap.get(type); List posList = posMap.get(pos); if (posList != null) { for (BlockPos checkPos : posList) { List checkPosList = posMap.get(checkPos); if (checkPosList != null) { checkPosList.remove(pos); } } posMap.remove(pos); } } } } //TODO: Change to use the nearPillarMap. public static List getNearbyPillars(World world, EnumDemonWillType type, BlockPos pos) { int dim = world.provider.getDimension(); if (nearPillarMap.containsKey(dim)) { Map>> willMap = nearPillarMap.get(dim); if (willMap.containsKey(type)) { Map> posMap = willMap.get(type); List posList = posMap.get(pos); if (posList != null) { return posList; } } } return new ArrayList<>(); } public static List getAllConnectedPillars(World world, EnumDemonWillType type, BlockPos pos) { List checkedPosList = new ArrayList<>(); List uncheckedPosList = new ArrayList<>(); //Positions where we did not check their connections. uncheckedPosList.add(pos); int dim = world.provider.getDimension(); if (nearPillarMap.containsKey(dim)) { Map>> willMap = nearPillarMap.get(dim); if (willMap.containsKey(type)) { Map> posMap = willMap.get(type); // This is where the magic happens. while (!uncheckedPosList.isEmpty()) { //Positions that are new this iteration and need to be dumped into uncheckedPosList next iteration. List newPosList = new ArrayList<>(); for (BlockPos checkPos : uncheckedPosList) { List posList = posMap.get(checkPos); if (posList != null) { for (BlockPos testPos : posList) { //Check if the position has already been checked, is scheduled to be checked, or is already found it needs to be checked. if (!checkedPosList.contains(testPos) && !uncheckedPosList.contains(testPos) && !newPosList.contains(testPos)) { newPosList.add(testPos); } } } } checkedPosList.addAll(uncheckedPosList); uncheckedPosList = newPosList; } } } return checkedPosList; } }