begin work on janky pregenerator

This commit is contained in:
dfsek 2021-01-04 00:21:49 -07:00
parent 3c12a98ef3
commit ee093397d3
17 changed files with 631 additions and 3 deletions

1
.gitignore vendored
View File

@ -142,3 +142,4 @@ build
/lang/
/packs/
/config.yml
/region/

View File

@ -0,0 +1,27 @@
package com.dfsek.terra.api.structures.structure.buffer.items.state;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedItem;
@SuppressWarnings("unchecked")
public abstract class BufferedStateManipulator<T extends BlockState> implements BufferedItem {
private final TerraPlugin main;
protected BufferedStateManipulator(TerraPlugin main) {
this.main = main;
}
@Override
public void paste(Location origin) {
BlockState state = origin.getBlock().getState();
try {
apply((T) state);
} catch(ClassCastException e) {
main.getLogger().warning("Could not find expected BlockState at " + origin + "; found " + origin.getBlock().getBlockData().getAsString());
}
}
public abstract void apply(T state);
}

View File

@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Random;
public interface TerraChunkGenerator {
ChunkGenerator.ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, ChunkGenerator.ChunkData original);
ChunkGenerator.ChunkData generateChunkData(@NotNull World world, Random random, int x, int z, ChunkGenerator.ChunkData original);
void generateBiomes(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome);

View File

@ -86,7 +86,7 @@ public class MasterChunkGenerator implements TerraChunkGenerator {
@Override
@SuppressWarnings({"try"})
public ChunkGenerator.ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, ChunkGenerator.ChunkData chunk) {
public ChunkGenerator.ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkGenerator.ChunkData chunk) {
TerraWorld tw = main.getWorld(world);
com.dfsek.terra.api.world.biome.BiomeGrid grid = tw.getGrid();
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {

View File

@ -0,0 +1,26 @@
import com.dfsek.terra.configureCommon
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
`java-library`
}
configureCommon()
group = "com.dfsek.terra"
repositories {
mavenCentral()
maven { url = uri("https://jitpack.io/") }
}
dependencies {
"shadedApi"(project(":common"))
"shadedImplementation"("com.github.Querz:NBT:5.2") // Standalone NBT API
"shadedImplementation"("org.yaml:snakeyaml:1.27")
"shadedImplementation"("com.googlecode.json-simple:json-simple:1.1.1")
}
tasks.named<ShadowJar>("shadowJar") {
relocate("net.querz", "com.dfsek.terra.libs.nbt")
}

View File

@ -0,0 +1,18 @@
package com.dfsek.terra;
import com.dfsek.terra.region.Generator;
import java.io.IOException;
import java.util.concurrent.ThreadLocalRandom;
public class RegionGenerator {
public static void main(String[] args) throws IOException {
long seed;
if(args.length == 1) seed = Long.parseLong(args[0]);
else seed = ThreadLocalRandom.current().nextLong();
Generator generator = new Generator(seed);
generator.generate();
}
}

View File

@ -0,0 +1,111 @@
package com.dfsek.terra;
import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.api.GenericLoaders;
import com.dfsek.terra.api.lang.Language;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.Biome;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.config.base.PluginConfig;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.platform.RawBiome;
import com.dfsek.terra.platform.RawWorldHandle;
import com.dfsek.terra.registry.ConfigRegistry;
import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;
public class StandalonePlugin implements TerraPlugin {
private final ConfigRegistry registry = new ConfigRegistry();
private final PluginConfig config = new PluginConfig();
private final RawWorldHandle worldHandle = new RawWorldHandle();
@Override
public WorldHandle getWorldHandle() {
return worldHandle;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public TerraWorld getWorld(World world) {
return new TerraWorld(world, registry.get("DEFAULT"), this);
}
@Override
public Logger getLogger() {
return Logger.getLogger("Terra");
}
@Override
public PluginConfig getTerraConfig() {
return config;
}
@Override
public File getDataFolder() {
return new File(".");
}
@Override
public boolean isDebug() {
return true;
}
@Override
public Language getLanguage() {
try {
return new Language(new File(getDataFolder(), "lang/en_us.yml"));
} catch(IOException e) {
throw new IllegalArgumentException();
}
}
@Override
public ConfigRegistry getRegistry() {
return registry;
}
@Override
public void reload() {
throw new UnsupportedOperationException();
}
@Override
public ItemHandle getItemHandle() {
return null;
}
@Override
public void saveDefaultConfig() {
}
@Override
public String platformName() {
return "Standalone";
}
@Override
public void register(TypeRegistry registry) {
registry
.registerLoader(BlockData.class, (t, o, l) -> worldHandle.createBlockData((String) o))
.registerLoader(Biome.class, (t, o, l) -> new RawBiome(o.toString()))
.registerLoader(MaterialData.class, (t, o, l) -> worldHandle.createMaterialData((String) o));
new GenericLoaders(this).register(registry);
}
public void load() {
LangUtil.load("en_us", this);
registry.loadAll(this);
config.load(this);
}
}

View File

@ -0,0 +1,71 @@
package com.dfsek.terra.platform;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.MaterialData;
import net.querz.nbt.tag.CompoundTag;
public class Data implements BlockData, MaterialData {
private final CompoundTag data;
private final String noProp;
public Data(String data) {
this.data = new CompoundTag();
if(data.contains("[")) noProp = data.substring(0, data.indexOf('[')); // Strip properties for now TODO: actually do properties lol
else noProp = data;
this.data.putString("Name", noProp);
}
@Override
public MaterialData getMaterial() {
return this;
}
@Override
public boolean matches(MaterialData materialData) {
return ((Data) materialData).noProp.equals(noProp);
}
@Override
public boolean matches(BlockData other) {
return ((Data) other).noProp.equals(noProp);
}
@Override
public boolean isSolid() {
return !isAir(); //TODO: actual implementation
}
@Override
public boolean isAir() {
return noProp.equals("minecraft:air");
}
@Override
public double getMaxDurability() {
return 0;
}
@Override
public BlockData createBlockData() {
return this;
}
@Override
public BlockData clone() {
try {
return (BlockData) super.clone();
} catch(CloneNotSupportedException e) {
throw new Error(e);
}
}
@Override
public String getAsString() {
return noProp;
}
@Override
public CompoundTag getHandle() {
return data;
}
}

View File

@ -0,0 +1,41 @@
package com.dfsek.terra.platform;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.generator.ChunkGenerator;
import net.querz.mca.Chunk;
import net.querz.nbt.tag.CompoundTag;
import org.jetbrains.annotations.NotNull;
public class DirectChunkData implements ChunkGenerator.ChunkData {
private final Chunk delegate;
private final int offX;
private final int offZ;
public DirectChunkData(Chunk delegate, int offX, int offZ) {
this.delegate = delegate;
this.offX = offX;
this.offZ = offZ;
}
@Override
public Object getHandle() {
return delegate;
}
@Override
public int getMaxHeight() {
return 255;
}
@Override
public void setBlock(int x, int y, int z, @NotNull BlockData blockData) {
delegate.setBlockStateAt(x, y, z, ((Data) blockData).getHandle(), false);
}
@Override
public @NotNull BlockData getBlockData(int x, int y, int z) {
CompoundTag tag = delegate.getBlockStateAt(x, y, z);
if(tag == null) return new Data("minecraft:air");
return new Data(tag.getString("Name"));
}
}

View File

@ -0,0 +1,88 @@
package com.dfsek.terra.platform;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.entity.Entity;
import com.dfsek.terra.api.platform.world.entity.EntityType;
import java.io.File;
import java.util.UUID;
public class DirectWorld implements World {
private final long seed;
private final GenWrapper generator;
public DirectWorld(long seed, GenWrapper generator) {
this.seed = seed;
this.generator = generator;
}
@Override
public long getSeed() {
return seed;
}
@Override
public int getMaxHeight() {
return 255;
}
@Override
public ChunkGenerator getGenerator() {
return generator;
}
@Override
public String getName() {
return null;
}
@Override
public UUID getUID() {
return null;
}
@Override
public boolean isChunkGenerated(int x, int z) {
return false;
}
@Override
public Chunk getChunkAt(int x, int z) {
return null;
}
@Override
public File getWorldFolder() {
return null;
}
@Override
public Block getBlockAt(int x, int y, int z) {
return null;
}
@Override
public Block getBlockAt(Location l) {
return null;
}
@Override
public boolean generateTree(Location l, Tree vanillaTreeType) {
return false;
}
@Override
public Entity spawnEntity(Location location, EntityType entityType) {
return null;
}
@Override
public Object getHandle() {
return generator;
}
}

View File

@ -0,0 +1,67 @@
package com.dfsek.terra.platform;
import com.dfsek.terra.api.platform.generator.BlockPopulator;
import com.dfsek.terra.api.platform.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.BiomeGrid;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.generation.MasterChunkGenerator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class GenWrapper implements ChunkGenerator {
private final MasterChunkGenerator generator;
public GenWrapper(MasterChunkGenerator generator) {
this.generator = generator;
}
@Override
public Object getHandle() {
return generator;
}
@Override
public boolean isParallelCapable() {
return true;
}
@Override
public boolean shouldGenerateCaves() {
return true;
}
@Override
public boolean shouldGenerateDecorations() {
return true;
}
@Override
public boolean shouldGenerateMobs() {
return true;
}
@Override
public boolean shouldGenerateStructures() {
return true;
}
@Override
public ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome) {
throw new UnsupportedOperationException(); // gen is directly handled by Generator
}
@Override
public List<BlockPopulator> getDefaultPopulators(World world) {
return Collections.emptyList();
}
@Override
public @Nullable TerraChunkGenerator getTerraGenerator() {
return generator;
}
}

View File

@ -0,0 +1,16 @@
package com.dfsek.terra.platform;
import com.dfsek.terra.api.platform.world.Biome;
public class RawBiome implements Biome {
private final String id;
public RawBiome(String id) {
this.id = id;
}
@Override
public Object getHandle() {
return id;
}
}

View File

@ -0,0 +1,25 @@
package com.dfsek.terra.platform;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.world.Tree;
import java.util.Random;
import java.util.Set;
public class RawTree implements Tree { // TODO: implement
@Override
public Object getHandle() {
return null;
}
@Override
public boolean plant(Location l, Random r) {
return false;
}
@Override
public Set<MaterialData> getSpawnable() {
return null;
}
}

View File

@ -0,0 +1,45 @@
package com.dfsek.terra.platform;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.platform.world.entity.EntityType;
public class RawWorldHandle implements WorldHandle {
@Override
public void setBlockData(Block block, BlockData data, boolean physics) {
}
@Override
public BlockData getBlockData(Block block) {
return null;
}
@Override
public MaterialData getType(Block block) {
return null;
}
@Override
public BlockData createBlockData(String data) {
return new Data(data);
}
@Override
public MaterialData createMaterialData(String data) {
return new Data(data);
}
@Override
public Tree getTree(String id) {
return new RawTree();
}
@Override
public EntityType getEntity(String id) {
return null;
}
}

View File

@ -0,0 +1,87 @@
package com.dfsek.terra.region;
import com.dfsek.terra.StandalonePlugin;
import com.dfsek.terra.api.platform.generator.ChunkGenerator;
import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.generation.MasterChunkGenerator;
import com.dfsek.terra.generation.math.SamplerCache;
import com.dfsek.terra.platform.DirectChunkData;
import com.dfsek.terra.platform.DirectWorld;
import com.dfsek.terra.platform.GenWrapper;
import net.querz.mca.Chunk;
import net.querz.mca.MCAFile;
import net.querz.mca.MCAUtil;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Generator {
private final Map<Long, MCAFile> files = new HashMap<>();
private final long seed;
public Generator(long seed) {
this.seed = seed;
}
public void generate() throws IOException {
int rad = 50;
StandalonePlugin plugin = new StandalonePlugin();
plugin.load();
MasterChunkGenerator generator = new MasterChunkGenerator(plugin.getRegistry().get("DEFAULT"), plugin, new SamplerCache(plugin));
GenWrapper wrapper = new GenWrapper(generator);
int count = 0;
List<Double> times = new GlueList<>();
for(int cx = -rad; cx <= rad; cx++) {
for(int cz = -rad; cz <= rad; cz++) {
long start = System.nanoTime();
long key = (((long) MCAUtil.chunkToRegion(cx)) << 32) | (MCAUtil.chunkToRegion(cz) & 0xffffffffL);
int finalCx = cx;
int finalCz = cz;
MCAFile file = files.computeIfAbsent(key, k -> new MCAFile(MCAUtil.chunkToRegion(finalCx), MCAUtil.chunkToRegion(finalCz)));
Chunk chunk = Chunk.newChunk();
ChunkGenerator.ChunkData chunkData = new DirectChunkData(chunk, cx, cz);
generator.generateChunkData(new DirectWorld(seed, wrapper), null, cx, cz, chunkData);
file.setChunk(cx, cz, chunk);
long end = System.nanoTime() - start;
count++;
times.add((double) end / 1000000);
if(count % 200 == 0) {
double total = 0;
for(double d : times) total += d;
double avg = total / count;
double pct = ((double) count / (rad * rad * 2 * 2)) * 100D;
plugin.getLogger().info("Generated " + count + " chunks. " + (1 / avg) * 1000 + "cps; " + pct + "%");
}
}
}
for(Map.Entry<Long, MCAFile> entry : files.entrySet()) {
entry.getValue().cleanupPalettesAndBlockStates();
int x = (int) (entry.getKey() >> 32);
int z = (int) (long) entry.getKey();
File file = new File("region", MCAUtil.createNameFromRegionLocation(x, z));
file.getParentFile().mkdirs();
MCAUtil.write(entry.getValue(), file);
}
}
}

View File

@ -0,0 +1,5 @@
package com.dfsek.terra.region;
public class RegionWriter {
}

View File

@ -11,7 +11,7 @@ rootProject.name = "Terra"
include("common")
include("platforms:bukkit")
include("platforms:fabric")
include("platforms:region")
pluginManagement {
repositories {