Compare commits

..

4 Commits

Author SHA1 Message Date
Astrashh 3527eafbca Use logger in Gradle over println (#434)
* Log info instead of println in gradle scripts

* Missed buildSrc printlns
2023-11-25 00:59:25 +00:00
Astrashh 09ee0eccba Invert exposed ore logic (#433)
* Invert exposed ore logic

* Bump ore addon version
2023-11-24 00:48:17 +00:00
Zoë 58fae9fee3 fix fabric dev env 2023-11-23 16:42:45 -07:00
Astrash a2c51e99c2 Bump version to 6.4.1 2023-11-21 13:36:40 +11:00
190 changed files with 4144 additions and 1797 deletions
-47
View File
@@ -1,47 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
name: Gradle Build
on: [ pull_request ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Set up JDK 17
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
with:
java-version: '17'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- uses: burrunan/gradle-cache-action@03c71a8ba93d670980695505f48f49daf43704a6
name: Build Terra
with:
# Specifies arguments for Gradle execution
# If arguments is missing or empty, then Gradle is not executed
arguments: build
# arguments can be multi-line for better readability
# arguments: |
# --no-paralell
# build
# -x test
# Gradle version to use for execution:
# wrapper (default), current, rc, nightly, release-nightly, or
# versions like 6.6 (see https://services.gradle.org/versions/all)
gradle-version: wrapper
# Properties are passed as -Pname=value
properties: |
kotlin.js.compiler=ir
kotlin.parallel.tasks.in.project=true
-2
View File
@@ -249,5 +249,3 @@ nbdist/
platforms/**/run/**
#Vale Config File
**/.vale.ini
+3 -3
View File
@@ -1,8 +1,8 @@
preRelease(true)
versionProjects(":common:api", version("6.5.0"))
versionProjects(":common:implementation", version("6.5.0"))
versionProjects(":platforms", version("6.5.0"))
versionProjects(":common:api", version("6.4.1"))
versionProjects(":common:implementation", version("6.4.1"))
versionProjects(":platforms", version("6.4.1"))
allprojects {
+4 -4
View File
@@ -17,10 +17,10 @@ repositories {
dependencies {
//TODO Allow pulling from Versions.kt
implementation("com.github.johnrengelman", "shadow", "8.1.1")
implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "1.5.11")
implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "1.5.6")
implementation("org.ow2.asm", "asm", "9.6")
implementation("org.ow2.asm", "asm-tree", "9.6")
implementation("com.dfsek.tectonic", "common", "4.2.1")
implementation("org.ow2.asm", "asm", "9.5")
implementation("org.ow2.asm", "asm-tree", "9.5")
implementation("com.dfsek.tectonic", "common", "4.2.0")
implementation("org.yaml", "snakeyaml", "2.2")
}
+8 -5
View File
@@ -48,14 +48,17 @@ fun Project.configureDependencies() {
maven("https://jitpack.io") {
name = "JitPack"
}
maven("https://nexuslite.gcnt.net/repos/other/") {
name = "GCNT"
}
}
dependencies {
testImplementation("org.junit.jupiter", "junit-jupiter-api", Versions.Libraries.Internal.junit)
testImplementation("org.junit.jupiter", "junit-jupiter-engine", Versions.Libraries.Internal.junit)
compileOnly("org.jetbrains", "annotations", Versions.Libraries.Internal.jetBrainsAnnotations)
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.0")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("com.google.guava", "guava", Versions.Libraries.Internal.guava)
testImplementation("com.google.guava", "guava", Versions.Libraries.Internal.guava)
compileOnly("com.google.guava:guava:30.0-jre")
testImplementation("com.google.guava:guava:30.0-jre")
}
}
@@ -27,8 +27,7 @@ fun Project.configureDistribution() {
group = "terra"
doFirst {
file("${buildDir}/resources/main/packs/").deleteRecursively()
val defaultPackUrl =
URL("https://github.com/PolyhedralDev/TerraOverworldConfig/releases/download/" + Versions.Terra.overworldConfig + "/default.zip")
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraOverworldConfig/releases/download/latest/default.zip")
downloadPack(defaultPackUrl, project)
}
}
+25 -31
View File
@@ -1,8 +1,4 @@
object Versions {
object Terra {
const val overworldConfig = "v1.3.4"
}
object Libraries {
const val tectonic = "4.2.1"
const val paralithic = "0.7.1"
@@ -10,25 +6,21 @@ object Versions {
const val cloud = "1.8.4"
const val caffeine = "3.1.8"
const val slf4j = "2.0.9"
const val log4j_slf4j_impl = "2.20.0"
object Internal {
const val shadow = "8.1.1"
const val apacheText = "1.11.0"
const val apacheIO = "2.15.1"
const val apacheText = "1.10.0"
const val apacheIO = "2.14.0"
const val guava = "32.1.3-jre"
const val asm = "9.6"
const val asm = "9.5"
const val snakeYml = "2.2"
const val jetBrainsAnnotations = "24.1.0"
const val junit = "5.10.1"
}
}
object Fabric {
const val fabricAPI = "0.91.2+${Mod.minecraft}"
const val fabricAPI = "0.90.0+${Mod.minecraft}"
}
//
// object Quilt {
@@ -39,28 +31,30 @@ object Versions {
object Mod {
const val mixin = "0.12.5+mixin.0.8.5"
const val minecraft = "1.20.4"
const val yarn = "$minecraft+build.1"
const val fabricLoader = "0.15.1"
const val minecraft = "1.20.2"
const val yarn = "$minecraft+build.4"
const val fabricLoader = "0.14.23"
const val architecuryLoom = "1.4.369"
const val architecturyPlugin = "3.4.151"
const val architecuryLoom = "1.3.357"
const val architecturyPlugin = "3.4.146"
const val loomVineflower = "1.11.0"
}
object Forge {
const val forge = "${Mod.minecraft}-48.0.13"
const val burningwave = "12.63.0"
}
//
// object Forge {
// const val forge = "${Mod.minecraft}-48.0.13"
// const val burningwave = "12.63.0"
// }
object Bukkit {
const val minecraft = "1.20.4"
const val paperBuild = "$minecraft-R0.1-20231209.173338-2"
const val paper = paperBuild
const val paperLib = "1.0.8"
const val reflectionRemapper = "0.1.0"
const val paperDevBundle = paperBuild
const val runPaper = "2.2.2"
const val paperWeight = "1.5.11"
const val paper = "1.18.2-R0.1-SNAPSHOT"
const val paperLib = "1.0.5"
const val foliaLib = "0.2.5"
const val minecraft = "1.20.2"
const val reflectionRemapper = "0.1.0-SNAPSHOT"
const val paperDevBundle = "1.20.2-R0.1-SNAPSHOT"
const val runPaper = "2.2.0"
const val paperWeight = "1.5.6"
}
//
@@ -72,6 +66,6 @@ object Versions {
//
object CLI {
const val nbt = "6.1"
const val logback = "1.4.14"
const val logback = "1.4.11"
}
}
@@ -1,9 +1,5 @@
package com.dfsek.terra.addons.biome.extrusion.extrusions;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
import com.dfsek.terra.addons.biome.query.api.BiomeQueries;
@@ -12,6 +8,10 @@ import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Biome;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Sets biomes at locations based on a sampler.
@@ -7,13 +7,13 @@
package com.dfsek.terra.addons.biome.image.v2;
import java.util.Optional;
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
import com.dfsek.terra.addons.image.converter.ColorConverter;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import java.util.Optional;
public class ImageBiomeProvider implements BiomeProvider {
private final int resolution;
@@ -1,9 +1,9 @@
package com.dfsek.terra.addons.biome.pipeline.v2.api.biome;
import com.dfsek.terra.api.world.biome.Biome;
import java.util.Set;
import com.dfsek.terra.api.world.biome.Biome;
public final class DelegatedPipelineBiome implements PipelineBiome {
private final Biome biome;
@@ -14,8 +14,7 @@ public class BiomeChunkImpl implements BiomeChunk {
private final SeededVector worldOrigin;
private final int chunkOriginArrayIndex;
private final int worldCoordinateScale;
private final int size;
private PipelineBiome[] biomes;
private PipelineBiome[][] biomes;
public BiomeChunkImpl(SeededVector worldOrigin, PipelineImpl pipeline) {
@@ -23,14 +22,14 @@ public class BiomeChunkImpl implements BiomeChunk {
this.chunkOriginArrayIndex = pipeline.getChunkOriginArrayIndex();
this.worldCoordinateScale = pipeline.getResolution();
this.size = pipeline.getArraySize();
int size = pipeline.getArraySize();
int expanderCount = pipeline.getExpanderCount();
int expansionsApplied = 0;
// Allocate working arrays
this.biomes = new PipelineBiome[size * size];
PipelineBiome[] lookupArray = new PipelineBiome[size * size];
this.biomes = new PipelineBiome[size][size];
PipelineBiome[][] lookupArray = new PipelineBiome[size][size];
// A second lookup array is required such that stage application doesn't affect lookups, otherwise application may cascade
// Construct working grid
@@ -44,7 +43,7 @@ public class BiomeChunkImpl implements BiomeChunk {
for(int gridZ = 0; gridZ < gridSize; gridZ++) {
int xIndex = gridOrigin + gridX * gridInterval;
int zIndex = gridOrigin + gridZ * gridInterval;
biomes[(xIndex * size) + zIndex] = pipeline.getSource().get(worldOrigin.seed(), xIndexToWorldCoordinate(xIndex),
biomes[xIndex][zIndex] = pipeline.getSource().get(worldOrigin.seed(), xIndexToWorldCoordinate(xIndex),
zIndexToWorldCoordinate(zIndex));
}
}
@@ -66,7 +65,7 @@ public class BiomeChunkImpl implements BiomeChunk {
// Cycle arrays, the previously populated array is swapped to be used for lookups, and the result of the stage application
// overwrites the previous lookup array. This saves having to allocate a new array copy each time
PipelineBiome[] tempArray = biomes;
PipelineBiome[][] tempArray = biomes;
biomes = lookupArray;
lookupArray = tempArray;
@@ -75,8 +74,7 @@ public class BiomeChunkImpl implements BiomeChunk {
for(int gridX = 0; gridX < gridSize; gridX = gridX + 1) {
int xIndex = gridOrigin + gridX * gridInterval;
int zIndex = gridOrigin + gridZ * gridInterval;
biomes[(xIndex * size) + zIndex] = stage.apply(
new ViewPoint(this, gridInterval, gridX, gridZ, xIndex, zIndex, lookupArray, size));
biomes[xIndex][zIndex] = stage.apply(new ViewPoint(this, gridInterval, gridX, gridZ, xIndex, zIndex, lookupArray));
}
}
}
@@ -135,7 +133,7 @@ public class BiomeChunkImpl implements BiomeChunk {
public PipelineBiome get(int xInChunk, int zInChunk) {
int xIndex = xInChunk + chunkOriginArrayIndex;
int zIndex = zInChunk + chunkOriginArrayIndex;
return biomes[(xIndex * size) + zIndex];
return biomes[xIndex][zIndex];
}
private int xIndexToWorldCoordinate(int xIndex) {
@@ -161,11 +159,10 @@ public class BiomeChunkImpl implements BiomeChunk {
private final int gridZ;
private final int xIndex;
private final int zIndex;
private final PipelineBiome[] lookupArray;
private final int size;
private final PipelineBiome[][] lookupArray;
private ViewPoint(BiomeChunkImpl chunk, int gridInterval, int gridX, int gridZ, int xIndex, int zIndex,
PipelineBiome[] lookupArray, int size) {
PipelineBiome[][] lookupArray) {
this.chunk = chunk;
this.gridInterval = gridInterval;
this.gridX = gridX;
@@ -173,14 +170,13 @@ public class BiomeChunkImpl implements BiomeChunk {
this.xIndex = xIndex;
this.zIndex = zIndex;
this.lookupArray = lookupArray;
this.size = size;
this.biome = lookupArray[(this.xIndex * this.size) + this.zIndex];
this.biome = lookupArray[xIndex][zIndex];
}
public PipelineBiome getRelativeBiome(int x, int z) {
int lookupXIndex = this.xIndex + x * gridInterval;
int lookupZIndex = this.zIndex + z * gridInterval;
return lookupArray[(lookupXIndex * this.size) + lookupZIndex];
return lookupArray[lookupXIndex][lookupZIndex];
}
public PipelineBiome getBiome() {
@@ -7,17 +7,17 @@
package com.dfsek.terra.addons.biome.pipeline.v2.stage.mutators;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import com.dfsek.terra.addons.biome.pipeline.v2.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.v2.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.v2.pipeline.BiomeChunkImpl;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
public class ReplaceListStage implements Stage {
private final Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace;
@@ -13,7 +13,6 @@ import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties;
import com.dfsek.terra.addons.chunkgenerator.config.palette.BiomePaletteTemplate;
import com.dfsek.terra.addons.chunkgenerator.config.palette.slant.SlantLayerTemplate;
import com.dfsek.terra.addons.chunkgenerator.generation.NoiseChunkGenerator3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
@@ -46,8 +45,8 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer {
.priority(1000)
.then(event -> {
event.getPack().applyLoader(SlantCalculationMethod.class,
(type, o, loader, depthTracker) -> SlantCalculationMethod.valueOf((String) o));
event.getPack().applyLoader(SlantHolder.CalculationMethod.class,
(type, o, loader, depthTracker) -> SlantHolder.CalculationMethod.valueOf((String) o));
NoiseChunkGeneratorPackConfigTemplate config = event.loadTemplate(new NoiseChunkGeneratorPackConfigTemplate());
event.getPack().getContext().put(config);
@@ -58,7 +57,7 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer {
pack -> new NoiseChunkGenerator3D(pack, platform, config.getElevationBlend(),
config.getHorizontalRes(),
config.getVerticalRes(), noisePropertiesPropertyKey,
paletteInfoPropertyKey, config.getSlantCalculationMethod()));
paletteInfoPropertyKey));
event.getPack()
.applyLoader(SlantHolder.Layer.class, SlantLayerTemplate::new);
})
@@ -4,7 +4,7 @@ import com.dfsek.tectonic.api.config.template.ConfigTemplate;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.properties.Properties;
@@ -24,7 +24,7 @@ public class NoiseChunkGeneratorPackConfigTemplate implements ConfigTemplate, Pr
@Value("slant.calculation-method")
@Default
private @Meta SlantCalculationMethod slantCalculationMethod = SlantCalculationMethod.Derivative;
private SlantHolder.@Meta CalculationMethod slantCalculationMethod = SlantHolder.CalculationMethod.Derivative;
public int getElevationBlend() {
return elevationBlend;
@@ -38,7 +38,7 @@ public class NoiseChunkGeneratorPackConfigTemplate implements ConfigTemplate, Pr
return verticalRes;
}
public SlantCalculationMethod getSlantCalculationMethod() {
public SlantHolder.CalculationMethod getSlantCalculationMethod() {
return slantCalculationMethod;
}
}
@@ -16,7 +16,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder;
@@ -28,7 +27,7 @@ import com.dfsek.terra.api.world.chunk.generation.util.Palette;
public class BiomePaletteTemplate implements ObjectTemplate<BiomePaletteInfo> {
private final Platform platform;
private final SlantCalculationMethod slantCalculationMethod;
private final SlantHolder.CalculationMethod slantCalculationMethod;
@Value("slant")
@Default
@Description("The slant palettes to use in this biome.")
@@ -57,7 +56,7 @@ public class BiomePaletteTemplate implements ObjectTemplate<BiomePaletteInfo> {
@Default
private @Meta boolean updatePalette = false;
public BiomePaletteTemplate(Platform platform, SlantCalculationMethod slantCalculationMethod) {
public BiomePaletteTemplate(Platform platform, SlantHolder.CalculationMethod slantCalculationMethod) {
this.platform = platform;
this.slantCalculationMethod = slantCalculationMethod;
}
@@ -8,13 +8,10 @@
package com.dfsek.terra.addons.chunkgenerator.generation;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties;
import com.dfsek.terra.addons.chunkgenerator.generation.math.PaletteUtil;
import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.LazilyEvaluatedInterpolator;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider;
@@ -45,19 +42,16 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
private final PropertyKey<BiomePaletteInfo> paletteInfoPropertyKey;
private final PropertyKey<BiomeNoiseProperties> noisePropertiesKey;
private final SlantCalculationMethod slantCalculationMethod;
public NoiseChunkGenerator3D(ConfigPack pack, Platform platform, int elevationBlend, int carverHorizontalResolution,
int carverVerticalResolution,
PropertyKey<BiomeNoiseProperties> noisePropertiesKey,
PropertyKey<BiomePaletteInfo> paletteInfoPropertyKey, SlantCalculationMethod slantCalculationMethod) {
PropertyKey<BiomePaletteInfo> paletteInfoPropertyKey) {
this.platform = platform;
this.air = platform.getWorldHandle().air();
this.carverHorizontalResolution = carverHorizontalResolution;
this.carverVerticalResolution = carverVerticalResolution;
this.paletteInfoPropertyKey = paletteInfoPropertyKey;
this.noisePropertiesKey = noisePropertiesKey;
this.slantCalculationMethod = slantCalculationMethod;
int maxBlend = pack
.getBiomeProvider()
.stream()
@@ -69,17 +63,6 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
this.samplerCache = new SamplerProvider(platform, elevationBlend, noisePropertiesKey, maxBlend);
}
private Palette paletteAt(int x, int y, int z, Sampler3D sampler, BiomePaletteInfo paletteInfo, int depth) {
SlantHolder slantHolder = paletteInfo.slantHolder();
if(slantHolder.isAboveDepth(depth)) {
double slant = slantCalculationMethod.slant(sampler, x, y, z);
if(slantHolder.isInSlantThreshold(slant)) {
return slantHolder.getPalette(slant).getPalette(y);
}
}
return paletteInfo.paletteHolder().getPalette(y);
}
@Override
@SuppressWarnings("try")
public void generateChunkData(@NotNull ProtoChunk chunk, @NotNull WorldProperties world,
@@ -120,7 +103,8 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
if(sampler.sample(x, y, z) > 0) {
if(carver.sample(x, y, z) <= 0) {
data = paletteAt(x, y, z, sampler, paletteInfo, paletteLevel)
data = PaletteUtil
.getPalette(x, y, z, sampler, paletteInfo, paletteLevel)
.get(paletteLevel, cx, y, cz, seed);
chunk.setBlock(x, y, z, data);
paletteLevel++;
@@ -151,7 +135,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
int fdX = Math.floorMod(x, 16);
int fdZ = Math.floorMod(z, 16);
Palette palette = paletteAt(fdX, y, fdZ, sampler, paletteInfo, 0);
Palette palette = PaletteUtil.getPalette(fdX, y, fdZ, sampler, paletteInfo, 0);
double noise = sampler.sample(fdX, y, fdZ);
if(noise > 0) {
int level = 0;
@@ -173,8 +157,11 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
public double getSlant(int x, int y, int z, WorldProperties world, BiomeProvider biomeProvider) {
int fdX = Math.floorMod(x, 16);
int fdZ = Math.floorMod(z, 16);
Sampler3D sampler = samplerCache.get(x, z, world, biomeProvider);
return slantCalculationMethod.slant(sampler, fdX, y, fdZ);
return biomeProvider.getBiome(x, y, z, world.getSeed())
.getContext()
.get(paletteInfoPropertyKey)
.slantHolder()
.calculateSlant(samplerCache.get(x, z, world, biomeProvider), fdX, y, fdZ);
}
public SamplerProvider samplerProvider() {
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2020-2023 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.generation.math;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder;
import com.dfsek.terra.api.world.chunk.generation.util.Palette;
public final class PaletteUtil {
public static Palette getPalette(int x, int y, int z, Sampler3D sampler, BiomePaletteInfo paletteInfo, int depth) {
SlantHolder slantHolder = paletteInfo.slantHolder();
if(slantHolder.isAboveDepth(depth)) {
double slant = slantHolder.calculateSlant(sampler, x, y, z);
if(slantHolder.isInSlantThreshold(slant)) {
return slantHolder.getPalette(slant).getPalette(y);
}
}
return paletteInfo.paletteHolder().getPalette(y);
}
}
@@ -1,69 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.api.util.vector.Vector3;
public enum SlantCalculationMethod {
DotProduct {
private static final Vector3 DOT_PRODUCT_DIRECTION = Vector3.of(0, 1, 0);
private static final Vector3[] DOT_PRODUCT_SAMPLE_POINTS = {
Vector3.of(0, 0, -DERIVATIVE_DIST),
Vector3.of(0, 0, DERIVATIVE_DIST),
Vector3.of(0, -DERIVATIVE_DIST, 0),
Vector3.of(0, DERIVATIVE_DIST, 0),
Vector3.of(-DERIVATIVE_DIST, 0, 0),
Vector3.of(DERIVATIVE_DIST, 0, 0)
};
@Override
public double slant(Sampler3D sampler, double x, double y, double z) {
Vector3.Mutable normalApproximation = Vector3.Mutable.of(0, 0, 0);
for(Vector3 point : DOT_PRODUCT_SAMPLE_POINTS) {
var scalar = -sampler.sample(x + point.getX(), y + point.getY(), z + point.getZ());
normalApproximation.add(point.mutable().multiply(scalar));
}
return DOT_PRODUCT_DIRECTION.dot(normalApproximation.normalize());
}
@Override
public boolean floorToThreshold() {
return false;
}
},
Derivative {
@Override
public double slant(Sampler3D sampler, double x, double y, double z) {
double baseSample = sampler.sample(x, y, z);
double xVal1 = (sampler.sample(x + DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
double xVal2 = (sampler.sample(x - DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
double zVal1 = (sampler.sample(x, y, z + DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
double zVal2 = (sampler.sample(x, y, z - DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
double yVal1 = (sampler.sample(x, y + DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
double yVal2 = (sampler.sample(x, y - DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
return Math.sqrt(
((xVal2 - xVal1) * (xVal2 - xVal1)) + ((zVal2 - zVal1) * (zVal2 - zVal1)) + ((yVal2 - yVal1) * (yVal2 - yVal1)));
}
@Override
public boolean floorToThreshold() {
return true;
}
};
private static final double DERIVATIVE_DIST = 0.55;
public abstract double slant(Sampler3D sampler, double x, double y, double z);
/*
* Controls whether palettes should be applied before or after their respective thresholds.
*
* If true, slant values will map to the palette of the next floor threshold, otherwise they
* will map to the ceiling.
*/
public abstract boolean floorToThreshold();
}
@@ -14,7 +14,6 @@ import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
@@ -22,7 +21,7 @@ public class MultipleSlantHolder extends SlantHolderImpl {
private final NavigableMap<Double, PaletteHolder> layers;
private final double slantThreshold;
MultipleSlantHolder(List<SlantHolder.Layer> slant, int slantDepth, SlantCalculationMethod calculationMethod) {
MultipleSlantHolder(List<SlantHolder.Layer> slant, int slantDepth, CalculationMethod calculationMethod) {
super(slantDepth, calculationMethod);
NavigableMap<Double, PaletteHolder> layers = new TreeMap<>(
slant.stream().collect(Collectors.toMap(SlantHolder.Layer::threshold, SlantHolder.Layer::palette)));
@@ -1,6 +1,5 @@
package com.dfsek.terra.addons.chunkgenerator.palette.slant;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
@@ -8,7 +7,7 @@ final class SingleSlantHolder extends SlantHolderImpl {
private final SlantHolder.Layer layer;
public SingleSlantHolder(SlantHolder.Layer layer, int slantDepth, SlantCalculationMethod calculationMethod) {
public SingleSlantHolder(SlantHolder.Layer layer, int slantDepth, CalculationMethod calculationMethod) {
super(slantDepth, calculationMethod);
this.layer = layer;
}
@@ -2,13 +2,19 @@ package com.dfsek.terra.addons.chunkgenerator.palette.slant;
import java.util.List;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
import com.dfsek.terra.api.util.vector.Vector3;
public interface SlantHolder {
SlantHolder EMPTY = new SlantHolder() {
@Override
public double calculateSlant(Sampler3D sampler, double x, double y, double z) {
throw new UnsupportedOperationException("Empty holder should not calculate slant");
}
@Override
public boolean isAboveDepth(int depth) {
return false;
@@ -25,7 +31,7 @@ public interface SlantHolder {
}
};
static SlantHolder of(List<SlantHolder.Layer> layers, int slantDepth, SlantCalculationMethod calculationMethod) {
static SlantHolder of(List<SlantHolder.Layer> layers, int slantDepth, CalculationMethod calculationMethod) {
if(layers.isEmpty()) {
return EMPTY;
} else if(layers.size() == 1) {
@@ -34,6 +40,8 @@ public interface SlantHolder {
return new MultipleSlantHolder(layers, slantDepth, calculationMethod);
}
double calculateSlant(Sampler3D sampler, double x, double y, double z);
boolean isAboveDepth(int depth);
boolean isInSlantThreshold(double slant);
@@ -41,6 +49,71 @@ public interface SlantHolder {
PaletteHolder getPalette(double slant);
enum CalculationMethod {
DotProduct {
private static final Vector3 DOT_PRODUCT_DIRECTION = Vector3.of(0, 1, 0);
private static final Vector3[] DOT_PRODUCT_SAMPLE_POINTS = {
Vector3.of(0, 0, -DERIVATIVE_DIST),
Vector3.of(0, 0, DERIVATIVE_DIST),
Vector3.of(0, -DERIVATIVE_DIST, 0),
Vector3.of(0, DERIVATIVE_DIST, 0),
Vector3.of(-DERIVATIVE_DIST, 0, 0),
Vector3.of(DERIVATIVE_DIST, 0, 0)
};
@Override
public double slant(Sampler3D sampler, double x, double y, double z) {
Vector3.Mutable normalApproximation = Vector3.Mutable.of(0, 0, 0);
for(Vector3 point : DOT_PRODUCT_SAMPLE_POINTS) {
var scalar = -sampler.sample(x + point.getX(), y + point.getY(), z + point.getZ());
normalApproximation.add(point.mutable().multiply(scalar));
}
return DOT_PRODUCT_DIRECTION.dot(normalApproximation.normalize());
}
@Override
public boolean floorToThreshold() {
return false;
}
},
Derivative {
@Override
public double slant(Sampler3D sampler, double x, double y, double z) {
double baseSample = sampler.sample(x, y, z);
double xVal1 = (sampler.sample(x + DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
double xVal2 = (sampler.sample(x - DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
double zVal1 = (sampler.sample(x, y, z + DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
double zVal2 = (sampler.sample(x, y, z - DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
double yVal1 = (sampler.sample(x, y + DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
double yVal2 = (sampler.sample(x, y - DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
return Math.sqrt(
((xVal2 - xVal1) * (xVal2 - xVal1)) + ((zVal2 - zVal1) * (zVal2 - zVal1)) + ((yVal2 - yVal1) * (yVal2 - yVal1)));
}
@Override
public boolean floorToThreshold() {
return true;
}
};
private static final double DERIVATIVE_DIST = 0.55;
public abstract double slant(Sampler3D sampler, double x, double y, double z);
/*
* Controls whether palettes should be applied before or after their respective thresholds.
*
* If true, slant values will map to the palette of the next floor threshold, otherwise they
* will map to the ceiling.
*/
public abstract boolean floorToThreshold();
}
record Layer(PaletteHolder palette, double threshold) {
}
}
@@ -1,19 +1,26 @@
package com.dfsek.terra.addons.chunkgenerator.palette.slant;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
public abstract class SlantHolderImpl implements SlantHolder {
protected final boolean floorToThreshold;
private final SlantHolder.CalculationMethod calculationMethod;
private final int slantDepth;
protected SlantHolderImpl(int slantDepth, SlantCalculationMethod calculationMethod) {
protected SlantHolderImpl(int slantDepth, CalculationMethod calculationMethod) {
this.floorToThreshold = calculationMethod.floorToThreshold();
this.calculationMethod = calculationMethod;
this.slantDepth = slantDepth;
}
protected abstract double getSlantThreshold();
@Override
public final double calculateSlant(Sampler3D sampler, double x, double y, double z) {
return calculationMethod.slant(sampler, x, y, z);
}
@Override
public final boolean isAboveDepth(int depth) {
return depth <= slantDepth;
@@ -6,8 +6,7 @@ import cloud.commandframework.arguments.standard.EnumArgument;
import cloud.commandframework.arguments.standard.LongArgument;
import cloud.commandframework.context.CommandContext;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.Random;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform;
@@ -57,11 +56,7 @@ public class StructureCommandAddon implements AddonInitializer {
structure.generate(
sender.position().toInt(),
sender.world(),
((Long) context.get("seed") == 0)
? RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus")
.create()
: RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus")
.create(context.get("seed")),
((Long) context.get("seed") == 0) ? new Random() : new Random(context.get("seed")),
context.get("rotation")
);
})
@@ -1,7 +1,6 @@
package com.dfsek.terra.addons.feature.distributor.distributors;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.Random;
import com.dfsek.terra.api.structure.feature.Distributor;
import com.dfsek.terra.api.util.MathUtil;
@@ -25,8 +24,7 @@ public class PaddedGridDistributor implements Distributor {
int cellX = Math.floorDiv(x, cellWidth);
int cellZ = Math.floorDiv(z, cellWidth);
RandomGenerator random = RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(
(MathUtil.murmur64(MathUtil.squash(cellX, cellZ)) ^ seed) + salt);
Random random = new Random((MathUtil.murmur64(MathUtil.squash(cellX, cellZ)) ^ seed) + salt);
int pointX = random.nextInt(width) + cellX * cellWidth;
int pointZ = random.nextInt(width) + cellZ * cellWidth;
@@ -10,8 +10,7 @@ package com.dfsek.terra.addons.flora.flora.gen;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.Random;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.block.state.properties.enums.Direction;
@@ -72,7 +71,7 @@ public class TerraFlora implements Structure {
}
@Override
public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
boolean doRotation = testRotation.size() > 0;
int size = layers.size();
int c = ceiling ? -1 : 1;
@@ -87,9 +86,7 @@ public class TerraFlora implements Structure {
location.getZ(), world.getSeed());
if(doRotation) {
Direction oneFace = new ArrayList<>(faces).get(
RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus")
.create(location.getX() ^ location.getZ())
.nextInt(faces.size())); // Get RandomGenerator face.
new Random(location.getX() ^ location.getZ()).nextInt(faces.size())); // Get random face.
}
world.setBlockState(location.mutable().add(0, i + c, 0).immutable(), data, physics);
}
@@ -7,8 +7,7 @@
package com.dfsek.terra.addons.feature.locator.locators;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.Random;
import com.dfsek.terra.api.structure.feature.BinaryColumn;
import com.dfsek.terra.api.structure.feature.Locator;
@@ -41,7 +40,7 @@ public class GaussianRandomLocator implements Locator {
seed = 31 * seed + column.getZ();
seed += salt;
RandomGenerator r = RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(seed);
Random r = new Random(seed);
int size = points.get(r);
@@ -7,8 +7,7 @@
package com.dfsek.terra.addons.feature.locator.locators;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.Random;
import com.dfsek.terra.api.structure.feature.BinaryColumn;
import com.dfsek.terra.api.structure.feature.Locator;
@@ -37,7 +36,7 @@ public class RandomLocator implements Locator {
seed = 31 * seed + column.getZ();
seed += salt;
RandomGenerator r = RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(seed);
Random r = new Random(seed);
int size = points.get(r);
@@ -24,7 +24,7 @@ public class BrownianMotionSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) {
double noise = input.noise(seed++, x, y);
sum += noise * amp;
amp *= MathUtil.lerp(weightedStrength, 1.0, Math.min(noise + 1, 2) * 0.5);
amp *= MathUtil.lerp(1.0, Math.min(noise + 1, 2) * 0.5, weightedStrength);
x *= lacunarity;
y *= lacunarity;
@@ -42,7 +42,7 @@ public class BrownianMotionSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) {
double noise = input.noise(seed++, x, y, z);
sum += noise * amp;
amp *= MathUtil.lerp(weightedStrength, 1.0, (noise + 1) * 0.5);
amp *= MathUtil.lerp(1.0, (noise + 1) * 0.5, weightedStrength);
x *= lacunarity;
y *= lacunarity;
@@ -36,7 +36,7 @@ public class PingPongSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) {
double noise = pingPong((input.noise(seed++, x, y) + 1) * pingPongStrength);
sum += (noise - 0.5) * 2 * amp;
amp *= MathUtil.lerp(weightedStrength, 1.0, noise);
amp *= MathUtil.lerp(1.0, noise, weightedStrength);
x *= lacunarity;
y *= lacunarity;
@@ -54,7 +54,7 @@ public class PingPongSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) {
double noise = pingPong((input.noise(seed++, x, y, z) + 1) * pingPongStrength);
sum += (noise - 0.5) * 2 * amp;
amp *= MathUtil.lerp(weightedStrength, 1.0, noise);
amp *= MathUtil.lerp(1.0, noise, weightedStrength);
x *= lacunarity;
y *= lacunarity;
@@ -25,7 +25,7 @@ public class RidgedFractalSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) {
double noise = Math.abs(input.noise(seed++, x, y));
sum += (noise * -2 + 1) * amp;
amp *= MathUtil.lerp(weightedStrength, 1.0, 1 - noise);
amp *= MathUtil.lerp(1.0, 1 - noise, weightedStrength);
x *= lacunarity;
y *= lacunarity;
@@ -43,7 +43,7 @@ public class RidgedFractalSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) {
double noise = Math.abs(input.noise(seed++, x, y, z));
sum += (noise * -2 + 1) * amp;
amp *= MathUtil.lerp(weightedStrength, 1.0, 1 - noise);
amp *= MathUtil.lerp(1.0, 1 - noise, weightedStrength);
x *= lacunarity;
y *= lacunarity;
@@ -33,10 +33,10 @@ public class PerlinSampler extends SimplexStyleSampler {
int x1 = x0 + PRIME_X;
int y1 = y0 + PRIME_Y;
double xf0 = MathUtil.lerp(xs, gradCoord(seed, x0, y0, xd0, yd0), gradCoord(seed, x1, y0, xd1, yd0));
double xf1 = MathUtil.lerp(xs, gradCoord(seed, x0, y1, xd0, yd1), gradCoord(seed, x1, y1, xd1, yd1));
double xf0 = MathUtil.lerp(gradCoord(seed, x0, y0, xd0, yd0), gradCoord(seed, x1, y0, xd1, yd0), xs);
double xf1 = MathUtil.lerp(gradCoord(seed, x0, y1, xd0, yd1), gradCoord(seed, x1, y1, xd1, yd1), xs);
return MathUtil.lerp(ys, xf0, xf1) * 1.4247691104677813;
return MathUtil.lerp(xf0, xf1, ys) * 1.4247691104677813;
}
@Override
@@ -64,14 +64,14 @@ public class PerlinSampler extends SimplexStyleSampler {
int y1 = y0 + PRIME_Y;
int z1 = z0 + PRIME_Z;
double xf00 = MathUtil.lerp(xs, gradCoord(seed, x0, y0, z0, xd0, yd0, zd0), gradCoord(seed, x1, y0, z0, xd1, yd0, zd0));
double xf10 = MathUtil.lerp(xs, gradCoord(seed, x0, y1, z0, xd0, yd1, zd0), gradCoord(seed, x1, y1, z0, xd1, yd1, zd0));
double xf01 = MathUtil.lerp(xs, gradCoord(seed, x0, y0, z1, xd0, yd0, zd1), gradCoord(seed, x1, y0, z1, xd1, yd0, zd1));
double xf11 = MathUtil.lerp(xs, gradCoord(seed, x0, y1, z1, xd0, yd1, zd1), gradCoord(seed, x1, y1, z1, xd1, yd1, zd1));
double xf00 = MathUtil.lerp(gradCoord(seed, x0, y0, z0, xd0, yd0, zd0), gradCoord(seed, x1, y0, z0, xd1, yd0, zd0), xs);
double xf10 = MathUtil.lerp(gradCoord(seed, x0, y1, z0, xd0, yd1, zd0), gradCoord(seed, x1, y1, z0, xd1, yd1, zd0), xs);
double xf01 = MathUtil.lerp(gradCoord(seed, x0, y0, z1, xd0, yd0, zd1), gradCoord(seed, x1, y0, z1, xd1, yd0, zd1), xs);
double xf11 = MathUtil.lerp(gradCoord(seed, x0, y1, z1, xd0, yd1, zd1), gradCoord(seed, x1, y1, z1, xd1, yd1, zd1), xs);
double yf0 = MathUtil.lerp(ys, xf00, xf10);
double yf1 = MathUtil.lerp(ys, xf01, xf11);
double yf0 = MathUtil.lerp(xf00, xf10, ys);
double yf1 = MathUtil.lerp(xf01, xf11, ys);
return MathUtil.lerp(zs, yf0, yf1) * 0.964921414852142333984375;
return MathUtil.lerp(yf0, yf1, zs) * 0.964921414852142333984375;
}
}
@@ -25,10 +25,10 @@ public class ValueSampler extends ValueStyleNoise {
int x1 = x0 + PRIME_X;
int y1 = y0 + PRIME_Y;
double xf0 = MathUtil.lerp(xs, valCoord(seed, x0, y0), valCoord(seed, x1, y0));
double xf1 = MathUtil.lerp(xs, valCoord(seed, x0, y1), valCoord(seed, x1, y1));
double xf0 = MathUtil.lerp(valCoord(seed, x0, y0), valCoord(seed, x1, y0), xs);
double xf1 = MathUtil.lerp(valCoord(seed, x0, y1), valCoord(seed, x1, y1), xs);
return MathUtil.lerp(ys, xf0, xf1);
return MathUtil.lerp(xf0, xf1, ys);
}
@Override
@@ -49,14 +49,14 @@ public class ValueSampler extends ValueStyleNoise {
int y1 = y0 + PRIME_Y;
int z1 = z0 + PRIME_Z;
double xf00 = MathUtil.lerp(xs, valCoord(seed, x0, y0, z0), valCoord(seed, x1, y0, z0));
double xf10 = MathUtil.lerp(xs, valCoord(seed, x0, y1, z0), valCoord(seed, x1, y1, z0));
double xf01 = MathUtil.lerp(xs, valCoord(seed, x0, y0, z1), valCoord(seed, x1, y0, z1));
double xf11 = MathUtil.lerp(xs, valCoord(seed, x0, y1, z1), valCoord(seed, x1, y1, z1));
double xf00 = MathUtil.lerp(valCoord(seed, x0, y0, z0), valCoord(seed, x1, y0, z0), xs);
double xf10 = MathUtil.lerp(valCoord(seed, x0, y1, z0), valCoord(seed, x1, y1, z0), xs);
double xf01 = MathUtil.lerp(valCoord(seed, x0, y0, z1), valCoord(seed, x1, y0, z1), xs);
double xf11 = MathUtil.lerp(valCoord(seed, x0, y1, z1), valCoord(seed, x1, y1, z1), xs);
double yf0 = MathUtil.lerp(ys, xf00, xf10);
double yf1 = MathUtil.lerp(ys, xf01, xf11);
double yf0 = MathUtil.lerp(xf00, xf10, ys);
double yf1 = MathUtil.lerp(xf01, xf11, ys);
return MathUtil.lerp(zs, yf0, yf1);
return MathUtil.lerp(yf0, yf1, zs);
}
}
@@ -9,7 +9,7 @@ package com.dfsek.terra.addons.ore.ores;
import java.util.BitSet;
import java.util.Map;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState;
@@ -44,7 +44,7 @@ public class VanillaOre implements Structure {
}
@Override
public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
float randomRadian = random.nextFloat() * (float) Math.PI;
double eighthSize = size / 8.0F;
@@ -1,7 +1,7 @@
package com.dfsek.terra.addons.ore.ores;
import java.util.Map;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState;
@@ -24,7 +24,7 @@ public class VanillaScatteredOre extends VanillaOre {
}
@Override
public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
int i = random.nextInt((int) (size + 1));
Vector3Int.Mutable mutable = Vector3Int.zero().mutable();
@@ -39,7 +39,7 @@ public class VanillaScatteredOre extends VanillaOre {
return true;
}
private void setPos(Vector3Int.Mutable mutable, RandomGenerator random, Vector3Int location, int spread) {
private void setPos(Vector3Int.Mutable mutable, Random random, Vector3Int location, int spread) {
int x = this.getSpread(random, spread);
int y = this.getSpread(random, spread);
int z = this.getSpread(random, spread);
@@ -48,7 +48,7 @@ public class VanillaScatteredOre extends VanillaOre {
mutable.setZ(location.getZ() + z);
}
private int getSpread(RandomGenerator random, int spread) {
private int getSpread(Random random, int spread) {
return Math.round((random.nextFloat() - random.nextFloat()) * (float) spread);
}
}
@@ -1,6 +1,6 @@
package com.dfsek.terra.addons.ore.utils;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.util.collection.MaterialSet;
@@ -8,14 +8,13 @@ import com.dfsek.terra.api.world.WritableWorld;
public class VanillaOreUtils {
private static boolean shouldExpose(RandomGenerator random, double exposedChance) {
private static boolean shouldExpose(Random random, double exposedChance) {
if(exposedChance >= 1.0F) return true;
if(exposedChance <= 0.0F) return false;
return random.nextFloat() < exposedChance;
}
public static boolean shouldPlace(MaterialSet replaceable, BlockType type, Double exposedChance, RandomGenerator random,
WritableWorld world,
public static boolean shouldPlace(MaterialSet replaceable, BlockType type, Double exposedChance, Random random, WritableWorld world,
int x,
int y, int z) {
if(!replaceable.contains(type)) return false;
@@ -12,7 +12,7 @@ import org.json.simple.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.addons.structure.structures.loot.functions.AmountFunction;
import com.dfsek.terra.addons.structure.structures.loot.functions.DamageFunction;
@@ -85,11 +85,11 @@ public class Entry {
/**
* Fetches a single ItemStack from the Entry, applying all functions to it.
*
* @param r The RandomGenerator instance to apply functions with
* @param r The Random instance to apply functions with
*
* @return ItemStack - The ItemStack with all functions applied.
*/
public ItemStack getItem(RandomGenerator r) {
public ItemStack getItem(Random r) {
ItemStack item = this.item.newItemStack(1);
for(LootFunction f : functions) {
item = f.apply(item, r);
@@ -14,7 +14,7 @@ import org.json.simple.parser.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.inventory.Inventory;
@@ -44,7 +44,7 @@ public class LootTableImpl implements com.dfsek.terra.api.structure.LootTable {
}
@Override
public void fillInventory(Inventory i, RandomGenerator r) {
public void fillInventory(Inventory i, Random r) {
List<ItemStack> loot = getLoot(r);
for(ItemStack stack : loot) {
int attempts = 0;
@@ -70,7 +70,7 @@ public class LootTableImpl implements com.dfsek.terra.api.structure.LootTable {
}
@Override
public List<ItemStack> getLoot(RandomGenerator r) {
public List<ItemStack> getLoot(Random r) {
List<ItemStack> itemList = new ArrayList<>();
for(Pool pool : pools) {
itemList.addAll(pool.getItems(r));
@@ -12,7 +12,7 @@ import org.json.simple.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.inventory.ItemStack;
@@ -50,13 +50,13 @@ public class Pool {
}
/**
* Fetches a list of items from the pool using the provided RandomGenerator instance.
* Fetches a list of items from the pool using the provided Random instance.
*
* @param r The RandomGenerator instance to use.
* @param r The Random instance to use.
*
* @return List&lt;ItemStack&gt; - The list of items fetched.
*/
public List<ItemStack> getItems(RandomGenerator r) {
public List<ItemStack> getItems(Random r) {
int rolls = r.nextInt(max - min + 1) + min;
List<ItemStack> items = new ArrayList<>();
@@ -8,7 +8,7 @@
package com.dfsek.terra.addons.structure.structures.loot.functions;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.inventory.ItemStack;
@@ -35,12 +35,12 @@ public class AmountFunction implements LootFunction {
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The RandomGenerator instance to use.
* @param r The Random instance to use.
*
* @return - ItemStack - The mutated ItemStack.
*/
@Override
public ItemStack apply(ItemStack original, RandomGenerator r) {
public ItemStack apply(ItemStack original, Random r) {
original.setAmount(r.nextInt(max - min + 1) + min);
return original;
}
@@ -7,7 +7,7 @@
package com.dfsek.terra.addons.structure.structures.loot.functions;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.inventory.ItemStack;
import com.dfsek.terra.api.inventory.item.Damageable;
@@ -36,12 +36,12 @@ public class DamageFunction implements LootFunction {
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The RandomGenerator instance to use.
* @param r The Random instance to use.
*
* @return - ItemStack - The mutated ItemStack.
*/
@Override
public ItemStack apply(ItemStack original, RandomGenerator r) {
public ItemStack apply(ItemStack original, Random r) {
if(original == null) return null;
if(!original.isDamageable()) return original;
ItemMeta meta = original.getItemMeta();
@@ -14,7 +14,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.inventory.ItemStack;
@@ -41,12 +41,12 @@ public class EnchantFunction implements LootFunction {
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The RandomGenerator instance to use.
* @param r The Random instance to use.
*
* @return - ItemStack - The mutated ItemStack.
*/
@Override
public ItemStack apply(ItemStack original, RandomGenerator r) {
public ItemStack apply(ItemStack original, Random r) {
if(original.getItemMeta() == null) return original;
double enchant = (r.nextDouble() * (max - min)) + min;
@@ -8,7 +8,7 @@
package com.dfsek.terra.addons.structure.structures.loot.functions;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.inventory.ItemStack;
@@ -21,9 +21,9 @@ public interface LootFunction {
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The RandomGenerator instance to use.
* @param r The Random instance to use.
*
* @return - ItemStack - The mutated ItemStack.
*/
ItemStack apply(ItemStack original, RandomGenerator r);
ItemStack apply(ItemStack original, Random r);
}
@@ -8,8 +8,7 @@
package com.dfsek.terra.addons.generation.feature;
import java.util.Collections;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.Random;
import com.dfsek.terra.addons.generation.feature.config.BiomeFeatures;
import com.dfsek.terra.api.Platform;
@@ -73,9 +72,7 @@ public class FeatureGenerationStage implements GenerationStage, StringIdentifiab
.forEach(y -> feature.getStructure(world, x, y, z)
.generate(Vector3Int.of(x, y, z),
world,
RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of(
"Xoroshiro128PlusPlus")
.create(coordinateSeed * 31 + y),
new Random(coordinateSeed * 31 + y),
Rotation.NONE)
);
}
@@ -11,16 +11,12 @@ import com.dfsek.tectonic.yaml.YamlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.Files;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.event.events.config.ConfigurationDiscoveryEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.util.FileUtil;
public class YamlAddon implements AddonInitializer {
@@ -37,21 +33,10 @@ public class YamlAddon implements AddonInitializer {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigurationDiscoveryEvent.class)
.then(event -> {
try {
FileUtil.filesWithExtension(event.getPack().getRootPath(), ".yml")
.forEach((key, value) -> {
LOGGER.debug("Discovered config {}", key);
try {
event.register(key, new YamlConfiguration(Files.newInputStream(value), key));
} catch(IOException e) {
throw new RuntimeException("Failed to load config " + key, e);
}
});
} catch(IOException e) {
throw new RuntimeException("Error occurred while reading config pack files", e);
}
})
.then(event -> event.getLoader().open("", ".yml").thenEntries(entries -> entries.forEach(entry -> {
LOGGER.debug("Discovered config {}", entry.getKey());
event.register(entry.getKey(), new YamlConfiguration(entry.getValue(), entry.getKey()));
})).close())
.failThrough();
}
}
@@ -60,8 +60,8 @@ public class ImageLibraryAddon implements AddonInitializer {
.then(event -> {
ConfigPack pack = event.getPack();
CheckedRegistry<Supplier<ObjectTemplate<Image>>> imageRegistry = pack.getOrCreateRegistry(IMAGE_REGISTRY_KEY);
imageRegistry.register(addon.key("BITMAP"), () -> new ImageTemplate(pack));
imageRegistry.register(addon.key("STITCHED_BITMAP"), () -> new StitchedImageTemplate(pack));
imageRegistry.register(addon.key("BITMAP"), () -> new ImageTemplate(pack.getLoader(), pack));
imageRegistry.register(addon.key("STITCHED_BITMAP"), () -> new StitchedImageTemplate(pack.getLoader(), pack));
})
.then(event -> {
event.getPack()
@@ -4,10 +4,8 @@ import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import javax.imageio.ImageIO;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import com.dfsek.terra.addons.image.config.ImageLibraryPackConfigTemplate;
@@ -15,6 +13,7 @@ import com.dfsek.terra.addons.image.image.BufferedImageWrapper;
import com.dfsek.terra.addons.image.image.Image;
import com.dfsek.terra.addons.image.image.SuppliedImage;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.properties.Properties;
import com.dfsek.terra.api.util.generic.Lazy;
@@ -23,13 +22,13 @@ import com.dfsek.terra.api.util.generic.Lazy;
* Cache prevents configs from loading the same image multiple times into memory
*/
record ImageCache(LoadingCache<String, Image> cache) implements Properties {
public static Image load(String path, ConfigPack pack) throws IOException {
public static Image load(String path, ConfigPack pack, Loader files) throws IOException {
ImageLibraryPackConfigTemplate config = pack.getContext().get(ImageLibraryPackConfigTemplate.class);
ImageCache images;
if(!pack.getContext().has(ImageCache.class)) {
var cacheBuilder = Caffeine.newBuilder();
if(config.unloadOnTimeout()) cacheBuilder.expireAfterAccess(config.getCacheTimeout(), TimeUnit.SECONDS);
images = new ImageCache(cacheBuilder.build(s -> loadImage(s, pack.getRootPath())));
images = new ImageCache(cacheBuilder.build(s -> loadImage(s, files)));
pack.getContext().put(images);
} else images = pack.getContext().get(ImageCache.class);
@@ -46,8 +45,17 @@ record ImageCache(LoadingCache<String, Image> cache) implements Properties {
return images.cache.get(path);
}
private static Image loadImage(String path, Path directory) throws IOException {
InputStream is = Files.newInputStream(directory.resolve(path));
return new BufferedImageWrapper(ImageIO.read(is));
private static Image loadImage(String path, Loader files) throws IOException {
try {
return new BufferedImageWrapper(ImageIO.read(files.get(path)));
} catch(IllegalArgumentException e) {
throw new IllegalArgumentException("Unable to load image (image might be too large?)", e);
} catch(IOException e) {
if(e instanceof FileNotFoundException) {
// Rethrow using nicer message
throw new IOException("Unable to load image: No such file or directory: " + path, e);
}
throw new IOException("Unable to load image", e);
}
}
}
@@ -7,22 +7,25 @@ import java.io.IOException;
import com.dfsek.terra.addons.image.image.Image;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
public class ImageTemplate implements ObjectTemplate<Image> {
private final Loader files;
private final ConfigPack pack;
@Value("path")
private String path;
public ImageTemplate(ConfigPack pack) {
public ImageTemplate(Loader files, ConfigPack pack) {
this.files = files;
this.pack = pack;
}
@Override
public Image get() {
try {
return ImageCache.load(path, pack);
return ImageCache.load(path, pack, files);
} catch(IOException e) {
throw new RuntimeException(e);
}
@@ -11,10 +11,12 @@ import java.io.IOException;
import com.dfsek.terra.addons.image.image.Image;
import com.dfsek.terra.addons.image.image.StitchedImage;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
public class StitchedImageTemplate implements ObjectTemplate<Image>, ValidatedConfigTemplate {
private final Loader files;
private final ConfigPack pack;
@Value("path-format")
private String path;
@@ -26,7 +28,8 @@ public class StitchedImageTemplate implements ObjectTemplate<Image>, ValidatedCo
@Default
private boolean zeroIndexed = false;
public StitchedImageTemplate(ConfigPack pack) {
public StitchedImageTemplate(Loader files, ConfigPack pack) {
this.files = files;
this.pack = pack;
}
@@ -36,7 +39,7 @@ public class StitchedImageTemplate implements ObjectTemplate<Image>, ValidatedCo
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
try {
grid[i][j] = ImageCache.load(getFormattedPath(i, j), pack);
grid[i][j] = ImageCache.load(getFormattedPath(i, j), pack, files);
} catch(IOException e) {
throw new RuntimeException(e);
}
@@ -1,6 +1,6 @@
package com.dfsek.terra.addons.palette.shortcut.block;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.structure.Structure;
@@ -17,7 +17,7 @@ public class SingletonStructure implements Structure {
}
@Override
public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
world.setBlockState(location, blockState);
return true;
}
@@ -1,5 +1,7 @@
package com.dfsek.terra.addons.structure.mutator;
import java.util.Random;
import com.dfsek.terra.api.registry.key.Keyed;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.structure.Structure;
@@ -9,8 +11,6 @@ import com.dfsek.terra.api.world.WritableWorld;
import com.dfsek.terra.api.world.util.ReadInterceptor;
import com.dfsek.terra.api.world.util.WriteInterceptor;
import java.util.random.RandomGenerator;
public class MutatedStructure implements Structure, Keyed<MutatedStructure> {
private final RegistryKey key;
@@ -32,7 +32,7 @@ public class MutatedStructure implements Structure, Keyed<MutatedStructure> {
}
@Override
public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
return base.generate(location,
world
.buffer()
@@ -16,7 +16,6 @@ import net.querz.nbt.tag.Tag;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPInputStream;
@@ -30,7 +29,7 @@ import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.util.FileUtil;
import com.dfsek.terra.api.util.StringUtil;
import com.dfsek.terra.api.util.vector.Vector3Int;
@@ -59,21 +58,13 @@ public class SpongeSchematicAddon implements AddonInitializer {
.register(addon, ConfigPackPreLoadEvent.class)
.then(event -> {
CheckedRegistry<Structure> structureRegistry = event.getPack().getOrCreateRegistry(Structure.class);
try {
FileUtil.filesWithExtension(event.getPack().getRootPath(), ".schem")
.entrySet()
event.getPack()
.getLoader()
.open("", ".schem")
.thenEntries(entries -> entries
.stream()
.map(entry -> {
try {
return convert(Files.newInputStream(entry.getValue()), FileUtil.fileName(entry.getKey()));
} catch(IOException e) {
throw new RuntimeException("Failed to load config " + entry.getKey(), e);
}
})
.forEach(structureRegistry::register);
} catch(IOException e) {
throw new RuntimeException("Error occurred while reading config pack files", e);
}
.map(entry -> convert(entry.getValue(), StringUtil.fileName(entry.getKey())))
.forEach(structureRegistry::register)).close();
})
.failThrough();
}
@@ -7,7 +7,7 @@
package com.dfsek.terra.addons.sponge;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.registry.key.Keyed;
@@ -36,7 +36,7 @@ public class SpongeStructure implements Structure, Keyed<SpongeStructure> {
}
@Override
public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
int bX = location.getX();
int bY = location.getY();
int bZ = location.getZ();
@@ -7,9 +7,6 @@
package com.dfsek.terra.addons.terrascript;
import java.io.IOException;
import java.nio.file.Files;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
@@ -22,7 +19,7 @@ import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.LootTable;
import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.util.FileUtil;
import com.dfsek.terra.api.util.StringUtil;
public class TerraScriptAddon implements AddonInitializer {
@@ -40,28 +37,26 @@ public class TerraScriptAddon implements AddonInitializer {
.then(event -> {
CheckedRegistry<Structure> structureRegistry = event.getPack().getOrCreateRegistry(Structure.class);
CheckedRegistry<LootTable> lootRegistry = event.getPack().getOrCreateRegistry(LootTable.class);
try {
FileUtil.filesWithExtension(event.getPack().getRootPath(), ".tesf")
.entrySet()
.stream()
.parallel()
.map(entry -> {
try {
String id = FileUtil.fileName(entry.getKey());
return new StructureScript(Files.newInputStream(entry.getValue()),
addon.key(id),
platform,
structureRegistry,
lootRegistry,
event.getPack().getOrCreateRegistry(FunctionBuilder.class));
} catch(ParseException | IOException e) {
throw new RuntimeException("Failed to load script \"" + entry.getKey() + "\"", e);
}
})
.forEach(structureRegistry::register);
} catch(IOException e) {
throw new RuntimeException("Error occurred while reading config pack files", e);
}
event.getPack().getLoader().open("", ".tesf").thenEntries(
entries ->
entries.stream()
.parallel()
.map(entry -> {
try {
String id = StringUtil.fileName(entry.getKey());
return new StructureScript(entry.getValue(),
addon.key(id),
platform,
structureRegistry,
lootRegistry,
event.getPack().getOrCreateRegistry(FunctionBuilder.class));
} catch(ParseException e) {
throw new RuntimeException("Failed to load script \"" + entry.getKey() + "\"", e);
}
})
.toList()
.forEach(structureRegistry::register))
.close();
})
.priority(100)
.failThrough();
@@ -14,7 +14,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.addons.terrascript.parser.Parser;
import com.dfsek.terra.addons.terrascript.parser.lang.Executable;
@@ -131,14 +131,14 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
@Override
@SuppressWarnings("try")
public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
platform.getProfiler().push(profile);
boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, 0));
platform.getProfiler().pop(profile);
return result;
}
public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation, int recursions) {
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation, int recursions) {
platform.getProfiler().push(profile);
boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, recursions));
platform.getProfiler().pop(profile);
@@ -9,7 +9,7 @@ package com.dfsek.terra.addons.terrascript.script;
import java.util.HashMap;
import java.util.Map;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
import com.dfsek.terra.api.util.Rotation;
@@ -20,14 +20,14 @@ import com.dfsek.terra.api.world.WritableWorld;
public class TerraImplementationArguments implements ImplementationArguments {
private final Rotation rotation;
private final RandomGenerator random;
private final Random random;
private final WritableWorld world;
private final Map<Vector3, String> marks = new HashMap<>();
private final int recursions;
private final Vector3Int origin;
private boolean waterlog = false;
public TerraImplementationArguments(Vector3Int origin, Rotation rotation, RandomGenerator random, WritableWorld world, int recursions) {
public TerraImplementationArguments(Vector3Int origin, Rotation rotation, Random random, WritableWorld world, int recursions) {
this.rotation = rotation;
this.random = random;
this.world = world;
@@ -39,7 +39,7 @@ public class TerraImplementationArguments implements ImplementationArguments {
return recursions;
}
public RandomGenerator getRandom() {
public Random getRandom() {
return random;
}
@@ -10,8 +10,8 @@ package com.dfsek.terra.addons.terrascript.script.functions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
@@ -32,7 +32,7 @@ public class BlockFunction implements Function<Void> {
protected final Returnable<Number> x, y, z;
protected final Returnable<String> blockData;
protected final Platform platform;
private final Map<String, BlockState> data = new ConcurrentHashMap<>();
private final Map<String, BlockState> data = new HashMap<>();
private final Returnable<Boolean> overwrite;
private final Returnable<Boolean> physics;
private final Position position;
@@ -10,8 +10,7 @@ package com.dfsek.terra.addons.terrascript.script.functions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.Random;
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
@@ -85,8 +84,7 @@ public class LootFunction implements Function<Void> {
if(event.isCancelled()) return;
event.getTable().fillInventory(container.getInventory(),
RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of(
"Xoroshiro128PlusPlus").create(apply.hashCode()));
new Random(apply.hashCode()));
data.update(false);
} catch(Exception e) {
LOGGER.error("Could not apply loot at {}", apply, e);
+1 -1
View File
@@ -6,6 +6,6 @@ dependencies {
api("com.dfsek.tectonic", "common", Versions.Libraries.tectonic)
api("com.github.ben-manes.caffeine", "caffeine", Versions.Libraries.caffeine)
api("com.github.ben-manes.caffeine:caffeine:3.1.0")
}
@@ -14,7 +14,6 @@ import java.io.File;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.config.PluginConfig;
import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.handle.ItemHandle;
@@ -62,10 +61,6 @@ public interface Platform extends LoaderRegistrar {
@Contract(pure = true)
CheckedRegistry<ConfigPack> getConfigRegistry();
@NotNull
@Contract(pure = true)
CheckedRegistry<MetaPack> getMetaConfigRegistry();
@NotNull
@Contract(pure = true)
Registry<BaseAddon> getAddons();
@@ -10,7 +10,6 @@ package com.dfsek.terra.api.config;
import ca.solostudios.strata.version.Version;
import ca.solostudios.strata.version.VersionRange;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
@@ -44,7 +43,7 @@ public interface ConfigPack extends LoaderRegistrar,
List<GenerationStage> getStages();
Path getRootPath();
Loader getLoader();
String getAuthor();
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2020-2023 Polyhedral Development
*
* The Terra API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the common/api directory.
*/
package com.dfsek.terra.api.config;
import com.dfsek.tectonic.api.exception.ConfigException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public interface Loader {
Loader thenNames(Consumer<List<String>> consumer) throws ConfigException;
Loader thenEntries(Consumer<Set<Map.Entry<String, InputStream>>> consumer) throws ConfigException;
/**
* Get a single file from this Loader.
*
* @param singleFile File to get
*
* @return InputStream from file.
*/
InputStream get(String singleFile) throws IOException;
/**
* Open a subdirectory.
*
* @param directory Directory to open
* @param extension File extension
*/
Loader open(String directory, String extension);
/**
* Close all InputStreams opened.
*/
Loader close();
}
@@ -1,27 +0,0 @@
package com.dfsek.terra.api.config;
import ca.solostudios.strata.version.Version;
import java.util.Map;
import com.dfsek.terra.api.properties.PropertyHolder;
import com.dfsek.terra.api.registry.key.Keyed;
import com.dfsek.terra.api.registry.meta.CheckedRegistryHolder;
import com.dfsek.terra.api.registry.meta.RegistryProvider;
import com.dfsek.terra.api.tectonic.ConfigLoadingDelegate;
import com.dfsek.terra.api.tectonic.LoaderRegistrar;
public interface MetaPack extends LoaderRegistrar,
ConfigLoadingDelegate,
CheckedRegistryHolder,
RegistryProvider,
Keyed<MetaPack>,
PropertyHolder {
Map<String, ConfigPack> packs();
String getAuthor();
Version getVersion();
}
@@ -12,6 +12,7 @@ import com.dfsek.tectonic.api.config.Configuration;
import java.util.function.BiConsumer;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.event.events.FailThroughEvent;
import com.dfsek.terra.api.event.events.PackEvent;
@@ -24,11 +25,13 @@ import com.dfsek.terra.api.event.events.PackEvent;
*/
public class ConfigurationDiscoveryEvent implements PackEvent, FailThroughEvent {
private final ConfigPack pack;
private final Loader loader;
private final BiConsumer<String, Configuration> consumer;
public ConfigurationDiscoveryEvent(ConfigPack pack, BiConsumer<String, Configuration> consumer) {
public ConfigurationDiscoveryEvent(ConfigPack pack, Loader loader, BiConsumer<String, Configuration> consumer) {
this.pack = pack;
this.loader = loader;
this.consumer = consumer;
}
@@ -40,4 +43,8 @@ public class ConfigurationDiscoveryEvent implements PackEvent, FailThroughEvent
public ConfigPack getPack() {
return pack;
}
public Loader getLoader() {
return loader;
}
}
@@ -10,7 +10,7 @@ package com.dfsek.terra.api.structure;
import org.jetbrains.annotations.ApiStatus.Experimental;
import java.util.List;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.inventory.Inventory;
import com.dfsek.terra.api.inventory.ItemStack;
@@ -22,16 +22,16 @@ public interface LootTable {
* Fills an Inventory with loot.
*
* @param i The Inventory to fill.
* @param r The The RandomGenerator instance to use.
* @param r The The Random instance to use.
*/
void fillInventory(Inventory i, RandomGenerator r);
void fillInventory(Inventory i, Random r);
/**
* Fetches a list of ItemStacks from the loot table using the given RandomGenerator instance.
* Fetches a list of ItemStacks from the loot table using the given Random instance.
*
* @param r The RandomGenerator instance to use.
* @param r The Random instance to use.
*
* @return List&lt;ItemStack&gt; - The list of loot fetched.
*/
List<ItemStack> getLoot(RandomGenerator r);
List<ItemStack> getLoot(Random r);
}
@@ -7,7 +7,7 @@
package com.dfsek.terra.api.structure;
import java.util.random.RandomGenerator;
import java.util.Random;
import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.vector.Vector3Int;
@@ -15,5 +15,5 @@ import com.dfsek.terra.api.world.WritableWorld;
public interface Structure {
boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation);
boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation);
}
@@ -10,7 +10,7 @@ package com.dfsek.terra.api.util;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
import java.util.random.RandomGenerator;
import java.util.Random;
public class ConstantRange implements Range {
@@ -36,7 +36,7 @@ public class ConstantRange implements Range {
}
@Override
public int get(RandomGenerator r) {
public int get(Random r) {
return r.nextInt(min, max);
}
@@ -1,38 +0,0 @@
package com.dfsek.terra.api.util;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.function.Function.identity;
public class FileUtil {
public static Map<String, Path> filesWithExtension(Path start, String... extensions) throws IOException {
if(Files.notExists(start) || !Files.isDirectory(start)) return Collections.emptyMap();
try(Stream<Path> paths = Files.walk(start)) {
return paths
.filter(Files::isRegularFile)
.filter(p -> Arrays.stream(extensions).anyMatch(e -> p.getFileName().toString().endsWith(e)))
.collect(Collectors.toMap(p -> start.relativize(p).toString(), identity()));
}
}
public static String fileName(String path) {
if(path.contains(File.separator)) {
return path.substring(path.lastIndexOf(File.separatorChar) + 1, path.lastIndexOf('.'));
} else if(path.contains("/")) {
return path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf('.'));
} else if(path.contains(".")) {
return path.substring(0, path.lastIndexOf('.'));
} else {
return path;
}
}
}
@@ -7,20 +7,18 @@
package com.dfsek.terra.api.util;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.Random;
import com.dfsek.terra.api.world.chunk.Chunk;
public final class PopulationUtil {
public static RandomGenerator getRandom(Chunk c) {
public static Random getRandom(Chunk c) {
return getRandom(c, 0);
}
public static RandomGenerator getRandom(Chunk c, long salt) {
return RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(
getCarverChunkSeed(c.getX(), c.getZ(), c.getWorld().getSeed() + salt));
public static Random getRandom(Chunk c, long salt) {
return new Random(getCarverChunkSeed(c.getX(), c.getZ(), c.getWorld().getSeed() + salt));
}
/**
@@ -33,7 +31,7 @@ public final class PopulationUtil {
* @return long - The carver seed.
*/
public static long getCarverChunkSeed(int chunkX, int chunkZ, long seed) {
RandomGenerator r = RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(seed);
Random r = new Random(seed);
return chunkX * r.nextLong() ^ chunkZ * r.nextLong() ^ seed;
}
}
@@ -10,8 +10,8 @@ package com.dfsek.terra.api.util;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
import java.util.Random;
import java.util.function.Supplier;
import java.util.random.RandomGenerator;
public interface Range extends Iterable<Integer> {
@@ -19,7 +19,7 @@ public interface Range extends Iterable<Integer> {
Range reflect(int pt);
int get(RandomGenerator r);
int get(Random r);
Range intersects(Range other);
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020-2023 Polyhedral Development
*
* The Terra API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the common/api directory.
*/
package com.dfsek.terra.api.util;
import java.io.File;
public class StringUtil {
public static String fileName(String path) {
if(path.contains(File.separator)) {
return path.substring(path.lastIndexOf(File.separatorChar) + 1, path.lastIndexOf('.'));
} else if(path.contains("/")) {
return path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf('.'));
} else if(path.contains(".")) {
return path.substring(0, path.lastIndexOf('.'));
} else {
return path;
}
}
}
@@ -15,9 +15,9 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.function.Function;
import java.util.random.RandomGenerator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil;
@@ -43,7 +43,7 @@ public class ProbabilityCollection<E> implements Collection<E> {
}
@SuppressWarnings("unchecked")
public E get(RandomGenerator r) {
public E get(Random r) {
if(array.length == 0) return null;
return (E) array[r.nextInt(array.length)];
}
@@ -197,7 +197,7 @@ public class ProbabilityCollection<E> implements Collection<E> {
}
@Override
public T get(RandomGenerator r) {
public T get(Random r) {
return single;
}
@@ -51,7 +51,6 @@ import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.addon.bootstrap.BootstrapAddonClassLoader;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.config.PluginConfig;
import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent;
@@ -73,8 +72,6 @@ import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.LockedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry.PackLoadFailuresException;
import com.dfsek.terra.registry.master.MetaConfigRegistry;
/**
@@ -88,12 +85,9 @@ public abstract class AbstractPlatform implements Platform {
private static final MutableBoolean LOADED = new MutableBoolean(false);
private final EventManager eventManager = new EventManagerImpl();
private final ConfigRegistry configRegistry = new ConfigRegistry();
private final MetaConfigRegistry metaConfigRegistry = new MetaConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedConfigRegistry = new CheckedRegistryImpl<>(configRegistry);
private final CheckedRegistry<MetaPack> checkedMetaConfigRegistry = new CheckedRegistryImpl<>(metaConfigRegistry);
private final Profiler profiler = new ProfilerImpl();
private final GenericLoaders loaders = new GenericLoaders(this);
@@ -108,10 +102,6 @@ public abstract class AbstractPlatform implements Platform {
return configRegistry;
}
public MetaConfigRegistry getRawMetaConfigRegistry() {
return metaConfigRegistry;
}
protected Iterable<BaseAddon> platformAddon() {
return Collections.emptySet();
}
@@ -157,12 +147,11 @@ public abstract class AbstractPlatform implements Platform {
eventManager.getHandler(FunctionalEventHandler.class)
.register(internalAddon, PlatformInitializationEvent.class)
.then(event -> loadConfigPacks())
.global();
eventManager.getHandler(FunctionalEventHandler.class)
.register(internalAddon, PlatformInitializationEvent.class)
.then(event -> loadMetaConfigPacks())
.then(event -> {
logger.info("Loading config packs...");
configRegistry.loadAll(this);
logger.info("Loaded packs.");
})
.global();
@@ -170,38 +159,6 @@ public abstract class AbstractPlatform implements Platform {
logger.info("Finished initialization.");
}
protected boolean loadConfigPacks() {
logger.info("Loading config packs...");
ConfigRegistry configRegistry = getRawConfigRegistry();
configRegistry.clear();
try {
configRegistry.loadAll(this);
} catch(IOException e) {
logger.error("Failed to load config packs", e);
return false;
} catch(PackLoadFailuresException e) {
e.getExceptions().forEach(ex -> logger.error("Failed to load config pack", ex));
return false;
}
return true;
}
protected boolean loadMetaConfigPacks() {
logger.info("Loading meta config packs...");
MetaConfigRegistry metaConfigRegistry = getRawMetaConfigRegistry();
metaConfigRegistry.clear();
try {
metaConfigRegistry.loadAll(this, configRegistry);
} catch(IOException e) {
logger.error("Failed to load meta config packs", e);
return false;
} catch(PackLoadFailuresException e) {
e.getExceptions().forEach(ex -> logger.error("Failed to meta load config pack", ex));
return false;
}
return true;
}
protected InternalAddon loadAddons() {
List<BaseAddon> addonList = new ArrayList<>();
@@ -368,12 +325,6 @@ public abstract class AbstractPlatform implements Platform {
return checkedConfigRegistry;
}
@Override
public @NotNull CheckedRegistry<MetaPack> getMetaConfigRegistry() {
return checkedMetaConfigRegistry;
}
@Override
public @NotNull Registry<BaseAddon> getAddons() {
return lockedAddonRegistry;
@@ -0,0 +1,66 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.config.fileloaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
/**
* Load all {@code *.yml} files from a {@link java.nio.file.Path}.
*/
public class FolderLoader extends LoaderImpl {
private static final Logger logger = LoggerFactory.getLogger(FolderLoader.class);
private final Path path;
public FolderLoader(Path path) {
this.path = path;
}
@Override
public InputStream get(String singleFile) throws IOException {
return new FileInputStream(new File(path.toFile(), singleFile));
}
protected void load(String directory, String extension) {
File newPath = new File(path.toFile(), directory);
newPath.mkdirs();
try(Stream<Path> paths = Files.walk(newPath.toPath())) {
paths.filter(Files::isRegularFile).filter(file -> file.toString().toLowerCase().endsWith(extension)).forEach(file -> {
try {
String rel = newPath.toPath().relativize(file).toString();
streams.put(rel, new FileInputStream(file.toFile()));
} catch(FileNotFoundException e) {
logger.error("Could not find file to load", e);
}
});
} catch(IOException e) {
logger.error("Error while loading files", e);
}
}
}
@@ -0,0 +1,83 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.config.fileloaders;
import com.dfsek.tectonic.api.exception.ConfigException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import com.dfsek.terra.api.config.Loader;
public abstract class LoaderImpl implements Loader {
private static final Logger logger = LoggerFactory.getLogger(LoaderImpl.class);
protected final Map<String, InputStream> streams = new HashMap<>();
@Override
public Loader thenNames(Consumer<List<String>> consumer) throws ConfigException {
consumer.accept(new ArrayList<>(streams.keySet()));
return this;
}
@Override
public Loader thenEntries(Consumer<Set<Map.Entry<String, InputStream>>> consumer) throws ConfigException {
consumer.accept(streams.entrySet());
return this;
}
/**
* Open a subdirectory.
*
* @param directory Directory to open
* @param extension File extension
*/
@Override
public LoaderImpl open(String directory, String extension) {
if(!streams.isEmpty()) throw new IllegalStateException("Attempted to load new directory before closing existing InputStreams");
load(directory, extension);
return this;
}
/**
* Close all InputStreams opened.
*/
@Override
public Loader close() {
streams.forEach((name, input) -> {
try {
input.close();
} catch(IOException e) {
logger.error("Error occurred while loading", e);
}
});
streams.clear();
return this;
}
protected abstract void load(String directory, String extension);
}
@@ -0,0 +1,63 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.config.fileloaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ZIPLoader extends LoaderImpl {
private static final Logger logger = LoggerFactory.getLogger(ZIPLoader.class);
private final ZipFile file;
public ZIPLoader(ZipFile file) {
this.file = file;
}
@Override
public InputStream get(String singleFile) throws IOException {
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(!entry.isDirectory() && entry.getName().equals(singleFile)) return file.getInputStream(entry);
}
throw new IllegalArgumentException("No such file: " + singleFile);
}
protected void load(String directory, String extension) {
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(!entry.isDirectory() && entry.getName().startsWith(directory) && entry.getName().endsWith(extension)) {
try {
String rel = entry.getName().substring(directory.length());
streams.put(rel, file.getInputStream(entry));
} catch(IOException e) {
logger.error("Error while loading file from zip", e);
}
}
}
}
}
@@ -27,10 +27,10 @@ import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.AnnotatedType;
import java.nio.file.Files;
import java.util.concurrent.ConcurrentHashMap;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.properties.Properties;
@@ -39,10 +39,12 @@ import com.dfsek.terra.api.properties.Properties;
*/
@Deprecated
public class BufferedImageLoader implements TypeLoader<BufferedImage> {
private final Loader files;
private final ConfigPack pack;
public BufferedImageLoader(ConfigPack pack) {
public BufferedImageLoader(Loader files, ConfigPack pack) {
this.files = files;
this.pack = pack;
if(!pack.getContext().has(ImageCache.class))
pack.getContext().put(new ImageCache(new ConcurrentHashMap<>()));
@@ -53,7 +55,7 @@ public class BufferedImageLoader implements TypeLoader<BufferedImage> {
throws LoadException {
return pack.getContext().get(ImageCache.class).map.computeIfAbsent((String) c, s -> {
try {
return ImageIO.read(Files.newInputStream(pack.getRootPath().resolve(s)));
return ImageIO.read(files.get(s));
} catch(IOException e) {
throw new LoadException("Unable to load image", e, depthTracker);
}
@@ -26,37 +26,13 @@ import com.dfsek.tectonic.api.loader.AbstractConfigLoader;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import com.dfsek.tectonic.api.loader.type.TypeLoader;
import com.dfsek.tectonic.yaml.YamlConfiguration;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.event.events.config.ConfigurationDiscoveryEvent;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
@@ -69,24 +45,39 @@ import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.tectonic.ShortcutLoader;
import com.dfsek.terra.api.util.generic.Construct;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
import com.dfsek.terra.api.world.chunk.generation.util.provider.ChunkGeneratorProvider;
import com.dfsek.terra.config.fileloaders.FolderLoader;
import com.dfsek.terra.config.fileloaders.ZIPLoader;
import com.dfsek.terra.config.loaders.GenericTemplateSupplierLoader;
import com.dfsek.terra.config.loaders.config.BufferedImageLoader;
import com.dfsek.terra.config.preprocessor.MetaListLikePreprocessor;
import com.dfsek.terra.config.preprocessor.MetaMapPreprocessor;
import com.dfsek.terra.config.preprocessor.MetaNumberPreprocessor;
import com.dfsek.terra.config.preprocessor.MetaStringPreprocessor;
import com.dfsek.terra.config.preprocessor.MetaValuePreprocessor;
import com.dfsek.terra.config.preprocessor.*;
import com.dfsek.terra.config.prototype.ProtoConfig;
import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.ShortcutHolder;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* Represents a Terra configuration pack.
@@ -101,7 +92,7 @@ public class ConfigPackImpl implements ConfigPack {
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
private final ConfigLoader selfLoader = new ConfigLoader();
private final Platform platform;
private final Path rootPath;
private final Loader loader;
private final Map<BaseAddon, VersionRange> addons;
@@ -115,29 +106,40 @@ public class ConfigPackImpl implements ConfigPack {
private final RegistryKey key;
@SuppressWarnings({ "rawtypes" })
public ConfigPackImpl(Path path, Platform platform) throws IOException {
public ConfigPackImpl(File folder, Platform platform) {
this(new FolderLoader(folder.toPath()), Construct.construct(() -> {
try {
return new YamlConfiguration(new FileInputStream(new File(folder, "pack.yml")), "pack.yml");
} catch(FileNotFoundException e) {
throw new UncheckedIOException("No pack.yml file found in " + folder.getAbsolutePath(), e);
}
}), platform);
}
public ConfigPackImpl(ZipFile file, Platform platform) {
this(new ZIPLoader(file), Construct.construct(() -> {
ZipEntry pack = null;
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(entry.getName().equals("pack.yml")) pack = entry;
}
if(pack == null) throw new IllegalArgumentException("No pack.yml file found in " + file.getName());
try {
return new YamlConfiguration(file.getInputStream(pack), "pack.yml");
} catch(IOException e) {
throw new UncheckedIOException("Unable to load pack.yml from ZIP file", e);
}
}), platform);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private ConfigPackImpl(Loader loader, Configuration packManifest, Platform platform) {
long start = System.nanoTime();
if(Files.notExists(path)) throw new FileNotFoundException("Could not load config pack, " + path + " does not exist");
if(Files.isDirectory(path)) {
this.rootPath = path;
} else if(Files.isRegularFile(path)) {
if(!path.getFileName().toString().endsWith(".zip")) {
throw new IOException("Could not load config pack, file " + path + " is not a zip");
}
FileSystem zipfs = FileSystems.newFileSystem(path);
this.rootPath = zipfs.getPath("/");
} else {
throw new IOException("Could not load config pack from " + path);
}
Path packManifestPath = rootPath.resolve("pack.yml");
if(Files.notExists(packManifestPath)) throw new IOException("No pack.yml found in " + path);
Configuration packManifest = new YamlConfiguration(Files.newInputStream(packManifestPath),
packManifestPath.getFileName().toString());
this.loader = loader;
this.platform = platform;
this.configTypeRegistry = createConfigRegistry();
@@ -221,7 +223,7 @@ public class ConfigPackImpl implements ConfigPack {
private Map<String, Configuration> discoverConfigurations() {
Map<String, Configuration> configurations = new HashMap<>();
platform.getEventManager().callEvent(new ConfigurationDiscoveryEvent(this,
platform.getEventManager().callEvent(new ConfigurationDiscoveryEvent(this, loader,
(s, c) -> configurations.put(s.replace("\\", "/"),
c))); // Create all the configs.
return configurations;
@@ -266,7 +268,7 @@ public class ConfigPackImpl implements ConfigPack {
@Override
public void register(TypeRegistry registry) {
registry.registerLoader(ConfigType.class, configTypeRegistry)
.registerLoader(BufferedImage.class, new BufferedImageLoader(this));
.registerLoader(BufferedImage.class, new BufferedImageLoader(loader, this));
registryMap.forEach(registry::registerLoader);
shortcuts.forEach(registry::registerLoader); // overwrite with delegated shortcuts if present
}
@@ -292,6 +294,7 @@ public class ConfigPackImpl implements ConfigPack {
return seededBiomeProvider;
}
@SuppressWarnings("unchecked")
@Override
public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) {
return (CheckedRegistry<T>) registryMap.computeIfAbsent(typeKey.getType(), c -> {
@@ -330,8 +333,8 @@ public class ConfigPackImpl implements ConfigPack {
}
@Override
public Path getRootPath() {
return rootPath;
public Loader getLoader() {
return loader;
}
@Override
@@ -344,7 +347,7 @@ public class ConfigPackImpl implements ConfigPack {
return template.getVersion();
}
@SuppressWarnings("rawtypes")
@SuppressWarnings("unchecked,rawtypes")
@Override
public <T> ConfigPack registerShortcut(TypeKey<T> clazz, String shortcut, ShortcutLoader<T> loader) {
ShortcutHolder<?> holder = shortcuts
@@ -388,10 +391,12 @@ public class ConfigPackImpl implements ConfigPack {
}
@Override
@SuppressWarnings("unchecked")
public <T> CheckedRegistry<T> getRegistry(Type type) {
return (CheckedRegistry<T>) registryMap.get(type);
}
@SuppressWarnings("unchecked")
@Override
public <T> CheckedRegistry<T> getCheckedRegistry(Type type) throws IllegalStateException {
return (CheckedRegistry<T>) registryMap.get(type);
@@ -1,215 +0,0 @@
package com.dfsek.terra.config.pack;
import ca.solostudios.strata.version.Version;
import com.dfsek.tectonic.api.TypeRegistry;
import com.dfsek.tectonic.api.config.Configuration;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.tectonic.api.loader.AbstractConfigLoader;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import com.dfsek.tectonic.api.loader.type.TypeLoader;
import com.dfsek.tectonic.yaml.YamlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.loaders.GenericTemplateSupplierLoader;
import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class MetaPackImpl implements MetaPack {
private static final Pattern PATTERN = Pattern.compile(", ");
private static final Logger logger = LoggerFactory.getLogger(MetaPackImpl.class);
private final MetaPackTemplate template = new MetaPackTemplate();
private final Platform platform;
private final Path rootPath;
private final Map<String, ConfigPack> packs = new HashMap<>();
private final ConfigLoader selfLoader = new ConfigLoader();
private final Context context = new Context();
private final RegistryKey key;
private final Map<Type, CheckedRegistryImpl<?>> registryMap = new HashMap<>();
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
private final String author;
public MetaPackImpl(Path path, Platform platform, ConfigRegistry configRegistry) throws IOException {
long start = System.nanoTime();
if(Files.notExists(path)) throw new FileNotFoundException("Could not load metapack, " + path + " does not exist");
if(Files.isDirectory(path)) {
this.rootPath = path;
} else if(Files.isRegularFile(path)) {
if(!path.getFileName().toString().endsWith(".zip")) {
throw new IOException("Could not load metapack, file " + path + " is not a zip");
}
FileSystem zipfs = FileSystems.newFileSystem(path);
this.rootPath = zipfs.getPath("/");
} else {
throw new IOException("Could not load metapack from " + path);
}
Path packManifestPath = rootPath.resolve("metapack.yml");
if(Files.notExists(packManifestPath)) throw new IOException("No metapack.yml found in " + path);
Configuration packManifest = new YamlConfiguration(Files.newInputStream(packManifestPath),
packManifestPath.getFileName().toString());
this.platform = platform;
register(selfLoader);
platform.register(selfLoader);
register(abstractConfigLoader);
platform.register(abstractConfigLoader);
selfLoader.load(template, packManifest);
String namespace;
String id;
if(template.getID().contains(":")) {
namespace = template.getID().substring(0, template.getID().indexOf(":"));
id = template.getID().substring(template.getID().indexOf(":") + 1);
} else {
id = template.getID();
namespace = template.getID();
}
this.key = RegistryKey.of(namespace, id);
logger.info("Loading metapack \"{}:{}\"", id, namespace);
template.getPacks().forEach((k, v) -> {
RegistryKey registryKey = RegistryKey.parse(v);
if(configRegistry.contains(registryKey)) {
packs.put(k, configRegistry.get(registryKey).get());
logger.info("Linked config pack \"{}\" to metapack \"{}:{}\".", v, namespace, id);
} else {
logger.warn("Failed to link config pack \"{}\" to metapack \"{}:{}\".", v, namespace, id);
}
});
HashSet<String> authors = new HashSet<>();
packs.forEach((k, v) -> {
authors.addAll(Arrays.asList(PATTERN.split(v.getAuthor())));
});
authors.addAll(Arrays.asList(PATTERN.split(template.getAuthor())));
this.author = String.join(", ", authors);
logger.info("Loaded metapack \"{}:{}\" v{} by {} in {}ms.",
namespace, id, getVersion().getFormatted(), author, (System.nanoTime() - start) / 1000000.0D);
}
@Override
public String getAuthor() {
return author;
}
@Override
public Version getVersion() {
return template.getVersion();
}
@Override
public Map<String, ConfigPack> packs() {
return packs;
}
@Override
public Context getContext() {
return context;
}
@Override
public RegistryKey getRegistryKey() {
return key;
}
@Override
public <T> CheckedRegistry<T> getRegistry(Type type) {
return (CheckedRegistry<T>) registryMap.get(type);
}
@Override
public <T> CheckedRegistry<T> getCheckedRegistry(Type type) throws IllegalStateException {
return (CheckedRegistry<T>) registryMap.get(type);
}
@Override
public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) {
return (CheckedRegistry<T>) registryMap.computeIfAbsent(typeKey.getType(), c -> {
OpenRegistry<T> registry = new OpenRegistryImpl<>(typeKey);
selfLoader.registerLoader(c, registry);
abstractConfigLoader.registerLoader(c, registry);
logger.debug("Registered loader for registry of class {}", ReflectionUtil.typeToString(c));
if(typeKey.getType() instanceof ParameterizedType param) {
Type base = param.getRawType();
if(base instanceof Class // should always be true but we'll check anyways
&& Supplier.class.isAssignableFrom((Class<?>) base)) { // If it's a supplier
Type supplied = param.getActualTypeArguments()[0]; // Grab the supplied type
if(supplied instanceof ParameterizedType suppliedParam) {
Type suppliedBase = suppliedParam.getRawType();
if(suppliedBase instanceof Class // should always be true but we'll check anyways
&& ObjectTemplate.class.isAssignableFrom((Class<?>) suppliedBase)) {
Type templateType = suppliedParam.getActualTypeArguments()[0];
GenericTemplateSupplierLoader<?> loader = new GenericTemplateSupplierLoader<>(
(Registry<Supplier<ObjectTemplate<Supplier<ObjectTemplate<?>>>>>) registry);
selfLoader.registerLoader(templateType, loader);
abstractConfigLoader.registerLoader(templateType, loader);
logger.debug("Registered template loader for registry of class {}", ReflectionUtil.typeToString(templateType));
}
}
}
}
return new CheckedRegistryImpl<>(registry);
});
}
@Override
public <T> MetaPackImpl applyLoader(Type type, TypeLoader<T> loader) {
abstractConfigLoader.registerLoader(type, loader);
selfLoader.registerLoader(type, loader);
return this;
}
@Override
public <T> MetaPackImpl applyLoader(Type type, Supplier<ObjectTemplate<T>> loader) {
abstractConfigLoader.registerLoader(type, loader);
selfLoader.registerLoader(type, loader);
return this;
}
@Override
public void register(TypeRegistry registry) {
registryMap.forEach(registry::registerLoader);
}
}
@@ -1,41 +0,0 @@
package com.dfsek.terra.config.pack;
import ca.solostudios.strata.version.Version;
import com.dfsek.tectonic.api.config.template.ConfigTemplate;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import java.util.Map;
@SuppressWarnings({ "unused", "FieldMayBeFinal" })
public class MetaPackTemplate implements ConfigTemplate {
@Value("id")
private String id;
@Value("author")
@Default
private String author = "Anon Y. Mous";
@Value("version")
private Version version;
@Value("packs")
private Map<String, String> packs;
public String getID() {
return id;
}
public String getAuthor() {
return author;
}
public Version getVersion() {
return version;
}
public Map<String, String> getPacks() {
return packs;
}
}
@@ -17,13 +17,14 @@
package com.dfsek.terra.registry.master;
import com.dfsek.tectonic.api.exception.ConfigException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.Serial;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.util.Objects;
import java.util.zip.ZipFile;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigPack;
@@ -36,42 +37,44 @@ import com.dfsek.terra.registry.OpenRegistryImpl;
* Class to hold config packs
*/
public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
private static final Logger logger = LoggerFactory.getLogger(ConfigRegistry.class);
public ConfigRegistry() {
super(TypeKey.of(ConfigPack.class));
}
public void loadAll(Platform platform) throws IOException, PackLoadFailuresException {
Path packsDirectory = platform.getDataFolder().toPath().resolve("packs");
Files.createDirectories(packsDirectory);
List<IOException> failedLoads = new ArrayList<>();
try(Stream<Path> packs = Files.list(packsDirectory)) {
packs.forEach(path -> {
try {
ConfigPack pack = new ConfigPackImpl(path, platform);
registerChecked(pack.getRegistryKey(), pack);
} catch(IOException e) {
failedLoads.add(e);
}
});
}
if(!failedLoads.isEmpty()) {
throw new PackLoadFailuresException(failedLoads);
}
public void load(File folder, Platform platform) throws ConfigException {
ConfigPack pack = new ConfigPackImpl(folder, platform);
registerChecked(pack.getRegistryKey(), pack);
}
public static class PackLoadFailuresException extends Exception {
@Serial
private static final long serialVersionUID = 538998844645186306L;
private final List<Throwable> exceptions;
public PackLoadFailuresException(List<? extends Throwable> exceptions) {
this.exceptions = (List<Throwable>) exceptions;
public boolean loadAll(Platform platform) {
boolean valid = true;
File packsFolder = new File(platform.getDataFolder(), "packs");
packsFolder.mkdirs();
for(File dir : Objects.requireNonNull(packsFolder.listFiles(File::isDirectory))) {
try {
load(dir, platform);
} catch(ConfigException e) {
logger.error("Error loading config pack {}", dir.getName(), e);
valid = false;
}
}
public List<Throwable> getExceptions() {
return exceptions;
for(File zip : Objects.requireNonNull(
packsFolder.listFiles(file -> file.getName().endsWith(".zip") || file.getName().endsWith(".terra")))) {
try {
logger.info("Loading ZIP archive: {}", zip.getName());
load(new ZipFile(zip), platform);
} catch(IOException | ConfigException e) {
logger.error("Error loading config pack {}", zip.getName(), e);
valid = false;
}
}
return valid;
}
public void load(ZipFile file, Platform platform) throws ConfigException {
ConfigPackImpl pack = new ConfigPackImpl(file, platform);
registerChecked(pack.getRegistryKey(), pack);
}
}
@@ -1,62 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.registry.master;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.pack.MetaPackImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry.PackLoadFailuresException;
/**
* Class to hold config packs
*/
public class MetaConfigRegistry extends OpenRegistryImpl<MetaPack> {
public MetaConfigRegistry() {
super(TypeKey.of(MetaPack.class));
}
public void loadAll(Platform platform, ConfigRegistry configRegistry) throws IOException, PackLoadFailuresException {
Path packsDirectory = platform.getDataFolder().toPath().resolve("metapacks");
Files.createDirectories(packsDirectory);
List<IOException> failedLoads = new ArrayList<>();
try(Stream<Path> packs = Files.list(packsDirectory)) {
packs.forEach(path -> {
try {
MetaPack pack = new MetaPackImpl(path, platform, configRegistry);
registerChecked(pack.getRegistryKey(), pack);
} catch(IOException e) {
failedLoads.add(e);
}
});
}
if(!failedLoads.isEmpty()) {
throw new PackLoadFailuresException(failedLoads);
}
}
}
Binary file not shown.
+1 -2
View File
@@ -1,7 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+7 -7
View File
@@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -202,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
+7 -1
View File
@@ -10,13 +10,19 @@ repositories {
dependencies {
shaded(project(":platforms:bukkit:common"))
shaded(project(":platforms:bukkit:nms:v1_20_R3", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_18_R2", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R1", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R2", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R3", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_20_R1", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_20_R2", configuration = "reobf"))
shaded("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
tasks {
shadowJar {
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
relocate("com.tcoded.folialib", "com.dfsek.terra.lib.folialib")
relocate("com.google.common", "com.dfsek.terra.lib.google.common")
relocate("org.apache.logging.slf4j", "com.dfsek.terra.lib.slf4j-over-log4j")
exclude("org/slf4j/**")
+3 -1
View File
@@ -8,7 +8,9 @@ dependencies {
compileOnly("io.papermc.paper", "paper-api", Versions.Bukkit.paper)
shadedApi("io.papermc", "paperlib", Versions.Bukkit.paperLib)
// TODO: 2023-11-08 When we drop support for 1.18 and 1.19, we can remove FoliaLib and instead use `RegionScheduler`,
// AsyncScheduler, or GlobalRegionScheduler.
shadedApi("com.tcoded", "FoliaLib", Versions.Bukkit.foliaLib)
shadedApi("com.google.guava", "guava", Versions.Libraries.Internal.guava)
shadedApi("cloud.commandframework", "cloud-paper", Versions.Libraries.cloud)
@@ -63,7 +63,8 @@ public class PlatformImpl extends AbstractPlatform {
@Override
public boolean reload() {
getTerraConfig().load(this);
boolean succeed = loadConfigPacks();
getRawConfigRegistry().clear();
boolean succeed = getRawConfigRegistry().loadAll(this);
Bukkit.getWorlds().forEach(world -> {
if(world.getGenerator() instanceof BukkitChunkGeneratorWrapper wrapper) {
@@ -83,8 +84,8 @@ public class PlatformImpl extends AbstractPlatform {
}
@Override
public void runPossiblyUnsafeTask(@NotNull Runnable runnable) {
plugin.getGlobalRegionScheduler().run(plugin, task -> runnable.run());
public void runPossiblyUnsafeTask(@NotNull Runnable task) {
plugin.getFoliaLib().getImpl().runAsync(task);
}
@Override
@@ -21,8 +21,7 @@ import cloud.commandframework.brigadier.CloudBrigadierManager;
import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.execution.CommandExecutionCoordinator;
import cloud.commandframework.paper.PaperCommandManager;
import io.papermc.paper.threadedregions.scheduler.AsyncScheduler;
import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler;
import com.tcoded.folialib.FoliaLib;
import org.bukkit.Bukkit;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
@@ -33,7 +32,6 @@ import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.dfsek.terra.api.command.CommandSender;
import com.dfsek.terra.api.config.ConfigPack;
@@ -53,9 +51,7 @@ public class TerraBukkitPlugin extends JavaPlugin {
private final PlatformImpl platform = new PlatformImpl(this);
private final Map<String, com.dfsek.terra.api.world.chunk.generation.ChunkGenerator> generatorMap = new HashMap<>();
private AsyncScheduler asyncScheduler = this.getServer().getAsyncScheduler();
private GlobalRegionScheduler globalRegionScheduler = this.getServer().getGlobalRegionScheduler();
private final FoliaLib foliaLib = new FoliaLib(this);
@Override
public void onEnable() {
@@ -65,10 +61,6 @@ public class TerraBukkitPlugin extends JavaPlugin {
platform.getEventManager().callEvent(new PlatformInitializationEvent());
if(!Initializer.init(platform)) {
Bukkit.getPluginManager().disablePlugin(this);
return;
}
try {
PaperCommandManager<CommandSender> commandManager = getCommandSenderPaperCommandManager();
@@ -88,6 +80,8 @@ public class TerraBukkitPlugin extends JavaPlugin {
Bukkit.getPluginManager().registerEvents(new CommonListener(), this); // Register master event listener
PaperUtil.checkPaper(this);
Initializer.init(platform);
}
@NotNull
@@ -122,9 +116,6 @@ public class TerraBukkitPlugin extends JavaPlugin {
if(!VersionUtil.getSpigotVersionInfo().isSpigot())
logger.error("YOU ARE RUNNING A CRAFTBUKKIT OR BUKKIT SERVER. PLEASE UPGRADE TO PAPER.");
if(!VersionUtil.getSpigotVersionInfo().isPaper())
logger.error("YOU ARE RUNNING A SPIGOT SERVER. PLEASE UPGRADE TO PAPER.");
if(VersionUtil.getSpigotVersionInfo().isMohist()) {
if(System.getProperty("IKnowMohistCausesLotsOfIssuesButIWillUseItAnyways") == null) {
Runnable runnable = () -> { // scary big block of text
@@ -168,7 +159,7 @@ public class TerraBukkitPlugin extends JavaPlugin {
""".strip());
};
runnable.run();
asyncScheduler.runDelayed(this, task -> runnable.run(), 200L, TimeUnit.SECONDS);
foliaLib.getImpl().runLaterAsync(runnable, 200L);
// Bukkit.shutdown(); // we're not *that* evil
Bukkit.getPluginManager().disablePlugin(this);
return false;
@@ -196,11 +187,7 @@ public class TerraBukkitPlugin extends JavaPlugin {
}), platform.getRawConfigRegistry().getByID(id).orElseThrow(), platform.getWorldHandle().air());
}
public AsyncScheduler getAsyncScheduler() {
return asyncScheduler;
}
public GlobalRegionScheduler getGlobalRegionScheduler() {
return globalRegionScheduler;
public FoliaLib getFoliaLib() {
return foliaLib;
}
}
@@ -28,7 +28,6 @@ import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Random;
import java.util.random.RandomGenerator;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.config.ConfigPack;
@@ -20,8 +20,6 @@ package com.dfsek.terra.bukkit.handles;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Locale;
@@ -33,7 +31,6 @@ import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;
public class BukkitWorldHandle implements WorldHandle {
private static final Logger logger = LoggerFactory.getLogger(BukkitWorldHandle.class);
private final BlockState air;
public BukkitWorldHandle() {
@@ -42,13 +39,6 @@ public class BukkitWorldHandle implements WorldHandle {
@Override
public synchronized @NotNull BlockState createBlockState(@NotNull String data) {
if(data.equals("minecraft:grass")) { //TODO: remove in 7.0
data = "minecraft:short_grass";
logger.warn(
"Translating minecraft:grass to minecraft:short_grass. In 1.20.3 minecraft:grass was renamed to minecraft:short_grass" +
". You are advised to perform this rename in your config backs as this translation will be removed in the next major " +
"version of Terra.");
}
org.bukkit.block.data.BlockData bukkitData = Bukkit.createBlockData(
data); // somehow bukkit managed to make this not thread safe! :)
return BukkitBlockState.newInstance(bukkitData);
@@ -61,13 +51,6 @@ public class BukkitWorldHandle implements WorldHandle {
@Override
public @NotNull EntityType getEntity(@NotNull String id) {
if(!id.contains(":")) { //TODO: remove in 7.0
String newid = "minecraft:" + id.toLowerCase();
logger.warn(
"Translating " + id + " to " + newid + ". In 1.20.3 entity parsing was reworked" +
". You are advised to perform this rename in your config backs as this translation will be removed in the next major " +
"version of Terra.");
}
if(!id.startsWith("minecraft:")) throw new IllegalArgumentException("Invalid entity identifier " + id);
String entityID = id.toUpperCase(Locale.ROOT).substring(10);
@@ -11,7 +11,7 @@ public interface Initializer {
String NMS = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
String TERRA_PACKAGE = Initializer.class.getPackageName();
static boolean init(PlatformImpl platform) {
static void init(PlatformImpl platform) {
Logger logger = LoggerFactory.getLogger(Initializer.class);
try {
Class<?> initializerClass = Class.forName(TERRA_PACKAGE + "." + NMS + ".NMSInitializer");
@@ -24,27 +24,16 @@ public interface Initializer {
} catch(ClassNotFoundException e) {
logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS);
logger.error("This is usually due to running Terra on an unsupported Minecraft version.");
String bypassKey = "IKnowThereAreNoNMSBindingsFor" + NMS + "ButIWillProceedAnyway";
if(System.getProperty(bypassKey) == null) {
logger.error("Because of this **TERRA HAS BEEN DISABLED**.");
logger.error("Do not come ask us why it is not working.");
logger.error("If you wish to proceed anyways, you can add the JVM System Property \"{}\" to enable the plugin.", bypassKey);
return false;
} else {
logger.error("");
logger.error("");
for(int i = 0; i < 20; i++) {
logger.error("PROCEEDING WITH AN EXISTING TERRA WORLD WILL RESULT IN CORRUPTION!!!");
}
logger.error("");
logger.error("");
logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS);
logger.error("This is usually due to running Terra on an unsupported Minecraft version.");
logger.error("We will not give you any support for issues that may arise.");
logger.error("Since you enabled the \"{}\" flag, we won't disable Terra. But be warned.", bypassKey);
logger.error("");
logger.error("");
for(int i = 0; i < 20; i++) {
logger.error("PROCEEDING WITH AN EXISTING TERRA WORLD WILL RESULT IN CORRUPTION!!!");
}
logger.error("");
logger.error("");
logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS);
logger.error("This is usually due to running Terra on an unsupported Minecraft version.");
}
return true;
}
void initialize(PlatformImpl plugin);
@@ -19,8 +19,6 @@ package com.dfsek.terra.bukkit.util;
import io.papermc.lib.PaperLib;
import java.util.concurrent.TimeUnit;
import com.dfsek.terra.bukkit.TerraBukkitPlugin;
import static io.papermc.lib.PaperLib.suggestPaper;
@@ -28,10 +26,10 @@ import static io.papermc.lib.PaperLib.suggestPaper;
public final class PaperUtil {
public static void checkPaper(TerraBukkitPlugin plugin) {
plugin.getAsyncScheduler().runDelayed(plugin, task -> {
plugin.getFoliaLib().getImpl().runLaterAsync(() -> {
if(!PaperLib.isPaper()) {
suggestPaper(plugin);
}
}, 100L, TimeUnit.SECONDS);
}, 100L);
}
}
@@ -4,6 +4,6 @@ version: "@VERSION@"
load: "STARTUP"
author: dfsek
website: "@WIKI@"
api-version: "1.20"
api-version: "1.13"
description: "@DESCRIPTION@"
folia-supported: true
@@ -0,0 +1,17 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle("1.18.2-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
tasks {
assemble {
dependsOn("reobfJar")
}
}
@@ -0,0 +1,115 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSBiomeInjector.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) Registries.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(
biome,
biomeRegistry.get(vanillaMinecraftKey) // get
);
ResourceKey<Biome> delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY, new ResourceLocation("terra",
NMSBiomeInjector.createBiomeID(
pack, key)));
BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform);
biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
platformBiome.getContext().put(new NMSBiomeInfo(delegateKey));
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<TagKey<Biome>, List<Holder<Biome>>> collect = biomeRegistry
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
terraBiomeMap
.forEach((vb, terraBiomes) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb)
.ifPresentOrElse(
vanilla -> terraBiomes
.forEach(tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb)
.ifPresentOrElse(
terra -> {
LOGGER.debug(
vanilla.unwrapKey()
.orElseThrow()
.location() +
" (vanilla for " +
terra.unwrapKey()
.orElseThrow()
.location() +
": " +
vanilla.tags()
.toList());
vanilla.tags()
.forEach(
tag -> collect
.computeIfAbsent(
tag,
t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error(
"No such biome: {}",
tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.resetTags(); // clearTags
biomeRegistry.bindTags(ImmutableMap.copyOf(collect)); // populateTags
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_20_R3;
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
@@ -0,0 +1,79 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.map(registry::getOrCreateHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder(); // Builder
builder.biomeCategory(Reflection.BIOME.getBiomeCategory(vanilla))
.precipitation(vanilla.getPrecipitation()) // getPrecipitation
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings())
.temperature(vanilla.getBaseTemperature())
.downfall(vanilla.getDownfall());
BiomeSpecialEffects.Builder effects = new BiomeSpecialEffects.Builder();
effects.grassColorModifier(vanilla.getSpecialEffects().getGrassColorModifier());
VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class);
effects.fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor()))
.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor()))
.waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor()))
.skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor()));
if(vanillaBiomeProperties.getFoliageColor() == null) {
vanilla.getSpecialEffects().getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
} else {
effects.foliageColorOverride(vanillaBiomeProperties.getFoliageColor());
}
if(vanillaBiomeProperties.getGrassColor() == null) {
vanilla.getSpecialEffects().getGrassColorOverride().ifPresent(effects::grassColorOverride);
} else {
effects.grassColorOverride(vanillaBiomeProperties.getGrassColor());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build(); // build()
}
public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) {
return pack.getID()
.toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT);
}
}
@@ -0,0 +1,49 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate.Sampler;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
public class NMSBiomeProvider extends BiomeSource {
private final BiomeProvider delegate;
private final BiomeSource vanilla;
private final long seed;
private final Registry<Biome> biomeRegistry = Registries.biomeRegistry();
public NMSBiomeProvider(BiomeProvider delegate, BiomeSource vanilla, long seed) {
super(delegate.stream()
.map(biome -> Registries.biomeRegistry()
.getOrCreateHolder(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey())));
this.delegate = delegate;
this.vanilla = vanilla;
this.seed = seed;
}
@Override
protected Codec<? extends BiomeSource> codec() {
return BiomeSource.CODEC;
}
@Override
public @NotNull BiomeSource withSeed(long seed) {
return new NMSBiomeProvider(delegate, vanilla, seed);
}
@Override
public @NotNull Holder<Biome> getNoiseBiome(int x, int y, int z, @NotNull Sampler sampler) {
return biomeRegistry.getOrCreateHolder(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed).getPlatformBiome())
.getContext()
.get(NMSBiomeInfo.class)
.biomeKey());
}
}
@@ -0,0 +1,254 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.NoiseColumn;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.biome.Climate;
import net.minecraft.world.level.biome.Climate.Sampler;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.blending.Blender;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.util.generic.Lazy;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSChunkGeneratorDelegate.class);
private static final Lazy<List<ChunkPos>> EMPTY = Lazy.lazy(List::of);
private final NMSBiomeProvider biomeSource;
private final com.dfsek.terra.api.world.chunk.generation.ChunkGenerator delegate;
private final ChunkGenerator vanilla;
private final ConfigPack pack;
private final long seed;
private final Map<ConcentricRingsStructurePlacement, Lazy<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap<>();
private volatile boolean rings = false;
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
super(Registries.structureSet(), Optional.empty(), biomeProvider, biomeProvider, seed);
this.delegate = pack.getGeneratorProvider().newInstance(pack);
this.vanilla = vanilla;
this.biomeSource = biomeProvider;
this.pack = pack;
this.seed = seed;
}
@Override
public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull BiomeManager biomeAccess,
@NotNull StructureFeatureManager structureAccessor,
@NotNull ChunkAccess chunk, GenerationStep.@NotNull Carving generationStep) {
// no-op
}
@Override
public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk,
@NotNull StructureFeatureManager structureAccessor) {
vanilla.applyBiomeDecoration(world, chunk, structureAccessor);
}
@Override
public int getSeaLevel() {
return vanilla.getSeaLevel();
}
@Override
public @NotNull CompletableFuture<ChunkAccess> fillFromNoise(@NotNull Executor executor, @NotNull Blender blender,
@NotNull StructureFeatureManager structureAccessor,
@NotNull ChunkAccess chunk) {
return vanilla.fillFromNoise(executor, blender, structureAccessor, chunk);
}
@Override
public void buildSurface(@NotNull WorldGenRegion region, @NotNull StructureFeatureManager structures, @NotNull ChunkAccess chunk) {
// no-op
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return ChunkGenerator.CODEC;
}
@Override
public @NotNull NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor height) {
/*
BlockState[] array = new BlockState[height.getHeight()];
WorldProperties properties = new NMSWorldProperties(seed, height);
BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties);
for(int y = properties.getMaxHeight() - 1; y >= properties.getMinHeight(); y--) {
array[y - properties.getMinHeight()] = ((CraftBlockData) delegate.getBlock(properties, x, y, z, biomeProvider)
.getHandle()).getState();
}
return new NoiseColumn(getMinY(), array);
*/
return vanilla.getBaseColumn(x, z, height);
}
@Override // withSeed
public @NotNull ChunkGenerator withSeed(long seed) {
return new NMSChunkGeneratorDelegate(vanilla, pack, biomeSource, seed);
}
@Override
public void spawnOriginalMobs(@NotNull WorldGenRegion regionlimitedworldaccess) {
vanilla.spawnOriginalMobs(regionlimitedworldaccess);
}
@Override
public int getGenDepth() {
return vanilla.getGenDepth();
}
@Override
public @NotNull Sampler climateSampler() {
return Climate.empty();
}
@Override
public int getMinY() {
return vanilla.getMinY();
}
@Override
public int getBaseHeight(int x, int z, Heightmap.@NotNull Types heightmap, @NotNull LevelHeightAccessor world) {
WorldProperties properties = new NMSWorldProperties(seed, world);
int y = properties.getMaxHeight();
BiomeProvider biomeProvider = pack.getBiomeProvider();
while(y >= getMinY() && !heightmap.isOpaque().test(
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
y--;
}
return y;
}
@Nullable
@Override
public List<ChunkPos> getRingPositionsFor(@NotNull ConcentricRingsStructurePlacement concentricringsstructureplacement) {
ensureStructuresGenerated();
return ringPositions.getOrDefault(concentricringsstructureplacement, EMPTY).value();
}
@Override
public synchronized void ensureStructuresGenerated() {
if(!this.rings) {
super.ensureStructuresGenerated();
this.populateStrongholdData();
this.rings = true;
}
}
private void populateStrongholdData() {
LOGGER.info("Generating safe stronghold data. This may take up to a minute.");
Set<Holder<Biome>> set = this.runtimeBiomeSource.possibleBiomes();
possibleStructureSets().map(Holder::value).forEach((holder) -> { // we dont need the spigot crap because it doesnt touch concentric.
StructurePlacement structureplacement = holder.placement();
if(structureplacement instanceof ConcentricRingsStructurePlacement concentricringsstructureplacement) {
if(holder.structures().stream().anyMatch((structureset_a1) -> structureset_a1.generatesInMatchingBiome(set::contains))) {
this.ringPositions.put(concentricringsstructureplacement,
Lazy.lazy(() -> this.generateRingPositions(holder, concentricringsstructureplacement)));
}
}
});
}
private List<ChunkPos> generateRingPositions(StructureSet holder,
ConcentricRingsStructurePlacement concentricringsstructureplacement) { // Spigot
if(concentricringsstructureplacement.count() == 0) {
return List.of();
}
List<ChunkPos> list = new ArrayList<>();
Set<Holder<Biome>> set = holder
.structures()
.stream()
.flatMap((structureset_a) -> structureset_a.structure().value().biomes().stream())
.collect(Collectors.toSet());
int i = concentricringsstructureplacement.distance();
int j = concentricringsstructureplacement.count();
int k = concentricringsstructureplacement.spread();
Random random = new Random();
// Paper start
if(this.conf.strongholdSeed != null && this.structureSets.getResourceKey(holder).orElse(null) ==
net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS) {
random.setSeed(this.conf.strongholdSeed);
} else {
// Paper end
random.setSeed(this.ringPlacementSeed);
} // Paper
double d0 = random.nextDouble() * 3.141592653589793D * 2.0D;
int l = 0;
int i1 = 0;
for(int j1 = 0; j1 < j; ++j1) {
double d1 = (double) (4 * i + i * i1 * 6) + (random.nextDouble() - 0.5D) * (double) i * 2.5D;
int k1 = (int) Math.round(MathUtil.cos(d0) * d1);
int l1 = (int) Math.round(MathUtil.sin(d0) * d1);
int i2 = SectionPos.sectionToBlockCoord(k1, 8);
int j2 = SectionPos.sectionToBlockCoord(l1, 8);
Objects.requireNonNull(set);
Pair<BlockPos, Holder<Biome>> pair = this.biomeSource.findBiomeHorizontal(i2, 0, j2, 112, set::contains, random,
this.climateSampler());
if(pair != null) {
BlockPos blockposition = pair.getFirst();
k1 = SectionPos.blockToSectionCoord(blockposition.getX());
l1 = SectionPos.blockToSectionCoord(blockposition.getZ());
}
list.add(new ChunkPos(k1, l1));
d0 += 6.283185307179586D / (double) k;
++l;
if(l == k) {
++i1;
l = 0;
k += 2 * k / (i1 + 1);
k = Math.min(k, j - j1);
d0 += random.nextDouble() * 3.141592653589793D * 2.0D;
}
}
return list;
}
@Override
public void addDebugScreenInfo(@NotNull List<String> arg0, @NotNull BlockPos arg1) {
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_20_R3;
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import org.bukkit.Bukkit;

Some files were not shown because too many files have changed in this diff Show More