package rocks.cleanstone.game.world.region; import com.google.common.collect.ImmutableSet; import org.apache.commons.lang3.tuple.Pair; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.util.concurrent.ListenableFuture; import rocks.cleanstone.game.world.chunk.ChunkCoords; import rocks.cleanstone.game.world.chunk.ChunkProvider; import javax.annotation.Nullable; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * Divides the world into equal quadratic regions */ public class QuadraticRegionManager implements RegionManager { private final Map<Pair<Integer, Integer>, Region> regions; private final ChunkProvider chunkProvider; private final int chunksPerRegionRoot = 16; // TODO make this customizable public QuadraticRegionManager(ChunkProvider chunkProvider) { this.chunkProvider = chunkProvider; regions = new HashMap<>(); } @Override public Collection<Region> getLoadedRegions() { return ImmutableSet.copyOf(regions.values()); } @Nullable @Override public Region getLoadedRegion(ChunkCoords chunkCoords) { return regions.get(getRegionCoordinates(chunkCoords)); } @Override public ListenableFuture<Region> loadRegion(ChunkCoords chunkCoords) { Pair<Integer, Integer> regionCoords = getRegionCoordinates(chunkCoords); Region region = new SimpleRegion("QuR[" + regionCoords.getLeft() + ":" + regionCoords.getRight() + "]", new LocalRegionWorker(), chunkProvider); regions.put(regionCoords, region); return new AsyncResult<>(region); } @Override public ListenableFuture<Region> getRegion(ChunkCoords chunkCoords) { Pair<Integer, Integer> regionCoords = getRegionCoordinates(chunkCoords); if (regions.containsKey(regionCoords)) { return new AsyncResult<>(regions.get(regionCoords)); } return loadRegion(chunkCoords); } @Override public void unloadRegion(Region region) { regions.values().remove(region); } private Pair<Integer, Integer> getRegionCoordinates(ChunkCoords coords) { int x = coords.getX() >> 4; int z = coords.getZ() >> 4; return Pair.of(x, z); } @Override public void close() { regions.values().forEach(Region::unloadAllChunks); } }