Merge pull request #164 from TerraForged/master
update branch to latest
This commit is contained in:
commit
bfb726d2d5
@ -1 +1 @@
|
||||
Subproject commit 5af4aff86ab3e3a362346bb91076d2bdb0206ca7
|
||||
Subproject commit 0da0d13c3dc8426b18a55107b42986e9d66387f1
|
@ -0,0 +1,57 @@
|
||||
package com.terraforged.core.region.gen;
|
||||
|
||||
import com.terraforged.core.region.Region;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FutureRegion implements Future<Region>, Callable<Region> {
|
||||
|
||||
private final int rx;
|
||||
private final int rz;
|
||||
private final RegionGenerator generator;
|
||||
|
||||
private volatile Region result;
|
||||
|
||||
public FutureRegion(int rx, int rz, RegionGenerator generator) {
|
||||
this.rx = rx;
|
||||
this.rz = rz;
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region call() {
|
||||
Region region = result;
|
||||
if (region == null) {
|
||||
region = generator.generateRegion(rx, rz);
|
||||
result = region;
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return result != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region get() {
|
||||
return call();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region get(long timeout, TimeUnit unit) {
|
||||
return get();
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.terraforged.core.region.gen;
|
||||
|
||||
import com.terraforged.core.region.Region;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FutureRegionZoom implements Future<Region>, Callable<Region> {
|
||||
|
||||
private final float cx;
|
||||
private final float cz;
|
||||
private final float zoom;
|
||||
private final boolean filters;
|
||||
private final RegionGenerator generator;
|
||||
|
||||
private volatile Region result;
|
||||
|
||||
public FutureRegionZoom(float cx, float cz, float zoom, boolean filters, RegionGenerator generator) {
|
||||
this.cx = cx;
|
||||
this.cz = cz;
|
||||
this.zoom = zoom;
|
||||
this.filters = filters;
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region call() {
|
||||
Region region = result;
|
||||
if (region == null) {
|
||||
region = generator.generateRegion(cx, cz, zoom, filters);
|
||||
result = region;
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return result != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region get() {
|
||||
return call();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region get(long timeout, TimeUnit unit) {
|
||||
return get();
|
||||
}
|
||||
}
|
@ -73,7 +73,7 @@ public class RegionCache implements RegionExtent, Disposable.Listener<Region> {
|
||||
|
||||
@Override
|
||||
public Region getRegion(int regionX, int regionZ) {
|
||||
Region region = queueRegion(regionX, regionZ).get();
|
||||
Region region = computeRegion(regionX, regionZ).get();
|
||||
|
||||
if (queuing) {
|
||||
queueNeighbours(regionX, regionZ);
|
||||
@ -82,9 +82,14 @@ public class RegionCache implements RegionExtent, Disposable.Listener<Region> {
|
||||
return region;
|
||||
}
|
||||
|
||||
private CacheEntry<Region> computeRegion(int regionX, int regionZ) {
|
||||
long id = NoiseUtil.seed(regionX, regionZ);
|
||||
return cache.computeIfAbsent(id, l -> generator.compute(regionX, regionZ));
|
||||
}
|
||||
|
||||
public CacheEntry<Region> queueRegion(int regionX, int regionZ) {
|
||||
long id = NoiseUtil.seed(regionX, regionZ);
|
||||
return cache.computeIfAbsent(id, l -> generator.generateCached(regionX, regionZ));
|
||||
return cache.computeIfAbsent(id, l -> generator.queue(regionX, regionZ));
|
||||
}
|
||||
|
||||
private void queueNeighbours(int regionX, int regionZ) {
|
||||
|
@ -97,8 +97,20 @@ public class RegionGenerator implements RegionExtent {
|
||||
return CompletableFuture.supplyAsync(() -> generateRegion(centerX, centerZ, zoom, filter), threadPool);
|
||||
}
|
||||
|
||||
public CacheEntry<Region> generateCached(int regionX, int regionZ) {
|
||||
return CacheEntry.supplyAsync(() -> generateRegion(regionX, regionZ), 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) {
|
||||
|
@ -3,14 +3,16 @@ package com.terraforged.core.util.concurrent.cache;
|
||||
import com.terraforged.core.util.concurrent.ThreadPool;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class CacheEntry<T> implements ExpiringEntry {
|
||||
|
||||
private volatile long timestamp;
|
||||
private final ForkJoinTask<T> task;
|
||||
private final Future<T> task;
|
||||
|
||||
public CacheEntry(ForkJoinTask<T> task) {
|
||||
public CacheEntry(Future<T> task) {
|
||||
this.task = task;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
@ -25,7 +27,19 @@ public class CacheEntry<T> implements ExpiringEntry {
|
||||
}
|
||||
|
||||
public T get() {
|
||||
return task.join();
|
||||
if (task instanceof ForkJoinTask) {
|
||||
return ((ForkJoinTask<T>) task).join();
|
||||
}
|
||||
|
||||
try {
|
||||
return task.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> CacheEntry<T> supply(Future<T> future) {
|
||||
return new CacheEntry<>(future);
|
||||
}
|
||||
|
||||
public static <T> CacheEntry<T> supplyAsync(Callable<T> callable, ThreadPool executor) {
|
||||
|
@ -163,9 +163,8 @@ public class River extends TerrainPopulator {
|
||||
// lerp the position's height to the riverbank height
|
||||
if (cell.value > bankHeight) {
|
||||
cell.value = NoiseUtil.lerp(cell.value, bankHeight, valleyAlpha);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean carveBanks(Cell<Terrain> cell, float banksAlpha, float bedHeight) {
|
||||
|
@ -63,10 +63,22 @@ public class BiomeProvider extends AbstractBiomeProvider {
|
||||
this.modifierManager = SetupHooks.setup(new BiomeModifierManager(context, biomeMap), context.copy());
|
||||
}
|
||||
|
||||
public TerraContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void lookupPos(int x, int z, Cell<Terrain> cell) {
|
||||
worldLookup.applyCell(cell, x, z);
|
||||
}
|
||||
|
||||
public Cell<Terrain> lookupPos(int x, int z) {
|
||||
return worldLookup.getCell(x, z);
|
||||
}
|
||||
|
||||
public boolean canSpawnAt(Cell<Terrain> cell) {
|
||||
return cell.tag != context.terrain.ocean && cell.tag != context.terrain.deepOcean && cell.value > context.levels.ground;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getNoiseBiome(int x, int y, int z) {
|
||||
x = (x << 2);
|
||||
|
@ -0,0 +1,43 @@
|
||||
package com.terraforged.mod.biome.spawn;
|
||||
|
||||
import com.terraforged.mod.Log;
|
||||
import com.terraforged.mod.biome.provider.BiomeProvider;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.gen.feature.ConfiguredFeature;
|
||||
import net.minecraft.world.gen.feature.Feature;
|
||||
import net.minecraft.world.gen.feature.IFeatureConfig;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE)
|
||||
public class SpawnHandler {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void createSpawn(WorldEvent.CreateSpawnPosition event) {
|
||||
if (event.getWorld() instanceof ServerWorld) {
|
||||
ServerWorld world =(ServerWorld) event.getWorld();
|
||||
if (world.getChunkProvider().getChunkGenerator().getBiomeProvider() instanceof BiomeProvider) {
|
||||
Log.info("Searching for world spawn position");
|
||||
BiomeProvider provider = (BiomeProvider) world.getChunkProvider().getChunkGenerator().getBiomeProvider();
|
||||
SpawnSearch search = new SpawnSearch(BlockPos.ZERO, provider);
|
||||
BlockPos spawn = search.get();
|
||||
|
||||
Log.info("Setting world spawn: {}", spawn);
|
||||
event.setCanceled(true);
|
||||
event.getWorld().getWorldInfo().setSpawn(spawn);
|
||||
|
||||
if (event.getSettings().isBonusChestEnabled()) {
|
||||
Log.info("Generating bonus chest");
|
||||
createBonusChest(world, spawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void createBonusChest(ServerWorld world, BlockPos pos) {
|
||||
ConfiguredFeature<?, ?> chest = Feature.BONUS_CHEST.withConfiguration(IFeatureConfig.NO_FEATURE_CONFIG);
|
||||
chest.place(world, world.getChunkProvider().getChunkGenerator(), world.rand, pos);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.terraforged.mod.biome.spawn;
|
||||
|
||||
import com.terraforged.core.cell.Cell;
|
||||
import com.terraforged.core.world.terrain.Terrain;
|
||||
import com.terraforged.mod.Log;
|
||||
import com.terraforged.mod.biome.provider.BiomeProvider;
|
||||
import com.terraforged.mod.command.search.Search;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class SpawnSearch extends Search {
|
||||
|
||||
private final BiomeProvider biomeProvider;
|
||||
private final Cell<Terrain> cell = new Cell<>();
|
||||
|
||||
public SpawnSearch(BlockPos center, BiomeProvider biomeProvider) {
|
||||
super(center, 0, 2048);
|
||||
this.biomeProvider = biomeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpacing() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(BlockPos pos) {
|
||||
biomeProvider.lookupPos(pos.getX(), pos.getZ(), cell);
|
||||
return biomeProvider.canSpawnAt(cell);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockPos success(BlockPos.Mutable pos) {
|
||||
pos.setY(biomeProvider.getContext().levels.scale(cell.value));
|
||||
Log.info("Found valid spawn position: {}", pos);
|
||||
return super.success(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockPos fail(BlockPos pos) {
|
||||
Log.info("Unable to find valid spawn position, defaulting x=0, z=0");
|
||||
return new BlockPos(0, biomeProvider.getContext().levels.groundLevel, 0);
|
||||
}
|
||||
}
|
@ -395,7 +395,7 @@ public class TerraChunkGenerator extends ObfHelperChunkGenerator<GenerationSetti
|
||||
.legacy(context.terraSettings.version == 0)
|
||||
.pool(ThreadPool.getPool())
|
||||
.factory(context.factory)
|
||||
.size(4, 2)
|
||||
.size(3, 2)
|
||||
.build()
|
||||
.toCache(false);
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package com.terraforged.mod.command;
|
||||
|
||||
public class Permissions {
|
||||
|
||||
public static final String QUERY = "terraforged.command.terra.query";
|
||||
public static final String DEBUG = "terraforged.command.terra.debug";
|
||||
public static final String DATA = "terraforged.command.terra.data";
|
||||
public static final String DEFAULTS = "terraforged.command.terra.defaults";
|
||||
public static final String LOCATE = "terraforged.command.terra.locate";
|
||||
}
|
@ -27,7 +27,6 @@ package com.terraforged.mod.command;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
@ -49,7 +48,6 @@ import com.terraforged.mod.data.DataGen;
|
||||
import com.terraforged.mod.settings.SettingsHelper;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.Commands;
|
||||
import net.minecraft.command.arguments.ArgumentSerializer;
|
||||
import net.minecraft.command.arguments.ArgumentTypes;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
@ -70,18 +68,21 @@ import net.minecraft.world.gen.ChunkGenerator;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
|
||||
import net.minecraftforge.server.permission.DefaultPermissionLevel;
|
||||
import net.minecraftforge.server.permission.PermissionAPI;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE)
|
||||
public class TerraCommand {
|
||||
|
||||
public static void init() {
|
||||
ArgumentTypes.register("terraforged:biome", BiomeArgType.class, new ArgumentSerializer<>(BiomeArgType::new));
|
||||
ArgumentTypes.register("terraforged:terrain", TerrainArgType.class, new ArgumentSerializer<>(TerrainArgType::new));
|
||||
ArgumentTypes.register("terraforged:biome", BiomeArgType.class, new BiomeArgType.Serializer());
|
||||
ArgumentTypes.register("terraforged:terrain", TerrainArgType.class, new TerrainArgType.Serializer());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@ -91,31 +92,59 @@ public class TerraCommand {
|
||||
}
|
||||
|
||||
public static void register(CommandDispatcher<CommandSource> dispatcher) {
|
||||
dispatcher.register(command());
|
||||
registerSimple(dispatcher);
|
||||
registerLocate(dispatcher);
|
||||
PermissionAPI.registerNode(Permissions.QUERY, DefaultPermissionLevel.OP, "Allows use of the query command");
|
||||
PermissionAPI.registerNode(Permissions.DATA, DefaultPermissionLevel.OP, "Allows use of the data command");
|
||||
PermissionAPI.registerNode(Permissions.DEFAULTS, DefaultPermissionLevel.OP, "Allows use of the defaults command");
|
||||
PermissionAPI.registerNode(Permissions.DEBUG, DefaultPermissionLevel.OP, "Allows use of the debug command");
|
||||
PermissionAPI.registerNode(Permissions.LOCATE, DefaultPermissionLevel.OP, "Allows use of the locate command");
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder<CommandSource> command() {
|
||||
return Commands.literal("terra")
|
||||
.requires(source -> source.hasPermissionLevel(2))
|
||||
private static void registerSimple(CommandDispatcher<CommandSource> dispatcher) {
|
||||
dispatcher.register(Commands.literal("terra")
|
||||
.then(Commands.literal("query")
|
||||
.requires(perm(Permissions.QUERY))
|
||||
.executes(TerraCommand::query))
|
||||
.then(Commands.literal("data")
|
||||
.requires(perm(Permissions.DATA))
|
||||
.then(Commands.literal("dump")
|
||||
.executes(TerraCommand::dump)))
|
||||
.then(Commands.literal("defaults")
|
||||
.requires(perm(Permissions.DEFAULTS))
|
||||
.then(Commands.literal("set")
|
||||
.executes(TerraCommand::setDefaults)))
|
||||
.then(Commands.literal("debug")
|
||||
.executes(TerraCommand::debugBiome))
|
||||
.requires(perm(Permissions.DEBUG))
|
||||
.executes(TerraCommand::debugBiome)));
|
||||
}
|
||||
|
||||
private static void registerLocate(CommandDispatcher<CommandSource> dispatcher) {
|
||||
dispatcher.register(Commands.literal("terra")
|
||||
.then(Commands.literal("locate")
|
||||
.requires(perm(Permissions.LOCATE))
|
||||
.then(Commands.argument("biome", BiomeArgType.biome())
|
||||
.executes(TerraCommand::findBiome)
|
||||
.then(Commands.argument("terrain", TerrainArgType.terrain())
|
||||
.executes(TerraCommand::findTerrainAndBiome)))
|
||||
.executes(TerraCommand::findBiome))));
|
||||
|
||||
dispatcher.register(Commands.literal("terra")
|
||||
.then(Commands.literal("locate")
|
||||
.requires(perm(Permissions.LOCATE))
|
||||
.then(Commands.argument("terrain", TerrainArgType.terrain())
|
||||
.executes(TerraCommand::findTerrain))));
|
||||
|
||||
dispatcher.register(Commands.literal("terra")
|
||||
.then(Commands.literal("locate")
|
||||
.requires(perm(Permissions.LOCATE))
|
||||
.then(Commands.argument("biome", BiomeArgType.biome())
|
||||
.then(Commands.argument("terrain", TerrainArgType.terrain())
|
||||
.executes(TerraCommand::findTerrainAndBiome)))));
|
||||
|
||||
dispatcher.register(Commands.literal("terra")
|
||||
.then(Commands.literal("locate")
|
||||
.requires(perm(Permissions.LOCATE))
|
||||
.then(Commands.argument("terrain", TerrainArgType.terrain())
|
||||
.executes(TerraCommand::findTerrain)
|
||||
.then(Commands.argument("biome", BiomeArgType.biome())
|
||||
.executes(TerraCommand::findTerrainAndBiome))));
|
||||
.executes(TerraCommand::findTerrainAndBiome)))));
|
||||
}
|
||||
|
||||
private static int query(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
@ -194,7 +223,7 @@ public class TerraCommand {
|
||||
WorldGenerator worldGenerator = terraContext.factory.get();
|
||||
Search search = new TerrainSearchTask(pos, worldGenerator, target);
|
||||
doSearch(server, playerID, search);
|
||||
context.getSource().sendFeedback(new StringTextComponent("Searching..."), false);
|
||||
context.getSource().sendFeedback(new StringTextComponent("Locating terrain..."), false);
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
@ -213,7 +242,7 @@ public class TerraCommand {
|
||||
IWorldReader reader = context.getSource().asPlayer().getServerWorld();
|
||||
Search search = new BiomeSearchTask(pos, reader, biome);
|
||||
doSearch(server, playerID, search);
|
||||
context.getSource().sendFeedback(new StringTextComponent("Searching..."), false);
|
||||
context.getSource().sendFeedback(new StringTextComponent("Locating biome..."), false);
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
@ -237,7 +266,7 @@ public class TerraCommand {
|
||||
Search terrainSearch = new TerrainSearchTask(pos, worldGenerator, target);
|
||||
Search search = new BothSearchTask(pos, biomeSearch, terrainSearch);
|
||||
doSearch(server, playerID, search);
|
||||
context.getSource().sendFeedback(new StringTextComponent("Searching..."), false);
|
||||
context.getSource().sendFeedback(new StringTextComponent("Locating biome & terrain..."), false);
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
@ -275,14 +304,31 @@ public class TerraCommand {
|
||||
// the terrain parsed from the command will not be the same instance as used in the
|
||||
// world generator, so find the matching instance by name
|
||||
private static Terrain getTerrainInstance(Terrain find, Terrains terrains) {
|
||||
// search for exact match first
|
||||
for (Terrain t : terrains.index) {
|
||||
if (t.getName().equals(find.getName())) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
// find a mixed terrain as a fallback
|
||||
for (Terrain t : terrains.index) {
|
||||
if (t.getName().contains("-") && t.getName().contains(find.getName())) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return find;
|
||||
}
|
||||
|
||||
private static Predicate<CommandSource> perm(String node) {
|
||||
return source -> {
|
||||
try {
|
||||
return PermissionAPI.hasPermission(source.asPlayer(), node);
|
||||
} catch (Throwable t) {
|
||||
return source.hasPermissionLevel(2);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static BiomeProvider getBiomeProvider(CommandContext<CommandSource> context) {
|
||||
return (BiomeProvider) context.getSource().getWorld().getChunkProvider().getChunkGenerator().getBiomeProvider();
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package com.terraforged.mod.command.arg;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
@ -33,8 +34,9 @@ import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import net.minecraft.command.ISuggestionProvider;
|
||||
import net.minecraft.command.arguments.IArgumentSerializer;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
@ -45,9 +47,28 @@ public class BiomeArgType implements ArgumentType<Biome> {
|
||||
|
||||
@Override
|
||||
public Biome parse(StringReader reader) throws CommandSyntaxException {
|
||||
ResourceLocation resourcelocation = ResourceLocation.read(reader);
|
||||
return Registry.BIOME.getValue(resourcelocation)
|
||||
.orElseThrow(() -> createException("Invalid biome", "%s is not a valid biome", resourcelocation));
|
||||
int cursor = reader.getCursor();
|
||||
String raw = reader.getString().substring(cursor);
|
||||
|
||||
if (raw.indexOf(':') == -1) {
|
||||
reader.setCursor(cursor);
|
||||
throw createException("Invalid biome", "%s is not a valid biome", raw);
|
||||
}
|
||||
|
||||
ResourceLocation resourcelocation = ResourceLocation.tryCreate(raw);
|
||||
if (resourcelocation == null) {
|
||||
reader.setCursor(cursor);
|
||||
throw createException("Invalid biome", "%s is not a valid biome", raw);
|
||||
}
|
||||
|
||||
if (!ForgeRegistries.BIOMES.containsKey(resourcelocation)) {
|
||||
reader.setCursor(cursor);
|
||||
throw createException("Invalid biome", "%s is not a valid biome", resourcelocation);
|
||||
}
|
||||
|
||||
reader.setCursor(reader.getString().length());
|
||||
|
||||
return ForgeRegistries.BIOMES.getValue(resourcelocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -69,4 +90,22 @@ public class BiomeArgType implements ArgumentType<Biome> {
|
||||
public static <S> Biome getBiome(CommandContext<S> context, String name) {
|
||||
return context.getArgument(name, Biome.class);
|
||||
}
|
||||
|
||||
public static class Serializer implements IArgumentSerializer<BiomeArgType> {
|
||||
|
||||
@Override
|
||||
public void write(BiomeArgType type, PacketBuffer buffer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeArgType read(PacketBuffer buffer) {
|
||||
return new BiomeArgType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(BiomeArgType type, JsonObject json) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package com.terraforged.mod.command.arg;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
@ -32,8 +33,12 @@ 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.command.arguments.IArgumentSerializer;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
|
||||
import java.util.List;
|
||||
@ -42,7 +47,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class TerrainArgType implements ArgumentType<Terrain> {
|
||||
|
||||
private final List<Terrain> terrains = Terrain.getRegistered();
|
||||
private final List<Terrain> terrains = createTerrainList();
|
||||
|
||||
@Override
|
||||
public Terrain parse(StringReader reader) throws CommandSyntaxException {
|
||||
@ -76,4 +81,26 @@ public class TerrainArgType implements ArgumentType<Terrain> {
|
||||
new StringTextComponent(String.format(message, args))
|
||||
);
|
||||
}
|
||||
|
||||
private static List<Terrain> createTerrainList() {
|
||||
return Terrains.create(new Settings()).index;
|
||||
}
|
||||
|
||||
public static class Serializer implements IArgumentSerializer<TerrainArgType> {
|
||||
|
||||
@Override
|
||||
public void write(TerrainArgType type, PacketBuffer buffer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerrainArgType read(PacketBuffer buffer) {
|
||||
return new TerrainArgType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(TerrainArgType type, JsonObject json) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,14 @@ public abstract class Search implements Supplier<BlockPos> {
|
||||
return 16;
|
||||
}
|
||||
|
||||
protected BlockPos success(BlockPos.Mutable pos) {
|
||||
return pos.toImmutable();
|
||||
}
|
||||
|
||||
protected BlockPos fail(BlockPos pos) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos get() {
|
||||
int radius = maxRadius;
|
||||
@ -60,7 +68,7 @@ public abstract class Search implements Supplier<BlockPos> {
|
||||
pos.setPos(center.getX() + (x * getSpacing()), center.getY(), center.getZ() + (z * getSpacing()));
|
||||
if (center.distanceSq(pos) >= minRadius2) {
|
||||
if (test(pos)) {
|
||||
return pos.toImmutable();
|
||||
return success(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,7 +83,7 @@ public abstract class Search implements Supplier<BlockPos> {
|
||||
z += dz;
|
||||
}
|
||||
|
||||
return BlockPos.ZERO;
|
||||
return fail(BlockPos.ZERO);
|
||||
}
|
||||
|
||||
public abstract boolean test(BlockPos pos);
|
||||
|
@ -30,12 +30,24 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.datafixers.Dynamic;
|
||||
import com.mojang.datafixers.types.JsonOps;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.gen.GenerationStage;
|
||||
import net.minecraft.world.gen.feature.ConfiguredFeature;
|
||||
import net.minecraft.world.gen.feature.IFeatureConfig;
|
||||
import net.minecraft.world.gen.feature.jigsaw.JigsawManager;
|
||||
import net.minecraft.world.gen.feature.jigsaw.JigsawPattern;
|
||||
import net.minecraft.world.gen.feature.jigsaw.JigsawPatternRegistry;
|
||||
import net.minecraft.world.gen.feature.jigsaw.JigsawPiece;
|
||||
import net.minecraft.world.gen.feature.structure.Structure;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class WorldGenFeatures extends DataGen {
|
||||
|
||||
@ -43,7 +55,9 @@ public class WorldGenFeatures extends DataGen {
|
||||
if (dataDir.exists() || dataDir.mkdirs()) {
|
||||
for (Biome biome : ForgeRegistries.BIOMES) {
|
||||
genBiomeFeatures(dataDir, biome);
|
||||
genBiomeStructures(dataDir, biome);
|
||||
}
|
||||
genBiomeJigsaws(dataDir);
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,4 +79,55 @@ public class WorldGenFeatures extends DataGen {
|
||||
write(root, writer);
|
||||
});
|
||||
}
|
||||
|
||||
private static void genBiomeStructures(File dir, Biome biome) {
|
||||
write(new File(dir, getJsonPath("structures", biome.getRegistryName())), writer -> {
|
||||
JsonObject root = new JsonObject();
|
||||
for (Map.Entry<String, Structure<?>> e : Structure.STRUCTURES.entrySet()) {
|
||||
JsonArray array = new JsonArray();
|
||||
IFeatureConfig config = biome.getStructureConfig(e.getValue());
|
||||
if (config == null) {
|
||||
continue;
|
||||
}
|
||||
JsonElement element = config.serialize(JsonOps.INSTANCE).getValue();
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("structure", e.getValue().getRegistryName() + "");
|
||||
object.add("config", element);
|
||||
array.add(object);
|
||||
}
|
||||
write(root, writer);
|
||||
});
|
||||
}
|
||||
|
||||
private static void genBiomeJigsaws(File dir) {
|
||||
Random random = new Random();
|
||||
write(new File(dir, "jigsaws.json"), writer -> {
|
||||
JsonObject root = new JsonObject();
|
||||
for (Map.Entry<ResourceLocation, JigsawPattern> e : getJigsawRegistry().entrySet()) {
|
||||
JsonArray array = new JsonArray();
|
||||
List<JigsawPiece> pieces = e.getValue().getShuffledPieces(random);
|
||||
for (JigsawPiece piece : pieces) {
|
||||
JsonElement element = piece.serialize(JsonOps.INSTANCE).getValue();
|
||||
array.add(element);
|
||||
}
|
||||
root.add(e.getKey().toString(), array);
|
||||
}
|
||||
write(root, writer);
|
||||
});
|
||||
}
|
||||
|
||||
private static Map<ResourceLocation, JigsawPattern> getJigsawRegistry() {
|
||||
try {
|
||||
for (Field field : JigsawPatternRegistry.class.getDeclaredFields()) {
|
||||
if (field.getType() == Map.class) {
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(JigsawManager.REGISTRY);
|
||||
return (Map<ResourceLocation, JigsawPattern>) value;
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ import net.minecraft.world.gen.feature.Feature;
|
||||
import net.minecraft.world.gen.feature.NoFeatureConfig;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.event.world.SaplingGrowTreeEvent;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@ -54,7 +55,7 @@ public class SaplingListener {
|
||||
{new Vec3i(-1, 0, 0), new Vec3i(-1, 0, 1), new Vec3i(0, 0, 1)},
|
||||
};
|
||||
|
||||
@SubscribeEvent
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
public static void onTreeGrow(SaplingGrowTreeEvent event) {
|
||||
// ignore if client
|
||||
if (event.getWorld().isRemote()) {
|
||||
|
@ -53,6 +53,6 @@ public class StructurePage extends BasePage {
|
||||
@Override
|
||||
public void init(OverlayScreen parent) {
|
||||
Column left = getColumn(0);
|
||||
addElements(left.left, left.top, left, structureSettings, false, left.scrollPane::addButton, this::update);
|
||||
addElements(left.left, left.top, left, structureSettings, true, left.scrollPane::addButton, this::update);
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import com.terraforged.core.region.Region;
|
||||
import com.terraforged.core.region.gen.RegionGenerator;
|
||||
import com.terraforged.core.settings.Settings;
|
||||
import com.terraforged.core.util.concurrent.ThreadPool;
|
||||
import com.terraforged.core.util.concurrent.cache.CacheEntry;
|
||||
import com.terraforged.core.world.GeneratorContext;
|
||||
import com.terraforged.core.world.WorldGeneratorFactory;
|
||||
import com.terraforged.core.world.terrain.Terrain;
|
||||
@ -48,8 +49,6 @@ import net.minecraft.nbt.CompoundNBT;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class Preview extends Button {
|
||||
|
||||
@ -68,7 +67,7 @@ public class Preview extends Button {
|
||||
private int seed;
|
||||
private long lastUpdate = 0L;
|
||||
private Settings settings = new Settings();
|
||||
private Future<Region> task = null;
|
||||
private CacheEntry<Region> task = null;
|
||||
private Region region = null;
|
||||
|
||||
private String[] labels = {"Area: ", "Terrain: ", "Biome: "};
|
||||
@ -131,10 +130,6 @@ public class Preview extends Button {
|
||||
try {
|
||||
region = task.get();
|
||||
render(region);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.getCause().printStackTrace();
|
||||
} finally {
|
||||
task = null;
|
||||
}
|
||||
@ -195,7 +190,7 @@ public class Preview extends Button {
|
||||
texture.updateDynamicTexture();
|
||||
}
|
||||
|
||||
private Future<Region> generate(Settings settings, CompoundNBT prevSettings) {
|
||||
private CacheEntry<Region> generate(Settings settings, CompoundNBT prevSettings) {
|
||||
NBTHelper.deserialize(prevSettings, previewSettings);
|
||||
settings.generator.seed = seed;
|
||||
this.settings = settings;
|
||||
@ -208,7 +203,7 @@ public class Preview extends Button {
|
||||
.size(FACTOR, 0)
|
||||
.build();
|
||||
|
||||
return renderer.generate(offsetX, offsetZ, 101 - previewSettings.zoom, true);
|
||||
return renderer.queue(offsetX, offsetZ, 101 - previewSettings.zoom, true);
|
||||
}
|
||||
|
||||
private void updateLegend(int mx ,int my) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"biomes": [
|
||||
"minecraft:jungle",
|
||||
"minecraft:modified_jungle",
|
||||
"minecraft:bamboo_jungle"
|
||||
],
|
||||
"match": [
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"biomes": [
|
||||
"minecraft:jungle_edge"
|
||||
"minecraft:jungle_edge",
|
||||
"minecraft:modified_jungle_edge"
|
||||
],
|
||||
"match": [
|
||||
[
|
||||
|
@ -1,7 +1,19 @@
|
||||
{
|
||||
"biomes": [
|
||||
"minecraft:plains",
|
||||
"minecraft:river"
|
||||
"minecraft:sunflower_plains",
|
||||
"minecraft:river",
|
||||
"minecraft:frozen_river",
|
||||
"minecraft:ocean",
|
||||
"minecraft:deep_ocean",
|
||||
"minecraft:warm_ocean",
|
||||
"minecraft:deep_warm_ocean",
|
||||
"minecraft:lukewarm_ocean",
|
||||
"minecraft:deep_lukewarm_ocean",
|
||||
"minecraft:cold_ocean",
|
||||
"minecraft:deep_cold_ocean",
|
||||
"minecraft:frozen_ocean",
|
||||
"minecraft:deep_frozen_ocean"
|
||||
],
|
||||
"match": [
|
||||
[
|
||||
|
Loading…
Reference in New Issue
Block a user