start working on internal stuff

This commit is contained in:
dfsek
2021-06-02 15:21:03 -07:00
parent c0f1ccb66a
commit 74fdf9a18e
9 changed files with 341 additions and 44 deletions

View File

@@ -3,6 +3,7 @@ import com.dfsek.terra.configureCommon
plugins {
java
id("org.spongepowered.plugin").version("0.9.0")
id("org.spongepowered.gradle.vanilla").version("0.2")
}
configureCommon()
@@ -25,4 +26,12 @@ sponge {
plugin {
id = "terra"
}
}
minecraft {
version("1.16.5")
runs {
server()
client()
}
}

View File

@@ -1,15 +0,0 @@
package com.dfsek.terra.sponge;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.sponge.world.block.data.SpongeBlockData;
import org.spongepowered.api.block.BlockState;
public final class SpongeAdapter {
public static BlockData adapt(BlockState state) {
return new SpongeBlockData(state);
}
public static BlockState adapt(BlockData data) {
return ((SpongeBlockData) data).getHandle();
}
}

View File

@@ -14,10 +14,12 @@ import com.dfsek.terra.api.event.events.config.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.platform.block.BlockData;
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.Tree;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.LockedRegistry;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.api.util.logging.DebugLogger;
import com.dfsek.terra.config.GenericLoaders;
import com.dfsek.terra.config.PluginConfig;
@@ -30,19 +32,28 @@ import com.dfsek.terra.registry.master.AddonRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.sponge.handle.SpongeItemHandle;
import com.dfsek.terra.sponge.handle.SpongeWorldHandle;
import com.dfsek.terra.sponge.intern.util.SpongeUtil;
import com.dfsek.terra.sponge.world.SpongeTree;
import com.dfsek.terra.world.TerraWorld;
import com.google.inject.Inject;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.dimension.DimensionType;
import org.spongepowered.api.Server;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.lifecycle.StartedEngineEvent;
import org.spongepowered.api.event.lifecycle.StartingEngineEvent;
import org.spongepowered.api.registry.Registry;
import org.spongepowered.api.world.biome.Biomes;
import org.spongepowered.api.world.server.ServerWorld;
import org.spongepowered.plugin.PluginContainer;
import org.spongepowered.plugin.jvm.Plugin;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Plugin("terra")
public class TerraSpongePlugin implements TerraPlugin {
@@ -53,7 +64,9 @@ public class TerraSpongePlugin implements TerraPlugin {
private final AddonRegistry addonRegistry;
private final LockedRegistry<TerraAddon> addonLockedRegistry;
private static TerraSpongePlugin INSTANCE;
private final Map<DimensionType, Pair<ServerWorld, TerraWorld>> worldMap = new HashMap<>();
private final PluginContainer plugin;
@@ -61,18 +74,22 @@ public class TerraSpongePlugin implements TerraPlugin {
private final WorldHandle worldHandle = new SpongeWorldHandle();
Profiler profiler = new ProfilerImpl();
private final Profiler profiler = new ProfilerImpl();
@Inject
public TerraSpongePlugin(PluginContainer plugin) {
this.plugin = plugin;
this.addonRegistry = new AddonRegistry(new SpongeAddon(this), this);
this.addonLockedRegistry = new LockedRegistry<>(addonRegistry);
INSTANCE = this;
}
public static TerraSpongePlugin getInstance() {
return INSTANCE;
}
@Listener
public void initialize(org.spongepowered.api.event.lifecycle.StartingEngineEvent<Server> event) {
public void initialize(StartingEngineEvent<Server> event) {
plugin.logger().info("Loading Terra...");
addonRegistry.loadAll();
configRegistry.loadAll(this);
@@ -81,7 +98,8 @@ public class TerraSpongePlugin implements TerraPlugin {
@Override
public void register(TypeRegistry registry) {
loaders.register(registry);
registry.registerLoader(BlockData.class, (t, o, l) -> worldHandle.createBlockData((String) o));
registry.registerLoader(BlockData.class, (t, o, l) -> worldHandle.createBlockData((String) o))
.registerLoader(Biome.class, (t, o, l) -> SpongeUtil.BIOME_FIXER.translate((String) o));
}
@Override
@@ -91,7 +109,13 @@ public class TerraSpongePlugin implements TerraPlugin {
@Override
public TerraWorld getWorld(World world) {
return null;
return getWorld(((LevelReader) world).dimensionType());
}
public TerraWorld getWorld(DimensionType type) {
TerraWorld world = worldMap.get(type).getRight();
if(world == null) throw new IllegalArgumentException("No world exists with dimension type " + type);
return world;
}
@Override

View File

@@ -0,0 +1,200 @@
package com.dfsek.terra.sponge.intern;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkData;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.locate.AsyncStructureFinder;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.sponge.TerraSpongePlugin;
import com.dfsek.terra.sponge.intern.util.SpongeAdapter;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.generation.generators.DefaultChunkGenerator3D;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.population.items.TerraStructure;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.jafama.FastMath;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.NaturalSpawner;
import net.minecraft.world.level.NoiseColumn;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.StructureSettings;
import net.minecraft.world.level.levelgen.WorldgenRandom;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.api.world.biome.provider.BiomeProvider;
import org.spongepowered.api.world.generation.config.structure.StructureGenerationConfig;
import org.spongepowered.api.world.server.ServerWorld;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class SpongeChunkGeneratorWrapper extends ChunkGenerator implements GeneratorWrapper {
private final long seed;
private final DefaultChunkGenerator3D delegate;
private final TerraBiomeSource biomeSource;
public static final Codec<ConfigPack> PACK_CODEC = (RecordCodecBuilder.create(config -> config.group(
Codec.STRING.fieldOf("pack").forGetter(pack -> pack.getTemplate().getID())
).apply(config, config.stable(TerraSpongePlugin.getInstance().getConfigRegistry()::get))));
public static final Codec<SpongeChunkGeneratorWrapper> CODEC = RecordCodecBuilder.create(instance -> instance.group(
TerraBiomeSource.CODEC.fieldOf("biome_source").forGetter(generator -> generator.biomeSource),
Codec.LONG.fieldOf("seed").stable().forGetter(generator -> generator.seed),
PACK_CODEC.fieldOf("pack").stable().forGetter(generator -> generator.pack))
.apply(instance, instance.stable(SpongeChunkGeneratorWrapper::new)));
private final ConfigPack pack;
public ConfigPack getPack() {
return pack;
}
private DimensionType dimensionType;
public SpongeChunkGeneratorWrapper(TerraBiomeSource biomeSource, long seed, ConfigPack configPack) {
super(biomeSource, new StructureSettings(configPack.getTemplate().vanillaStructures()));
this.pack = configPack;
this.delegate = new DefaultChunkGenerator3D(pack, TerraSpongePlugin.getInstance());
delegate.getMain().logger().info("Loading world with config pack " + pack.getTemplate().getID());
this.biomeSource = biomeSource;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return CODEC;
}
@Override
public @NotNull ChunkGenerator withSeed(long seed) {
return new SpongeChunkGeneratorWrapper((TerraBiomeSource) this.biomeSource.withSeed(seed), seed, pack);
}
@Override
public void buildSurfaceAndBedrock(WorldGenRegion worldGenRegion, ChunkAccess chunkAccess) {
}
@Nullable
@Override
public BlockPos findNearestMapFeature(ServerLevel world, StructureFeature<?> feature, BlockPos center, int param3, boolean param4) {
if(!pack.getTemplate().disableStructures()) {
String name = Objects.requireNonNull(Registry.STRUCTURE_FEATURE.getKey(feature)).toString();
TerraWorld terraWorld = TerraSpongePlugin.getInstance().getWorld((World) world);
TerraStructure located = pack.getStructure(pack.getTemplate().getLocatable().get(name));
if(located != null) {
CompletableFuture<BlockPos> result = new CompletableFuture<>();
AsyncStructureFinder finder = new AsyncStructureFinder(terraWorld.getBiomeProvider(), located, SpongeAdapter.adapt(center).toLocation((World) world), 0, 500, location -> {
result.complete(SpongeAdapter.adapt(location));
}, TerraSpongePlugin.getInstance());
finder.run(); // Do this synchronously.
try {
return result.get();
} catch(InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}
return super.findNearestMapFeature(world, feature, center, param3, param4);
}
@Override
public boolean hasStronghold(@NotNull ChunkPos p_235952_1_) {
if(pack.getTemplate().vanillaStructures()) return super.hasStronghold(p_235952_1_);
return false;
}
@Override
public void createStructures(RegistryAccess param0, StructureFeatureManager param1, ChunkAccess param2, StructureManager param3, long param4) {
if(pack.getTemplate().vanillaStructures()) super.createStructures(param0, param1, param2, param3, param4);
}
@Override
public void applyCarvers(long param0, BiomeManager param1, ChunkAccess param2, GenerationStep.Carving param3) {
if(pack.getTemplate().vanillaCaves()) super.applyCarvers(param0, param1, param2, param3);
}
@Override
public void fillFromNoise(@NotNull LevelAccessor world, @NotNull StructureFeatureManager p_230352_2_, @NotNull ChunkAccess chunk) {
delegate.generateChunkData((World) world, new FastRandom(), chunk.getPos().x, chunk.getPos().z, (ChunkData) chunk);
}
@Override
public int getBaseHeight(int x, int z, Heightmap.@NotNull Types p_222529_3_) {
TerraWorld world = TerraSpongePlugin.getInstance().getWorld(dimensionType);
Sampler sampler = world.getConfig().getSamplerCache().getChunk(FastMath.floorDiv(x, 16), FastMath.floorDiv(z, 16));
int cx = FastMath.floorMod(x, 16);
int cz = FastMath.floorMod(z, 16);
int height = world.getWorld().getMaxHeight();
while(height >= 0 && sampler.sample(cx, height - 1, cz) < 0) height--;
return height;
}
@Override
public @NotNull BlockGetter getBaseColumn(int x, int z) {
TerraWorld world = TerraSpongePlugin.getInstance().getWorld(dimensionType);
int height = getBaseHeight(x, z, Heightmap.Types.WORLD_SURFACE);
BlockState[] array = new BlockState[256];
for(int y = 255; y >= 0; y--) {
if(y > height) {
if(y > ((UserDefinedBiome) world.getBiomeProvider().getBiome(x, z)).getConfig().getSeaLevel()) {
array[y] = Blocks.AIR.defaultBlockState();
} else {
array[y] = Blocks.WATER.defaultBlockState();
}
} else {
array[y] = Blocks.STONE.defaultBlockState();
}
}
return new NoiseColumn(array);
}
@Override
public void spawnOriginalMobs(WorldGenRegion region) {
if(pack.getTemplate().vanillaMobs()) {
int cx = region.getCenterX();
int cy = region.getCenterZ();
Biome biome = region.getBiome((new ChunkPos(cx, cy)).getWorldPosition());
WorldgenRandom chunkRandom = new WorldgenRandom();
chunkRandom.setDecorationSeed(region.getSeed(), cx << 4, cy << 4);
NaturalSpawner.spawnMobsForChunkGeneration(region, biome, cx, cy, chunkRandom);
}
}
@Override
public TerraChunkGenerator getHandle() {
return delegate;
}
public void setDimensionType(DimensionType dimensionType) {
this.dimensionType = dimensionType;
}
}

View File

@@ -0,0 +1,63 @@
package com.dfsek.terra.sponge.intern;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.sponge.TerraSpongePlugin;
import com.dfsek.terra.sponge.intern.util.SpongeUtil;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.Registry;
import net.minecraft.resources.RegistryLookupCodec;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class TerraBiomeSource extends BiomeSource {
public static final Codec<ConfigPack> PACK_CODEC = (RecordCodecBuilder.create(config -> config.group(
Codec.STRING.fieldOf("pack").forGetter(pack -> pack.getTemplate().getID())
).apply(config, config.stable(TerraSpongePlugin.getInstance().getConfigRegistry()::get))));
public static final Codec<TerraBiomeSource> CODEC = RecordCodecBuilder.create(instance -> instance.group(
RegistryLookupCodec.create(Registry.BIOME_REGISTRY).forGetter(source -> source.biomeRegistry),
Codec.LONG.fieldOf("seed").stable().forGetter(source -> source.seed),
PACK_CODEC.fieldOf("pack").stable().forGetter(source -> source.pack))
.apply(instance, instance.stable(TerraBiomeSource::new)));
private final Registry<Biome> biomeRegistry;
private final long seed;
private final BiomeProvider grid;
private final ConfigPack pack;
public TerraBiomeSource(Registry<Biome> biomes, long seed, ConfigPack pack) {
super(biomes.stream().collect(Collectors.toList()));
this.biomeRegistry = biomes;
this.seed = seed;
this.grid = pack.getBiomeProviderBuilder().build(seed);
this.pack = pack;
}
@Override
protected @NotNull Codec<TerraBiomeSource> codec() {
return CODEC;
}
@Override
public BiomeSource withSeed(long seed) {
return new TerraBiomeSource(this.biomeRegistry, seed, pack);
}
@Override
public @NotNull Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) {
UserDefinedBiome biome = (UserDefinedBiome) grid.getBiome(biomeX << 2, biomeZ << 2);
return Objects.requireNonNull(biomeRegistry.get(new ResourceLocation("terra", SpongeUtil.createBiomeID(pack, biome.getID()))));
}
}

View File

@@ -0,0 +1,6 @@
/**
* Stuff that accesses the internal server.
* <p>
* Should be replaced with API stuff when API is complete.
*/
package com.dfsek.terra.sponge.intern;

View File

@@ -0,0 +1,14 @@
package com.dfsek.terra.sponge.intern.util;
import com.dfsek.terra.api.math.vector.Vector3;
import net.minecraft.core.BlockPos;
public final class SpongeAdapter {
public static Vector3 adapt(BlockPos pos) {
return new Vector3(pos.getX(), pos.getY(), pos.getZ());
}
public static BlockPos adapt(Vector3 vec) {
return new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ());
}
}

View File

@@ -0,0 +1,21 @@
package com.dfsek.terra.sponge.intern.util;
import com.dfsek.terra.api.transform.Transformer;
import com.dfsek.terra.api.transform.Validator;
import com.dfsek.terra.config.pack.ConfigPack;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import java.util.Locale;
public final class SpongeUtil {
public static String createBiomeID(ConfigPack pack, String biomeID) {
return pack.getTemplate().getID().toLowerCase() + "/" + biomeID.toLowerCase(Locale.ROOT);
}
public static final Transformer<String, Biome> BIOME_FIXER = new Transformer.Builder<String, Biome>()
.addTransform(id -> BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(id)), Validator.notNull())
.addTransform(id -> BuiltinRegistries.BIOME.get(ResourceLocation.tryParse("minecraft:" + id.toLowerCase())), Validator.notNull()).build();
}

View File

@@ -1,25 +0,0 @@
package com.dfsek.terra.sponge.world.generator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import org.spongepowered.api.world.biome.provider.BiomeProvider;
import org.spongepowered.api.world.generation.ChunkGenerator;
import org.spongepowered.api.world.generation.config.structure.StructureGenerationConfig;
public class SpongeChunkGeneratorWrapper implements ChunkGenerator, GeneratorWrapper {
@Override
public TerraChunkGenerator getHandle() {
return null;
}
@Override
public BiomeProvider biomeProvider() {
return null;
}
@Override
public StructureGenerationConfig structureConfig() {
return null;
}
}