Merge remote-tracking branch 'origin/master' into dev/repeat-script

# Conflicts:
#	common/src/main/java/com/dfsek/terra/api/TerraPlugin.java
#	common/src/test/java/biome/DistributionTest.java
#	platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java
#	platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java
#	platforms/region/src/main/java/com/dfsek/terra/StandalonePlugin.java
#	platforms/sponge/src/main/java/com/dfsek/terra/sponge/TerraSpongePlugin.java
This commit is contained in:
dfsek 2021-05-09 15:20:57 -07:00
commit 8f9fc3e08f
191 changed files with 4588 additions and 1581 deletions

View File

@ -342,6 +342,6 @@ ij_json_wrap_long_lines = false
indent_size = 2
ij_yaml_keep_indents_on_empty_lines = true
ij_yaml_keep_line_breaks = true
ij_yaml_space_before_colon = true
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true

View File

@ -7,20 +7,36 @@ to your specifications, with no knowledge of Java required.
* Paper+ servers (Paper, Tuinity, Purpur, etc): [SpigotMC](https://www.spigotmc.org/resources/85151/)
* Fabric: [Modrinth](https://modrinth.com/mod/terra) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
* Forge: [Modrinth](https://modrinth.com/mod/terra) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
## Building and running Terra
## Building and Running Terra
To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This will produce a jar in `build/libs`
called `Terra-[CURRENT VERSION].jar`. You can put this right into your plugins dir, along with the correct Gaea version.
To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This will build all platforms, and
produce JARs in `platforms/<platform>/build/libs`
If you would like to test it with a default server config, just run `./gradlew setupServer` or
`./gradlew.bat setupServer` to set up the server, then `./gradlew testWithPaper` or `gradlew.bat testWithPaper` to run the server. If you
want a clean installation of the server, re-run the `setupServer` task. This will download a default server config
from [here](https://github.com/PolyhedralDev/WorldGenTestServer)
and install the server in the `target/server` directory, along with all the needed plugins.
### Production JARs:
* Bukkit: `Terra-<version>-shaded.jar`
* Fabric: `Terra-<version>-shaded-mapped.jar`
* Forge: `Terra-<version>-shaded.jar`
**Note: You will need to adjust the `NAME` variable `bukkit.yml` of the test server if you are not using the default Terra config.**
### Building a Specific Platform
To build a specific platform, run `gradlew :platforms:<platform>:build`.
JARs are produced in `platforms/<platform>/build/libs`.
### Running Minecraft in the IDE
To run Minecraft with Terra in the IDE (for testing) use the following tasks:
* Bukkit
* `installPaper` - Install a [Paper](https://github.com/PaperMC/Paper) test server. (Only needs to be run once).
* `installPurpur` - Install a [Purpur](https://github.com/pl3xgaming/Purpur) test server. (Only needs to be run once).
* `runPaper` - Run the Paper test server with Terra (`installPaper` must have been run previously).
* `runPurpur` - Run the Purpur test server with Terra (`installPurpur` must have been run previously).
* Fabric
* `runClient` - Run a Minecraft client with Terra installed.
* `runServer` - Run a Minecraft server with Terra installed.
* Forge
* `runClient` - Run a Minecraft client with Terra installed.
* `runServer` - Run a Minecraft server with Terra installed.
## Contributing
Contributions are welcome! If you want to see a feature in Terra, please, open an issue, or implement it yourself and
submit a PR!

View File

@ -1,10 +1,27 @@
import com.dfsek.terra.getGitHash
val versionObj = Version("5", "1", "3", true)
val versionObj = Version("5", "3", "0", true)
allprojects {
version = versionObj
group = "com.dfsek.terra"
tasks.withType<JavaCompile>().configureEach {
options.isFork = true
options.isIncremental = true
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
maxHeapSize = "2G"
ignoreFailures = false
failFast = true
maxParallelForks = (Runtime.getRuntime().availableProcessors() - 1).takeIf { it > 0 } ?: 1
reports.html.isEnabled = false
reports.junitXml.isEnabled = false
}
}
/**
* Version class that does version stuff.

View File

@ -7,26 +7,11 @@ import org.gradle.kotlin.dsl.withType
import java.io.ByteArrayOutputStream
fun Project.configureCommon() {
apply(plugin = "java-library")
apply(plugin = "maven-publish")
apply(plugin = "idea")
configureDependencies()
configureCompilation()
configureDistribution()
version = rootProject.version
tasks.withType<Test>().configureEach {
useJUnitPlatform()
maxHeapSize = "2G"
ignoreFailures = false
failFast = true
maxParallelForks = 12
}
}
fun Project.getGitHash(): String {

View File

@ -3,14 +3,16 @@ package com.dfsek.terra
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.filter
import org.gradle.kotlin.dsl.withType
import org.gradle.kotlin.dsl.*
import org.gradle.language.jvm.tasks.ProcessResources
fun Project.configureCompilation() {
apply(plugin = "maven-publish")
apply(plugin = "idea")
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
@ -19,7 +21,7 @@ fun Project.configureCompilation() {
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
doFirst {
options.compilerArgs = mutableListOf("-Xlint:all")
options.compilerArgs.add("-Xlint:all")
}
}
@ -35,4 +37,19 @@ fun Project.configureCompilation() {
tasks.withType<Javadoc> {
options.encoding = "UTF-8"
}
tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE")
}
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
}

View File

@ -1,13 +1,27 @@
package com.dfsek.terra
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.invoke
import org.gradle.kotlin.dsl.repositories
fun Project.configureDependencies() {
apply(plugin = "java")
apply(plugin = "java-library")
configurations {
val shaded = create("shaded")
val shadedApi = create("shadedApi")
shaded.extendsFrom(shadedApi)
getByName("api").extendsFrom(shadedApi)
val shadedImplementation = create("shadedImplementation")
shaded.extendsFrom(shadedImplementation)
getByName("implementation").extendsFrom(shadedImplementation)
}
repositories {
maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://maven.enginehub.org/repo/") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
maven { url = uri("https://maven.fabricmc.net/") }
@ -19,6 +33,6 @@ fun Project.configureDependencies() {
dependencies {
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
"testImplementation"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"compileOnly"("org.jetbrains:annotations:20.1.0")
"api"("org.jetbrains:annotations:20.1.0")
}
}

View File

@ -14,17 +14,6 @@ fun Project.configureDistribution() {
apply(plugin = "java-library")
apply(plugin = "com.github.johnrengelman.shadow")
configurations {
val shaded = create("shaded")
getByName("compile").extendsFrom(shaded)
val shadedApi = create("shadedApi")
shaded.extendsFrom(shadedApi)
getByName("api").extendsFrom(shadedApi)
val shadedImplementation = create("shadedImplementation")
shaded.extendsFrom(shadedImplementation)
getByName("implementation").extendsFrom(shadedImplementation)
}
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
group = "terra"
doFirst {
@ -38,21 +27,6 @@ fun Project.configureDistribution() {
}
tasks["processResources"].dependsOn(downloadDefaultPacks)
tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE")
}
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
tasks.named<ShadowJar>("shadowJar") {
// Tell shadow to download the packs
dependsOn(downloadDefaultPacks)

View File

@ -1,11 +1,14 @@
import com.dfsek.terra.configureCommon
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCommon()
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
@ -14,7 +17,7 @@ dependencies {
"shadedApi"("commons-io:commons-io:2.4")
"shadedApi"("com.dfsek:Paralithic:0.3.2")
"shadedApi"("com.dfsek:Tectonic:1.2.3")
"shadedApi"("com.dfsek:Tectonic:1.3.1")
"shadedApi"("net.jafama:jafama:2.3.2")
"shadedApi"("org.yaml:snakeyaml:1.27")
"shadedApi"("org.ow2.asm:asm:9.0")

View File

@ -8,14 +8,19 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.LockedRegistry;
import com.dfsek.terra.api.task.TaskScheduler;
import com.dfsek.terra.api.util.JarUtil;
import com.dfsek.terra.api.util.logging.DebugLogger;
import com.dfsek.terra.api.util.logging.Logger;
import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.world.TerraWorld;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.jar.JarFile;
/**
* Represents a Terra mod/plugin instance.
@ -66,5 +71,11 @@ public interface TerraPlugin extends LoaderRegistrar {
task.run();
}
Profiler getProfiler();
default JarFile getModJar() throws URISyntaxException, IOException {
return JarUtil.getJarFile();
}
TaskScheduler getScheduler();
}

View File

@ -65,7 +65,7 @@ public class TerraCommandManager implements CommandManager {
return;
}
if(commandClass.isAnnotationPresent(WorldCommand.class) && (!(sender instanceof Player) || !TerraWorld.isTerraWorld(((Player) sender).getWorld()))) {
if(commandClass.isAnnotationPresent(WorldCommand.class) && (!(sender instanceof Player) || !(((Player) sender).getWorld()).isTerraWorld())) {
sender.sendMessage("Command must be executed in a Terra world.");
return;
}

View File

@ -1,6 +1,7 @@
package com.dfsek.terra.api.platform.inventory;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.inventory.item.Damageable;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
public interface ItemStack extends Handle {
@ -13,4 +14,8 @@ public interface ItemStack extends Handle {
ItemMeta getItemMeta();
void setItemMeta(ItemMeta meta);
default boolean isDamageable() {
return getItemMeta() instanceof Damageable;
}
}

View File

@ -6,6 +6,8 @@ import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import java.io.File;
import java.util.UUID;
@ -17,20 +19,12 @@ public interface World extends Handle {
ChunkGenerator getGenerator();
String getName();
UUID getUID();
boolean isChunkGenerated(int x, int z);
Chunk getChunkAt(int x, int z);
default Chunk getChunkAt(Location location) {
return getChunkAt(location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
File getWorldFolder();
Block getBlockAt(int x, int y, int z);
default Block getBlockAt(Location l) {
@ -40,4 +34,12 @@ public interface World extends Handle {
Entity spawnEntity(Location location, EntityType entityType);
int getMinHeight();
default boolean isTerraWorld() {
return getGenerator().getHandle() instanceof GeneratorWrapper;
}
default TerraChunkGenerator getTerraGenerator() {
return ((GeneratorWrapper) getGenerator().getHandle()).getHandle();
}
}

View File

@ -34,8 +34,8 @@ public class DamageFunction implements LootFunction {
@Override
public ItemStack apply(ItemStack original, Random r) {
if(original == null) return null;
if(!original.isDamageable()) return original;
ItemMeta meta = original.getItemMeta();
if(!(meta instanceof Damageable)) return original;
double itemDurability = (r.nextDouble() * (max - min)) + min;
Damageable damage = (Damageable) meta;
damage.setDamage((int) (original.getType().getMaxDurability() - (itemDurability / 100) * original.getType().getMaxDurability()));

View File

@ -29,6 +29,7 @@ import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
import com.dfsek.terra.api.structures.structure.buffer.DirectBuffer;
import com.dfsek.terra.api.structures.structure.buffer.StructureBuffer;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.registry.config.FunctionRegistry;
import com.dfsek.terra.registry.config.LootRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
@ -39,6 +40,7 @@ import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Random;
import java.util.concurrent.ExecutionException;
@ -52,7 +54,7 @@ public class StructureScript {
public StructureScript(InputStream inputStream, TerraPlugin main, ScriptRegistry registry, LootRegistry lootRegistry, FunctionRegistry functionRegistry) throws ParseException {
Parser parser;
try {
parser = new Parser(IOUtils.toString(inputStream));
parser = new Parser(IOUtils.toString(inputStream, Charset.defaultCharset()));
} catch(IOException e) {
throw new RuntimeException(e);
}
@ -87,6 +89,12 @@ public class StructureScript {
.registerFunction("ceil", new UnaryNumberFunctionBuilder(number -> FastMath.ceil(number.doubleValue())))
.registerFunction("log", new UnaryNumberFunctionBuilder(number -> FastMath.log(number.doubleValue())))
.registerFunction("round", new UnaryNumberFunctionBuilder(number -> FastMath.round(number.doubleValue())))
.registerFunction("sin", new UnaryNumberFunctionBuilder(number -> FastMath.sin(number.doubleValue())))
.registerFunction("cos", new UnaryNumberFunctionBuilder(number -> FastMath.cos(number.doubleValue())))
.registerFunction("tan", new UnaryNumberFunctionBuilder(number -> FastMath.tan(number.doubleValue())))
.registerFunction("asin", new UnaryNumberFunctionBuilder(number -> FastMath.asin(number.doubleValue())))
.registerFunction("acos", new UnaryNumberFunctionBuilder(number -> FastMath.acos(number.doubleValue())))
.registerFunction("atan", new UnaryNumberFunctionBuilder(number -> FastMath.atan(number.doubleValue())))
.registerFunction("max", new BinaryNumberFunctionBuilder((number, number2) -> FastMath.max(number.doubleValue(), number2.doubleValue())))
.registerFunction("min", new BinaryNumberFunctionBuilder((number, number2) -> FastMath.min(number.doubleValue(), number2.doubleValue())));
@ -104,22 +112,31 @@ public class StructureScript {
* @param rotation Rotation of structure
* @return Whether generation was successful
*/
@SuppressWarnings("try")
public boolean execute(Location location, Random random, Rotation rotation) {
StructureBuffer buffer = new StructureBuffer(location);
boolean level = applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
buffer.paste();
return level;
try(ProfileFrame ignore = main.getProfiler().profile("terrascript:" + id)) {
StructureBuffer buffer = new StructureBuffer(location);
boolean level = applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
buffer.paste();
return level;
}
}
@SuppressWarnings("try")
public boolean execute(Location location, Chunk chunk, Random random, Rotation rotation) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
buffer.paste(chunk);
return buffer.succeeded();
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_chunk:" + id)) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
buffer.paste(chunk);
return buffer.succeeded();
}
}
@SuppressWarnings("try")
public boolean test(Location location, Random random, Rotation rotation) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
return buffer.succeeded();
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_test:" + id)) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
return buffer.succeeded();
}
}
private StructureBuffer computeBuffer(Location location, Random random, Rotation rotation) {
@ -134,13 +151,19 @@ public class StructureScript {
}
}
@SuppressWarnings("try")
public boolean executeInBuffer(Buffer buffer, Random random, Rotation rotation, int recursions) {
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, recursions));
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_recursive:" + id)) {
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, recursions));
}
}
@SuppressWarnings("try")
public boolean executeDirect(Location location, Random random, Rotation rotation) {
DirectBuffer buffer = new DirectBuffer(location);
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_direct:" + id)) {
DirectBuffer buffer = new DirectBuffer(location);
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
}
}
public String getId() {

View File

@ -19,6 +19,6 @@ public class BufferedEntity implements BufferedItem {
@Override
public void paste(Location origin) {
Entity entity = origin.clone().add(0.5, 0, 0.5).getWorld().spawnEntity(origin, type);
main.getEventManager().callEvent(new EntitySpawnEvent(main.getWorld(entity.getWorld()).getGenerator().getConfigPack(), entity, entity.getLocation()));
main.getEventManager().callEvent(new EntitySpawnEvent(entity.getWorld().getTerraGenerator().getConfigPack(), entity, entity.getLocation()));
}
}

View File

@ -32,7 +32,7 @@ public class BufferedLootApplication implements BufferedItem {
}
Container container = (Container) data;
LootPopulateEvent event = new LootPopulateEvent(block, container, table, main.getWorld(block.getLocation().getWorld()).getGenerator().getConfigPack(), structure);
LootPopulateEvent event = new LootPopulateEvent(block, container, table, block.getLocation().getWorld().getTerraGenerator().getConfigPack(), structure);
main.getEventManager().callEvent(event);
if(event.isCancelled()) return;
@ -40,7 +40,7 @@ public class BufferedLootApplication implements BufferedItem {
data.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply loot at " + origin + ": " + e.getMessage());
main.getDebugLogger().stack(e);
e.printStackTrace();
}
}
}

View File

@ -21,7 +21,7 @@ public class BufferedStateManipulator implements BufferedItem {
state.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply BlockState at " + origin + ": " + e.getMessage());
main.getDebugLogger().stack(e);
e.printStackTrace();
}
}
}

View File

@ -53,6 +53,7 @@ public class Transformer<F, T> {
private final LinkedHashMap<Transform<F, T>, List<Validator<T>>> transforms = new LinkedHashMap<>();
@SafeVarargs
@SuppressWarnings("varargs")
public final Builder<F, T> addTransform(Transform<F, T> transform, Validator<T>... validators) {
transforms.put(transform, Arrays.asList(validators));
return this;

View File

@ -1,9 +1,13 @@
package com.dfsek.terra.api.util;
import com.dfsek.terra.api.TerraPlugin;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@ -32,4 +36,12 @@ public class JarUtil {
}
}
}
public static JarFile getJarFile() throws URISyntaxException, IOException {
return new JarFile(new File(getJarURL().toURI()));
}
public static URL getJarURL() {
return TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation();
}
}

View File

@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileQueryCommand implements CommandTemplate {
@Inject
@ -21,8 +15,9 @@ public class ProfileQueryCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
player.sendMessage(world.getProfiler().getResultsFormatted());
StringBuilder data = new StringBuilder("Terra Profiler data dump: \n");
main.getProfiler().getTimings().forEach((id, timings) -> data.append(id).append(": ").append(timings.toString()).append('\n'));
main.logger().info(data.toString());
sender.sendMessage("Profiler data dumped to console.");
}
}

View File

@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileResetCommand implements CommandTemplate {
@Inject
@ -21,9 +15,7 @@ public class ProfileResetCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().reset();
player.sendMessage("Profiler reset.");
main.getProfiler().reset();
sender.sendMessage("Profiler reset.");
}
}

View File

@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileStartCommand implements CommandTemplate {
@Inject
@ -21,9 +15,7 @@ public class ProfileStartCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().setProfiling(true);
player.sendMessage("Profiling enabled.");
main.getProfiler().start();
sender.sendMessage("Profiling enabled.");
}
}

View File

@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileStopCommand implements CommandTemplate {
@Inject
@ -21,9 +15,7 @@ public class ProfileStopCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().setProfiling(false);
player.sendMessage("Profiling disabled.");
main.getProfiler().stop();
sender.sendMessage("Profiling disabled.");
}
}

View File

@ -69,12 +69,12 @@ public class PluginConfig implements ConfigTemplate {
ConfigLoader loader = new ConfigLoader();
loader.load(this, file);
if(dumpDefaultConfig) { // Don't dump default config if already loaded.
try(JarFile jar = new JarFile(new File(TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {
try(JarFile jar = main.getModJar()) {
JarUtil.copyResourcesToDirectory(jar, "packs", new File(main.getDataFolder(), "packs").toString());
} catch(IOException | URISyntaxException e) {
main.getDebugLogger().error("Failed to dump default config files!");
e.printStackTrace();
main.getDebugLogger().error("Report this to Terra!");
main.getDebugLogger().error("Either you're on Forge, or this is a bug. If it's the latter, report this to Terra!");
}
}
} catch(ConfigException | IOException e) {

View File

@ -9,9 +9,6 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import java.io.File;
import java.util.UUID;
public class DummyWorld implements World {
@Override
public Object getHandle() {
@ -33,31 +30,11 @@ public class DummyWorld implements World {
return () -> (GeneratorWrapper) () -> null;
}
@Override
public String getName() {
return "DUMMY";
}
@Override
public UUID getUID() {
return UUID.randomUUID();
}
@Override
public boolean isChunkGenerated(int x, int z) {
return false;
}
@Override
public Chunk getChunkAt(int x, int z) {
throw new UnsupportedOperationException("Cannot get chunk in DummyWorld");
}
@Override
public File getWorldFolder() {
throw new UnsupportedOperationException("Cannot get folder of DummyWorld");
}
@Override
public Block getBlockAt(int x, int y, int z) {
throw new UnsupportedOperationException("Cannot get block in DummyWorld");

View File

@ -1,5 +1,6 @@
package com.dfsek.terra.config.fileloaders;
import com.dfsek.tectonic.config.Configuration;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.util.GlueList;
@ -18,8 +19,12 @@ public abstract class Loader {
*
* @param consumer Something to do with the streams.
*/
public Loader then(ExceptionalConsumer<List<InputStream>> consumer) throws ConfigException {
consumer.accept(new GlueList<>(streams.values()));
public Loader then(ExceptionalConsumer<List<Configuration>> consumer) throws ConfigException {
List<Configuration> list = new GlueList<>();
streams.forEach((id, stream) -> {
list.add(new Configuration(stream, id));
});
consumer.accept(list);
return this;
}

View File

@ -17,7 +17,7 @@ public final class LangUtil {
public static void load(String langID, TerraPlugin main) {
Logger logger = main.logger();
File file = new File(main.getDataFolder(), "lang");
try(JarFile jar = new JarFile(new File(TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {
try(JarFile jar = main.getModJar()) {
copyResourcesToDirectory(jar, "lang", file.toString());
} catch(IOException | URISyntaxException e) {
main.getDebugLogger().error("Failed to dump language files!");

View File

@ -18,7 +18,7 @@ public class OreHolderLoader implements TypeLoader<OreHolder> {
Map<String, Object> map = (Map<String, Object>) o;
for(Map.Entry<String, Object> entry : map.entrySet()) {
holder.add(configLoader.loadClass(Ore.class, entry.getKey()), (OreConfig) configLoader.loadType(OreConfig.class, entry.getValue()));
holder.add(configLoader.loadClass(Ore.class, entry.getKey()), configLoader.loadClass(OreConfig.class, entry.getValue()), entry.getKey());
}
return holder;

View File

@ -237,13 +237,13 @@ public class ConfigPack implements LoaderRegistrar {
}).close();
loader
.open("carving", ".yml").then(streams -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.load(streams, CarverTemplate::new), main)).close()
.open("palettes", ".yml").then(streams -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.load(streams, PaletteTemplate::new), main)).close()
.open("ores", ".yml").then(streams -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.load(streams, OreTemplate::new), main)).close()
.open("structures/trees", ".yml").then(streams -> buildAll(new TreeFactory(), treeRegistry, abstractConfigLoader.load(streams, TreeTemplate::new), main)).close()
.open("structures/structures", ".yml").then(streams -> buildAll(new StructureFactory(), structureRegistry, abstractConfigLoader.load(streams, StructureTemplate::new), main)).close()
.open("flora", ".yml").then(streams -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.load(streams, FloraTemplate::new), main)).close()
.open("biomes", ".yml").then(streams -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.load(streams, () -> new BiomeTemplate(this, main)), main)).close();
.open("carving", ".yml").then(configs -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.loadConfigs(configs, CarverTemplate::new), main)).close()
.open("palettes", ".yml").then(configs -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.loadConfigs(configs, PaletteTemplate::new), main)).close()
.open("ores", ".yml").then(configs -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.loadConfigs(configs, OreTemplate::new), main)).close()
.open("structures/trees", ".yml").then(configs -> buildAll(new TreeFactory(), treeRegistry, abstractConfigLoader.loadConfigs(configs, TreeTemplate::new), main)).close()
.open("structures/structures", ".yml").then(configs -> buildAll(new StructureFactory(), structureRegistry, abstractConfigLoader.loadConfigs(configs, StructureTemplate::new), main)).close()
.open("flora", ".yml").then(configs -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.loadConfigs(configs, FloraTemplate::new), main)).close()
.open("biomes", ".yml").then(configs -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.loadConfigs(configs, () -> new BiomeTemplate(this, main)), main)).close();
main.getEventManager().callEvent(new ConfigPackPostLoadEvent(this));
main.logger().info("Loaded config pack \"" + template.getID() + "\" v" + template.getVersion() + " by " + template.getAuthor() + " in " + (System.nanoTime() - start) / 1000000D + "ms.");

View File

@ -1,36 +0,0 @@
package com.dfsek.terra.profiler;
/**
* Class to hold a profiler data value. Contains formatting method to highlight value based on desired range.
*/
public class DataHolder {
private final long desired;
private final DataType type;
private final double desiredRangePercent;
/**
* Constructs a DataHolder with a DataType and a desired value, including a percentage around the desired value considered acceptable
*
* @param type The type of data held in this instance.
* @param desired The desired value. This should be the average value of whatever is being measured.
* @param desiredRangePercent The percentage around the desired value to be considered acceptable.
*/
public DataHolder(DataType type, long desired, double desiredRangePercent) {
this.desired = desired;
this.type = type;
this.desiredRangePercent = desiredRangePercent;
}
/**
* Returns a String, formatted with Bungee ChatColors.<br>
* GREEN if the value is better than desired and outside of acceptable range.<br>
* YELLOW if the value is better or worse than desired, and within acceptable range.<br>
* RED if the value is worse than desired and outside of acceptable range.<br>
*
* @param data The data to format.
* @return String - The formatted data.
*/
public String getFormattedData(long data) {
return type.getFormatted(data);
}
}

View File

@ -1,24 +0,0 @@
package com.dfsek.terra.profiler;
import net.jafama.FastMath;
public enum DataType {
PERIOD_MILLISECONDS(Desire.LOW, 1000000, "ms"), PERIOD_NANOSECONDS(Desire.LOW, 1, "ns");
private final Desire desire;
private final long divisor;
private final String unit;
DataType(Desire d, long divisor, String unit) {
this.desire = d;
this.divisor = divisor;
this.unit = unit;
}
public String getFormatted(long value) {
return (double) FastMath.round(((double) value / divisor) * 100D) / 100D + unit;
}
public Desire getDesire() {
return desire;
}
}

View File

@ -1,10 +0,0 @@
package com.dfsek.terra.profiler;
/**
* Enum to represent the "goal" of a value, whether it is desirable for the value to be high (e.g. Frequency), or low (e.g. Period)
*/
public enum Desire {
LOW, HIGH
}

View File

@ -0,0 +1,24 @@
package com.dfsek.terra.profiler;
public class Frame {
private final String id;
private final long start;
public Frame(String id) {
this.id = id;
this.start = System.nanoTime();
}
public String getId() {
return id;
}
public long getStart() {
return start;
}
@Override
public String toString() {
return id;
}
}

View File

@ -1,87 +0,0 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.api.util.GlueList;
import net.jafama.FastMath;
import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;
/**
* Class to record and hold all data for a single type of measurement performed by the profiler.
*/
public class Measurement {
private final List<Long> measurements = new LinkedList<>();
private final long desirable;
private final DataType type;
private long min = Long.MAX_VALUE;
private long max = Long.MIN_VALUE;
/**
* Constructs a new Measurement with a desired value and DataType.
*
* @param desirable The desired value of the measurement.
* @param type The type of data the measurement is holding.
*/
public Measurement(long desirable, DataType type) {
this.desirable = desirable;
this.type = type;
}
public void record(long value) {
max = FastMath.max(value, max);
min = FastMath.min(value, min);
measurements.add(value);
}
public int size() {
return measurements.size();
}
public ProfileFuture beginMeasurement() {
ProfileFuture future = new ProfileFuture();
long current = System.nanoTime();
future.thenRun(() -> record(System.nanoTime() - current));
return future;
}
public void reset() {
min = Long.MAX_VALUE;
max = Long.MIN_VALUE;
measurements.clear();
}
public DataHolder getDataHolder() {
return new DataHolder(type, desirable, 0.25);
}
public long getMin() {
if(min == Long.MAX_VALUE) return 0;
return min;
}
public long getMax() {
if(max == Long.MIN_VALUE) return 0;
return max;
}
public long average() {
BigInteger running = BigInteger.valueOf(0);
List<Long> mTemp = new GlueList<>(measurements);
for(Long l : mTemp) {
running = running.add(BigInteger.valueOf(l));
}
if(measurements.size() == 0) return 0;
return running.divide(BigInteger.valueOf(measurements.size())).longValue();
}
public double getStdDev() {
return MathUtil.standardDeviation(new GlueList<>(measurements));
}
public int entries() {
return measurements.size();
}
}

View File

@ -0,0 +1,14 @@
package com.dfsek.terra.profiler;
public class ProfileFrame implements AutoCloseable {
private final Runnable action;
public ProfileFrame(Runnable action) {
this.action = action;
}
@Override
public void close() {
action.run();
}
}

View File

@ -1,18 +0,0 @@
package com.dfsek.terra.profiler;
import java.util.concurrent.CompletableFuture;
public class ProfileFuture extends CompletableFuture<Boolean> implements AutoCloseable {
public ProfileFuture() {
super();
}
public boolean complete() {
return super.complete(true);
}
@Override
public void close() {
this.complete();
}
}

View File

@ -0,0 +1,56 @@
package com.dfsek.terra.profiler;
import java.util.Map;
public interface Profiler {
/**
* Push a frame to this profiler.
*
* @param frame ID of frame.
*/
void push(String frame);
/**
* Pop a frame from this profiler.
*
* @param frame ID of frame. Must match ID
* at the top of the profiler stack.
*/
void pop(String frame);
/**
* Start profiling.
*/
void start();
/**
* Stop profiling.
*/
void stop();
/**
* Get the profiler data.
*
* @return Profiler data.
*/
Map<String, Timings> getTimings();
/**
* Return a {@link AutoCloseable} implementation that
* may be used in a try-with-resources statement for
* more intuitive profiling, with auto-push/pop.
*
* @param frame ID of frame.
* @return {@link AutoCloseable} implementation for use
* in try-with-resources.
*/
default ProfileFrame profile(String frame) {
push(frame);
return new ProfileFrame(() -> pop(frame));
}
/**
* Clear the profiler data.
*/
void reset();
}

View File

@ -0,0 +1,91 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.profiler.exception.MalformedStackException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
public class ProfilerImpl implements Profiler {
private static final ThreadLocal<Stack<Frame>> THREAD_STACK = ThreadLocal.withInitial(Stack::new);
private static final ThreadLocal<Map<String, List<Long>>> TIMINGS = ThreadLocal.withInitial(HashMap::new);
private final List<Map<String, List<Long>>> accessibleThreadMaps = new ArrayList<>();
private volatile boolean running = false;
private static boolean instantiated = false;
private static final ThreadLocal<Boolean> SAFE = ThreadLocal.withInitial(() -> false);
private static final ThreadLocal<MutableInteger> STACK_SIZE = ThreadLocal.withInitial(() -> new MutableInteger(0));
public ProfilerImpl() {
if(instantiated) throw new IllegalStateException("Only one instance of Profiler may exist!");
instantiated = true;
}
@Override
public void push(String frame) {
STACK_SIZE.get().increment();
if(running && SAFE.get()) {
Stack<Frame> stack = THREAD_STACK.get();
stack.push(new Frame(stack.isEmpty() ? frame : stack.peek().getId() + "." + frame));
} else SAFE.set(false);
}
@Override
public void pop(String frame) {
MutableInteger size = STACK_SIZE.get();
size.decrement();
if(running && SAFE.get()) {
long time = System.nanoTime();
Stack<Frame> stack = THREAD_STACK.get();
Map<String, List<Long>> timingsMap = TIMINGS.get();
if(timingsMap.size() == 0) {
synchronized(accessibleThreadMaps) {
accessibleThreadMaps.add(timingsMap);
}
}
Frame top = stack.pop();
if((stack.size() != 0 && !top.getId().endsWith("." + frame)) || (stack.size() == 0 && !top.getId().equals(frame)))
throw new MalformedStackException("Expected " + frame + ", found " + top);
List<Long> timings = timingsMap.computeIfAbsent(top.getId(), id -> new ArrayList<>());
timings.add(time - top.getStart());
}
if(size.get() == 0) SAFE.set(true);
}
@Override
public void start() {
running = true;
}
@Override
public void stop() {
running = false;
}
@Override
public Map<String, Timings> getTimings() {
Map<String, Timings> map = new HashMap<>();
accessibleThreadMaps.forEach(smap -> smap.forEach((key, list) -> {
String[] keys = key.split("\\.");
Timings timings = map.computeIfAbsent(keys[0], id -> new Timings());
for(int i = 1; i < keys.length; i++) {
timings = timings.getSubItem(keys[i]);
}
list.forEach(timings::addTime);
}));
return map;
}
@Override
public void reset() {
accessibleThreadMaps.forEach(Map::clear);
}
}

View File

@ -0,0 +1,73 @@
package com.dfsek.terra.profiler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Timings {
private final Map<String, Timings> subItems = new HashMap<>();
private final List<Long> timings = new ArrayList<>();
public void addTime(long time) {
timings.add(time);
}
public List<Long> getTimings() {
return timings;
}
public double average() {
return (double) timings.stream().reduce(0L, Long::sum) / timings.size();
}
public long max() {
return timings.stream().mapToLong(Long::longValue).max().orElse(0L);
}
public long min() {
return timings.stream().mapToLong(Long::longValue).min().orElse(0L);
}
public double sum() {
return timings.stream().mapToDouble(Long::doubleValue).sum();
}
public Timings getSubItem(String id) {
return subItems.computeIfAbsent(id, s -> new Timings());
}
public String toString(int indent, Timings parent, Set<Integer> branches) {
StringBuilder builder = new StringBuilder();
builder.append((double) min() / 1000000).append("ms min / ").append(average() / 1000000).append("ms avg / ")
.append((double) max() / 1000000).append("ms max (").append(timings.size()).append(" samples, ")
.append((sum() / parent.sum()) * 100).append("% of parent)");
List<String> frames = new ArrayList<>();
Set<Integer> newBranches = new HashSet<>(branches);
newBranches.add(indent);
subItems.forEach((id, timings) -> frames.add(id + ": " + timings.toString(indent + 1, this, newBranches)));
for(int i = 0; i < frames.size(); i++) {
builder.append('\n');
for(int j = 0; j < indent; j++) {
if(branches.contains(j)) builder.append("");
else builder.append(" ");
}
if(i == frames.size() - 1 && !frames.get(i).contains("\n")) builder.append("└───");
else builder.append("├───");
builder.append(frames.get(i));
}
return builder.toString();
}
@Override
public String toString() {
return toString(1, this, Collections.emptySet());
}
}

View File

@ -1,85 +0,0 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.world.TerraWorld;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.jafama.FastMath;
import java.util.Map;
public class WorldProfiler {
private final BiMap<String, Measurement> measures = HashBiMap.create();
private final World world;
private boolean isProfiling;
public WorldProfiler(World w) {
if(!TerraWorld.isTerraWorld(w))
throw new IllegalArgumentException("Attempted to instantiate profiler on non-Terra managed world!");
this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime")
.addMeasurement(new Measurement(10000000, DataType.PERIOD_MILLISECONDS), "TreeTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "OreTime")
.addMeasurement(new Measurement(5000000, DataType.PERIOD_MILLISECONDS), "CaveTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime");
isProfiling = false;
this.world = w;
}
public String getResultsFormatted() {
if(! isProfiling) return "Profiler is not currently running.";
StringBuilder result = new StringBuilder("Gaea World Profiler Results (Min / Avg / Max / Std Dev): \n");
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
result
.append(e.getKey())
.append(": ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMin()))
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().average()))
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMax()))
.append(" / ")
.append((double) FastMath.round((e.getValue().getStdDev() / 1000000) * 100D) / 100D)
.append("ms")
.append(" (x").append(e.getValue().size()).append(")\n");
}
return result.toString();
}
public void reset() {
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
e.getValue().reset();
}
}
public com.dfsek.terra.profiler.WorldProfiler addMeasurement(Measurement m, String name) {
measures.put(name, m);
return this;
}
public void setMeasurement(String id, long value) {
if(isProfiling) measures.get(id).record(value);
}
public ProfileFuture measure(String id) {
if(isProfiling) return measures.get(id).beginMeasurement();
else return null;
}
public String getID(Measurement m) {
return measures.inverse().get(m);
}
public boolean isProfiling() {
return isProfiling;
}
public void setProfiling(boolean enabled) {
this.isProfiling = enabled;
}
public World getWorld() {
return world;
}
}

View File

@ -0,0 +1,17 @@
package com.dfsek.terra.profiler.exception;
public class MalformedStackException extends ProfilerException {
private static final long serialVersionUID = -3009539681021691054L;
public MalformedStackException(String message) {
super(message);
}
public MalformedStackException(String message, Throwable cause) {
super(message, cause);
}
public MalformedStackException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,17 @@
package com.dfsek.terra.profiler.exception;
public class ProfilerException extends RuntimeException {
private static final long serialVersionUID = 8206737998791649002L;
public ProfilerException(String message) {
super(message);
}
public ProfilerException(String message, Throwable cause) {
super(message, cause);
}
public ProfilerException(Throwable cause) {
super(cause);
}
}

View File

@ -65,7 +65,9 @@ public class OpenRegistry<T> implements Registry<T> {
@Override
public T get(String identifier) {
return objects.get(identifier).getValue();
Entry<T> entry = objects.get(identifier);
if(entry == null) return null;
return entry.getValue();
}
@Override

View File

@ -68,10 +68,4 @@ public class FloraRegistry extends OpenRegistry<Flora> {
private BlockData data(String s) {
return main.getWorldHandle().createBlockData(s);
}
@Override
public Flora get(String identifier) {
return super.get(identifier);
}
}

View File

@ -13,7 +13,6 @@ import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.profiler.WorldProfiler;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import net.jafama.FastMath;
@ -21,33 +20,25 @@ public class TerraWorld {
private final BiomeProvider provider;
private final WorldConfig config;
private final boolean safe;
private final WorldProfiler profiler;
private final World world;
private final BlockData air;
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
if(!isTerraWorld(w)) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
if(!w.isTerraWorld()) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
this.world = w;
config = c.toWorldConfig(this);
this.provider = config.getProvider();
profiler = new WorldProfiler(w);
air = main.getWorldHandle().createBlockData("minecraft:air");
main.getEventManager().callEvent(new TerraWorldLoadEvent(this, c));
safe = true;
}
public static boolean isTerraWorld(World w) {
return w.getGenerator().getHandle() instanceof GeneratorWrapper;
}
public World getWorld() {
return world;
}
public TerraChunkGenerator getGenerator() {
return ((GeneratorWrapper) world.getGenerator().getHandle()).getHandle();
}
public BiomeProvider getBiomeProvider() {
return provider;
@ -61,9 +52,6 @@ public class TerraWorld {
return safe;
}
public WorldProfiler getProfiler() {
return profiler;
}
/**
* Get a block at an ungenerated location

View File

@ -15,7 +15,7 @@ import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
@ -94,7 +94,7 @@ public class DefaultChunkGenerator2D implements TerraChunkGenerator {
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_2d")) {
if(!tw.isSafe()) return chunk;
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);

View File

@ -23,7 +23,7 @@ import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.palette.SinglePalette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
@ -50,7 +50,6 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
private final Carver carver;
public DefaultChunkGenerator3D(ConfigPack c, TerraPlugin main) {
this.configPack = c;
this.main = main;
@ -104,9 +103,10 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
@Override
@SuppressWarnings({"try"})
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_3d")) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
if(!tw.isSafe()) return chunk;
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
@ -120,7 +120,7 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
int cx = xOrig + x;
int cz = zOrig + z;
TerraBiome b = grid.getBiome(xOrig + x, zOrig + z);
TerraBiome b = grid.getBiome(cx, cz);
BiomeTemplate c = ((UserDefinedBiome) b).getConfig();
int sea = c.getSeaLevel();
@ -227,17 +227,20 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
return false;
}
@SuppressWarnings({"try"})
static void biomes(@NotNull World world, int chunkX, int chunkZ, @NotNull BiomeGrid biome, TerraPlugin main) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
BiomeProvider grid = main.getWorld(world).getBiomeProvider();
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
int cx = xOrig + (x << 2);
int cz = zOrig + (z << 2);
TerraBiome b = grid.getBiome(cx, cz);
try(ProfileFrame ignore = main.getProfiler().profile("biomes")) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
BiomeProvider grid = main.getWorld(world).getBiomeProvider();
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
int cx = xOrig + (x << 2);
int cz = zOrig + (z << 2);
TerraBiome b = grid.getBiome(cx, cz);
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator(world).getBiomeNoise(), cx, 0, cz));
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator(world).getBiomeNoise(), cx, 0, cz));
}
}
}
}

View File

@ -25,7 +25,7 @@ public class SamplerCache {
public Sampler load(@NotNull Long key) {
int cx = (int) (key >> 32);
int cz = (int) key.longValue();
return world.getGenerator().createSampler(cx, cz, world.getBiomeProvider(), world.getWorld(), world.getConfig().getTemplate().getElevationBlend());
return world.getWorld().getTerraGenerator().createSampler(cx, cz, world.getBiomeProvider(), world.getWorld(), world.getConfig().getTemplate().getElevationBlend());
}
});
}

View File

@ -14,7 +14,7 @@ import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.config.templates.CarverTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import org.jetbrains.annotations.NotNull;
@ -38,7 +38,7 @@ public class CavePopulator implements TerraBlockPopulator, Chunkified {
TerraWorld tw = main.getWorld(world);
WorldHandle handle = main.getWorldHandle();
BlockData AIR = handle.createBlockData("minecraft:air");
try(ProfileFuture ignored = tw.getProfiler().measure("CaveTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("carving")) {
Random random = PopulationUtil.getRandom(chunk);
if(!tw.isSafe()) return;
WorldConfig config = tw.getConfig();
@ -49,38 +49,40 @@ public class CavePopulator implements TerraBlockPopulator, Chunkified {
Map<Location, BlockData> shiftCandidate = new HashMap<>();
Set<Block> updateNeeded = new HashSet<>();
c.carve(chunk.getX(), chunk.getZ(), world, (v, type) -> {
Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
BlockData m = b.getBlockData();
BlockType re = m.getBlockType();
switch(type) {
case CENTER:
if(template.getInner().canReplace(re)) {
b.setBlockData(template.getInner().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case WALL:
if(template.getOuter().canReplace(re)) {
b.setBlockData(template.getOuter().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case TOP:
if(template.getTop().canReplace(re)) {
b.setBlockData(template.getTop().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case BOTTOM:
if(template.getBottom().canReplace(re)) {
b.setBlockData(template.getBottom().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
try(ProfileFrame ignored = main.getProfiler().profile("carving:" + c.getConfig().getID())) {
Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
BlockData m = b.getBlockData();
BlockType re = m.getBlockType();
switch(type) {
case CENTER:
if(template.getInner().canReplace(re)) {
b.setBlockData(template.getInner().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case WALL:
if(template.getOuter().canReplace(re)) {
b.setBlockData(template.getOuter().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case TOP:
if(template.getTop().canReplace(re)) {
b.setBlockData(template.getTop().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case BOTTOM:
if(template.getBottom().canReplace(re)) {
b.setBlockData(template.getBottom().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
}
}
});
for(Map.Entry<Location, BlockData> entry : shiftCandidate.entrySet()) {
@ -93,7 +95,7 @@ public class CavePopulator implements TerraBlockPopulator, Chunkified {
if(template.getShift().get(entry.getValue().getBlockType()).contains(mut.getBlock().getBlockData().getBlockType())) {
mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(entry.getValue().getBlockType(), BlockType::getDefaultData), false);
}
} catch(NullPointerException ignore) {
} catch(NullPointerException ignored) {
}
}
for(Block b : updateNeeded) {

View File

@ -8,7 +8,7 @@ import com.dfsek.terra.api.util.world.PopulationUtil;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.flora.FloraLayer;
import org.jetbrains.annotations.NotNull;
@ -32,7 +32,7 @@ public class FloraPopulator implements TerraBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("FloraTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("flora")) {
if(tw.getConfig().getTemplate().disableFlora()) return;
if(!tw.isSafe()) return;

View File

@ -10,7 +10,7 @@ import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import org.jetbrains.annotations.NotNull;
@ -27,7 +27,7 @@ public class OrePopulator implements TerraBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("OreTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("ore")) {
if(tw.getConfig().getTemplate().disableOres()) return;
if(!tw.isSafe()) return;
@ -40,11 +40,13 @@ public class OrePopulator implements TerraBlockPopulator {
BiomeTemplate config = ((UserDefinedBiome) b).getConfig();
int finalCx = cx;
int finalCz = cz;
config.getOreHolder().forEach((ore, oreConfig) -> {
int amount = oreConfig.getAmount().get(random);
for(int i = 0; i < amount; i++) {
Vector3 location = new Vector3(random.nextInt(16) + 16 * finalCx, oreConfig.getHeight().get(random), random.nextInt(16) + 16 * finalCz);
ore.generate(location, chunk, random);
config.getOreHolder().forEach((id, orePair) -> {
try(ProfileFrame ignored = main.getProfiler().profile("ore:" + id)) {
int amount = orePair.getRight().getAmount().get(random);
for(int i = 0; i < amount; i++) {
Vector3 location = new Vector3(random.nextInt(16) + 16 * finalCx, orePair.getRight().getHeight().get(random), random.nextInt(16) + 16 * finalCz);
orePair.getLeft().generate(location, chunk, random);
}
}
});
}

View File

@ -11,9 +11,8 @@ import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.TerraStructure;
import net.jafama.FastMath;
@ -32,7 +31,7 @@ public class StructurePopulator implements TerraBlockPopulator, Chunkified {
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("StructureTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("structure")) {
if(tw.getConfig().getTemplate().disableStructures()) return;
int cx = (chunk.getX() << 4);

View File

@ -8,7 +8,7 @@ import com.dfsek.terra.api.util.world.PopulationUtil;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.tree.TreeLayer;
import net.jafama.FastMath;
@ -32,7 +32,7 @@ public class TreePopulator implements TerraBlockPopulator {
@SuppressWarnings("try")
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("TreeTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("tree")) {
if(tw.getConfig().getTemplate().disableTrees()) return;
if(!tw.isSafe()) return;
@ -42,8 +42,9 @@ public class TreePopulator implements TerraBlockPopulator {
for(int z = 0; z < 16; z += 2) {
UserDefinedBiome biome = (UserDefinedBiome) provider.getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z);
for(TreeLayer layer : biome.getConfig().getTrees()) {
if(layer.getDensity() >= random.nextDouble() * 100)
if(layer.getDensity() >= random.nextDouble() * 100) {
layer.place(chunk, new Vector2(offset(random, x), offset(random, z)));
}
}
}
}

View File

@ -16,7 +16,6 @@ public abstract class Ore {
protected TerraPlugin main;
public Ore(BlockData material, MaterialSet replaceable, boolean applyGravity, TerraPlugin main) {
this.material = material;
this.replaceable = replaceable;
this.applyGravity = applyGravity;

View File

@ -1,6 +1,7 @@
package com.dfsek.terra.world.population.items.ores;
import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.api.util.generic.pair.ImmutablePair;
import java.util.List;
import java.util.function.BiConsumer;
@ -11,22 +12,24 @@ import java.util.function.BiConsumer;
public class OreHolder {
private final List<Entry> entries = new GlueList<>();
public void forEach(BiConsumer<Ore, OreConfig> consumer) {
entries.forEach(entry -> consumer.accept(entry.getOre(), entry.getConfig()));
public void forEach(BiConsumer<String, ImmutablePair<Ore, OreConfig>> consumer) {
entries.forEach(entry -> consumer.accept(entry.getId(), ImmutablePair.of(entry.getOre(), entry.getConfig())));
}
public OreHolder add(Ore ore, OreConfig config) {
entries.add(new Entry(ore, config));
public OreHolder add(Ore ore, OreConfig config, String id) {
entries.add(new Entry(ore, config, id));
return this;
}
private static final class Entry {
private final Ore ore;
private final OreConfig config;
private final String id;
private Entry(Ore ore, OreConfig config) {
private Entry(Ore ore, OreConfig config, String id) {
this.ore = ore;
this.config = config;
this.id = id;
}
public OreConfig getConfig() {
@ -36,5 +39,9 @@ public class OreHolder {
public Ore getOre() {
return ore;
}
public String getId() {
return id;
}
}
}

View File

@ -41,6 +41,7 @@ import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.AbstractableTemplate;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.registry.config.BiomeRegistry;
import com.dfsek.terra.registry.config.NoiseRegistry;
import com.dfsek.terra.world.TerraWorld;
@ -143,6 +144,11 @@ public class DistributionTest {
return null;
}
@Override
public Profiler getProfiler() {
return null;
}
@Override
public void register(TypeRegistry registry) {
@ -159,7 +165,7 @@ public class DistributionTest {
new GenericLoaders(MAIN).register(loader);
BiomeRegistry biomeRegistry = new BiomeRegistry();
folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.load(inputStreams, TestBiome::new), MAIN));
folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.loadConfigs(inputStreams, TestBiome::new), MAIN));
BiomeProviderTemplate template = new BiomeProviderTemplate();
ConfigLoader pipeLoader = new ConfigLoader()

View File

@ -46,7 +46,7 @@ public class ImageTest {
OpenRegistry<TerraBiome> biomeRegistry = new OpenRegistry<TerraBiome>() {
};
folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.load(inputStreams, TestBiome::new), null));
folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.loadConfigs(inputStreams, TestBiome::new), null));
return new ImageBiomeProvider(biomeRegistry.entries(), ImageIO.read(ImageTest.class.getResourceAsStream("/map.jpg")), 1, ImageBiomeProvider.Align.CENTER);
}

View File

@ -0,0 +1,63 @@
package profiler;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.profiler.ProfilerImpl;
public class ProfilerTest {
private static final Profiler PROFILER = new ProfilerImpl();
//@Test
public static void main(String... a) throws InterruptedException {
//PROFILER.start();
for(int i = 0; i < 1000; i++) {
doThing();
}
for(int i = 0; i < 100; i++) {
doThirdOtherThing();
}
for(int i = 0; i < 100; i++) {
doOtherThing();
}
PROFILER.stop();
PROFILER.push("thing");
PROFILER.push("thing2");
PROFILER.start();
PROFILER.pop("thing2");
PROFILER.pop("thing");
PROFILER.push("thing4");
PROFILER.pop("thing4");
PROFILER.getTimings().forEach((id, timings) -> {
System.out.println(id + ": " + timings.toString());
});
}
private static void doThing() throws InterruptedException {
PROFILER.push("thing");
Thread.sleep(1);
doOtherThing();
thing4();
PROFILER.pop("thing");
}
private static void doOtherThing() throws InterruptedException {
PROFILER.push("thing2");
Thread.sleep(2);
doThirdOtherThing();
thing4();
PROFILER.pop("thing2");
}
private static void doThirdOtherThing() throws InterruptedException {
PROFILER.push("thing3");
Thread.sleep(2);
PROFILER.pop("thing3");
}
private static void thing4() throws InterruptedException {
PROFILER.push("thing4");
Thread.sleep(2);
PROFILER.pop("thing4");
}
}

View File

@ -13,6 +13,7 @@ import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -20,7 +21,7 @@ import java.util.Map;
public class ParserTest {
@Test
public void parse() throws IOException, ParseException {
Parser parser = new Parser(IOUtils.toString(getClass().getResourceAsStream("/test.tesf")));
Parser parser = new Parser(IOUtils.toString(getClass().getResourceAsStream("/test.tesf"), Charset.defaultCharset()));
parser.registerFunction("test", new FunctionBuilder<Test1>() {
@Override

10
gradle.properties Normal file
View File

@ -0,0 +1,10 @@
# Magic options for more perf
org.gradle.jvmargs=-Xmx2048M -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC
org.gradle.vfs.watch=true
kapt.use.worker.api=true
kapt.include.compile.classpath=false
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.warning.mode=all
#org.gradle.logging.level=info
org.gradle.configureondemand=true

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
org.gradle.jvmargs=-Xmx4096m

View File

@ -70,8 +70,8 @@ fun installServer(dir: String) {
// Cloning test setup.
gitClone("https://github.com/PolyhedralDev/WorldGenTestServer")
// Copying plugins
Files.move(Paths.get("WorldGenTestServer/plugins"),
Paths.get("$testDir/$dir/plugins"),
Files.move(file("WorldGenTestServer/plugins").toPath(),
file("$testDir/$dir/plugins").toPath(),
StandardCopyOption.REPLACE_EXISTING)
// Copying config
val serverText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/server.properties").readText()

View File

@ -36,12 +36,15 @@ import com.dfsek.terra.bukkit.listeners.TerraListener;
import com.dfsek.terra.bukkit.task.BukkitTaskScheduler;
import com.dfsek.terra.bukkit.util.PaperUtil;
import com.dfsek.terra.bukkit.world.BukkitBiome;
import com.dfsek.terra.bukkit.world.BukkitWorld;
import com.dfsek.terra.commands.CommandUtil;
import com.dfsek.terra.config.GenericLoaders;
import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.profiler.ProfilerImpl;
import com.dfsek.terra.registry.master.AddonRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.world.TerraWorld;
@ -66,6 +69,8 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
private final Map<World, TerraWorld> worldMap = new HashMap<>();
private final Map<String, ConfigPack> worlds = new HashMap<>();
private final Profiler profiler = new ProfilerImpl();
private final TaskScheduler scheduler = new BukkitTaskScheduler(this);
private final ConfigRegistry registry = new ConfigRegistry();
@ -145,6 +150,11 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
Bukkit.getScheduler().runTask(this, task);
}
@Override
public Profiler getProfiler() {
return profiler;
}
@Override
public TaskScheduler getScheduler() {
return scheduler;
@ -268,14 +278,15 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
return checkedRegistry;
}
public TerraWorld getWorld(World w) {
if(!TerraWorld.isTerraWorld(w))
public TerraWorld getWorld(World world) {
BukkitWorld w = (BukkitWorld) world;
if(!w.isTerraWorld())
throw new IllegalArgumentException("Not a Terra world! " + w.getGenerator());
if(!worlds.containsKey(w.getName())) {
getLogger().warning("Unexpected world load detected: \"" + w.getName() + "\"");
return new TerraWorld(w, ((TerraChunkGenerator) w.getGenerator().getHandle()).getConfigPack(), this);
}
return worldMap.computeIfAbsent(w, world -> new TerraWorld(w, worlds.get(w.getName()), this));
return worldMap.computeIfAbsent(w, w2 -> new TerraWorld(w, worlds.get(w.getName()), this));
}
@Override

View File

@ -3,19 +3,11 @@ package com.dfsek.terra.bukkit.generator;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.bukkit.population.PopulationManager;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.bukkit.world.BukkitBiomeGrid;
import com.dfsek.terra.profiler.DataType;
import com.dfsek.terra.profiler.Measurement;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.CavePopulator;
import com.dfsek.terra.world.population.FloraPopulator;
import com.dfsek.terra.world.population.OrePopulator;
import com.dfsek.terra.world.population.StructurePopulator;
import com.dfsek.terra.world.population.TreePopulator;
import org.bukkit.World;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
@ -24,13 +16,10 @@ import org.jetbrains.annotations.NotNull;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements GeneratorWrapper {
@ -63,7 +52,7 @@ public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements Gener
}
public static synchronized void fixChunk(Chunk c) {
if(!TerraWorld.isTerraWorld(c.getWorld())) throw new IllegalArgumentException();
if(!c.getWorld().isTerraWorld()) throw new IllegalArgumentException();
popMap.get(c.getWorld()).checkNeighbors(c.getX(), c.getZ(), c.getWorld());
}
@ -76,8 +65,6 @@ public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements Gener
e.printStackTrace();
}
popMap.put(w, popMan);
main.getWorld(w).getProfiler().addMeasurement(new Measurement(15000000, DataType.PERIOD_MILLISECONDS), "PopulationManagerTime");
popMan.attachProfiler(main.getWorld(w).getProfiler());
needsLoad = false;
}

View File

@ -44,7 +44,7 @@ public class CommonListener implements Listener {
public void onSaplingGrow(StructureGrowEvent e) {
if(e.isCancelled()) return;
World bukkit = BukkitAdapter.adapt(e.getWorld());
if(!TerraWorld.isTerraWorld(bukkit)) return;
if(!bukkit.isTerraWorld()) return;
TerraWorld tw = main.getWorld(bukkit);
WorldConfig c = tw.getConfig();
if(c.getTemplate().isDisableSaplings()) return;

View File

@ -18,7 +18,7 @@ public class PaperListener implements Listener {
@EventHandler
public void onStructureLocate(StructureLocateEvent e) {
if(!TerraWorld.isTerraWorld(BukkitAdapter.adapt(e.getWorld()))) return;
if(!BukkitAdapter.adapt(e.getWorld()).isTerraWorld()) return;
e.setResult(null); // Assume no result.
String name = "minecraft:" + e.getType().getName();
main.getDebugLogger().info("Overriding structure location for \"" + name + "\"");

View File

@ -34,7 +34,7 @@ public class SpigotListener implements Listener {
Entity entity = e.getEntity();
if(e.getEntityType().equals(EntityType.ENDER_SIGNAL)) {
main.getDebugLogger().info("Detected Ender Signal...");
if(!TerraWorld.isTerraWorld(BukkitAdapter.adapt(e.getEntity().getWorld()))) return;
if(!BukkitAdapter.adapt(e.getEntity().getWorld()).isTerraWorld()) return;
TerraWorld tw = main.getWorld(BukkitAdapter.adapt(e.getEntity().getWorld()));
EnderSignal signal = (EnderSignal) entity;
TerraStructure config = tw.getConfig().getStructureRegistry().get(tw.getConfig().getTemplate().getLocatable().get("STRONGHOLD"));
@ -53,7 +53,7 @@ public class SpigotListener implements Listener {
@EventHandler
public void onCartographerChange(VillagerAcquireTradeEvent e) {
if(!TerraWorld.isTerraWorld(BukkitAdapter.adapt(e.getEntity().getWorld()))) return;
if(!BukkitAdapter.adapt(e.getEntity().getWorld()).isTerraWorld()) return;
if(!(e.getEntity() instanceof Villager)) return;
if(((Villager) e.getEntity()).getProfession().equals(Villager.Profession.CARTOGRAPHER)) {
main.logger().severe("Prevented server crash by stopping Cartographer villager from spawning.");
@ -65,7 +65,7 @@ public class SpigotListener implements Listener {
@EventHandler
public void onCartographerLevel(VillagerCareerChangeEvent e) {
if(!TerraWorld.isTerraWorld(BukkitAdapter.adapt(e.getEntity().getWorld()))) return;
if(!BukkitAdapter.adapt(e.getEntity().getWorld()).isTerraWorld()) return;
if(e.getProfession().equals(Villager.Profession.CARTOGRAPHER)) {
main.logger().severe("Prevented server crash by stopping Cartographer villager from spawning.");
main.logger().severe("Please upgrade to Paper, which has a StructureLocateEvent that fixes this issue");

View File

@ -2,6 +2,7 @@ package com.dfsek.terra.bukkit.population;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.bukkit.world.BukkitWorld;
import java.io.Serializable;
import java.util.UUID;
@ -21,7 +22,7 @@ public class ChunkCoordinate implements Serializable {
public ChunkCoordinate(Chunk c) {
this.x = c.getX();
this.z = c.getZ();
this.worldID = c.getWorld().getUID();
this.worldID = ((BukkitWorld) c.getWorld()).getUID();
}
public UUID getWorldID() {

View File

@ -1,20 +0,0 @@
package com.dfsek.terra.bukkit.population;
import com.dfsek.terra.api.platform.world.World;
import java.io.File;
public class Gaea {
private static boolean debug;
public static File getGaeaFolder(World w) {
File f = new File(w.getWorldFolder(), "gaea");
f.mkdirs();
return f;
}
public static boolean isDebug() {
return debug;
}
}

View File

@ -5,12 +5,11 @@ import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.bukkit.TerraBukkitPlugin;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.WorldProfiler;
import com.dfsek.terra.bukkit.world.BukkitWorld;
import com.dfsek.terra.profiler.ProfileFrame;
import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull;
@ -26,39 +25,36 @@ public class PopulationManager extends BlockPopulator {
private final TerraChunkGenerator generator;
private final HashSet<ChunkCoordinate> needsPop = new HashSet<>();
private final TerraPlugin main;
private WorldProfiler profiler;
public PopulationManager(TerraChunkGenerator generator, TerraPlugin main) {
this.generator = generator;
this.main = main;
}
private ProfileFuture measure() {
if(profiler != null) return profiler.measure("PopulationManagerTime");
return null;
}
public void attachProfiler(WorldProfiler p) {
this.profiler = p;
}
@SuppressWarnings("unchecked")
public synchronized void saveBlocks(World w) throws IOException {
File f = new File(Gaea.getGaeaFolder(w), "chunks.bin");
File f = new File(getDataFolder(w), "chunks.bin");
f.createNewFile();
SerializationUtil.toFile((HashSet<ChunkCoordinate>) needsPop.clone(), f);
}
@SuppressWarnings("unchecked")
public synchronized void loadBlocks(World w) throws IOException, ClassNotFoundException {
File f = new File(Gaea.getGaeaFolder(w), "chunks.bin");
File f = new File(getDataFolder(w), "chunks.bin");
needsPop.addAll((HashSet<ChunkCoordinate>) SerializationUtil.fromFile(f));
}
public static File getDataFolder(World w) {
File f = new File(((BukkitWorld) w).getWorldFolder(), "gaea");
f.mkdirs();
return f;
}
// Synchronize to prevent chunks from being queued for population multiple times.
public synchronized void checkNeighbors(int x, int z, World w) {
ChunkCoordinate c = new ChunkCoordinate(x, z, w.getUID());
public synchronized void checkNeighbors(int x, int z, World world) {
BukkitWorld w = (BukkitWorld) world;
ChunkCoordinate c = new ChunkCoordinate(x, z, (w).getUID());
if(w.isChunkGenerated(x + 1, z)
&& w.isChunkGenerated(x - 1, z)
&& w.isChunkGenerated(x, z + 1)
@ -78,8 +74,9 @@ public class PopulationManager extends BlockPopulator {
}
@Override
@SuppressWarnings("try")
public void populate(org.bukkit.@NotNull World world, @NotNull Random random, org.bukkit.@NotNull Chunk source) {
try(ProfileFuture ignored = measure()) {
try(ProfileFrame ignore = main.getProfiler().profile("popman")) {
Chunk chunk = BukkitAdapter.adapt(source);
needsPop.add(new ChunkCoordinate(chunk));
int x = chunk.getX();

View File

@ -5,8 +5,10 @@ import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.profiler.ProfileFrame;
import org.bukkit.TreeType;
import java.util.Locale;
import java.util.Random;
public class BukkitTree implements Tree {
@ -40,8 +42,11 @@ public class BukkitTree implements Tree {
}
@Override
@SuppressWarnings("try")
public boolean plant(Location l, Random r) {
return ((BukkitWorld) l.getWorld()).getHandle().generateTree(BukkitAdapter.adapt(l), delegate);
try(ProfileFrame ignore = main.getProfiler().profile("bukkit_tree:" + delegate.toString().toLowerCase(Locale.ROOT))) {
return ((BukkitWorld) l.getWorld()).getHandle().generateTree(BukkitAdapter.adapt(l), delegate);
}
}
@Override

View File

@ -37,17 +37,14 @@ public class BukkitWorld implements World {
return new BukkitChunkGenerator(delegate.getGenerator());
}
@Override
public String getName() {
return delegate.getName();
}
@Override
public UUID getUID() {
return delegate.getUID();
}
@Override
public boolean isChunkGenerated(int x, int z) {
return delegate.isChunkGenerated(x, z);
}
@ -57,7 +54,6 @@ public class BukkitWorld implements World {
return BukkitAdapter.adapt(delegate.getChunkAt(x, z));
}
@Override
public File getWorldFolder() {
return delegate.getWorldFolder();
}

View File

@ -4,6 +4,7 @@ import com.dfsek.terra.api.platform.block.state.SerialState;
import com.dfsek.terra.api.platform.block.state.Sign;
import org.jetbrains.annotations.NotNull;
@SuppressWarnings("deprecation")
public class BukkitSign extends BukkitBlockState implements Sign {
protected BukkitSign(org.bukkit.block.Sign block) {
super(block);

View File

@ -33,6 +33,7 @@ dependencies {
configure<LoomGradleExtension> {
accessWidener("src/main/resources/terra.accesswidener")
refmapName = "terra-refmap.json"
}
val remapped = tasks.register<RemapJarTask>("remapShadedJar") {
@ -46,12 +47,12 @@ val remapped = tasks.register<RemapJarTask>("remapShadedJar") {
}
tasks.register<TaskModrinthUpload>("publishModrinth") {
tasks.register<TaskModrinthUpload>("publishModrinthFabric") {
dependsOn("remapShadedJar")
group = "fabric"
token = System.getenv("MODRINTH_SECRET")
projectId = "FIlZB9L0"
versionNumber = project.version.toString()
versionNumber = "${project.version}-fabric"
uploadFile = remapped.get().archiveFile.get().asFile
releaseType = "beta"
addGameVersion("1.16.4")

View File

@ -0,0 +1,224 @@
package com.dfsek.terra.fabric;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.Axis;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Bisected;
import com.dfsek.terra.api.platform.block.data.Slab;
import com.dfsek.terra.api.platform.block.data.Stairs;
import com.dfsek.terra.api.platform.block.state.Container;
import com.dfsek.terra.api.platform.block.state.MobSpawner;
import com.dfsek.terra.api.platform.block.state.Sign;
import com.dfsek.terra.fabric.block.FabricBlockData;
import com.dfsek.terra.fabric.block.data.FabricDirectional;
import com.dfsek.terra.fabric.block.data.FabricMultipleFacing;
import com.dfsek.terra.fabric.block.data.FabricOrientable;
import com.dfsek.terra.fabric.block.data.FabricRotatable;
import com.dfsek.terra.fabric.block.data.FabricSlab;
import com.dfsek.terra.fabric.block.data.FabricStairs;
import com.dfsek.terra.fabric.block.data.FabricWaterlogged;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.LootableContainerBlockEntity;
import net.minecraft.block.entity.MobSpawnerBlockEntity;
import net.minecraft.block.entity.SignBlockEntity;
import net.minecraft.block.enums.BlockHalf;
import net.minecraft.block.enums.SlabType;
import net.minecraft.block.enums.StairShape;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.WorldAccess;
import java.util.Arrays;
public final class FabricAdapter {
public static BlockPos adapt(Vector3 v) {
return new BlockPos(v.getBlockX(), v.getBlockY(), v.getBlockZ());
}
public static Vector3 adapt(BlockPos pos) {
return new Vector3(pos.getX(), pos.getY(), pos.getZ());
}
public static FabricBlockData adapt(BlockState state) {
if(state.contains(Properties.STAIR_SHAPE)) return new FabricStairs(state);
if(state.contains(Properties.SLAB_TYPE)) return new FabricSlab(state);
if(state.contains(Properties.AXIS)) return new FabricOrientable(state, Properties.AXIS);
if(state.contains(Properties.HORIZONTAL_AXIS)) return new FabricOrientable(state, Properties.HORIZONTAL_AXIS);
if(state.contains(Properties.ROTATION)) return new FabricRotatable(state);
if(state.contains(Properties.FACING)) return new FabricDirectional(state, Properties.FACING);
if(state.contains(Properties.HOPPER_FACING)) return new FabricDirectional(state, Properties.HOPPER_FACING);
if(state.contains(Properties.HORIZONTAL_FACING)) return new FabricDirectional(state, Properties.HORIZONTAL_FACING);
if(state.getProperties().containsAll(Arrays.asList(Properties.NORTH, Properties.SOUTH, Properties.EAST, Properties.WEST)))
return new FabricMultipleFacing(state);
if(state.contains(Properties.WATERLOGGED)) return new FabricWaterlogged(state);
return new FabricBlockData(state);
}
public static Direction adapt(BlockFace face) {
switch(face) {
case NORTH:
return Direction.NORTH;
case WEST:
return Direction.WEST;
case SOUTH:
return Direction.SOUTH;
case EAST:
return Direction.EAST;
case UP:
return Direction.UP;
case DOWN:
return Direction.DOWN;
default:
throw new IllegalArgumentException("Illegal direction: " + face);
}
}
public static com.dfsek.terra.api.platform.block.state.BlockState adapt(com.dfsek.terra.api.platform.block.Block block) {
WorldAccess worldAccess = (WorldAccess) block.getLocation().getWorld();
BlockEntity entity = worldAccess.getBlockEntity(adapt(block.getLocation().toVector()));
if(entity instanceof SignBlockEntity) {
return (Sign) entity;
} else if(entity instanceof MobSpawnerBlockEntity) {
return (MobSpawner) entity;
} else if(entity instanceof LootableContainerBlockEntity) {
return (Container) entity;
}
return null;
}
public static Stairs.Shape adapt(StairShape shape) {
switch(shape) {
case OUTER_RIGHT:
return Stairs.Shape.OUTER_RIGHT;
case INNER_RIGHT:
return Stairs.Shape.INNER_RIGHT;
case OUTER_LEFT:
return Stairs.Shape.OUTER_LEFT;
case INNER_LEFT:
return Stairs.Shape.INNER_LEFT;
case STRAIGHT:
return Stairs.Shape.STRAIGHT;
default:
throw new IllegalStateException();
}
}
public static Bisected.Half adapt(BlockHalf half) {
switch(half) {
case BOTTOM:
return Bisected.Half.BOTTOM;
case TOP:
return Bisected.Half.TOP;
default:
throw new IllegalStateException();
}
}
public static BlockFace adapt(Direction direction) {
switch(direction) {
case DOWN:
return BlockFace.DOWN;
case UP:
return BlockFace.UP;
case WEST:
return BlockFace.WEST;
case EAST:
return BlockFace.EAST;
case NORTH:
return BlockFace.NORTH;
case SOUTH:
return BlockFace.SOUTH;
default:
throw new IllegalStateException();
}
}
public static Slab.Type adapt(SlabType type) {
switch(type) {
case BOTTOM:
return Slab.Type.BOTTOM;
case TOP:
return Slab.Type.TOP;
case DOUBLE:
return Slab.Type.DOUBLE;
default:
throw new IllegalStateException();
}
}
public static StairShape adapt(Stairs.Shape shape) {
switch(shape) {
case STRAIGHT:
return StairShape.STRAIGHT;
case INNER_LEFT:
return StairShape.INNER_LEFT;
case OUTER_LEFT:
return StairShape.OUTER_LEFT;
case INNER_RIGHT:
return StairShape.INNER_RIGHT;
case OUTER_RIGHT:
return StairShape.OUTER_RIGHT;
default:
throw new IllegalStateException();
}
}
public static BlockHalf adapt(Bisected.Half half) {
switch(half) {
case TOP:
return BlockHalf.TOP;
case BOTTOM:
return BlockHalf.BOTTOM;
default:
throw new IllegalStateException();
}
}
public static SlabType adapt(Slab.Type type) {
switch(type) {
case DOUBLE:
return SlabType.DOUBLE;
case TOP:
return SlabType.TOP;
case BOTTOM:
return SlabType.BOTTOM;
default:
throw new IllegalStateException();
}
}
public static Axis adapt(Direction.Axis axis) {
switch(axis) {
case X:
return Axis.X;
case Y:
return Axis.Y;
case Z:
return Axis.Z;
default:
throw new IllegalStateException();
}
}
public static Direction.Axis adapt(Axis axis) {
switch(axis) {
case Z:
return Direction.Axis.Z;
case Y:
return Direction.Axis.Y;
case X:
return Direction.Axis.X;
default:
throw new IllegalStateException();
}
}
}

View File

@ -18,6 +18,7 @@ import com.dfsek.terra.api.event.annotations.Priority;
import com.dfsek.terra.api.event.events.config.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.Tree;
@ -44,12 +45,22 @@ import com.dfsek.terra.fabric.world.*;
import com.dfsek.terra.fabric.world.features.PopulatorFeature;
import com.dfsek.terra.fabric.world.generator.FabricChunkGenerator;
import com.dfsek.terra.fabric.world.generator.FabricChunkGeneratorWrapper;
import com.dfsek.terra.fabric.handle.FabricItemHandle;
import com.dfsek.terra.fabric.handle.FabricWorldHandle;
import com.dfsek.terra.fabric.mixin.access.BiomeEffectsAccessor;
import com.dfsek.terra.fabric.mixin.access.GeneratorTypeAccessor;
import com.dfsek.terra.fabric.generation.TerraBiomeSource;
import com.dfsek.terra.fabric.generation.PopulatorFeature;
import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.profiler.ProfilerImpl;
import com.dfsek.terra.registry.exception.DuplicateEntryException;
import com.dfsek.terra.registry.master.AddonRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.world.TerraWorld;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
@ -95,6 +106,9 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
private final Map<Long, TerraWorld> worldMap = new HashMap<>();
private final EventManager eventManager = new TerraEventManager(this);
private final GenericLoaders genericLoaders = new GenericLoaders(this);
private final Profiler profiler = new ProfilerImpl();
private final Logger logger = new Logger() {
private final org.apache.logging.log4j.Logger logger = LogManager.getLogger();
@ -145,7 +159,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
public TerraWorld getWorld(World world) {
return worldMap.computeIfAbsent(world.getSeed(), w -> {
logger.info("Loading world " + w);
return new TerraWorld(world, ((FabricChunkGeneratorWrapper) ((FabricChunkGenerator) world.getGenerator()).getHandle()).getPack(), this);
return new TerraWorld(world, ((FabricChunkGeneratorWrapper) world.getGenerator()).getPack(), this);
});
}
@ -236,37 +250,37 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
genericLoaders.register(registry);
registry
.registerLoader(BlockData.class, (t, o, l) -> worldHandle.createBlockData((String) o))
.registerLoader(com.dfsek.terra.api.platform.world.Biome.class, (t, o, l) -> new FabricBiome(biomeFixer.translate((String) o)));
.registerLoader(com.dfsek.terra.api.platform.world.Biome.class, (t, o, l) -> biomeFixer.translate((String) o));
}
private Biome createBiome(BiomeBuilder biome) {
BiomeTemplate template = biome.getTemplate();
Map<String, Integer> colors = template.getColors();
Biome vanilla = ((FabricBiome) new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0)).getHandle();
Biome vanilla = (Biome) (new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0)).getHandle();
GenerationSettings.Builder generationSettings = new GenerationSettings.Builder();
generationSettings.surfaceBuilder(SurfaceBuilder.DEFAULT.withConfig(new TernarySurfaceConfig(Blocks.GRASS_BLOCK.getDefaultState(), Blocks.DIRT.getDefaultState(), Blocks.GRAVEL.getDefaultState()))); // It needs a surfacebuilder, even though we dont use it.
generationSettings.feature(GenerationStep.Feature.VEGETAL_DECORATION, POPULATOR_CONFIGURED_FEATURE);
BiomeEffectsAccessor accessor = (BiomeEffectsAccessor) vanilla.getEffects();
BiomeEffects.Builder effects = new BiomeEffects.Builder()
.waterColor(colors.getOrDefault("water", vanilla.getEffects().waterColor))
.waterFogColor(colors.getOrDefault("water-fog", vanilla.getEffects().waterFogColor))
.fogColor(colors.getOrDefault("fog", vanilla.getEffects().fogColor))
.skyColor(colors.getOrDefault("sky", vanilla.getEffects().skyColor))
.grassColorModifier(vanilla.getEffects().grassColorModifier);
.waterColor(colors.getOrDefault("water", accessor.getWaterColor()))
.waterFogColor(colors.getOrDefault("water-fog", accessor.getWaterFogColor()))
.fogColor(colors.getOrDefault("fog", accessor.getFogColor()))
.skyColor(colors.getOrDefault("sky", accessor.getSkyColor()))
.grassColorModifier(accessor.getGrassColorModifier());
if(colors.containsKey("grass")) {
effects.grassColor(colors.get("grass"));
} else {
vanilla.getEffects().grassColor.ifPresent(effects::grassColor);
accessor.getGrassColor().ifPresent(effects::grassColor);
}
vanilla.getEffects().foliageColor.ifPresent(effects::foliageColor);
if(colors.containsKey("foliage")) {
effects.foliageColor(colors.get("foliage"));
} else {
vanilla.getEffects().foliageColor.ifPresent(effects::foliageColor);
accessor.getFoliageColor().ifPresent(effects::foliageColor);
}
return new Biome.Builder()
@ -319,7 +333,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
};
//noinspection ConstantConditions
((GeneratorTypeAccessor) generatorType).setTranslationKey(new LiteralText("Terra:" + pack.getTemplate().getID()));
GeneratorTypeAccessor.getVALUES().add(generatorType);
GeneratorTypeAccessor.getValues().add(generatorType);
});
}
@ -351,7 +365,11 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
private RequiredArgumentBuilder<ServerCommandSource, String> assemble(RequiredArgumentBuilder<ServerCommandSource, String> in, CommandManager manager) {
return in.suggests((context, builder) -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = FabricAdapter.adapt(context.getSource());
CommandSender sender = (CommandSender) context.getSource();
try {
sender = (Entity) context.getSource().getEntityOrThrow();
} catch(CommandSyntaxException ignore) {
}
try {
manager.tabComplete(args.remove(0), sender, args).forEach(builder::suggest);
} catch(CommandException e) {
@ -360,8 +378,13 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
return builder.buildFuture();
}).executes(context -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = (CommandSender) context.getSource();
try {
manager.execute(args.remove(0), FabricAdapter.adapt(context.getSource()), args);
sender = (Entity) context.getSource().getEntityOrThrow();
} catch(CommandSyntaxException ignore) {
}
try {
manager.execute(args.remove(0), sender, args);
} catch(CommandException e) {
context.getSource().sendError(new LiteralText(e.getMessage()));
}
@ -383,6 +406,11 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
return eventManager;
}
@Override
public Profiler getProfiler() {
return profiler;
}
@Override
public TaskScheduler getScheduler() {
return scheduler;
@ -430,7 +458,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
private void injectTree(CheckedRegistry<Tree> registry, String id, ConfiguredFeature<?, ?> tree) {
try {
registry.add(id, new FabricTree(tree));
registry.add(id, (Tree) tree);
} catch(DuplicateEntryException ignore) {
}
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.fabric.world.block;
package com.dfsek.terra.fabric.block;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
@ -6,9 +6,8 @@ import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.fabric.world.FabricAdapter;
import com.dfsek.terra.fabric.world.block.state.FabricBlockState;
import com.dfsek.terra.fabric.world.handles.world.FabricWorldAccess;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.fabric.FabricAdapter;
import net.minecraft.block.FluidBlock;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.WorldAccess;
@ -35,7 +34,7 @@ public class FabricBlock implements Block {
@Override
public BlockState getState() {
return FabricBlockState.newInstance(this);
return FabricAdapter.adapt(this);
}
@Override
@ -51,7 +50,7 @@ public class FabricBlock implements Block {
@Override
public Location getLocation() {
return FabricAdapter.adapt(delegate.position).toLocation(new FabricWorldAccess(delegate.worldAccess));
return FabricAdapter.adapt(delegate.position).toLocation((World) delegate.worldAccess);
}
@Override

View File

@ -1,11 +1,10 @@
package com.dfsek.terra.fabric.world.block;
package com.dfsek.terra.fabric.block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.fabric.world.FabricAdapter;
import com.dfsek.terra.fabric.mixin.access.StateAccessor;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.state.State;
import net.minecraft.util.registry.Registry;
import java.util.stream.Collectors;
@ -19,7 +18,7 @@ public class FabricBlockData implements BlockData {
@Override
public BlockType getBlockType() {
return FabricAdapter.adapt(delegate.getBlock());
return (BlockType) delegate.getBlock();
}
@Override
@ -41,7 +40,7 @@ public class FabricBlockData implements BlockData {
StringBuilder data = new StringBuilder(Registry.BLOCK.getId(delegate.getBlock()).toString());
if(!delegate.getEntries().isEmpty()) {
data.append('[');
data.append(delegate.getEntries().entrySet().stream().map(State.PROPERTY_MAP_PRINTER).collect(Collectors.joining(",")));
data.append(delegate.getEntries().entrySet().stream().map(StateAccessor.getPropertyMapPrinter()).collect(Collectors.joining(",")));
data.append(']');
}
return data.toString();

View File

@ -1,7 +1,7 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.data.AnaloguePowerable;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.block.FabricBlockData;
import net.minecraft.block.BlockState;
/**

View File

@ -1,9 +1,9 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Directional;
import com.dfsek.terra.fabric.world.FabricAdapter;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.block.FabricBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.DirectionProperty;

View File

@ -1,8 +1,8 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.MultipleFacing;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.block.FabricBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.Properties;

View File

@ -1,8 +1,9 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.Axis;
import com.dfsek.terra.api.platform.block.data.Orientable;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.block.FabricBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.util.math.Direction;
@ -26,11 +27,11 @@ public class FabricOrientable extends FabricBlockData implements Orientable {
@Override
public Axis getAxis() {
return FabricEnumAdapter.adapt(getHandle().get(property));
return FabricAdapter.adapt(getHandle().get(property));
}
@Override
public void setAxis(Axis axis) {
delegate = delegate.with(property, FabricEnumAdapter.adapt(axis));
delegate = delegate.with(property, FabricAdapter.adapt(axis));
}
}

View File

@ -1,8 +1,8 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Rotatable;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.block.FabricBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.Properties;

View File

@ -1,6 +1,7 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.data.Slab;
import com.dfsek.terra.fabric.FabricAdapter;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.Properties;
@ -11,11 +12,11 @@ public class FabricSlab extends FabricWaterlogged implements Slab {
@Override
public Type getType() {
return FabricEnumAdapter.adapt(delegate.get(Properties.SLAB_TYPE));
return FabricAdapter.adapt(delegate.get(Properties.SLAB_TYPE));
}
@Override
public void setType(Type type) {
delegate = delegate.with(Properties.SLAB_TYPE, FabricEnumAdapter.adapt(type));
delegate = delegate.with(Properties.SLAB_TYPE, FabricAdapter.adapt(type));
}
}

View File

@ -1,7 +1,8 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Stairs;
import com.dfsek.terra.fabric.FabricAdapter;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.Properties;
@ -12,31 +13,31 @@ public class FabricStairs extends FabricWaterlogged implements Stairs {
@Override
public Shape getShape() {
return FabricEnumAdapter.adapt(getHandle().get(Properties.STAIR_SHAPE));
return FabricAdapter.adapt(getHandle().get(Properties.STAIR_SHAPE));
}
@Override
public void setShape(Shape shape) {
super.delegate = getHandle().with(Properties.STAIR_SHAPE, FabricEnumAdapter.adapt(shape));
super.delegate = getHandle().with(Properties.STAIR_SHAPE, FabricAdapter.adapt(shape));
}
@Override
public Half getHalf() {
return FabricEnumAdapter.adapt(getHandle().get(Properties.BLOCK_HALF));
return FabricAdapter.adapt(getHandle().get(Properties.BLOCK_HALF));
}
@Override
public void setHalf(Half half) {
super.delegate = getHandle().with(Properties.BLOCK_HALF, FabricEnumAdapter.adapt(half));
super.delegate = getHandle().with(Properties.BLOCK_HALF, FabricAdapter.adapt(half));
}
@Override
public BlockFace getFacing() {
return FabricEnumAdapter.adapt(getHandle().get(Properties.HORIZONTAL_FACING));
return FabricAdapter.adapt(getHandle().get(Properties.HORIZONTAL_FACING));
}
@Override
public void setFacing(BlockFace facing) {
super.delegate = getHandle().with(Properties.HORIZONTAL_FACING, FabricEnumAdapter.adapt(facing));
super.delegate = getHandle().with(Properties.HORIZONTAL_FACING, FabricAdapter.adapt(facing));
}
}

View File

@ -1,7 +1,7 @@
package com.dfsek.terra.fabric.world.block.data;
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.data.Waterlogged;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.block.FabricBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.Properties;

View File

@ -1,7 +0,0 @@
package com.dfsek.terra.fabric.command;
public class FabricCommandAdapter {
public static void register() {
}
}

View File

@ -1,17 +0,0 @@
package com.dfsek.terra.fabric.command;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class StringListArgumentType implements ArgumentType<List<String>> {
@Override
public List<String> parse(StringReader reader) {
final String text = reader.getRemaining();
reader.setCursor(reader.getTotalLength());
return new ArrayList<>(Arrays.asList(text.split(" ")));
}
}

View File

@ -1,28 +1,29 @@
package com.dfsek.terra.fabric.world.generator;
package com.dfsek.terra.fabric.generation;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkData;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.locate.AsyncStructureFinder;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.dfsek.terra.fabric.world.TerraBiomeSource;
import com.dfsek.terra.fabric.world.handles.world.FabricSeededWorldAccess;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.generation.generators.DefaultChunkGenerator3D;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.population.CavePopulator;
import com.dfsek.terra.world.population.FloraPopulator;
import com.dfsek.terra.world.population.OrePopulator;
import com.dfsek.terra.world.population.StructurePopulator;
import com.dfsek.terra.world.population.TreePopulator;
import com.dfsek.terra.world.population.items.TerraStructure;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.jafama.FastMath;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.structure.StructureManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.BlockView;
import net.minecraft.world.ChunkRegion;
import net.minecraft.world.Heightmap;
@ -34,6 +35,12 @@ import net.minecraft.world.gen.StructureAccessor;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.chunk.StructuresConfig;
import net.minecraft.world.gen.chunk.VerticalBlockSample;
import net.minecraft.world.gen.feature.StructureFeature;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class FabricChunkGeneratorWrapper extends ChunkGenerator implements GeneratorWrapper {
private final long seed;
@ -80,6 +87,28 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener
}
@Nullable
@Override
public BlockPos locateStructure(ServerWorld world, StructureFeature<?> feature, BlockPos center, int radius, boolean skipExistingChunks) {
String name = Objects.requireNonNull(Registry.STRUCTURE_FEATURE.getId(feature)).toString();
TerraWorld terraWorld = TerraFabricPlugin.getInstance().getWorld((World) world);
TerraStructure located = pack.getStructure(pack.getTemplate().getLocatable().get(name));
if(located != null) {
CompletableFuture<BlockPos> result = new CompletableFuture<>();
AsyncStructureFinder finder = new AsyncStructureFinder(terraWorld.getBiomeProvider(), located, FabricAdapter.adapt(center).toLocation((World) world), 0, 500, location -> {
result.complete(FabricAdapter.adapt(location));
}, TerraFabricPlugin.getInstance());
finder.run(); // Do this synchronously.
try {
return result.get();
} catch(InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
TerraFabricPlugin.getInstance().logger().warning("No overrides are defined for \"" + name + "\"");
return null;
}
@Override
public void generateFeatures(ChunkRegion region, StructureAccessor accessor) {
super.generateFeatures(region, accessor);
@ -87,8 +116,7 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener
@Override
public void populateNoise(WorldAccess world, StructureAccessor accessor, Chunk chunk) {
FabricSeededWorldAccess worldAccess = new FabricSeededWorldAccess(world, seed, this);
delegate.generateChunkData(worldAccess, new FastRandom(), chunk.getPos().x, chunk.getPos().z, new FabricChunkData(chunk));
delegate.generateChunkData((World) world, new FastRandom(), chunk.getPos().x, chunk.getPos().z, (ChunkData) chunk);
}
@Override

View File

@ -1,10 +1,8 @@
package com.dfsek.terra.fabric.world.features;
package com.dfsek.terra.fabric.generation;
import com.dfsek.terra.fabric.world.generator.FabricChunkGenerator;
import com.dfsek.terra.fabric.world.generator.FabricChunkGeneratorWrapper;
import com.dfsek.terra.fabric.world.handles.FabricWorld;
import com.dfsek.terra.fabric.world.handles.chunk.FabricChunkWorldAccess;
import com.dfsek.terra.fabric.world.handles.world.FabricWorldAccess;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper;
import com.mojang.serialization.Codec;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.StructureWorldAccess;
@ -25,9 +23,7 @@ public class PopulatorFeature extends Feature<DefaultFeatureConfig> {
@Override
public boolean generate(StructureWorldAccess world, ChunkGenerator chunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config) {
FabricChunkGeneratorWrapper gen = (FabricChunkGeneratorWrapper) chunkGenerator;
FabricChunkWorldAccess chunk = new FabricChunkWorldAccess(world, pos.getX() >> 4, pos.getZ() >> 4);
FabricWorld world1 = new FabricWorld(world.toServerWorld(), new FabricChunkGenerator(chunkGenerator));
gen.getHandle().getPopulators().forEach(populator -> populator.populate(world1, chunk));
gen.getHandle().getPopulators().forEach(populator -> populator.populate((World) world, (Chunk) world));
return true;
}
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.fabric.world;
package com.dfsek.terra.fabric.generation;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;

View File

@ -1,9 +1,8 @@
package com.dfsek.terra.fabric.inventory;
package com.dfsek.terra.fabric.handle;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.inventory.Item;
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
import com.dfsek.terra.fabric.world.FabricAdapter;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.command.argument.ItemStackArgumentType;
@ -18,7 +17,7 @@ public class FabricItemHandle implements ItemHandle {
@Override
public Item createItem(String data) {
try {
return FabricAdapter.adapt(new ItemStackArgumentType().parse(new StringReader(data)).getItem());
return (Item) new ItemStackArgumentType().parse(new StringReader(data)).getItem();
} catch(CommandSyntaxException e) {
throw new IllegalArgumentException("Invalid item data \"" + data + "\"", e);
}
@ -26,11 +25,11 @@ public class FabricItemHandle implements ItemHandle {
@Override
public Enchantment getEnchantment(String id) {
return FabricAdapter.adapt(Registry.ENCHANTMENT.get(Identifier.tryParse(id)));
return (Enchantment) (Registry.ENCHANTMENT.get(Identifier.tryParse(id)));
}
@Override
public Set<Enchantment> getEnchantments() {
return Registry.ENCHANTMENT.stream().map(FabricAdapter::adapt).collect(Collectors.toSet());
return Registry.ENCHANTMENT.stream().map(enchantment -> (Enchantment) enchantment).collect(Collectors.toSet());
}
}

View File

@ -1,8 +1,9 @@
package com.dfsek.terra.fabric.world;
package com.dfsek.terra.fabric.handle;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.fabric.world.block.FabricBlockData;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.block.FabricBlockData;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.block.BlockState;
@ -30,6 +31,6 @@ public class FabricWorldHandle implements WorldHandle {
public EntityType getEntity(String id) {
Identifier identifier = Identifier.tryParse(id);
if(identifier == null) identifier = Identifier.tryParse("minecraft:" + id.toLowerCase(Locale.ROOT));
return FabricAdapter.adapt(Registry.ENTITY_TYPE.get(identifier));
return (EntityType) Registry.ENTITY_TYPE.get(identifier);
}
}

View File

@ -1,35 +0,0 @@
package com.dfsek.terra.fabric.inventory;
import com.dfsek.terra.api.platform.inventory.Inventory;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.fabric.world.FabricAdapter;
import net.minecraft.item.Items;
public class FabricInventory implements Inventory {
private final net.minecraft.inventory.Inventory delegate;
public FabricInventory(net.minecraft.inventory.Inventory delegate) {
this.delegate = delegate;
}
@Override
public net.minecraft.inventory.Inventory getHandle() {
return delegate;
}
@Override
public int getSize() {
return delegate.size();
}
@Override
public ItemStack getItem(int slot) {
net.minecraft.item.ItemStack itemStack = delegate.getStack(slot);
return itemStack.getItem() == Items.AIR ? null : FabricAdapter.adapt(itemStack);
}
@Override
public void setItem(int slot, ItemStack newStack) {
delegate.setStack(slot, FabricAdapter.adapt(newStack));
}
}

View File

@ -2,8 +2,8 @@ package com.dfsek.terra.fabric.mixin;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.dfsek.terra.fabric.world.TerraBiomeSource;
import com.dfsek.terra.fabric.world.generator.FabricChunkGeneratorWrapper;
import com.dfsek.terra.fabric.generation.TerraBiomeSource;
import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper;
import com.google.common.base.MoreObjects;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
@ -13,16 +13,17 @@ import net.minecraft.world.dimension.DimensionOptions;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.GeneratorOptions;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Properties;
import java.util.Random;
// Mixins commented out until loom fixes multi-project builds.
//@Mixin(GeneratorOptions.class)
public class MixinGeneratorOptions {
//@Inject(method = "fromProperties(Lnet/minecraft/util/registry/DynamicRegistryManager;Ljava/util/Properties;)Lnet/minecraft/world/gen/GeneratorOptions;", at = @At("HEAD"), cancellable = true)
@Mixin(GeneratorOptions.class)
public abstract class GeneratorOptionsMixin {
@Inject(method = "fromProperties(Lnet/minecraft/util/registry/DynamicRegistryManager;Ljava/util/Properties;)Lnet/minecraft/world/gen/GeneratorOptions;", at = @At("HEAD"), cancellable = true)
private static void fromProperties(DynamicRegistryManager dynamicRegistryManager, Properties properties, CallbackInfoReturnable<GeneratorOptions> cir) {
if(properties.get("level-type") == null) {
return;

View File

@ -0,0 +1,31 @@
package com.dfsek.terra.fabric.mixin.access;
import net.minecraft.world.biome.BiomeEffects;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Optional;
@Mixin(BiomeEffects.class)
public interface BiomeEffectsAccessor {
@Accessor("fogColor")
int getFogColor();
@Accessor("waterColor")
int getWaterColor();
@Accessor("waterFogColor")
int getWaterFogColor();
@Accessor("skyColor")
int getSkyColor();
@Accessor("foliageColor")
Optional<Integer> getFoliageColor();
@Accessor("grassColor")
Optional<Integer> getGrassColor();
@Accessor("grassColorModifier")
BiomeEffects.GrassColorModifier getGrassColorModifier();
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.fabric.mixin;
package com.dfsek.terra.fabric.mixin.access;
import net.minecraft.client.world.GeneratorType;
import net.minecraft.text.Text;
@ -10,12 +10,12 @@ import java.util.List;
@Mixin(GeneratorType.class)
public interface GeneratorTypeAccessor {
@Accessor
static List<GeneratorType> getVALUES() {
@Accessor("VALUES")
static List<GeneratorType> getValues() {
throw new UnsupportedOperationException();
}
@Mutable
@Accessor
@Accessor("translationKey")
void setTranslationKey(Text translationKey);
}

View File

@ -0,0 +1,12 @@
package com.dfsek.terra.fabric.mixin.access;
import net.minecraft.util.Identifier;
import net.minecraft.world.MobSpawnerLogic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(MobSpawnerLogic.class)
public interface MobSpawnerLogicAccessor {
@Invoker("getEntityId")
Identifier callGetEntityId();
}

View File

@ -0,0 +1,17 @@
package com.dfsek.terra.fabric.mixin.access;
import net.minecraft.state.State;
import net.minecraft.state.property.Property;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
import java.util.function.Function;
@Mixin(State.class)
public interface StateAccessor {
@Accessor("PROPERTY_MAP_PRINTER")
static Function<Map.Entry<Property<?>, Comparable<?>>, String> getPropertyMapPrinter() {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,14 @@
package com.dfsek.terra.fabric.mixin.implementations;
import net.minecraft.world.biome.Biome;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Biome.class)
@Implements(@Interface(iface = com.dfsek.terra.api.platform.world.Biome.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class BiomeMixin {
public Object terra$getHandle() {
return this;
}
}

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