- ignore 3rd party ChunkPrimer candidates for the fast chunk wrapper
- some tweaks to terrains stuff
This commit is contained in:
parent
f0d8cf3a76
commit
5142264bcf
@ -91,7 +91,7 @@ public class Main extends Applet {
|
||||
if (cell.tag == getCache().getTerrain().volcano) {
|
||||
return 0F;
|
||||
}
|
||||
return 20 + (cell.tag.getId() / (float) Terrain.MAX_ID.get()) * 80;
|
||||
return 20 + (cell.tag.getHue() * 80);
|
||||
case ELEVATION:
|
||||
float value = (cell.value - 0.245F) / 0.65F;
|
||||
return (1 - value) * 30;
|
||||
|
@ -26,6 +26,7 @@
|
||||
package com.terraforged.core.settings;
|
||||
|
||||
import com.terraforged.core.util.serialization.annotation.Comment;
|
||||
import com.terraforged.core.util.serialization.annotation.Name;
|
||||
import com.terraforged.core.util.serialization.annotation.Range;
|
||||
import com.terraforged.core.util.serialization.annotation.Serializable;
|
||||
import me.dags.noise.Module;
|
||||
@ -77,6 +78,7 @@ public class GeneratorSettings {
|
||||
public int continentScale = 4000;
|
||||
|
||||
@Range(min = 250, max = 5000)
|
||||
@Name("Mountain Range Scale")
|
||||
@Comment("Controls the size of mountain ranges")
|
||||
public int mountainScale = 950;
|
||||
|
||||
|
@ -30,34 +30,30 @@ import com.terraforged.core.util.concurrent.batcher.Batcher;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
|
||||
public class ThreadPool implements Executor {
|
||||
|
||||
private static final ThreadPool instance = new ThreadPool("TerraForged", defaultPoolSize());
|
||||
private static final ThreadPool instance = new ThreadPool("TF", defaultPoolSize());
|
||||
private static final Object lock = new Object();
|
||||
|
||||
private final ExecutorService service;
|
||||
private final ForkJoinPool service;
|
||||
|
||||
private ThreadPool(String name, int size) {
|
||||
this.service = ThreadPool.createPool(size, name);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
service.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
service.execute(command);
|
||||
service.submit(command);
|
||||
}
|
||||
|
||||
public <T> Future<?> submit(Runnable runnable) {
|
||||
public <T> ForkJoinTask<?> submit(Runnable runnable) {
|
||||
return service.submit(runnable);
|
||||
}
|
||||
|
||||
public <T> Future<T> submit(Callable<T> callable) {
|
||||
public <T> ForkJoinTask<T> submit(Callable<T> callable) {
|
||||
return service.submit(callable);
|
||||
}
|
||||
|
||||
@ -73,16 +69,13 @@ public class ThreadPool implements Executor {
|
||||
return new ThreadPool("Pool", Math.max(1, size));
|
||||
}
|
||||
|
||||
public static void shutdownCurrent() {
|
||||
instance.shutdown();
|
||||
}
|
||||
|
||||
private static int defaultPoolSize() {
|
||||
int threads = Runtime.getRuntime().availableProcessors();
|
||||
return Math.max(1, (int) ((threads / 3F) * 2F));
|
||||
}
|
||||
|
||||
public static ForkJoinPool createPool(int size, String name) {
|
||||
|
||||
return new ForkJoinPool(size, new WorkerFactory.ForkJoin(name), null, true);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ public class Cache<V extends ExpiringEntry> implements Runnable {
|
||||
private final long expireMS;
|
||||
private final long intervalMS;
|
||||
private final SynchronizedLongMap<V> map;
|
||||
private final ThreadPool threadPool = ThreadPool.getPool();
|
||||
|
||||
private volatile long timestamp = 0L;
|
||||
|
||||
@ -33,7 +34,7 @@ public class Cache<V extends ExpiringEntry> implements Runnable {
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - timestamp > intervalMS) {
|
||||
timestamp = now;
|
||||
ThreadPool.getPool().execute(this);
|
||||
threadPool.submit(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,17 @@
|
||||
package com.terraforged.core.util.concurrent.cache;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
import com.terraforged.core.util.concurrent.ThreadPool;
|
||||
|
||||
public class CacheEntry<T> implements Runnable, ExpiringEntry {
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
|
||||
public class CacheEntry<T> implements ExpiringEntry {
|
||||
|
||||
private volatile T result;
|
||||
private volatile long timestamp;
|
||||
private final ForkJoinTask<T> task;
|
||||
|
||||
private final Supplier<T> supplier;
|
||||
|
||||
private CacheEntry(Supplier<T> supplier) {
|
||||
this.supplier = supplier;
|
||||
public CacheEntry(ForkJoinTask<T> task) {
|
||||
this.task = task;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@ -20,33 +20,15 @@ public class CacheEntry<T> implements Runnable, ExpiringEntry {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.result = supplier.get();
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return result != null;
|
||||
return task.isDone();
|
||||
}
|
||||
|
||||
public T get() {
|
||||
T value = result;
|
||||
if (value == null) {
|
||||
value = getNow();
|
||||
}
|
||||
return value;
|
||||
return task.join();
|
||||
}
|
||||
|
||||
private T getNow() {
|
||||
T result = supplier.get();
|
||||
this.result = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> CacheEntry<T> supplyAsync(Supplier<T> supplier, Executor executor) {
|
||||
CacheEntry<T> entry = new CacheEntry<>(supplier);
|
||||
executor.execute(entry);
|
||||
return entry;
|
||||
public static <T> CacheEntry<T> supplyAsync(Callable<T> callable, ThreadPool executor) {
|
||||
return new CacheEntry<>(executor.submit(callable));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
*
|
||||
* 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.util.serialization.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Name {
|
||||
|
||||
String value();
|
||||
}
|
@ -26,6 +26,7 @@
|
||||
package com.terraforged.core.util.serialization.serializer;
|
||||
|
||||
import com.terraforged.core.util.serialization.annotation.Comment;
|
||||
import com.terraforged.core.util.serialization.annotation.Name;
|
||||
import com.terraforged.core.util.serialization.annotation.Range;
|
||||
import com.terraforged.core.util.serialization.annotation.Serializable;
|
||||
|
||||
@ -163,7 +164,9 @@ public class Serializer {
|
||||
}
|
||||
|
||||
private static String getName(Field field) {
|
||||
String name = field.getName();
|
||||
Name nameMeta = field.getAnnotation(Name.class);
|
||||
|
||||
String name = nameMeta == null ? field.getName() : nameMeta.value();
|
||||
StringBuilder sb = new StringBuilder(name.length() * 2);
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
|
@ -48,6 +48,7 @@ public class RiverMap {
|
||||
private final GeneratorContext context;
|
||||
private final RiverMapConfig riverMapConfig;
|
||||
private final Cache<CacheEntry<RiverRegion>> cache;
|
||||
private final ThreadPool threadPool = ThreadPool.getPool();
|
||||
|
||||
public RiverMap(Heightmap heightmap, GeneratorContext context) {
|
||||
RiverConfig primary = RiverConfig.builder(context.levels)
|
||||
@ -151,6 +152,6 @@ public class RiverMap {
|
||||
}
|
||||
|
||||
private CacheEntry<RiverRegion> generateRegion(int rx, int rz) {
|
||||
return CacheEntry.supplyAsync(() -> new RiverRegion(rx, rz, heightmap, context, riverMapConfig), ThreadPool.getPool());
|
||||
return CacheEntry.supplyAsync(() -> new RiverRegion(rx, rz, heightmap, context, riverMapConfig), threadPool);
|
||||
}
|
||||
}
|
||||
|
@ -29,17 +29,25 @@ import com.terraforged.core.cell.Tag;
|
||||
import com.terraforged.core.settings.Settings;
|
||||
import com.terraforged.core.world.heightmap.Levels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Terrain implements Tag {
|
||||
|
||||
public static final int ID_START = 9;
|
||||
public static final AtomicInteger MAX_ID = new AtomicInteger(0);
|
||||
private static final AtomicInteger MAX_ID = new AtomicInteger(0);
|
||||
private static final Map<String, Terrain> register = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
public static final int ID_START = 10;
|
||||
public static final Terrain NONE = new Terrain("none", -1);
|
||||
|
||||
private final String name;
|
||||
private final int id;
|
||||
private float weight;
|
||||
private final float weight;
|
||||
|
||||
public Terrain(String name, int id) {
|
||||
this(name, id, 1F);
|
||||
@ -49,6 +57,7 @@ public class Terrain implements Tag {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
this.weight = (float) weight;
|
||||
register.put(name, this);
|
||||
MAX_ID.set(Math.max(MAX_ID.get(), id));
|
||||
}
|
||||
|
||||
@ -69,6 +78,10 @@ public class Terrain implements Tag {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public float getHue() {
|
||||
return id / (float) MAX_ID.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
@ -177,4 +190,12 @@ public class Terrain implements Tag {
|
||||
public static Terrain volcanoPipe(Settings settings) {
|
||||
return new Terrain("volcano_pipe", 15, settings.terrain.volcano.weight);
|
||||
}
|
||||
|
||||
public static Optional<Terrain> get(String name) {
|
||||
return Optional.ofNullable(register.get(name));
|
||||
}
|
||||
|
||||
public static List<Terrain> getRegistered() {
|
||||
return new ArrayList<>(register.values());
|
||||
}
|
||||
}
|
||||
|
@ -26,20 +26,17 @@
|
||||
package com.terraforged.mod;
|
||||
|
||||
import com.terraforged.api.material.WGTags;
|
||||
import com.terraforged.core.util.concurrent.ThreadPool;
|
||||
import com.terraforged.feature.FeatureManager;
|
||||
import com.terraforged.mod.data.DataGen;
|
||||
import com.terraforged.mod.feature.feature.DiskFeature;
|
||||
import com.terraforged.mod.feature.tree.SaplingManager;
|
||||
import com.terraforged.mod.util.Environment;
|
||||
import net.minecraft.world.gen.feature.Feature;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
|
||||
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
|
||||
|
||||
/**
|
||||
* Author <dags@dags.me>
|
||||
@ -51,7 +48,6 @@ public class TerraForgedMod {
|
||||
@SubscribeEvent
|
||||
public static void setup(FMLCommonSetupEvent event) {
|
||||
Log.info("Common setup");
|
||||
MinecraftForge.EVENT_BUS.addListener(TerraForgedMod::onShutdown);
|
||||
WGTags.init();
|
||||
TerraWorld.init();
|
||||
SaplingManager.init();
|
||||
@ -69,8 +65,4 @@ public class TerraForgedMod {
|
||||
FeatureManager.registerTemplates(event);
|
||||
event.getRegistry().register(DiskFeature.INSTANCE);
|
||||
}
|
||||
|
||||
private static void onShutdown(FMLServerStoppingEvent event) {
|
||||
ThreadPool.shutdownCurrent();
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,17 @@ import net.minecraft.world.chunk.ChunkPrimer;
|
||||
import net.minecraft.world.chunk.ChunkSection;
|
||||
import net.minecraft.world.chunk.IChunk;
|
||||
import net.minecraft.world.gen.Heightmap;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
/**
|
||||
* A ChunkPrimer wrapper that handles setting BlockStates within the chunk & updating heightmaps accordingly
|
||||
*/
|
||||
public class FastChunk implements ChunkDelegate {
|
||||
|
||||
private static final int arraySize = 256;
|
||||
private static final int bitsPerEntry = 9;
|
||||
private static final long maxEntryValue = (1L << bitsPerEntry) - 1L;
|
||||
|
||||
private final int blockX;
|
||||
private final int blockZ;
|
||||
private final ChunkPrimer primer;
|
||||
@ -66,9 +71,56 @@ public class FastChunk implements ChunkDelegate {
|
||||
if (chunk instanceof FastChunk) {
|
||||
return chunk;
|
||||
}
|
||||
if (chunk instanceof ChunkPrimer) {
|
||||
if (chunk.getClass() == ChunkPrimer.class) {
|
||||
return new FastChunk((ChunkPrimer) chunk);
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public static void updateWGHeightmaps(IChunk chunk, BlockPos.Mutable pos) {
|
||||
int topY = chunk.getTopFilledSegment() + 15;
|
||||
long[] ocean = chunk.getHeightmap(Heightmap.Type.OCEAN_FLOOR_WG).getDataArray();
|
||||
long[] surface = chunk.getHeightmap(Heightmap.Type.WORLD_SURFACE_WG).getDataArray();
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
boolean flag = false;
|
||||
for (int y = topY; y >= 0; y--) {
|
||||
BlockState state = chunk.getBlockState(pos.setPos(x, y, z));
|
||||
if (state.getBlock() != Blocks.AIR) {
|
||||
if (!flag) {
|
||||
// WORLD_SURFACE_WG predicate is when block != air .: can set the height at this y value
|
||||
setAt(surface, index(x, z), y + 1);
|
||||
// flag = true means subsequent y values are ignored
|
||||
flag = true;
|
||||
}
|
||||
if (Heightmap.Type.OCEAN_FLOOR_WG.getHeightLimitPredicate().test(state)) {
|
||||
setAt(ocean, index(x, z), y + 1);
|
||||
// no more heightmaps to update at this x/z so can exit the y loop here
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from BitArray
|
||||
private static void setAt(long[] longArray, int index, int value) {
|
||||
Validate.inclusiveBetween(0L, (arraySize - 1), index);
|
||||
Validate.inclusiveBetween(0L, maxEntryValue, value);
|
||||
int i = index * bitsPerEntry;
|
||||
int j = i >> 6;
|
||||
int k = (index + 1) * bitsPerEntry - 1 >> 6;
|
||||
int l = i ^ j << 6;
|
||||
longArray[j] = longArray[j] & ~(maxEntryValue << l) | ((long) value & maxEntryValue) << l;
|
||||
if (j != k) {
|
||||
int i1 = 64 - l;
|
||||
int j1 = bitsPerEntry - i1;
|
||||
longArray[k] = longArray[k] >>> j1 << j1 | ((long) value & maxEntryValue) >> i1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int index(int x, int z) {
|
||||
return x + (z << 4);
|
||||
}
|
||||
}
|
||||
|
@ -187,6 +187,8 @@ public class TerraChunkGenerator extends ObfHelperChunkGenerator<GenerationSetti
|
||||
processor.decorate(ctx.buffer, ctx, px, py, pz);
|
||||
}
|
||||
});
|
||||
|
||||
FastChunk.updateWGHeightmaps(chunk, context.pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -32,20 +32,17 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import com.terraforged.core.settings.Settings;
|
||||
import com.terraforged.core.world.terrain.Terrain;
|
||||
import com.terraforged.core.world.terrain.Terrains;
|
||||
import net.minecraft.command.ISuggestionProvider;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TerrainArgType implements ArgumentType<Terrain> {
|
||||
|
||||
private final List<Terrain> terrains = getTerrains();
|
||||
private final List<Terrain> terrains = Terrain.getRegistered();
|
||||
|
||||
@Override
|
||||
public Terrain parse(StringReader reader) throws CommandSyntaxException {
|
||||
@ -79,39 +76,4 @@ public class TerrainArgType implements ArgumentType<Terrain> {
|
||||
new StringTextComponent(String.format(message, args))
|
||||
);
|
||||
}
|
||||
|
||||
private static List<Terrain> getTerrains() {
|
||||
Terrains terrains = Terrains.create(new Settings());
|
||||
List<Terrain> result = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < terrains.index.size(); i++) {
|
||||
Terrain terrain = terrains.index.get(i);
|
||||
result.add(terrain);
|
||||
if (dontMix(terrain, terrains)) {
|
||||
continue;
|
||||
}
|
||||
for (int j = i + 1; j < terrains.index.size(); j++) {
|
||||
Terrain other = terrains.index.get(j);
|
||||
if (dontMix(other, terrains)) {
|
||||
continue;
|
||||
}
|
||||
Terrain mix = new Terrain(terrain.getName() + "-" + other.getName(), -1);
|
||||
result.add(mix);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean dontMix(Terrain terrain, Terrains terrains) {
|
||||
return terrain == terrains.ocean
|
||||
|| terrain == terrains.deepOcean
|
||||
|| terrain == terrains.river
|
||||
|| terrain == terrains.riverBanks
|
||||
|| terrain == terrains.beach
|
||||
|| terrain == terrains.coast
|
||||
|| terrain == terrains.volcano
|
||||
|| terrain == terrains.volcanoPipe
|
||||
|| terrain == terrains.lake;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user