Merge branch 'gh-builds'

# Conflicts:
#	build.gradle.kts
#	src/main/java/com/dfsek/terra/config/genconfig/CarverConfig.java
#	src/main/java/com/dfsek/terra/config/genconfig/FloraConfig.java
#	src/main/java/com/dfsek/terra/config/genconfig/OreConfig.java
#	src/main/java/com/dfsek/terra/config/genconfig/PaletteConfig.java
#	src/main/java/com/dfsek/terra/config/genconfig/biome/BiomeConfig.java
#	src/main/java/com/dfsek/terra/config/genconfig/biome/BiomeSnowConfig.java
#	src/test/java/LookupGeneratorTest.java
This commit is contained in:
solonovamax
2020-11-24 18:35:33 -05:00
87 changed files with 1907 additions and 906 deletions

40
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Java CI with Gradle
on:
push:
tags:
- "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build Terra
run: gradle shadowJar
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: Package
path: build/libs
- name: Publish release
uses: marvinpinto/action-automatic-releases@latest
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
prerelease: false
files: |
build/libs/Terra-*.jar
LICENSE

3
.gitignore vendored
View File

@@ -135,4 +135,5 @@ build
.idea/**.xml
.idea/modules/**.iml
!lib/*.jar
!lib/*.jar
.idea/Terra.iml

View File

@@ -15,7 +15,6 @@ plugins {
}
repositories {
mavenCentral()
flatDir {
dirs("lib")
}
@@ -23,6 +22,7 @@ repositories {
maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
// maven { url = uri("https://maven.pkg.github.com/solonovamax/Gaea") }
}
java {
@@ -30,49 +30,36 @@ java {
targetCompatibility = JavaVersion.VERSION_1_8
}
val versionObj = Version("1", "3", "1", true)
val versionObj = Version("1", "5", "0", true)
version = versionObj
dependencies {
// Commons. Used for stuff.
implementation("commons-io:commons-io:2.4")
// Commons-imagine. Used for loading images from disk for the biome images.
implementation("org.apache.commons:commons-imaging:1.0-alpha2")
// Bstats. For tracking stats.
implementation("org.bstats:bstats-bukkit:1.7")
// Parsii. Does parsing of the equations.
implementation(name = "parsii-1.2", group = "")
// Papermc API. for Paper spigot
implementation("io.papermc:paperlib:1.0.5")
// Jackson
implementation("com.fasterxml.jackson.core:jackson-core:2.11+")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.11+")
implementation("com.fasterxml.jackson.core:jackson-databind:2.11+")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11+")
// Spigot mc API. Provided by spigot.
compileOnly("org.spigotmc:spigot-api:1.16.2-R0.1-SNAPSHOT")
// Annotations. Provided by mc.
compileOnly("org.jetbrains:annotations:20.1.0")
// Gaea. Provided as a plugin.
val gaeaVersion = "1.14.2"
val gaeaVersion = "1.14.3"
compileOnly(name = "Gaea-${gaeaVersion}", group = "")
testImplementation(name = "Gaea-${gaeaVersion}", group = "")
// Worldedit. For saving structures. Provided as a plugin.
compileOnly("org.jetbrains:annotations:20.1.0")
implementation("commons-io:commons-io:2.4")
implementation("org.apache.commons:commons-imaging:1.0-alpha2")
compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.0-SNAPSHOT")
// GSON. idk how it's used.
implementation("org.bstats:bstats-bukkit:1.7")
compileOnly("com.googlecode.json-simple:json-simple:1.1")
// JUnit. Used for testing.
implementation(name = "parsii-1.2.1", group = "")
compileOnly("org.spigotmc:spigot-api:1.16.2-R0.1-SNAPSHOT")
implementation("io.papermc:paperlib:1.0.5")
implementation("net.jafama:jafama:2.3.2")
// JUnit.
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
// Included here becaues tests rely on it.
testImplementation(name = "Gaea-1.14.2", group = "")
testImplementation("org.spigotmc:spigot-api:1.16.2-R0.1-SNAPSHOT")
}
val compileJava: JavaCompile by tasks
@@ -81,6 +68,7 @@ val mainSourceSet: SourceSet = sourceSets["main"]
val tokenizeJavaSources = task<Copy>(name = "tokenizeJavaSources") {
from(mainSourceSet.allSource) {
include("**/plugin.yml")
println("version: $versionObj")
val tokens = mapOf("VERSION" to versionObj.toString())
filter(org.apache.tools.ant.filters.ReplaceTokens::class, "tokens" to tokens)
@@ -118,6 +106,8 @@ tasks.named<ShadowJar>("shadowJar") {
relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats")
relocate("parsii", "com.dfsek.terra.lib.parsii")
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
relocate("net.jafama", "com.dfsek.terra.lib.jafama")
minimize()
}
tasks.build {
@@ -204,31 +194,13 @@ val testWithPaper = task<JavaExec>(name = "testWithPaper") {
classpath = files("${testDir}/paper.jar")
}
tasks.named<ShadowJar>("shadowJar") {
archiveClassifier.set("")
archiveBaseName.set("Terra")
setVersion(project.version)
relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats")
relocate("parsii", "com.dfsek.terra.lib.parsii")
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
relocate("com.fasterxml.jackson", "com.dfsek.terra.lib.jackson")
}
tasks.build {
dependsOn(tasks.test)
dependsOn(tasks.shadowJar)
// dependsOn(testWithPaper)
tasks.shadowJar.get().mustRunAfter(tasks.test)
// testWithPaper.mustRunAfter(tasks.shadowJar)
}
/**
* Version class that does version stuff.
*/
@Suppress("MemberVisibilityCanBePrivate")
class Version(val major: String, val minor: String, val revision: String, val preRelease: Boolean = false) {
override fun toString(): String {
return if (!preRelease)
"$major.$minor.$revision"
@@ -239,25 +211,19 @@ class Version(val major: String, val minor: String, val revision: String, val pr
fun getGitHash(): String {
val stdout = ByteArrayOutputStream()
val exitCode = exec {
exec {
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
standardOutput = stdout
}.exitValue
if (exitCode == 128) // https://canary.discord.com/channels/715448651786485780/765260067812540416/777236094768381954
System.err.println("You can only use this in a git repo. Please run \"git clone https://github.com/PolyhedralDev/Terra.git\", then cd into there.")
if (exitCode == 127 || exitCode == 9009) // https://canary.discord.com/channels/715448651786485780/715448652411437099/777304618853335082
System.err.println("You must install git for this to work. https://git-scm.com/downloads")
}
return stdout.toString().trim()
}
fun gitClone(name: String) {
val stdout = ByteArrayOutputStream()
val result = exec {
exec {
commandLine = mutableListOf("git", "clone", name)
standardOutput = stdout
}.exitValue
if (result == 127 || result == 9009) // https://canary.discord.com/channels/715448651786485780/715448652411437099/777304618853335082
System.err.println("You must install git for this to work.")
}
}
fun downloadAndUnzipPack(packUrl: URL) {

Binary file not shown.

Binary file not shown.

View File

@@ -2,6 +2,7 @@ package com.dfsek.terra;
import com.dfsek.terra.async.AsyncStructureFinder;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.genconfig.TreeConfig;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.registry.TreeRegistry;
import com.dfsek.terra.util.StructureTypeEnum;
@@ -22,8 +23,7 @@ import org.bukkit.event.world.StructureGrowEvent;
import org.polydev.gaea.GaeaPlugin;
import org.polydev.gaea.tree.Tree;
import org.polydev.gaea.tree.TreeType;
import java.util.Random;
import org.polydev.gaea.util.FastRandom;
public class EventListener implements Listener {
private final GaeaPlugin main;
@@ -80,6 +80,10 @@ public class EventListener implements Listener {
TreeRegistry registry = c.getTreeRegistry();
Tree tree = registry.get(TreeType.fromBukkit(e.getSpecies()).toString());
Debug.info("Overriding tree type: " + e.getSpecies());
if(!tree.plant(e.getLocation(), new Random(), Terra.getInstance())) block.setBlockData(data);
if(tree instanceof TreeConfig) {
if(!((TreeConfig) tree).plantBlockCheck(e.getLocation(), new FastRandom())) {
block.setBlockData(data);
}
} else if(!tree.plant(e.getLocation(), new FastRandom(), Terra.getInstance())) block.setBlockData(data);
}
}

View File

@@ -16,12 +16,12 @@ public class TerraProfiler extends WorldProfiler {
super(w);
this
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "TreeTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "OreTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "CaveTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "ElevationTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "SnowTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "CaveBlockUpdate");
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "SnowTime");
}
public static TerraProfiler fromWorld(World w) {

View File

@@ -24,14 +24,6 @@ public class TerraWorld {
private final WorldConfig worldConfig;
private boolean safe;
public static void loadWorld(WorldConfig w) {
loaded.put(w.getWorldID(), w);
}
public static synchronized TerraWorld getWorld(World w) {
return map.computeIfAbsent(w, TerraWorld::new);
}
private TerraWorld(World w) {
safe = true;
worldConfig = loaded.get(w.getName());
@@ -87,6 +79,14 @@ public class TerraWorld {
grid = new TerraBiomeGrid(w, config.freq1, config.freq2, zone, config, erosion);
}
public static void loadWorld(WorldConfig w) {
loaded.put(w.getWorldID(), w);
}
public static synchronized TerraWorld getWorld(World w) {
return map.computeIfAbsent(w, TerraWorld::new);
}
public static synchronized void invalidate() {
map.clear();
for(WorldConfig config : loaded.values()) {
@@ -98,6 +98,10 @@ public class TerraWorld {
return map.size();
}
public static boolean isTerraWorld(World w) {
return w.getGenerator() instanceof TerraChunkGenerator;
}
public TerraBiomeGrid getGrid() {
return grid;
}
@@ -117,8 +121,4 @@ public class TerraWorld {
public boolean isSafe() {
return safe;
}
public static boolean isTerraWorld(World w) {
return w.getGenerator() instanceof TerraChunkGenerator;
}
}

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.async;
import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import com.dfsek.terra.config.base.ConfigUtil;
import org.bukkit.Location;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
@@ -27,11 +28,11 @@ public class AsyncBiomeFinder extends AsyncFeatureFinder<Biome> {
*/
@Override
public boolean isValid(int x, int z, Biome target) {
return getGrid().getBiome(x, z, GenerationPhase.POST_GEN).equals(target);
return getGrid().getBiome(x * ConfigUtil.biomeSearchRes, z * ConfigUtil.biomeSearchRes, GenerationPhase.POST_GEN).equals(target);
}
@Override
public Vector finalizeVector(Vector orig) {
return orig;
return orig.multiply(ConfigUtil.biomeSearchRes);
}
}

View File

@@ -1,6 +1,5 @@
package com.dfsek.terra.async;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
@@ -10,6 +9,7 @@ import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.util.FastRandom;
import java.util.Random;
import java.util.function.Consumer;
@@ -33,9 +33,9 @@ public class AsyncStructureFinder extends AsyncFeatureFinder<StructureConfig> {
public boolean isValid(int x, int z, StructureConfig target) {
World world = getWorld();
Location spawn = target.getSpawn().getChunkSpawn(x, z, world.getSeed()).toLocation(world);
if(!TerraWorld.getWorld(world).getConfig().getBiome((UserDefinedBiome) getGrid().getBiome(spawn)).getStructures().contains(target))
if(!((UserDefinedBiome) getGrid().getBiome(spawn)).getConfig().getStructures().contains(target))
return false;
Random r2 = new Random(spawn.hashCode());
Random r2 = new FastRandom(spawn.hashCode());
Structure struc = target.getStructure(r2);
Rotation rotation = Rotation.fromDegrees(r2.nextInt(4) * 90);
for(int y = target.getSearchStart().get(r2); y > 0; y--) {

View File

@@ -1,7 +1,9 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig;
import com.dfsek.terra.config.genconfig.biome.GeneratorOptions;
import com.dfsek.terra.generation.UserDefinedDecorator;
import com.dfsek.terra.generation.UserDefinedGenerator;
import org.bukkit.World;
import org.polydev.gaea.biome.Biome;
import org.polydev.gaea.biome.Decorator;
import org.polydev.gaea.biome.Generator;
@@ -13,19 +15,21 @@ import java.util.List;
* Class representing a config-defined biome
*/
public class UserDefinedBiome implements Biome {
private final UserDefinedGenerator gen;
private final GeneratorOptions gen;
private final UserDefinedDecorator decorator;
private final org.bukkit.block.Biome vanilla;
private final String id;
private final BiomeConfig config;
private final boolean erode;
public UserDefinedBiome(org.bukkit.block.Biome vanilla, UserDefinedDecorator dec, UserDefinedGenerator gen, boolean erode, String id) {
public UserDefinedBiome(org.bukkit.block.Biome vanilla, UserDefinedDecorator dec, GeneratorOptions gen, boolean erode, BiomeConfig config) {
this.vanilla = vanilla;
this.decorator = dec;
this.gen = gen;
this.id = id;
this.id = config.getID();
this.erode = erode;
this.config = config;
}
/**
@@ -45,7 +49,7 @@ public class UserDefinedBiome implements Biome {
*/
@Override
public Generator getGenerator() {
return gen;
return gen.getGenerator(0);
}
/**
@@ -75,4 +79,13 @@ public class UserDefinedBiome implements Biome {
public boolean isErodible() {
return erode;
}
public BiomeConfig getConfig() {
return config;
}
@Override
public Generator getGenerator(World w) {
return gen.getGenerator(w.getSeed());
}
}

View File

@@ -1,61 +0,0 @@
package com.dfsek.terra.biome.failsafe;
import org.bukkit.Bukkit;
import org.polydev.gaea.biome.Biome;
import parsii.tokenizer.ParseException;
/**
* What happens if terrain generation is attempted with an unrecoverable config error.
*/
@SuppressWarnings("unused")
public enum FailType {
/**
* Return failover biome, then shut down server to minimize damage.
* Generally the safest option.
*/
SHUTDOWN {
@Override
public Biome fail() {
Bukkit.getServer().shutdown();
try {
return new FailoverBiome();
} catch(ParseException e) {
e.printStackTrace();
return null;
}
}
},
/**
* Returns null, hard crashing the server, but not generating any corrupted terrain.<br>
* This option is <b>NOT</b> stable, but it has the least risk of blank chunks being generated.
* However, it has the highest risk of corruption!
*/
CRASH {
@Override
public Biome fail() {
return null;
}
},
/**
* Returns a failover biome, which generates completely blank chunks.
* Recommended for debugging.
*/
FAILOVER {
@Override
public Biome fail() {
try {
return new FailoverBiome();
} catch(ParseException e) {
e.printStackTrace();
return null;
}
}
};
/**
* Performs the action specified by the enum type to occur on failure of terrain generation.
*
* @return Failover biome, if specified, null if not.
*/
public abstract Biome fail();
}

View File

@@ -1,13 +0,0 @@
package com.dfsek.terra.biome.failsafe;
import com.dfsek.terra.biome.UserDefinedBiome;
import parsii.tokenizer.ParseException;
/**
* Blank biome to generate in case of a severe config error
*/
public final class FailoverBiome extends UserDefinedBiome {
public FailoverBiome() throws ParseException {
super(org.bukkit.block.Biome.PLAINS, new FailoverDecorator(), new FailoverGenerator(), false, "FAILSAFE");
}
}

View File

@@ -1,10 +0,0 @@
package com.dfsek.terra.biome.failsafe;
import com.dfsek.terra.generation.UserDefinedDecorator;
import org.polydev.gaea.math.ProbabilityCollection;
public final class FailoverDecorator extends UserDefinedDecorator {
public FailoverDecorator() {
super(new ProbabilityCollection<>(), new ProbabilityCollection<>(), 0, 0);
}
}

View File

@@ -1,24 +0,0 @@
package com.dfsek.terra.biome.failsafe;
import com.dfsek.terra.generation.UserDefinedGenerator;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette;
import parsii.tokenizer.ParseException;
import java.util.HashMap;
import java.util.Random;
import java.util.TreeMap;
public final class FailoverGenerator extends UserDefinedGenerator {
private static final TreeMap<Integer, Palette<BlockData>> palette = new TreeMap<>();
static {
palette.put(255, new RandomPalette<BlockData>(new Random(2403)).add(Material.STONE.createBlockData(), 1));
}
public FailoverGenerator() throws ParseException {
super("0", null, new HashMap<>(), palette, new TreeMap<>(), false);
}
}

View File

@@ -57,7 +57,7 @@ public class TerraBiomeGrid extends BiomeGrid {
if(failNum % 256 == 0)
LangUtil.log("error.severe-config", Level.SEVERE, String.valueOf(x), String.valueOf(z));
failNum++;
return ConfigUtil.failType.fail();
return null;
}
if(erode != null && b.isErodible() && erode.isEroded(xp, zp)) {
return erosionGrid.getBiome(xp, zp, phase);

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.biome.postprocessing;
import net.jafama.FastMath;
import org.polydev.gaea.math.FastNoiseLite;
/**
@@ -27,7 +28,7 @@ public class ErosionNoise {
* @return Whether location is eroded
*/
public boolean isEroded(int x, int z) {
double abs = Math.pow(noise.getNoise(x, z), 2);
double abs = FastMath.pow(noise.getNoise(x, z), 2);
return abs < thresh;
}
}

View File

@@ -9,6 +9,7 @@ import org.bukkit.World;
import org.bukkit.util.Vector;
import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.MathUtil;
import org.polydev.gaea.util.FastRandom;
import java.util.Random;
@@ -23,7 +24,7 @@ public class Cavern {
public VoxelGeometry carveChunk(int chunkX, int chunkZ) {
long seedC = MathUtil.getCarverChunkSeed(chunkX, chunkZ, seed);
Random chunk = new Random(seedC);
Random chunk = new FastRandom(seedC);
Vector org = node.getNodeLocation((chunkX << 4) + 8, (chunkZ << 4) + 8).clone().setY(chunk.nextInt(128));
VoxelGeometry carve = VoxelGeometry.getBlank();
@@ -33,7 +34,7 @@ public class Cavern {
Bukkit.getLogger().info("Cavern: " + org.toString());
carve.merge(new DeformedSphere(org.clone(), chunk.nextInt(4) + 3, 0.75, smpl));
Vector _00 = new Vector(org.getX() + 16, new Random(MathUtil.getCarverChunkSeed(chunkX + 1, chunkZ, seed)).nextInt(128), org.getZ());
Vector _00 = new Vector(org.getX() + 16, new FastRandom(MathUtil.getCarverChunkSeed(chunkX + 1, chunkZ, seed)).nextInt(128), org.getZ());
carve.merge(new Tube(org, _00, 4));
return carve;

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.carving;
import net.jafama.FastMath;
import org.bukkit.World;
import org.bukkit.util.Vector;
import org.polydev.gaea.math.FastNoiseLite;
@@ -15,7 +16,7 @@ public class SimplexCarver extends Carver {
private final FastNoiseLite height;
private final FastNoiseLite column;
private final FastNoiseLite hasCaves;
private final double root2inverse = 1D / Math.sqrt(2);
private final double root2inverse = 1D / FastMath.sqrt(2);
public SimplexCarver(int minY, int maxY) {
super(minY, maxY);
@@ -40,6 +41,10 @@ public class SimplexCarver extends Carver {
hasCaves.setFrequency(0.005f);
}
private static double acot(double x) {
return FastMath.PI / 2 - FastMath.atan(x);
}
@Override
public CarvingData carve(int chunkX, int chunkZ, World w) {
CarvingData c = new CarvingData(chunkX, chunkZ);
@@ -49,15 +54,15 @@ public class SimplexCarver extends Carver {
for(int z = oz; z < oz + 16; z++) {
double heightNoise = height.getNoise(x, z);
double mainNoise = noise.getNoise(x, z) * 2;
double columnNoise = Math.pow(Math.max(column.getNoise(x, z), 0) * 2, 3);
double hc = (acot(16 * (hasCaves.getNoise(x, z) - 0.2)) / Math.PI) - 0.1;
double columnNoise = FastMath.pow(FastMath.max(column.getNoise(x, z), 0) * 2, 3);
double hc = (acot(16 * (hasCaves.getNoise(x, z) - 0.2)) / FastMath.PI) - 0.1;
CarvingData.CarvingType type = CarvingData.CarvingType.BOTTOM;
double simplex = (Math.pow(mainNoise + root2inverse, 3) / 2 + columnNoise) * hc;
double simplex = (FastMath.pow(mainNoise + root2inverse, 3) / 2 + columnNoise) * hc;
for(int y = 0; y < 64; y++) {
double finalNoise = (-0.05 * Math.abs(y - (heightNoise * 16 + 24)) + 1 - simplex) * hc;
double finalNoise = (-0.05 * FastMath.abs(y - (heightNoise * 16 + 24)) + 1 - simplex) * hc;
if(finalNoise > 0.5) {
c.carve(x - ox, y, z - oz, type);
double finalNoiseUp = (-0.05 * Math.abs((y + 1) - (heightNoise * 16 + 24)) + 1 - simplex) * hc;
double finalNoiseUp = (-0.05 * FastMath.abs((y + 1) - (heightNoise * 16 + 24)) + 1 - simplex) * hc;
if(finalNoiseUp > 0.5) {
type = CarvingData.CarvingType.CENTER;
} else type = CarvingData.CarvingType.TOP;
@@ -68,10 +73,6 @@ public class SimplexCarver extends Carver {
return c;
}
private static double acot(double x) {
return Math.PI / 2 - Math.atan(x);
}
@Override
public Worm getWorm(long l, Vector vector) {
return null;

View File

@@ -3,10 +3,12 @@ package com.dfsek.terra.carving;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.base.ConfigPack;
import net.jafama.FastMath;
import org.bukkit.World;
import org.bukkit.util.Vector;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.math.Range;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.world.carving.Carver;
import org.polydev.gaea.world.carving.Worm;
@@ -39,7 +41,7 @@ public class UserDefinedCarver extends Carver {
@Override
public Worm getWorm(long l, Vector vector) {
Random r = new Random(l + hash);
Random r = new FastRandom(l + hash);
return new UserDefinedWorm(length.get(r) / 2, r, vector, radius.getMax(), topCut, bottomCut);
}
@@ -58,7 +60,7 @@ public class UserDefinedCarver extends Carver {
@Override
public boolean isChunkCarved(World w, int chunkX, int chunkZ, Random random) {
ConfigPack c = TerraWorld.getWorld(w).getConfig();
return new Random(random.nextLong() + hash).nextInt(100) < c.getBiome((UserDefinedBiome) TerraWorld.getWorld(w).getGrid().getBiome(chunkX << 4, chunkZ << 4, GenerationPhase.POPULATE)).getCarverChance(this);
return new FastRandom(random.nextLong() + hash).nextInt(100) < ((UserDefinedBiome) TerraWorld.getWorld(w).getGrid().getBiome(chunkX << 4, chunkZ << 4, GenerationPhase.POPULATE)).getConfig().getCarverChance(this);
}
private class UserDefinedWorm extends Worm {
@@ -81,9 +83,9 @@ public class UserDefinedCarver extends Carver {
@Override
public void step() {
if(steps == nextDirection) {
direction.rotateAroundX(Math.toRadians((getRandom().nextGaussian()) * mutate[0] * recalcMagnitude));
direction.rotateAroundY(Math.toRadians((getRandom().nextGaussian()) * mutate[1] * recalcMagnitude));
direction.rotateAroundZ(Math.toRadians((getRandom().nextGaussian()) * mutate[2] * recalcMagnitude));
direction.rotateAroundX(FastMath.toRadians((getRandom().nextGaussian()) * mutate[0] * recalcMagnitude));
direction.rotateAroundY(FastMath.toRadians((getRandom().nextGaussian()) * mutate[1] * recalcMagnitude));
direction.rotateAroundZ(FastMath.toRadians((getRandom().nextGaussian()) * mutate[2] * recalcMagnitude));
currentRotation = new double[] {(getRandom().nextGaussian()) * mutate[0],
(getRandom().nextGaussian()) * mutate[1],
(getRandom().nextGaussian()) * mutate[2]};
@@ -92,10 +94,10 @@ public class UserDefinedCarver extends Carver {
steps++;
setRadius(new int[] {(int) (runningRadius * radiusMultiplier[0]), (int) (runningRadius * radiusMultiplier[1]), (int) (runningRadius * radiusMultiplier[2])});
runningRadius += (getRandom().nextDouble() - 0.5) * mutate[3];
runningRadius = Math.max(Math.min(runningRadius, maxRad), 1);
direction.rotateAroundX(Math.toRadians(currentRotation[0] * mutate[0]));
direction.rotateAroundY(Math.toRadians(currentRotation[1] * mutate[1]));
direction.rotateAroundZ(Math.toRadians(currentRotation[2] * mutate[2]));
runningRadius = FastMath.max(FastMath.min(runningRadius, maxRad), 1);
direction.rotateAroundX(FastMath.toRadians(currentRotation[0] * mutate[0]));
direction.rotateAroundY(FastMath.toRadians(currentRotation[1] * mutate[1]));
direction.rotateAroundZ(FastMath.toRadians(currentRotation[2] * mutate[2]));
getRunning().add(direction);
}
}

View File

@@ -3,6 +3,7 @@ package com.dfsek.terra.command;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.config.genconfig.OreConfig;
import com.dfsek.terra.config.lang.LangUtil;
import net.jafama.FastMath;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.command.Command;
@@ -11,10 +12,10 @@ import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.command.WorldCommand;
import org.polydev.gaea.util.FastRandom;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class OreCommand extends WorldCommand {
public OreCommand(org.polydev.gaea.command.Command parent) {
@@ -34,8 +35,8 @@ public class OreCommand extends WorldCommand {
LangUtil.send("command.ore.out-of-range", sender);
return true;
}
Vector source = new Vector(Math.floorMod(bl.getX(), 16), bl.getY(), Math.floorMod(bl.getZ(), 16));
ore.doVein(source, bl.getChunk(), new Random());
Vector source = new Vector(FastMath.floorMod(bl.getX(), 16), bl.getY(), FastMath.floorMod(bl.getZ(), 16));
ore.doVein(source, bl.getChunk(), new FastRandom());
} else {
LangUtil.send("command.ore.main-menu", sender);
}

View File

@@ -25,7 +25,7 @@ public class BiomeCommand extends WorldCommand {
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args, World w) {
TerraBiomeGrid grid = TerraWorld.getWorld(sender.getWorld()).getGrid();
UserDefinedBiome biome = (UserDefinedBiome) grid.getBiome(sender.getLocation(), GenerationPhase.POPULATE);
LangUtil.send("command.biome.in", sender, TerraWorld.getWorld(w).getConfig().getBiome(biome).getID());
LangUtil.send("command.biome.in", sender, biome.getID());
return true;
}

View File

@@ -40,7 +40,7 @@ public class BiomeInfoCommand extends WorldCommand {
sender.sendMessage("Erodible: " + b.isErodible());
BiomeConfig bio = cfg.getBiome(b);
BiomeConfig bio = b.getConfig();
List<StructureConfig> structureConfigs = bio.getStructures();
if(structureConfigs.size() == 0) sender.sendMessage("No Structures");

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.command.structure;
import com.dfsek.terra.command.structure.load.LoadCommand;
import com.dfsek.terra.config.lang.LangUtil;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;

View File

@@ -0,0 +1,62 @@
package com.dfsek.terra.command.structure.load;
import com.dfsek.terra.Terra;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.command.DebugCommand;
import org.polydev.gaea.command.PlayerCommand;
import java.io.File;
import java.io.FilenameFilter;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class LoadCommand extends PlayerCommand implements DebugCommand {
public LoadCommand(org.polydev.gaea.command.Command parent) {
super(parent);
}
public static List<String> getStructureNames() {
List<String> names = new ArrayList<>();
File structureDir = new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures");
if(!structureDir.exists()) return Collections.emptyList();
Path structurePath = structureDir.toPath();
FilenameFilter filter = (dir, name) -> name.endsWith(".tstructure");
for(File f : structureDir.listFiles(filter)) {
String path = structurePath.relativize(f.toPath()).toString();
names.add(path.substring(0, path.length() - 11));
}
return names;
}
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return true;
}
@Override
public String getName() {
return "load";
}
@Override
public List<org.polydev.gaea.command.Command> getSubCommands() {
return Arrays.asList(new LoadRawCommand(this), new LoadFullCommand(this, true), new LoadFullCommand(this, false));
}
@Override
public List<String> getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
return Collections.emptyList();
}
@Override
public int arguments() {
return 0;
}
}

View File

@@ -1,4 +1,4 @@
package com.dfsek.terra.command.structure;
package com.dfsek.terra.command.structure.load;
import com.dfsek.terra.Terra;
import com.dfsek.terra.config.lang.LangUtil;
@@ -15,14 +15,19 @@ import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class LoadCommand extends PlayerCommand implements DebugCommand {
public LoadCommand(org.polydev.gaea.command.Command parent) {
public class LoadFullCommand extends PlayerCommand implements DebugCommand {
private final boolean chunk;
public LoadFullCommand(org.polydev.gaea.command.Command parent, boolean chunk) {
super(parent);
this.chunk = chunk;
}
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String s, @NotNull String[] args) {
try {
Rotation r;
try {
@@ -32,8 +37,8 @@ public class LoadCommand extends PlayerCommand implements DebugCommand {
return true;
}
Structure struc = Structure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", args[0] + ".tstructure"));
if("true".equals(args[2])) struc.paste(sender.getLocation(), r);
else struc.paste(sender.getLocation(), sender.getLocation().getChunk(), r);
if(chunk) struc.paste(sender.getLocation(), sender.getLocation().getChunk(), r);
else struc.paste(sender.getLocation(), r);
//sender.sendMessage(String.valueOf(struc.checkSpawns(sender.getLocation(), r)));
} catch(IOException e) {
e.printStackTrace();
@@ -44,7 +49,7 @@ public class LoadCommand extends PlayerCommand implements DebugCommand {
@Override
public String getName() {
return "load";
return chunk ? "chunk" : "full";
}
@Override
@@ -54,11 +59,17 @@ public class LoadCommand extends PlayerCommand implements DebugCommand {
@Override
public int arguments() {
return 3;
return 2;
}
@Override
public List<String> getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
public List<String> getTabCompletions(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] args) {
switch(args.length) {
case 1:
return LoadCommand.getStructureNames().stream().filter(string -> string.toUpperCase().startsWith(args[0].toUpperCase())).collect(Collectors.toList());
case 2:
return Stream.of("0", "90", "180", "270").filter(string -> string.toUpperCase().startsWith(args[1].toUpperCase())).collect(Collectors.toList());
}
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,113 @@
package com.dfsek.terra.command.structure.load;
import com.dfsek.terra.Terra;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.structure.Structure;
import com.dfsek.terra.structure.StructureContainedBlock;
import com.dfsek.terra.structure.StructureInfo;
import com.dfsek.terra.structure.StructureSpawnRequirement;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Sign;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.command.DebugCommand;
import org.polydev.gaea.command.PlayerCommand;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class LoadRawCommand extends PlayerCommand implements DebugCommand {
public LoadRawCommand(org.polydev.gaea.command.Command parent) {
super(parent);
}
private static void setTerraSign(Sign sign, String data) {
sign.setLine(0, "[TERRA]");
sign.setLine(2, data.substring(0, 16));
sign.setLine(3, data.substring(16));
}
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String s, @NotNull String[] args) {
try {
Structure struc = Structure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", args[0] + ".tstructure"));
StructureInfo info = struc.getStructureInfo();
int centerX = info.getCenterX();
int centerZ = info.getCenterZ();
for(StructureContainedBlock[][] level0 : struc.getRawStructure()) {
for(StructureContainedBlock[] level1 : level0) {
for(StructureContainedBlock block : level1) {
Location bLocation = sender.getLocation().add(block.getX() - centerX, block.getY(), block.getZ() - centerZ);
if(!block.getPull().equals(StructureContainedBlock.Pull.NONE)) {
bLocation.getBlock().setBlockData(Material.OAK_SIGN.createBlockData(), false);
Sign sign = (Sign) bLocation.getBlock().getState();
sign.setLine(1, "[PULL=" + block.getPull() + "_" + block.getPullOffset() + "]");
String data = block.getBlockData().getAsString(true);
setTerraSign(sign, data);
sign.update();
} else if(!block.getRequirement().equals(StructureSpawnRequirement.BLANK)) {
bLocation.getBlock().setBlockData(Material.OAK_SIGN.createBlockData(), false);
Sign sign = (Sign) bLocation.getBlock().getState();
sign.setLine(1, "[SPAWN=" + block.getRequirement() + "]");
String data = block.getBlockData().getAsString(true);
setTerraSign(sign, data);
sign.update();
} else {
bLocation.getBlock().setBlockData(block.getBlockData(), false);
if(block.getState() != null) {
block.getState().getState(bLocation.getBlock().getState()).update(true, false);
}
}
}
}
}
for(int y = 0; y < struc.getStructureInfo().getSizeY(); y++) {
StructureContainedBlock block = struc.getRawStructure()[centerX][centerZ][y];
if(block.getRequirement().equals(StructureSpawnRequirement.BLANK) && block.getPull().equals(StructureContainedBlock.Pull.NONE)) {
Location bLocation = sender.getLocation().add(block.getX() - centerX, block.getY(), block.getZ() - centerZ);
bLocation.getBlock().setBlockData(Material.OAK_SIGN.createBlockData(), false);
Sign sign = (Sign) bLocation.getBlock().getState();
sign.setLine(1, "[CENTER]");
String data = block.getBlockData().getAsString(true);
setTerraSign(sign, data);
sign.update();
break;
}
}
} catch(IOException e) {
e.printStackTrace();
LangUtil.send("command.structure.invalid", sender, args[0]);
}
return true;
}
@Override
public String getName() {
return "raw";
}
@Override
public List<org.polydev.gaea.command.Command> getSubCommands() {
return Collections.emptyList();
}
@Override
public int arguments() {
return 1;
}
@Override
public List<String> getTabCompletions(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] args) {
if(args.length == 1) {
return LoadCommand.getStructureNames().stream().filter(string -> string.toUpperCase().startsWith(args[0].toUpperCase())).collect(Collectors.toList());
}
return Collections.emptyList();
}
}

View File

@@ -2,7 +2,6 @@ package com.dfsek.terra.config.base;
import com.dfsek.terra.Debug;
import com.dfsek.terra.Terra;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.ConfigLoader;
import com.dfsek.terra.config.exception.ConfigException;
@@ -15,6 +14,7 @@ import com.dfsek.terra.config.genconfig.PaletteConfig;
import com.dfsek.terra.config.genconfig.TreeConfig;
import com.dfsek.terra.config.genconfig.biome.AbstractBiomeConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig;
import com.dfsek.terra.config.genconfig.noise.NoiseConfig;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.registry.FloraRegistry;
@@ -24,6 +24,7 @@ import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import parsii.eval.Scope;
import java.io.File;
import java.io.IOException;
@@ -56,8 +57,6 @@ public class ConfigPack extends YamlConfiguration {
public final int blendAmp;
public final boolean biomeBlend;
public final double blendFreq;
public final int octaves;
public final double frequency;
public final boolean vanillaCaves;
public final boolean vanillaStructures;
public final boolean vanillaDecoration;
@@ -75,7 +74,8 @@ public class ConfigPack extends YamlConfiguration {
private final TreeRegistry treeRegistry = new TreeRegistry();
private final FloraRegistry floraRegistry = new FloraRegistry();
private final Set<StructureConfig> allStructures = new HashSet<>();
private final Map<String, Double> definedVariables = new HashMap<>();
private final Map<String, NoiseConfig> noiseBuilders = new HashMap<>();
private final Scope vScope;
private final File dataFolder;
private final String id;
@@ -87,6 +87,13 @@ public class ConfigPack extends YamlConfiguration {
if(!contains("id")) throw new ConfigException("No ID specified!", "null");
this.id = getString("id");
Map<String, Object> noise = Objects.requireNonNull(getConfigurationSection("noise")).getValues(false);
for(Map.Entry<String, Object> entry : noise.entrySet()) {
NoiseConfig noiseConfig = new NoiseConfig((ConfigurationSection) entry.getValue());
noiseBuilders.put(entry.getKey(), noiseConfig);
Debug.info("Loaded noise function " + entry.getKey() + " with type " + noiseConfig.getBuilder().getType());
}
ores = ConfigLoader.load(new File(file, "ores").toPath(), this, OreConfig.class);
palettes = ConfigLoader.load(new File(file, "palettes").toPath(), this, PaletteConfig.class);
@@ -108,11 +115,12 @@ public class ConfigPack extends YamlConfiguration {
Debug.info("Overriding Vanilla tree: " + entry.getKey());
}
vScope = new Scope();
if(contains("variables")) {
Map<String, Object> vars = Objects.requireNonNull(getConfigurationSection("variables")).getValues(false);
for(Map.Entry<String, Object> entry : vars.entrySet()) {
try {
definedVariables.put(entry.getKey(), Double.valueOf(entry.getValue().toString()));
vScope.getVariable(entry.getKey()).setValue(Double.parseDouble(entry.getValue().toString()));
Debug.info("Registered variable " + entry.getKey() + " with value " + entry.getValue());
} catch(ClassCastException | NumberFormatException e) {
Debug.stack(e);
@@ -141,9 +149,6 @@ public class ConfigPack extends YamlConfiguration {
erosionThresh = getDouble("erode.threshold", 0.04);
erosionOctaves = getInt("erode.octaves", 3);
octaves = getInt("noise.octaves", 4);
frequency = getDouble("noise.frequency", 1f / 96);
erosionName = getString("erode.grid");
vanillaCaves = getBoolean("vanilla.caves", false);
@@ -190,26 +195,6 @@ public class ConfigPack extends YamlConfiguration {
LangUtil.log("config-pack.loaded", Level.INFO, getID(), String.valueOf((System.nanoTime() - l) / 1000000D));
}
public String getID() {
return id;
}
public Map<String, Double> getDefinedVariables() {
return definedVariables;
}
public Map<String, BiomeConfig> getBiomes() {
return biomes;
}
public StructureConfig getStructure(String id) {
return structures.get(id);
}
public BiomeGridConfig getBiomeGrid(String id) {
return grids.get(id);
}
public static synchronized void loadAll(JavaPlugin main) {
configs.clear();
File file = new File(main.getDataFolder(), "packs");
@@ -244,6 +229,30 @@ public class ConfigPack extends YamlConfiguration {
return configs.get(id);
}
public String getID() {
return id;
}
public Scope getVariableScope() {
return vScope;
}
public Map<String, BiomeConfig> getBiomes() {
return biomes;
}
public StructureConfig getStructure(String id) {
return structures.get(id);
}
public BiomeGridConfig getBiomeGrid(String id) {
return grids.get(id);
}
public Map<String, NoiseConfig> getNoiseBuilders() {
return noiseBuilders;
}
public Map<StructureTypeEnum, StructureConfig> getLocatable() {
return locatable;
}
@@ -264,13 +273,6 @@ public class ConfigPack extends YamlConfiguration {
return dataFolder;
}
public BiomeConfig getBiome(UserDefinedBiome b) {
for(BiomeConfig biome : biomes.values()) {
if(biome.getBiome().equals(b)) return biome;
}
throw new IllegalArgumentException("No BiomeConfig for provided biome.");
}
public BiomeConfig getBiome(String id) {
return biomes.get(id);
}

View File

@@ -3,7 +3,6 @@ package com.dfsek.terra.config.base;
import com.dfsek.terra.Debug;
import com.dfsek.terra.Terra;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.failsafe.FailType;
import com.dfsek.terra.config.exception.ConfigException;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.util.TagUtil;
@@ -18,20 +17,19 @@ import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.HashSet;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class ConfigUtil {
public static boolean debug;
public static long dataSave; // Period of population data saving, in ticks.
public static boolean masterDisableCaves;
public static int biomeSearchRes;
public static int cacheSize;
public static FailType failType;
public static void loadConfig(JavaPlugin main) {
main.saveDefaultConfig();
@@ -40,9 +38,10 @@ public final class ConfigUtil {
LangUtil.load(config.getString("language", "en_us"), main);
debug = config.getBoolean("debug", false);
cacheSize = config.getInt("cache-size", 3);
dataSave = Duration.parse(Objects.requireNonNull(config.getString("data-save", "PT6M"))).toMillis() / 20L;
masterDisableCaves = config.getBoolean("master-disable.caves", false);
biomeSearchRes = config.getInt("biome-search-resolution", 4);
cacheSize = config.getInt("cache-size", 384);
if(config.getBoolean("dump-default", true)) {
try(JarFile jar = new JarFile(new File(Terra.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {
@@ -54,14 +53,6 @@ public final class ConfigUtil {
}
}
String fail = config.getString("fail-type", "SHUTDOWN");
try {
failType = FailType.valueOf(fail);
} catch(IllegalArgumentException e) {
LangUtil.log("config.invalid-failover", Level.SEVERE, fail);
}
Logger logger = main.getLogger();
logger.info("Loading config values");
@@ -70,7 +61,7 @@ public final class ConfigUtil {
}
public static Set<Material> toBlockData(List<String> list, String phase, String id) throws InvalidConfigurationException {
Set<Material> bl = new HashSet<>();
Set<Material> bl = EnumSet.noneOf(Material.class);
for(String s : list) {
try {
if(s.startsWith("#")) {

View File

@@ -42,7 +42,7 @@ public class WorldConfig {
FileConfiguration config = new YamlConfiguration();
Debug.info("Loading config " + configID + " for world " + worldID);
try { // Load/create world config file
if(configID == null || configID.equals(""))
if(configID == null || configID.isEmpty())
throw new ConfigException("Config pack unspecified in bukkit.yml!", worldID);
File configFile = new File(main.getDataFolder() + File.separator + "worlds", worldID + ".yml");
if(!configFile.exists()) {

View File

@@ -15,8 +15,8 @@ import org.polydev.gaea.math.Range;
import java.io.File;
import java.io.IOException;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -45,8 +45,9 @@ public class CarverConfig extends TerraConfig {
@SuppressWarnings("unchecked")
public CarverConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException {
super(file, config);
if(!yaml.contains("id")) throw new ConfigException("No ID specified for Carver!", "null");
id = Objects.requireNonNull(yaml.getString("id"));
load(file);
if(!contains("id")) throw new ConfigException("No ID specified for Carver!", "null");
id = Objects.requireNonNull(getString("id"));
inner = getBlocks("palette.inner.layers");
@@ -56,24 +57,24 @@ public class CarverConfig extends TerraConfig {
bottom = getBlocks("palette.bottom.layers");
replaceableInner = ConfigUtil.toBlockData(yaml.getStringList("palette.inner.replace"), "replaceable inner", getID());
replaceableInner = ConfigUtil.toBlockData(getStringList("palette.inner.replace"), "replaceable inner", getID());
replaceableOuter = ConfigUtil.toBlockData(yaml.getStringList("palette.outer.replace"), "replaceable outer", getID());
replaceableOuter = ConfigUtil.toBlockData(getStringList("palette.outer.replace"), "replaceable outer", getID());
replaceableTop = ConfigUtil.toBlockData(yaml.getStringList("palette.top.replace"), "replaceable top", getID());
replaceableTop = ConfigUtil.toBlockData(getStringList("palette.top.replace"), "replaceable top", getID());
replaceableBottom = ConfigUtil.toBlockData(yaml.getStringList("palette.bottom.replace"), "replaceable bottom", getID());
replaceableBottom = ConfigUtil.toBlockData(getStringList("palette.bottom.replace"), "replaceable bottom", getID());
update = ConfigUtil.toBlockData(yaml.getStringList("update"), "update", getID());
update = ConfigUtil.toBlockData(getStringList("update"), "update", getID());
updateOcean = yaml.getBoolean("update-liquids", false);
updateOcean = getBoolean("update-liquids", false);
double step = yaml.getDouble("step", 2);
Range recalc = new Range(yaml.getInt("recalculate-direction.min", 8), yaml.getInt("recalculate-direction.max", 12));
double rm = yaml.getDouble("recalculate-magnitude", 4);
double step = getDouble("step", 2);
Range recalc = new Range(getInt("recalculate-direction.min", 8), getInt("recalculate-direction.max", 12));
double rm = getDouble("recalculate-magnitude", 4);
shift = new HashMap<>();
for(Map.Entry<String, Object> e : Objects.requireNonNull(yaml.getConfigurationSection("shift")).getValues(false).entrySet()) {
Set<Material> l = new HashSet<>();
for(Map.Entry<String, Object> e : Objects.requireNonNull(getConfigurationSection("shift")).getValues(false).entrySet()) {
Set<Material> l = EnumSet.noneOf(Material.class);
for(String s : (List<String>) e.getValue()) {
l.add(Bukkit.createBlockData(s).getMaterial());
Debug.info("Added " + s + " to shift-able blocks");
@@ -82,19 +83,19 @@ public class CarverConfig extends TerraConfig {
Debug.info("Added " + e.getKey() + " as master block");
}
replaceIsBlacklistInner = yaml.getBoolean("palette.inner.replace-blacklist", false);
replaceIsBlacklistOuter = yaml.getBoolean("palette.outer.replace-blacklist", false);
replaceIsBlacklistTop = yaml.getBoolean("palette.top.replace-blacklist", false);
replaceIsBlacklistBottom = yaml.getBoolean("palette.bottom.replace-blacklist", false);
replaceIsBlacklistInner = getBoolean("palette.inner.replace-blacklist", false);
replaceIsBlacklistOuter = getBoolean("palette.outer.replace-blacklist", false);
replaceIsBlacklistTop = getBoolean("palette.top.replace-blacklist", false);
replaceIsBlacklistBottom = getBoolean("palette.bottom.replace-blacklist", false);
double[] start = new double[] {yaml.getDouble("start.x"), yaml.getDouble("start.y"), yaml.getDouble("start.z")};
double[] mutate = new double[] {yaml.getDouble("mutate.x"), yaml.getDouble("mutate.y"), yaml.getDouble("mutate.z"), yaml.getDouble("mutate.radius")};
double[] radiusMultiplier = new double[] {yaml.getDouble("start.radius.multiply.x"), yaml.getDouble("start.radius.multiply.y"), yaml.getDouble("start.radius.multiply.z")};
Range length = new Range(yaml.getInt("length.min"), yaml.getInt("length.max"));
Range radius = new Range(yaml.getInt("start.radius.min"), yaml.getInt("start.radius.max"));
Range height = new Range(yaml.getInt("start.height.min"), yaml.getInt("start.height.max"));
double[] start = new double[] {getDouble("start.x"), getDouble("start.y"), getDouble("start.z")};
double[] mutate = new double[] {getDouble("mutate.x"), getDouble("mutate.y"), getDouble("mutate.z"), getDouble("mutate.radius")};
double[] radiusMultiplier = new double[] {getDouble("start.radius.multiply.x"), getDouble("start.radius.multiply.y"), getDouble("start.radius.multiply.z")};
Range length = new Range(getInt("length.min"), getInt("length.max"));
Range radius = new Range(getInt("start.radius.min"), getInt("start.radius.max"));
Range height = new Range(getInt("start.height.min"), getInt("start.height.max"));
carver = new UserDefinedCarver(height, radius, length, start, mutate, radiusMultiplier, id.hashCode(), yaml.getInt("cut.top", 0), yaml.getInt("cut.bottom", 0));
carver = new UserDefinedCarver(height, radius, length, start, mutate, radiusMultiplier, id.hashCode(), getInt("cut.top", 0), getInt("cut.bottom", 0));
carver.setStep(step);
carver.setRecalc(recalc);
carver.setRecalcMagnitude(rm);
@@ -102,9 +103,9 @@ public class CarverConfig extends TerraConfig {
@SuppressWarnings("unchecked")
private Map<Integer, ProbabilityCollection<BlockData>> getBlocks(String key) throws InvalidConfigurationException {
if(!yaml.contains(key)) throw new ConfigException("Missing Carver Palette!", getID());
if(!contains(key)) throw new ConfigException("Missing Carver Palette!", getID());
Map<Integer, ProbabilityCollection<BlockData>> result = new TreeMap<>();
for(Map<?, ?> m : yaml.getMapList(key)) {
for(Map<?, ?> m : getMapList(key)) {
try {
ProbabilityCollection<BlockData> layer = new ProbabilityCollection<>();
for(Map.Entry<String, Integer> type : ((Map<String, Integer>) m.get("materials")).entrySet()) {

View File

@@ -4,6 +4,7 @@ import com.dfsek.terra.config.TerraConfig;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.exception.ConfigException;
import net.jafama.FastMath;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -12,6 +13,7 @@ import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException;
import org.polydev.gaea.math.Range;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.world.Flora;
import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette;
@@ -20,7 +22,6 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
public class FloraConfig extends TerraConfig implements Flora {
@@ -36,24 +37,25 @@ public class FloraConfig extends TerraConfig implements Flora {
public FloraConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException {
super(file, config);
if(!yaml.contains("id")) throw new ConfigException("Flora ID unspecified!", "null");
this.id = yaml.getString("id");
if(!yaml.contains("layers")) throw new ConfigException("No blocks defined in custom flora!", getID());
if(!yaml.contains("spawnable")) throw new ConfigException("Flora spawnable blocks unspecified!", getID());
load(file);
if(!contains("id")) throw new ConfigException("Flora ID unspecified!", "null");
this.id = getString("id");
if(!contains("layers")) throw new ConfigException("No blocks defined in custom flora!", getID());
if(!contains("spawnable")) throw new ConfigException("Flora spawnable blocks unspecified!", getID());
spawnable = ConfigUtil.toBlockData(yaml.getStringList("spawnable"), "spawnable", getID());
replaceable = ConfigUtil.toBlockData(yaml.getStringList("replaceable"), "replaceable", getID());
spawnable = ConfigUtil.toBlockData(getStringList("spawnable"), "spawnable", getID());
replaceable = ConfigUtil.toBlockData(getStringList("replaceable"), "replaceable", getID());
if(yaml.contains("irrigable")) {
irrigable = ConfigUtil.toBlockData(yaml.getStringList("irrigable"), "irrigable", getID());
if(contains("irrigable")) {
irrigable = ConfigUtil.toBlockData(getStringList("irrigable"), "irrigable", getID());
} else irrigable = null;
physics = yaml.getBoolean("physics", false);
ceiling = yaml.getBoolean("ceiling", false);
physics = getBoolean("physics", false);
ceiling = getBoolean("ceiling", false);
Palette<BlockData> p = new RandomPalette<>(new Random(yaml.getInt("seed", 4)));
Palette<BlockData> p = new RandomPalette<>(new FastRandom(getInt("seed", 4)));
floraPalette = PaletteConfig.getPalette(yaml.getMapList("layers"), p);
floraPalette = PaletteConfig.getPalette(getMapList("layers"), p);
}
public String getID() {
@@ -62,26 +64,28 @@ public class FloraConfig extends TerraConfig implements Flora {
@Override
public List<Block> getValidSpawnsAt(Chunk chunk, int x, int z, Range range) {
int size = floraPalette.getSize();
Block current = chunk.getBlock(x, range.getMin(), z);
List<Block> blocks = new ArrayList<>();
if(ceiling) for(int y : range) {
if(y > 255 || y < 1) continue;
Block check = chunk.getBlock(x, y, z);
Block other = check.getRelative(BlockFace.DOWN);
if(spawnable.contains(check.getType()) && replaceable.contains(other.getType())) {
blocks.add(check);
}
}
else for(int y : range) {
if(y > 254 || y < 0) continue;
Block check = chunk.getBlock(x, y, z);
Block other = check.getRelative(BlockFace.UP);
if(spawnable.contains(check.getType()) && replaceable.contains(other.getType()) && isIrrigated(check)) {
blocks.add(check);
for(int y : range) {
if(y > 255 || y < 0) continue;
current = current.getRelative(BlockFace.UP);
if(spawnable.contains(current.getType()) && isIrrigated(current) && valid(size, current)) {
blocks.add(current);
}
}
return blocks;
}
private boolean valid(int size, Block block) {
for(int i = 0; i < size; i++) { // Down if ceiling, up if floor
if(block.getY() + 1 > 255 || block.getY() < 0) return false;
block = block.getRelative(ceiling ? BlockFace.DOWN : BlockFace.UP);
if(!replaceable.contains(block.getType())) return false;
}
return true;
}
private boolean isIrrigated(Block b) {
if(irrigable == null) return true;
return irrigable.contains(b.getRelative(BlockFace.NORTH).getType())
@@ -94,12 +98,8 @@ public class FloraConfig extends TerraConfig implements Flora {
public boolean plant(Location location) {
int size = floraPalette.getSize();
int c = ceiling ? -1 : 1;
for(int i = 0; Math.abs(i) < size; i += c) { // Down if ceiling, up if floor
if(i + 1 > 255) return false;
if(!replaceable.contains(location.clone().add(0, i + c, 0).getBlock().getType())) return false;
}
for(int i = 0; Math.abs(i) < size; i += c) { // Down if ceiling, up if floor
int lvl = (Math.abs(i));
for(int i = 0; FastMath.abs(i) < size; i += c) { // Down if ceiling, up if floor
int lvl = (FastMath.abs(i));
location.clone().add(0, i + c, 0).getBlock().setBlockData(floraPalette.get((ceiling ? lvl : size - lvl - 1), location.getBlockX(), location.getBlockZ()), physics);
}
return true;

View File

@@ -4,6 +4,7 @@ import com.dfsek.terra.config.TerraConfig;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.exception.ConfigException;
import net.jafama.FastMath;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
@@ -30,34 +31,27 @@ public class OreConfig extends TerraConfig {
private final double deformFrequency;
private final String id;
private final boolean update;
private final boolean crossChunks;
private final int chunkEdgeOffset;
Set<Material> replaceable;
public OreConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException {
super(file, config);
if(!yaml.contains("id")) throw new ConfigException("Ore ID not found!", "null");
this.id = yaml.getString("id");
if(!yaml.contains("material")) throw new ConfigException("Ore material not found!", getID());
if(!yaml.contains("deform")) throw new ConfigException("Ore vein deformation not found!", getID());
if(!yaml.contains("replace")) throw new ConfigException("Ore replaceable materials not found!", getID());
min = yaml.getInt("radius.min", 1);
max = yaml.getInt("radius.max", 1);
deform = yaml.getDouble("deform", 0.75);
deformFrequency = yaml.getDouble("deform-frequency", 0.1);
update = yaml.getBoolean("update", false);
crossChunks = yaml.getBoolean("cross-chunks", true);
chunkEdgeOffset = yaml.getInt("edge-offset", 1);
if(!contains("id")) throw new ConfigException("Ore ID not found!", "null");
this.id = getString("id");
if(!contains("material")) throw new ConfigException("Ore material not found!", getID());
if(!contains("deform")) throw new ConfigException("Ore vein deformation not found!", getID());
if(!contains("replace")) throw new ConfigException("Ore replaceable materials not found!", getID());
min = getInt("radius.min", 1);
max = getInt("radius.max", 1);
deform = getDouble("deform", 0.75);
deformFrequency = getDouble("deform-frequency", 0.1);
update = getBoolean("update", false);
if(chunkEdgeOffset > 7 || chunkEdgeOffset < 0)
throw new ConfigException("Edge offset is too high/low!", getID());
replaceable = ConfigUtil.toBlockData(yaml.getStringList("replace"), "replaceable", getID());
replaceable = ConfigUtil.toBlockData(getStringList("replace"), "replaceable", getID());
try {
oreData = Bukkit.createBlockData(Objects.requireNonNull(yaml.getString("material")));
oreData = Bukkit.createBlockData(Objects.requireNonNull(getString("material")));
} catch(NullPointerException | IllegalArgumentException e) {
throw new ConfigException("Invalid ore material: " + yaml.getString("material"), getID());
throw new ConfigException("Invalid ore material: " + getString("material"), getID());
}
}
@@ -80,9 +74,9 @@ public class OreConfig extends TerraConfig {
Vector source = l.clone().add(new Vector(x, y, z));
if(oreLoc.getBlockY() > 255 || oreLoc.getBlockY() < 0) continue;
if(source.distance(l) < (rad + 0.5) * ((ore.getNoise(x, y, z) + 1) * deform)) {
ChunkCoordinate coord = new ChunkCoordinate(Math.floorDiv(oreLoc.getBlockX(), 16), Math.floorDiv(oreLoc.getBlockZ(), 16), chunk.getWorld().getUID());
ChunkCoordinate coord = new ChunkCoordinate(FastMath.floorDiv(oreLoc.getBlockX(), 16), FastMath.floorDiv(oreLoc.getBlockZ(), 16), chunk.getWorld().getUID());
Block b = chunks.computeIfAbsent(coord, k -> chunk.getWorld().getChunkAt(oreLoc.toLocation(chunk.getWorld())))
.getBlock(Math.floorMod(source.getBlockX(), 16), source.getBlockY(), Math.floorMod(source.getBlockZ(), 16)); // Chunk caching conditional computation
.getBlock(FastMath.floorMod(source.getBlockX(), 16), source.getBlockY(), FastMath.floorMod(source.getBlockZ(), 16)); // Chunk caching conditional computation
if(replaceable.contains(b.getType()) && b.getLocation().getY() >= 0)
b.setBlockData(oreData, update);
}
@@ -120,12 +114,4 @@ public class OreConfig extends TerraConfig {
public String toString() {
return "Ore with ID " + getID();
}
public boolean crossChunks() {
return crossChunks;
}
public int getChunkEdgeOffset() {
return chunkEdgeOffset;
}
}

View File

@@ -9,6 +9,7 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException;
import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.ProbabilityCollection;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette;
import org.polydev.gaea.world.palette.SimplexPalette;
@@ -17,7 +18,6 @@ import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class PaletteConfig extends TerraConfig {
private final Palette<BlockData> palette;
@@ -26,18 +26,18 @@ public class PaletteConfig extends TerraConfig {
public PaletteConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException {
super(file, config);
if(!yaml.contains("id")) throw new ConfigException("Palette ID unspecified!", "null");
this.paletteID = yaml.getString("id");
if(!contains("id")) throw new ConfigException("Palette ID unspecified!", "null");
this.paletteID = getString("id");
Palette<BlockData> pal;
if(yaml.getBoolean("simplex", false)) {
if(getBoolean("simplex", false)) {
useNoise = true;
FastNoiseLite pNoise = new FastNoiseLite(yaml.getInt("seed", 2403));
FastNoiseLite pNoise = new FastNoiseLite(getInt("seed", 2403));
pNoise.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2);
pNoise.setFractalOctaves(4);
pNoise.setFrequency(yaml.getDouble("frequency", 0.02));
pNoise.setFrequency(getDouble("frequency", 0.02));
pal = new SimplexPalette<>(pNoise);
} else pal = new RandomPalette<>(new Random(yaml.getInt("seed", 2403)));
palette = getPalette(yaml.getMapList("layers"), pal);
} else pal = new RandomPalette<>(new FastRandom(getInt("seed", 2403)));
palette = getPalette(getMapList("layers"), pal);
}
@SuppressWarnings("unchecked")

View File

@@ -6,8 +6,12 @@ import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.exception.ConfigException;
import com.dfsek.terra.config.exception.NotFoundException;
import com.dfsek.terra.procgen.math.Vector2;
import com.dfsek.terra.structure.Rotation;
import com.dfsek.terra.structure.Structure;
import com.dfsek.terra.structure.StructureContainedBlock;
import com.dfsek.terra.structure.StructureInfo;
import com.dfsek.terra.util.structure.RotationUtil;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.configuration.InvalidConfigurationException;
@@ -73,4 +77,28 @@ public class TreeConfig extends TerraConfig implements Tree {
struc.paste(mut, rotation);
return true;
}
public boolean plantBlockCheck(Location location, Random random) {
location.subtract(0, 1, 0);
Location mut = location.clone().subtract(0, yOffset, 0);
if(!spawnable.contains(location.getBlock().getType())) return false;
Structure struc = structure.get(random);
Rotation rotation = Rotation.fromDegrees(random.nextInt(4) * 90);
StructureInfo info = struc.getStructureInfo();
for(StructureContainedBlock spawn : struc.getSpawns()) {
Vector2 rot = RotationUtil.getRotatedCoords(new Vector2(spawn.getX() - info.getCenterX(), spawn.getZ() - info.getCenterZ()), rotation);
int x = (int) rot.getX();
int z = (int) rot.getZ();
switch(spawn.getRequirement()) {
case AIR:
if(!mut.clone().add(x, spawn.getY() - 1, z).getBlock().isPassable()) return false;
break;
case LAND:
if(!mut.clone().add(x, spawn.getY() - 1, z).getBlock().getType().isSolid()) return false;
break;
}
}
struc.paste(mut, rotation);
return true;
}
}

View File

@@ -9,7 +9,6 @@ import com.dfsek.terra.config.exception.ConfigException;
import com.dfsek.terra.config.exception.NotFoundException;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.generation.UserDefinedDecorator;
import com.dfsek.terra.generation.UserDefinedGenerator;
import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException;
import org.polydev.gaea.math.Range;
@@ -45,36 +44,36 @@ public class BiomeConfig extends TerraConfig {
public BiomeConfig(File file, ConfigPack config) throws InvalidConfigurationException, IOException {
super(file, config);
load(file);
this.config = config;
if(!yaml.contains("id")) throw new ConfigException("Biome ID unspecified!", "null");
this.biomeID = yaml.getString("id");
if(!contains("id")) throw new ConfigException("Biome ID unspecified!", "null");
this.biomeID = getString("id");
AbstractBiomeConfig abstractBiome = null;
// Whether an abstract biome is to be extended. Default to false.
boolean extending = false;
// Check if biome extends an abstract biome, load abstract biome if so.
if(yaml.contains("extends")) {
if(contains("extends")) {
try {
abstractBiome = config.getAbstractBiomes().get(yaml.getString("extends"));
if(abstractBiome == null)
throw new NotFoundException("Abstract Biome", yaml.getString("extends"), getID());
abstractBiome = config.getAbstractBiomes().get(getString("extends"));
if(abstractBiome == null) throw new NotFoundException("Abstract Biome", getString("extends"), getID());
extending = true;
Debug.info("Extending biome " + yaml.getString("extends"));
Debug.info("Extending biome " + getString("extends"));
} catch(NullPointerException e) {
throw new NotFoundException("Abstract Biome", yaml.getString("extends"), getID());
throw new NotFoundException("Abstract Biome", getString("extends"), getID());
}
}
// Get various simple values using getOrDefault config methods.
try {
eq = yaml.getString("noise-equation", Objects.requireNonNull(abstractBiome).getEquation());
eq = getString("noise-equation", Objects.requireNonNull(abstractBiome).getEquation());
} catch(NullPointerException e) {
eq = yaml.getString("noise-equation", null);
eq = getString("noise-equation", null);
}
BiomePaletteConfig palette;
// Check if biome is extending abstract biome, only use abstract biome's palette if palette is NOT defined for current biome.
if(extending && abstractBiome.getPaletteData() != null && !yaml.contains("palette")) {
if(extending && abstractBiome.getPaletteData() != null && !contains("palette")) {
palette = abstractBiome.getPaletteData();
Debug.info("Using super palette");
} else palette = new BiomePaletteConfig(this, "palette");
@@ -84,31 +83,31 @@ public class BiomeConfig extends TerraConfig {
throw new ConfigException("No Palette specified in biome or super biome.", getID());
// Check if carving should be handled by super biome.
if(extending && abstractBiome.getCarving() != null && !yaml.contains("carving")) {
if(extending && abstractBiome.getCarving() != null && !contains("carving")) {
carver = abstractBiome.getCarving();
Debug.info("Using super carvers");
} else carver = new BiomeCarverConfig(this);
// Check if flora should be handled by super biome.
if(extending && abstractBiome.getFlora() != null && !yaml.contains("flora")) {
if(extending && abstractBiome.getFlora() != null && !contains("flora")) {
flora = abstractBiome.getFlora();
Debug.info("Using super flora (" + flora.getFlora().size() + " entries, " + flora.getFloraChance() + " % chance)");
} else flora = new BiomeFloraConfig(this);
// Check if trees should be handled by super biome.
if(extending && abstractBiome.getTrees() != null && !yaml.contains("trees")) {
if(extending && abstractBiome.getTrees() != null && !contains("trees")) {
tree = abstractBiome.getTrees();
Debug.info("Using super trees");
} else tree = new BiomeTreeConfig(this);
// Check if ores should be handled by super biome.
if(extending && abstractBiome.getOres() != null && !yaml.contains("ores")) {
if(extending && abstractBiome.getOres() != null && !contains("ores")) {
ore = abstractBiome.getOres();
Debug.info("Using super ores");
} else ore = new BiomeOreConfig(this);
// Get slab stuff
if(extending && abstractBiome.getSlabs() != null && !yaml.contains("slabs")) {
if(extending && abstractBiome.getSlabs() != null && !contains("slabs")) {
slab = abstractBiome.getSlabs();
Debug.info("Using super slabs");
} else slab = new BiomeSlabConfig(this);
@@ -127,17 +126,17 @@ public class BiomeConfig extends TerraConfig {
// Get slant stuff
TreeMap<Integer, Palette<BlockData>> slant = new TreeMap<>();
if(yaml.contains("slant")) {
String slantS = yaml.getString("slant.palette");
if(contains("slant")) {
String slantS = getString("slant.palette");
slant = new BiomePaletteConfig(this, "slant.palette").getPaletteMap();
Debug.info("Using slant palette: " + slantS);
if(slant == null) throw new NotFoundException("Slant Palette", slantS, getID());
}
ySlantOffsetTop = yaml.getDouble("slant.y-offset.top", 0.25);
ySlantOffsetBottom = yaml.getDouble("slant.y-offset.bottom", 0.25);
ySlantOffsetTop = getDouble("slant.y-offset.top", 0.25);
ySlantOffsetBottom = getDouble("slant.y-offset.bottom", 0.25);
//Make sure equation is non-null
if(eq == null || eq.equals(""))
if(eq == null || eq.isEmpty())
throw new ConfigException("Could not find noise equation! Biomes must include a noise equation, or extend an abstract biome with one.", getID());
// Create decorator for this config.
@@ -146,10 +145,10 @@ public class BiomeConfig extends TerraConfig {
// Get Vanilla biome, throw exception if it is invalid/unspecified.
org.bukkit.block.Biome vanillaBiome;
try {
if(!yaml.contains("vanilla")) throw new ConfigException("Vanilla Biome unspecified!", getID());
vanillaBiome = org.bukkit.block.Biome.valueOf(yaml.getString("vanilla"));
if(!contains("vanilla")) throw new ConfigException("Vanilla Biome unspecified!", getID());
vanillaBiome = org.bukkit.block.Biome.valueOf(getString("vanilla"));
} catch(IllegalArgumentException e) {
throw new ConfigException("Invalid Vanilla biome: \"" + yaml.getString("vanilla") + "\"", getID());
throw new ConfigException("Invalid Vanilla biome: \"" + getString("vanilla") + "\"", getID());
}
// Structure stuff
@@ -157,7 +156,7 @@ public class BiomeConfig extends TerraConfig {
List<String> st = new ArrayList<>();
if(abstractBiome != null && abstractBiome.getStructureConfigs() != null)
st = abstractBiome.getStructureConfigs();
if(yaml.contains("structures")) st = yaml.getStringList("structures");
if(contains("structures")) st = getStringList("structures");
for(String s : st) {
try {
structures.add(Objects.requireNonNull(config.getStructure(s)));
@@ -166,14 +165,13 @@ public class BiomeConfig extends TerraConfig {
}
}
String elevation = yaml.getString("elevation.equation", null);
boolean doElevationInterpolation = yaml.getBoolean("elevation.interpolation", true);
String elevation = getString("elevation.equation", null);
boolean doElevationInterpolation = getBoolean("elevation.interpolation", true);
try {
// Get UserDefinedBiome instance representing this config.
UserDefinedGenerator gen = new UserDefinedGenerator(eq, elevation, config.getDefinedVariables(), palette.getPaletteMap(), slant, yaml.getBoolean("prevent-smooth", false));
gen.setElevationInterpolation(doElevationInterpolation);
this.biome = new UserDefinedBiome(vanillaBiome, dec, gen, yaml.getBoolean("erodible", false), biomeID);
GeneratorOptions gen = new GeneratorOptions(eq, elevation, config.getVariableScope(), palette.getPaletteMap(), slant, config.getNoiseBuilders(), getBoolean("prevent-smooth", false), doElevationInterpolation);
this.biome = new UserDefinedBiome(vanillaBiome, dec, gen, getBoolean("erodible", false), this);
} catch(ParseException e) {
e.printStackTrace();
throw new ConfigException("Unable to parse noise equation!", getID());

View File

@@ -10,13 +10,12 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.math.ProbabilityCollection;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette;
import java.util.Random;
public class BiomeOceanConfig extends TerraConfigSection {
private static final Palette<BlockData> oceanDefault = new RandomPalette<BlockData>(new Random(0)).add(Material.WATER.createBlockData(), 1);
private static final Palette<BlockData> oceanDefault = new RandomPalette<BlockData>(new FastRandom(0)).add(Material.WATER.createBlockData(), 1);
private final Palette<BlockData> ocean;
private final int seaLevel;
@@ -27,7 +26,7 @@ public class BiomeOceanConfig extends TerraConfigSection {
if(oceanN != null) {
if(oceanN.startsWith("BLOCK:")) {
try {
ocean = new RandomPalette<BlockData>(new Random(0)).add(new ProbabilityCollection<BlockData>().add(Bukkit.createBlockData(oceanN.substring(6)), 1), 1);
ocean = new RandomPalette<BlockData>(new FastRandom(0)).add(new ProbabilityCollection<BlockData>().add(Bukkit.createBlockData(oceanN.substring(6)), 1), 1);
} catch(IllegalArgumentException ex) {
throw new ConfigException("BlockData \"" + oceanN + "\" is invalid! (Ocean Palette)", parent.getID());
}

View File

@@ -8,12 +8,12 @@ import org.bukkit.Bukkit;
import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException;
import org.polydev.gaea.math.ProbabilityCollection;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
public class BiomePaletteConfig extends TerraConfigSection {
@@ -29,7 +29,7 @@ public class BiomePaletteConfig extends TerraConfigSection {
try {
if(((String) entry.getKey()).startsWith("BLOCK:")) {
try {
paletteMap.put((Integer) entry.getValue(), new RandomPalette<BlockData>(new Random(0)).add(new ProbabilityCollection<BlockData>().add(Bukkit.createBlockData(((String) entry.getKey()).substring(6)), 1), 1));
paletteMap.put((Integer) entry.getValue(), new RandomPalette<BlockData>(new FastRandom(0)).add(new ProbabilityCollection<BlockData>().add(Bukkit.createBlockData(((String) entry.getKey()).substring(6)), 1), 1));
} catch(IllegalArgumentException ex) {
throw new ConfigException("BlockData " + entry.getKey() + " is invalid! (Palettes)", parent.getID());
}

View File

@@ -11,13 +11,14 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.math.ProbabilityCollection;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class BiomeSlabConfig extends TerraConfigSection {
private final Map<Material, Palette<BlockData>> slabs;
@@ -34,7 +35,7 @@ public class BiomeSlabConfig extends TerraConfigSection {
}
protected Map<Material, Palette<BlockData>> getSlabPalettes(List<Map<?, ?>> paletteConfigSection) throws InvalidConfigurationException {
Map<Material, Palette<BlockData>> paletteMap = new HashMap<>();
Map<Material, Palette<BlockData>> paletteMap = new EnumMap<>(Material.class);
for(Map<?, ?> e : paletteConfigSection) {
for(Map.Entry<?, ?> entry : e.entrySet()) {
@@ -42,7 +43,7 @@ public class BiomeSlabConfig extends TerraConfigSection {
if(((String) entry.getValue()).startsWith("BLOCK:")) {
try {
Debug.info("Adding slab palette with single material " + entry.getKey());
paletteMap.put(Bukkit.createBlockData((String) entry.getKey()).getMaterial(), new RandomPalette<BlockData>(new Random(0)).add(new ProbabilityCollection<BlockData>().add(Bukkit.createBlockData(((String) entry.getValue()).substring(6)), 1), 1));
paletteMap.put(Bukkit.createBlockData((String) entry.getKey()).getMaterial(), new RandomPalette<BlockData>(new FastRandom(0)).add(new ProbabilityCollection<BlockData>().add(Bukkit.createBlockData(((String) entry.getValue()).substring(6)), 1), 1));
} catch(IllegalArgumentException ex) {
throw new ConfigException("Invalid BlockData in slab configuration: " + ex.getMessage(), getParent().getConfig().getID());
}

View File

@@ -12,12 +12,14 @@ import java.util.Map;
public class BiomeSnowConfig extends TerraConfigSection {
private final int[] snowHeights;
private final boolean physics;
private boolean doSnow = false;
public BiomeSnowConfig(TerraConfig parent) throws InvalidConfigurationException {
super(parent);
snowHeights = new int[256];
List<Map<?, ?>> maps = parent.getYaml().getMapList("snow");
List<Map<?, ?>> maps = parent.getMapList("snow");
this.physics = getParent().getBoolean("snow-physics", false);
if(maps.size() == 0) return;
try {
for(Map<?, ?> e : maps) {
@@ -41,4 +43,8 @@ public class BiomeSnowConfig extends TerraConfigSection {
public boolean doSnow() {
return doSnow;
}
public boolean doPhysics() {
return physics;
}
}

View File

@@ -0,0 +1,78 @@
package com.dfsek.terra.config.genconfig.biome;
import com.dfsek.terra.config.genconfig.noise.NoiseConfig;
import com.dfsek.terra.generation.config.WorldGenerator;
import com.dfsek.terra.math.BlankFunction;
import com.dfsek.terra.util.DataUtil;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.Nullable;
import org.polydev.gaea.world.palette.Palette;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.tokenizer.ParseException;
import java.util.HashMap;
import java.util.Map;
public class GeneratorOptions {
private final Map<Long, WorldGenerator> generators = new HashMap<>();
private final boolean preventSmooth;
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final Palette<BlockData>[] palettes = new Palette[256];
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final Palette<BlockData>[] slantPalettes = new Palette[256];
private final String equation;
private final String elevationEquation;
private final Scope userVariables;
private final Map<String, NoiseConfig> noiseBuilders;
private final boolean elevationInterpolation;
public GeneratorOptions(String equation, @Nullable String elevateEquation, Scope userVariables, Map<Integer, Palette<BlockData>> paletteMap, Map<Integer, Palette<BlockData>> slantPaletteMap, Map<String, NoiseConfig> noiseBuilders, boolean preventSmooth, boolean elevationInterpolation)
throws ParseException {
this.equation = equation;
this.elevationEquation = elevateEquation;
this.userVariables = userVariables;
this.noiseBuilders = noiseBuilders;
this.preventSmooth = preventSmooth;
Scope s = new Scope().withParent(userVariables);
Parser p = new Parser();
for(Map.Entry<String, NoiseConfig> e : noiseBuilders.entrySet()) {
int dimensions = e.getValue().getDimensions();
if(dimensions == 2 || dimensions == 3) p.registerFunction(e.getKey(), new BlankFunction(dimensions));
}
p.parse(equation, s); // Validate equation at config load time to prevent error during world load.
if(elevateEquation != null) p.parse(elevateEquation, s);
for(int y = 0; y < 256; y++) {
Palette<BlockData> d = DataUtil.BLANK_PALETTE;
for(Map.Entry<Integer, Palette<BlockData>> e : paletteMap.entrySet()) {
if(e.getKey() >= y) {
d = e.getValue();
break;
}
}
palettes[y] = d;
Palette<BlockData> slantPalette = null;
for(Map.Entry<Integer, Palette<BlockData>> e : slantPaletteMap.entrySet()) {
if(e.getKey() >= y) {
slantPalette = e.getValue();
break;
}
}
slantPalettes[y] = slantPalette;
}
this.elevationInterpolation = elevationInterpolation;
}
public WorldGenerator getGenerator(long seed) {
return generators.computeIfAbsent(seed, s -> new WorldGenerator(seed, equation, elevationEquation, userVariables, noiseBuilders, palettes, slantPalettes, preventSmooth)
.setElevationInterpolation(elevationInterpolation));
}
}

View File

@@ -0,0 +1,56 @@
package com.dfsek.terra.config.genconfig.noise;
import com.dfsek.terra.config.exception.ConfigException;
import com.dfsek.terra.generation.config.NoiseBuilder;
import org.bukkit.configuration.ConfigurationSection;
import org.polydev.gaea.math.FastNoiseLite;
public class NoiseConfig {
private final NoiseBuilder builder;
private final int dimensions;
public NoiseConfig(ConfigurationSection section) throws ConfigException {
NoiseBuilder builder = new NoiseBuilder();
try {
builder.setType(FastNoiseLite.NoiseType.valueOf(section.getString("type", "OpenSimplex2")))
.setFrequency(section.getDouble("frequency", 0.02D))
.setRotationType3D(FastNoiseLite.RotationType3D.valueOf(section.getString("rotation", "None")))
.setSeedOffset(section.getInt("offset", 0));
dimensions = section.getInt("dimensions", 3);
if(dimensions != 2 && dimensions != 3)
throw new ConfigException("Invalid number of dimensions: " + dimensions, "Noise");
if(section.contains("fractal")) {
builder.setFractalType(FastNoiseLite.FractalType.valueOf(section.getString("fractal.type", "FBm")))
.setOctaves(section.getInt("fractal.octaves", 1))
.setFractalGain(section.getDouble("fractal.gain", 0.5D))
.setFractalLacunarity(section.getDouble("fractal.lacunarity", 2.0D))
.setPingPong(section.getDouble("fractal.ping-pong", 2.0D))
.setWeightedStrength(section.getDouble("fractal.weighted-strength", 0.0D));
}
if(section.contains("cellular")) {
builder.setCellularDistanceFunction(FastNoiseLite.CellularDistanceFunction.valueOf(section.getString("cellular.distance", "EuclideanSq")))
.setCellularReturnType(FastNoiseLite.CellularReturnType.valueOf(section.getString("cellular.return", "Distance")));
}
if(section.contains("warp")) {
builder.setDomainWarpType(FastNoiseLite.DomainWarpType.valueOf(section.getString("warp.type", "OpenSimplex2")))
.setDomainWarpAmp(section.getDouble("warp.amplitude", 1.0D));
}
this.builder = builder;
} catch(IllegalArgumentException | ClassCastException e) {
throw new ConfigException(e.getMessage(), "Noise");
}
}
public NoiseBuilder getBuilder() {
return builder;
}
public int getDimensions() {
return dimensions;
}
}

View File

@@ -38,7 +38,6 @@ public class EntityFeatureConfig implements FeatureConfig {
throw new InvalidConfigurationException("Error in Entity Configuration!");
}
int attempts = (Integer) items.get("attempts");
int height = (Integer) items.get("in-height");
Range amount;
@@ -52,7 +51,7 @@ public class EntityFeatureConfig implements FeatureConfig {
Set<Material> on = ConfigUtil.toBlockData((List<String>) items.get("spawnable-on"), "SpawnableOn", "");
Set<Material> in = ConfigUtil.toBlockData((List<String>) items.get("spawnable-in"), "SpawnableIn", "");
this.feature = new EntityFeature(type, amount, attempts, on, in, height);
this.feature = new EntityFeature(type, amount, on, in, height);
Debug.info("Loaded EntityFeature with type: " + type);
}

View File

@@ -4,6 +4,7 @@ import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.generation.TerraChunkGenerator;
import com.dfsek.terra.image.ImageLoader;
import net.jafama.FastMath;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.polydev.gaea.generation.GenerationPhase;
@@ -33,14 +34,14 @@ public class DebugFrame extends JFrame implements ActionListener {
super.paintComponents(g);
for(Player p : Bukkit.getOnlinePlayers()) {
if(!(p.getWorld().getGenerator() instanceof TerraChunkGenerator)) break;
int xp = (int) (((double) Math.floorMod(p.getLocation().getBlockX() - (img.getWidth() / 2), x) / x) * getWidth());
int zp = (int) (((double) Math.floorMod(p.getLocation().getBlockZ() - (img.getHeight() / 2), z) / z) * getHeight());
int xp = (int) (((double) FastMath.floorMod(p.getLocation().getBlockX() - (img.getWidth() / 2), x) / x) * getWidth());
int zp = (int) (((double) FastMath.floorMod(p.getLocation().getBlockZ() - (img.getHeight() / 2), z) / z) * getHeight());
ImageLoader loader = TerraWorld.getWorld(p.getWorld()).getWorldConfig().imageLoader;
if(loader != null && loader.getAlign().equals(ImageLoader.Align.NONE)) {
xp = (int) (((double) Math.floorMod(p.getLocation().getBlockX(), x) / x) * getWidth());
zp = (int) (((double) Math.floorMod(p.getLocation().getBlockZ(), z) / z) * getHeight());
xp = (int) (((double) FastMath.floorMod(p.getLocation().getBlockX(), x) / x) * getWidth());
zp = (int) (((double) FastMath.floorMod(p.getLocation().getBlockZ(), z) / z) * getHeight());
}
String str = TerraWorld.getWorld(p.getWorld()).getConfig().getBiome((UserDefinedBiome) TerraWorld.getWorld(p.getWorld()).getGrid().getBiome(p.getLocation(), GenerationPhase.POPULATE)).getID();
String str = ((UserDefinedBiome) TerraWorld.getWorld(p.getWorld()).getGrid().getBiome(p.getLocation(), GenerationPhase.POPULATE)).getID();
g.setColor(new Color(255, 255, 255, 128));
g.fillRect(xp + 13, zp - 13, (int) (8 + 8.25 * str.length()), 33);
g.setColor(Color.BLACK);

View File

@@ -1,35 +0,0 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.math.NoiseFunction2;
import org.polydev.gaea.math.FastNoiseLite;
import parsii.eval.Expression;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
public class ElevationEquation {
private static final Object noiseLock = new Object();
private final Expression delegate;
private final Scope s = new Scope();
private final NoiseFunction2 n2 = new NoiseFunction2();
private final Variable xVar = s.getVariable("x");
private final Variable zVar = s.getVariable("z");
public ElevationEquation(String equation) throws ParseException {
Parser p = new Parser();
p.registerFunction("noise2", n2);
delegate = p.parse(equation, s);
}
public double getNoise(double x, double z, FastNoiseLite noiseLite) {
synchronized(noiseLock) {
xVar.setValue(x);
zVar.setValue(z);
n2.setNoise(noiseLite);
return delegate.evaluate();
}
}
}

View File

@@ -1,34 +1,31 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import org.bukkit.World;
import com.dfsek.terra.generation.config.WorldGenerator;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.Interpolator;
public class ElevationInterpolator {
private final UserDefinedGenerator[][] gens = new UserDefinedGenerator[10][10];
private final WorldGenerator[][] gens = new WorldGenerator[10][10];
private final double[][] values = new double[18][18];
private final FastNoiseLite noise;
private final int xOrigin;
private final int zOrigin;
private final TerraBiomeGrid grid;
public ElevationInterpolator(World w, int chunkX, int chunkZ, TerraBiomeGrid grid, FastNoiseLite noise) {
public ElevationInterpolator(int chunkX, int chunkZ, TerraBiomeGrid grid) {
this.xOrigin = chunkX << 4;
this.zOrigin = chunkZ << 4;
this.noise = noise;
this.grid = grid;
for(int x = -2; x < 8; x++) {
for(int z = -2; z < 8; z++) {
gens[x + 2][z + 2] = (UserDefinedGenerator) grid.getBiome(xOrigin + x * 4, zOrigin + z * 4, GenerationPhase.BASE).getGenerator();
gens[x + 2][z + 2] = (WorldGenerator) grid.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), GenerationPhase.BASE).getGenerator();
}
}
for(byte x = -1; x <= 16; x++) {
for(byte z = -1; z <= 16; z++) {
UserDefinedGenerator generator = getGenerator(x, z);
WorldGenerator generator = getGenerator(x, z);
if(compareGens((x / 4), (z / 4)) && generator.interpolateElevation()) {
Interpolator interpolator = new Interpolator(biomeAvg(x / 4, z / 4),
biomeAvg((x / 4) + 1, z / 4),
@@ -41,16 +38,16 @@ public class ElevationInterpolator {
}
}
private UserDefinedGenerator getGenerator(int x, int z) {
return (UserDefinedGenerator) grid.getBiome(xOrigin + x, zOrigin + z, GenerationPhase.BASE).getGenerator();
private WorldGenerator getGenerator(int x, int z) {
return (WorldGenerator) grid.getBiome(xOrigin + x, zOrigin + z, GenerationPhase.BASE).getGenerator();
}
private UserDefinedGenerator getStoredGen(int x, int z) {
private WorldGenerator getStoredGen(int x, int z) {
return gens[x + 2][z + 2];
}
private boolean compareGens(int x, int z) {
UserDefinedGenerator comp = getStoredGen(x, z);
WorldGenerator comp = getStoredGen(x, z);
for(int xi = x - 2; xi <= x + 2; xi++) {
for(int zi = z - 2; zi <= z + 2; zi++) {
@@ -61,20 +58,19 @@ public class ElevationInterpolator {
}
private double biomeAvg(int x, int z) {
return (elevate(getStoredGen(x + 1, z), x * 4 + 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x - 1, z), x * 4 - 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x, z + 1), x * 4 + xOrigin, z * 4 + 4 + zOrigin)
+ elevate(getStoredGen(x, z - 1), x * 4 + xOrigin, z * 4 - 4 + zOrigin)
+ elevate(getStoredGen(x, z), x * 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x - 1, z - 1), x * 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x - 1, z + 1), x * 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x + 1, z - 1), x * 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x + 1, z + 1), x * 4 + xOrigin, z * 4 + zOrigin)) / 9D;
return (elevate(getStoredGen(x + 1, z), (x << 2) + 4 + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x - 1, z), (x << 2) - 4 + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x, z + 1), (x << 2) + xOrigin, (z << 2) + 4 + zOrigin)
+ elevate(getStoredGen(x, z - 1), (x << 2) + xOrigin, (z << 2) - 4 + zOrigin)
+ elevate(getStoredGen(x, z), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x - 1, z - 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x - 1, z + 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x + 1, z - 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x + 1, z + 1), (x << 2) + xOrigin, (z << 2) + zOrigin)) / 9D;
}
private double elevate(UserDefinedGenerator g, int x, int z) {
if(g.getElevationEquation() != null) return g.getElevationEquation().getNoise(x, z, noise);
return 0;
private double elevate(WorldGenerator g, int x, int z) {
return g.getElevation(x, z);
}
public double getElevation(int x, int z) {

View File

@@ -9,11 +9,13 @@ import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeSlabConfig;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.generation.config.WorldGenerator;
import com.dfsek.terra.population.CavePopulator;
import com.dfsek.terra.population.FloraPopulator;
import com.dfsek.terra.population.OrePopulator;
import com.dfsek.terra.population.SnowPopulator;
import com.dfsek.terra.population.StructurePopulator;
import com.dfsek.terra.population.TreePopulator;
import com.dfsek.terra.util.DataUtil;
import org.bukkit.Chunk;
import org.bukkit.Material;
@@ -55,8 +57,9 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
public TerraChunkGenerator(ConfigPack c) {
super(ChunkInterpolator.InterpolationType.TRILINEAR);
this.configPack = c;
popMan.attach(new FloraPopulator());
popMan.attach(new OrePopulator());
popMan.attach(new TreePopulator());
popMan.attach(new FloraPopulator());
popMan.attach(new SnowPopulator());
}
@@ -76,26 +79,22 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
popMap.get(c.getWorld()).checkNeighbors(c.getX(), c.getZ(), c.getWorld());
}
@Override
public void attachProfiler(WorldProfiler p) {
super.attachProfiler(p);
popMan.attachProfiler(p);
}
private static Palette<BlockData> getPalette(int x, int y, int z, BiomeConfig c, ChunkInterpolator interpolator, ElevationInterpolator elevationInterpolator) {
Palette<BlockData> slant = ((UserDefinedGenerator) c.getBiome().getGenerator()).getSlantPalette(y);
Palette<BlockData> slant = ((WorldGenerator) c.getBiome().getGenerator()).getSlantPalette(y);
if(slant != null) {
boolean north = interpolator.getNoise(x, y - elevationInterpolator.getElevation(x, z + 1), z + 1) > 0;
boolean south = interpolator.getNoise(x, y - elevationInterpolator.getElevation(x, z - 1), z - 1) > 0;
boolean east = interpolator.getNoise(x + 1, y - elevationInterpolator.getElevation(x + 1, z), z) > 0;
boolean west = interpolator.getNoise(x - 1, y - elevationInterpolator.getElevation(x - 1, z), z) > 0;
double ySlantOffsetTop = c.getYSlantOffsetTop();
double ySlantOffsetBottom = c.getYSlantOffsetBottom();
boolean top = interpolator.getNoise(x, y + ySlantOffsetTop - elevationInterpolator.getElevation(x, z), z) > 0;
boolean bottom = interpolator.getNoise(x, y - ySlantOffsetBottom - elevationInterpolator.getElevation(x, z), z) > 0;
if((top && bottom) && (north || south || east || west) && (!(north && south && east && west))) return slant;
if(top && bottom) {
boolean north = interpolator.getNoise(x, y - elevationInterpolator.getElevation(x, z + 1), z + 1) > 0;
boolean south = interpolator.getNoise(x, y - elevationInterpolator.getElevation(x, z - 1), z - 1) > 0;
boolean east = interpolator.getNoise(x + 1, y - elevationInterpolator.getElevation(x + 1, z), z) > 0;
boolean west = interpolator.getNoise(x - 1, y - elevationInterpolator.getElevation(x - 1, z), z) > 0;
if((north || south || east || west) && (!(north && south && east && west))) return slant;
}
}
return c.getBiome().getGenerator().getPalette(y);
}
@@ -109,10 +108,10 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
if(stairPalette != null) {
BlockData stair = stairPalette.get(0, block.getBlockX(), block.getBlockZ());
Stairs stairNew = (Stairs) stair.clone();
double elevationN = elevationInterpolator.getElevation(block.getBlockX(), block.getBlockZ() - 1); // Northern elevation
double elevationS = elevationInterpolator.getElevation(block.getBlockX(), block.getBlockZ() + 1); // Southern elevation
double elevationE = elevationInterpolator.getElevation(block.getBlockX() + 1, block.getBlockZ()); // Eastern elevation
double elevationW = elevationInterpolator.getElevation(block.getBlockX() - 1, block.getBlockZ()); // Western elevation
int elevationN = (int) elevationInterpolator.getElevation(block.getBlockX(), block.getBlockZ() - 1); // Northern elevation
int elevationS = (int) elevationInterpolator.getElevation(block.getBlockX(), block.getBlockZ() + 1); // Southern elevation
int elevationE = (int) elevationInterpolator.getElevation(block.getBlockX() + 1, block.getBlockZ()); // Eastern elevation
int elevationW = (int) elevationInterpolator.getElevation(block.getBlockX() - 1, block.getBlockZ()); // Western elevation
if(interpolator.getNoise(block.getBlockX() - 0.5, block.getBlockY() - elevationW, block.getBlockZ()) > thresh) {
stairNew.setFacing(BlockFace.WEST);
} else if(interpolator.getNoise(block.getBlockX(), block.getBlockY() - elevationN, block.getBlockZ() - 0.5) > thresh) {
@@ -137,6 +136,12 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
}
}
@Override
public void attachProfiler(WorldProfiler p) {
super.attachProfiler(p);
popMan.attachProfiler(p);
}
@Override
@SuppressWarnings("try")
public ChunkData generateBase(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, ChunkInterpolator interpolator) {
@@ -144,14 +149,13 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
ChunkData chunk = createChunkData(world);
TerraWorld tw = TerraWorld.getWorld(world);
if(!tw.isSafe()) return chunk;
ConfigPack config = tw.getConfig();
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
org.polydev.gaea.biome.BiomeGrid grid = getBiomeGrid(world);
ElevationInterpolator elevationInterpolator;
try(ProfileFuture ignore = TerraProfiler.fromWorld(world).measure("ElevationTime")) {
elevationInterpolator = new ElevationInterpolator(world, chunkX, chunkZ, tw.getGrid(), getNoiseGenerator());
elevationInterpolator = new ElevationInterpolator(chunkX, chunkZ, tw.getGrid());
}
for(byte x = 0; x < 16; x++) {
@@ -162,7 +166,7 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
int cz = zOrig + z;
Biome b = grid.getBiome(xOrig + x, zOrig + z, GenerationPhase.PALETTE_APPLY);
BiomeConfig c = config.getBiome((UserDefinedBiome) b);
BiomeConfig c = ((UserDefinedBiome) b).getConfig();
double elevate = elevationInterpolator.getElevation(x, z);
@@ -203,12 +207,12 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
@Override
public int getNoiseOctaves(World world) {
return configPack.octaves;
return 1;
}
@Override
public double getNoiseFrequency(World world) {
return configPack.frequency;
return 0.02;
}
@Override

View File

@@ -1,152 +0,0 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.Debug;
import com.dfsek.terra.math.NoiseFunction2;
import com.dfsek.terra.math.NoiseFunction3;
import com.dfsek.terra.util.DataUtil;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.Nullable;
import org.polydev.gaea.biome.Generator;
import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.Interpolator;
import org.polydev.gaea.world.palette.Palette;
import parsii.eval.Expression;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
import java.util.Map;
public class UserDefinedGenerator extends Generator {
private static final Object noiseLock = new Object();
private final Expression noiseExp;
private final Scope s = new Scope();
private final Variable xVar = s.getVariable("x");
private final Variable yVar = s.getVariable("y");
private final Variable zVar = s.getVariable("z");
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final Palette<BlockData>[] palettes = new Palette[256];
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final Palette<BlockData>[] slantPalettes = new Palette[256];
private final NoiseFunction2 n2 = new NoiseFunction2();
private final NoiseFunction3 n3 = new NoiseFunction3();
private final ElevationEquation elevationEquation;
private final boolean preventSmooth;
private boolean elevationInterpolation;
public UserDefinedGenerator(String equation, @Nullable String elevateEquation, Map<String, Double> userVariables, Map<Integer, Palette<BlockData>> paletteMap, Map<Integer, Palette<BlockData>> slantPaletteMap, boolean preventSmooth)
throws ParseException {
for(Map.Entry<String, Double> entry : userVariables.entrySet()) {
s.getVariable(entry.getKey()).setValue(entry.getValue()); // Define all user variables.
}
Parser p = new Parser();
p.registerFunction("noise2", n2);
p.registerFunction("noise3", n3);
for(int y = 0; y < 256; y++) {
Palette<BlockData> d = DataUtil.BLANK_PALETTE;
for(Map.Entry<Integer, Palette<BlockData>> e : paletteMap.entrySet()) {
if(e.getKey() >= y) {
d = e.getValue();
break;
}
}
palettes[y] = d;
Palette<BlockData> slantPalette = null;
for(Map.Entry<Integer, Palette<BlockData>> e : slantPaletteMap.entrySet()) {
if(e.getKey() >= y) {
slantPalette = e.getValue();
break;
}
}
slantPalettes[y] = slantPalette;
}
if(elevateEquation != null) {
Debug.info("Using elevation equation");
this.elevationEquation = new ElevationEquation(elevateEquation);
} else this.elevationEquation = null;
this.noiseExp = p.parse(equation, s);
this.preventSmooth = preventSmooth;
}
/**
* Gets the 2D noise at a pair of coordinates using the provided FastNoiseLite instance.
*
* @param gen - The FastNoiseLite instance to use.
* @param x - The x coordinate.
* @param z - The z coordinate.
* @return double - Noise value at the specified coordinates.
*/
@Override
public double getNoise(FastNoiseLite gen, World w, int x, int z) {
synchronized(noiseLock) {
xVar.setValue(x);
yVar.setValue(0);
zVar.setValue(z);
n2.setNoise(gen);
n3.setNoise(gen);
return noiseExp.evaluate();
}
}
/**
* Gets the 3D noise at a pair of coordinates using the provided FastNoiseLite instance.
*
* @param gen - The FastNoiseLite instance to use.
* @param x - The x coordinate.
* @param y - The y coordinate.
* @param z - The z coordinate.
* @return double - Noise value at the specified coordinates.
*/
@Override
public double getNoise(FastNoiseLite gen, World w, int x, int y, int z) {
synchronized(noiseLock) {
xVar.setValue(x);
yVar.setValue(y);
zVar.setValue(z);
n2.setNoise(gen);
n3.setNoise(gen);
return noiseExp.evaluate();
}
}
/**
* Gets the BlocPalette to generate the biome with.
*
* @return BlocPalette - The biome's palette.
*/
@Override
public Palette<BlockData> getPalette(int y) {
return palettes[y];
}
public Palette<BlockData> getSlantPalette(int y) {
return slantPalettes[y];
}
@Override
public boolean useMinimalInterpolation() {
return preventSmooth;
}
@Override
public Interpolator.Type getInterpolationType() {
return Interpolator.Type.LINEAR;
}
public ElevationEquation getElevationEquation() {
return elevationEquation;
}
public boolean interpolateElevation() {
return elevationInterpolation;
}
public void setElevationInterpolation(boolean elevationInterpolation) {
this.elevationInterpolation = elevationInterpolation;
}
}

View File

@@ -0,0 +1,186 @@
package com.dfsek.terra.generation.config;
import org.polydev.gaea.math.FastNoiseLite;
public class NoiseBuilder {
private FastNoiseLite.NoiseType type = FastNoiseLite.NoiseType.OpenSimplex2;
private int octaves = 1;
private FastNoiseLite.FractalType fractalType = FastNoiseLite.FractalType.None;
private double frequency = 0.02D;
private double fractalGain = 0.5D;
private double fractalLacunarity = 2.0D;
private double pingPong = 2.0D;
private double weightedStrength = 0.0D;
private int seedOffset = 0;
private FastNoiseLite.CellularDistanceFunction cellularDistanceFunction = FastNoiseLite.CellularDistanceFunction.EuclideanSq;
private FastNoiseLite.CellularReturnType cellularReturnType = FastNoiseLite.CellularReturnType.Distance;
private double cellularJitter = 1.0D;
private FastNoiseLite.DomainWarpType domainWarpType = FastNoiseLite.DomainWarpType.OpenSimplex2;
private double domainWarpAmp = 1.0D;
private FastNoiseLite.RotationType3D rotationType3D = FastNoiseLite.RotationType3D.None;
public FastNoiseLite build(int seed) {
FastNoiseLite noise = new FastNoiseLite(seed + seedOffset);
if(!fractalType.equals(FastNoiseLite.FractalType.None)) {
noise.setFractalType(fractalType);
noise.setFractalOctaves(octaves);
noise.setFractalGain(fractalGain);
noise.setFractalLacunarity(fractalLacunarity);
if(fractalType.equals(FastNoiseLite.FractalType.PingPong)) noise.setFractalPingPongStrength(pingPong);
noise.setFractalWeightedStrength(weightedStrength);
}
if(type.equals(FastNoiseLite.NoiseType.Cellular)) {
noise.setCellularDistanceFunction(cellularDistanceFunction);
noise.setCellularReturnType(cellularReturnType);
noise.setCellularJitter(cellularJitter);
}
noise.setNoiseType(type);
noise.setDomainWarpType(domainWarpType);
noise.setDomainWarpAmp(domainWarpAmp);
noise.setRotationType3D(rotationType3D);
noise.setFrequency(frequency);
return noise;
}
public FastNoiseLite.NoiseType getType() {
return type;
}
public NoiseBuilder setType(FastNoiseLite.NoiseType type) {
this.type = type;
return this;
}
public int getSeedOffset() {
return seedOffset;
}
public void setSeedOffset(int seedOffset) {
this.seedOffset = seedOffset;
}
public FastNoiseLite.CellularDistanceFunction getCellularDistanceFunction() {
return cellularDistanceFunction;
}
public NoiseBuilder setCellularDistanceFunction(FastNoiseLite.CellularDistanceFunction cellularDistanceFunction) {
this.cellularDistanceFunction = cellularDistanceFunction;
return this;
}
public FastNoiseLite.CellularReturnType getCellularReturnType() {
return cellularReturnType;
}
public NoiseBuilder setCellularReturnType(FastNoiseLite.CellularReturnType cellularReturnType) {
this.cellularReturnType = cellularReturnType;
return this;
}
public FastNoiseLite.DomainWarpType getDomainWarpType() {
return domainWarpType;
}
public NoiseBuilder setDomainWarpType(FastNoiseLite.DomainWarpType domainWarpType) {
this.domainWarpType = domainWarpType;
return this;
}
public double getCellularJitter() {
return cellularJitter;
}
public NoiseBuilder setCellularJitter(double cellularJitter) {
this.cellularJitter = cellularJitter;
return this;
}
public double getDomainWarpAmp() {
return domainWarpAmp;
}
public NoiseBuilder setDomainWarpAmp(double domainWarpAmp) {
this.domainWarpAmp = domainWarpAmp;
return this;
}
public double getFractalGain() {
return fractalGain;
}
public NoiseBuilder setFractalGain(double fractalGain) {
this.fractalGain = fractalGain;
return this;
}
public double getFractalLacunarity() {
return fractalLacunarity;
}
public NoiseBuilder setFractalLacunarity(double fractalLacunarity) {
this.fractalLacunarity = fractalLacunarity;
return this;
}
public double getFrequency() {
return frequency;
}
public NoiseBuilder setFrequency(double frequency) {
this.frequency = frequency;
return this;
}
public double getPingPong() {
return pingPong;
}
public NoiseBuilder setPingPong(double pingPong) {
this.pingPong = pingPong;
return this;
}
public double getWeightedStrength() {
return weightedStrength;
}
public NoiseBuilder setWeightedStrength(double weightedStrength) {
this.weightedStrength = weightedStrength;
return this;
}
public int getOctaves() {
return octaves;
}
public NoiseBuilder setOctaves(int octaves) {
this.octaves = octaves;
return this;
}
public FastNoiseLite.FractalType getFractalType() {
return fractalType;
}
public NoiseBuilder setFractalType(FastNoiseLite.FractalType fractalType) {
this.fractalType = fractalType;
return this;
}
public FastNoiseLite.RotationType3D getRotationType3D() {
return rotationType3D;
}
public NoiseBuilder setRotationType3D(FastNoiseLite.RotationType3D rotationType3D) {
this.rotationType3D = rotationType3D;
return this;
}
}

View File

@@ -0,0 +1,140 @@
package com.dfsek.terra.generation.config;
import com.dfsek.terra.config.genconfig.noise.NoiseConfig;
import com.dfsek.terra.math.NoiseFunction2;
import com.dfsek.terra.math.NoiseFunction3;
import com.dfsek.terra.math.RandomFunction;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.polydev.gaea.biome.Generator;
import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.Interpolator;
import org.polydev.gaea.world.palette.Palette;
import parsii.eval.Expression;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
import java.util.Map;
public class WorldGenerator extends Generator {
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final Palette<BlockData>[] palettes;
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final Palette<BlockData>[] slantPalettes;
private final boolean preventSmooth;
private final Expression noiseExp;
private final Expression elevationExp;
private final Variable xVar;
private final Variable yVar;
private final Variable zVar;
private final Variable elevationXVar;
private final Variable elevationZVar;
private boolean elevationInterpolation = true;
@SuppressWarnings({"rawtypes", "unchecked"})
public WorldGenerator(long seed, String equation, String elevateEquation, Scope vScope, Map<String, NoiseConfig> noiseBuilders, Palette[] palettes, Palette[] slantPalettes, boolean preventSmooth) {
Parser p = new Parser();
p.registerFunction("rand", new RandomFunction());
Parser ep = new Parser();
ep.registerFunction("rand", new RandomFunction());
Scope s = new Scope().withParent(vScope);
xVar = s.create("x");
yVar = s.create("y");
zVar = s.create("z");
s.create("seed").setValue(seed);
this.preventSmooth = preventSmooth;
this.palettes = palettes;
this.slantPalettes = slantPalettes;
for(Map.Entry<String, NoiseConfig> e : noiseBuilders.entrySet()) {
switch(e.getValue().getDimensions()) {
case 2:
p.registerFunction(e.getKey(), new NoiseFunction2(seed, e.getValue().getBuilder()));
ep.registerFunction(e.getKey(), new NoiseFunction2(seed, e.getValue().getBuilder()));
break;
case 3:
p.registerFunction(e.getKey(), new NoiseFunction3(seed, e.getValue().getBuilder()));
break;
}
}
try {
this.noiseExp = p.parse(equation, s).simplify();
if(elevateEquation != null) {
Scope es = new Scope().withParent(vScope);
es.create("seed").setValue(seed);
this.elevationXVar = es.create("x");
this.elevationZVar = es.create("z");
this.elevationExp = ep.parse(elevateEquation, es).simplify();
} else {
this.elevationExp = null;
this.elevationXVar = null;
this.elevationZVar = null;
}
} catch(ParseException e) {
throw new IllegalArgumentException();
}
}
public synchronized double getElevation(int x, int z) {
if(elevationExp == null) return 0;
elevationXVar.setValue(x);
elevationZVar.setValue(z);
return elevationExp.evaluate();
}
@Override
public synchronized double getNoise(FastNoiseLite fastNoiseLite, World world, int x, int z) {
xVar.setValue(x);
yVar.setValue(0);
zVar.setValue(z);
return noiseExp.evaluate();
}
@Override
public synchronized double getNoise(FastNoiseLite fastNoiseLite, World world, int x, int y, int z) {
xVar.setValue(x);
yVar.setValue(y);
zVar.setValue(z);
return noiseExp.evaluate();
}
/**
* Gets the BlockPalette to generate the biome with.
*
* @return BlockPalette - The biome's palette.
*/
@Override
public Palette<BlockData> getPalette(int y) {
return palettes[y];
}
public Palette<BlockData> getSlantPalette(int y) {
return slantPalettes[y];
}
@Override
public boolean useMinimalInterpolation() {
return preventSmooth;
}
@Override
public Interpolator.Type getInterpolationType() {
return Interpolator.Type.LINEAR;
}
public boolean interpolateElevation() {
return elevationInterpolation;
}
public WorldGenerator setElevationInterpolation(boolean elevationInterpolation) {
this.elevationInterpolation = elevationInterpolation;
return this;
}
}

View File

@@ -5,6 +5,7 @@ import com.dfsek.terra.biome.BiomeZone;
import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.debug.gui.DebugGUI;
import net.jafama.FastMath;
import org.bukkit.World;
import org.polydev.gaea.biome.NormalizationUtil;
@@ -108,12 +109,12 @@ public class ImageLoader {
NONE {
@Override
public int getRGB(BufferedImage image, int x, int y) {
return image.getRGB(Math.floorMod(x, image.getWidth()), Math.floorMod(y, image.getHeight()));
return image.getRGB(FastMath.floorMod(x, image.getWidth()), FastMath.floorMod(y, image.getHeight()));
}
};
private static int getRGBNoAlign(BufferedImage image, int x, int y) {
return image.getRGB(Math.floorMod(x, image.getWidth()), Math.floorMod(y, image.getHeight()));
return image.getRGB(FastMath.floorMod(x, image.getWidth()), FastMath.floorMod(y, image.getHeight()));
}
public abstract int getRGB(BufferedImage image, int x, int y);

View File

@@ -0,0 +1,29 @@
package com.dfsek.terra.math;
import parsii.eval.Expression;
import parsii.eval.Function;
import java.util.List;
public class BlankFunction implements Function {
private final int args;
public BlankFunction(int args) {
this.args = args;
}
@Override
public int getNumberOfArguments() {
return args;
}
@Override
public double eval(List<Expression> list) {
return 0;
}
@Override
public boolean isNaturalFunction() {
return true;
}
}

View File

@@ -0,0 +1,6 @@
package com.dfsek.terra.math;
import parsii.eval.Function;
public interface NoiseFunction extends Function {
}

View File

@@ -1,15 +1,20 @@
package com.dfsek.terra.math;
import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.generation.config.NoiseBuilder;
import com.dfsek.terra.util.hash.HashMapDoubleDouble;
import org.polydev.gaea.math.FastNoiseLite;
import parsii.eval.Expression;
import parsii.eval.Function;
import java.util.List;
public class NoiseFunction2 implements Function {
public class NoiseFunction2 implements NoiseFunction {
private final FastNoiseLite gen;
private final Cache cache = new Cache();
private FastNoiseLite gen;
public NoiseFunction2(long seed, NoiseBuilder builder) {
this.gen = builder.build((int) seed);
}
@Override
public int getNumberOfArguments() {
@@ -18,7 +23,17 @@ public class NoiseFunction2 implements Function {
@Override
public double eval(List<Expression> list) {
return cache.get(list.get(0).evaluate(), list.get(1).evaluate());
return cache.get(gen, list.get(0).evaluate(), list.get(1).evaluate());
}
/**
* Evaluate without cache. For testing.
*
* @param list Parameters.
* @return Result.
*/
public double evalNoCache(List<Expression> list) {
return gen.getNoise(list.get(0).evaluate(), list.get(1).evaluate());
}
@Override
@@ -26,28 +41,24 @@ public class NoiseFunction2 implements Function {
return true;
}
public void setNoise(FastNoiseLite gen) {
this.gen = gen;
}
private static class Cache extends HashMapDoubleDouble {
private static final long serialVersionUID = 8915092734723467010L;
private static final int cacheSize = ConfigUtil.cacheSize;
private final class Cache {
private final double[] cacheX = new double[ConfigUtil.cacheSize];
private final double[] cacheZ = new double[ConfigUtil.cacheSize];
private final double[] cacheValues = new double[ConfigUtil.cacheSize];
public double get(FastNoiseLite noise, double x, double z) {
double xx = x >= 0 ? x * 2 : x * -2 - 1;
double zz = z >= 0 ? z * 2 : z * -2 - 1;
double key = (xx >= zz) ? (xx * xx + xx + zz) : (zz * zz + xx);
double value = this.get(key);
if(this.size() > cacheSize) {
this.clear();
}
return (value == 4.9E-324D ? addAndReturn(noise.getNoise(x, z), key) : value);
}
public double get(double x, double z) {
for(int i = 0; i < cacheX.length; i++) {
if(cacheX[i] == x && cacheZ[i] == z) return cacheValues[i];
}
cacheX[0] = x;
cacheZ[0] = z;
cacheValues[0] = gen.getNoise(x, z);
for(int i = 0; i < cacheX.length - 1; i++) {
cacheX[i + 1] = cacheX[i];
cacheZ[i + 1] = cacheZ[i];
cacheValues[i + 1] = cacheValues[i];
}
return cacheValues[0];
private double addAndReturn(double value, double key) {
this.put(key, value);
return value;
}
}
}

View File

@@ -1,13 +1,17 @@
package com.dfsek.terra.math;
import com.dfsek.terra.generation.config.NoiseBuilder;
import org.polydev.gaea.math.FastNoiseLite;
import parsii.eval.Expression;
import parsii.eval.Function;
import java.util.List;
public class NoiseFunction3 implements Function {
private FastNoiseLite gen;
public class NoiseFunction3 implements NoiseFunction {
private final FastNoiseLite gen;
public NoiseFunction3(long seed, NoiseBuilder builder) {
this.gen = builder.build((int) seed);
}
@Override
public int getNumberOfArguments() {
@@ -23,8 +27,4 @@ public class NoiseFunction3 implements Function {
public boolean isNaturalFunction() {
return true;
}
public void setNoise(FastNoiseLite gen) {
this.gen = gen;
}
}

View File

@@ -0,0 +1,30 @@
package com.dfsek.terra.math;
import org.polydev.gaea.util.FastRandom;
import parsii.eval.Expression;
import parsii.eval.Function;
import java.util.List;
/**
* Provides access to a PRNG ({@link org.polydev.gaea.util.FastRandom})
* <p>
* Takes 1 argument, which sets the seed
*/
public class RandomFunction implements Function {
@Override
public int getNumberOfArguments() {
return 1;
}
@Override
public double eval(List<Expression> list) {
long seed = (long) list.get(0).evaluate();
return new FastRandom(seed).nextDouble();
}
@Override
public boolean isNaturalFunction() {
return true;
}
}

View File

@@ -5,6 +5,7 @@ import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.genconfig.CarverConfig;
import com.dfsek.terra.util.PopulationUtil;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -30,9 +31,10 @@ public class CavePopulator extends BlockPopulator {
@SuppressWarnings("try")
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
public void populate(@NotNull World world, @NotNull Random r, @NotNull Chunk chunk) {
if(ConfigUtil.masterDisableCaves) return;
try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("CaveTime")) {
Random random = PopulationUtil.getRandom(chunk);
TerraWorld tw = TerraWorld.getWorld(world);
if(!tw.isSafe()) return;
ConfigPack config = tw.getConfig();
@@ -70,24 +72,23 @@ public class CavePopulator extends BlockPopulator {
updateNeeded.add(b);
}
}
for(Location l : shiftCandidate.keySet()) {
for(Map.Entry<Location, Material> entry : shiftCandidate.entrySet()) {
Location l = entry.getKey();
Location mut = l.clone();
Material orig = l.getBlock().getType();
do mut.subtract(0, 1, 0);
while(mut.getBlock().getType().equals(orig));
try {
if(c.getShiftedBlocks().get(shiftCandidate.get(l)).contains(mut.getBlock().getType())) {
mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(shiftCandidate.get(l), Material::createBlockData), false);
if(c.getShiftedBlocks().get(entry.getValue()).contains(mut.getBlock().getType())) {
mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(entry.getValue(), Material::createBlockData), false);
}
} catch(NullPointerException ignore) {
}
}
try(ProfileFuture ignore = TerraProfiler.fromWorld(world).measure("CaveBlockUpdate")) {
for(Block b : updateNeeded) {
BlockData orig = b.getBlockData();
b.setBlockData(AIR, false);
b.setBlockData(orig, true);
}
for(Block b : updateNeeded) {
BlockData orig = b.getBlockData();
b.setBlockData(AIR, false);
b.setBlockData(orig, true);
}
/*for(Map.Entry<Vector, CarvingData.CarvingType> e : new SimplexCarver(chunk.getX(), chunk.getZ()).carve(chunk.getX(), chunk.getZ(), world).getCarvedBlocks().entrySet()) {
Vector v = e.getKey();

View File

@@ -1,29 +1,20 @@
package com.dfsek.terra.population;
import com.dfsek.terra.Terra;
import com.dfsek.terra.TerraProfiler;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeFloraConfig;
import com.dfsek.terra.event.TreeGenerateEvent;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.math.Range;
import org.polydev.gaea.population.GaeaBlockPopulator;
import org.polydev.gaea.profiler.ProfileFuture;
import org.polydev.gaea.tree.Tree;
import org.polydev.gaea.world.Flora;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
@@ -39,21 +30,12 @@ public class FloraPopulator extends GaeaBlockPopulator {
int originX = chunk.getX() << 4;
int originZ = chunk.getZ() << 4;
TerraBiomeGrid grid = tw.getGrid();
ConfigPack config = tw.getConfig();
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
UserDefinedBiome biome = (UserDefinedBiome) grid.getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z, GenerationPhase.POPULATE);
if((x & 1) == 0 && (z & 1) == 0) {
int treeChance = biome.getDecorator().getTreeDensity();
if(random.nextInt(1000) < treeChance) {
int xt = offset(random, x);
int zt = offset(random, z);
if(doTrees(biome, tw, random, chunk, xt, zt)) continue;
}
}
if(biome.getDecorator().getFloraChance() <= 0) continue;
try {
BiomeConfig c = config.getBiome(biome);
BiomeConfig c = biome.getConfig();
BiomeFloraConfig f = c.getFlora();
for(int i = 0; i < f.getFloraAttempts(); i++) {
Flora item;
@@ -71,34 +53,4 @@ public class FloraPopulator extends GaeaBlockPopulator {
}
}
}
private static boolean doTrees(@NotNull UserDefinedBiome biome, TerraWorld world, @NotNull Random random, @NotNull Chunk chunk, int x, int z) {
for(Block block : getValidTreeSpawnsAt(chunk, x, z, new Range(0, 254))) {
Tree tree = biome.getDecorator().getTrees().get(random);
Range range = world.getConfig().getBiome(biome).getTreeRange(tree);
if(!range.isInRange(block.getY())) continue;
try {
Location l = block.getLocation();
TreeGenerateEvent event = new TreeGenerateEvent(world, l, tree);
Bukkit.getPluginManager().callEvent(event);
if(!event.isCancelled()) tree.plant(l, random, Terra.getInstance());
} catch(NullPointerException ignore) {
}
}
return false;
}
public static List<Block> getValidTreeSpawnsAt(Chunk chunk, int x, int z, Range check) {
List<Block> blocks = new ArrayList<>();
for(int y : check) {
if(chunk.getBlock(x, y, z).getType().isSolid() && chunk.getBlock(x, y + 1, z).getType().isAir()) {
blocks.add(chunk.getBlock(x, y + 1, z));
}
}
return blocks;
}
private static int offset(Random r, int i) {
return Math.min(Math.max(i + r.nextInt(3) - 1, 0), 15);
}
}

View File

@@ -3,7 +3,6 @@ package com.dfsek.terra.population;
import com.dfsek.terra.TerraProfiler;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.genconfig.OreConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeOreConfig;
import com.dfsek.terra.event.OreVeinGenerateEvent;
@@ -24,28 +23,29 @@ import java.util.Random;
public class OrePopulator extends GaeaBlockPopulator {
@SuppressWarnings("try")
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
public void populate(@NotNull World world, @NotNull Random r, @NotNull Chunk chunk) {
try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("OreTime")) {
TerraWorld tw = TerraWorld.getWorld(world);
if(!tw.isSafe()) return;
ConfigPack config = tw.getConfig();
Biome b = TerraWorld.getWorld(world).getGrid().getBiome((chunk.getX() << 4) + 8, (chunk.getZ() << 4) + 8, GenerationPhase.POPULATE);
BiomeOreConfig ores = config.getBiome((UserDefinedBiome) b).getOres();
for(Map.Entry<OreConfig, Range> e : ores.getOres().entrySet()) {
int num = e.getValue().get(random);
OreConfig ore = e.getKey();
int edgeOffset = ore.getChunkEdgeOffset();
for(int i = 0; i < num; i++) {
int x = random.nextInt(16 - edgeOffset * 2) + edgeOffset;
int z = random.nextInt(16 - edgeOffset * 2) + edgeOffset;
int y = ores.getOreHeights().get(ore).get(random);
for(int cx = -1; cx <= 1; cx++) {
for(int cz = -1; cz <= 1; cz++) {
Biome b = TerraWorld.getWorld(world).getGrid().getBiome(((chunk.getX() + cx) << 4) + 8, ((chunk.getZ() + cz) << 4) + 8, GenerationPhase.POPULATE);
BiomeOreConfig ores = ((UserDefinedBiome) b).getConfig().getOres();
for(Map.Entry<OreConfig, Range> e : ores.getOres().entrySet()) {
int num = e.getValue().get(r);
OreConfig ore = e.getKey();
for(int i = 0; i < num; i++) {
int x = r.nextInt(16) + cx * 16;
int z = r.nextInt(16) + cz * 16;
int y = ores.getOreHeights().get(ore).get(r);
Vector v = new Vector(x, y, z);
OreVeinGenerateEvent event = new OreVeinGenerateEvent(tw, v.toLocation(world), ore);
Bukkit.getPluginManager().callEvent(event);
if(!event.isCancelled()) {
if(ore.crossChunks()) ore.doVein(v, chunk, random);
else ore.doVeinSingle(new Vector(x, y, z), chunk, random);
Vector v = new Vector(x, y, z);
OreVeinGenerateEvent event = new OreVeinGenerateEvent(tw, v.toLocation(world), ore);
Bukkit.getPluginManager().callEvent(event);
if(!event.isCancelled()) {
ore.doVeinSingle(new Vector(x, y, z), chunk, r);
}
}
}
}
}

View File

@@ -12,6 +12,9 @@ import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Snowable;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.population.GaeaBlockPopulator;
@@ -55,7 +58,7 @@ public class SnowPopulator extends GaeaBlockPopulator {
TerraBiomeGrid g = w.getGrid();
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
BiomeConfig biome = w.getConfig().getBiome((UserDefinedBiome) g.getBiome(origX + x, origZ + z, GenerationPhase.PALETTE_APPLY));
BiomeConfig biome = ((UserDefinedBiome) g.getBiome(origX + x, origZ + z, GenerationPhase.PALETTE_APPLY)).getConfig();
if(!biome.getSnow().doSnow()) continue;
int y;
Block b = null;
@@ -66,7 +69,13 @@ public class SnowPopulator extends GaeaBlockPopulator {
if(random.nextInt(100) >= biome.getSnow().getSnowChance(y))
continue;
if(blacklistSpawn.contains(b.getType()) || b.isPassable()) continue;
chunk.getBlock(x, ++y, z).setBlockData(DataUtil.SNOW);
boolean phys = biome.getSnow().doPhysics();
if(!phys) {
BlockData data = b.getBlockData();
if(data instanceof Snowable) phys = true;
}
b.getRelative(BlockFace.UP).setBlockData(DataUtil.SNOW, phys);
}
}
}

View File

@@ -12,7 +12,9 @@ import com.dfsek.terra.structure.Rotation;
import com.dfsek.terra.structure.Structure;
import com.dfsek.terra.structure.StructureContainedInventory;
import com.dfsek.terra.structure.features.Feature;
import com.dfsek.terra.util.PopulationUtil;
import com.dfsek.terra.util.structure.RotationUtil;
import net.jafama.FastMath;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
@@ -21,6 +23,7 @@ import org.bukkit.inventory.BlockInventoryHolder;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.profiler.ProfileFuture;
import org.polydev.gaea.structures.loot.LootTable;
import org.polydev.gaea.util.FastRandom;
import java.util.Random;
@@ -28,8 +31,9 @@ public class StructurePopulator extends BlockPopulator {
@SuppressWarnings("try")
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
public void populate(@NotNull World world, @NotNull Random r, @NotNull Chunk chunk) {
try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("StructureTime")) {
Random random = PopulationUtil.getRandom(chunk);
int cx = (chunk.getX() << 4);
int cz = (chunk.getZ() << 4);
TerraWorld tw = TerraWorld.getWorld(world);
@@ -39,8 +43,8 @@ public class StructurePopulator extends BlockPopulator {
structure:
for(StructureConfig conf : config.getAllStructures()) {
Location spawn = conf.getSpawn().getNearestSpawn(cx + 8, cz + 8, world.getSeed()).toLocation(world);
if(!config.getBiome((UserDefinedBiome) grid.getBiome(spawn)).getStructures().contains(conf)) continue;
Random r2 = new Random(spawn.hashCode());
if(!((UserDefinedBiome) grid.getBiome(spawn)).getConfig().getStructures().contains(conf)) continue;
Random r2 = new FastRandom(spawn.hashCode());
Structure struc = conf.getStructure(r2);
Rotation rotation = Rotation.fromDegrees(r2.nextInt(4) * 90);
for(int y = conf.getSearchStart().get(r2); y > 0; y--) {
@@ -48,15 +52,15 @@ public class StructurePopulator extends BlockPopulator {
spawn.setY(y);
if(!struc.checkSpawns(spawn, rotation)) continue;
double horizontal = struc.getStructureInfo().getMaxHorizontal();
if(Math.abs((cx + 8) - spawn.getBlockX()) <= horizontal && Math.abs((cz + 8) - spawn.getBlockZ()) <= horizontal) {
if(FastMath.abs((cx + 8) - spawn.getBlockX()) <= horizontal && FastMath.abs((cz + 8) - spawn.getBlockZ()) <= horizontal) {
struc.paste(spawn, chunk, rotation);
for(StructureContainedInventory i : struc.getInventories()) {
try {
Debug.info("Attempting to populate loot: " + i.getUid());
Vector2 lootCoords = RotationUtil.getRotatedCoords(new Vector2(i.getX() - struc.getStructureInfo().getCenterX(), i.getZ() - struc.getStructureInfo().getCenterZ()), rotation.inverse());
Location inv = spawn.clone().add(lootCoords.getX(), i.getY(), lootCoords.getZ());
Debug.info(Math.floorDiv(inv.getBlockX(), 16) + ":" + chunk.getX() + ", " + Math.floorDiv(inv.getBlockZ(), 16) + ":" + chunk.getZ());
if(Math.floorDiv(inv.getBlockX(), 16) != chunk.getX() || Math.floorDiv(inv.getBlockZ(), 16) != chunk.getZ())
Debug.info(FastMath.floorDiv(inv.getBlockX(), 16) + ":" + chunk.getX() + ", " + FastMath.floorDiv(inv.getBlockZ(), 16) + ":" + chunk.getZ());
if(FastMath.floorDiv(inv.getBlockX(), 16) != chunk.getX() || FastMath.floorDiv(inv.getBlockZ(), 16) != chunk.getZ())
continue;
Debug.info("Target is in chunk.");
Debug.info(spawn.toString() + " became: " + inv.toString() + " (" + rotation + ", " + inv.getBlock().getType() + ")");
@@ -69,7 +73,7 @@ public class StructurePopulator extends BlockPopulator {
Debug.stack(e);
}
}
for(Feature f : conf.getFeatures()) f.apply(struc, spawn, chunk); // Apply features.
for(Feature f : conf.getFeatures()) f.apply(struc, rotation, spawn, chunk); // Apply features.
break;
}
}

View File

@@ -0,0 +1,77 @@
package com.dfsek.terra.population;
import com.dfsek.terra.Terra;
import com.dfsek.terra.TerraProfiler;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import com.dfsek.terra.event.TreeGenerateEvent;
import net.jafama.FastMath;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.math.Range;
import org.polydev.gaea.population.GaeaBlockPopulator;
import org.polydev.gaea.profiler.ProfileFuture;
import org.polydev.gaea.tree.Tree;
import org.polydev.gaea.util.GlueList;
import java.util.List;
import java.util.Random;
public class TreePopulator extends GaeaBlockPopulator {
private static void doTrees(@NotNull UserDefinedBiome biome, TerraWorld world, @NotNull Random random, @NotNull Chunk chunk, int x, int z) {
for(Block block : getValidTreeSpawnsAt(chunk, x, z, new Range(0, 254))) {
Tree tree = biome.getDecorator().getTrees().get(random);
Range range = biome.getConfig().getTreeRange(tree);
if(!range.isInRange(block.getY())) continue;
try {
Location l = block.getLocation();
TreeGenerateEvent event = new TreeGenerateEvent(world, l, tree);
Bukkit.getPluginManager().callEvent(event);
if(!event.isCancelled()) tree.plant(l, random, Terra.getInstance());
} catch(NullPointerException ignore) {
}
}
}
public static List<Block> getValidTreeSpawnsAt(Chunk chunk, int x, int z, Range check) {
List<Block> blocks = new GlueList<>();
for(int y : check) {
if(chunk.getBlock(x, y, z).getType().isSolid() && chunk.getBlock(x, y + 1, z).isPassable()) {
blocks.add(chunk.getBlock(x, y + 1, z));
}
}
return blocks;
}
private static int offset(Random r, int i) {
return FastMath.min(FastMath.max(i + r.nextInt(3) - 1, 0), 15);
}
@Override
@SuppressWarnings("try")
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("TreeTime")) {
TerraWorld tw = TerraWorld.getWorld(world);
if(!tw.isSafe()) return;
TerraBiomeGrid grid = tw.getGrid();
for(int x = 0; x < 16; x += 2) {
for(int z = 0; z < 16; z += 2) {
UserDefinedBiome biome = (UserDefinedBiome) grid.getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z, GenerationPhase.POPULATE);
int treeChance = biome.getDecorator().getTreeDensity();
if(random.nextInt(1000) < treeChance) {
int xt = offset(random, x);
int zt = offset(random, z);
doTrees(biome, tw, random, chunk, xt, zt);
}
}
}
}
}
}

View File

@@ -2,8 +2,9 @@ package com.dfsek.terra.procgen;
import org.bukkit.util.Vector;
import org.polydev.gaea.math.MathUtil;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.util.GlueList;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@@ -30,7 +31,7 @@ public class GridSpawn {
public Vector getNearestSpawn(int x, int z, long seed) {
int structureChunkX = x / (width + 2 * separation);
int structureChunkZ = z / (width + 2 * separation);
List<Vector> zones = new ArrayList<>();
List<Vector> zones = new GlueList<>();
for(int xi = structureChunkX - 1; xi <= structureChunkX + 1; xi++) {
for(int zi = structureChunkZ - 1; zi <= structureChunkZ + 1; zi++) {
zones.add(getChunkSpawn(xi, zi, seed));
@@ -53,7 +54,7 @@ public class GridSpawn {
* @return Vector representing spawnpoint
*/
public Vector getChunkSpawn(int structureChunkX, int structureChunkZ, long seed) {
Random r = new Random(MathUtil.getCarverChunkSeed(structureChunkX, structureChunkZ, seed));
Random r = new FastRandom(MathUtil.getCarverChunkSeed(structureChunkX, structureChunkZ, seed));
int offsetX = r.nextInt(width);
int offsetZ = r.nextInt(width);
int sx = structureChunkX * (width + 2 * separation) + offsetX;

View File

@@ -1,5 +1,7 @@
package com.dfsek.terra.procgen.math;
import net.jafama.FastMath;
/**
* oh yeah
*/
@@ -111,7 +113,7 @@ public class Vector2 implements Cloneable {
* @return length
*/
public double length() {
return Math.sqrt(lengthSquared());
return FastMath.sqrt(lengthSquared());
}
/**
@@ -130,7 +132,7 @@ public class Vector2 implements Cloneable {
* @return Distance between vectors
*/
public double distance(Vector2 other) {
return Math.sqrt(distanceSquared(other));
return FastMath.sqrt(distanceSquared(other));
}
/**

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.procgen.pixel;
import com.dfsek.terra.procgen.math.Vector2;
import net.jafama.FastMath;
import java.util.HashSet;
import java.util.Set;
@@ -11,8 +12,8 @@ public class Rectangle extends Polygon {
private final Vector2 max;
public Rectangle(Vector2 min, Vector2 max) {
this.max = new Vector2(Math.min(min.getX(), max.getX()), Math.min(min.getZ(), max.getZ()));
this.min = new Vector2(Math.max(min.getX(), max.getX()), Math.max(min.getZ(), max.getZ()));
this.max = new Vector2(FastMath.min(min.getX(), max.getX()), FastMath.min(min.getZ(), max.getZ()));
this.min = new Vector2(FastMath.max(min.getX(), max.getX()), FastMath.max(min.getZ(), max.getZ()));
}
public Rectangle(Vector2 center, double xRadius, double zRadius) {

View File

@@ -1,12 +1,12 @@
package com.dfsek.terra.procgen.voxel;
import org.bukkit.util.Vector;
import org.polydev.gaea.util.GlueList;
import java.util.ArrayList;
import java.util.List;
public abstract class VoxelGeometry {
private final List<Vector> geometry = new ArrayList<>();
private final List<Vector> geometry = new GlueList<>();
public static VoxelGeometry getBlank() {
return new VoxelGeometry() {

View File

@@ -1,5 +1,7 @@
package com.dfsek.terra.structure;
import net.jafama.FastMath;
public enum Rotation {
CW_90(90), CW_180(180), CCW_90(270), NONE(0);
private final int degrees;
@@ -9,7 +11,7 @@ public enum Rotation {
}
public static Rotation fromDegrees(int deg) {
switch(Math.floorMod(deg, 360)) {
switch(FastMath.floorMod(deg, 360)) {
case 0:
return Rotation.NONE;
case 90:

View File

@@ -3,6 +3,7 @@ package com.dfsek.terra.structure;
import com.dfsek.terra.Debug;
import com.dfsek.terra.procgen.math.Vector2;
import com.dfsek.terra.util.structure.RotationUtil;
import net.jafama.FastMath;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
@@ -144,6 +145,16 @@ public class Structure implements Serializable {
return (Structure) o;
}
private static void toFile(@NotNull Serializable o, @NotNull File f) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(o);
oos.close();
}
public StructureContainedBlock[][][] getRawStructure() {
return structure;
}
/**
* Paste the structure at a Location, ignoring chunk boundaries.
*
@@ -188,7 +199,7 @@ public class Structure implements Serializable {
}
int offset = block.getPullOffset();
if(offset != 0)
worldBlock = worldBlock.getRelative((offset > 0) ? BlockFace.UP : BlockFace.DOWN, Math.abs(offset));
worldBlock = worldBlock.getRelative((offset > 0) ? BlockFace.UP : BlockFace.DOWN, FastMath.abs(offset));
RotationUtil.rotateBlockData(data, r);
@@ -255,9 +266,9 @@ public class Structure implements Serializable {
Vector2 max = getRotatedCoords(new Vector2(x.getMax(), z.getMax()).subtract(center), r.inverse()).add(center);
if(a.equals(Rotation.Axis.X))
return new Range((int) Math.floor(Math.min(min.getX(), max.getX())), (int) Math.ceil(Math.max(min.getX(), max.getX())) + 1);
return new Range((int) FastMath.floor(FastMath.min(min.getX(), max.getX())), (int) FastMath.ceil(FastMath.max(min.getX(), max.getX())) + 1);
else
return new Range((int) Math.floor(Math.min(min.getZ(), max.getZ())), (int) Math.ceil(Math.max(min.getZ(), max.getZ())) + 1);
return new Range((int) FastMath.floor(FastMath.min(min.getZ(), max.getZ())), (int) FastMath.ceil(FastMath.max(min.getZ(), max.getZ())) + 1);
}
@NotNull
@@ -283,6 +294,10 @@ public class Structure implements Serializable {
return true;
}
public HashSet<StructureContainedBlock> getSpawns() {
return spawns;
}
public HashSet<StructureContainedInventory> getInventories() {
return inventories;
}
@@ -324,12 +339,6 @@ public class Structure implements Serializable {
toFile(this, f);
}
private static void toFile(@NotNull Serializable o, @NotNull File f) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(o);
oos.close();
}
@NotNull
public String getId() {
return id;

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.structure;
import com.dfsek.terra.procgen.math.Vector2;
import net.jafama.FastMath;
import java.io.Serializable;
@@ -41,6 +42,6 @@ public class StructureInfo implements Serializable {
}
public double getMaxHorizontal() {
return Math.sqrt(Math.pow(sizeX, 2) + Math.pow(sizeZ, 2));
return FastMath.sqrt(FastMath.pow(sizeX, 2) + FastMath.pow(sizeZ, 2));
}
}

View File

@@ -1,8 +1,10 @@
package com.dfsek.terra.structure.features;
import com.dfsek.terra.Debug;
import com.dfsek.terra.structure.Rotation;
import com.dfsek.terra.structure.Structure;
import com.dfsek.terra.structure.StructureInfo;
import net.jafama.FastMath;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -11,105 +13,83 @@ import org.bukkit.block.BlockFace;
import org.bukkit.entity.EntityType;
import org.polydev.gaea.math.MathUtil;
import org.polydev.gaea.math.Range;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.util.GlueList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
public class EntityFeature implements Feature {
private final EntityType type;
private final Range amount;
private final int attempts;
private final Set<Material> in;
private final Set<Material> stand;
private final int inSize;
public EntityFeature(EntityType type, Range amount, int attempts, Set<Material> stand, Set<Material> in, int inSize) {
public EntityFeature(EntityType type, Range amount, Set<Material> stand, Set<Material> in, int inSize) {
this.type = type;
this.amount = amount;
this.attempts = attempts;
this.in = in;
this.stand = stand;
this.inSize = inSize;
}
@Override
public void apply(Structure structure, Location l, Chunk chunk) {
Random random = new Random(MathUtil.getCarverChunkSeed(chunk.getX(), chunk.getZ(), chunk.getWorld().getSeed()));
int amountSpawn = amount.get(random);
private static boolean isInChunk(Chunk c, Location l) {
return FastMath.floorDiv(l.getBlockX(), 16) == c.getX() && FastMath.floorDiv(l.getBlockZ(), 16) == c.getZ();
}
private static List<Location> getLocations(Structure structure, Rotation r, Location origin, Random random, int number) {
StructureInfo info = structure.getStructureInfo();
Range x = new Range(0, info.getSizeZ());
Range y = new Range(0, info.getSizeY());
Range z = new Range(0, info.getSizeZ());
Range x = structure.getRange(Rotation.Axis.X, r);
Range y = structure.getRange(Rotation.Axis.Y, r);
Range z = structure.getRange(Rotation.Axis.Z, r);
int cx = info.getCenterX();
int cz = info.getCenterZ();
List<Location> locations = new GlueList<>();
for(int i = 0; i < number; i++)
locations.add(origin.clone().add(x.get(random) - cx, y.get(random), z.get(random) - cz));
return locations;
}
for(int i = 0; i < amountSpawn && i < attempts; i++) {
int yv = y.get(random);
Location attempt = l.clone().add(x.get(random) - cx, yv, z.get(random) - cz);
@Override
public void apply(Structure structure, Rotation r, Location l, Chunk chunk) {
Random random = new FastRandom(MathUtil.getCarverChunkSeed(chunk.getX(), chunk.getZ(), chunk.getWorld().getSeed()));
for(Location attempt : getLocations(structure, r, l, random, amount.get(random))) {
if(!isInChunk(chunk, attempt)) continue; // Don't attempt spawn if not in current chunk.
boolean canSpawn = false;
while(yv >= 0 && attempt.getBlockY() >= l.getBlockY()) { // Go down, see if valid spawns exist.
canSpawn = true;
Block on = attempt.getBlock();
attempt.subtract(0, 1, 0);
yv--;
if(!stand.contains(on.getType())) continue;
for(int j = 1; j < inSize + 1; j++)
if(!in.contains(on.getRelative(BlockFace.UP, j).getType())) canSpawn = false;
if(canSpawn) break;
}
if(canSpawn) {
Debug.info("Spawning entity at " + attempt);
chunk.getWorld().spawnEntity(attempt.add(0.5, 2, 0.5), type); // Add 0.5 to X & Z so entity spawns in center of block.
}
attemptSpawn(attempt, l);
}
}
private static boolean isInChunk(Chunk c, Location l) {
return Math.floorDiv(l.getBlockX(), 16) == c.getX() && Math.floorDiv(l.getBlockZ(), 16) == c.getZ();
private void attemptSpawn(Location attempt, Location origin) {
boolean canSpawn = false;
while(attempt.getBlockY() >= origin.getBlockY()) { // Go down, see if valid spawns exist.
canSpawn = true;
Block on = attempt.getBlock();
attempt.subtract(0, 1, 0);
if(!stand.contains(on.getType())) {
canSpawn = false;
continue;
}
for(int j = 1; j < inSize + 1; j++)
if(!in.contains(on.getRelative(BlockFace.UP, j).getType())) canSpawn = false;
if(canSpawn) break;
}
if(canSpawn) {
Debug.info("Spawning entity at " + attempt);
Objects.requireNonNull(attempt.getWorld()).spawnEntity(attempt.add(0.5, 2, 0.5), type); // Add 0.5 to X & Z so entity spawns in center of block.
}
}
@Override
public void apply(Structure structure, Location l, Random random) {
int amountSpawn = amount.get(random);
StructureInfo info = structure.getStructureInfo();
Range x = new Range(0, info.getSizeZ());
Range y = new Range(0, info.getSizeY());
Range z = new Range(0, info.getSizeZ());
int cx = info.getCenterX();
int cz = info.getCenterZ();
for(int i = 0; i < amountSpawn && i < attempts; i++) {
int yv = y.get(random);
Location attempt = l.clone().add(x.get(random) - cx, yv, z.get(random) - cz);
boolean canSpawn = false;
while(yv >= 0 && attempt.getBlockY() >= l.getBlockY()) { // Go down, see if valid spawns exist.
canSpawn = true;
Block on = attempt.getBlock();
attempt.subtract(0, 1, 0);
yv--;
if(!stand.contains(on.getType())) continue;
for(int j = 1; j < inSize + 1; j++)
if(!in.contains(on.getRelative(BlockFace.UP, j).getType())) canSpawn = false;
if(canSpawn) break;
}
if(canSpawn) {
Debug.info("Spawning entity at " + attempt);
l.getWorld().spawnEntity(attempt.add(0.5, 1, 0.5), type); // Add 0.5 to X & Z so entity spawns in center of block.
}
public void apply(Structure structure, Rotation r, Location l, Random random) {
for(Location attempt : getLocations(structure, r, l, random, amount.get(random))) {
attemptSpawn(attempt, l);
}
}
}

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.structure.features;
import com.dfsek.terra.structure.Rotation;
import com.dfsek.terra.structure.Structure;
import org.bukkit.Chunk;
import org.bukkit.Location;
@@ -7,7 +8,7 @@ import org.bukkit.Location;
import java.util.Random;
public interface Feature {
void apply(Structure structure, Location l, Chunk chunk);
void apply(Structure structure, Rotation r, Location l, Chunk chunk);
void apply(Structure structure, Location l, Random random);
void apply(Structure structure, Rotation r, Location l, Random random);
}

View File

@@ -2,8 +2,8 @@ package com.dfsek.terra.structure.spawn;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig;
import com.dfsek.terra.generation.config.WorldGenerator;
import org.bukkit.World;
import org.polydev.gaea.generation.GenerationPhase;
@@ -15,10 +15,10 @@ public class AirSpawn extends Requirement {
@Override
public boolean matches(int x, int y, int z) {
TerraWorld tw = TerraWorld.getWorld(getWorld());
ConfigPack wc = tw.getConfig();
UserDefinedBiome b = (UserDefinedBiome) tw.getGrid().getBiome(x, z, GenerationPhase.POPULATE);
BiomeConfig c = wc.getBiome(b);
BiomeConfig c = b.getConfig();
if(y <= c.getOcean().getSeaLevel()) return false;
return b.getGenerator().getNoise(getNoise(), getWorld(), x, y, z) <= 0;
int yf = (int) (y - ((WorldGenerator) b.getGenerator()).getElevation(x, z));
return b.getGenerator().getNoise(getNoise(), getWorld(), x, yf, z) <= 0;
}
}

View File

@@ -2,6 +2,7 @@ package com.dfsek.terra.structure.spawn;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.generation.config.WorldGenerator;
import org.bukkit.World;
import org.polydev.gaea.generation.GenerationPhase;
@@ -14,6 +15,7 @@ public class LandSpawn extends Requirement {
public boolean matches(int x, int y, int z) {
TerraWorld tw = TerraWorld.getWorld(getWorld());
UserDefinedBiome b = (UserDefinedBiome) tw.getGrid().getBiome(x, z, GenerationPhase.POPULATE);
return b.getGenerator().getNoise(getNoise(), getWorld(), x, y, z) > 0;
int yf = (int) (y - ((WorldGenerator) b.getGenerator()).getElevation(x, z));
return b.getGenerator().getNoise(getNoise(), getWorld(), x, yf, z) > 0;
}
}

View File

@@ -3,6 +3,7 @@ package com.dfsek.terra.structure.spawn;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig;
import com.dfsek.terra.generation.config.WorldGenerator;
import org.bukkit.World;
import org.polydev.gaea.generation.GenerationPhase;
@@ -15,8 +16,9 @@ public class OceanSpawn extends Requirement {
public boolean matches(int x, int y, int z) {
TerraWorld tw = TerraWorld.getWorld(getWorld());
UserDefinedBiome b = (UserDefinedBiome) tw.getGrid().getBiome(x, z, GenerationPhase.POPULATE);
BiomeConfig c = tw.getConfig().getBiome(b);
BiomeConfig c = b.getConfig();
if(y > c.getOcean().getSeaLevel()) return false;
return b.getGenerator().getNoise(getNoise(), getWorld(), x, y, z) <= 0;
int yf = (int) (y - ((WorldGenerator) b.getGenerator()).getElevation(x, z));
return b.getGenerator().getNoise(getNoise(), getWorld(), x, yf, z) <= 0;
}
}

View File

@@ -2,15 +2,14 @@ package com.dfsek.terra.util;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette;
import java.util.Random;
public final class DataUtil {
public static final BlockData STONE = Material.STONE.createBlockData();
public static final BlockData SNOW = Material.SNOW.createBlockData();
public static final BlockData WATER = Material.WATER.createBlockData();
public static final BlockData AIR = Material.AIR.createBlockData();
public static final Palette<BlockData> BLANK_PALETTE = new RandomPalette<BlockData>(new Random(2403)).add(AIR, 1);
public static final Palette<BlockData> BLANK_PALETTE = new RandomPalette<BlockData>(new FastRandom(2403)).add(AIR, 1);
}

View File

@@ -1,17 +1,16 @@
package com.dfsek.terra.util;
import com.dfsek.terra.config.lang.LangUtil;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.logging.Level;
import static io.papermc.lib.PaperLib.suggestPaper;
public final class PaperUtil {
public static void checkPaper(JavaPlugin main) {
Bukkit.getScheduler().scheduleSyncDelayedTask(main, () -> {
if(!PaperLib.isPaper()) {
LangUtil.log("use-paper", Level.WARNING);
suggestPaper(main);
}
}, 100L);
}

View File

@@ -0,0 +1,11 @@
package com.dfsek.terra.util;
import org.bukkit.Chunk;
import org.polydev.gaea.math.MathUtil;
import org.polydev.gaea.util.FastRandom;
public final class PopulationUtil {
public static FastRandom getRandom(Chunk c) {
return new FastRandom(MathUtil.getCarverChunkSeed(c.getX(), c.getZ(), c.getWorld().getSeed()));
}
}

View File

@@ -15,7 +15,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
@SuppressWarnings("unchecked")
public class TagUtil {
public final class TagUtil {
private static final Map<String, Set<Material>> tagMap;
static {

View File

@@ -0,0 +1,118 @@
/*
Copyright 2009 Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
retains certain rights in this software.
BSD Open Source License.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Sandia National Laboratories nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
package com.dfsek.terra.util.hash;
import java.io.Serializable;
public abstract class HashIntrinsic implements Serializable {
public static final int FLOAT_EXP_BIT_MASK = 2139095040;
public static final int FLOAT_SIGNIF_BIT_MASK = 8388607;
public static final long DOUBLE_EXP_BIT_MASK = 9218868437227405312L;
public static final long DOUBLE_SIGNIF_BIT_MASK = 4503599627370495L;
protected static final int DEFAULT_INITIAL_CAPACITY = 16;
protected static final int MAXIMUM_CAPACITY = 1073741824;
protected static final float DEFAULT_LOAD_FACTOR = 0.75F;
private static final long serialVersionUID = 8058099372006904458L;
protected int size;
protected int threshold;
protected float loadFactor;
protected int capMinus1;
protected HashIntrinsic(int initialCapacity, float loadFactor) {
if(initialCapacity <= 0) {
throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
} else if(!(loadFactor <= 0.0F) && !Float.isNaN(loadFactor)) {
if(initialCapacity > 1073741824) {
initialCapacity = 1073741824;
}
int capacity;
for(capacity = 1; capacity < initialCapacity; capacity <<= 1) {
}
this.capMinus1 = capacity - 1;
this.loadFactor = loadFactor;
this.threshold = (int) ((float) capacity * loadFactor);
} else {
throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
}
}
protected static int hashCodeLong(long value) {
return (int) (value ^ value >>> 32);
}
protected static int hashCodeFloat(float value) {
return floatToIntBits(value);
}
protected static int hashCodeDouble(double value) {
long bits = doubleToLongBits(value);
return (int) (bits ^ bits >>> 32);
}
public static int floatToIntBits(float value) {
int result = Float.floatToRawIntBits(value);
if((result & 2139095040) == 2139095040 && (result & 8388607) != 0) {
result = 2143289344;
}
return result;
}
public static long doubleToLongBits(double value) {
long result = Double.doubleToRawLongBits(value);
if((result & 9218868437227405312L) == 9218868437227405312L && (result & 4503599627370495L) != 0L) {
result = 9221120237041090560L;
}
return result;
}
protected static int tableIndex(int hc, int lm1) {
hc ^= hc >>> 20 ^ hc >>> 12;
hc ^= hc >>> 7 ^ hc >>> 4;
return hc & lm1;
}
public int size() {
return this.size;
}
public boolean isEmpty() {
return this.size == 0;
}
public abstract void clear();
}

View File

@@ -0,0 +1,291 @@
/*
Copyright 2009 Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
retains certain rights in this software.
BSD Open Source License.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Sandia National Laboratories nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
package com.dfsek.terra.util.hash;
import java.io.Serializable;
import java.util.NoSuchElementException;
public class HashMapDoubleDouble extends HashIntrinsic {
private static final long serialVersionUID = 2109458761298324234L;
private HashMapDoubleDouble.Entry[] table;
public HashMapDoubleDouble(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
this.table = this.createTable(this.capMinus1 + 1);
}
public HashMapDoubleDouble(int initialCapacity) {
this(initialCapacity, 0.75F);
}
public HashMapDoubleDouble() {
this(16, 0.75F);
}
public final boolean contains(double key) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if(e.key == key) {
return true;
}
}
return false;
}
public boolean containsValue(double value) {
for(int i = 0; i < this.table.length; ++i) {
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if(value == e.value) {
return true;
}
}
}
return false;
}
public double get(double key) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if(key == e.key) {
return e.value;
}
}
return 4.9E-324D;
}
public HashMapDoubleDouble.Entry getEntry(double key) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if(key == e.key) {
return e;
}
}
return null;
}
public double put(double key, double value) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if(key == e.key) {
double oldValue = e.value;
e.value = value;
return oldValue;
}
}
this.addEntry(key, value, i);
return 4.9E-324D;
}
private void addEntry(double key, double value, int index) {
HashMapDoubleDouble.Entry e = this.table[index];
this.table[index] = new HashMapDoubleDouble.Entry(key, value, e);
if(this.size++ >= this.threshold) {
this.resize(2 * this.table.length);
}
}
public void resize(int newCapacity) {
int oldCapacity = this.table.length;
if(oldCapacity == 1073741824) {
this.threshold = 2147483647;
} else {
HashMapDoubleDouble.Entry[] newTable = this.createTable(newCapacity);
this.capMinus1 = newCapacity - 1;
this.transfer(newTable);
this.table = newTable;
this.threshold = (int) ((float) newCapacity * this.loadFactor);
}
}
private void transfer(HashMapDoubleDouble.Entry[] newTable) {
for(int j = 0; j < this.table.length; ++j) {
HashMapDoubleDouble.Entry e = this.table[j];
if(e != null) {
this.table[j] = null;
HashMapDoubleDouble.Entry next;
do {
next = e.next;
int i = tableIndex(hashCodeDouble(e.key), this.capMinus1);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while(next != null);
}
}
}
public final HashMapDoubleDouble.Entry remove(double key) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
HashMapDoubleDouble.Entry prev = this.table[i];
HashMapDoubleDouble.Entry e;
HashMapDoubleDouble.Entry next;
for(e = prev; e != null; e = next) {
next = e.next;
if(key == e.key) {
--this.size;
if(prev == e) {
this.table[i] = next;
} else {
prev.next = next;
}
return e;
}
prev = e;
}
return e;
}
public void clear() {
for(int i = 0; i < this.table.length; ++i) {
this.table[i] = null;
}
this.size = 0;
}
private HashMapDoubleDouble.Entry[] createTable(int capacity) {
return new HashMapDoubleDouble.Entry[capacity];
}
public long memoryEstimate(int ptrsize) {
return (long) ptrsize * (long) (this.capMinus1 + this.size + 1) + (long) (this.size * 64 / 4);
}
public HashMapDoubleDouble.Iterator iterator() {
return new HashMapDoubleDouble.Iterator();
}
public static class Entry implements Serializable {
private static final long serialVersionUID = 7972173983741231238L;
private final double key;
private double value;
private HashMapDoubleDouble.Entry next;
public Entry(double key, double val, HashMapDoubleDouble.Entry n) {
this.key = key;
this.value = val;
this.next = n;
}
public final double getKey() {
return this.key;
}
public final double getValue() {
return this.value;
}
public final double setValue(double newValue) {
double oldValue = this.value;
this.value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
HashMapDoubleDouble.Entry e = (HashMapDoubleDouble.Entry) o;
return this.key == e.key && this.value == e.value;
}
public final String toString() {
return this.key + " = " + this.value;
}
public final int hashCode() {
return hashCodeDouble(key) + hashCodeDouble(value);
}
}
public class Iterator {
HashMapDoubleDouble.Entry next;
int index;
HashMapDoubleDouble.Entry current;
Iterator() {
if(HashMapDoubleDouble.this.size > 0) {
while(this.index < HashMapDoubleDouble.this.table.length && (this.next = HashMapDoubleDouble.this.table[this.index++]) == null) {
}
}
}
public final boolean hasNext() {
return this.next != null;
}
public HashMapDoubleDouble.Entry nextEntry() {
HashMapDoubleDouble.Entry e = this.next;
if(e == null) {
throw new NoSuchElementException();
} else {
if((this.next = e.next) == null) {
while(this.index < HashMapDoubleDouble.this.table.length && (this.next = HashMapDoubleDouble.this.table[this.index++]) == null) {
}
}
this.current = e;
return e;
}
}
public double next() {
return this.nextEntry().value;
}
public void remove() {
if(this.current == null) {
throw new IllegalStateException();
} else {
double k = this.current.key;
this.current = null;
HashMapDoubleDouble.this.remove(k);
}
}
}
}

View File

@@ -2,6 +2,7 @@ package com.dfsek.terra.util.structure;
import com.dfsek.terra.procgen.math.Vector2;
import com.dfsek.terra.structure.Rotation;
import net.jafama.FastMath;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
@@ -11,7 +12,7 @@ import org.bukkit.block.data.Rail;
import org.bukkit.block.data.Rotatable;
import org.bukkit.block.data.type.RedstoneWire;
import java.util.HashMap;
import java.util.EnumMap;
import java.util.Map;
public final class RotationUtil {
@@ -107,7 +108,7 @@ public final class RotationUtil {
* @return BlockFace represented by integer.
*/
public static BlockFace fromRotation(int r) {
switch(Math.floorMod(r, 16)) {
switch(FastMath.floorMod(r, 16)) {
case 0:
return BlockFace.NORTH;
case 1:
@@ -251,7 +252,7 @@ public final class RotationUtil {
((Directional) data).setFacing(rt);
} else if(data instanceof MultipleFacing) {
MultipleFacing mfData = (MultipleFacing) data;
Map<BlockFace, Boolean> faces = new HashMap<>();
Map<BlockFace, Boolean> faces = new EnumMap<>(BlockFace.class);
for(BlockFace f : mfData.getAllowedFaces()) {
faces.put(f, mfData.hasFace(f));
}
@@ -265,7 +266,7 @@ public final class RotationUtil {
org.bukkit.Axis newAxis = getRotatedAxis(((Orientable) data).getAxis(), r);
((Orientable) data).setAxis(newAxis);
} else if(data instanceof RedstoneWire) {
Map<BlockFace, RedstoneWire.Connection> connections = new HashMap<>();
Map<BlockFace, RedstoneWire.Connection> connections = new EnumMap<>(BlockFace.class);
RedstoneWire rData = (RedstoneWire) data;
for(BlockFace f : rData.getAllowedFaces()) {
connections.put(f, rData.getFace(f));

View File

@@ -3,6 +3,7 @@ data-save: PT6M
language: "en_us"
fail-type: SHUTDOWN
dump-default: true
cache-size: 8
biome-search-resolution: 4
cache-size: 384
master-disable:
caves: false

View File

@@ -1,3 +1,4 @@
import net.jafama.FastMath;
import org.junit.jupiter.api.Test;
import org.polydev.gaea.math.FastNoiseLite;
@@ -26,8 +27,8 @@ class DistributionTest {
long l = System.nanoTime();
for(int i = 0; i < 1000000; i++) {
double n = noise.getNoise(0, i);
max = Math.max(max, n);
min = Math.min(min, n);
max = FastMath.max(max, n);
min = FastMath.min(min, n);
numbers[normalize(n, attempts)]++;
}
long l2 = System.nanoTime() - l;
@@ -36,8 +37,8 @@ class DistributionTest {
l = System.nanoTime();
for(int i = 0; i < 1000000; i++) {
double n = noise.getNoise(0, i);
max = Math.max(max, n);
min = Math.min(min, n);
max = FastMath.max(max, n);
min = FastMath.min(min, n);
}
l2 = System.nanoTime() - l;
System.out.println("Took " + (double) l2 / 1000000 + "ms (" + ((double) l2 / 1000000) + "ns per.");
@@ -61,22 +62,22 @@ class DistributionTest {
int end = normalMap.length - 1;
while(start + 1 < end) {
int mid = start + (end - start) / 2;
if (normalMap[mid] <= d) {
if(normalMap[mid] <= d) {
start = mid;
} else {
end = mid;
}
}
double left = Math.abs(normalMap[start] - d);
double right = Math.abs(normalMap[end] - d);
if (left <= right) {
double left = FastMath.abs(normalMap[start] - d);
double right = FastMath.abs(normalMap[end] - d);
if(left <= right) {
return start * (num) / (normalMap.length);
}
return end * (num) / (normalMap.length);
}
public static int normal(double d, int max) {
double ranged = Math.max(0, Math.min((d + 1) / 2D, 1));
double ranged = FastMath.max(0, FastMath.min((d + 1) / 2D, 1));
return (int) (ranged * max);
}
}

View File

@@ -1,5 +1,7 @@
import net.jafama.FastMath;
import org.junit.jupiter.api.Test;
import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.util.GlueList;
import java.util.ArrayList;
import java.util.Collections;
@@ -12,7 +14,7 @@ class LookupGenerator {
static void main(String[] args) throws InterruptedException {
int dist = 4096;
List<Double> vals = new ArrayList<>();
List<Double> vals = new GlueList<>();
FastNoiseLite noise = new FastNoiseLite();
noise.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2);
noise.setFrequency(0.02f);
@@ -25,10 +27,10 @@ class LookupGenerator {
int workerAmount = 16;
List<Worker> workers = new ArrayList<>();
List<Worker> workers = new GlueList<>();
for(int i = 0; i < workerAmount; i++) {
workers.add(new Worker(new ArrayList<>(), 5000000, noise));
workers.add(new Worker(new GlueList<>(), 5000000, noise));
}
for(Worker w : workers) {
@@ -98,6 +100,12 @@ class LookupGenerator {
return lookup.length - 1;
}
public static int normalize(double i, int n) {
i *= 1.42; // Magic simplex value (sqrt(2) plus a little)
i = FastMath.min(FastMath.max(i, -1), 1);
return FastMath.min((int) FastMath.floor((i + 1) * ((double) n / 2)), n - 1);
}
private static class Worker extends Thread {
private final List<Double> l;
private final int searches;
@@ -120,5 +128,9 @@ class LookupGenerator {
public List<Double> getResult() {
return l;
}
public String getStatus() {
return "Generating values. " + l.size() + "/" + searches + " (" + ((long) l.size() * 100L) / searches + "%)";
}
}
}

View File

@@ -0,0 +1,52 @@
import com.dfsek.terra.generation.config.NoiseBuilder;
import com.dfsek.terra.math.NoiseFunction2;
import org.junit.jupiter.api.Test;
import parsii.eval.Expression;
import java.util.Arrays;
public class NoiseTest {
@Test
public void noise() {
NoiseFunction2 noiseFunction = new NoiseFunction2(12345, new NoiseBuilder());
System.out.println("Cache:");
int a = 0;
for(int i = 0; i < 200; i++) {
long l = System.nanoTime();
for(int j = 0; j < 1000; j++) {
for(int x = 0; x < 4; x++) {
for(int y = 0; y < 64; y++) {
for(int z = 0; z < 4; z++) {
noiseFunction.eval(Arrays.asList(get(j * 16 + (x * 4)), get(i * 16 + (z * 4))));
}
}
}
}
double n = System.nanoTime() - l;
System.out.print((long) n / 1000000 + "ms" + ((a % 10 == 0) ? "\n" : " "));
a++;
}
System.out.println();
System.out.println();
System.out.println("No Cache:");
for(int i = 0; i < 200; i++) {
long l = System.nanoTime();
for(int j = 0; j < 1000; j++) {
for(int x = 0; x < 4; x++) {
for(int y = 0; y < 64; y++) {
for(int z = 0; z < 4; z++) {
noiseFunction.evalNoCache(Arrays.asList(get(j * 16 + (x * 4)), get(i * 16 + (z * 4))));
}
}
}
}
double n = System.nanoTime() - l;
System.out.print((long) n / 1000000 + "ms" + ((a % 10 == 0) ? "\n" : " "));
a++;
}
}
private Expression get(double val) {
return () -> val;
}
}