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 committed 2020-11-24 18:35:33 -05:00
commit a73767ca75
87 files changed
+1906 -905

No files matched your search

+40
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
+1
View File
@@ -136,3 +136,4 @@ build
.idea/modules/**.iml .idea/modules/**.iml
!lib/*.jar !lib/*.jar
.idea/Terra.iml
+28 -62
View File
@@ -15,7 +15,6 @@ plugins {
} }
repositories { repositories {
mavenCentral()
flatDir { flatDir {
dirs("lib") dirs("lib")
} }
@@ -23,6 +22,7 @@ repositories {
maven { url = uri("http://maven.enginehub.org/repo/") } maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") } maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") } maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
// maven { url = uri("https://maven.pkg.github.com/solonovamax/Gaea") }
} }
java { java {
@@ -30,49 +30,36 @@ java {
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
val versionObj = Version("1", "3", "1", true) val versionObj = Version("1", "5", "0", true)
version = versionObj version = versionObj
dependencies { dependencies {
val gaeaVersion = "1.14.3"
// 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"
compileOnly(name = "Gaea-${gaeaVersion}", group = "") compileOnly(name = "Gaea-${gaeaVersion}", group = "")
testImplementation(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") 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") 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") testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine: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 val compileJava: JavaCompile by tasks
@@ -81,6 +68,7 @@ val mainSourceSet: SourceSet = sourceSets["main"]
val tokenizeJavaSources = task<Copy>(name = "tokenizeJavaSources") { val tokenizeJavaSources = task<Copy>(name = "tokenizeJavaSources") {
from(mainSourceSet.allSource) { from(mainSourceSet.allSource) {
include("**/plugin.yml") include("**/plugin.yml")
println("version: $versionObj")
val tokens = mapOf("VERSION" to versionObj.toString()) val tokens = mapOf("VERSION" to versionObj.toString())
filter(org.apache.tools.ant.filters.ReplaceTokens::class, "tokens" to tokens) 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("org.bstats.bukkit", "com.dfsek.terra.lib.bstats")
relocate("parsii", "com.dfsek.terra.lib.parsii") relocate("parsii", "com.dfsek.terra.lib.parsii")
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib") relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
relocate("net.jafama", "com.dfsek.terra.lib.jafama")
minimize()
} }
tasks.build { tasks.build {
@@ -204,31 +194,13 @@ val testWithPaper = task<JavaExec>(name = "testWithPaper") {
classpath = files("${testDir}/paper.jar") 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. * Version class that does version stuff.
*/ */
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
class Version(val major: String, val minor: String, val revision: String, val preRelease: Boolean = false) { class Version(val major: String, val minor: String, val revision: String, val preRelease: Boolean = false) {
override fun toString(): String { override fun toString(): String {
return if (!preRelease) return if (!preRelease)
"$major.$minor.$revision" "$major.$minor.$revision"
@@ -239,25 +211,19 @@ class Version(val major: String, val minor: String, val revision: String, val pr
fun getGitHash(): String { fun getGitHash(): String {
val stdout = ByteArrayOutputStream() val stdout = ByteArrayOutputStream()
val exitCode = exec { exec {
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD") commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
standardOutput = stdout 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() return stdout.toString().trim()
} }
fun gitClone(name: String) { fun gitClone(name: String) {
val stdout = ByteArrayOutputStream() val stdout = ByteArrayOutputStream()
val result = exec { exec {
commandLine = mutableListOf("git", "clone", name) commandLine = mutableListOf("git", "clone", name)
standardOutput = stdout 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) { fun downloadAndUnzipPack(packUrl: URL) {
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,6 +2,7 @@ package com.dfsek.terra;
import com.dfsek.terra.async.AsyncStructureFinder; import com.dfsek.terra.async.AsyncStructureFinder;
import com.dfsek.terra.config.base.ConfigPack; 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.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.registry.TreeRegistry; import com.dfsek.terra.registry.TreeRegistry;
import com.dfsek.terra.util.StructureTypeEnum; 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.GaeaPlugin;
import org.polydev.gaea.tree.Tree; import org.polydev.gaea.tree.Tree;
import org.polydev.gaea.tree.TreeType; import org.polydev.gaea.tree.TreeType;
import org.polydev.gaea.util.FastRandom;
import java.util.Random;
public class EventListener implements Listener { public class EventListener implements Listener {
private final GaeaPlugin main; private final GaeaPlugin main;
@@ -80,6 +80,10 @@ public class EventListener implements Listener {
TreeRegistry registry = c.getTreeRegistry(); TreeRegistry registry = c.getTreeRegistry();
Tree tree = registry.get(TreeType.fromBukkit(e.getSpecies()).toString()); Tree tree = registry.get(TreeType.fromBukkit(e.getSpecies()).toString());
Debug.info("Overriding tree type: " + e.getSpecies()); 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);
} }
} }
@@ -16,12 +16,12 @@ public class TerraProfiler extends WorldProfiler {
super(w); super(w);
this this
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime") .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), "OreTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "CaveTime") .addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "CaveTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime") .addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "ElevationTime") .addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "ElevationTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "SnowTime") .addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "SnowTime");
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "CaveBlockUpdate");
} }
public static TerraProfiler fromWorld(World w) { public static TerraProfiler fromWorld(World w) {
+12 -12
View File
@@ -24,14 +24,6 @@ public class TerraWorld {
private final WorldConfig worldConfig; private final WorldConfig worldConfig;
private boolean safe; 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) { private TerraWorld(World w) {
safe = true; safe = true;
worldConfig = loaded.get(w.getName()); worldConfig = loaded.get(w.getName());
@@ -87,6 +79,14 @@ public class TerraWorld {
grid = new TerraBiomeGrid(w, config.freq1, config.freq2, zone, config, erosion); 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() { public static synchronized void invalidate() {
map.clear(); map.clear();
for(WorldConfig config : loaded.values()) { for(WorldConfig config : loaded.values()) {
@@ -98,6 +98,10 @@ public class TerraWorld {
return map.size(); return map.size();
} }
public static boolean isTerraWorld(World w) {
return w.getGenerator() instanceof TerraChunkGenerator;
}
public TerraBiomeGrid getGrid() { public TerraBiomeGrid getGrid() {
return grid; return grid;
} }
@@ -117,8 +121,4 @@ public class TerraWorld {
public boolean isSafe() { public boolean isSafe() {
return safe; return safe;
} }
public static boolean isTerraWorld(World w) {
return w.getGenerator() instanceof TerraChunkGenerator;
}
} }
@@ -1,6 +1,7 @@
package com.dfsek.terra.async; package com.dfsek.terra.async;
import com.dfsek.terra.biome.grid.TerraBiomeGrid; import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import com.dfsek.terra.config.base.ConfigUtil;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -27,11 +28,11 @@ public class AsyncBiomeFinder extends AsyncFeatureFinder<Biome> {
*/ */
@Override @Override
public boolean isValid(int x, int z, Biome target) { 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 @Override
public Vector finalizeVector(Vector orig) { public Vector finalizeVector(Vector orig) {
return orig; return orig.multiply(ConfigUtil.biomeSearchRes);
} }
} }
@@ -1,6 +1,5 @@
package com.dfsek.terra.async; package com.dfsek.terra.async;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.grid.TerraBiomeGrid; import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import com.dfsek.terra.config.genconfig.structure.StructureConfig; import com.dfsek.terra.config.genconfig.structure.StructureConfig;
@@ -10,6 +9,7 @@ import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.util.FastRandom;
import java.util.Random; import java.util.Random;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -33,9 +33,9 @@ public class AsyncStructureFinder extends AsyncFeatureFinder<StructureConfig> {
public boolean isValid(int x, int z, StructureConfig target) { public boolean isValid(int x, int z, StructureConfig target) {
World world = getWorld(); World world = getWorld();
Location spawn = target.getSpawn().getChunkSpawn(x, z, world.getSeed()).toLocation(world); 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; return false;
Random r2 = new Random(spawn.hashCode()); Random r2 = new FastRandom(spawn.hashCode());
Structure struc = target.getStructure(r2); Structure struc = target.getStructure(r2);
Rotation rotation = Rotation.fromDegrees(r2.nextInt(4) * 90); Rotation rotation = Rotation.fromDegrees(r2.nextInt(4) * 90);
for(int y = target.getSearchStart().get(r2); y > 0; y--) { for(int y = target.getSearchStart().get(r2); y > 0; y--) {
@@ -1,7 +1,9 @@
package com.dfsek.terra.biome; 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.UserDefinedDecorator;
import com.dfsek.terra.generation.UserDefinedGenerator; import org.bukkit.World;
import org.polydev.gaea.biome.Biome; import org.polydev.gaea.biome.Biome;
import org.polydev.gaea.biome.Decorator; import org.polydev.gaea.biome.Decorator;
import org.polydev.gaea.biome.Generator; import org.polydev.gaea.biome.Generator;
@@ -13,19 +15,21 @@ import java.util.List;
* Class representing a config-defined biome * Class representing a config-defined biome
*/ */
public class UserDefinedBiome implements Biome { public class UserDefinedBiome implements Biome {
private final UserDefinedGenerator gen; private final GeneratorOptions gen;
private final UserDefinedDecorator decorator; private final UserDefinedDecorator decorator;
private final org.bukkit.block.Biome vanilla; private final org.bukkit.block.Biome vanilla;
private final String id; private final String id;
private final BiomeConfig config;
private final boolean erode; 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.vanilla = vanilla;
this.decorator = dec; this.decorator = dec;
this.gen = gen; this.gen = gen;
this.id = id; this.id = config.getID();
this.erode = erode; this.erode = erode;
this.config = config;
} }
/** /**
@@ -45,7 +49,7 @@ public class UserDefinedBiome implements Biome {
*/ */
@Override @Override
public Generator getGenerator() { public Generator getGenerator() {
return gen; return gen.getGenerator(0);
} }
/** /**
@@ -75,4 +79,13 @@ public class UserDefinedBiome implements Biome {
public boolean isErodible() { public boolean isErodible() {
return erode; return erode;
} }
public BiomeConfig getConfig() {
return config;
}
@Override
public Generator getGenerator(World w) {
return gen.getGenerator(w.getSeed());
}
} }
@@ -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();
}
@@ -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");
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -57,7 +57,7 @@ public class TerraBiomeGrid extends BiomeGrid {
if(failNum % 256 == 0) if(failNum % 256 == 0)
LangUtil.log("error.severe-config", Level.SEVERE, String.valueOf(x), String.valueOf(z)); LangUtil.log("error.severe-config", Level.SEVERE, String.valueOf(x), String.valueOf(z));
failNum++; failNum++;
return ConfigUtil.failType.fail(); return null;
} }
if(erode != null && b.isErodible() && erode.isEroded(xp, zp)) { if(erode != null && b.isErodible() && erode.isEroded(xp, zp)) {
return erosionGrid.getBiome(xp, zp, phase); return erosionGrid.getBiome(xp, zp, phase);
@@ -1,5 +1,6 @@
package com.dfsek.terra.biome.postprocessing; package com.dfsek.terra.biome.postprocessing;
import net.jafama.FastMath;
import org.polydev.gaea.math.FastNoiseLite; import org.polydev.gaea.math.FastNoiseLite;
/** /**
@@ -27,7 +28,7 @@ public class ErosionNoise {
* @return Whether location is eroded * @return Whether location is eroded
*/ */
public boolean isEroded(int x, int z) { 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; return abs < thresh;
} }
} }
@@ -9,6 +9,7 @@ import org.bukkit.World;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.polydev.gaea.math.FastNoiseLite; import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.MathUtil; import org.polydev.gaea.math.MathUtil;
import org.polydev.gaea.util.FastRandom;
import java.util.Random; import java.util.Random;
@@ -23,7 +24,7 @@ public class Cavern {
public VoxelGeometry carveChunk(int chunkX, int chunkZ) { public VoxelGeometry carveChunk(int chunkX, int chunkZ) {
long seedC = MathUtil.getCarverChunkSeed(chunkX, chunkZ, seed); 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)); Vector org = node.getNodeLocation((chunkX << 4) + 8, (chunkZ << 4) + 8).clone().setY(chunk.nextInt(128));
VoxelGeometry carve = VoxelGeometry.getBlank(); VoxelGeometry carve = VoxelGeometry.getBlank();
@@ -33,7 +34,7 @@ public class Cavern {
Bukkit.getLogger().info("Cavern: " + org.toString()); Bukkit.getLogger().info("Cavern: " + org.toString());
carve.merge(new DeformedSphere(org.clone(), chunk.nextInt(4) + 3, 0.75, smpl)); 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)); carve.merge(new Tube(org, _00, 4));
return carve; return carve;
@@ -1,5 +1,6 @@
package com.dfsek.terra.carving; package com.dfsek.terra.carving;
import net.jafama.FastMath;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.polydev.gaea.math.FastNoiseLite; import org.polydev.gaea.math.FastNoiseLite;
@@ -15,7 +16,7 @@ public class SimplexCarver extends Carver {
private final FastNoiseLite height; private final FastNoiseLite height;
private final FastNoiseLite column; private final FastNoiseLite column;
private final FastNoiseLite hasCaves; 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) { public SimplexCarver(int minY, int maxY) {
super(minY, maxY); super(minY, maxY);
@@ -40,6 +41,10 @@ public class SimplexCarver extends Carver {
hasCaves.setFrequency(0.005f); hasCaves.setFrequency(0.005f);
} }
private static double acot(double x) {
return FastMath.PI / 2 - FastMath.atan(x);
}
@Override @Override
public CarvingData carve(int chunkX, int chunkZ, World w) { public CarvingData carve(int chunkX, int chunkZ, World w) {
CarvingData c = new CarvingData(chunkX, chunkZ); CarvingData c = new CarvingData(chunkX, chunkZ);
@@ -49,15 +54,15 @@ public class SimplexCarver extends Carver {
for(int z = oz; z < oz + 16; z++) { for(int z = oz; z < oz + 16; z++) {
double heightNoise = height.getNoise(x, z); double heightNoise = height.getNoise(x, z);
double mainNoise = noise.getNoise(x, z) * 2; double mainNoise = noise.getNoise(x, z) * 2;
double columnNoise = Math.pow(Math.max(column.getNoise(x, z), 0) * 2, 3); double columnNoise = FastMath.pow(FastMath.max(column.getNoise(x, z), 0) * 2, 3);
double hc = (acot(16 * (hasCaves.getNoise(x, z) - 0.2)) / Math.PI) - 0.1; double hc = (acot(16 * (hasCaves.getNoise(x, z) - 0.2)) / FastMath.PI) - 0.1;
CarvingData.CarvingType type = CarvingData.CarvingType.BOTTOM; 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++) { 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) { if(finalNoise > 0.5) {
c.carve(x - ox, y, z - oz, type); 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) { if(finalNoiseUp > 0.5) {
type = CarvingData.CarvingType.CENTER; type = CarvingData.CarvingType.CENTER;
} else type = CarvingData.CarvingType.TOP; } else type = CarvingData.CarvingType.TOP;
@@ -68,10 +73,6 @@ public class SimplexCarver extends Carver {
return c; return c;
} }
private static double acot(double x) {
return Math.PI / 2 - Math.atan(x);
}
@Override @Override
public Worm getWorm(long l, Vector vector) { public Worm getWorm(long l, Vector vector) {
return null; return null;
@@ -3,10 +3,12 @@ package com.dfsek.terra.carving;
import com.dfsek.terra.TerraWorld; import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.base.ConfigPack; import com.dfsek.terra.config.base.ConfigPack;
import net.jafama.FastMath;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.math.Range; 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.Carver;
import org.polydev.gaea.world.carving.Worm; import org.polydev.gaea.world.carving.Worm;
@@ -39,7 +41,7 @@ public class UserDefinedCarver extends Carver {
@Override @Override
public Worm getWorm(long l, Vector vector) { 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); return new UserDefinedWorm(length.get(r) / 2, r, vector, radius.getMax(), topCut, bottomCut);
} }
@@ -58,7 +60,7 @@ public class UserDefinedCarver extends Carver {
@Override @Override
public boolean isChunkCarved(World w, int chunkX, int chunkZ, Random random) { public boolean isChunkCarved(World w, int chunkX, int chunkZ, Random random) {
ConfigPack c = TerraWorld.getWorld(w).getConfig(); 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 { private class UserDefinedWorm extends Worm {
@@ -81,9 +83,9 @@ public class UserDefinedCarver extends Carver {
@Override @Override
public void step() { public void step() {
if(steps == nextDirection) { if(steps == nextDirection) {
direction.rotateAroundX(Math.toRadians((getRandom().nextGaussian()) * mutate[0] * recalcMagnitude)); direction.rotateAroundX(FastMath.toRadians((getRandom().nextGaussian()) * mutate[0] * recalcMagnitude));
direction.rotateAroundY(Math.toRadians((getRandom().nextGaussian()) * mutate[1] * recalcMagnitude)); direction.rotateAroundY(FastMath.toRadians((getRandom().nextGaussian()) * mutate[1] * recalcMagnitude));
direction.rotateAroundZ(Math.toRadians((getRandom().nextGaussian()) * mutate[2] * recalcMagnitude)); direction.rotateAroundZ(FastMath.toRadians((getRandom().nextGaussian()) * mutate[2] * recalcMagnitude));
currentRotation = new double[] {(getRandom().nextGaussian()) * mutate[0], currentRotation = new double[] {(getRandom().nextGaussian()) * mutate[0],
(getRandom().nextGaussian()) * mutate[1], (getRandom().nextGaussian()) * mutate[1],
(getRandom().nextGaussian()) * mutate[2]}; (getRandom().nextGaussian()) * mutate[2]};
@@ -92,10 +94,10 @@ public class UserDefinedCarver extends Carver {
steps++; steps++;
setRadius(new int[] {(int) (runningRadius * radiusMultiplier[0]), (int) (runningRadius * radiusMultiplier[1]), (int) (runningRadius * radiusMultiplier[2])}); setRadius(new int[] {(int) (runningRadius * radiusMultiplier[0]), (int) (runningRadius * radiusMultiplier[1]), (int) (runningRadius * radiusMultiplier[2])});
runningRadius += (getRandom().nextDouble() - 0.5) * mutate[3]; runningRadius += (getRandom().nextDouble() - 0.5) * mutate[3];
runningRadius = Math.max(Math.min(runningRadius, maxRad), 1); runningRadius = FastMath.max(FastMath.min(runningRadius, maxRad), 1);
direction.rotateAroundX(Math.toRadians(currentRotation[0] * mutate[0])); direction.rotateAroundX(FastMath.toRadians(currentRotation[0] * mutate[0]));
direction.rotateAroundY(Math.toRadians(currentRotation[1] * mutate[1])); direction.rotateAroundY(FastMath.toRadians(currentRotation[1] * mutate[1]));
direction.rotateAroundZ(Math.toRadians(currentRotation[2] * mutate[2])); direction.rotateAroundZ(FastMath.toRadians(currentRotation[2] * mutate[2]));
getRunning().add(direction); getRunning().add(direction);
} }
} }
@@ -3,6 +3,7 @@ package com.dfsek.terra.command;
import com.dfsek.terra.TerraWorld; import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.config.genconfig.OreConfig; import com.dfsek.terra.config.genconfig.OreConfig;
import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.lang.LangUtil;
import net.jafama.FastMath;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@@ -11,10 +12,10 @@ import org.bukkit.entity.Player;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.command.WorldCommand; import org.polydev.gaea.command.WorldCommand;
import org.polydev.gaea.util.FastRandom;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random;
public class OreCommand extends WorldCommand { public class OreCommand extends WorldCommand {
public OreCommand(org.polydev.gaea.command.Command parent) { 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); LangUtil.send("command.ore.out-of-range", sender);
return true; return true;
} }
Vector source = new Vector(Math.floorMod(bl.getX(), 16), bl.getY(), Math.floorMod(bl.getZ(), 16)); Vector source = new Vector(FastMath.floorMod(bl.getX(), 16), bl.getY(), FastMath.floorMod(bl.getZ(), 16));
ore.doVein(source, bl.getChunk(), new Random()); ore.doVein(source, bl.getChunk(), new FastRandom());
} else { } else {
LangUtil.send("command.ore.main-menu", sender); LangUtil.send("command.ore.main-menu", sender);
} }
@@ -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) { public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args, World w) {
TerraBiomeGrid grid = TerraWorld.getWorld(sender.getWorld()).getGrid(); TerraBiomeGrid grid = TerraWorld.getWorld(sender.getWorld()).getGrid();
UserDefinedBiome biome = (UserDefinedBiome) grid.getBiome(sender.getLocation(), GenerationPhase.POPULATE); 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; return true;
} }
@@ -40,7 +40,7 @@ public class BiomeInfoCommand extends WorldCommand {
sender.sendMessage("Erodible: " + b.isErodible()); sender.sendMessage("Erodible: " + b.isErodible());
BiomeConfig bio = cfg.getBiome(b); BiomeConfig bio = b.getConfig();
List<StructureConfig> structureConfigs = bio.getStructures(); List<StructureConfig> structureConfigs = bio.getStructures();
if(structureConfigs.size() == 0) sender.sendMessage("No Structures"); if(structureConfigs.size() == 0) sender.sendMessage("No Structures");
@@ -1,5 +1,6 @@
package com.dfsek.terra.command.structure; package com.dfsek.terra.command.structure;
import com.dfsek.terra.command.structure.load.LoadCommand;
import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.lang.LangUtil;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@@ -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;
}
}
@@ -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.Terra;
import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.lang.LangUtil;
@@ -15,14 +15,19 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class LoadCommand extends PlayerCommand implements DebugCommand { public class LoadFullCommand extends PlayerCommand implements DebugCommand {
public LoadCommand(org.polydev.gaea.command.Command parent) { private final boolean chunk;
public LoadFullCommand(org.polydev.gaea.command.Command parent, boolean chunk) {
super(parent); super(parent);
this.chunk = chunk;
} }
@Override @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 { try {
Rotation r; Rotation r;
try { try {
@@ -32,8 +37,8 @@ public class LoadCommand extends PlayerCommand implements DebugCommand {
return true; return true;
} }
Structure struc = Structure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", args[0] + ".tstructure")); 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); if(chunk) struc.paste(sender.getLocation(), sender.getLocation().getChunk(), r);
else struc.paste(sender.getLocation(), sender.getLocation().getChunk(), r); else struc.paste(sender.getLocation(), r);
//sender.sendMessage(String.valueOf(struc.checkSpawns(sender.getLocation(), r))); //sender.sendMessage(String.valueOf(struc.checkSpawns(sender.getLocation(), r)));
} catch(IOException e) { } catch(IOException e) {
e.printStackTrace(); e.printStackTrace();
@@ -44,7 +49,7 @@ public class LoadCommand extends PlayerCommand implements DebugCommand {
@Override @Override
public String getName() { public String getName() {
return "load"; return chunk ? "chunk" : "full";
} }
@Override @Override
@@ -54,11 +59,17 @@ public class LoadCommand extends PlayerCommand implements DebugCommand {
@Override @Override
public int arguments() { public int arguments() {
return 3; return 2;
} }
@Override @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(); return Collections.emptyList();
} }
} }
@@ -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();
}
}
@@ -2,7 +2,6 @@ package com.dfsek.terra.config.base;
import com.dfsek.terra.Debug; import com.dfsek.terra.Debug;
import com.dfsek.terra.Terra; import com.dfsek.terra.Terra;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.carving.UserDefinedCarver; import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.ConfigLoader; import com.dfsek.terra.config.ConfigLoader;
import com.dfsek.terra.config.exception.ConfigException; 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.TreeConfig;
import com.dfsek.terra.config.genconfig.biome.AbstractBiomeConfig; import com.dfsek.terra.config.genconfig.biome.AbstractBiomeConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig; 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.genconfig.structure.StructureConfig;
import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.registry.FloraRegistry; import com.dfsek.terra.registry.FloraRegistry;
@@ -24,6 +24,7 @@ import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import parsii.eval.Scope;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -56,8 +57,6 @@ public class ConfigPack extends YamlConfiguration {
public final int blendAmp; public final int blendAmp;
public final boolean biomeBlend; public final boolean biomeBlend;
public final double blendFreq; public final double blendFreq;
public final int octaves;
public final double frequency;
public final boolean vanillaCaves; public final boolean vanillaCaves;
public final boolean vanillaStructures; public final boolean vanillaStructures;
public final boolean vanillaDecoration; public final boolean vanillaDecoration;
@@ -75,7 +74,8 @@ public class ConfigPack extends YamlConfiguration {
private final TreeRegistry treeRegistry = new TreeRegistry(); private final TreeRegistry treeRegistry = new TreeRegistry();
private final FloraRegistry floraRegistry = new FloraRegistry(); private final FloraRegistry floraRegistry = new FloraRegistry();
private final Set<StructureConfig> allStructures = new HashSet<>(); 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 File dataFolder;
private final String id; private final String id;
@@ -87,6 +87,13 @@ public class ConfigPack extends YamlConfiguration {
if(!contains("id")) throw new ConfigException("No ID specified!", "null"); if(!contains("id")) throw new ConfigException("No ID specified!", "null");
this.id = getString("id"); 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); ores = ConfigLoader.load(new File(file, "ores").toPath(), this, OreConfig.class);
palettes = ConfigLoader.load(new File(file, "palettes").toPath(), this, PaletteConfig.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()); Debug.info("Overriding Vanilla tree: " + entry.getKey());
} }
vScope = new Scope();
if(contains("variables")) { if(contains("variables")) {
Map<String, Object> vars = Objects.requireNonNull(getConfigurationSection("variables")).getValues(false); Map<String, Object> vars = Objects.requireNonNull(getConfigurationSection("variables")).getValues(false);
for(Map.Entry<String, Object> entry : vars.entrySet()) { for(Map.Entry<String, Object> entry : vars.entrySet()) {
try { 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()); Debug.info("Registered variable " + entry.getKey() + " with value " + entry.getValue());
} catch(ClassCastException | NumberFormatException e) { } catch(ClassCastException | NumberFormatException e) {
Debug.stack(e); Debug.stack(e);
@@ -141,9 +149,6 @@ public class ConfigPack extends YamlConfiguration {
erosionThresh = getDouble("erode.threshold", 0.04); erosionThresh = getDouble("erode.threshold", 0.04);
erosionOctaves = getInt("erode.octaves", 3); erosionOctaves = getInt("erode.octaves", 3);
octaves = getInt("noise.octaves", 4);
frequency = getDouble("noise.frequency", 1f / 96);
erosionName = getString("erode.grid"); erosionName = getString("erode.grid");
vanillaCaves = getBoolean("vanilla.caves", false); 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)); 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) { public static synchronized void loadAll(JavaPlugin main) {
configs.clear(); configs.clear();
File file = new File(main.getDataFolder(), "packs"); File file = new File(main.getDataFolder(), "packs");
@@ -244,6 +229,30 @@ public class ConfigPack extends YamlConfiguration {
return configs.get(id); 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() { public Map<StructureTypeEnum, StructureConfig> getLocatable() {
return locatable; return locatable;
} }
@@ -264,13 +273,6 @@ public class ConfigPack extends YamlConfiguration {
return dataFolder; 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) { public BiomeConfig getBiome(String id) {
return biomes.get(id); return biomes.get(id);
} }
@@ -3,7 +3,6 @@ package com.dfsek.terra.config.base;
import com.dfsek.terra.Debug; import com.dfsek.terra.Debug;
import com.dfsek.terra.Terra; import com.dfsek.terra.Terra;
import com.dfsek.terra.TerraWorld; import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.failsafe.FailType;
import com.dfsek.terra.config.exception.ConfigException; import com.dfsek.terra.config.exception.ConfigException;
import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.util.TagUtil; import com.dfsek.terra.util.TagUtil;
@@ -18,20 +17,19 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.time.Duration; import java.time.Duration;
import java.util.HashSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
public final class ConfigUtil { public final class ConfigUtil {
public static boolean debug; public static boolean debug;
public static long dataSave; // Period of population data saving, in ticks. public static long dataSave; // Period of population data saving, in ticks.
public static boolean masterDisableCaves; public static boolean masterDisableCaves;
public static int biomeSearchRes;
public static int cacheSize; public static int cacheSize;
public static FailType failType;
public static void loadConfig(JavaPlugin main) { public static void loadConfig(JavaPlugin main) {
main.saveDefaultConfig(); main.saveDefaultConfig();
@@ -40,9 +38,10 @@ public final class ConfigUtil {
LangUtil.load(config.getString("language", "en_us"), main); LangUtil.load(config.getString("language", "en_us"), main);
debug = config.getBoolean("debug", false); debug = config.getBoolean("debug", false);
cacheSize = config.getInt("cache-size", 3);
dataSave = Duration.parse(Objects.requireNonNull(config.getString("data-save", "PT6M"))).toMillis() / 20L; dataSave = Duration.parse(Objects.requireNonNull(config.getString("data-save", "PT6M"))).toMillis() / 20L;
masterDisableCaves = config.getBoolean("master-disable.caves", false); 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)) { if(config.getBoolean("dump-default", true)) {
try(JarFile jar = new JarFile(new File(Terra.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) { 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 logger = main.getLogger();
logger.info("Loading config values"); 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 { 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) { for(String s : list) {
try { try {
if(s.startsWith("#")) { if(s.startsWith("#")) {
@@ -42,7 +42,7 @@ public class WorldConfig {
FileConfiguration config = new YamlConfiguration(); FileConfiguration config = new YamlConfiguration();
Debug.info("Loading config " + configID + " for world " + worldID); Debug.info("Loading config " + configID + " for world " + worldID);
try { // Load/create world config file 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); throw new ConfigException("Config pack unspecified in bukkit.yml!", worldID);
File configFile = new File(main.getDataFolder() + File.separator + "worlds", worldID + ".yml"); File configFile = new File(main.getDataFolder() + File.separator + "worlds", worldID + ".yml");
if(!configFile.exists()) { if(!configFile.exists()) {
@@ -15,8 +15,8 @@ import org.polydev.gaea.math.Range;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@@ -45,8 +45,9 @@ public class CarverConfig extends TerraConfig {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public CarverConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException { public CarverConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException {
super(file, config); super(file, config);
if(!yaml.contains("id")) throw new ConfigException("No ID specified for Carver!", "null"); load(file);
id = Objects.requireNonNull(yaml.getString("id")); if(!contains("id")) throw new ConfigException("No ID specified for Carver!", "null");
id = Objects.requireNonNull(getString("id"));
inner = getBlocks("palette.inner.layers"); inner = getBlocks("palette.inner.layers");
@@ -56,24 +57,24 @@ public class CarverConfig extends TerraConfig {
bottom = getBlocks("palette.bottom.layers"); 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); double step = getDouble("step", 2);
Range recalc = new Range(yaml.getInt("recalculate-direction.min", 8), yaml.getInt("recalculate-direction.max", 12)); Range recalc = new Range(getInt("recalculate-direction.min", 8), getInt("recalculate-direction.max", 12));
double rm = yaml.getDouble("recalculate-magnitude", 4); double rm = getDouble("recalculate-magnitude", 4);
shift = new HashMap<>(); shift = new HashMap<>();
for(Map.Entry<String, Object> e : Objects.requireNonNull(yaml.getConfigurationSection("shift")).getValues(false).entrySet()) { for(Map.Entry<String, Object> e : Objects.requireNonNull(getConfigurationSection("shift")).getValues(false).entrySet()) {
Set<Material> l = new HashSet<>(); Set<Material> l = EnumSet.noneOf(Material.class);
for(String s : (List<String>) e.getValue()) { for(String s : (List<String>) e.getValue()) {
l.add(Bukkit.createBlockData(s).getMaterial()); l.add(Bukkit.createBlockData(s).getMaterial());
Debug.info("Added " + s + " to shift-able blocks"); 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"); Debug.info("Added " + e.getKey() + " as master block");
} }
replaceIsBlacklistInner = yaml.getBoolean("palette.inner.replace-blacklist", false); replaceIsBlacklistInner = getBoolean("palette.inner.replace-blacklist", false);
replaceIsBlacklistOuter = yaml.getBoolean("palette.outer.replace-blacklist", false); replaceIsBlacklistOuter = getBoolean("palette.outer.replace-blacklist", false);
replaceIsBlacklistTop = yaml.getBoolean("palette.top.replace-blacklist", false); replaceIsBlacklistTop = getBoolean("palette.top.replace-blacklist", false);
replaceIsBlacklistBottom = yaml.getBoolean("palette.bottom.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[] start = new double[] {getDouble("start.x"), getDouble("start.y"), getDouble("start.z")};
double[] mutate = new double[] {yaml.getDouble("mutate.x"), yaml.getDouble("mutate.y"), yaml.getDouble("mutate.z"), yaml.getDouble("mutate.radius")}; double[] mutate = new double[] {getDouble("mutate.x"), getDouble("mutate.y"), getDouble("mutate.z"), 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")}; double[] radiusMultiplier = new double[] {getDouble("start.radius.multiply.x"), getDouble("start.radius.multiply.y"), getDouble("start.radius.multiply.z")};
Range length = new Range(yaml.getInt("length.min"), yaml.getInt("length.max")); Range length = new Range(getInt("length.min"), getInt("length.max"));
Range radius = new Range(yaml.getInt("start.radius.min"), yaml.getInt("start.radius.max")); Range radius = new Range(getInt("start.radius.min"), getInt("start.radius.max"));
Range height = new Range(yaml.getInt("start.height.min"), yaml.getInt("start.height.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.setStep(step);
carver.setRecalc(recalc); carver.setRecalc(recalc);
carver.setRecalcMagnitude(rm); carver.setRecalcMagnitude(rm);
@@ -102,9 +103,9 @@ public class CarverConfig extends TerraConfig {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Map<Integer, ProbabilityCollection<BlockData>> getBlocks(String key) throws InvalidConfigurationException { 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<>(); Map<Integer, ProbabilityCollection<BlockData>> result = new TreeMap<>();
for(Map<?, ?> m : yaml.getMapList(key)) { for(Map<?, ?> m : getMapList(key)) {
try { try {
ProbabilityCollection<BlockData> layer = new ProbabilityCollection<>(); ProbabilityCollection<BlockData> layer = new ProbabilityCollection<>();
for(Map.Entry<String, Integer> type : ((Map<String, Integer>) m.get("materials")).entrySet()) { for(Map.Entry<String, Integer> type : ((Map<String, Integer>) m.get("materials")).entrySet()) {
@@ -4,6 +4,7 @@ import com.dfsek.terra.config.TerraConfig;
import com.dfsek.terra.config.base.ConfigPack; import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigUtil; import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.exception.ConfigException; import com.dfsek.terra.config.exception.ConfigException;
import net.jafama.FastMath;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@@ -12,6 +13,7 @@ import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.polydev.gaea.math.Range; import org.polydev.gaea.math.Range;
import org.polydev.gaea.util.FastRandom;
import org.polydev.gaea.world.Flora; import org.polydev.gaea.world.Flora;
import org.polydev.gaea.world.palette.Palette; import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette; import org.polydev.gaea.world.palette.RandomPalette;
@@ -20,7 +22,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.Set; import java.util.Set;
public class FloraConfig extends TerraConfig implements Flora { 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 { public FloraConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException {
super(file, config); super(file, config);
if(!yaml.contains("id")) throw new ConfigException("Flora ID unspecified!", "null"); load(file);
this.id = yaml.getString("id"); if(!contains("id")) throw new ConfigException("Flora ID unspecified!", "null");
if(!yaml.contains("layers")) throw new ConfigException("No blocks defined in custom flora!", getID()); this.id = getString("id");
if(!yaml.contains("spawnable")) throw new ConfigException("Flora spawnable blocks unspecified!", getID()); 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()); spawnable = ConfigUtil.toBlockData(getStringList("spawnable"), "spawnable", getID());
replaceable = ConfigUtil.toBlockData(yaml.getStringList("replaceable"), "replaceable", getID()); replaceable = ConfigUtil.toBlockData(getStringList("replaceable"), "replaceable", getID());
if(yaml.contains("irrigable")) { if(contains("irrigable")) {
irrigable = ConfigUtil.toBlockData(yaml.getStringList("irrigable"), "irrigable", getID()); irrigable = ConfigUtil.toBlockData(getStringList("irrigable"), "irrigable", getID());
} else irrigable = null; } else irrigable = null;
physics = yaml.getBoolean("physics", false); physics = getBoolean("physics", false);
ceiling = yaml.getBoolean("ceiling", 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() { public String getID() {
@@ -62,26 +64,28 @@ public class FloraConfig extends TerraConfig implements Flora {
@Override @Override
public List<Block> getValidSpawnsAt(Chunk chunk, int x, int z, Range range) { 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<>(); List<Block> blocks = new ArrayList<>();
if(ceiling) for(int y : range) { for(int y : range) {
if(y > 255 || y < 1) continue; if(y > 255 || y < 0) continue;
Block check = chunk.getBlock(x, y, z); current = current.getRelative(BlockFace.UP);
Block other = check.getRelative(BlockFace.DOWN); if(spawnable.contains(current.getType()) && isIrrigated(current) && valid(size, current)) {
if(spawnable.contains(check.getType()) && replaceable.contains(other.getType())) { blocks.add(current);
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);
} }
} }
return blocks; 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) { private boolean isIrrigated(Block b) {
if(irrigable == null) return true; if(irrigable == null) return true;
return irrigable.contains(b.getRelative(BlockFace.NORTH).getType()) return irrigable.contains(b.getRelative(BlockFace.NORTH).getType())
@@ -94,12 +98,8 @@ public class FloraConfig extends TerraConfig implements Flora {
public boolean plant(Location location) { public boolean plant(Location location) {
int size = floraPalette.getSize(); int size = floraPalette.getSize();
int c = ceiling ? -1 : 1; int c = ceiling ? -1 : 1;
for(int i = 0; Math.abs(i) < size; i += c) { // Down if ceiling, up if floor for(int i = 0; FastMath.abs(i) < size; i += c) { // Down if ceiling, up if floor
if(i + 1 > 255) return false; int lvl = (FastMath.abs(i));
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));
location.clone().add(0, i + c, 0).getBlock().setBlockData(floraPalette.get((ceiling ? lvl : size - lvl - 1), location.getBlockX(), location.getBlockZ()), physics); location.clone().add(0, i + c, 0).getBlock().setBlockData(floraPalette.get((ceiling ? lvl : size - lvl - 1), location.getBlockX(), location.getBlockZ()), physics);
} }
return true; return true;
@@ -4,6 +4,7 @@ import com.dfsek.terra.config.TerraConfig;
import com.dfsek.terra.config.base.ConfigPack; import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigUtil; import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.exception.ConfigException; import com.dfsek.terra.config.exception.ConfigException;
import net.jafama.FastMath;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Material; import org.bukkit.Material;
@@ -30,34 +31,27 @@ public class OreConfig extends TerraConfig {
private final double deformFrequency; private final double deformFrequency;
private final String id; private final String id;
private final boolean update; private final boolean update;
private final boolean crossChunks;
private final int chunkEdgeOffset;
Set<Material> replaceable; Set<Material> replaceable;
public OreConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException { public OreConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException {
super(file, config); super(file, config);
if(!yaml.contains("id")) throw new ConfigException("Ore ID not found!", "null"); if(!contains("id")) throw new ConfigException("Ore ID not found!", "null");
this.id = yaml.getString("id"); this.id = getString("id");
if(!yaml.contains("material")) throw new ConfigException("Ore material not found!", getID()); if(!contains("material")) throw new ConfigException("Ore material not found!", getID());
if(!yaml.contains("deform")) throw new ConfigException("Ore vein deformation not found!", getID()); if(!contains("deform")) throw new ConfigException("Ore vein deformation not found!", getID());
if(!yaml.contains("replace")) throw new ConfigException("Ore replaceable materials not found!", getID()); if(!contains("replace")) throw new ConfigException("Ore replaceable materials not found!", getID());
min = yaml.getInt("radius.min", 1); min = getInt("radius.min", 1);
max = yaml.getInt("radius.max", 1); max = getInt("radius.max", 1);
deform = yaml.getDouble("deform", 0.75); deform = getDouble("deform", 0.75);
deformFrequency = yaml.getDouble("deform-frequency", 0.1); deformFrequency = getDouble("deform-frequency", 0.1);
update = yaml.getBoolean("update", false); update = getBoolean("update", false);
crossChunks = yaml.getBoolean("cross-chunks", true);
chunkEdgeOffset = yaml.getInt("edge-offset", 1);
if(chunkEdgeOffset > 7 || chunkEdgeOffset < 0) replaceable = ConfigUtil.toBlockData(getStringList("replace"), "replaceable", getID());
throw new ConfigException("Edge offset is too high/low!", getID());
replaceable = ConfigUtil.toBlockData(yaml.getStringList("replace"), "replaceable", getID());
try { try {
oreData = Bukkit.createBlockData(Objects.requireNonNull(yaml.getString("material"))); oreData = Bukkit.createBlockData(Objects.requireNonNull(getString("material")));
} catch(NullPointerException | IllegalArgumentException e) { } 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)); Vector source = l.clone().add(new Vector(x, y, z));
if(oreLoc.getBlockY() > 255 || oreLoc.getBlockY() < 0) continue; if(oreLoc.getBlockY() > 255 || oreLoc.getBlockY() < 0) continue;
if(source.distance(l) < (rad + 0.5) * ((ore.getNoise(x, y, z) + 1) * deform)) { 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()))) 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) if(replaceable.contains(b.getType()) && b.getLocation().getY() >= 0)
b.setBlockData(oreData, update); b.setBlockData(oreData, update);
} }
@@ -120,12 +114,4 @@ public class OreConfig extends TerraConfig {
public String toString() { public String toString() {
return "Ore with ID " + getID(); return "Ore with ID " + getID();
} }
public boolean crossChunks() {
return crossChunks;
}
public int getChunkEdgeOffset() {
return chunkEdgeOffset;
}
} }
@@ -9,6 +9,7 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.polydev.gaea.math.FastNoiseLite; import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.ProbabilityCollection; 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.Palette;
import org.polydev.gaea.world.palette.RandomPalette; import org.polydev.gaea.world.palette.RandomPalette;
import org.polydev.gaea.world.palette.SimplexPalette; import org.polydev.gaea.world.palette.SimplexPalette;
@@ -17,7 +18,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
public class PaletteConfig extends TerraConfig { public class PaletteConfig extends TerraConfig {
private final Palette<BlockData> palette; private final Palette<BlockData> palette;
@@ -26,18 +26,18 @@ public class PaletteConfig extends TerraConfig {
public PaletteConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException { public PaletteConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException {
super(file, config); super(file, config);
if(!yaml.contains("id")) throw new ConfigException("Palette ID unspecified!", "null"); if(!contains("id")) throw new ConfigException("Palette ID unspecified!", "null");
this.paletteID = yaml.getString("id"); this.paletteID = getString("id");
Palette<BlockData> pal; Palette<BlockData> pal;
if(yaml.getBoolean("simplex", false)) { if(getBoolean("simplex", false)) {
useNoise = true; useNoise = true;
FastNoiseLite pNoise = new FastNoiseLite(yaml.getInt("seed", 2403)); FastNoiseLite pNoise = new FastNoiseLite(getInt("seed", 2403));
pNoise.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2); pNoise.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2);
pNoise.setFractalOctaves(4); pNoise.setFractalOctaves(4);
pNoise.setFrequency(yaml.getDouble("frequency", 0.02)); pNoise.setFrequency(getDouble("frequency", 0.02));
pal = new SimplexPalette<>(pNoise); pal = new SimplexPalette<>(pNoise);
} else pal = new RandomPalette<>(new Random(yaml.getInt("seed", 2403))); } else pal = new RandomPalette<>(new FastRandom(getInt("seed", 2403)));
palette = getPalette(yaml.getMapList("layers"), pal); palette = getPalette(getMapList("layers"), pal);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -6,8 +6,12 @@ import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigUtil; import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.exception.ConfigException; import com.dfsek.terra.config.exception.ConfigException;
import com.dfsek.terra.config.exception.NotFoundException; 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.Rotation;
import com.dfsek.terra.structure.Structure; 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.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
@@ -73,4 +77,28 @@ public class TreeConfig extends TerraConfig implements Tree {
struc.paste(mut, rotation); struc.paste(mut, rotation);
return true; 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;
}
} }
@@ -9,7 +9,6 @@ import com.dfsek.terra.config.exception.ConfigException;
import com.dfsek.terra.config.exception.NotFoundException; import com.dfsek.terra.config.exception.NotFoundException;
import com.dfsek.terra.config.genconfig.structure.StructureConfig; import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.generation.UserDefinedDecorator; import com.dfsek.terra.generation.UserDefinedDecorator;
import com.dfsek.terra.generation.UserDefinedGenerator;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.polydev.gaea.math.Range; import org.polydev.gaea.math.Range;
@@ -45,36 +44,36 @@ public class BiomeConfig extends TerraConfig {
public BiomeConfig(File file, ConfigPack config) throws InvalidConfigurationException, IOException { public BiomeConfig(File file, ConfigPack config) throws InvalidConfigurationException, IOException {
super(file, config); super(file, config);
load(file);
this.config = config; this.config = config;
if(!yaml.contains("id")) throw new ConfigException("Biome ID unspecified!", "null"); if(!contains("id")) throw new ConfigException("Biome ID unspecified!", "null");
this.biomeID = yaml.getString("id"); this.biomeID = getString("id");
AbstractBiomeConfig abstractBiome = null; AbstractBiomeConfig abstractBiome = null;
// Whether an abstract biome is to be extended. Default to false. // Whether an abstract biome is to be extended. Default to false.
boolean extending = false; boolean extending = false;
// Check if biome extends an abstract biome, load abstract biome if so. // Check if biome extends an abstract biome, load abstract biome if so.
if(yaml.contains("extends")) { if(contains("extends")) {
try { try {
abstractBiome = config.getAbstractBiomes().get(yaml.getString("extends")); abstractBiome = config.getAbstractBiomes().get(getString("extends"));
if(abstractBiome == null) if(abstractBiome == null) throw new NotFoundException("Abstract Biome", getString("extends"), getID());
throw new NotFoundException("Abstract Biome", yaml.getString("extends"), getID());
extending = true; extending = true;
Debug.info("Extending biome " + yaml.getString("extends")); Debug.info("Extending biome " + getString("extends"));
} catch(NullPointerException e) { } 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. // Get various simple values using getOrDefault config methods.
try { try {
eq = yaml.getString("noise-equation", Objects.requireNonNull(abstractBiome).getEquation()); eq = getString("noise-equation", Objects.requireNonNull(abstractBiome).getEquation());
} catch(NullPointerException e) { } catch(NullPointerException e) {
eq = yaml.getString("noise-equation", null); eq = getString("noise-equation", null);
} }
BiomePaletteConfig palette; BiomePaletteConfig palette;
// Check if biome is extending abstract biome, only use abstract biome's palette if palette is NOT defined for current biome. // 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(); palette = abstractBiome.getPaletteData();
Debug.info("Using super palette"); Debug.info("Using super palette");
} else palette = new BiomePaletteConfig(this, "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()); throw new ConfigException("No Palette specified in biome or super biome.", getID());
// Check if carving should be handled by super biome. // 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(); carver = abstractBiome.getCarving();
Debug.info("Using super carvers"); Debug.info("Using super carvers");
} else carver = new BiomeCarverConfig(this); } else carver = new BiomeCarverConfig(this);
// Check if flora should be handled by super biome. // 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(); flora = abstractBiome.getFlora();
Debug.info("Using super flora (" + flora.getFlora().size() + " entries, " + flora.getFloraChance() + " % chance)"); Debug.info("Using super flora (" + flora.getFlora().size() + " entries, " + flora.getFloraChance() + " % chance)");
} else flora = new BiomeFloraConfig(this); } else flora = new BiomeFloraConfig(this);
// Check if trees should be handled by super biome. // 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(); tree = abstractBiome.getTrees();
Debug.info("Using super trees"); Debug.info("Using super trees");
} else tree = new BiomeTreeConfig(this); } else tree = new BiomeTreeConfig(this);
// Check if ores should be handled by super biome. // 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(); ore = abstractBiome.getOres();
Debug.info("Using super ores"); Debug.info("Using super ores");
} else ore = new BiomeOreConfig(this); } else ore = new BiomeOreConfig(this);
// Get slab stuff // Get slab stuff
if(extending && abstractBiome.getSlabs() != null && !yaml.contains("slabs")) { if(extending && abstractBiome.getSlabs() != null && !contains("slabs")) {
slab = abstractBiome.getSlabs(); slab = abstractBiome.getSlabs();
Debug.info("Using super slabs"); Debug.info("Using super slabs");
} else slab = new BiomeSlabConfig(this); } else slab = new BiomeSlabConfig(this);
@@ -127,17 +126,17 @@ public class BiomeConfig extends TerraConfig {
// Get slant stuff // Get slant stuff
TreeMap<Integer, Palette<BlockData>> slant = new TreeMap<>(); TreeMap<Integer, Palette<BlockData>> slant = new TreeMap<>();
if(yaml.contains("slant")) { if(contains("slant")) {
String slantS = yaml.getString("slant.palette"); String slantS = getString("slant.palette");
slant = new BiomePaletteConfig(this, "slant.palette").getPaletteMap(); slant = new BiomePaletteConfig(this, "slant.palette").getPaletteMap();
Debug.info("Using slant palette: " + slantS); Debug.info("Using slant palette: " + slantS);
if(slant == null) throw new NotFoundException("Slant Palette", slantS, getID()); if(slant == null) throw new NotFoundException("Slant Palette", slantS, getID());
} }
ySlantOffsetTop = yaml.getDouble("slant.y-offset.top", 0.25); ySlantOffsetTop = getDouble("slant.y-offset.top", 0.25);
ySlantOffsetBottom = yaml.getDouble("slant.y-offset.bottom", 0.25); ySlantOffsetBottom = getDouble("slant.y-offset.bottom", 0.25);
//Make sure equation is non-null //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()); 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. // Create decorator for this config.
@@ -146,10 +145,10 @@ public class BiomeConfig extends TerraConfig {
// Get Vanilla biome, throw exception if it is invalid/unspecified. // Get Vanilla biome, throw exception if it is invalid/unspecified.
org.bukkit.block.Biome vanillaBiome; org.bukkit.block.Biome vanillaBiome;
try { try {
if(!yaml.contains("vanilla")) throw new ConfigException("Vanilla Biome unspecified!", getID()); if(!contains("vanilla")) throw new ConfigException("Vanilla Biome unspecified!", getID());
vanillaBiome = org.bukkit.block.Biome.valueOf(yaml.getString("vanilla")); vanillaBiome = org.bukkit.block.Biome.valueOf(getString("vanilla"));
} catch(IllegalArgumentException e) { } catch(IllegalArgumentException e) {
throw new ConfigException("Invalid Vanilla biome: \"" + yaml.getString("vanilla") + "\"", getID()); throw new ConfigException("Invalid Vanilla biome: \"" + getString("vanilla") + "\"", getID());
} }
// Structure stuff // Structure stuff
@@ -157,7 +156,7 @@ public class BiomeConfig extends TerraConfig {
List<String> st = new ArrayList<>(); List<String> st = new ArrayList<>();
if(abstractBiome != null && abstractBiome.getStructureConfigs() != null) if(abstractBiome != null && abstractBiome.getStructureConfigs() != null)
st = abstractBiome.getStructureConfigs(); st = abstractBiome.getStructureConfigs();
if(yaml.contains("structures")) st = yaml.getStringList("structures"); if(contains("structures")) st = getStringList("structures");
for(String s : st) { for(String s : st) {
try { try {
structures.add(Objects.requireNonNull(config.getStructure(s))); structures.add(Objects.requireNonNull(config.getStructure(s)));
@@ -166,14 +165,13 @@ public class BiomeConfig extends TerraConfig {
} }
} }
String elevation = yaml.getString("elevation.equation", null); String elevation = getString("elevation.equation", null);
boolean doElevationInterpolation = yaml.getBoolean("elevation.interpolation", true); boolean doElevationInterpolation = getBoolean("elevation.interpolation", true);
try { try {
// Get UserDefinedBiome instance representing this config. // Get UserDefinedBiome instance representing this config.
UserDefinedGenerator gen = new UserDefinedGenerator(eq, elevation, config.getDefinedVariables(), palette.getPaletteMap(), slant, yaml.getBoolean("prevent-smooth", false)); GeneratorOptions gen = new GeneratorOptions(eq, elevation, config.getVariableScope(), palette.getPaletteMap(), slant, config.getNoiseBuilders(), getBoolean("prevent-smooth", false), doElevationInterpolation);
gen.setElevationInterpolation(doElevationInterpolation); this.biome = new UserDefinedBiome(vanillaBiome, dec, gen, getBoolean("erodible", false), this);
this.biome = new UserDefinedBiome(vanillaBiome, dec, gen, yaml.getBoolean("erodible", false), biomeID);
} catch(ParseException e) { } catch(ParseException e) {
e.printStackTrace(); e.printStackTrace();
throw new ConfigException("Unable to parse noise equation!", getID()); throw new ConfigException("Unable to parse noise equation!", getID());
@@ -10,13 +10,12 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.math.ProbabilityCollection; 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.Palette;
import org.polydev.gaea.world.palette.RandomPalette; import org.polydev.gaea.world.palette.RandomPalette;
import java.util.Random;
public class BiomeOceanConfig extends TerraConfigSection { 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 Palette<BlockData> ocean;
private final int seaLevel; private final int seaLevel;
@@ -27,7 +26,7 @@ public class BiomeOceanConfig extends TerraConfigSection {
if(oceanN != null) { if(oceanN != null) {
if(oceanN.startsWith("BLOCK:")) { if(oceanN.startsWith("BLOCK:")) {
try { 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) { } catch(IllegalArgumentException ex) {
throw new ConfigException("BlockData \"" + oceanN + "\" is invalid! (Ocean Palette)", parent.getID()); throw new ConfigException("BlockData \"" + oceanN + "\" is invalid! (Ocean Palette)", parent.getID());
} }
@@ -8,12 +8,12 @@ import org.bukkit.Bukkit;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.polydev.gaea.math.ProbabilityCollection; 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.Palette;
import org.polydev.gaea.world.palette.RandomPalette; import org.polydev.gaea.world.palette.RandomPalette;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
import java.util.TreeMap; import java.util.TreeMap;
public class BiomePaletteConfig extends TerraConfigSection { public class BiomePaletteConfig extends TerraConfigSection {
@@ -29,7 +29,7 @@ public class BiomePaletteConfig extends TerraConfigSection {
try { try {
if(((String) entry.getKey()).startsWith("BLOCK:")) { if(((String) entry.getKey()).startsWith("BLOCK:")) {
try { 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) { } catch(IllegalArgumentException ex) {
throw new ConfigException("BlockData " + entry.getKey() + " is invalid! (Palettes)", parent.getID()); throw new ConfigException("BlockData " + entry.getKey() + " is invalid! (Palettes)", parent.getID());
} }
@@ -11,13 +11,14 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.math.ProbabilityCollection; 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.Palette;
import org.polydev.gaea.world.palette.RandomPalette; import org.polydev.gaea.world.palette.RandomPalette;
import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
public class BiomeSlabConfig extends TerraConfigSection { public class BiomeSlabConfig extends TerraConfigSection {
private final Map<Material, Palette<BlockData>> slabs; 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 { 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<?, ?> e : paletteConfigSection) {
for(Map.Entry<?, ?> entry : e.entrySet()) { for(Map.Entry<?, ?> entry : e.entrySet()) {
@@ -42,7 +43,7 @@ public class BiomeSlabConfig extends TerraConfigSection {
if(((String) entry.getValue()).startsWith("BLOCK:")) { if(((String) entry.getValue()).startsWith("BLOCK:")) {
try { try {
Debug.info("Adding slab palette with single material " + entry.getKey()); 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) { } catch(IllegalArgumentException ex) {
throw new ConfigException("Invalid BlockData in slab configuration: " + ex.getMessage(), getParent().getConfig().getID()); throw new ConfigException("Invalid BlockData in slab configuration: " + ex.getMessage(), getParent().getConfig().getID());
} }
@@ -12,12 +12,14 @@ import java.util.Map;
public class BiomeSnowConfig extends TerraConfigSection { public class BiomeSnowConfig extends TerraConfigSection {
private final int[] snowHeights; private final int[] snowHeights;
private final boolean physics;
private boolean doSnow = false; private boolean doSnow = false;
public BiomeSnowConfig(TerraConfig parent) throws InvalidConfigurationException { public BiomeSnowConfig(TerraConfig parent) throws InvalidConfigurationException {
super(parent); super(parent);
snowHeights = new int[256]; 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; if(maps.size() == 0) return;
try { try {
for(Map<?, ?> e : maps) { for(Map<?, ?> e : maps) {
@@ -41,4 +43,8 @@ public class BiomeSnowConfig extends TerraConfigSection {
public boolean doSnow() { public boolean doSnow() {
return doSnow; return doSnow;
} }
public boolean doPhysics() {
return physics;
}
} }
@@ -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));
}
}
@@ -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;
}
}
@@ -38,7 +38,6 @@ public class EntityFeatureConfig implements FeatureConfig {
throw new InvalidConfigurationException("Error in Entity Configuration!"); throw new InvalidConfigurationException("Error in Entity Configuration!");
} }
int attempts = (Integer) items.get("attempts");
int height = (Integer) items.get("in-height"); int height = (Integer) items.get("in-height");
Range amount; 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> on = ConfigUtil.toBlockData((List<String>) items.get("spawnable-on"), "SpawnableOn", "");
Set<Material> in = ConfigUtil.toBlockData((List<String>) items.get("spawnable-in"), "SpawnableIn", ""); 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); Debug.info("Loaded EntityFeature with type: " + type);
} }
@@ -4,6 +4,7 @@ import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.generation.TerraChunkGenerator; import com.dfsek.terra.generation.TerraChunkGenerator;
import com.dfsek.terra.image.ImageLoader; import com.dfsek.terra.image.ImageLoader;
import net.jafama.FastMath;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.generation.GenerationPhase;
@@ -33,14 +34,14 @@ public class DebugFrame extends JFrame implements ActionListener {
super.paintComponents(g); super.paintComponents(g);
for(Player p : Bukkit.getOnlinePlayers()) { for(Player p : Bukkit.getOnlinePlayers()) {
if(!(p.getWorld().getGenerator() instanceof TerraChunkGenerator)) break; if(!(p.getWorld().getGenerator() instanceof TerraChunkGenerator)) break;
int xp = (int) (((double) Math.floorMod(p.getLocation().getBlockX() - (img.getWidth() / 2), x) / x) * getWidth()); int xp = (int) (((double) FastMath.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 zp = (int) (((double) FastMath.floorMod(p.getLocation().getBlockZ() - (img.getHeight() / 2), z) / z) * getHeight());
ImageLoader loader = TerraWorld.getWorld(p.getWorld()).getWorldConfig().imageLoader; ImageLoader loader = TerraWorld.getWorld(p.getWorld()).getWorldConfig().imageLoader;
if(loader != null && loader.getAlign().equals(ImageLoader.Align.NONE)) { if(loader != null && loader.getAlign().equals(ImageLoader.Align.NONE)) {
xp = (int) (((double) Math.floorMod(p.getLocation().getBlockX(), x) / x) * getWidth()); xp = (int) (((double) FastMath.floorMod(p.getLocation().getBlockX(), x) / x) * getWidth());
zp = (int) (((double) Math.floorMod(p.getLocation().getBlockZ(), z) / z) * getHeight()); 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.setColor(new Color(255, 255, 255, 128));
g.fillRect(xp + 13, zp - 13, (int) (8 + 8.25 * str.length()), 33); g.fillRect(xp + 13, zp - 13, (int) (8 + 8.25 * str.length()), 33);
g.setColor(Color.BLACK); g.setColor(Color.BLACK);
@@ -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();
}
}
}
@@ -1,34 +1,31 @@
package com.dfsek.terra.generation; package com.dfsek.terra.generation;
import com.dfsek.terra.biome.grid.TerraBiomeGrid; 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.generation.GenerationPhase;
import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.Interpolator; import org.polydev.gaea.math.Interpolator;
public class ElevationInterpolator { 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 double[][] values = new double[18][18];
private final FastNoiseLite noise;
private final int xOrigin; private final int xOrigin;
private final int zOrigin; private final int zOrigin;
private final TerraBiomeGrid grid; 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.xOrigin = chunkX << 4;
this.zOrigin = chunkZ << 4; this.zOrigin = chunkZ << 4;
this.noise = noise;
this.grid = grid; this.grid = grid;
for(int x = -2; x < 8; x++) { for(int x = -2; x < 8; x++) {
for(int z = -2; z < 8; z++) { 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 x = -1; x <= 16; x++) {
for(byte z = -1; z <= 16; z++) { 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()) { if(compareGens((x / 4), (z / 4)) && generator.interpolateElevation()) {
Interpolator interpolator = new Interpolator(biomeAvg(x / 4, z / 4), Interpolator interpolator = new Interpolator(biomeAvg(x / 4, z / 4),
biomeAvg((x / 4) + 1, z / 4), biomeAvg((x / 4) + 1, z / 4),
@@ -41,16 +38,16 @@ public class ElevationInterpolator {
} }
} }
private UserDefinedGenerator getGenerator(int x, int z) { private WorldGenerator getGenerator(int x, int z) {
return (UserDefinedGenerator) grid.getBiome(xOrigin + x, zOrigin + z, GenerationPhase.BASE).getGenerator(); 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]; return gens[x + 2][z + 2];
} }
private boolean compareGens(int x, int z) { 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 xi = x - 2; xi <= x + 2; xi++) {
for(int zi = z - 2; zi <= z + 2; zi++) { for(int zi = z - 2; zi <= z + 2; zi++) {
@@ -61,20 +58,19 @@ public class ElevationInterpolator {
} }
private double biomeAvg(int x, int z) { private double biomeAvg(int x, int z) {
return (elevate(getStoredGen(x + 1, z), x * 4 + 4 + xOrigin, z * 4 + zOrigin) return (elevate(getStoredGen(x + 1, z), (x << 2) + 4 + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x - 1, z), x * 4 - 4 + xOrigin, z * 4 + zOrigin) + elevate(getStoredGen(x - 1, z), (x << 2) - 4 + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x, z + 1), x * 4 + xOrigin, z * 4 + 4 + zOrigin) + elevate(getStoredGen(x, z + 1), (x << 2) + xOrigin, (z << 2) + 4 + zOrigin)
+ elevate(getStoredGen(x, z - 1), x * 4 + xOrigin, z * 4 - 4 + zOrigin) + elevate(getStoredGen(x, z - 1), (x << 2) + xOrigin, (z << 2) - 4 + zOrigin)
+ elevate(getStoredGen(x, z), x * 4 + xOrigin, z * 4 + zOrigin) + elevate(getStoredGen(x, z), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x - 1, z - 1), x * 4 + xOrigin, z * 4 + zOrigin) + elevate(getStoredGen(x - 1, z - 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x - 1, z + 1), x * 4 + xOrigin, z * 4 + zOrigin) + elevate(getStoredGen(x - 1, z + 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x + 1, z - 1), x * 4 + xOrigin, z * 4 + zOrigin) + elevate(getStoredGen(x + 1, z - 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x + 1, z + 1), x * 4 + xOrigin, z * 4 + zOrigin)) / 9D; + elevate(getStoredGen(x + 1, z + 1), (x << 2) + xOrigin, (z << 2) + zOrigin)) / 9D;
} }
private double elevate(UserDefinedGenerator g, int x, int z) { private double elevate(WorldGenerator g, int x, int z) {
if(g.getElevationEquation() != null) return g.getElevationEquation().getNoise(x, z, noise); return g.getElevation(x, z);
return 0;
} }
public double getElevation(int x, int z) { public double getElevation(int x, int z) {
@@ -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.BiomeConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeSlabConfig; import com.dfsek.terra.config.genconfig.biome.BiomeSlabConfig;
import com.dfsek.terra.config.lang.LangUtil; 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.CavePopulator;
import com.dfsek.terra.population.FloraPopulator; import com.dfsek.terra.population.FloraPopulator;
import com.dfsek.terra.population.OrePopulator; import com.dfsek.terra.population.OrePopulator;
import com.dfsek.terra.population.SnowPopulator; import com.dfsek.terra.population.SnowPopulator;
import com.dfsek.terra.population.StructurePopulator; import com.dfsek.terra.population.StructurePopulator;
import com.dfsek.terra.population.TreePopulator;
import com.dfsek.terra.util.DataUtil; import com.dfsek.terra.util.DataUtil;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Material; import org.bukkit.Material;
@@ -55,8 +57,9 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
public TerraChunkGenerator(ConfigPack c) { public TerraChunkGenerator(ConfigPack c) {
super(ChunkInterpolator.InterpolationType.TRILINEAR); super(ChunkInterpolator.InterpolationType.TRILINEAR);
this.configPack = c; this.configPack = c;
popMan.attach(new FloraPopulator());
popMan.attach(new OrePopulator()); popMan.attach(new OrePopulator());
popMan.attach(new TreePopulator());
popMan.attach(new FloraPopulator());
popMan.attach(new SnowPopulator()); popMan.attach(new SnowPopulator());
} }
@@ -76,26 +79,22 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
popMap.get(c.getWorld()).checkNeighbors(c.getX(), c.getZ(), c.getWorld()); 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) { 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) { 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 ySlantOffsetTop = c.getYSlantOffsetTop();
double ySlantOffsetBottom = c.getYSlantOffsetBottom(); double ySlantOffsetBottom = c.getYSlantOffsetBottom();
boolean top = interpolator.getNoise(x, y + ySlantOffsetTop - elevationInterpolator.getElevation(x, z), z) > 0; 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; 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); return c.getBiome().getGenerator().getPalette(y);
} }
@@ -109,10 +108,10 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
if(stairPalette != null) { if(stairPalette != null) {
BlockData stair = stairPalette.get(0, block.getBlockX(), block.getBlockZ()); BlockData stair = stairPalette.get(0, block.getBlockX(), block.getBlockZ());
Stairs stairNew = (Stairs) stair.clone(); Stairs stairNew = (Stairs) stair.clone();
double elevationN = elevationInterpolator.getElevation(block.getBlockX(), block.getBlockZ() - 1); // Northern elevation int elevationN = (int) elevationInterpolator.getElevation(block.getBlockX(), block.getBlockZ() - 1); // Northern elevation
double elevationS = elevationInterpolator.getElevation(block.getBlockX(), block.getBlockZ() + 1); // Southern elevation int elevationS = (int) elevationInterpolator.getElevation(block.getBlockX(), block.getBlockZ() + 1); // Southern elevation
double elevationE = elevationInterpolator.getElevation(block.getBlockX() + 1, block.getBlockZ()); // Eastern elevation int elevationE = (int) elevationInterpolator.getElevation(block.getBlockX() + 1, block.getBlockZ()); // Eastern elevation
double elevationW = elevationInterpolator.getElevation(block.getBlockX() - 1, block.getBlockZ()); // Western 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) { if(interpolator.getNoise(block.getBlockX() - 0.5, block.getBlockY() - elevationW, block.getBlockZ()) > thresh) {
stairNew.setFacing(BlockFace.WEST); stairNew.setFacing(BlockFace.WEST);
} else if(interpolator.getNoise(block.getBlockX(), block.getBlockY() - elevationN, block.getBlockZ() - 0.5) > thresh) { } 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 @Override
@SuppressWarnings("try") @SuppressWarnings("try")
public ChunkData generateBase(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, ChunkInterpolator interpolator) { 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); ChunkData chunk = createChunkData(world);
TerraWorld tw = TerraWorld.getWorld(world); TerraWorld tw = TerraWorld.getWorld(world);
if(!tw.isSafe()) return chunk; if(!tw.isSafe()) return chunk;
ConfigPack config = tw.getConfig();
int xOrig = (chunkX << 4); int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4); int zOrig = (chunkZ << 4);
org.polydev.gaea.biome.BiomeGrid grid = getBiomeGrid(world); org.polydev.gaea.biome.BiomeGrid grid = getBiomeGrid(world);
ElevationInterpolator elevationInterpolator; ElevationInterpolator elevationInterpolator;
try(ProfileFuture ignore = TerraProfiler.fromWorld(world).measure("ElevationTime")) { 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++) { for(byte x = 0; x < 16; x++) {
@@ -162,7 +166,7 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
int cz = zOrig + z; int cz = zOrig + z;
Biome b = grid.getBiome(xOrig + x, zOrig + z, GenerationPhase.PALETTE_APPLY); 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); double elevate = elevationInterpolator.getElevation(x, z);
@@ -203,12 +207,12 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
@Override @Override
public int getNoiseOctaves(World world) { public int getNoiseOctaves(World world) {
return configPack.octaves; return 1;
} }
@Override @Override
public double getNoiseFrequency(World world) { public double getNoiseFrequency(World world) {
return configPack.frequency; return 0.02;
} }
@Override @Override
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -5,6 +5,7 @@ import com.dfsek.terra.biome.BiomeZone;
import com.dfsek.terra.biome.grid.TerraBiomeGrid; import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import com.dfsek.terra.config.base.ConfigUtil; import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.debug.gui.DebugGUI; import com.dfsek.terra.debug.gui.DebugGUI;
import net.jafama.FastMath;
import org.bukkit.World; import org.bukkit.World;
import org.polydev.gaea.biome.NormalizationUtil; import org.polydev.gaea.biome.NormalizationUtil;
@@ -108,12 +109,12 @@ public class ImageLoader {
NONE { NONE {
@Override @Override
public int getRGB(BufferedImage image, int x, int y) { 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) { 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); public abstract int getRGB(BufferedImage image, int x, int y);
@@ -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;
}
}
@@ -0,0 +1,6 @@
package com.dfsek.terra.math;
import parsii.eval.Function;
public interface NoiseFunction extends Function {
}
@@ -1,15 +1,20 @@
package com.dfsek.terra.math; package com.dfsek.terra.math;
import com.dfsek.terra.config.base.ConfigUtil; 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 org.polydev.gaea.math.FastNoiseLite;
import parsii.eval.Expression; import parsii.eval.Expression;
import parsii.eval.Function;
import java.util.List; 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 final Cache cache = new Cache();
private FastNoiseLite gen;
public NoiseFunction2(long seed, NoiseBuilder builder) {
this.gen = builder.build((int) seed);
}
@Override @Override
public int getNumberOfArguments() { public int getNumberOfArguments() {
@@ -18,7 +23,17 @@ public class NoiseFunction2 implements Function {
@Override @Override
public double eval(List<Expression> list) { 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 @Override
@@ -26,28 +41,24 @@ public class NoiseFunction2 implements Function {
return true; return true;
} }
public void setNoise(FastNoiseLite gen) { private static class Cache extends HashMapDoubleDouble {
this.gen = gen; private static final long serialVersionUID = 8915092734723467010L;
} private static final int cacheSize = ConfigUtil.cacheSize;
private final class Cache { public double get(FastNoiseLite noise, double x, double z) {
private final double[] cacheX = new double[ConfigUtil.cacheSize]; double xx = x >= 0 ? x * 2 : x * -2 - 1;
private final double[] cacheZ = new double[ConfigUtil.cacheSize]; double zz = z >= 0 ? z * 2 : z * -2 - 1;
private final double[] cacheValues = new double[ConfigUtil.cacheSize]; 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) { private double addAndReturn(double value, double key) {
for(int i = 0; i < cacheX.length; i++) { this.put(key, value);
if(cacheX[i] == x && cacheZ[i] == z) return cacheValues[i]; return value;
}
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];
} }
} }
} }
@@ -1,13 +1,17 @@
package com.dfsek.terra.math; package com.dfsek.terra.math;
import com.dfsek.terra.generation.config.NoiseBuilder;
import org.polydev.gaea.math.FastNoiseLite; import org.polydev.gaea.math.FastNoiseLite;
import parsii.eval.Expression; import parsii.eval.Expression;
import parsii.eval.Function;
import java.util.List; import java.util.List;
public class NoiseFunction3 implements Function { public class NoiseFunction3 implements NoiseFunction {
private FastNoiseLite gen; private final FastNoiseLite gen;
public NoiseFunction3(long seed, NoiseBuilder builder) {
this.gen = builder.build((int) seed);
}
@Override @Override
public int getNumberOfArguments() { public int getNumberOfArguments() {
@@ -23,8 +27,4 @@ public class NoiseFunction3 implements Function {
public boolean isNaturalFunction() { public boolean isNaturalFunction() {
return true; return true;
} }
public void setNoise(FastNoiseLite gen) {
this.gen = gen;
}
} }
@@ -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;
}
}
@@ -5,6 +5,7 @@ import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.config.base.ConfigPack; import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigUtil; import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.genconfig.CarverConfig; import com.dfsek.terra.config.genconfig.CarverConfig;
import com.dfsek.terra.util.PopulationUtil;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@@ -30,9 +31,10 @@ public class CavePopulator extends BlockPopulator {
@SuppressWarnings("try") @SuppressWarnings("try")
@Override @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; if(ConfigUtil.masterDisableCaves) return;
try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("CaveTime")) { try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("CaveTime")) {
Random random = PopulationUtil.getRandom(chunk);
TerraWorld tw = TerraWorld.getWorld(world); TerraWorld tw = TerraWorld.getWorld(world);
if(!tw.isSafe()) return; if(!tw.isSafe()) return;
ConfigPack config = tw.getConfig(); ConfigPack config = tw.getConfig();
@@ -70,24 +72,23 @@ public class CavePopulator extends BlockPopulator {
updateNeeded.add(b); updateNeeded.add(b);
} }
} }
for(Location l : shiftCandidate.keySet()) { for(Map.Entry<Location, Material> entry : shiftCandidate.entrySet()) {
Location l = entry.getKey();
Location mut = l.clone(); Location mut = l.clone();
Material orig = l.getBlock().getType(); Material orig = l.getBlock().getType();
do mut.subtract(0, 1, 0); do mut.subtract(0, 1, 0);
while(mut.getBlock().getType().equals(orig)); while(mut.getBlock().getType().equals(orig));
try { try {
if(c.getShiftedBlocks().get(shiftCandidate.get(l)).contains(mut.getBlock().getType())) { if(c.getShiftedBlocks().get(entry.getValue()).contains(mut.getBlock().getType())) {
mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(shiftCandidate.get(l), Material::createBlockData), false); mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(entry.getValue(), Material::createBlockData), false);
} }
} catch(NullPointerException ignore) { } catch(NullPointerException ignore) {
} }
} }
try(ProfileFuture ignore = TerraProfiler.fromWorld(world).measure("CaveBlockUpdate")) { for(Block b : updateNeeded) {
for(Block b : updateNeeded) { BlockData orig = b.getBlockData();
BlockData orig = b.getBlockData(); b.setBlockData(AIR, false);
b.setBlockData(AIR, false); b.setBlockData(orig, true);
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()) { /*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(); Vector v = e.getKey();
@@ -1,29 +1,20 @@
package com.dfsek.terra.population; package com.dfsek.terra.population;
import com.dfsek.terra.Terra;
import com.dfsek.terra.TerraProfiler; import com.dfsek.terra.TerraProfiler;
import com.dfsek.terra.TerraWorld; import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.grid.TerraBiomeGrid; 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.BiomeConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeFloraConfig; 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.Chunk;
import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.math.Range;
import org.polydev.gaea.population.GaeaBlockPopulator; import org.polydev.gaea.population.GaeaBlockPopulator;
import org.polydev.gaea.profiler.ProfileFuture; import org.polydev.gaea.profiler.ProfileFuture;
import org.polydev.gaea.tree.Tree;
import org.polydev.gaea.world.Flora; import org.polydev.gaea.world.Flora;
import java.util.ArrayList;
import java.util.List;
import java.util.Random; import java.util.Random;
/** /**
@@ -39,21 +30,12 @@ public class FloraPopulator extends GaeaBlockPopulator {
int originX = chunk.getX() << 4; int originX = chunk.getX() << 4;
int originZ = chunk.getZ() << 4; int originZ = chunk.getZ() << 4;
TerraBiomeGrid grid = tw.getGrid(); TerraBiomeGrid grid = tw.getGrid();
ConfigPack config = tw.getConfig();
for(int x = 0; x < 16; x++) { for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) { for(int z = 0; z < 16; z++) {
UserDefinedBiome biome = (UserDefinedBiome) grid.getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z, GenerationPhase.POPULATE); 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; if(biome.getDecorator().getFloraChance() <= 0) continue;
try { try {
BiomeConfig c = config.getBiome(biome); BiomeConfig c = biome.getConfig();
BiomeFloraConfig f = c.getFlora(); BiomeFloraConfig f = c.getFlora();
for(int i = 0; i < f.getFloraAttempts(); i++) { for(int i = 0; i < f.getFloraAttempts(); i++) {
Flora item; 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);
}
} }
@@ -3,7 +3,6 @@ package com.dfsek.terra.population;
import com.dfsek.terra.TerraProfiler; import com.dfsek.terra.TerraProfiler;
import com.dfsek.terra.TerraWorld; import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome; 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.OreConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeOreConfig; import com.dfsek.terra.config.genconfig.biome.BiomeOreConfig;
import com.dfsek.terra.event.OreVeinGenerateEvent; import com.dfsek.terra.event.OreVeinGenerateEvent;
@@ -24,28 +23,29 @@ import java.util.Random;
public class OrePopulator extends GaeaBlockPopulator { public class OrePopulator extends GaeaBlockPopulator {
@SuppressWarnings("try") @SuppressWarnings("try")
@Override @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")) { try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("OreTime")) {
TerraWorld tw = TerraWorld.getWorld(world); TerraWorld tw = TerraWorld.getWorld(world);
if(!tw.isSafe()) return; if(!tw.isSafe()) return;
ConfigPack config = tw.getConfig(); for(int cx = -1; cx <= 1; cx++) {
Biome b = TerraWorld.getWorld(world).getGrid().getBiome((chunk.getX() << 4) + 8, (chunk.getZ() << 4) + 8, GenerationPhase.POPULATE); for(int cz = -1; cz <= 1; cz++) {
BiomeOreConfig ores = config.getBiome((UserDefinedBiome) b).getOres(); Biome b = TerraWorld.getWorld(world).getGrid().getBiome(((chunk.getX() + cx) << 4) + 8, ((chunk.getZ() + cz) << 4) + 8, GenerationPhase.POPULATE);
for(Map.Entry<OreConfig, Range> e : ores.getOres().entrySet()) { BiomeOreConfig ores = ((UserDefinedBiome) b).getConfig().getOres();
int num = e.getValue().get(random); for(Map.Entry<OreConfig, Range> e : ores.getOres().entrySet()) {
OreConfig ore = e.getKey(); int num = e.getValue().get(r);
int edgeOffset = ore.getChunkEdgeOffset(); OreConfig ore = e.getKey();
for(int i = 0; i < num; i++) { for(int i = 0; i < num; i++) {
int x = random.nextInt(16 - edgeOffset * 2) + edgeOffset; int x = r.nextInt(16) + cx * 16;
int z = random.nextInt(16 - edgeOffset * 2) + edgeOffset; int z = r.nextInt(16) + cz * 16;
int y = ores.getOreHeights().get(ore).get(random); int y = ores.getOreHeights().get(ore).get(r);
Vector v = new Vector(x, y, z); Vector v = new Vector(x, y, z);
OreVeinGenerateEvent event = new OreVeinGenerateEvent(tw, v.toLocation(world), ore); OreVeinGenerateEvent event = new OreVeinGenerateEvent(tw, v.toLocation(world), ore);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if(!event.isCancelled()) { if(!event.isCancelled()) {
if(ore.crossChunks()) ore.doVein(v, chunk, random); ore.doVeinSingle(new Vector(x, y, z), chunk, r);
else ore.doVeinSingle(new Vector(x, y, z), chunk, random); }
}
} }
} }
} }
@@ -12,6 +12,9 @@ import org.bukkit.Chunk;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; 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.jetbrains.annotations.NotNull;
import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.population.GaeaBlockPopulator; import org.polydev.gaea.population.GaeaBlockPopulator;
@@ -55,7 +58,7 @@ public class SnowPopulator extends GaeaBlockPopulator {
TerraBiomeGrid g = w.getGrid(); TerraBiomeGrid g = w.getGrid();
for(int x = 0; x < 16; x++) { for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) { 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; if(!biome.getSnow().doSnow()) continue;
int y; int y;
Block b = null; Block b = null;
@@ -66,7 +69,13 @@ public class SnowPopulator extends GaeaBlockPopulator {
if(random.nextInt(100) >= biome.getSnow().getSnowChance(y)) if(random.nextInt(100) >= biome.getSnow().getSnowChance(y))
continue; continue;
if(blacklistSpawn.contains(b.getType()) || b.isPassable()) 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);
} }
} }
} }
@@ -12,7 +12,9 @@ import com.dfsek.terra.structure.Rotation;
import com.dfsek.terra.structure.Structure; import com.dfsek.terra.structure.Structure;
import com.dfsek.terra.structure.StructureContainedInventory; import com.dfsek.terra.structure.StructureContainedInventory;
import com.dfsek.terra.structure.features.Feature; import com.dfsek.terra.structure.features.Feature;
import com.dfsek.terra.util.PopulationUtil;
import com.dfsek.terra.util.structure.RotationUtil; import com.dfsek.terra.util.structure.RotationUtil;
import net.jafama.FastMath;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
@@ -21,6 +23,7 @@ import org.bukkit.inventory.BlockInventoryHolder;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.profiler.ProfileFuture; import org.polydev.gaea.profiler.ProfileFuture;
import org.polydev.gaea.structures.loot.LootTable; import org.polydev.gaea.structures.loot.LootTable;
import org.polydev.gaea.util.FastRandom;
import java.util.Random; import java.util.Random;
@@ -28,8 +31,9 @@ public class StructurePopulator extends BlockPopulator {
@SuppressWarnings("try") @SuppressWarnings("try")
@Override @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")) { try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("StructureTime")) {
Random random = PopulationUtil.getRandom(chunk);
int cx = (chunk.getX() << 4); int cx = (chunk.getX() << 4);
int cz = (chunk.getZ() << 4); int cz = (chunk.getZ() << 4);
TerraWorld tw = TerraWorld.getWorld(world); TerraWorld tw = TerraWorld.getWorld(world);
@@ -39,8 +43,8 @@ public class StructurePopulator extends BlockPopulator {
structure: structure:
for(StructureConfig conf : config.getAllStructures()) { for(StructureConfig conf : config.getAllStructures()) {
Location spawn = conf.getSpawn().getNearestSpawn(cx + 8, cz + 8, world.getSeed()).toLocation(world); Location spawn = conf.getSpawn().getNearestSpawn(cx + 8, cz + 8, world.getSeed()).toLocation(world);
if(!config.getBiome((UserDefinedBiome) grid.getBiome(spawn)).getStructures().contains(conf)) continue; if(!((UserDefinedBiome) grid.getBiome(spawn)).getConfig().getStructures().contains(conf)) continue;
Random r2 = new Random(spawn.hashCode()); Random r2 = new FastRandom(spawn.hashCode());
Structure struc = conf.getStructure(r2); Structure struc = conf.getStructure(r2);
Rotation rotation = Rotation.fromDegrees(r2.nextInt(4) * 90); Rotation rotation = Rotation.fromDegrees(r2.nextInt(4) * 90);
for(int y = conf.getSearchStart().get(r2); y > 0; y--) { for(int y = conf.getSearchStart().get(r2); y > 0; y--) {
@@ -48,15 +52,15 @@ public class StructurePopulator extends BlockPopulator {
spawn.setY(y); spawn.setY(y);
if(!struc.checkSpawns(spawn, rotation)) continue; if(!struc.checkSpawns(spawn, rotation)) continue;
double horizontal = struc.getStructureInfo().getMaxHorizontal(); 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); struc.paste(spawn, chunk, rotation);
for(StructureContainedInventory i : struc.getInventories()) { for(StructureContainedInventory i : struc.getInventories()) {
try { try {
Debug.info("Attempting to populate loot: " + i.getUid()); 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()); 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()); 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()); Debug.info(FastMath.floorDiv(inv.getBlockX(), 16) + ":" + chunk.getX() + ", " + FastMath.floorDiv(inv.getBlockZ(), 16) + ":" + chunk.getZ());
if(Math.floorDiv(inv.getBlockX(), 16) != chunk.getX() || Math.floorDiv(inv.getBlockZ(), 16) != chunk.getZ()) if(FastMath.floorDiv(inv.getBlockX(), 16) != chunk.getX() || FastMath.floorDiv(inv.getBlockZ(), 16) != chunk.getZ())
continue; continue;
Debug.info("Target is in chunk."); Debug.info("Target is in chunk.");
Debug.info(spawn.toString() + " became: " + inv.toString() + " (" + rotation + ", " + inv.getBlock().getType() + ")"); Debug.info(spawn.toString() + " became: " + inv.toString() + " (" + rotation + ", " + inv.getBlock().getType() + ")");
@@ -69,7 +73,7 @@ public class StructurePopulator extends BlockPopulator {
Debug.stack(e); 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; break;
} }
} }
@@ -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);
}
}
}
}
}
}
@@ -2,8 +2,9 @@ package com.dfsek.terra.procgen;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.polydev.gaea.math.MathUtil; 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.List;
import java.util.Random; import java.util.Random;
@@ -30,7 +31,7 @@ public class GridSpawn {
public Vector getNearestSpawn(int x, int z, long seed) { public Vector getNearestSpawn(int x, int z, long seed) {
int structureChunkX = x / (width + 2 * separation); int structureChunkX = x / (width + 2 * separation);
int structureChunkZ = z / (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 xi = structureChunkX - 1; xi <= structureChunkX + 1; xi++) {
for(int zi = structureChunkZ - 1; zi <= structureChunkZ + 1; zi++) { for(int zi = structureChunkZ - 1; zi <= structureChunkZ + 1; zi++) {
zones.add(getChunkSpawn(xi, zi, seed)); zones.add(getChunkSpawn(xi, zi, seed));
@@ -53,7 +54,7 @@ public class GridSpawn {
* @return Vector representing spawnpoint * @return Vector representing spawnpoint
*/ */
public Vector getChunkSpawn(int structureChunkX, int structureChunkZ, long seed) { 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 offsetX = r.nextInt(width);
int offsetZ = r.nextInt(width); int offsetZ = r.nextInt(width);
int sx = structureChunkX * (width + 2 * separation) + offsetX; int sx = structureChunkX * (width + 2 * separation) + offsetX;
@@ -1,5 +1,7 @@
package com.dfsek.terra.procgen.math; package com.dfsek.terra.procgen.math;
import net.jafama.FastMath;
/** /**
* oh yeah * oh yeah
*/ */
@@ -111,7 +113,7 @@ public class Vector2 implements Cloneable {
* @return length * @return length
*/ */
public double 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 * @return Distance between vectors
*/ */
public double distance(Vector2 other) { public double distance(Vector2 other) {
return Math.sqrt(distanceSquared(other)); return FastMath.sqrt(distanceSquared(other));
} }
/** /**
@@ -1,6 +1,7 @@
package com.dfsek.terra.procgen.pixel; package com.dfsek.terra.procgen.pixel;
import com.dfsek.terra.procgen.math.Vector2; import com.dfsek.terra.procgen.math.Vector2;
import net.jafama.FastMath;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@@ -11,8 +12,8 @@ public class Rectangle extends Polygon {
private final Vector2 max; private final Vector2 max;
public Rectangle(Vector2 min, 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.max = new Vector2(FastMath.min(min.getX(), max.getX()), FastMath.min(min.getZ(), max.getZ()));
this.min = new Vector2(Math.max(min.getX(), max.getX()), Math.max(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) { public Rectangle(Vector2 center, double xRadius, double zRadius) {
@@ -1,12 +1,12 @@
package com.dfsek.terra.procgen.voxel; package com.dfsek.terra.procgen.voxel;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.polydev.gaea.util.GlueList;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public abstract class VoxelGeometry { public abstract class VoxelGeometry {
private final List<Vector> geometry = new ArrayList<>(); private final List<Vector> geometry = new GlueList<>();
public static VoxelGeometry getBlank() { public static VoxelGeometry getBlank() {
return new VoxelGeometry() { return new VoxelGeometry() {
@@ -1,5 +1,7 @@
package com.dfsek.terra.structure; package com.dfsek.terra.structure;
import net.jafama.FastMath;
public enum Rotation { public enum Rotation {
CW_90(90), CW_180(180), CCW_90(270), NONE(0); CW_90(90), CW_180(180), CCW_90(270), NONE(0);
private final int degrees; private final int degrees;
@@ -9,7 +11,7 @@ public enum Rotation {
} }
public static Rotation fromDegrees(int deg) { public static Rotation fromDegrees(int deg) {
switch(Math.floorMod(deg, 360)) { switch(FastMath.floorMod(deg, 360)) {
case 0: case 0:
return Rotation.NONE; return Rotation.NONE;
case 90: case 90:
@@ -3,6 +3,7 @@ package com.dfsek.terra.structure;
import com.dfsek.terra.Debug; import com.dfsek.terra.Debug;
import com.dfsek.terra.procgen.math.Vector2; import com.dfsek.terra.procgen.math.Vector2;
import com.dfsek.terra.util.structure.RotationUtil; import com.dfsek.terra.util.structure.RotationUtil;
import net.jafama.FastMath;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
@@ -144,6 +145,16 @@ public class Structure implements Serializable {
return (Structure) o; 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. * Paste the structure at a Location, ignoring chunk boundaries.
* *
@@ -188,7 +199,7 @@ public class Structure implements Serializable {
} }
int offset = block.getPullOffset(); int offset = block.getPullOffset();
if(offset != 0) 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); 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); Vector2 max = getRotatedCoords(new Vector2(x.getMax(), z.getMax()).subtract(center), r.inverse()).add(center);
if(a.equals(Rotation.Axis.X)) 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 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 @NotNull
@@ -283,6 +294,10 @@ public class Structure implements Serializable {
return true; return true;
} }
public HashSet<StructureContainedBlock> getSpawns() {
return spawns;
}
public HashSet<StructureContainedInventory> getInventories() { public HashSet<StructureContainedInventory> getInventories() {
return inventories; return inventories;
} }
@@ -324,12 +339,6 @@ public class Structure implements Serializable {
toFile(this, f); 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 @NotNull
public String getId() { public String getId() {
return id; return id;
@@ -1,6 +1,7 @@
package com.dfsek.terra.structure; package com.dfsek.terra.structure;
import com.dfsek.terra.procgen.math.Vector2; import com.dfsek.terra.procgen.math.Vector2;
import net.jafama.FastMath;
import java.io.Serializable; import java.io.Serializable;
@@ -41,6 +42,6 @@ public class StructureInfo implements Serializable {
} }
public double getMaxHorizontal() { 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));
} }
} }
@@ -1,8 +1,10 @@
package com.dfsek.terra.structure.features; package com.dfsek.terra.structure.features;
import com.dfsek.terra.Debug; import com.dfsek.terra.Debug;
import com.dfsek.terra.structure.Rotation;
import com.dfsek.terra.structure.Structure; import com.dfsek.terra.structure.Structure;
import com.dfsek.terra.structure.StructureInfo; import com.dfsek.terra.structure.StructureInfo;
import net.jafama.FastMath;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@@ -11,105 +13,83 @@ import org.bukkit.block.BlockFace;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.polydev.gaea.math.MathUtil; import org.polydev.gaea.math.MathUtil;
import org.polydev.gaea.math.Range; 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.Random;
import java.util.Set; import java.util.Set;
public class EntityFeature implements Feature { public class EntityFeature implements Feature {
private final EntityType type; private final EntityType type;
private final Range amount; private final Range amount;
private final int attempts;
private final Set<Material> in; private final Set<Material> in;
private final Set<Material> stand; private final Set<Material> stand;
private final int inSize; 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.type = type;
this.amount = amount; this.amount = amount;
this.attempts = attempts;
this.in = in; this.in = in;
this.stand = stand; this.stand = stand;
this.inSize = inSize; this.inSize = inSize;
} }
@Override private static boolean isInChunk(Chunk c, Location l) {
public void apply(Structure structure, Location l, Chunk chunk) { return FastMath.floorDiv(l.getBlockX(), 16) == c.getX() && FastMath.floorDiv(l.getBlockZ(), 16) == c.getZ();
Random random = new Random(MathUtil.getCarverChunkSeed(chunk.getX(), chunk.getZ(), chunk.getWorld().getSeed())); }
int amountSpawn = amount.get(random);
private static List<Location> getLocations(Structure structure, Rotation r, Location origin, Random random, int number) {
StructureInfo info = structure.getStructureInfo(); StructureInfo info = structure.getStructureInfo();
Range x = new Range(0, info.getSizeZ()); Range x = structure.getRange(Rotation.Axis.X, r);
Range y = new Range(0, info.getSizeY()); Range y = structure.getRange(Rotation.Axis.Y, r);
Range z = new Range(0, info.getSizeZ()); Range z = structure.getRange(Rotation.Axis.Z, r);
int cx = info.getCenterX(); int cx = info.getCenterX();
int cz = info.getCenterZ(); 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++) { @Override
int yv = y.get(random); public void apply(Structure structure, Rotation r, Location l, Chunk chunk) {
Location attempt = l.clone().add(x.get(random) - cx, yv, z.get(random) - cz); 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. if(!isInChunk(chunk, attempt)) continue; // Don't attempt spawn if not in current chunk.
attemptSpawn(attempt, l);
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.
}
} }
} }
private static boolean isInChunk(Chunk c, Location l) { private void attemptSpawn(Location attempt, Location origin) {
return Math.floorDiv(l.getBlockX(), 16) == c.getX() && Math.floorDiv(l.getBlockZ(), 16) == c.getZ(); 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 @Override
public void apply(Structure structure, Location l, Random random) { public void apply(Structure structure, Rotation r, Location l, Random random) {
int amountSpawn = amount.get(random); for(Location attempt : getLocations(structure, r, l, random, amount.get(random))) {
attemptSpawn(attempt, l);
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.
}
} }
} }
} }
@@ -1,5 +1,6 @@
package com.dfsek.terra.structure.features; package com.dfsek.terra.structure.features;
import com.dfsek.terra.structure.Rotation;
import com.dfsek.terra.structure.Structure; import com.dfsek.terra.structure.Structure;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
@@ -7,7 +8,7 @@ import org.bukkit.Location;
import java.util.Random; import java.util.Random;
public interface Feature { 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);
} }
@@ -2,8 +2,8 @@ package com.dfsek.terra.structure.spawn;
import com.dfsek.terra.TerraWorld; import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome; 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.config.genconfig.biome.BiomeConfig;
import com.dfsek.terra.generation.config.WorldGenerator;
import org.bukkit.World; import org.bukkit.World;
import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.generation.GenerationPhase;
@@ -15,10 +15,10 @@ public class AirSpawn extends Requirement {
@Override @Override
public boolean matches(int x, int y, int z) { public boolean matches(int x, int y, int z) {
TerraWorld tw = TerraWorld.getWorld(getWorld()); TerraWorld tw = TerraWorld.getWorld(getWorld());
ConfigPack wc = tw.getConfig();
UserDefinedBiome b = (UserDefinedBiome) tw.getGrid().getBiome(x, z, GenerationPhase.POPULATE); 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; 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;
} }
} }
@@ -2,6 +2,7 @@ package com.dfsek.terra.structure.spawn;
import com.dfsek.terra.TerraWorld; import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.generation.config.WorldGenerator;
import org.bukkit.World; import org.bukkit.World;
import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.generation.GenerationPhase;
@@ -14,6 +15,7 @@ public class LandSpawn extends Requirement {
public boolean matches(int x, int y, int z) { public boolean matches(int x, int y, int z) {
TerraWorld tw = TerraWorld.getWorld(getWorld()); TerraWorld tw = TerraWorld.getWorld(getWorld());
UserDefinedBiome b = (UserDefinedBiome) tw.getGrid().getBiome(x, z, GenerationPhase.POPULATE); 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;
} }
} }
@@ -3,6 +3,7 @@ package com.dfsek.terra.structure.spawn;
import com.dfsek.terra.TerraWorld; import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig; import com.dfsek.terra.config.genconfig.biome.BiomeConfig;
import com.dfsek.terra.generation.config.WorldGenerator;
import org.bukkit.World; import org.bukkit.World;
import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.generation.GenerationPhase;
@@ -15,8 +16,9 @@ public class OceanSpawn extends Requirement {
public boolean matches(int x, int y, int z) { public boolean matches(int x, int y, int z) {
TerraWorld tw = TerraWorld.getWorld(getWorld()); TerraWorld tw = TerraWorld.getWorld(getWorld());
UserDefinedBiome b = (UserDefinedBiome) tw.getGrid().getBiome(x, z, GenerationPhase.POPULATE); 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; 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;
} }
} }
@@ -2,15 +2,14 @@ package com.dfsek.terra.util;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.data.BlockData; 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.Palette;
import org.polydev.gaea.world.palette.RandomPalette; import org.polydev.gaea.world.palette.RandomPalette;
import java.util.Random;
public final class DataUtil { public final class DataUtil {
public static final BlockData STONE = Material.STONE.createBlockData(); public static final BlockData STONE = Material.STONE.createBlockData();
public static final BlockData SNOW = Material.SNOW.createBlockData(); public static final BlockData SNOW = Material.SNOW.createBlockData();
public static final BlockData WATER = Material.WATER.createBlockData(); public static final BlockData WATER = Material.WATER.createBlockData();
public static final BlockData AIR = Material.AIR.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);
} }
@@ -1,17 +1,16 @@
package com.dfsek.terra.util; package com.dfsek.terra.util;
import com.dfsek.terra.config.lang.LangUtil;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.util.logging.Level; import static io.papermc.lib.PaperLib.suggestPaper;
public final class PaperUtil { public final class PaperUtil {
public static void checkPaper(JavaPlugin main) { public static void checkPaper(JavaPlugin main) {
Bukkit.getScheduler().scheduleSyncDelayedTask(main, () -> { Bukkit.getScheduler().scheduleSyncDelayedTask(main, () -> {
if(!PaperLib.isPaper()) { if(!PaperLib.isPaper()) {
LangUtil.log("use-paper", Level.WARNING); suggestPaper(main);
} }
}, 100L); }, 100L);
} }
@@ -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()));
}
}
@@ -15,7 +15,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class TagUtil { public final class TagUtil {
private static final Map<String, Set<Material>> tagMap; private static final Map<String, Set<Material>> tagMap;
static { static {
@@ -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();
}
@@ -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);
}
}
}
}
@@ -2,6 +2,7 @@ package com.dfsek.terra.util.structure;
import com.dfsek.terra.procgen.math.Vector2; import com.dfsek.terra.procgen.math.Vector2;
import com.dfsek.terra.structure.Rotation; import com.dfsek.terra.structure.Rotation;
import net.jafama.FastMath;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional; 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.Rotatable;
import org.bukkit.block.data.type.RedstoneWire; import org.bukkit.block.data.type.RedstoneWire;
import java.util.HashMap; import java.util.EnumMap;
import java.util.Map; import java.util.Map;
public final class RotationUtil { public final class RotationUtil {
@@ -107,7 +108,7 @@ public final class RotationUtil {
* @return BlockFace represented by integer. * @return BlockFace represented by integer.
*/ */
public static BlockFace fromRotation(int r) { public static BlockFace fromRotation(int r) {
switch(Math.floorMod(r, 16)) { switch(FastMath.floorMod(r, 16)) {
case 0: case 0:
return BlockFace.NORTH; return BlockFace.NORTH;
case 1: case 1:
@@ -251,7 +252,7 @@ public final class RotationUtil {
((Directional) data).setFacing(rt); ((Directional) data).setFacing(rt);
} else if(data instanceof MultipleFacing) { } else if(data instanceof MultipleFacing) {
MultipleFacing mfData = (MultipleFacing) data; MultipleFacing mfData = (MultipleFacing) data;
Map<BlockFace, Boolean> faces = new HashMap<>(); Map<BlockFace, Boolean> faces = new EnumMap<>(BlockFace.class);
for(BlockFace f : mfData.getAllowedFaces()) { for(BlockFace f : mfData.getAllowedFaces()) {
faces.put(f, mfData.hasFace(f)); faces.put(f, mfData.hasFace(f));
} }
@@ -265,7 +266,7 @@ public final class RotationUtil {
org.bukkit.Axis newAxis = getRotatedAxis(((Orientable) data).getAxis(), r); org.bukkit.Axis newAxis = getRotatedAxis(((Orientable) data).getAxis(), r);
((Orientable) data).setAxis(newAxis); ((Orientable) data).setAxis(newAxis);
} else if(data instanceof RedstoneWire) { } 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; RedstoneWire rData = (RedstoneWire) data;
for(BlockFace f : rData.getAllowedFaces()) { for(BlockFace f : rData.getAllowedFaces()) {
connections.put(f, rData.getFace(f)); connections.put(f, rData.getFace(f));
+2 -1
View File
@@ -3,6 +3,7 @@ data-save: PT6M
language: "en_us" language: "en_us"
fail-type: SHUTDOWN fail-type: SHUTDOWN
dump-default: true dump-default: true
cache-size: 8 biome-search-resolution: 4
cache-size: 384
master-disable: master-disable:
caves: false caves: false
+10 -9
View File
@@ -1,3 +1,4 @@
import net.jafama.FastMath;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.polydev.gaea.math.FastNoiseLite; import org.polydev.gaea.math.FastNoiseLite;
@@ -26,8 +27,8 @@ class DistributionTest {
long l = System.nanoTime(); long l = System.nanoTime();
for(int i = 0; i < 1000000; i++) { for(int i = 0; i < 1000000; i++) {
double n = noise.getNoise(0, i); double n = noise.getNoise(0, i);
max = Math.max(max, n); max = FastMath.max(max, n);
min = Math.min(min, n); min = FastMath.min(min, n);
numbers[normalize(n, attempts)]++; numbers[normalize(n, attempts)]++;
} }
long l2 = System.nanoTime() - l; long l2 = System.nanoTime() - l;
@@ -36,8 +37,8 @@ class DistributionTest {
l = System.nanoTime(); l = System.nanoTime();
for(int i = 0; i < 1000000; i++) { for(int i = 0; i < 1000000; i++) {
double n = noise.getNoise(0, i); double n = noise.getNoise(0, i);
max = Math.max(max, n); max = FastMath.max(max, n);
min = Math.min(min, n); min = FastMath.min(min, n);
} }
l2 = System.nanoTime() - l; l2 = System.nanoTime() - l;
System.out.println("Took " + (double) l2 / 1000000 + "ms (" + ((double) l2 / 1000000) + "ns per."); System.out.println("Took " + (double) l2 / 1000000 + "ms (" + ((double) l2 / 1000000) + "ns per.");
@@ -61,22 +62,22 @@ class DistributionTest {
int end = normalMap.length - 1; int end = normalMap.length - 1;
while(start + 1 < end) { while(start + 1 < end) {
int mid = start + (end - start) / 2; int mid = start + (end - start) / 2;
if (normalMap[mid] <= d) { if(normalMap[mid] <= d) {
start = mid; start = mid;
} else { } else {
end = mid; end = mid;
} }
} }
double left = Math.abs(normalMap[start] - d); double left = FastMath.abs(normalMap[start] - d);
double right = Math.abs(normalMap[end] - d); double right = FastMath.abs(normalMap[end] - d);
if (left <= right) { if(left <= right) {
return start * (num) / (normalMap.length); return start * (num) / (normalMap.length);
} }
return end * (num) / (normalMap.length); return end * (num) / (normalMap.length);
} }
public static int normal(double d, int max) { 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); return (int) (ranged * max);
} }
} }
+15 -3
View File
@@ -1,5 +1,7 @@
import net.jafama.FastMath;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.polydev.gaea.math.FastNoiseLite; import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.util.GlueList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -12,7 +14,7 @@ class LookupGenerator {
static void main(String[] args) throws InterruptedException { static void main(String[] args) throws InterruptedException {
int dist = 4096; int dist = 4096;
List<Double> vals = new ArrayList<>(); List<Double> vals = new GlueList<>();
FastNoiseLite noise = new FastNoiseLite(); FastNoiseLite noise = new FastNoiseLite();
noise.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2); noise.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2);
noise.setFrequency(0.02f); noise.setFrequency(0.02f);
@@ -25,10 +27,10 @@ class LookupGenerator {
int workerAmount = 16; int workerAmount = 16;
List<Worker> workers = new ArrayList<>(); List<Worker> workers = new GlueList<>();
for(int i = 0; i < workerAmount; i++) { 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) { for(Worker w : workers) {
@@ -98,6 +100,12 @@ class LookupGenerator {
return lookup.length - 1; 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 static class Worker extends Thread {
private final List<Double> l; private final List<Double> l;
private final int searches; private final int searches;
@@ -120,5 +128,9 @@ class LookupGenerator {
public List<Double> getResult() { public List<Double> getResult() {
return l; return l;
} }
public String getStatus() {
return "Generating values. " + l.size() + "/" + searches + " (" + ((long) l.size() * 100L) / searches + "%)";
}
} }
} }
+52
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;
}
}