TerraForged/TerraForgedCore/src/main/java/com/terraforged/core/region/gen/RegionGenerator.java

205 lines
7.4 KiB
Java

/*
*
* MIT License
*
* Copyright (c) 2020 TerraForged
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.terraforged.core.region.gen;
import com.terraforged.core.region.Region;
import com.terraforged.core.region.RegionFactory;
import com.terraforged.core.region.legacy.LegacyRegion;
import com.terraforged.core.util.concurrent.Disposable;
import com.terraforged.core.util.concurrent.ObjectPool;
import com.terraforged.core.util.concurrent.ThreadPool;
import com.terraforged.core.util.concurrent.cache.CacheEntry;
import com.terraforged.core.world.WorldGenerator;
import com.terraforged.core.world.WorldGeneratorFactory;
import com.terraforged.core.world.heightmap.RegionExtent;
import com.terraforged.core.world.rivermap.RiverRegionList;
import java.util.concurrent.CompletableFuture;
public class RegionGenerator implements RegionExtent {
private final int factor;
private final int border;
private final RegionFactory regions;
private final ThreadPool threadPool;
private final ObjectPool<GenContext> genPool;
private final Disposable.Listener<Region> disposalListener;
private RegionGenerator(Builder builder) {
this.factor = builder.factor;
this.border = builder.border;
this.threadPool = builder.threadPool;
this.regions = builder.regionFactory;
this.genPool = new ObjectPool<>(6, GenContext.supplier(builder.factory));
this.disposalListener = region -> {};
}
protected RegionGenerator(RegionGenerator from, Disposable.Listener<Region> listener) {
this.factor = from.factor;
this.border = from.border;
this.threadPool = from.threadPool;
this.regions = from.regions;
this.genPool = from.genPool;
this.disposalListener = listener;
}
public RegionCache toCache() {
return toCache(true);
}
public RegionCache toCache(boolean queueNeighbours) {
return new RegionCache(queueNeighbours, this);
}
@Override
public int chunkToRegion(int i) {
return i >> factor;
}
@Override
public Region getRegion(int regionX, int regionZ) {
return generateRegion(regionX, regionZ);
}
@Override
public CompletableFuture<Region> getRegionAsync(int regionX, int regionZ) {
return generate(regionX, regionZ);
}
public CompletableFuture<Region> generate(int regionX, int regionZ) {
return CompletableFuture.supplyAsync(() -> generateRegion(regionX, regionZ), threadPool);
}
public CompletableFuture<Region> generate(float centerX, float centerZ, float zoom, boolean filter) {
return CompletableFuture.supplyAsync(() -> generateRegion(centerX, centerZ, zoom, filter), threadPool);
}
public CacheEntry<Region> compute(int regionX, int regionZ) {
return CacheEntry.supply(new FutureRegion(regionX, regionZ, this));
}
public CacheEntry<Region> compute(float centerX, float centerZ, float zoom, boolean filter) {
return CacheEntry.supply(new FutureRegionZoom(centerX, centerZ, zoom, filter, this));
}
public CacheEntry<Region> queue(int regionX, int regionZ) {
return CacheEntry.supplyAsync(new FutureRegion(regionX, regionZ, this), threadPool);
}
public CacheEntry<Region> queue(float centerX, float centerZ, float zoom, boolean filter) {
return CacheEntry.supplyAsync(new FutureRegionZoom(centerX, centerZ, zoom, filter, this), threadPool);
}
public Region generateRegion(int regionX, int regionZ) {
try (ObjectPool.Item<GenContext> item = genPool.get()) {
RiverRegionList rivers = item.getValue().rivers;
WorldGenerator generator = item.getValue().generator;
Region region = regions.create(regionX, regionZ, factor, border, disposalListener);
generator.getHeightmap().getRiverMap().getRivers(region, rivers);
region.generateBase(generator.getHeightmap());
region.generateRivers(generator.getHeightmap(), rivers);
postProcess(region, generator);
rivers.clear();
return region;
}
}
private void postProcess(Region region, WorldGenerator generator) {
generator.getFilters().apply(region);
region.decorate(generator.getDecorators().getDecorators());
}
public Region generateRegion(float centerX, float centerZ, float zoom, boolean filter) {
try (ObjectPool.Item<GenContext> item = genPool.get()) {
WorldGenerator generator = item.getValue().generator;
Region region = regions.create(0, 0, factor, border, disposalListener);
region.generateZoom(generator.getHeightmap(), centerX, centerZ, zoom);
postProcess(region, generator, centerX, centerZ, zoom, filter);
return region;
}
}
private void postProcess(Region region, WorldGenerator generator, float centerX, float centerZ, float zoom, boolean filter) {
if (filter) {
generator.getFilters().apply(region);
}
region.decorateZoom(generator.getDecorators().getDecorators(), centerX, centerZ, zoom);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private int factor = 0;
private int border = 0;
private ThreadPool threadPool;
private WorldGeneratorFactory factory;
private RegionFactory regionFactory = Region::new;
public Builder size(int factor, int border) {
return factor(factor).border(border);
}
public Builder factor(int factor) {
this.factor = factor;
return this;
}
public Builder border(int border) {
this.border = border;
return this;
}
public Builder pool(ThreadPool threadPool) {
this.threadPool = threadPool;
return this;
}
public Builder regions(RegionFactory factory) {
this.regionFactory = factory;
return this;
}
public Builder legacy(boolean legacy) {
if (legacy) {
return regions(LegacyRegion::new);
}
return this;
}
public Builder factory(WorldGeneratorFactory factory) {
this.factory = factory;
return this;
}
public RegionGenerator build() {
return new RegionGenerator(this);
}
}
}