- simplified ThreadPool further
- dispose heightmap Region when all chunks have been visited - reduce allocations caused by the depth buffer in strata gen - added temporary server props fix
This commit is contained in:
parent
1c045f91e7
commit
f0d8cf3a76
@ -28,6 +28,7 @@ package com.terraforged.api.chunk.column;
|
||||
import com.terraforged.api.chunk.ChunkContext;
|
||||
import com.terraforged.core.cell.Cell;
|
||||
import com.terraforged.core.world.climate.Climate;
|
||||
import com.terraforged.core.world.geology.DepthBuffer;
|
||||
import com.terraforged.core.world.heightmap.Levels;
|
||||
import com.terraforged.core.world.terrain.Terrain;
|
||||
import com.terraforged.core.world.terrain.Terrains;
|
||||
@ -40,6 +41,7 @@ public class DecoratorContext extends ChunkContext {
|
||||
public final Levels levels;
|
||||
public final Climate climate;
|
||||
public final Terrains terrains;
|
||||
public final DepthBuffer depthBuffer = new DepthBuffer();
|
||||
public final BlockPos.Mutable pos = new BlockPos.Mutable();
|
||||
|
||||
public Biome biome;
|
||||
|
@ -56,7 +56,7 @@ public class Cache {
|
||||
this.context = new GeneratorContext(terrain, settings);
|
||||
this.renderer = RegionGenerator.builder()
|
||||
.factory(new WorldGeneratorFactory(context))
|
||||
.pool(ThreadPool.getCommon())
|
||||
.pool(ThreadPool.getPool())
|
||||
.size(3, 2)
|
||||
.build();
|
||||
}
|
||||
|
@ -30,15 +30,18 @@ import com.terraforged.core.cell.Extent;
|
||||
import com.terraforged.core.filter.Filterable;
|
||||
import com.terraforged.core.region.chunk.ChunkReader;
|
||||
import com.terraforged.core.region.chunk.ChunkWriter;
|
||||
import com.terraforged.core.util.concurrent.Disposable;
|
||||
import com.terraforged.core.world.decorator.Decorator;
|
||||
import com.terraforged.core.world.heightmap.Heightmap;
|
||||
import com.terraforged.core.world.rivermap.RiverRegionList;
|
||||
import com.terraforged.core.world.terrain.Terrain;
|
||||
import me.dags.noise.util.NoiseUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Region implements Extent {
|
||||
public class Region implements Extent, Disposable {
|
||||
|
||||
private final int regionX;
|
||||
private final int regionZ;
|
||||
@ -51,8 +54,15 @@ public class Region implements Extent {
|
||||
private final Size chunkSize;
|
||||
private final GenCell[] blocks;
|
||||
private final GenChunk[] chunks;
|
||||
private final int disposableChunks;
|
||||
private final Disposable.Listener<Region> disposalListener;
|
||||
private final AtomicInteger disposedChunks = new AtomicInteger();
|
||||
|
||||
public Region(int regionX, int regionZ, int size, int borderChunks) {
|
||||
this(regionX, regionZ, size, borderChunks, region -> {});
|
||||
}
|
||||
|
||||
public Region(int regionX, int regionZ, int size, int borderChunks, Disposable.Listener<Region> disposalListener) {
|
||||
this.regionX = regionX;
|
||||
this.regionZ = regionZ;
|
||||
this.chunkX = regionX << size;
|
||||
@ -62,10 +72,25 @@ public class Region implements Extent {
|
||||
this.border = borderChunks;
|
||||
this.chunkSize = Size.chunks(size, borderChunks);
|
||||
this.blockSize = Size.blocks(size, borderChunks);
|
||||
this.disposalListener = disposalListener;
|
||||
this.disposableChunks = chunkSize.size * chunkSize.size;
|
||||
this.blocks = new GenCell[blockSize.total * blockSize.total];
|
||||
this.chunks = new GenChunk[chunkSize.total * chunkSize.total];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
int disposed = disposedChunks.incrementAndGet();
|
||||
if (disposed < disposableChunks) {
|
||||
return;
|
||||
}
|
||||
disposalListener.onDispose(this);
|
||||
}
|
||||
|
||||
public long getRegionId() {
|
||||
return NoiseUtil.seed(getRegionX(), getRegionZ());
|
||||
}
|
||||
|
||||
public int getRegionX() {
|
||||
return regionX;
|
||||
}
|
||||
@ -333,6 +358,11 @@ public class Region implements Extent {
|
||||
return blockZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
Region.this.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell<Terrain> getCell(int blockX, int blockZ) {
|
||||
int relX = regionBlockX + (blockX & 15);
|
||||
|
@ -26,6 +26,7 @@
|
||||
package com.terraforged.core.region;
|
||||
|
||||
import com.terraforged.core.region.chunk.ChunkReader;
|
||||
import com.terraforged.core.util.concurrent.Disposable;
|
||||
import com.terraforged.core.util.concurrent.cache.Cache;
|
||||
import com.terraforged.core.util.concurrent.cache.CacheEntry;
|
||||
import com.terraforged.core.world.heightmap.RegionExtent;
|
||||
@ -34,32 +35,37 @@ import me.dags.noise.util.NoiseUtil;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RegionCache implements RegionExtent {
|
||||
public class RegionCache implements RegionExtent, Disposable.Listener<Region> {
|
||||
|
||||
private final boolean queuing;
|
||||
private final RegionGenerator renderer;
|
||||
private final RegionGenerator generator;
|
||||
private final Cache<CacheEntry<Region>> cache;
|
||||
|
||||
public RegionCache(boolean queueNeighbours, RegionGenerator renderer) {
|
||||
this.renderer = renderer;
|
||||
public RegionCache(boolean queueNeighbours, RegionGenerator generator) {
|
||||
this.queuing = queueNeighbours;
|
||||
this.cache = new Cache<>(80, 60, TimeUnit.SECONDS);
|
||||
this.generator = new RegionGenerator(generator, this);
|
||||
this.cache = new Cache<>(60, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDispose(Region region) {
|
||||
cache.remove(region.getRegionId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int chunkToRegion(int coord) {
|
||||
return renderer.chunkToRegion(coord);
|
||||
return generator.chunkToRegion(coord);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Region> getRegionAsync(int regionX, int regionZ) {
|
||||
return renderer.generate(regionX, regionZ);
|
||||
return generator.generate(regionX, regionZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkReader getChunk(int chunkX, int chunkZ) {
|
||||
int regionX = renderer.chunkToRegion(chunkX);
|
||||
int regionZ = renderer.chunkToRegion(chunkZ);
|
||||
int regionX = generator.chunkToRegion(chunkX);
|
||||
int regionZ = generator.chunkToRegion(chunkZ);
|
||||
Region region = getRegion(regionX, regionZ);
|
||||
return region.getChunk(chunkX, chunkZ);
|
||||
}
|
||||
@ -77,7 +83,7 @@ public class RegionCache implements RegionExtent {
|
||||
|
||||
public CacheEntry<Region> queueRegion(int regionX, int regionZ) {
|
||||
long id = NoiseUtil.seed(regionX, regionZ);
|
||||
return cache.computeIfAbsent(id, l -> renderer.generateCached(regionX, regionZ));
|
||||
return cache.computeIfAbsent(id, l -> generator.generateCached(regionX, regionZ));
|
||||
}
|
||||
|
||||
private void queueNeighbours(int regionX, int regionZ) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.terraforged.core.region;
|
||||
|
||||
import com.terraforged.core.util.concurrent.Disposable;
|
||||
|
||||
public interface RegionFactory {
|
||||
|
||||
Region create(int regionX, int regionZ, int size, int borderChunks);
|
||||
Region create(int regionX, int regionZ, int size, int borderChunks, Disposable.Listener<Region> listener);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package com.terraforged.core.region;
|
||||
|
||||
import com.terraforged.core.region.legacy.LegacyRegion;
|
||||
import com.terraforged.core.util.concurrent.Disposable;
|
||||
import com.terraforged.core.util.concurrent.ThreadPool;
|
||||
import com.terraforged.core.util.concurrent.cache.CacheEntry;
|
||||
import com.terraforged.core.world.WorldGenerator;
|
||||
@ -42,6 +43,7 @@ public class RegionGenerator implements RegionExtent {
|
||||
private final RegionFactory regions;
|
||||
private final ThreadPool threadPool;
|
||||
private final ThreadLocal<WorldGenerator> genPool;
|
||||
private final Disposable.Listener<Region> disposalListener;
|
||||
|
||||
private RegionGenerator(Builder builder) {
|
||||
this.factor = builder.factor;
|
||||
@ -49,6 +51,16 @@ public class RegionGenerator implements RegionExtent {
|
||||
this.threadPool = builder.threadPool;
|
||||
this.regions = builder.regionFactory;
|
||||
this.genPool = ThreadLocal.withInitial(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() {
|
||||
@ -88,7 +100,7 @@ public class RegionGenerator implements RegionExtent {
|
||||
|
||||
public Region generateRegion(int regionX, int regionZ) {
|
||||
WorldGenerator generator = genPool.get();
|
||||
Region region = regions.create(regionX, regionZ, factor, border);
|
||||
Region region = regions.create(regionX, regionZ, factor, border, disposalListener);
|
||||
RiverRegionList rivers = generator.getHeightmap().getRiverMap().getRivers(region);
|
||||
region.generateBase(generator.getHeightmap());
|
||||
region.generateRivers(generator.getHeightmap(), rivers);
|
||||
@ -103,7 +115,7 @@ public class RegionGenerator implements RegionExtent {
|
||||
|
||||
public Region generateRegion(float centerX, float centerZ, float zoom, boolean filter) {
|
||||
WorldGenerator generator = genPool.get();
|
||||
Region region = regions.create(0, 0, factor, border);
|
||||
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;
|
||||
|
@ -26,8 +26,9 @@
|
||||
package com.terraforged.core.region.chunk;
|
||||
|
||||
import com.terraforged.core.cell.Extent;
|
||||
import com.terraforged.core.util.concurrent.Disposable;
|
||||
|
||||
public interface ChunkHolder extends Extent {
|
||||
public interface ChunkHolder extends Extent, Disposable {
|
||||
|
||||
int getChunkX();
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.terraforged.core.region.legacy;
|
||||
|
||||
import com.terraforged.core.region.Region;
|
||||
import com.terraforged.core.util.concurrent.Disposable;
|
||||
|
||||
/**
|
||||
* This is here to provide compatibility for versions 0.0.2 and below which contained a
|
||||
@ -9,8 +10,8 @@ import com.terraforged.core.region.Region;
|
||||
*/
|
||||
public class LegacyRegion extends Region {
|
||||
|
||||
public LegacyRegion(int regionX, int regionZ, int size, int borderChunks) {
|
||||
super(regionX, regionZ, size, borderChunks);
|
||||
public LegacyRegion(int regionX, int regionZ, int size, int borderChunks, Disposable.Listener<Region> listener) {
|
||||
super(regionX, regionZ, size, borderChunks, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,11 @@
|
||||
package com.terraforged.core.util.concurrent;
|
||||
|
||||
public interface Disposable {
|
||||
|
||||
void dispose();
|
||||
|
||||
interface Listener<T> {
|
||||
|
||||
void onDispose(T t);
|
||||
}
|
||||
}
|
@ -33,41 +33,19 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ThreadPool implements Executor {
|
||||
|
||||
public static final int DEFAULT_POOL_SIZE = defaultPoolSize();
|
||||
private static final ThreadPool instance = new ThreadPool("TerraForged", defaultPoolSize());
|
||||
|
||||
private static final Object lock = new Object();
|
||||
private static final ForkJoinPool defaultPool = ThreadPool.createPool(2, "TFCore");
|
||||
|
||||
private static ThreadPool instance = new ThreadPool(defaultPoolSize());
|
||||
|
||||
private final int poolSize;
|
||||
private final ExecutorService service;
|
||||
|
||||
private ThreadPool() {
|
||||
this.service = defaultPool;
|
||||
this.poolSize = -1;
|
||||
}
|
||||
|
||||
public ThreadPool(int size) {
|
||||
this.poolSize = size;
|
||||
this.service = ThreadPool.createExecutor(size, "TerraForged");
|
||||
}
|
||||
|
||||
private ThreadPool(ForkJoinPool pool) {
|
||||
this.service = pool;
|
||||
this.poolSize = pool.getPoolSize();
|
||||
private ThreadPool(String name, int size) {
|
||||
this.service = ThreadPool.createPool(size, name);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (poolSize > 0) {
|
||||
service.shutdown();
|
||||
}
|
||||
service.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -87,51 +65,16 @@ public class ThreadPool implements Executor {
|
||||
return new AsyncBatcher(service, size);
|
||||
}
|
||||
|
||||
public static ThreadPool getCurrent() {
|
||||
synchronized (lock) {
|
||||
return instance;
|
||||
}
|
||||
public static ThreadPool getPool() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static ThreadPool getFixed(int size) {
|
||||
synchronized (lock) {
|
||||
if (instance.poolSize != size) {
|
||||
instance.shutdown();
|
||||
instance = new ThreadPool(size);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static ThreadPool getFixed() {
|
||||
synchronized (lock) {
|
||||
if (instance.poolSize == -1) {
|
||||
instance = new ThreadPool(ThreadPool.DEFAULT_POOL_SIZE);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static ThreadPool getCommon() {
|
||||
synchronized (lock) {
|
||||
if (instance.poolSize != -1) {
|
||||
instance.shutdown();
|
||||
instance = new ThreadPool();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static ForkJoinPool getDefaultPool() {
|
||||
return defaultPool;
|
||||
public static ThreadPool create(int size) {
|
||||
return new ThreadPool("Pool", Math.max(1, size));
|
||||
}
|
||||
|
||||
public static void shutdownCurrent() {
|
||||
synchronized (lock) {
|
||||
instance.shutdown();
|
||||
// replace with the common pool
|
||||
instance = new ThreadPool();
|
||||
}
|
||||
instance.shutdown();
|
||||
}
|
||||
|
||||
private static int defaultPoolSize() {
|
||||
@ -139,19 +82,6 @@ public class ThreadPool implements Executor {
|
||||
return Math.max(1, (int) ((threads / 3F) * 2F));
|
||||
}
|
||||
|
||||
public static ExecutorService createExecutor(int size, String name) {
|
||||
ThreadPoolExecutor service = new ThreadPoolExecutor(
|
||||
size,
|
||||
size,
|
||||
30,
|
||||
TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(),
|
||||
new WorkerFactory(name)
|
||||
);
|
||||
service.allowCoreThreadTimeOut(true);
|
||||
return service;
|
||||
}
|
||||
|
||||
public static ForkJoinPool createPool(int size, String name) {
|
||||
return new ForkJoinPool(size, new WorkerFactory.ForkJoin(name), null, true);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import com.terraforged.core.util.concurrent.ThreadPool;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class Cache<V extends ExpiringEntry> implements Runnable {
|
||||
|
||||
@ -20,8 +19,8 @@ public class Cache<V extends ExpiringEntry> implements Runnable {
|
||||
this.map = new SynchronizedLongMap<>(100);
|
||||
}
|
||||
|
||||
public V computeIfAbsent(long key, Supplier<V> supplier) {
|
||||
return computeIfAbsent(key, o -> supplier.get());
|
||||
public void remove(long key) {
|
||||
map.remove(key);
|
||||
}
|
||||
|
||||
public V computeIfAbsent(long key, LongFunction<V> func) {
|
||||
@ -34,7 +33,7 @@ public class Cache<V extends ExpiringEntry> implements Runnable {
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - timestamp > intervalMS) {
|
||||
timestamp = now;
|
||||
ThreadPool.getDefaultPool().execute(this);
|
||||
ThreadPool.getPool().execute(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
package com.terraforged.core.world.geology;
|
||||
|
||||
public class DepthBuffer {
|
||||
|
||||
private float sum;
|
||||
private float[] buffer;
|
||||
|
||||
public void init(int size) {
|
||||
sum = 0F;
|
||||
if (buffer == null || buffer.length < size) {
|
||||
buffer = new float[size];
|
||||
}
|
||||
}
|
||||
|
||||
public float getSum() {
|
||||
return sum;
|
||||
}
|
||||
|
||||
public float get(int index) {
|
||||
return buffer[index];
|
||||
}
|
||||
|
||||
public float getDepth(int index) {
|
||||
return buffer[index] / sum;
|
||||
}
|
||||
|
||||
public void set(int index, float value) {
|
||||
sum += value;
|
||||
buffer[index] = value;
|
||||
}
|
||||
}
|
@ -44,14 +44,19 @@ public class Strata<T> {
|
||||
this.heightMod = heightMod;
|
||||
}
|
||||
|
||||
public boolean downwards(final int x, final int y, final int z, Stratum.Visitor<T> visitor) {
|
||||
DepthBuffer depthBuffer = new DepthBuffer(strata, x, z);
|
||||
public boolean downwards(final int x, final int y, final int z, final Stratum.Visitor<T> visitor) {
|
||||
DepthBuffer buffer = new DepthBuffer();
|
||||
initBuffer(buffer, x, z);
|
||||
return downwards(x, y, z, buffer, visitor);
|
||||
}
|
||||
|
||||
public boolean downwards(final int x, final int y, final int z, final DepthBuffer buffer, Stratum.Visitor<T> visitor) {
|
||||
initBuffer(buffer, x, z);
|
||||
|
||||
int py = y;
|
||||
T last = null;
|
||||
float sum = depthBuffer.sum;
|
||||
for (int i = 0; i < strata.size(); i++) {
|
||||
float depth = depthBuffer.buffer[i] / sum;
|
||||
float depth = buffer.get(i);
|
||||
int height = NoiseUtil.round(depth * y);
|
||||
T value = strata.get(i).getValue();
|
||||
last = value;
|
||||
@ -76,45 +81,15 @@ public class Strata<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean upwards(int x, int y, int z, Stratum.Visitor<T> visitor) {
|
||||
DepthBuffer depthBuffer = new DepthBuffer(strata, x, z);
|
||||
int py = 0;
|
||||
float sum = depthBuffer.sum;
|
||||
for (int i = strata.size() - 1; i > 0; i--) {
|
||||
float depth = depthBuffer.buffer[i] / sum;
|
||||
int height = NoiseUtil.round(depth * y);
|
||||
T value = strata.get(i).getValue();
|
||||
for (int dy = 0; dy < height; dy++) {
|
||||
boolean cont = visitor.visit(py, value);
|
||||
if (!cont) {
|
||||
return false;
|
||||
}
|
||||
if (++py > y) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getYOffset(int x, int z) {
|
||||
return (int) (64 * heightMod.getValue(x, z));
|
||||
}
|
||||
|
||||
private static class DepthBuffer {
|
||||
|
||||
private final float sum;
|
||||
private final float[] buffer;
|
||||
|
||||
private <T> DepthBuffer(List<Stratum<T>> strata, int x, int z) {
|
||||
buffer = new float[strata.size()];
|
||||
float sum = 0F;
|
||||
for (int i = 0; i < strata.size(); i++) {
|
||||
float depth = strata.get(i).getDepth(x, z);
|
||||
sum += depth;
|
||||
buffer[i] = depth;
|
||||
}
|
||||
this.sum = sum;
|
||||
private void initBuffer(DepthBuffer buffer, int x, int z) {
|
||||
buffer.init(strata.size());
|
||||
for (int i = 0; i < strata.size(); i++) {
|
||||
float depth = strata.get(i).getDepth(x, z);
|
||||
buffer.set(i, depth);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,6 @@ public class RiverMap {
|
||||
}
|
||||
|
||||
private CacheEntry<RiverRegion> generateRegion(int rx, int rz) {
|
||||
return CacheEntry.supplyAsync(() -> new RiverRegion(rx, rz, heightmap, context, riverMapConfig), ThreadPool.getDefaultPool());
|
||||
return CacheEntry.supplyAsync(() -> new RiverRegion(rx, rz, heightmap, context, riverMapConfig), ThreadPool.getPool());
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public class FastChunk implements ChunkDelegate {
|
||||
section.unlock();
|
||||
return replaced;
|
||||
}
|
||||
return Blocks.AIR.getDefaultState();
|
||||
return Blocks.VOID_AIR.getDefaultState();
|
||||
}
|
||||
|
||||
public void setBiomes(BiomeContainer biomes) {
|
||||
|
@ -216,6 +216,9 @@ public class TerraChunkGenerator extends ObfHelperChunkGenerator<GenerationSetti
|
||||
|
||||
// bake biome array & discard gen data
|
||||
((ChunkPrimer) chunk).func_225548_a_(container.bakeBiomes(Environment.isVanillaBiomes()));
|
||||
|
||||
// marks the heightmap data for this chunk for removal
|
||||
container.getChunkReader().dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -383,7 +386,7 @@ public class TerraChunkGenerator extends ObfHelperChunkGenerator<GenerationSetti
|
||||
protected RegionCache createRegionCache(TerraContext context) {
|
||||
return RegionGenerator.builder()
|
||||
.legacy(context.terraSettings.version == 0)
|
||||
.pool(ThreadPool.getFixed())
|
||||
.pool(ThreadPool.getPool())
|
||||
.factory(context.factory)
|
||||
.size(3, 2)
|
||||
.build()
|
||||
|
@ -52,7 +52,7 @@ public class TestChunkGenerator extends TerraChunkGenerator {
|
||||
protected RegionCache createRegionCache(TerraContext context) {
|
||||
return RegionGenerator.builder()
|
||||
.factory(new WorldGeneratorFactory(context, new TestHeightMap(context)))
|
||||
.pool(ThreadPool.getFixed())
|
||||
.pool(ThreadPool.getPool())
|
||||
.size(3, 2)
|
||||
.build()
|
||||
.toCache(false);
|
||||
|
@ -47,7 +47,7 @@ public class GeologyDecorator implements ColumnDecorator {
|
||||
@Override
|
||||
public void decorate(ChunkSurfaceBuffer buffer, DecoratorContext context, int x, int y, int z) {
|
||||
int top = buffer.getSurfaceBottom();
|
||||
geology.getGeology(context.biome).getStrata(x, z).downwards(x, top, z, (py, state) -> {
|
||||
geology.getGeology(context.biome).getStrata(x, z).downwards(x, top, z, context.depthBuffer, (py, state) -> {
|
||||
context.pos.setPos(x, py, z);
|
||||
buffer.getDelegate().setBlockState(context.pos, state, false);
|
||||
return true;
|
||||
|
@ -165,7 +165,7 @@ public class Preview extends Button {
|
||||
|
||||
RegionGenerator renderer = RegionGenerator.builder()
|
||||
.factory(new WorldGeneratorFactory(context))
|
||||
.pool(ThreadPool.getCommon())
|
||||
.pool(ThreadPool.getPool())
|
||||
.size(FACTOR, 0)
|
||||
.build();
|
||||
|
||||
|
@ -0,0 +1,51 @@
|
||||
package com.terraforged.mod.server;
|
||||
|
||||
import net.minecraft.server.ServerPropertiesProvider;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import net.minecraft.server.dedicated.PropertyManager;
|
||||
import net.minecraft.server.dedicated.ServerProperties;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
@Mod.EventBusSubscriber(value = Dist.DEDICATED_SERVER, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public class ServerPropertiesFix {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void setup(FMLDedicatedServerSetupEvent event) {
|
||||
DedicatedServer server = event.getServerSupplier().get();
|
||||
get(server, DedicatedServer.class, ServerPropertiesProvider.class).ifPresent(provider -> provider.func_219033_a(props -> {
|
||||
return get(props, PropertyManager.class, Properties.class).flatMap(properties -> {
|
||||
String world = properties.getProperty("mod-level-type");
|
||||
if (world != null && !world.isEmpty()) {
|
||||
properties.setProperty("level-type", world);
|
||||
return Optional.of(new ServerProperties(properties));
|
||||
}
|
||||
return Optional.empty();
|
||||
}).orElse(props);
|
||||
}));
|
||||
}
|
||||
|
||||
private static <T> Optional<T> get(Object owner, Class<?> target, Class<T> type) {
|
||||
for (Field field : target.getDeclaredFields()) {
|
||||
if (field.getType() == type) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(owner);
|
||||
if (value != null) {
|
||||
return Optional.of(type.cast(value));
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user