diff --git a/.gitignore b/.gitignore index c93edc41f..63dda4360 100644 --- a/.gitignore +++ b/.gitignore @@ -245,4 +245,7 @@ nbdist/ /run/ -**/testDir/ \ No newline at end of file +**/testDir/ + +platforms/**/run/** + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bbb72ecad..b876ff487 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,7 +63,8 @@ to [Terra global moderation team](CODE_OF_CONDUCT.md#Reporting). ## I don't want to read this whole thing I just have a question!!! -> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below. +> **Note:** Please don't file an issue to ask a question. You'll get faster +> results by using the resources below. We have an official discord server where you can request help from various users @@ -103,7 +104,9 @@ you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report) . -> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one. +> **Note:** If you find a **Closed** issue that seems like it is the same thing +> that you're experiencing, open a new issue and include a link to the original +> issue in the body of your new one. #### Before Submitting A Bug Report diff --git a/build.gradle.kts b/build.gradle.kts index 2938b5688..de1b02560 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,8 @@ preRelease(true) -versionProjects(":common:api", version("6.1.2")) -versionProjects(":common:implementation", version("6.1.2")) -versionProjects(":platforms", version("6.1.2")) +versionProjects(":common:api", version("6.2.0")) +versionProjects(":common:implementation", version("6.2.0")) +versionProjects(":platforms", version("6.2.0")) allprojects { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 21036749f..d6fbe2a8f 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -15,7 +15,9 @@ buildscript { repositories { mavenCentral() gradlePluginPortal() - maven { url = uri("https://repo.codemc.org/repository/maven-public") } + maven("https://repo.codemc.org/repository/maven-public") { + name = "CodeMC" + } maven("https://papermc.io/repo/repository/maven-public/") { name = "PaperMC" } diff --git a/buildSrc/src/main/kotlin/AddonConfig.kt b/buildSrc/src/main/kotlin/AddonConfig.kt index ec585ba8e..b4dda3bca 100644 --- a/buildSrc/src/main/kotlin/AddonConfig.kt +++ b/buildSrc/src/main/kotlin/AddonConfig.kt @@ -12,30 +12,30 @@ import kotlin.streams.asStream */ fun Project.addonDir(dir: File, task: Task) { val moveAddons = tasks.register("moveAddons" + task.name) { - dependsOn("compileAddons") - doLast { - dir.parentFile.mkdirs() - matchingAddons(dir) { - it.name.startsWith("Terra-") // Assume everything that starts with Terra- is a core addon. - }.forEach { - println("Deleting old addon: " + it.absolutePath) - it.delete() - } - forSubProjects(":common:addons") { - val jar = tasks.named("shadowJar").get() as ShadowJar - - val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else "" - val target = File(dir, boot + jar.archiveFileName.get()) - - val base = "${jar.archiveBaseName.get()}-${version}" - - println("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base") - - jar.archiveFile.orNull?.asFile?.copyTo(target) - } + dependsOn("compileAddons") + doLast { + dir.parentFile.mkdirs() + matchingAddons(dir) { + it.name.startsWith("Terra-") // Assume everything that starts with Terra- is a core addon. + }.forEach { + println("Deleting old addon: " + it.absolutePath) + it.delete() + } + forSubProjects(":common:addons") { + val jar = tasks.named("shadowJar").get() as ShadowJar + + val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else "" + val target = File(dir, boot + jar.archiveFileName.get()) + + val base = "${jar.archiveBaseName.get()}-${version}" + + println("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base") + + jar.archiveFile.orNull?.asFile?.copyTo(target) } - } + + } task.dependsOn(moveAddons) } diff --git a/buildSrc/src/main/kotlin/DependencyConfig.kt b/buildSrc/src/main/kotlin/DependencyConfig.kt index ecc0a8229..b0e7d32c4 100644 --- a/buildSrc/src/main/kotlin/DependencyConfig.kt +++ b/buildSrc/src/main/kotlin/DependencyConfig.kt @@ -30,10 +30,24 @@ fun Project.configureDependencies() { repositories { mavenCentral() gradlePluginPortal() - maven("https://maven.fabricmc.net/") - maven("https://repo.codemc.org/repository/maven-public") - maven("https://repo.codemc.io/repository/nms/") - maven("https://papermc.io/repo/repository/maven-public/") + maven("https://maven.fabricmc.net/") { + name = "FabricMC" + } + maven("https://repo.codemc.org/repository/maven-public") { + name = "CodeMC" + } + maven("https://papermc.io/repo/repository/maven-public/") { + name = "PaperMC" + } + maven("https://files.minecraftforge.net/maven/") { + name = "Forge" + } + maven("https://maven.quiltmc.org/repository/release/") { + name = "Quilt" + } + maven("https://jitpack.io") { + name = "JitPack" + } } dependencies { diff --git a/buildSrc/src/main/kotlin/DistributionConfig.kt b/buildSrc/src/main/kotlin/DistributionConfig.kt index df8d88d0f..56fe68ad7 100644 --- a/buildSrc/src/main/kotlin/DistributionConfig.kt +++ b/buildSrc/src/main/kotlin/DistributionConfig.kt @@ -7,12 +7,9 @@ import java.nio.file.Files import java.nio.file.StandardCopyOption import org.gradle.api.DefaultTask import org.gradle.api.Project -import org.gradle.api.Task import org.gradle.api.plugins.BasePluginExtension -import org.gradle.jvm.tasks.Jar import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.creating import org.gradle.kotlin.dsl.extra import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.named @@ -55,7 +52,7 @@ fun Project.configureDistribution() { println("Packaging addon ${jar.archiveFileName.get()} to $dest. size: ${jar.archiveFile.get().asFile.length() / 1024}KB") val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else "" - val addonPath = fs.getPath("/addons/$boot${jar.archiveFileName.get()}"); + val addonPath = fs.getPath("/addons/$boot${jar.archiveFileName.get()}") if (!Files.exists(addonPath)) { Files.createDirectories(addonPath.parent) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 05b7f8a64..28ca98ca0 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -4,7 +4,7 @@ object Versions { const val paralithic = "0.7.0" const val strata = "1.1.1" - const val cloud = "1.7.0-SNAPSHOT" + const val cloud = "1.7.0" const val slf4j = "1.7.36" const val log4j_slf4j_impl = "2.14.1" @@ -18,18 +18,40 @@ object Versions { } object Fabric { - const val fabricLoader = "0.14.2" - const val fabricAPI = "0.55.1+1.19" + const val fabricLoader = "0.14.8" + const val fabricAPI = "0.57.0+1.19" + } + + object Quilt { + const val quiltLoader = "0.17.0" + const val fabricApi = "2.0.0-beta.4+0.57.0-1.19" + } + + object Mod { + const val mixin = "0.11.2+mixin.0.8.5" + const val minecraft = "1.19" const val yarn = "$minecraft+build.1" - const val permissionsAPI = "0.1-SNAPSHOT" - const val mixin = "0.11.2+mixin.0.8.5" - const val loom = "0.11-SNAPSHOT" + const val fabricLoader = "0.14.2" + + const val architecuryLoom = "0.12.0-SNAPSHOT" + const val architecturyPlugin = "3.4-SNAPSHOT" + + const val loomQuiltflower = "1.7.1" + + const val lazyDfu = "0.1.2" + } + + object Forge { + const val forge = "${Mod.minecraft}-41.0.63" + const val burningwave = "12.53.0" } object Bukkit { - const val paper = "1.18-R0.1-SNAPSHOT" + const val paper = "1.18.2-R0.1-SNAPSHOT" const val paperLib = "1.0.5" + const val minecraft = "1.19" + const val reflectionRemapper = "0.1.0-SNAPSHOT" } object Sponge { @@ -37,4 +59,11 @@ object Versions { const val mixin = "0.8.2" const val minecraft = "1.17.1" } + + object CLI { + const val nbt = "6.1" + const val logback = "1.2.9" + const val commonsIO = "2.7" + const val guava = "31.0.1-jre" + } } \ No newline at end of file diff --git a/common/addons/biome-provider-extrusion/build.gradle.kts b/common/addons/biome-provider-extrusion/build.gradle.kts new file mode 100644 index 000000000..7615a16d0 --- /dev/null +++ b/common/addons/biome-provider-extrusion/build.gradle.kts @@ -0,0 +1,6 @@ +version = version("1.0.0") + +dependencies { + compileOnlyApi(project(":common:addons:manifest-addon-loader")) + compileOnlyApi(project(":common:addons:biome-query-api")) +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BaseBiomeColumn.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BaseBiomeColumn.java new file mode 100644 index 000000000..6dcad812f --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BaseBiomeColumn.java @@ -0,0 +1,51 @@ +package com.dfsek.terra.addons.biome.extrusion; + +import com.dfsek.terra.api.util.Column; +import com.dfsek.terra.api.world.biome.Biome; + + +class BaseBiomeColumn implements Column { + private final BiomeExtrusionProvider biomeProvider; + private final Biome base; + private final int min; + private final int max; + + private final int x; + private final int z; + private final long seed; + + protected BaseBiomeColumn(BiomeExtrusionProvider biomeProvider, Biome base, int min, int max, int x, int z, long seed) { + this.biomeProvider = biomeProvider; + this.base = base; + this.min = min; + this.max = max; + this.x = x; + this.z = z; + this.seed = seed; + } + + @Override + public int getMinY() { + return min; + } + + @Override + public int getMaxY() { + return max; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getZ() { + return z; + } + + @Override + public Biome get(int y) { + return biomeProvider.extrude(base, x, y, z, seed); + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionAddon.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionAddon.java new file mode 100644 index 000000000..cd4b1c9a4 --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionAddon.java @@ -0,0 +1,67 @@ +package com.dfsek.terra.addons.biome.extrusion; + +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; + +import java.util.function.Supplier; + +import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; +import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome; +import com.dfsek.terra.addons.biome.extrusion.config.BiomeExtrusionTemplate; +import com.dfsek.terra.addons.biome.extrusion.config.ReplaceableBiomeLoader; +import com.dfsek.terra.addons.biome.extrusion.config.extrusions.ReplaceExtrusionTemplate; +import com.dfsek.terra.addons.biome.extrusion.config.extrusions.SetExtrusionTemplate; +import com.dfsek.terra.addons.manifest.api.AddonInitializer; +import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; +import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; +import com.dfsek.terra.api.event.functional.FunctionalEventHandler; +import com.dfsek.terra.api.inject.annotations.Inject; +import com.dfsek.terra.api.registry.CheckedRegistry; +import com.dfsek.terra.api.registry.Registry; +import com.dfsek.terra.api.util.reflection.TypeKey; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; + + +public class BiomeExtrusionAddon implements AddonInitializer { + public static final TypeKey>> EXTRUSION_REGISTRY_KEY = new TypeKey<>() { + }; + + public static final TypeKey>> PROVIDER_REGISTRY_KEY = new TypeKey<>() { + }; + + @Inject + private Platform platform; + + @Inject + private BaseAddon addon; + + @Override + public void initialize() { + platform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(addon, ConfigPackPreLoadEvent.class) + .then(event -> { + CheckedRegistry>> providerRegistry = + event.getPack() + .getOrCreateRegistry(PROVIDER_REGISTRY_KEY); + providerRegistry.register(addon.key("EXTRUSION"), BiomeExtrusionTemplate::new); + }) + .then(event -> { + CheckedRegistry>> extrusionRegistry = event.getPack().getOrCreateRegistry( + EXTRUSION_REGISTRY_KEY); + extrusionRegistry.register(addon.key("SET"), SetExtrusionTemplate::new); + extrusionRegistry.register(addon.key("REPLACE"), ReplaceExtrusionTemplate::new); + }) + .failThrough(); + + platform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(addon, ConfigPackPostLoadEvent.class) + .then(event -> { + Registry biomeRegistry = event.getPack().getRegistry(Biome.class); + event.getPack().applyLoader(ReplaceableBiome.class, new ReplaceableBiomeLoader(biomeRegistry)); + }); + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionProvider.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionProvider.java new file mode 100644 index 000000000..c9f1f8129 --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionProvider.java @@ -0,0 +1,67 @@ +package com.dfsek.terra.addons.biome.extrusion; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; +import com.dfsek.terra.api.util.Column; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; + + +public class BiomeExtrusionProvider implements BiomeProvider { + private final BiomeProvider delegate; + private final Set biomes; + private final List extrusions; + private final int resolution; + + public BiomeExtrusionProvider(BiomeProvider delegate, List extrusions, int resolution) { + this.delegate = delegate; + this.biomes = delegate.stream().collect(Collectors.toSet()); + extrusions.forEach(e -> biomes.addAll(e.getBiomes())); + this.extrusions = extrusions; + this.resolution = resolution; + } + + @Override + public Biome getBiome(int x, int y, int z, long seed) { + Biome delegated = delegate.getBiome(x, y, z, seed); + + return extrude(delegated, x, y, z, seed); + } + + public Biome extrude(Biome original, int x, int y, int z, long seed) { + for(Extrusion extrusion : extrusions) { + original = extrusion.extrude(original, x, y, z, seed); + } + return original; + } + + @Override + public Column getColumn(int x, int z, long seed, int min, int max) { + return delegate.getBaseBiome(x, z, seed) + .map(base -> (Column) new BaseBiomeColumn(this, base, min, max, x, z, seed)) + .orElseGet(() -> BiomeProvider.super.getColumn(x, z, seed, min, max)); + } + + @Override + public Optional getBaseBiome(int x, int z, long seed) { + return delegate.getBaseBiome(x, z, seed); + } + + @Override + public Iterable getBiomes() { + return biomes; + } + + @Override + public int resolution() { + return resolution; + } + + public BiomeProvider getDelegate() { + return delegate; + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/Extrusion.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/Extrusion.java new file mode 100644 index 000000000..8a7154fa9 --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/Extrusion.java @@ -0,0 +1,12 @@ +package com.dfsek.terra.addons.biome.extrusion.api; + +import java.util.Collection; + +import com.dfsek.terra.api.world.biome.Biome; + + +public interface Extrusion { + Biome extrude(Biome original, int x, int y, int z, long seed); + + Collection getBiomes(); +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/PresentBiome.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/PresentBiome.java new file mode 100644 index 000000000..385b01e0b --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/PresentBiome.java @@ -0,0 +1,23 @@ +package com.dfsek.terra.addons.biome.extrusion.api; + + +import com.dfsek.terra.api.world.biome.Biome; + + +final class PresentBiome implements ReplaceableBiome { + private final Biome biome; + + PresentBiome(Biome biome) { + this.biome = biome; + } + + @Override + public Biome get(Biome existing) { + return biome; + } + + @Override + public boolean isSelf() { + return false; + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/ReplaceableBiome.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/ReplaceableBiome.java new file mode 100644 index 000000000..d79ec409a --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/ReplaceableBiome.java @@ -0,0 +1,31 @@ +package com.dfsek.terra.addons.biome.extrusion.api; + + +import java.util.Optional; + +import com.dfsek.terra.api.world.biome.Biome; + + +/** + * Basically just a specialised implementation of {@link Optional} for biomes where a biome may be a "self" reference. + */ +public sealed interface ReplaceableBiome permits PresentBiome, SelfBiome { + static ReplaceableBiome of(Biome biome) { + return new PresentBiome(biome); + } + + static ReplaceableBiome self() { + return SelfBiome.INSTANCE; + } + + Biome get(Biome existing); + + default Biome get() { + if(isSelf()) { + throw new IllegalStateException("Cannot get() self biome!"); + } + return get(null); + } + + boolean isSelf(); +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/SelfBiome.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/SelfBiome.java new file mode 100644 index 000000000..42e775ccc --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/api/SelfBiome.java @@ -0,0 +1,21 @@ +package com.dfsek.terra.addons.biome.extrusion.api; + + +import java.util.Objects; + +import com.dfsek.terra.api.world.biome.Biome; + + +final class SelfBiome implements ReplaceableBiome { + public static final SelfBiome INSTANCE = new SelfBiome(); + + @Override + public Biome get(Biome existing) { + return Objects.requireNonNull(existing); + } + + @Override + public boolean isSelf() { + return true; + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/BiomeExtrusionTemplate.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/BiomeExtrusionTemplate.java new file mode 100644 index 000000000..810246d65 --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/BiomeExtrusionTemplate.java @@ -0,0 +1,30 @@ +package com.dfsek.terra.addons.biome.extrusion.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; + +import java.util.List; + +import com.dfsek.terra.addons.biome.extrusion.BiomeExtrusionProvider; +import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; +import com.dfsek.terra.api.config.meta.Meta; +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; + + +public class BiomeExtrusionTemplate implements ObjectTemplate { + @Value("provider") + private @Meta BiomeProvider provider; + + @Value("resolution") + @Default + private @Meta int resolution = 4; + + @Value("extrusions") + private @Meta List<@Meta Extrusion> extrusions; + + @Override + public BiomeProvider get() { + return new BiomeExtrusionProvider(provider, extrusions, resolution); + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/ReplaceableBiomeLoader.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/ReplaceableBiomeLoader.java new file mode 100644 index 000000000..9ef2573ab --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/ReplaceableBiomeLoader.java @@ -0,0 +1,32 @@ +package com.dfsek.terra.addons.biome.extrusion.config; + +import com.dfsek.tectonic.api.depth.DepthTracker; +import com.dfsek.tectonic.api.exception.LoadException; +import com.dfsek.tectonic.api.loader.ConfigLoader; +import com.dfsek.tectonic.api.loader.type.TypeLoader; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.AnnotatedType; + +import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome; +import com.dfsek.terra.api.registry.Registry; +import com.dfsek.terra.api.world.biome.Biome; + + +public class ReplaceableBiomeLoader implements TypeLoader { + private final Registry biomeRegistry; + + public ReplaceableBiomeLoader(Registry biomeRegistry) { + this.biomeRegistry = biomeRegistry; + } + + @Override + public ReplaceableBiome load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker) + throws LoadException { + if(c.equals("SELF")) return ReplaceableBiome.self(); + return biomeRegistry + .getByID((String) c) + .map(ReplaceableBiome::of) + .orElseThrow(() -> new LoadException("No such biome: " + c, depthTracker)); + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/extrusions/ReplaceExtrusionTemplate.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/extrusions/ReplaceExtrusionTemplate.java new file mode 100644 index 000000000..1b4743dc4 --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/extrusions/ReplaceExtrusionTemplate.java @@ -0,0 +1,23 @@ +package com.dfsek.terra.addons.biome.extrusion.config.extrusions; + +import com.dfsek.tectonic.api.config.template.annotations.Value; + +import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; +import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome; +import com.dfsek.terra.addons.biome.extrusion.extrusions.ReplaceExtrusion; +import com.dfsek.terra.api.config.meta.Meta; +import com.dfsek.terra.api.util.collection.ProbabilityCollection; + + +public class ReplaceExtrusionTemplate extends SamplerExtrusionTemplate { + @Value("to") + private @Meta ProbabilityCollection<@Meta ReplaceableBiome> biomes; + + @Value("from") + private @Meta String fromTag; + + @Override + public Extrusion get() { + return new ReplaceExtrusion(sampler, range, biomes, fromTag); + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/extrusions/SamplerExtrusionTemplate.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/extrusions/SamplerExtrusionTemplate.java new file mode 100644 index 000000000..d21ef0f64 --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/extrusions/SamplerExtrusionTemplate.java @@ -0,0 +1,18 @@ +package com.dfsek.terra.addons.biome.extrusion.config.extrusions; + +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; + +import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; +import com.dfsek.terra.api.config.meta.Meta; +import com.dfsek.terra.api.noise.NoiseSampler; +import com.dfsek.terra.api.util.Range; + + +public abstract class SamplerExtrusionTemplate implements ObjectTemplate { + @Value("sampler") + protected @Meta NoiseSampler sampler; + + @Value("range") + protected @Meta Range range; +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/extrusions/SetExtrusionTemplate.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/extrusions/SetExtrusionTemplate.java new file mode 100644 index 000000000..1cfbaeb48 --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/config/extrusions/SetExtrusionTemplate.java @@ -0,0 +1,20 @@ +package com.dfsek.terra.addons.biome.extrusion.config.extrusions; + +import com.dfsek.tectonic.api.config.template.annotations.Value; + +import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; +import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome; +import com.dfsek.terra.addons.biome.extrusion.extrusions.SetExtrusion; +import com.dfsek.terra.api.config.meta.Meta; +import com.dfsek.terra.api.util.collection.ProbabilityCollection; + + +public class SetExtrusionTemplate extends SamplerExtrusionTemplate { + @Value("to") + private @Meta ProbabilityCollection<@Meta ReplaceableBiome> biomes; + + @Override + public Extrusion get() { + return new SetExtrusion(sampler, range, biomes); + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/ReplaceExtrusion.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/ReplaceExtrusion.java new file mode 100644 index 000000000..7458c475c --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/ReplaceExtrusion.java @@ -0,0 +1,52 @@ +package com.dfsek.terra.addons.biome.extrusion.extrusions; + +import java.util.Collection; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; +import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome; +import com.dfsek.terra.addons.biome.query.api.BiomeQueries; +import com.dfsek.terra.api.noise.NoiseSampler; +import com.dfsek.terra.api.util.Range; +import com.dfsek.terra.api.util.collection.ProbabilityCollection; +import com.dfsek.terra.api.world.biome.Biome; + + +/** + * Sets biomes at locations based on a sampler. + */ +public class ReplaceExtrusion implements Extrusion { + private final NoiseSampler sampler; + + private final Range range; + + private final ProbabilityCollection biomes; + + private final Predicate hasTag; + + public ReplaceExtrusion(NoiseSampler sampler, Range range, ProbabilityCollection biomes, String tag) { + this.sampler = sampler; + this.range = range; + this.biomes = biomes; + this.hasTag = BiomeQueries.has(tag); + } + + @Override + public Biome extrude(Biome original, int x, int y, int z, long seed) { + if(hasTag.test(original)) { + return range.ifInRange(y, () -> biomes.get(sampler, x, y, z, seed).get(original), original); + } + return original; + } + + @Override + public Collection getBiomes() { + return biomes + .getContents() + .stream() + .filter(Predicate.not(ReplaceableBiome::isSelf)) + .map(ReplaceableBiome::get) + .collect(Collectors.toSet()); + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/SetExtrusion.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/SetExtrusion.java new file mode 100644 index 000000000..79209c28a --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/SetExtrusion.java @@ -0,0 +1,45 @@ +package com.dfsek.terra.addons.biome.extrusion.extrusions; + +import java.util.Collection; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; +import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome; +import com.dfsek.terra.api.noise.NoiseSampler; +import com.dfsek.terra.api.util.Range; +import com.dfsek.terra.api.util.collection.ProbabilityCollection; +import com.dfsek.terra.api.world.biome.Biome; + + +/** + * Sets biomes at locations based on a sampler. + */ +public class SetExtrusion implements Extrusion { + private final NoiseSampler sampler; + + private final Range range; + + private final ProbabilityCollection biomes; + + public SetExtrusion(NoiseSampler sampler, Range range, ProbabilityCollection biomes) { + this.sampler = sampler; + this.range = range; + this.biomes = biomes; + } + + @Override + public Biome extrude(Biome original, int x, int y, int z, long seed) { + return range.ifInRange(y, () -> biomes.get(sampler, x, y, z, seed).get(original), original); + } + + @Override + public Collection getBiomes() { + return biomes + .getContents() + .stream() + .filter(Predicate.not(ReplaceableBiome::isSelf)) + .map(ReplaceableBiome::get) + .collect(Collectors.toSet()); + } +} diff --git a/common/addons/biome-provider-extrusion/src/main/resources/terra.addon.yml b/common/addons/biome-provider-extrusion/src/main/resources/terra.addon.yml new file mode 100644 index 000000000..21992a6d1 --- /dev/null +++ b/common/addons/biome-provider-extrusion/src/main/resources/terra.addon.yml @@ -0,0 +1,14 @@ +schema-version: 1 +contributors: + - Terra contributors +id: biome-provider-extrusion +version: @VERSION@ +entrypoints: + - "com.dfsek.terra.addons.biome.extrusion.BiomeExtrusionAddon" +website: + issues: https://github.com/PolyhedralDev/Terra/issues + source: https://github.com/PolyhedralDev/Terra + docs: https://terra.polydev.org +license: MIT License +depends: + biome-query-api: "1.+" \ No newline at end of file diff --git a/common/addons/biome-provider-image/src/main/java/com/dfsek/terra/addons/biome/image/ImageBiomeProvider.java b/common/addons/biome-provider-image/src/main/java/com/dfsek/terra/addons/biome/image/ImageBiomeProvider.java index 3c3fa90f5..aa2f647bb 100644 --- a/common/addons/biome-provider-image/src/main/java/com/dfsek/terra/addons/biome/image/ImageBiomeProvider.java +++ b/common/addons/biome-provider-image/src/main/java/com/dfsek/terra/addons/biome/image/ImageBiomeProvider.java @@ -13,6 +13,7 @@ import java.awt.Color; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.Set; import com.dfsek.terra.api.world.biome.Biome; @@ -38,6 +39,10 @@ public class ImageBiomeProvider implements BiomeProvider { @Override public Biome getBiome(int x, int y, int z, long seed) { + return getBiome(x, z); + } + + public Biome getBiome(int x, int z) { x /= resolution; z /= resolution; Color color = align.getColor(image, x, z); @@ -51,6 +56,11 @@ public class ImageBiomeProvider implements BiomeProvider { })); } + @Override + public Optional getBaseBiome(int x, int z, long seed) { + return Optional.of(getBiome(x, z)); + } + @Override public Iterable getBiomes() { return colorBiomeMap.values(); diff --git a/common/addons/biome-provider-pipeline/build.gradle.kts b/common/addons/biome-provider-pipeline/build.gradle.kts index 9342c3cad..2629ac476 100644 --- a/common/addons/biome-provider-pipeline/build.gradle.kts +++ b/common/addons/biome-provider-pipeline/build.gradle.kts @@ -1,14 +1,12 @@ -version = version("1.0.0") +version = version("1.0.1") dependencies { compileOnlyApi(project(":common:addons:manifest-addon-loader")) - implementation("com.github.ben-manes.caffeine:caffeine:3.1.0") implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama) testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama) } tasks.named("shadowJar") { - relocate("com.github.benmanes.caffeine", "com.dfsek.terra.addons.biome.pipeline.lib.caffeine") relocate("net.jafama", "com.dfsek.terra.addons.biome.pipeline.lib.jafama") } \ No newline at end of file diff --git a/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineColumn.java b/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineColumn.java new file mode 100644 index 000000000..609d22ee1 --- /dev/null +++ b/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineColumn.java @@ -0,0 +1,71 @@ +package com.dfsek.terra.addons.biome.pipeline; + +import java.util.function.Consumer; + +import com.dfsek.terra.api.util.Column; +import com.dfsek.terra.api.util.function.IntIntObjConsumer; +import com.dfsek.terra.api.util.function.IntObjConsumer; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; + + +class BiomePipelineColumn implements Column { + private final int min; + private final int max; + + private final int x; + private final int z; + private final Biome biome; + + protected BiomePipelineColumn(BiomeProvider biomeProvider, int min, int max, int x, int z, long seed) { + this.min = min; + this.max = max; + this.x = x; + this.z = z; + this.biome = biomeProvider.getBiome(x, 0, z, seed); + } + + @Override + public int getMinY() { + return min; + } + + @Override + public int getMaxY() { + return max; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getZ() { + return z; + } + + @Override + public Biome get(int y) { + return biome; + } + + @Override + public void forRanges(int resolution, IntIntObjConsumer consumer) { + consumer.accept(min, max, biome); + } + + @Override + public void forEach(Consumer consumer) { + for(int y = min; y < max; y++) { + consumer.accept(biome); + } + } + + @Override + public void forEach(IntObjConsumer consumer) { + for(int y = min; y < max; y++) { + consumer.accept(y, biome); + } + } +} diff --git a/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineProvider.java b/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineProvider.java index bef494a0f..f3f4c3aa9 100644 --- a/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineProvider.java +++ b/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineProvider.java @@ -13,6 +13,7 @@ import net.jafama.FastMath; import java.util.Comparator; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.stream.StreamSupport; @@ -21,6 +22,7 @@ import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate; import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage; import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.registry.key.StringIdentifiable; +import com.dfsek.terra.api.util.Column; import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; @@ -73,18 +75,26 @@ public class BiomePipelineProvider implements BiomeProvider { @Override public Biome getBiome(int x, int y, int z, long seed) { + return getBiome(x, z, seed); + } + + public Biome getBiome(int x, int z, long seed) { x += mutator.noise(seed + 1, x, z) * noiseAmp; z += mutator.noise(seed + 2, x, z) * noiseAmp; - - - x = FastMath.floorToInt(FastMath.floorDiv(x, resolution)); - - z = FastMath.floorToInt(FastMath.floorDiv(z, resolution)); - + + + x /= resolution; + z /= resolution; + int fdX = FastMath.floorDiv(x, pipeline.getSize()); int fdZ = FastMath.floorDiv(z, pipeline.getSize()); return holderCache.get(new SeededVector(fdX, fdZ, seed)).getBiome(x - fdX * pipeline.getSize(), - z - fdZ * pipeline.getSize()).getBiome(); + z - fdZ * pipeline.getSize()).getBiome(); + } + + @Override + public Optional getBaseBiome(int x, int z, long seed) { + return Optional.of(getBiome(x, z, seed)); } @Override @@ -92,6 +102,30 @@ public class BiomePipelineProvider implements BiomeProvider { return biomes; } + @Override + public Column getColumn(int x, int z, long seed, int min, int max) { + return new BiomePipelineColumn(this, min, max, x, z, seed); + } + + @Override + public int resolution() { + return resolution; + } + private record SeededVector(int x, int z, long seed) { + @Override + public boolean equals(Object obj) { + if(obj instanceof SeededVector that) { + return this.z == that.z && this.x == that.x && this.seed == that.seed; + } + return false; + } + + @Override + public int hashCode() { + int code = x; + code = 31 * code + z; + return 31 * code + ((int) (seed ^ (seed >>> 32))); + } } } diff --git a/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/config/BiomeProviderTemplate.java b/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/config/BiomeProviderTemplate.java index a6df1f200..1412485fe 100644 --- a/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/config/BiomeProviderTemplate.java +++ b/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/config/BiomeProviderTemplate.java @@ -22,7 +22,7 @@ public abstract class BiomeProviderTemplate implements ObjectTemplate getBaseBiome(int x, int z, long seed) { + return Optional.of(biome); + } + @Override public Iterable getBiomes() { return Collections.singleton(biome); diff --git a/common/addons/biome-query-api/README.md b/common/addons/biome-query-api/README.md new file mode 100644 index 000000000..e8e2a800c --- /dev/null +++ b/common/addons/biome-query-api/README.md @@ -0,0 +1,4 @@ +# Biome Query API + +This addon contains an API to allow other addons to quickly query +Biome data, by baking queries and using Contexts on biomes. \ No newline at end of file diff --git a/common/addons/biome-query-api/build.gradle.kts b/common/addons/biome-query-api/build.gradle.kts new file mode 100644 index 000000000..9d0aac37f --- /dev/null +++ b/common/addons/biome-query-api/build.gradle.kts @@ -0,0 +1,5 @@ +version = version("1.0.0") + +dependencies { + compileOnlyApi(project(":common:addons:manifest-addon-loader")) +} diff --git a/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/BiomeQueryAPIAddon.java b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/BiomeQueryAPIAddon.java new file mode 100644 index 000000000..9def4378b --- /dev/null +++ b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/BiomeQueryAPIAddon.java @@ -0,0 +1,46 @@ +package com.dfsek.terra.addons.biome.query; + +import java.util.Collection; + +import com.dfsek.terra.addons.biome.query.impl.BiomeTagFlattener; +import com.dfsek.terra.addons.biome.query.impl.BiomeTagHolder; +import com.dfsek.terra.addons.manifest.api.AddonInitializer; +import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; +import com.dfsek.terra.api.event.functional.FunctionalEventHandler; +import com.dfsek.terra.api.inject.annotations.Inject; +import com.dfsek.terra.api.properties.Context; +import com.dfsek.terra.api.properties.PropertyKey; +import com.dfsek.terra.api.world.biome.Biome; + + +public class BiomeQueryAPIAddon implements AddonInitializer { + public static PropertyKey BIOME_TAG_KEY = Context.create(BiomeTagHolder.class); + @Inject + private Platform platform; + @Inject + private BaseAddon addon; + + @Override + public void initialize() { + + platform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(addon, ConfigPackPostLoadEvent.class) + .then(event -> { + Collection biomes = event + .getPack() + .getRegistry(Biome.class) + .entries(); + + BiomeTagFlattener flattener = new BiomeTagFlattener(biomes + .stream() + .flatMap(biome -> biome.getTags().stream()) + .toList()); + + biomes.forEach(biome -> biome.getContext().put(BIOME_TAG_KEY, new BiomeTagHolder(biome, flattener))); + }) + .global(); + } +} diff --git a/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/api/BiomeQueries.java b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/api/BiomeQueries.java new file mode 100644 index 000000000..dbee2752b --- /dev/null +++ b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/api/BiomeQueries.java @@ -0,0 +1,17 @@ +package com.dfsek.terra.addons.biome.query.api; + +import java.util.function.Predicate; + +import com.dfsek.terra.addons.biome.query.impl.SingleTagQuery; +import com.dfsek.terra.api.world.biome.Biome; + + +public final class BiomeQueries { + private BiomeQueries() { + + } + + public static Predicate has(String tag) { + return new SingleTagQuery(tag); + } +} diff --git a/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/impl/BiomeTagFlattener.java b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/impl/BiomeTagFlattener.java new file mode 100644 index 000000000..98a416295 --- /dev/null +++ b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/impl/BiomeTagFlattener.java @@ -0,0 +1,20 @@ +package com.dfsek.terra.addons.biome.query.impl; + +import java.util.List; + + +public class BiomeTagFlattener { + private final List tags; + + public BiomeTagFlattener(List tags) { + this.tags = tags; + } + + public int index(String tag) { + return tags.indexOf(tag); + } + + public int size() { + return tags.size(); + } +} diff --git a/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/impl/BiomeTagHolder.java b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/impl/BiomeTagHolder.java new file mode 100644 index 000000000..0e4ab707b --- /dev/null +++ b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/impl/BiomeTagHolder.java @@ -0,0 +1,26 @@ +package com.dfsek.terra.addons.biome.query.impl; + +import com.dfsek.terra.api.properties.Properties; +import com.dfsek.terra.api.world.biome.Biome; + + +public class BiomeTagHolder implements Properties { + private final boolean[] tags; + private final BiomeTagFlattener flattener; + + public BiomeTagHolder(Biome biome, BiomeTagFlattener flattener) { + this.tags = new boolean[flattener.size()]; + this.flattener = flattener; + for(String tag : biome.getTags()) { + tags[flattener.index(tag)] = true; + } + } + + boolean get(int index) { + return tags[index]; + } + + public BiomeTagFlattener getFlattener() { + return flattener; + } +} diff --git a/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/impl/SingleTagQuery.java b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/impl/SingleTagQuery.java new file mode 100644 index 000000000..eef1a0a56 --- /dev/null +++ b/common/addons/biome-query-api/src/main/java/com/dfsek/terra/addons/biome/query/impl/SingleTagQuery.java @@ -0,0 +1,31 @@ +package com.dfsek.terra.addons.biome.query.impl; + +import java.util.function.Predicate; + +import com.dfsek.terra.addons.biome.query.BiomeQueryAPIAddon; +import com.dfsek.terra.api.world.biome.Biome; + + +public class SingleTagQuery implements Predicate { + private final String tag; + private int tagIndex = -1; + + public SingleTagQuery(String tag) { + this.tag = tag; + } + + @Override + public boolean test(Biome biome) { + if(tagIndex < 0) { + tagIndex = biome + .getContext() + .get(BiomeQueryAPIAddon.BIOME_TAG_KEY) + .getFlattener() + .index(tag); + } + return biome + .getContext() + .get(BiomeQueryAPIAddon.BIOME_TAG_KEY) + .get(tagIndex); + } +} diff --git a/common/addons/biome-query-api/src/main/resources/terra.addon.yml b/common/addons/biome-query-api/src/main/resources/terra.addon.yml new file mode 100644 index 000000000..8a55ce2dc --- /dev/null +++ b/common/addons/biome-query-api/src/main/resources/terra.addon.yml @@ -0,0 +1,12 @@ +schema-version: 1 +contributors: + - Terra contributors +id: biome-query-api +version: @VERSION@ +entrypoints: + - "com.dfsek.terra.addons.biome.query.BiomeQueryAPIAddon" +website: + issues: https://github.com/PolyhedralDev/Terra/issues + source: https://github.com/PolyhedralDev/Terra + docs: https://terra.polydev.org +license: MIT License \ No newline at end of file diff --git a/common/addons/chunk-generator-noise-3d/build.gradle.kts b/common/addons/chunk-generator-noise-3d/build.gradle.kts index 36e6012d7..685cc848c 100644 --- a/common/addons/chunk-generator-noise-3d/build.gradle.kts +++ b/common/addons/chunk-generator-noise-3d/build.gradle.kts @@ -1,4 +1,4 @@ -version = version("1.0.0") +version = version("1.1.0") dependencies { compileOnlyApi(project(":common:addons:manifest-addon-loader")) diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/NoiseChunkGenerator3DAddon.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/NoiseChunkGenerator3DAddon.java index a36f9093b..06450b613 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/NoiseChunkGenerator3DAddon.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/NoiseChunkGenerator3DAddon.java @@ -9,7 +9,9 @@ package com.dfsek.terra.addons.chunkgenerator; import com.dfsek.terra.addons.chunkgenerator.config.NoiseChunkGeneratorPackConfigTemplate; import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseConfigTemplate; +import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; import com.dfsek.terra.addons.chunkgenerator.config.palette.BiomePaletteTemplate; +import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo; import com.dfsek.terra.addons.chunkgenerator.config.palette.SlantLayer; import com.dfsek.terra.addons.chunkgenerator.generation.NoiseChunkGenerator3D; import com.dfsek.terra.addons.manifest.api.AddonInitializer; @@ -19,6 +21,8 @@ import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.inject.annotations.Inject; +import com.dfsek.terra.api.properties.Context; +import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.chunk.generation.util.provider.ChunkGeneratorProvider; @@ -32,17 +36,22 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer { @Override public void initialize() { + PropertyKey paletteInfoPropertyKey = Context.create(PaletteInfo.class); + PropertyKey noisePropertiesPropertyKey = Context.create(BiomeNoiseProperties.class); platform.getEventManager() .getHandler(FunctionalEventHandler.class) .register(addon, ConfigPackPreLoadEvent.class) + .priority(1000) .then(event -> { NoiseChunkGeneratorPackConfigTemplate config = event.loadTemplate(new NoiseChunkGeneratorPackConfigTemplate()); event.getPack() .getOrCreateRegistry(ChunkGeneratorProvider.class) .register(addon.key("NOISE_3D"), - pack -> new NoiseChunkGenerator3D(platform, config.getElevationBlend(), config.getHorizontalRes(), - config.getVerticalRes())); + pack -> new NoiseChunkGenerator3D(pack, platform, config.getElevationBlend(), + config.getHorizontalRes(), + config.getVerticalRes(), noisePropertiesPropertyKey, + paletteInfoPropertyKey)); event.getPack() .applyLoader(SlantLayer.class, SlantLayer::new); }) @@ -53,8 +62,10 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer { .register(addon, ConfigurationLoadEvent.class) .then(event -> { if(event.is(Biome.class)) { - event.getLoadedObject(Biome.class).getContext().put(event.load(new BiomePaletteTemplate(platform)).get()); - event.getLoadedObject(Biome.class).getContext().put(event.load(new BiomeNoiseConfigTemplate()).get()); + event.getLoadedObject(Biome.class).getContext().put(paletteInfoPropertyKey, + event.load(new BiomePaletteTemplate(platform)).get()); + event.getLoadedObject(Biome.class).getContext().put(noisePropertiesPropertyKey, + event.load(new BiomeNoiseConfigTemplate()).get()); } }) .failThrough(); diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/noise/BiomeNoiseConfigTemplate.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/noise/BiomeNoiseConfigTemplate.java index 14d3c97d2..cd034f012 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/noise/BiomeNoiseConfigTemplate.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/noise/BiomeNoiseConfigTemplate.java @@ -39,6 +39,6 @@ public class BiomeNoiseConfigTemplate implements ObjectTemplate holder = ThreadLocal.withInitial(Holder::new); + + public double getNoise(NoiseSampler sampler, int x, int y, int z, long seed) { + Holder holder = this.holder.get(); + + if(holder.init && holder.y == y && holder.z == z && holder.x == x && holder.seed == seed) { + return holder.noise; + } + + double noise = sampler.noise(seed, x, y, z); + holder.noise = noise; + holder.x = x; + holder.y = y; + holder.z = z; + holder.seed = seed; + holder.init = true; + return noise; + } + + private static final class Holder { + int x, y, z; + boolean init = false; + long seed; + double noise; + } +} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/BiomePaletteTemplate.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/BiomePaletteTemplate.java index 3497bdd75..f1f0f804a 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/BiomePaletteTemplate.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/BiomePaletteTemplate.java @@ -59,6 +59,10 @@ public class BiomePaletteTemplate implements ObjectTemplate { } }; + @Value("carving.update-palette") + @Default + private @Meta boolean updatePalette = false; + public BiomePaletteTemplate(Platform platform) { this.platform = platform; } @Override @@ -79,6 +83,7 @@ public class BiomePaletteTemplate implements ObjectTemplate { slantLayers.put(threshold, layer.getPalette()); } - return new PaletteInfo(builder.build(), SlantHolder.of(slantLayers, minThreshold), oceanPalette, seaLevel, slantDepth); + return new PaletteInfo(builder.build(), SlantHolder.of(slantLayers, minThreshold), oceanPalette, seaLevel, slantDepth, + updatePalette); } } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/PaletteInfo.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/PaletteInfo.java index d866446a3..caf3c4802 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/PaletteInfo.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/PaletteInfo.java @@ -17,5 +17,6 @@ public record PaletteInfo(PaletteHolder paletteHolder, SlantHolder slantHolder, Palette ocean, int seaLevel, - int maxSlantDepth) implements Properties { + int maxSlantDepth, + boolean updatePaletteWhenCarving) implements Properties { } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java index 300cdbfcc..fcb8d3fe2 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java @@ -11,6 +11,7 @@ package com.dfsek.terra.addons.chunkgenerator.generation; import net.jafama.FastMath; import org.jetbrains.annotations.NotNull; +import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo; import com.dfsek.terra.addons.chunkgenerator.generation.math.PaletteUtil; import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.LazilyEvaluatedInterpolator; @@ -18,6 +19,9 @@ import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider; import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.properties.PropertyKey; +import com.dfsek.terra.api.util.Column; import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; @@ -36,13 +40,28 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { private final int carverHorizontalResolution; private final int carverVerticalResolution; - public NoiseChunkGenerator3D(Platform platform, int elevationBlend, int carverHorizontalResolution, - int carverVerticalResolution) { + private final PropertyKey paletteInfoPropertyKey; + private final PropertyKey noisePropertiesKey; + + public NoiseChunkGenerator3D(ConfigPack pack, Platform platform, int elevationBlend, int carverHorizontalResolution, + int carverVerticalResolution, + PropertyKey noisePropertiesKey, + PropertyKey paletteInfoPropertyKey) { this.platform = platform; this.air = platform.getWorldHandle().air(); this.carverHorizontalResolution = carverHorizontalResolution; this.carverVerticalResolution = carverVerticalResolution; - this.samplerCache = new SamplerProvider(platform, elevationBlend); + this.paletteInfoPropertyKey = paletteInfoPropertyKey; + this.noisePropertiesKey = noisePropertiesKey; + int maxBlend = pack + .getBiomeProvider() + .stream() + .map(biome -> biome.getContext().get(noisePropertiesKey)) + .mapToInt(properties -> properties.blendDistance() * properties.blendStep()) + .max() + .orElse(0); + + this.samplerCache = new SamplerProvider(platform, elevationBlend, noisePropertiesKey, maxBlend); } @Override @@ -62,7 +81,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { chunkX, chunkZ, world.getMaxHeight(), - world.getMinHeight(), + noisePropertiesKey, world.getMinHeight(), carverHorizontalResolution, carverVerticalResolution, seed); @@ -73,23 +92,28 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { int cx = xOrig + x; int cz = zOrig + z; - Biome biome = biomeProvider.getBiome(cx, 0, cz, seed); - - PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class); - - int sea = paletteInfo.seaLevel(); - Palette seaPalette = paletteInfo.ocean(); - BlockState data; + Column biomeColumn = biomeProvider.getColumn(cx, cz, world); for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) { + Biome biome = biomeColumn.get(y); + + PaletteInfo paletteInfo = biome.getContext().get(paletteInfoPropertyKey); + + int sea = paletteInfo.seaLevel(); + Palette seaPalette = paletteInfo.ocean(); + if(sampler.sample(x, y, z) > 0) { if(carver.sample(x, y, z) <= 0) { - data = PaletteUtil.getPalette(x, y, z, sampler, paletteInfo, paletteLevel).get(paletteLevel, cx, y, cz, - seed); + data = PaletteUtil + .getPalette(x, y, z, sampler, paletteInfo, paletteLevel) + .get(paletteLevel, cx, y, cz, seed); chunk.setBlock(x, y, z, data); + paletteLevel++; + } else if(paletteInfo.updatePaletteWhenCarving()) { + paletteLevel = 0; + } else { + paletteLevel++; } - - paletteLevel++; } else if(y <= sea) { chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig, seed)); paletteLevel = 0; @@ -107,7 +131,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { Biome biome = biomeProvider.getBiome(x, y, z, world.getSeed()); Sampler3D sampler = samplerCache.get(x, z, world, biomeProvider); - PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class); + PaletteInfo paletteInfo = biome.getContext().get(paletteInfoPropertyKey); int fdX = FastMath.floorMod(x, 16); int fdZ = FastMath.floorMod(z, 16); @@ -128,7 +152,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { @Override public Palette getPalette(int x, int y, int z, WorldProperties world, BiomeProvider biomeProvider) { - return biomeProvider.getBiome(x, y, z, world.getSeed()).getContext().get(PaletteInfo.class).paletteHolder().getPalette(y); + return biomeProvider.getBiome(x, y, z, world.getSeed()).getContext().get(paletteInfoPropertyKey).paletteHolder().getPalette(y); } public SamplerProvider samplerProvider() { diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ChunkInterpolator.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ChunkInterpolator.java index 9f8cb782f..d712bfc60 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ChunkInterpolator.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ChunkInterpolator.java @@ -9,11 +9,10 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation; import net.jafama.FastMath; -import java.util.HashMap; -import java.util.Map; - import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; -import com.dfsek.terra.api.util.mutable.MutableInteger; +import com.dfsek.terra.api.properties.PropertyKey; +import com.dfsek.terra.api.util.Column; +import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; @@ -23,7 +22,6 @@ import com.dfsek.terra.api.world.biome.generation.BiomeProvider; */ public class ChunkInterpolator { private final Interpolator3[][][] interpGrid; - private final long seed; private final int min; private final int max; @@ -37,10 +35,10 @@ public class ChunkInterpolator { * @param min * @param max */ - public ChunkInterpolator(long seed, int chunkX, int chunkZ, BiomeProvider provider, int min, int max) { + public ChunkInterpolator(long seed, int chunkX, int chunkZ, BiomeProvider provider, int min, int max, + PropertyKey noisePropertiesKey, int maxBlend) { this.min = min; this.max = max; - this.seed = seed; int xOrigin = chunkX << 4; int zOrigin = chunkZ << 4; @@ -53,28 +51,67 @@ public class ChunkInterpolator { double[][][] noiseStorage = new double[5][5][size + 1]; + int maxBlendAndChunk = 17 + 2 * maxBlend; + + @SuppressWarnings("unchecked") + Column[] columns = new Column[maxBlendAndChunk * maxBlendAndChunk]; + for(int x = 0; x < 5; x++) { + int scaledX = x << 2; + int absoluteX = xOrigin + scaledX; for(int z = 0; z < 5; z++) { - BiomeNoiseProperties generationSettings = provider.getBiome(xOrigin + (x << 2), 0, zOrigin + (z << 2), seed) - .getContext() - .get(BiomeNoiseProperties.class); - Map genMap = new HashMap<>(); + int scaledZ = z << 2; + int absoluteZ = zOrigin + scaledZ; - int step = generationSettings.blendStep(); - int blend = generationSettings.blendDistance(); + int index = (scaledX + maxBlend) + maxBlendAndChunk * (scaledZ + maxBlend); + Column biomeColumn = columns[index]; - for(int xi = -blend; xi <= blend; xi++) { - for(int zi = -blend; zi <= blend; zi++) { - genMap.computeIfAbsent( - provider.getBiome(xOrigin + (x << 2) + (xi * step), 0, zOrigin + (z << 2) + (zi * step), seed) - .getContext() - .get(BiomeNoiseProperties.class), - g -> new MutableInteger(0)).increment(); // Increment by 1 - } + if(biomeColumn == null) { + biomeColumn = provider.getColumn(absoluteX, absoluteZ, seed, min, max); + columns[index] = biomeColumn; } - for(int y = 0; y < size + 1; y++) { - noiseStorage[x][z][y] = computeNoise(genMap, (x << 2) + xOrigin, (y << 2) + this.min, (z << 2) + zOrigin); + for(int y = 0; y < size; y++) { + int scaledY = (y << 2) + min; + BiomeNoiseProperties generationSettings = biomeColumn.get(scaledY) + .getContext() + .get(noisePropertiesKey); + + int step = generationSettings.blendStep(); + int blend = generationSettings.blendDistance(); + + double runningNoise = 0; + double runningDiv = 0; + + for(int xi = -blend; xi <= blend; xi++) { + for(int zi = -blend; zi <= blend; zi++) { + int blendX = (xi * step); + int blendZ = (zi * step); + + int localIndex = (scaledX + maxBlend + blendX) + maxBlendAndChunk * (scaledZ + maxBlend + blendZ); + Column column = columns[localIndex]; + + if(column == null) { + column = provider.getColumn(absoluteX + blendX, absoluteZ + blendZ, seed, min, max); + columns[localIndex] = column; + } + + BiomeNoiseProperties properties = column + .get(scaledY) + .getContext() + .get(noisePropertiesKey); + double sample = properties.noiseHolder().getNoise(properties.base(), absoluteX, scaledY, absoluteZ, seed); + runningNoise += sample * properties.blendWeight(); + runningDiv += properties.blendWeight(); + } + } + + double noise = runningNoise / runningDiv; + + noiseStorage[x][z][y] = noise; + if(y == size - 1) { + noiseStorage[x][z][size] = noise; + } } } } @@ -100,24 +137,6 @@ public class ChunkInterpolator { return FastMath.max(FastMath.min(value, high), 0); } - public double computeNoise(BiomeNoiseProperties generationSettings, double x, double y, double z) { - return generationSettings.base().noise(seed, x, y, z); - } - - public double computeNoise(Map gens, double x, double y, double z) { - double n = 0; - double div = 0; - for(Map.Entry entry : gens.entrySet()) { - BiomeNoiseProperties gen = entry.getKey(); - int weight = entry.getValue().get(); - double noise = computeNoise(gen, x, y, z); - - n += noise * weight; - div += gen.blendWeight() * weight; - } - return n / div; - } - /** * Gets the noise at a pair of internal chunk coordinates. * diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ElevationInterpolator.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ElevationInterpolator.java index 0342ca751..d4664673b 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ElevationInterpolator.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ElevationInterpolator.java @@ -8,13 +8,15 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation; import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; +import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; public class ElevationInterpolator { private final double[][] values = new double[18][18]; - public ElevationInterpolator(long seed, int chunkX, int chunkZ, BiomeProvider provider, int smooth) { + public ElevationInterpolator(long seed, int chunkX, int chunkZ, BiomeProvider provider, int smooth, + PropertyKey noisePropertiesKey) { int xOrigin = chunkX << 4; int zOrigin = chunkZ << 4; @@ -23,8 +25,14 @@ public class ElevationInterpolator { // Precompute generators. for(int x = -1 - smooth; x <= 16 + smooth; x++) { for(int z = -1 - smooth; z <= 16 + smooth; z++) { - gens[x + 1 + smooth][z + 1 + smooth] = provider.getBiome(xOrigin + x, 0, zOrigin + z, seed).getContext().get( - BiomeNoiseProperties.class); + int bx = xOrigin + x; + int bz = zOrigin + z; + gens[x + 1 + smooth][z + 1 + smooth] = + provider + .getBaseBiome(bx, bz, seed) + .orElseGet(() -> provider.getBiome(bx, 0, bz, seed)) // kind of a hack + .getContext() + .get(noisePropertiesKey); } } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java index 34c20ad97..f2a48c50a 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java @@ -3,16 +3,14 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation; import net.jafama.FastMath; import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; -import com.dfsek.terra.api.noise.NoiseSampler; +import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import static com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.Interpolator.lerp; public class LazilyEvaluatedInterpolator { - private final Double[][][] samples; - - private final NoiseSampler[][] samplers; + private final Double[] samples; // private final int chunkX; private final int chunkZ; @@ -21,16 +19,22 @@ public class LazilyEvaluatedInterpolator { private final int verticalRes; private final BiomeProvider biomeProvider; + private final PropertyKey noisePropertiesKey; private final long seed; - private final int min; + private final int min, max; - public LazilyEvaluatedInterpolator(BiomeProvider biomeProvider, int cx, int cz, int max, int min, int horizontalRes, int verticalRes, + private final int zMul, yMul; + + public LazilyEvaluatedInterpolator(BiomeProvider biomeProvider, int cx, int cz, int max, + PropertyKey noisePropertiesKey, int min, int horizontalRes, int verticalRes, long seed) { + this.noisePropertiesKey = noisePropertiesKey; int hSamples = FastMath.ceilToInt(16.0 / horizontalRes); int vSamples = FastMath.ceilToInt((double) (max - min) / verticalRes); - samples = new Double[hSamples + 1][vSamples + 1][hSamples + 1]; - samplers = new NoiseSampler[hSamples + 1][hSamples + 1]; + this.zMul = (hSamples + 1); + this.yMul = zMul * zMul; + samples = new Double[yMul * (vSamples + 1)]; this.chunkX = cx << 4; this.chunkZ = cz << 4; this.horizontalRes = horizontalRes; @@ -38,22 +42,25 @@ public class LazilyEvaluatedInterpolator { this.biomeProvider = biomeProvider; this.seed = seed; this.min = min; + this.max = max - 1; } - private double sample(int x, int y, int z, int ox, int oy, int oz) { - Double sample = samples[x][y][z]; + private double sample(int xIndex, int yIndex, int zIndex, int ox, int oy, int oz) { + int index = xIndex + (zIndex * zMul) + (yIndex * yMul); + Double sample = samples[index]; if(sample == null) { int xi = ox + chunkX; int zi = oz + chunkZ; - NoiseSampler sampler = samplers[x][z]; - if(sampler == null) { - sampler = biomeProvider.getBiome(xi, y, zi, seed).getContext().get(BiomeNoiseProperties.class).carving(); - samplers[x][z] = sampler; - } + int y = FastMath.min(max, oy); - sample = sampler.noise(seed, xi, oy, zi); - samples[x][y][z] = sample; + sample = biomeProvider + .getBiome(xi, y, zi, seed) + .getContext() + .get(noisePropertiesKey) + .carving() + .noise(seed, xi, y, zi); + samples[index] = sample; } return sample; } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/samplers/Sampler3D.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/samplers/Sampler3D.java index ea98b0af6..15a480969 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/samplers/Sampler3D.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/samplers/Sampler3D.java @@ -9,8 +9,10 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math.samplers; import net.jafama.FastMath; +import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ChunkInterpolator; import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ElevationInterpolator; +import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; @@ -18,10 +20,11 @@ public class Sampler3D { private final ChunkInterpolator interpolator; private final ElevationInterpolator elevationInterpolator; - public Sampler3D(int x, int z, long seed, int minHeight, int maxHeight, BiomeProvider provider, int elevationSmooth) { + public Sampler3D(int x, int z, long seed, int minHeight, int maxHeight, BiomeProvider provider, int elevationSmooth, + PropertyKey noisePropertiesKey, int maxBlend) { this.interpolator = new ChunkInterpolator(seed, x, z, provider, - minHeight, maxHeight); - this.elevationInterpolator = new ElevationInterpolator(seed, x, z, provider, elevationSmooth); + minHeight, maxHeight, noisePropertiesKey, maxBlend); + this.elevationInterpolator = new ElevationInterpolator(seed, x, z, provider, elevationSmooth, noisePropertiesKey); } public double sample(double x, double y, double z) { diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/samplers/SamplerProvider.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/samplers/SamplerProvider.java index 30fcb016a..ab20614b5 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/samplers/SamplerProvider.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/samplers/SamplerProvider.java @@ -17,13 +17,13 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math.samplers; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import net.jafama.FastMath; -import java.util.concurrent.ExecutionException; - +import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.info.WorldProperties; @@ -31,10 +31,17 @@ import com.dfsek.terra.api.world.info.WorldProperties; public class SamplerProvider { private final Cache cache; private final int elevationSmooth; + private final PropertyKey noisePropertiesKey; + private final int maxBlend; - public SamplerProvider(Platform platform, int elevationSmooth) { + public SamplerProvider(Platform platform, int elevationSmooth, PropertyKey noisePropertiesKey, int maxBlend) { + cache = Caffeine + .newBuilder() + .maximumSize(platform.getTerraConfig().getSamplerCache()) + .build(); this.elevationSmooth = elevationSmooth; - cache = CacheBuilder.newBuilder().maximumSize(platform.getTerraConfig().getSamplerCache()).build(); + this.noisePropertiesKey = noisePropertiesKey; + this.maxBlend = maxBlend; } public Sampler3D get(int x, int z, WorldProperties world, BiomeProvider provider) { @@ -45,13 +52,8 @@ public class SamplerProvider { public Sampler3D getChunk(int cx, int cz, WorldProperties world, BiomeProvider provider) { WorldContext context = new WorldContext(cx, cz, world.getSeed(), world.getMinHeight(), world.getMaxHeight()); - try { - return cache.get(context, - () -> new Sampler3D(context.cx, context.cz, context.seed, context.minHeight, context.maxHeight, provider, - elevationSmooth)); - } catch(ExecutionException e) { - throw new RuntimeException(e); - } + return cache.get(context, c -> new Sampler3D(c.cx, c.cz, c.seed, c.minHeight, c.maxHeight, provider, + elevationSmooth, noisePropertiesKey, maxBlend)); } private record WorldContext(int cx, int cz, long seed, int minHeight, int maxHeight) { diff --git a/common/addons/config-locators/build.gradle.kts b/common/addons/config-locators/build.gradle.kts index 99485164c..50fc70400 100644 --- a/common/addons/config-locators/build.gradle.kts +++ b/common/addons/config-locators/build.gradle.kts @@ -1,4 +1,4 @@ -version = version("1.0.0") +version = version("1.1.0") dependencies { compileOnlyApi(project(":common:addons:manifest-addon-loader")) diff --git a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/AdjacentPatternLocator.java b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/AdjacentPatternLocator.java index 55fc2c2b3..439c85ad1 100644 --- a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/AdjacentPatternLocator.java +++ b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/AdjacentPatternLocator.java @@ -11,6 +11,7 @@ import com.dfsek.terra.addons.feature.locator.patterns.Pattern; import com.dfsek.terra.api.structure.feature.BinaryColumn; import com.dfsek.terra.api.structure.feature.Locator; import com.dfsek.terra.api.util.Range; +import com.dfsek.terra.api.world.WritableWorld; import com.dfsek.terra.api.world.chunk.generation.util.Column; @@ -31,16 +32,19 @@ public class AdjacentPatternLocator implements Locator { } private boolean isValid(int y, Column column) { + WritableWorld world = column.getWorld(); + int x = column.getX(); + int z = column.getZ(); if(matchAll) { - return pattern.matches(y, column.adjacent(0, -1)) && - pattern.matches(y, column.adjacent(0, 1)) && - pattern.matches(y, column.adjacent(-1, 0)) && - pattern.matches(y, column.adjacent(1, 0)); + return pattern.matches(world, x, y, z - 1) && + pattern.matches(world, x, y, z + 1) && + pattern.matches(world, x - 1, y, z) && + pattern.matches(world, x + 1, y, z); } else { - return pattern.matches(y, column.adjacent(0, -1)) || - pattern.matches(y, column.adjacent(0, 1)) || - pattern.matches(y, column.adjacent(-1, 0)) || - pattern.matches(y, column.adjacent(1, 0)); + return pattern.matches(world, x, y, z - 1) || + pattern.matches(world, x, y, z + 1) || + pattern.matches(world, x - 1, y, z) || + pattern.matches(world, x + 1, y, z); } } } diff --git a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/PatternLocator.java b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/PatternLocator.java index f3f525af9..b4ea6b1d8 100644 --- a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/PatternLocator.java +++ b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/PatternLocator.java @@ -7,6 +7,8 @@ package com.dfsek.terra.addons.feature.locator.locators; +import net.jafama.FastMath; + import com.dfsek.terra.addons.feature.locator.patterns.Pattern; import com.dfsek.terra.api.structure.feature.BinaryColumn; import com.dfsek.terra.api.structure.feature.Locator; @@ -25,6 +27,9 @@ public class PatternLocator implements Locator { @Override public BinaryColumn getSuitableCoordinates(Column column) { - return new BinaryColumn(search, y -> pattern.matches(y, column)); + int min = FastMath.max(column.getMinY(), search.getMin()); + int max = FastMath.min(column.getMaxY(), search.getMax()); + if(min >= max) return BinaryColumn.getNull(); + return new BinaryColumn(min, max, y -> pattern.matches(y, column)); } } diff --git a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/SamplerLocator.java b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/SamplerLocator.java index 3a2ff8330..e5c43a122 100644 --- a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/SamplerLocator.java +++ b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/SamplerLocator.java @@ -23,6 +23,19 @@ public class SamplerLocator implements Locator { this.samplers = samplers; } + private static int floorToInt(double value) { + int valueInt = (int) value; + if(value < 0.0) { + if(value == (double) valueInt) { + return valueInt; + } else { + return valueInt == Integer.MIN_VALUE ? valueInt : valueInt - 1; + } + } else { + return valueInt; + } + } + @Override public BinaryColumn getSuitableCoordinates(Column column) { BinaryColumnBuilder results = column.newBinaryColumn(); @@ -36,17 +49,4 @@ public class SamplerLocator implements Locator { return results.build(); } - - private static int floorToInt(double value) { - int valueInt = (int)value; - if (value < 0.0) { - if (value == (double)valueInt) { - return valueInt; - } else { - return valueInt == Integer.MIN_VALUE ? valueInt : valueInt - 1; - } - } else { - return valueInt; - } - } } diff --git a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/SurfaceLocator.java b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/SurfaceLocator.java index c56f583d2..9e9b7ef2e 100644 --- a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/SurfaceLocator.java +++ b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/locators/SurfaceLocator.java @@ -7,6 +7,8 @@ package com.dfsek.terra.addons.feature.locator.locators; +import net.jafama.FastMath; + import com.dfsek.terra.api.structure.feature.BinaryColumn; import com.dfsek.terra.api.structure.feature.Locator; import com.dfsek.terra.api.util.Range; @@ -24,7 +26,10 @@ public class SurfaceLocator implements Locator { @Override public BinaryColumn getSuitableCoordinates(Column column) { BinaryColumnBuilder builder = column.newBinaryColumn(); - for(int y : search) { + int max = FastMath.min(search.getMax(), column.getMaxY()); + int min = FastMath.max(search.getMin(), column.getMinY()); + if(min >= max) return builder.build(); + for(int y = min; y < max; y++) { if(column.getBlock(y).isAir() && !column.getBlock(y - 1).isAir()) { builder.set(y); } diff --git a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/patterns/MatchPattern.java b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/patterns/MatchPattern.java index 3ef1c3fbb..e2ca64f69 100644 --- a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/patterns/MatchPattern.java +++ b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/patterns/MatchPattern.java @@ -7,10 +7,13 @@ package com.dfsek.terra.addons.feature.locator.patterns; +import net.jafama.FastMath; + import java.util.function.Predicate; import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.util.Range; +import com.dfsek.terra.api.world.WritableWorld; import com.dfsek.terra.api.world.chunk.generation.util.Column; @@ -25,8 +28,22 @@ public class MatchPattern implements Pattern { @Override public boolean matches(int y, Column column) { - for(int i : range) { - if(!matches.test(column.getBlock(y + i))) return false; + int min = FastMath.max(column.getMinY(), range.getMin() + y); + int max = FastMath.min(column.getMaxY(), range.getMax() + y); + if(max <= min) return false; + for(int i = min; i < max; i++) { + if(!matches.test(column.getBlock(i))) return false; + } + return true; + } + + @Override + public boolean matches(WritableWorld world, int x, int y, int z) { + int min = FastMath.max(world.getMinHeight(), range.getMin() + y); + int max = FastMath.min(world.getMaxHeight(), range.getMax() + y); + if(max <= min) return false; + for(int i = min; i < max; i++) { + if(!matches.test(world.getBlockState(x, i, z))) return false; } return true; } diff --git a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/patterns/Pattern.java b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/patterns/Pattern.java index dbe909943..4c2d0de67 100644 --- a/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/patterns/Pattern.java +++ b/common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/patterns/Pattern.java @@ -7,12 +7,18 @@ package com.dfsek.terra.addons.feature.locator.patterns; +import com.dfsek.terra.api.world.WritableWorld; import com.dfsek.terra.api.world.chunk.generation.util.Column; public interface Pattern { boolean matches(int y, Column column); + default boolean matches(WritableWorld world, int x, int y, int z) { + return matches(y, world.column(x, z)); + } + + default Pattern and(Pattern that) { return (y, column) -> this.matches(y, column) && that.matches(y, column); } diff --git a/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/paralithic/defined/UserDefinedFunction.java b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/paralithic/defined/UserDefinedFunction.java index fe72ed070..a087012ca 100644 --- a/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/paralithic/defined/UserDefinedFunction.java +++ b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/paralithic/defined/UserDefinedFunction.java @@ -23,11 +23,10 @@ import com.dfsek.terra.addons.noise.config.templates.FunctionTemplate; public class UserDefinedFunction implements DynamicFunction { + private static final Map CACHE = new HashMap<>(); private final Expression expression; private final int args; - private static final Map CACHE = new HashMap<>(); - protected UserDefinedFunction(Expression expression, int args) { this.expression = expression; this.args = args; @@ -38,17 +37,17 @@ public class UserDefinedFunction implements DynamicFunction { if(function == null) { Parser parser = new Parser(); Scope parent = new Scope(); - + Scope functionScope = new Scope().withParent(parent); - + template.getArgs().forEach(functionScope::addInvocationVariable); - + for(Entry entry : template.getFunctions().entrySet()) { String id = entry.getKey(); FunctionTemplate nest = entry.getValue(); parser.registerFunction(id, newInstance(nest)); } - + function = new UserDefinedFunction(parser.parse(template.getFunction(), functionScope), template.getArgs().size()); CACHE.put(template, function); } diff --git a/common/addons/config-palette/src/main/java/com/dfsek/terra/addons/palette/palette/PaletteLayerLoader.java b/common/addons/config-palette/src/main/java/com/dfsek/terra/addons/palette/palette/PaletteLayerLoader.java index f0ad5cbd1..0e12682ab 100644 --- a/common/addons/config-palette/src/main/java/com/dfsek/terra/addons/palette/palette/PaletteLayerLoader.java +++ b/common/addons/config-palette/src/main/java/com/dfsek/terra/addons/palette/palette/PaletteLayerLoader.java @@ -12,20 +12,21 @@ import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.util.collection.ProbabilityCollection; public class PaletteLayerLoader implements ObjectTemplate { @Value("materials") - private ProbabilityCollection collection; + private @Meta ProbabilityCollection<@Meta BlockState> collection; @Value("sampler") @Default - private NoiseSampler sampler = null; + private @Meta NoiseSampler sampler = null; @Value("layers") - private int layers; + private @Meta int layers; @Override public PaletteLayerHolder get() { diff --git a/common/addons/generation-stage-feature/build.gradle.kts b/common/addons/generation-stage-feature/build.gradle.kts index 9d0aac37f..84c179738 100644 --- a/common/addons/generation-stage-feature/build.gradle.kts +++ b/common/addons/generation-stage-feature/build.gradle.kts @@ -1,4 +1,4 @@ -version = version("1.0.0") +version = version("1.1.0") dependencies { compileOnlyApi(project(":common:addons:manifest-addon-loader")) diff --git a/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationAddon.java b/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationAddon.java index c3db72aac..ac0475d7e 100644 --- a/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationAddon.java +++ b/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationAddon.java @@ -28,6 +28,8 @@ import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.inject.annotations.Inject; +import com.dfsek.terra.api.properties.Context; +import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.structure.feature.Feature; import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.world.biome.Biome; @@ -49,12 +51,13 @@ public class FeatureGenerationAddon implements AddonInitializer { @SuppressWarnings("unchecked") @Override public void initialize() { + PropertyKey biomeFeaturesKey = Context.create(BiomeFeatures.class); platform.getEventManager() .getHandler(FunctionalEventHandler.class) .register(addon, ConfigPackPreLoadEvent.class) .then(event -> event.getPack() .getOrCreateRegistry(STAGE_TYPE_KEY) - .register(addon.key("FEATURE"), () -> new FeatureStageTemplate(platform))) + .register(addon.key("FEATURE"), () -> new FeatureStageTemplate(platform, biomeFeaturesKey))) .failThrough(); platform.getEventManager() @@ -84,7 +87,7 @@ public class FeatureGenerationAddon implements AddonInitializer { featureGenerationStages.forEach(stage -> features.put(stage, template.get(stage.getID(), List.class))); - event.getLoadedObject(Biome.class).getContext().put(new BiomeFeatures(features)); + event.getLoadedObject(Biome.class).getContext().put(biomeFeaturesKey, new BiomeFeatures(features)); } }) .failThrough(); diff --git a/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationStage.java b/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationStage.java index c60ecc6aa..5408b26e4 100644 --- a/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationStage.java +++ b/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationStage.java @@ -12,6 +12,7 @@ import java.util.Random; import com.dfsek.terra.addons.generation.feature.config.BiomeFeatures; import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.registry.key.StringIdentifiable; import com.dfsek.terra.api.util.Rotation; import com.dfsek.terra.api.util.vector.Vector3Int; @@ -28,10 +29,15 @@ public class FeatureGenerationStage implements GenerationStage, StringIdentifiab private final String profile; - public FeatureGenerationStage(Platform platform, String id) { + private final int resolution; + private final PropertyKey biomeFeaturesKey; + + public FeatureGenerationStage(Platform platform, String id, int resolution, PropertyKey biomeFeaturesKey) { this.platform = platform; this.id = id; this.profile = "feature_stage:" + id; + this.resolution = resolution; + this.biomeFeaturesKey = biomeFeaturesKey; } @Override @@ -41,33 +47,39 @@ public class FeatureGenerationStage implements GenerationStage, StringIdentifiab int cx = world.centerChunkX() << 4; int cz = world.centerChunkZ() << 4; long seed = world.getSeed(); - for(int x = 0; x < 16; x++) { - for(int z = 0; z < 16; z++) { - int tx = cx + x; - int tz = cz + z; - Column column = world.column(tx, tz); - long coordinateSeed = (seed * 31 + tx) * 31 + tz; - + for(int chunkX = 0; chunkX < 16; chunkX += resolution) { + for(int chunkZ = 0; chunkZ < 16; chunkZ += resolution) { + int tx = cx + chunkX; + int tz = cz + chunkZ; world.getBiomeProvider() - .getBiome(tx, 0, tz, seed) - .getContext() - .get(BiomeFeatures.class) - .getFeatures() - .getOrDefault(this, Collections.emptyList()) - .forEach(feature -> { - platform.getProfiler().push(feature.getID()); - if(feature.getDistributor().matches(tx, tz, seed)) { - feature.getLocator() - .getSuitableCoordinates(column) - .forEach(y -> - feature.getStructure(world, tx, y, tz) - .generate(Vector3Int.of(tx, y, tz), - world, - new Random(coordinateSeed * 31 + y), - Rotation.NONE) - ); + .getColumn(tx, tz, world) + .forRanges(resolution, (min, max, biome) -> { + for(int subChunkX = 0; subChunkX < resolution; subChunkX++) { + for(int subChunkZ = 0; subChunkZ < resolution; subChunkZ++) { + int x = subChunkX + tx; + int z = subChunkZ + tz; + long coordinateSeed = (seed * 31 + x) * 31 + z; + Column column = world.column(x, z); + biome.getContext() + .get(biomeFeaturesKey) + .getFeatures() + .getOrDefault(this, Collections.emptyList()) + .forEach(feature -> { + platform.getProfiler().push(feature.getID()); + if(feature.getDistributor().matches(x, z, seed)) { + feature.getLocator() + .getSuitableCoordinates(column.clamp(min, max)) + .forEach(y -> feature.getStructure(world, x, y, z) + .generate(Vector3Int.of(x, y, z), + world, + new Random(coordinateSeed * 31 + y), + Rotation.NONE) + ); + } + platform.getProfiler().pop(feature.getID()); + }); + } } - platform.getProfiler().pop(feature.getID()); }); } } diff --git a/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/config/FeatureStageTemplate.java b/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/config/FeatureStageTemplate.java index 1663ceed8..62e7006db 100644 --- a/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/config/FeatureStageTemplate.java +++ b/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/config/FeatureStageTemplate.java @@ -1,23 +1,46 @@ package com.dfsek.terra.addons.generation.feature.config; +import com.dfsek.tectonic.api.config.template.ValidatedConfigTemplate; +import com.dfsek.tectonic.api.config.template.annotations.Default; import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import com.dfsek.tectonic.api.exception.ValidationException; import com.dfsek.terra.addons.generation.feature.FeatureGenerationStage; import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage; -public class FeatureStageTemplate implements ObjectTemplate { +public class FeatureStageTemplate implements ObjectTemplate, ValidatedConfigTemplate { private final Platform platform; + private final PropertyKey biomeFeaturesKey; @Value("id") private String id; - public FeatureStageTemplate(Platform platform) { this.platform = platform; } + @Value("resolution") + @Default + private int resolution = 4; + + public FeatureStageTemplate(Platform platform, PropertyKey biomeFeaturesKey) { + this.platform = platform; + this.biomeFeaturesKey = biomeFeaturesKey; + } @Override public FeatureGenerationStage get() { - return new FeatureGenerationStage(platform, id); + return new FeatureGenerationStage(platform, id, resolution, biomeFeaturesKey); + } + + @Override + public boolean validate() throws ValidationException { + if(!(resolution == 1 + || resolution == 2 + || resolution == 4 + || resolution == 8 + || resolution == 16)) throw new ValidationException( + "Resolution must be power of 2 less than or equal to 16 (1, 2, 4, 8, 16), got: " + resolution); + return true; } } diff --git a/common/addons/structure-sponge-loader/build.gradle.kts b/common/addons/structure-sponge-loader/build.gradle.kts index d064e4fd5..dba93405f 100644 --- a/common/addons/structure-sponge-loader/build.gradle.kts +++ b/common/addons/structure-sponge-loader/build.gradle.kts @@ -2,10 +2,6 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar version = version("1.0.0") -repositories { - maven { url = uri("https://jitpack.io/") } -} - dependencies { api("commons-io:commons-io:2.7") api("com.github.Querz:NBT:6.1") diff --git a/common/addons/structure-terrascript-loader/build.gradle.kts b/common/addons/structure-terrascript-loader/build.gradle.kts index 62422cc79..18d4019b9 100644 --- a/common/addons/structure-terrascript-loader/build.gradle.kts +++ b/common/addons/structure-terrascript-loader/build.gradle.kts @@ -1,6 +1,6 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -version = version("1.0.1") +version = version("1.1.0") dependencies { api("commons-io:commons-io:2.7") diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java index 56aa24b87..2b344343a 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java @@ -15,9 +15,12 @@ import java.util.Map; import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.Executable; import com.dfsek.terra.addons.terrascript.parser.lang.Item; import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable.ReturnType; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder; import com.dfsek.terra.addons.terrascript.parser.lang.constants.BooleanConstant; import com.dfsek.terra.addons.terrascript.parser.lang.constants.ConstantExpression; import com.dfsek.terra.addons.terrascript.parser.lang.constants.NumericConstant; @@ -48,12 +51,17 @@ import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.Grea import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.LessThanOrEqualsStatement; import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.LessThanStatement; import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.NotEqualsStatement; -import com.dfsek.terra.addons.terrascript.parser.lang.variables.VariableAssignmentNode; -import com.dfsek.terra.addons.terrascript.parser.lang.variables.VariableDeclarationNode; -import com.dfsek.terra.addons.terrascript.parser.lang.variables.VariableReferenceNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.BoolAssignmentNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.NumAssignmentNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.StrAssignmentNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.VariableAssignmentNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.BoolVariableReferenceNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.NumVariableReferenceNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.StrVariableReferenceNode; import com.dfsek.terra.addons.terrascript.tokenizer.Position; import com.dfsek.terra.addons.terrascript.tokenizer.Token; import com.dfsek.terra.addons.terrascript.tokenizer.Tokenizer; +import com.dfsek.terra.api.util.generic.pair.Pair; @SuppressWarnings("unchecked") @@ -83,11 +91,12 @@ public class Parser { * * @throws ParseException If parsing fails. */ - public Block parse() { - return parseBlock(new Tokenizer(data), new HashMap<>(), false); + public Executable parse() { + ScopeBuilder scopeBuilder = new ScopeBuilder(); + return new Executable(parseBlock(new Tokenizer(data), false, scopeBuilder), scopeBuilder); } - private Keyword parseLoopLike(Tokenizer tokens, Map variableMap, boolean loop) throws ParseException { + private Keyword parseLoopLike(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) throws ParseException { Token identifier = tokens.consume(); ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP); @@ -95,43 +104,43 @@ public class Parser { ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); return switch(identifier.getType()) { - case FOR_LOOP -> parseForLoop(tokens, variableMap, identifier.getPosition()); - case IF_STATEMENT -> parseIfStatement(tokens, variableMap, identifier.getPosition(), loop); - case WHILE_LOOP -> parseWhileLoop(tokens, variableMap, identifier.getPosition()); + case FOR_LOOP -> parseForLoop(tokens, identifier.getPosition(), scopeBuilder); + case IF_STATEMENT -> parseIfStatement(tokens, identifier.getPosition(), loop, scopeBuilder); + case WHILE_LOOP -> parseWhileLoop(tokens, identifier.getPosition(), scopeBuilder); default -> throw new UnsupportedOperationException( "Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition()); }; } - private WhileKeyword parseWhileLoop(Tokenizer tokens, Map variableMap, Position start) { - Returnable first = parseExpression(tokens, true, variableMap); + private WhileKeyword parseWhileLoop(Tokenizer tokens, Position start, ScopeBuilder scopeBuilder) { + Returnable first = parseExpression(tokens, true, scopeBuilder); ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN); ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); - return new WhileKeyword(parseStatementBlock(tokens, variableMap, true), (Returnable) first, start); // While loop + return new WhileKeyword(parseStatementBlock(tokens, true, scopeBuilder), (Returnable) first, start); // While loop } - private IfKeyword parseIfStatement(Tokenizer tokens, Map variableMap, Position start, boolean loop) { - Returnable condition = parseExpression(tokens, true, variableMap); + private IfKeyword parseIfStatement(Tokenizer tokens, Position start, boolean loop, ScopeBuilder scopeBuilder) { + Returnable condition = parseExpression(tokens, true, scopeBuilder); ParserUtil.checkReturnType(condition, Returnable.ReturnType.BOOLEAN); ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); Block elseBlock = null; - Block statement = parseStatementBlock(tokens, variableMap, loop); + Block statement = parseStatementBlock(tokens, loop, scopeBuilder); - List, Block>> elseIf = new ArrayList<>(); + List, Block>> elseIf = new ArrayList<>(); while(tokens.hasNext() && tokens.get().getType().equals(Token.Type.ELSE)) { tokens.consume(); // Consume else. if(tokens.get().getType().equals(Token.Type.IF_STATEMENT)) { tokens.consume(); // Consume if. - Returnable elseCondition = parseExpression(tokens, true, variableMap); + Returnable elseCondition = parseExpression(tokens, true, scopeBuilder); ParserUtil.checkReturnType(elseCondition, Returnable.ReturnType.BOOLEAN); - elseIf.add(new IfKeyword.Pair<>((Returnable) elseCondition, parseStatementBlock(tokens, variableMap, loop))); + elseIf.add(Pair.of((Returnable) elseCondition, parseStatementBlock(tokens, loop, scopeBuilder))); } else { - elseBlock = parseStatementBlock(tokens, variableMap, loop); + elseBlock = parseStatementBlock(tokens, loop, scopeBuilder); break; // Else must be last. } } @@ -139,51 +148,51 @@ public class Parser { return new IfKeyword(statement, (Returnable) condition, elseIf, elseBlock, start); // If statement } - private Block parseStatementBlock(Tokenizer tokens, Map variableMap, boolean loop) { + private Block parseStatementBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) { if(tokens.get().getType().equals(Token.Type.BLOCK_BEGIN)) { ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN); - Block block = parseBlock(tokens, variableMap, loop); + Block block = parseBlock(tokens, loop, scopeBuilder); ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END); return block; } else { Position position = tokens.get().getPosition(); - Block block = new Block(Collections.singletonList(parseItem(tokens, variableMap, loop)), position); + Block block = new Block(Collections.singletonList(parseItem(tokens, loop, scopeBuilder)), position); ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); return block; } } - private ForKeyword parseForLoop(Tokenizer tokens, Map old, Position start) { - Map variableMap = new HashMap<>(old); // New scope + private ForKeyword parseForLoop(Tokenizer tokens, Position start, ScopeBuilder scopeBuilder) { + scopeBuilder = scopeBuilder.sub(); // new scope Token f = tokens.get(); ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER); Item initializer; if(f.isVariableDeclaration()) { - VariableDeclarationNode forVar = parseVariableDeclaration(tokens, variableMap); + VariableAssignmentNode forVar = parseVariableDeclaration(tokens, scopeBuilder); Token name = tokens.get(); - if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent())) + if(functions.containsKey(name.getContent()) || scopeBuilder.contains(name.getContent())) throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition()); initializer = forVar; - } else initializer = parseExpression(tokens, true, variableMap); + } else initializer = parseExpression(tokens, true, scopeBuilder); ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); - Returnable conditional = parseExpression(tokens, true, variableMap); + Returnable conditional = parseExpression(tokens, true, scopeBuilder); ParserUtil.checkReturnType(conditional, Returnable.ReturnType.BOOLEAN); ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); Item incrementer; Token token = tokens.get(); - if(variableMap.containsKey(token.getContent())) { // Assume variable assignment - incrementer = parseAssignment(tokens, variableMap); - } else incrementer = parseFunction(tokens, true, variableMap); + if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment + incrementer = parseAssignment(tokens, scopeBuilder); + } else incrementer = parseFunction(tokens, true, scopeBuilder); ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); - return new ForKeyword(parseStatementBlock(tokens, variableMap, true), initializer, (Returnable) conditional, incrementer, + return new ForKeyword(parseStatementBlock(tokens, true, scopeBuilder), initializer, (Returnable) conditional, incrementer, start); } - private Returnable parseExpression(Tokenizer tokens, boolean full, Map variableMap) { + private Returnable parseExpression(Tokenizer tokens, boolean full, ScopeBuilder scopeBuilder) { boolean booleanInverted = false; // Check for boolean not operator boolean negate = false; if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) { @@ -202,13 +211,21 @@ public class Parser { if(id.isConstant()) { expression = parseConstantExpression(tokens); } else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression - expression = parseGroup(tokens, variableMap); + expression = parseGroup(tokens, scopeBuilder); } else { if(functions.containsKey(id.getContent())) - expression = parseFunction(tokens, false, variableMap); - else if(variableMap.containsKey(id.getContent())) { + expression = parseFunction(tokens, false, scopeBuilder); + else if(scopeBuilder.contains(id.getContent())) { ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER); - expression = new VariableReferenceNode(id.getContent(), id.getPosition(), variableMap.get(id.getContent())); + String varId = id.getContent(); + ReturnType varType = scopeBuilder.getType(varId); + expression = switch(varType) { + case NUMBER -> new NumVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId)); + case STRING -> new StrVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId)); + case BOOLEAN -> new BoolVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId)); + default -> throw new ParseException("Illegal type for variable reference: " + varType, id.getPosition()); + }; + } else throw new ParseException("Unexpected token \" " + id.getContent() + "\"", id.getPosition()); } @@ -221,7 +238,7 @@ public class Parser { } if(full && tokens.get().isBinaryOperator()) { // Parse binary operations - return parseBinaryOperation(expression, tokens, variableMap); + return parseBinaryOperation(expression, tokens, scopeBuilder); } return expression; } @@ -243,25 +260,25 @@ public class Parser { } } - private Returnable parseGroup(Tokenizer tokens, Map variableMap) { + private Returnable parseGroup(Tokenizer tokens, ScopeBuilder scopeBuilder) { ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); - Returnable expression = parseExpression(tokens, true, variableMap); // Parse inside of group as a separate expression + Returnable expression = parseExpression(tokens, true, scopeBuilder); // Parse inside of group as a separate expression ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); return expression; } private BinaryOperation parseBinaryOperation(Returnable left, Tokenizer tokens, - Map variableMap) { + ScopeBuilder scopeBuilder) { Token binaryOperator = tokens.consume(); ParserUtil.checkBinaryOperator(binaryOperator); - Returnable right = parseExpression(tokens, false, variableMap); + Returnable right = parseExpression(tokens, false, scopeBuilder); Token other = tokens.get(); if(ParserUtil.hasPrecedence(binaryOperator.getType(), other.getType())) { - return assemble(left, parseBinaryOperation(right, tokens, variableMap), binaryOperator); + return assemble(left, parseBinaryOperation(right, tokens, scopeBuilder), binaryOperator); } else if(other.isBinaryOperator()) { - return parseBinaryOperation(assemble(left, right, binaryOperator), tokens, variableMap); + return parseBinaryOperation(assemble(left, right, binaryOperator), tokens, scopeBuilder); } return assemble(left, right, binaryOperator); } @@ -306,7 +323,7 @@ public class Parser { } } - private VariableDeclarationNode parseVariableDeclaration(Tokenizer tokens, Map variableMap) { + private VariableAssignmentNode parseVariableDeclaration(Tokenizer tokens, ScopeBuilder scopeBuilder) { Token type = tokens.consume(); ParserUtil.checkType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE); @@ -315,30 +332,34 @@ public class Parser { ParserUtil.checkVarType(type, returnType); // Check for type mismatch Token identifier = tokens.consume(); ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); - if(functions.containsKey(identifier.getContent()) || variableMap.containsKey(identifier.getContent())) + if(functions.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent())) throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition()); ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT); - Returnable value = parseExpression(tokens, true, variableMap); + Returnable value = parseExpression(tokens, true, scopeBuilder); ParserUtil.checkReturnType(value, returnType); - - variableMap.put(identifier.getContent(), returnType); - - return new VariableDeclarationNode<>(tokens.get().getPosition(), identifier.getContent(), value, returnType); + + String id = identifier.getContent(); + + return switch(value.returnType()) { + case NUMBER -> new NumAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.num(id)); + case STRING -> new StrAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.str(id)); + case BOOLEAN -> new BoolAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.bool(id)); + default -> throw new ParseException("Illegal type for variable declaration: " + type, value.getPosition()); + }; } - private Block parseBlock(Tokenizer tokens, Map superVars, boolean loop) { + private Block parseBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) { List> parsedItems = new ArrayList<>(); - Map parsedVariables = new HashMap<>( - superVars); // New hashmap as to not mutate parent scope's declarations. + scopeBuilder = scopeBuilder.sub(); Token first = tokens.get(); while(tokens.hasNext()) { Token token = tokens.get(); if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end. - Item parsedItem = parseItem(tokens, parsedVariables, loop); + Item parsedItem = parseItem(tokens, loop, scopeBuilder); if(parsedItem != Function.NULL) { parsedItems.add(parsedItem); } @@ -347,7 +368,7 @@ public class Parser { return new Block(parsedItems, first.getPosition()); } - private Item parseItem(Tokenizer tokens, Map variableMap, boolean loop) { + private Item parseItem(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) { Token token = tokens.get(); if(loop) ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, @@ -357,14 +378,14 @@ public class Parser { Token.Type.FAIL); if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc) - return parseLoopLike(tokens, variableMap, loop); + return parseLoopLike(tokens, loop, scopeBuilder); } else if(token.isIdentifier()) { // Parse identifiers - if(variableMap.containsKey(token.getContent())) { // Assume variable assignment - return parseAssignment(tokens, variableMap); - } else return parseFunction(tokens, true, variableMap); + if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment + return parseAssignment(tokens, scopeBuilder); + } else return parseFunction(tokens, true, scopeBuilder); } else if(token.isVariableDeclaration()) { - return parseVariableDeclaration(tokens, variableMap); + return parseVariableDeclaration(tokens, scopeBuilder); } else if(token.getType().equals(Token.Type.RETURN)) return new ReturnKeyword(tokens.consume().getPosition()); else if(token.getType().equals(Token.Type.BREAK)) return new BreakKeyword(tokens.consume().getPosition()); @@ -373,21 +394,30 @@ public class Parser { else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition()); } - private VariableAssignmentNode parseAssignment(Tokenizer tokens, Map variableMap) { + private VariableAssignmentNode parseAssignment(Tokenizer tokens, ScopeBuilder scopeBuilder) { Token identifier = tokens.consume(); ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT); - Returnable value = parseExpression(tokens, true, variableMap); + Returnable value = parseExpression(tokens, true, scopeBuilder); - ParserUtil.checkReturnType(value, variableMap.get(identifier.getContent())); + String id = identifier.getContent(); - return new VariableAssignmentNode<>(value, identifier.getContent(), identifier.getPosition()); + ParserUtil.checkReturnType(value, scopeBuilder.getType(id)); + + ReturnType type = value.returnType(); + + return switch(type) { + case NUMBER -> new NumAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.getIndex(id)); + case STRING -> new StrAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.getIndex(id)); + case BOOLEAN -> new BoolAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.getIndex(id)); + default -> throw new ParseException("Illegal type for variable assignment: " + type, value.getPosition()); + }; } - private Function parseFunction(Tokenizer tokens, boolean fullStatement, Map variableMap) { + private Function parseFunction(Tokenizer tokens, boolean fullStatement, ScopeBuilder scopeBuilder) { Token identifier = tokens.consume(); ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier @@ -397,7 +427,7 @@ public class Parser { ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); // Second is body begin - List> args = getArgs(tokens, variableMap); // Extract arguments, consume the rest. + List> args = getArgs(tokens, scopeBuilder); // Extract arguments, consume the rest. ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); // Remove body end @@ -425,11 +455,11 @@ public class Parser { throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent()); } - private List> getArgs(Tokenizer tokens, Map variableMap) { + private List> getArgs(Tokenizer tokens, ScopeBuilder scopeBuilder) { List> args = new ArrayList<>(); while(!tokens.get().getType().equals(Token.Type.GROUP_END)) { - args.add(parseExpression(tokens, true, variableMap)); + args.add(parseExpression(tokens, true, scopeBuilder)); ParserUtil.checkType(tokens.get(), Token.Type.SEPARATOR, Token.Type.GROUP_END); if(tokens.get().getType().equals(Token.Type.SEPARATOR)) tokens.consume(); } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Block.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Block.java index 473d033ef..65a8dbf7e 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Block.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Block.java @@ -21,23 +21,8 @@ public class Block implements Item> { this.position = position; } - public ReturnInfo apply(ImplementationArguments implementationArguments) { - return apply(implementationArguments, new Scope()); - } - @Override public ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { - Scope sub = scope.sub(); - for(Item item : items) { - Object result = item.apply(implementationArguments, sub); - if(result instanceof ReturnInfo level) { - if(!level.getLevel().equals(ReturnLevel.NONE)) return level; - } - } - return new ReturnInfo<>(ReturnLevel.NONE, null); - } - - public ReturnInfo applyNoNewScope(ImplementationArguments implementationArguments, Scope scope) { for(Item item : items) { Object result = item.apply(implementationArguments, scope); if(result instanceof ReturnInfo level) { @@ -52,10 +37,6 @@ public class Block implements Item> { return position; } - public List> getItems() { - return items; - } - public enum ReturnLevel { NONE(false), BREAK(false), diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Executable.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Executable.java new file mode 100644 index 000000000..6f9c026a0 --- /dev/null +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Executable.java @@ -0,0 +1,19 @@ +package com.dfsek.terra.addons.terrascript.parser.lang; + + +import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder; + + +public class Executable { + private final Block script; + private final ThreadLocal scope; + + public Executable(Block script, ScopeBuilder scopeBuilder) { + this.script = script; + this.scope = ThreadLocal.withInitial(scopeBuilder::build); + } + + public boolean execute(ImplementationArguments arguments) { + return script.apply(arguments, scope.get()).getLevel() != Block.ReturnLevel.FAIL; + } +} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Item.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Item.java index 10065bfc9..27947c291 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Item.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Item.java @@ -13,5 +13,13 @@ import com.dfsek.terra.addons.terrascript.tokenizer.Position; public interface Item { T apply(ImplementationArguments implementationArguments, Scope scope); + default double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + throw new UnsupportedOperationException("Cannot apply " + this + " as double"); + } + + default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + throw new UnsupportedOperationException("Cannot apply " + this + " as double"); + } + Position getPosition(); } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java index a511e2db4..511c486bd 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java @@ -1,46 +1,138 @@ package com.dfsek.terra.addons.terrascript.parser.lang; + +import net.jafama.FastMath; + import java.util.HashMap; import java.util.Map; -import com.dfsek.terra.addons.terrascript.parser.lang.variables.Variable; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable.ReturnType; +import com.dfsek.terra.api.util.generic.pair.Pair; public class Scope { - private static final Scope NULL = new Scope() { - @Override - public Variable get(String id) { - throw new IllegalStateException("Cannot get variable from null scope: " + id); + private final double[] num; + private final boolean[] bool; + private final String[] str; + + private Scope(int numSize, int boolSize, int strSize) { + this.num = new double[numSize]; + this.bool = new boolean[boolSize]; + this.str = new String[strSize]; + } + + public double getNum(int index) { + return num[index]; + } + + public boolean getBool(int index) { + return bool[index]; + } + + public String getStr(int index) { + return str[index]; + } + + public void setNum(int index, double value) { + num[index] = value; + } + + public void setBool(int index, boolean value) { + bool[index] = value; + } + + public void setStr(int index, String value) { + str[index] = value; + } + + public static final class ScopeBuilder { + private final Map> indices; + private int numSize, boolSize, strSize = 0; + private ScopeBuilder parent; + + public ScopeBuilder() { + this.indices = new HashMap<>(); } - @Override - public void put(String id, Variable variable) { - throw new IllegalStateException("Cannot set variable in null scope: " + id); + private ScopeBuilder(ScopeBuilder parent) { + this.parent = parent; + this.numSize = parent.numSize; + this.boolSize = parent.boolSize; + this.strSize = parent.strSize; + this.indices = new HashMap<>(parent.indices); + } + + public Scope build() { + return new Scope(numSize, boolSize, strSize); + } + + public ScopeBuilder sub() { + return new ScopeBuilder(this); + } + + private String check(String id) { + if(indices.containsKey(id)) { + throw new IllegalArgumentException("Variable with ID " + id + " already registered."); + } + return id; + } + + public int num(String id) { + int num = numSize; + indices.put(check(id), Pair.of(num, ReturnType.NUMBER)); + numSize++; + updateNumSize(numSize); + return num; + } + + public int str(String id) { + int str = strSize; + indices.put(check(id), Pair.of(str, ReturnType.STRING)); + strSize++; + updateStrSize(strSize); + return str; + } + + public int bool(String id) { + int bool = boolSize; + indices.put(check(id), Pair.of(bool, ReturnType.BOOLEAN)); + boolSize++; + updateBoolSize(boolSize); + return bool; + } + + private void updateBoolSize(int size) { + this.boolSize = FastMath.max(boolSize, size); + if(parent != null) { + parent.updateBoolSize(size); + } + } + + private void updateNumSize(int size) { + this.numSize = FastMath.max(numSize, size); + if(parent != null) { + parent.updateNumSize(size); + } + } + + private void updateStrSize(int size) { + this.strSize = FastMath.max(strSize, size); + if(parent != null) { + parent.updateStrSize(size); + } + } + + public int getIndex(String id) { + return indices.get(id).getLeft(); + } + + public ReturnType getType(String id) { + return indices.get(id).getRight(); + } + + + public boolean contains(String id) { + return indices.containsKey(id); } - }; - - private final Scope parent; - private final Map> variableMap = new HashMap<>(); - - public Scope(Scope parent) { - this.parent = parent; - } - - public Scope() { - this.parent = NULL; - } - - public Variable get(String id) { - Variable var = variableMap.get(id); - return var == null ? parent.get(id) : var; - } - - public void put(String id, Variable variable) { - variableMap.put(id, variable); - } - - - public Scope sub() { - return new Scope(this); } } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/BooleanConstant.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/BooleanConstant.java index b61e05364..3782344d1 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/BooleanConstant.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/BooleanConstant.java @@ -7,12 +7,22 @@ package com.dfsek.terra.addons.terrascript.parser.lang.constants; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; public class BooleanConstant extends ConstantExpression { + private final boolean constant; + public BooleanConstant(Boolean constant, Position position) { super(constant, position); + this.constant = constant; + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return constant; } @Override diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/NumericConstant.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/NumericConstant.java index 911f601f2..296b0c3e4 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/NumericConstant.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/NumericConstant.java @@ -7,13 +7,23 @@ package com.dfsek.terra.addons.terrascript.parser.lang.constants; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; public class NumericConstant extends ConstantExpression { + private final double constant; + public NumericConstant(Number constant, Position position) { super(constant, position); + this.constant = constant.doubleValue(); + } + + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return constant; } @Override diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/Function.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/Function.java index da27138b6..9c1da1155 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/Function.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/Function.java @@ -19,15 +19,25 @@ public interface Function extends Returnable { public ReturnType returnType() { return null; } - + @Override public Object apply(ImplementationArguments implementationArguments, Scope scope) { return null; } - + @Override public Position getPosition() { return null; } }; + + @Override + default double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return ((Number) apply(implementationArguments, scope)).doubleValue(); + } + + @Override + default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return (Boolean) apply(implementationArguments, scope); + } } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/ForKeyword.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/ForKeyword.java index eebd67183..49f874724 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/ForKeyword.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/ForKeyword.java @@ -33,11 +33,10 @@ public class ForKeyword implements Keyword> { @Override public Block.ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { - Scope sub = scope.sub(); - for(initializer.apply(implementationArguments, sub); - statement.apply(implementationArguments, sub); - incrementer.apply(implementationArguments, sub)) { - Block.ReturnInfo level = conditional.applyNoNewScope(implementationArguments, sub); + for(initializer.apply(implementationArguments, scope); + statement.apply(implementationArguments, scope); + incrementer.apply(implementationArguments, scope)) { + Block.ReturnInfo level = conditional.apply(implementationArguments, scope); if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break; if(level.getLevel().isReturnFast()) return level; } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/IfKeyword.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/IfKeyword.java index c3737433e..f49cab112 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/IfKeyword.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/IfKeyword.java @@ -17,6 +17,7 @@ import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; +import com.dfsek.terra.api.util.generic.pair.Pair; public class IfKeyword implements Keyword> { @@ -58,23 +59,4 @@ public class IfKeyword implements Keyword> { public ReturnType returnType() { return ReturnType.VOID; } - - - public static class Pair { - private final L left; - private final R right; - - public Pair(L left, R right) { - this.left = left; - this.right = right; - } - - public L getLeft() { - return left; - } - - public R getRight() { - return right; - } - } } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BinaryOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BinaryOperation.java index 11a4d74e8..fdacebe4c 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BinaryOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BinaryOperation.java @@ -7,17 +7,13 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import java.util.function.Supplier; - -import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; -import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; public abstract class BinaryOperation implements Returnable { - private final Returnable left; - private final Returnable right; + protected final Returnable left; + protected final Returnable right; private final Position start; public BinaryOperation(Returnable left, Returnable right, Position start) { @@ -26,13 +22,6 @@ public abstract class BinaryOperation implements Returnable { this.start = start; } - public abstract O apply(Supplier left, Supplier right); - - @Override - public O apply(ImplementationArguments implementationArguments, Scope scope) { - return apply(() -> left.apply(implementationArguments, scope), () -> right.apply(implementationArguments, scope)); - } - @Override public Position getPosition() { return start; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanAndOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanAndOperation.java index 6018b21d0..94a08bbe6 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanAndOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanAndOperation.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -18,13 +18,18 @@ public class BooleanAndOperation extends BinaryOperation { super(left, right, start); } - @Override - public Boolean apply(Supplier left, Supplier right) { - return left.get() && right.get(); - } - @Override public ReturnType returnType() { return ReturnType.BOOLEAN; } + + @Override + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return left.applyBoolean(implementationArguments, scope) && right.applyBoolean(implementationArguments, scope); + } } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanNotOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanNotOperation.java index e1b4d2fed..a65e00184 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanNotOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanNotOperation.java @@ -7,7 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -17,8 +19,13 @@ public class BooleanNotOperation extends UnaryOperation { } @Override - public Boolean apply(Boolean input) { - return !input; + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return !input.applyBoolean(implementationArguments, scope); } @Override diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanOrOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanOrOperation.java index 90b11cf86..4722e175c 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanOrOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanOrOperation.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -19,10 +19,15 @@ public class BooleanOrOperation extends BinaryOperation { } @Override - public Boolean apply(Supplier left, Supplier right) { - return left.get() || right.get(); + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); } + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return left.applyBoolean(implementationArguments, scope) || right.applyBoolean(implementationArguments, scope); + } + @Override public ReturnType returnType() { return ReturnType.BOOLEAN; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ConcatenationOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ConcatenationOperation.java index 79fd3d103..1ff9d11b1 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ConcatenationOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ConcatenationOperation.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -18,13 +18,24 @@ public class ConcatenationOperation extends BinaryOperation { super(left, right, position); } - @Override - public String apply(Supplier left, Supplier right) { - return left.get().toString() + right.get().toString(); + private static String toString(Object object) { + String s = object.toString(); + if(object instanceof Double) { + int l = s.length(); + if(s.charAt(l - 2) == '.' && s.charAt(l - 1) == '0') { + s = s.substring(0, s.length() - 2); + } + } + return s; } @Override public Returnable.ReturnType returnType() { return Returnable.ReturnType.STRING; } + + @Override + public Object apply(ImplementationArguments implementationArguments, Scope scope) { + return toString(left.apply(implementationArguments, scope)) + toString(right.apply(implementationArguments, scope)); + } } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/DivisionOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/DivisionOperation.java index b6d76c451..793012549 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/DivisionOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/DivisionOperation.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -18,13 +18,18 @@ public class DivisionOperation extends BinaryOperation { super(left, right, position); } - @Override - public Number apply(Supplier left, Supplier right) { - return left.get().doubleValue() / right.get().doubleValue(); - } - @Override public Returnable.ReturnType returnType() { return Returnable.ReturnType.NUMBER; } + + @Override + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return applyDouble(implementationArguments, scope); + } + + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return left.applyDouble(implementationArguments, scope) / right.applyDouble(implementationArguments, scope); + } } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ModuloOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ModuloOperation.java index a22439b6d..b305f4c90 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ModuloOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ModuloOperation.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -19,10 +19,15 @@ public class ModuloOperation extends BinaryOperation { } @Override - public Number apply(Supplier left, Supplier right) { - return left.get().doubleValue() % right.get().doubleValue(); + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return applyDouble(implementationArguments, scope); } + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return left.applyDouble(implementationArguments, scope) % right.applyDouble(implementationArguments, scope); + } + @Override public ReturnType returnType() { return ReturnType.NUMBER; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/MultiplicationOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/MultiplicationOperation.java index 232d8ee52..2a2cdbfe6 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/MultiplicationOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/MultiplicationOperation.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -19,10 +19,15 @@ public class MultiplicationOperation extends BinaryOperation { } @Override - public Number apply(Supplier left, Supplier right) { - return left.get().doubleValue() * right.get().doubleValue(); + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return applyDouble(implementationArguments, scope); } + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return left.applyDouble(implementationArguments, scope) * right.applyDouble(implementationArguments, scope); + } + @Override public ReturnType returnType() { return ReturnType.NUMBER; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NegationOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NegationOperation.java index 2f9ee5161..32d8f39b6 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NegationOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NegationOperation.java @@ -7,7 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -16,13 +18,18 @@ public class NegationOperation extends UnaryOperation { super(input, position); } - @Override - public Number apply(Number input) { - return -input.doubleValue(); - } - @Override public ReturnType returnType() { return ReturnType.NUMBER; } + + @Override + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return applyDouble(implementationArguments, scope); + } + + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return -input.applyDouble(implementationArguments, scope); + } } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NumberAdditionOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NumberAdditionOperation.java index 7baa56df3..075a27619 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NumberAdditionOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NumberAdditionOperation.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -19,10 +19,15 @@ public class NumberAdditionOperation extends BinaryOperation { } @Override - public Number apply(Supplier left, Supplier right) { - return left.get().doubleValue() + right.get().doubleValue(); + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return applyDouble(implementationArguments, scope); } + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return left.applyDouble(implementationArguments, scope) + right.applyDouble(implementationArguments, scope); + } + @Override public ReturnType returnType() { return ReturnType.NUMBER; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/SubtractionOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/SubtractionOperation.java index 70e6709b7..9a11c430f 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/SubtractionOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/SubtractionOperation.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -19,10 +19,15 @@ public class SubtractionOperation extends BinaryOperation { } @Override - public Number apply(Supplier left, Supplier right) { - return left.get().doubleValue() - right.get().doubleValue(); + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return applyDouble(implementationArguments, scope); } + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return left.applyDouble(implementationArguments, scope) - right.applyDouble(implementationArguments, scope); + } + @Override public ReturnType returnType() { return ReturnType.NUMBER; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/UnaryOperation.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/UnaryOperation.java index b8e9c1770..d83ab0ad2 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/UnaryOperation.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/UnaryOperation.java @@ -7,14 +7,12 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations; -import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; -import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; public abstract class UnaryOperation implements Returnable { - private final Returnable input; + protected final Returnable input; private final Position position; public UnaryOperation(Returnable input, Position position) { @@ -22,13 +20,6 @@ public abstract class UnaryOperation implements Returnable { this.position = position; } - public abstract T apply(T input); - - @Override - public T apply(ImplementationArguments implementationArguments, Scope scope) { - return apply(input.apply(implementationArguments, scope)); - } - @Override public Position getPosition() { return position; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/EqualsStatement.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/EqualsStatement.java index 9c9b73e0f..f402e4862 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/EqualsStatement.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/EqualsStatement.java @@ -9,9 +9,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements; import net.jafama.FastMath; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -24,20 +24,25 @@ public class EqualsStatement extends BinaryOperation { super(left, right, position); } - @Override - public Boolean apply(Supplier left, Supplier right) { - Object leftUnwrapped = left.get(); - Object rightUnwrapped = right.get(); - if(leftUnwrapped instanceof Number l && rightUnwrapped instanceof Number r) { - return FastMath.abs(l.doubleValue() - r.doubleValue()) <= EPSILON; - } - - return leftUnwrapped.equals(rightUnwrapped); - } - @Override public Returnable.ReturnType returnType() { return Returnable.ReturnType.BOOLEAN; } + + @Override + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + Object leftValue = left.apply(implementationArguments, scope); + Object rightValue = right.apply(implementationArguments, scope); + if(leftValue instanceof Number l && rightValue instanceof Number r) { + return FastMath.abs(l.doubleValue() - r.doubleValue()) <= EPSILON; + } + + return leftValue.equals(rightValue); + } } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterOrEqualsThanStatement.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterOrEqualsThanStatement.java index 2c795b1c9..d25f6bd0d 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterOrEqualsThanStatement.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterOrEqualsThanStatement.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -19,14 +19,18 @@ public class GreaterOrEqualsThanStatement extends BinaryOperation left, Supplier right) { - return left.get().doubleValue() >= right.get().doubleValue(); - } - - @Override public Returnable.ReturnType returnType() { return Returnable.ReturnType.BOOLEAN; } + + @Override + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return left.applyDouble(implementationArguments, scope) >= right.applyDouble(implementationArguments, scope); + } } diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterThanStatement.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterThanStatement.java index a6c7d8e52..8e5cc4aee 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterThanStatement.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterThanStatement.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -19,11 +19,16 @@ public class GreaterThanStatement extends BinaryOperation { super(left, right, position); } + @Override - public Boolean apply(Supplier left, Supplier right) { - return left.get().doubleValue() > right.get().doubleValue(); + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); } + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return left.applyDouble(implementationArguments, scope) > right.applyDouble(implementationArguments, scope); + } @Override public Returnable.ReturnType returnType() { diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanOrEqualsStatement.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanOrEqualsStatement.java index d798a6590..891210395 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanOrEqualsStatement.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanOrEqualsStatement.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -19,12 +19,17 @@ public class LessThanOrEqualsStatement extends BinaryOperation super(left, right, position); } + @Override - public Boolean apply(Supplier left, Supplier right) { - return left.get().doubleValue() <= right.get().doubleValue(); + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); } - + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return left.applyDouble(implementationArguments, scope) <= right.applyDouble(implementationArguments, scope); + } + @Override public Returnable.ReturnType returnType() { return Returnable.ReturnType.BOOLEAN; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanStatement.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanStatement.java index 04bca475c..969f0e27e 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanStatement.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanStatement.java @@ -7,9 +7,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -19,12 +19,17 @@ public class LessThanStatement extends BinaryOperation { super(left, right, position); } + @Override - public Boolean apply(Supplier left, Supplier right) { - return left.get().doubleValue() < right.get().doubleValue(); + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); } - + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return left.applyDouble(implementationArguments, scope) < right.applyDouble(implementationArguments, scope); + } + @Override public Returnable.ReturnType returnType() { return Returnable.ReturnType.BOOLEAN; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/NotEqualsStatement.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/NotEqualsStatement.java index 20fb34fe3..3241c8657 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/NotEqualsStatement.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/NotEqualsStatement.java @@ -9,9 +9,9 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements; import net.jafama.FastMath; -import java.util.function.Supplier; - +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; import com.dfsek.terra.addons.terrascript.tokenizer.Position; @@ -24,16 +24,20 @@ public class NotEqualsStatement extends BinaryOperation { } @Override - public Boolean apply(Supplier left, Supplier right) { - Object leftUnwrapped = left.get(); - Object rightUnwrapped = right.get(); - if(leftUnwrapped instanceof Number l && rightUnwrapped instanceof Number r) { - return FastMath.abs(l.doubleValue() - r.doubleValue()) > EPSILON; - } - - return !leftUnwrapped.equals(rightUnwrapped); + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); } + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + Object leftValue = left.apply(implementationArguments, scope); + Object rightValue = right.apply(implementationArguments, scope); + if(leftValue instanceof Number l && rightValue instanceof Number r) { + return FastMath.abs(l.doubleValue() - r.doubleValue()) > EPSILON; + } + + return !leftValue.equals(rightValue); + } @Override public Returnable.ReturnType returnType() { diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/VariableAssignmentNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/VariableAssignmentNode.java deleted file mode 100644 index af833d570..000000000 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/VariableAssignmentNode.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2020-2021 Polyhedral Development - * - * The Terra Core Addons are licensed under the terms of the MIT License. For more details, - * reference the LICENSE file in this module's root directory. - */ - -package com.dfsek.terra.addons.terrascript.parser.lang.variables; - -import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; -import com.dfsek.terra.addons.terrascript.parser.lang.Item; -import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; -import com.dfsek.terra.addons.terrascript.parser.lang.Scope; -import com.dfsek.terra.addons.terrascript.tokenizer.Position; - - -public class VariableAssignmentNode implements Item { - private final Returnable value; - private final Position position; - private final String identifier; - - public VariableAssignmentNode(Returnable value, String identifier, Position position) { - this.value = value; - this.identifier = identifier; - this.position = position; - } - - @SuppressWarnings("unchecked") - @Override - public synchronized T apply(ImplementationArguments implementationArguments, Scope scope) { - T val = value.apply(implementationArguments, scope); - ((Variable) scope.get(identifier)).setValue(val); - return val; - } - - @Override - public Position getPosition() { - return position; - } -} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/VariableDeclarationNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/VariableDeclarationNode.java deleted file mode 100644 index ceae122a3..000000000 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/VariableDeclarationNode.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2020-2021 Polyhedral Development - * - * The Terra Core Addons are licensed under the terms of the MIT License. For more details, - * reference the LICENSE file in this module's root directory. - */ - -package com.dfsek.terra.addons.terrascript.parser.lang.variables; - -import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; -import com.dfsek.terra.addons.terrascript.parser.lang.Item; -import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; -import com.dfsek.terra.addons.terrascript.parser.lang.Scope; -import com.dfsek.terra.addons.terrascript.tokenizer.Position; - - -public class VariableDeclarationNode implements Item { - private final Position position; - private final String identifier; - private final Returnable value; - private final Returnable.ReturnType type; - - public VariableDeclarationNode(Position position, String identifier, Returnable value, Returnable.ReturnType type) { - switch(type) { - case STRING: - case BOOLEAN: - case NUMBER: - break; - default: - throw new IllegalArgumentException("Invalid variable type: " + type); - } - this.position = position; - this.identifier = identifier; - this.value = value; - this.type = type; - } - - @Override - public T apply(ImplementationArguments implementationArguments, Scope scope) { - T result = value.apply(implementationArguments, scope); - scope.put(identifier, switch(type) { - case NUMBER -> new NumberVariable((Number) result, position); - case BOOLEAN -> new BooleanVariable((Boolean) result, position); - case STRING -> new StringVariable((String) result, position); - default -> throw new IllegalStateException("Unexpected value: " + type); - }); - return result; - } - - @Override - public Position getPosition() { - return position; - } - - public Returnable.ReturnType getType() { - return type; - } - - public String getIdentifier() { - return identifier; - } -} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/BoolAssignmentNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/BoolAssignmentNode.java new file mode 100644 index 000000000..8f0f47ee9 --- /dev/null +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/BoolAssignmentNode.java @@ -0,0 +1,25 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BoolAssignmentNode extends VariableAssignmentNode { + public BoolAssignmentNode(Returnable value, Position position, int index) { + super(value, position, index); + } + + @Override + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + boolean val = value.applyBoolean(implementationArguments, scope); + scope.setBool(index, val); + return val; + } +} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/NumAssignmentNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/NumAssignmentNode.java new file mode 100644 index 000000000..1b67e7150 --- /dev/null +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/NumAssignmentNode.java @@ -0,0 +1,25 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class NumAssignmentNode extends VariableAssignmentNode { + public NumAssignmentNode(Returnable value, Position position, int index) { + super(value, position, index); + } + + @Override + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return applyDouble(implementationArguments, scope); + } + + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + double val = value.applyDouble(implementationArguments, scope); + scope.setNum(index, val); + return val; + } +} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/StrAssignmentNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/StrAssignmentNode.java new file mode 100644 index 000000000..ee811dbd8 --- /dev/null +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/StrAssignmentNode.java @@ -0,0 +1,21 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class StrAssignmentNode extends VariableAssignmentNode { + public StrAssignmentNode(Returnable value, Position position, int index) { + super(value, position, index); + } + + @Override + public String apply(ImplementationArguments implementationArguments, Scope scope) { + String val = value.apply(implementationArguments, scope); + scope.setStr(index, val); + return val; + } + +} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/VariableAssignmentNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/VariableAssignmentNode.java new file mode 100644 index 000000000..ebca757b5 --- /dev/null +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/VariableAssignmentNode.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign; + +import com.dfsek.terra.addons.terrascript.parser.lang.Item; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public abstract class VariableAssignmentNode implements Item { + protected final Returnable value; + protected final int index; + private final Position position; + + + public VariableAssignmentNode(Returnable value, Position position, int index) { + this.value = value; + this.index = index; + this.position = position; + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/BoolVariableReferenceNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/BoolVariableReferenceNode.java new file mode 100644 index 000000000..c2295f2e2 --- /dev/null +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/BoolVariableReferenceNode.java @@ -0,0 +1,22 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BoolVariableReferenceNode extends VariableReferenceNode { + public BoolVariableReferenceNode(Position position, ReturnType type, int index) { + super(position, type, index); + } + + @Override + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return scope.getBool(index); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return scope.getBool(index); + } +} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/NumVariableReferenceNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/NumVariableReferenceNode.java new file mode 100644 index 000000000..a266dcca9 --- /dev/null +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/NumVariableReferenceNode.java @@ -0,0 +1,22 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class NumVariableReferenceNode extends VariableReferenceNode { + public NumVariableReferenceNode(Position position, ReturnType type, int index) { + super(position, type, index); + } + + @Override + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return scope.getNum(index); + } + + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return scope.getNum(index); + } +} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/StrVariableReferenceNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/StrVariableReferenceNode.java new file mode 100644 index 000000000..d67acc557 --- /dev/null +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/StrVariableReferenceNode.java @@ -0,0 +1,17 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class StrVariableReferenceNode extends VariableReferenceNode { + public StrVariableReferenceNode(Position position, ReturnType type, int index) { + super(position, type, index); + } + + @Override + public String apply(ImplementationArguments implementationArguments, Scope scope) { + return scope.getStr(index); + } +} diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/VariableReferenceNode.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/VariableReferenceNode.java similarity index 56% rename from common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/VariableReferenceNode.java rename to common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/VariableReferenceNode.java index 3d017b364..ecfebedca 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/VariableReferenceNode.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/VariableReferenceNode.java @@ -5,23 +5,21 @@ * reference the LICENSE file in this module's root directory. */ -package com.dfsek.terra.addons.terrascript.parser.lang.variables; +package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference; -import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; -import com.dfsek.terra.addons.terrascript.parser.lang.Scope; import com.dfsek.terra.addons.terrascript.tokenizer.Position; -public class VariableReferenceNode implements Returnable { - private final String identifier; +public abstract class VariableReferenceNode implements Returnable { + protected final int index; private final Position position; private final ReturnType type; - public VariableReferenceNode(String identifier, Position position, ReturnType type) { - this.identifier = identifier; + public VariableReferenceNode(Position position, ReturnType type, int index) { this.position = position; this.type = type; + this.index = index; } @Override @@ -29,11 +27,6 @@ public class VariableReferenceNode implements Returnable { return type; } - @Override - public synchronized Object apply(ImplementationArguments implementationArguments, Scope scope) { - return scope.get(identifier).getValue(); - } - @Override public Position getPosition() { return position; diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java index 1bba19e9e..e865d0d6d 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java @@ -18,7 +18,7 @@ import java.nio.charset.Charset; import java.util.Random; import com.dfsek.terra.addons.terrascript.parser.Parser; -import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.Executable; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; import com.dfsek.terra.addons.terrascript.script.builders.BinaryNumberFunctionBuilder; @@ -51,7 +51,7 @@ import com.dfsek.terra.api.world.WritableWorld; public class StructureScript implements Structure, Keyed { private static final Logger LOGGER = LoggerFactory.getLogger(StructureScript.class); - private final Block block; + private final Executable block; private final RegistryKey id; private final String profile; @@ -146,7 +146,7 @@ public class StructureScript implements Structure, Keyed { private boolean applyBlock(TerraImplementationArguments arguments) { try { - return block.apply(arguments).getLevel() != Block.ReturnLevel.FAIL; + return block.execute(arguments); } catch(RuntimeException e) { LOGGER.error("Failed to generate structure at {}", arguments.getOrigin(), e); return false; diff --git a/common/addons/structure-terrascript-loader/src/test/java/structure/ParserTest.java b/common/addons/structure-terrascript-loader/src/test/java/structure/ParserTest.java index b502a3563..fc0fcf532 100644 --- a/common/addons/structure-terrascript-loader/src/test/java/structure/ParserTest.java +++ b/common/addons/structure-terrascript-loader/src/test/java/structure/ParserTest.java @@ -14,10 +14,11 @@ import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.charset.Charset; import java.util.List; +import java.util.Objects; import com.dfsek.terra.addons.terrascript.parser.Parser; import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; -import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.Executable; import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; import com.dfsek.terra.addons.terrascript.parser.lang.Scope; @@ -29,7 +30,8 @@ import com.dfsek.terra.addons.terrascript.tokenizer.Position; public class ParserTest { @Test public void parse() throws IOException, ParseException { - Parser parser = new Parser(IOUtils.toString(getClass().getResourceAsStream("/test.tesf"), Charset.defaultCharset())); + Parser parser = new Parser( + IOUtils.toString(Objects.requireNonNull(getClass().getResourceAsStream("/test.tesf")), Charset.defaultCharset())); parser.registerFunction("test", new FunctionBuilder() { @Override @@ -54,13 +56,13 @@ public class ParserTest { }); long l = System.nanoTime(); - Block block = parser.parse(); + Executable block = parser.parse(); long t = System.nanoTime() - l; System.out.println("Took " + (double) t / 1000000); - block.apply(null, new Scope()); + block.execute(null); - block.apply(null, new Scope()); + block.execute(null); } private static class Test1 implements Function { diff --git a/common/addons/structure-terrascript-loader/src/test/java/structure/PerformanceTest.java b/common/addons/structure-terrascript-loader/src/test/java/structure/PerformanceTest.java deleted file mode 100644 index cc2ed4372..000000000 --- a/common/addons/structure-terrascript-loader/src/test/java/structure/PerformanceTest.java +++ /dev/null @@ -1,90 +0,0 @@ -package structure; - -import net.jafama.FastMath; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.List; - -import com.dfsek.terra.addons.terrascript.parser.Parser; -import com.dfsek.terra.addons.terrascript.parser.lang.Block; -import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; -import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; -import com.dfsek.terra.addons.terrascript.parser.lang.Returnable.ReturnType; -import com.dfsek.terra.addons.terrascript.parser.lang.Scope; -import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; -import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; -import com.dfsek.terra.addons.terrascript.script.builders.UnaryNumberFunctionBuilder; -import com.dfsek.terra.addons.terrascript.script.builders.UnaryStringFunctionBuilder; -import com.dfsek.terra.addons.terrascript.tokenizer.Position; - - -public class PerformanceTest { - public static void main(String... args) throws IOException { - Parser parser = new Parser( - IOUtils.toString(PerformanceTest.class.getResourceAsStream("/performance.tesf"), Charset.defaultCharset())); - - parser.registerFunction("assert", new FunctionBuilder() { - @Override - public AssertFunction build(List> argumentList, Position position) { - return new AssertFunction(position, (Returnable) argumentList.get(0)); - } - - @Override - public int argNumber() { - return 1; - } - - @Override - public Returnable.ReturnType getArgument(int position) { - return switch(position) { - case 0 -> ReturnType.BOOLEAN; - default -> null; - }; - } - - }).registerFunction("print", - new UnaryStringFunctionBuilder(System.out::println)) - .registerFunction("sqrt", new UnaryNumberFunctionBuilder(number -> FastMath.sqrt(number.doubleValue()))); - - Block block = parser.parse(); - - for(int i = 0; i < 20; i++) { - long s = System.nanoTime(); - - block.apply(null, new Scope()); - - long e = System.nanoTime(); - long d = e - s; - - System.out.println("Took " + ((double) d) / 1000000 + "ms"); - } - } - - public static final class AssertFunction implements Function { - private final Position position; - private final Returnable arg; - - public AssertFunction(Position position, Returnable arg) { - this.position = position; - this.arg = arg; - } - - @Override - public Void apply(ImplementationArguments implementationArguments, Scope scope) { - if(!arg.apply(implementationArguments, scope)) throw new IllegalStateException(); - return null; - } - - @Override - public Position getPosition() { - return position; - } - - @Override - public ReturnType returnType() { - return ReturnType.VOID; - } - } -} diff --git a/common/addons/structure-terrascript-loader/src/test/resources/performance.tesf b/common/addons/structure-terrascript-loader/src/test/resources/performance.tesf deleted file mode 100644 index 45527678c..000000000 --- a/common/addons/structure-terrascript-loader/src/test/resources/performance.tesf +++ /dev/null @@ -1,25 +0,0 @@ -num epsilon = 0.001; - -for(num n = 1; n < 1000000; n = n + 1) { - - num x = n; - - num root = 0; - - while(true) { - root = 0.5 * (x + (n / x)); - - num diff = root - x; - if(diff < 0) diff = -diff; - - if(diff < epsilon) break; - - x = root; - } - - num diff = root - sqrt(n); - - if(diff < 0) diff = -diff; - - assert(diff <= epsilon); -} \ No newline at end of file diff --git a/common/addons/terrascript-function-sampler/src/main/java/com/dfsek/terra/addons/terrascript/sampler/SamplerFunctionBuilder.java b/common/addons/terrascript-function-sampler/src/main/java/com/dfsek/terra/addons/terrascript/sampler/SamplerFunctionBuilder.java index 98ac7fca3..07ce640fd 100644 --- a/common/addons/terrascript-function-sampler/src/main/java/com/dfsek/terra/addons/terrascript/sampler/SamplerFunctionBuilder.java +++ b/common/addons/terrascript-function-sampler/src/main/java/com/dfsek/terra/addons/terrascript/sampler/SamplerFunctionBuilder.java @@ -61,7 +61,7 @@ public class SamplerFunctionBuilder implements FunctionBuilder) argumentList.get(1), (Returnable) argumentList.get(2), @@ -73,7 +73,7 @@ public class SamplerFunctionBuilder implements FunctionBuilder) argumentList.get(1), (Returnable) argumentList.get(2), (Returnable) argumentList.get(3), - s -> Objects.requireNonNull(samplers2d.get(s.get()), "No such 2D noise function " + s.get()) + s -> Objects.requireNonNull(samplers3d.get(s.get()), "No such 3D noise function " + s.get()) .getSampler(), true, position); diff --git a/common/api/build.gradle.kts b/common/api/build.gradle.kts index b31c8b89e..2fce99b17 100644 --- a/common/api/build.gradle.kts +++ b/common/api/build.gradle.kts @@ -1,10 +1,11 @@ dependencies { api("ca.solo-studios", "strata", Versions.Libraries.strata) - api("org.slf4j", "slf4j-api", Versions.Libraries.slf4j) + compileOnlyApi("org.slf4j", "slf4j-api", Versions.Libraries.slf4j) + testImplementation("org.slf4j", "slf4j-api", Versions.Libraries.slf4j) api("cloud.commandframework", "cloud-core", Versions.Libraries.cloud) api("com.dfsek.tectonic", "common", Versions.Libraries.tectonic) - + api("com.github.ben-manes.caffeine:caffeine:3.1.0") implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama) } \ No newline at end of file diff --git a/common/api/src/main/java/com/dfsek/terra/api/properties/Context.java b/common/api/src/main/java/com/dfsek/terra/api/properties/Context.java index 3b7f1fa40..175ec60af 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/properties/Context.java +++ b/common/api/src/main/java/com/dfsek/terra/api/properties/Context.java @@ -9,10 +9,20 @@ package com.dfsek.terra.api.properties; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; public class Context { + private static final AtomicInteger size = new AtomicInteger(0); + private static final Map, PropertyKey> properties = new HashMap<>(); private final Map, Properties> map = new HashMap<>(); + private final AtomicReference list = new AtomicReference<>(new Properties[size.get()]); + + @SuppressWarnings("unchecked") + public static PropertyKey create(Class clazz) { + return (PropertyKey) properties.computeIfAbsent(clazz, c -> new PropertyKey<>(size.getAndIncrement(), clazz)); + } @SuppressWarnings("unchecked") public T get(Class clazz) { @@ -28,6 +38,21 @@ public class Context { return this; } + public Context put(PropertyKey key, T properties) { + list.updateAndGet(p -> { + if(p.length == size.get()) return p; + Properties[] p2 = new Properties[size.get()]; + System.arraycopy(p, 0, p2, 0, p.length); + return p2; + })[key.key] = properties; + return this; + } + + @SuppressWarnings("unchecked") + public T get(PropertyKey key) { + return (T) list.get()[key.key]; + } + public boolean has(Class test) { return map.containsKey(test); } diff --git a/common/api/src/main/java/com/dfsek/terra/api/properties/PropertyKey.java b/common/api/src/main/java/com/dfsek/terra/api/properties/PropertyKey.java new file mode 100644 index 000000000..9c2daefe2 --- /dev/null +++ b/common/api/src/main/java/com/dfsek/terra/api/properties/PropertyKey.java @@ -0,0 +1,15 @@ +package com.dfsek.terra.api.properties; + +public class PropertyKey { + protected final int key; + private final Class clazz; + + protected PropertyKey(int key, Class clazz) { + this.key = key; + this.clazz = clazz; + } + + public Class getTypeClass() { + return clazz; + } +} diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/Column.java b/common/api/src/main/java/com/dfsek/terra/api/util/Column.java new file mode 100644 index 000000000..2b6264228 --- /dev/null +++ b/common/api/src/main/java/com/dfsek/terra/api/util/Column.java @@ -0,0 +1,66 @@ +package com.dfsek.terra.api.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import com.dfsek.terra.api.util.function.IntIntObjConsumer; +import com.dfsek.terra.api.util.function.IntObjConsumer; + + +public interface Column { + int getMinY(); + + int getMaxY(); + + int getX(); + + int getZ(); + + T get(int y); + + default void forEach(Consumer consumer) { + for(int y = getMinY(); y < getMaxY(); y++) { + consumer.accept(get(y)); + } + } + + default void forEach(IntObjConsumer consumer) { + for(int y = getMinY(); y < getMaxY(); y++) { + consumer.accept(y, get(y)); + } + } + + default void forRanges(int resolution, IntIntObjConsumer consumer) { + int min = getMinY(); + + int y = min; + + T runningObj = get(y); + + int runningMin = min; + + int max = getMaxY() - 1; + + while(true) { + y += resolution; + if(y > max) { + break; + } + T current = get(y); + + if(!current.equals(runningObj)) { + consumer.accept(runningMin, y, runningObj); + runningMin = y; + runningObj = current; + } + } + consumer.accept(runningMin, getMaxY(), runningObj); + } + + default List asList() { + List list = new ArrayList<>(); + forEach((Consumer) list::add); + return list; + } +} diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/GeometryUtil.java b/common/api/src/main/java/com/dfsek/terra/api/util/GeometryUtil.java index 6bb21b3df..25984257f 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/util/GeometryUtil.java +++ b/common/api/src/main/java/com/dfsek/terra/api/util/GeometryUtil.java @@ -7,7 +7,7 @@ import com.dfsek.terra.api.util.vector.Vector3Int; public final class GeometryUtil { private GeometryUtil() { - + } public static void sphere(Vector3Int origin, int radius, Consumer action) { diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/MathUtil.java b/common/api/src/main/java/com/dfsek/terra/api/util/MathUtil.java index e24de0e03..3c95df139 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/util/MathUtil.java +++ b/common/api/src/main/java/com/dfsek/terra/api/util/MathUtil.java @@ -87,6 +87,10 @@ public final class MathUtil { return FastMath.min(FastMath.max(in, -1), 1); } + public static int clamp(int min, int i, int max) { + return FastMath.max(FastMath.min(i, max), min); + } + /** * Compute the value in a normally distributed data set that has probability p. * diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/Range.java b/common/api/src/main/java/com/dfsek/terra/api/util/Range.java index 9aa57fde3..c417b8183 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/util/Range.java +++ b/common/api/src/main/java/com/dfsek/terra/api/util/Range.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.NotNull; import java.util.Iterator; import java.util.Random; +import java.util.function.Supplier; public interface Range extends Iterable { @@ -41,4 +42,24 @@ public interface Range extends Iterable { Range setMin(int min); int getRange(); + + default T ifInRange(int y, T inRange, T notInRange) { + if(isInRange(y)) return inRange; + return notInRange; + } + + default T ifInRange(int y, Supplier inRange, Supplier notInRange) { + if(isInRange(y)) return inRange.get(); + return notInRange.get(); + } + + default T ifInRange(int y, Supplier inRange, T notInRange) { + if(isInRange(y)) return inRange.get(); + return notInRange; + } + + default T ifInRange(int y, T inRange, Supplier notInRange) { + if(isInRange(y)) return inRange; + return notInRange.get(); + } } diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/function/IntIntObjConsumer.java b/common/api/src/main/java/com/dfsek/terra/api/util/function/IntIntObjConsumer.java new file mode 100644 index 000000000..69af95224 --- /dev/null +++ b/common/api/src/main/java/com/dfsek/terra/api/util/function/IntIntObjConsumer.java @@ -0,0 +1,6 @@ +package com.dfsek.terra.api.util.function; + +@FunctionalInterface +public interface IntIntObjConsumer { + void accept(int i, int j, T obj); +} diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/function/IntObjConsumer.java b/common/api/src/main/java/com/dfsek/terra/api/util/function/IntObjConsumer.java new file mode 100644 index 000000000..4e9c9e54b --- /dev/null +++ b/common/api/src/main/java/com/dfsek/terra/api/util/function/IntObjConsumer.java @@ -0,0 +1,6 @@ +package com.dfsek.terra.api.util.function; + +@FunctionalInterface +public interface IntObjConsumer { + void accept(int i, T obj); +} diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/generic/pair/Pair.java b/common/api/src/main/java/com/dfsek/terra/api/util/generic/pair/Pair.java index ad4c2c879..c1ddf92d6 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/util/generic/pair/Pair.java +++ b/common/api/src/main/java/com/dfsek/terra/api/util/generic/pair/Pair.java @@ -11,10 +11,10 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import java.util.Objects; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.UnaryOperator; public final class Pair { @@ -22,6 +22,11 @@ public final class Pair { private final L left; private final R right; + private Pair(L left, R right) { + this.left = left; + this.right = right; + } + public static Function, Pair> mapLeft(Function function) { return pair -> of(function.apply(pair.left), pair.right); } @@ -54,11 +59,6 @@ public final class Pair { return pair -> pair.left; } - private Pair(L left, R right) { - this.left = left; - this.right = right; - } - @Contract("_, _ -> new") public static Pair of(L1 left, R1 right) { return new Pair<>(left, right); @@ -96,57 +96,63 @@ public final class Pair { return Objects.equals(this.left, that.left) && Objects.equals(this.right, that.right); } - public static class Mutable { - private L left; - private R right; - - private Mutable(L left, R right) { - this.left = left; - this.right = right; - } - - @NotNull - @Contract("_, _ -> new") - public static Pair.Mutable of(L1 left, R1 right) { - return new Mutable<>(left, right); - } - - @Contract("-> new") - public Pair immutable() { - return Pair.of(left, right); - } - - public L getLeft() { - return left; - } - - public void setLeft(L left) { - this.left = left; - } - - public R getRight() { - return right; - } - - public void setRight(R right) { - this.right = right; - } - - @Override - public int hashCode() { - return Objects.hash(left, right); - } - - @Override - public boolean equals(Object obj) { - if(!(obj instanceof Mutable that)) return false; - - return Objects.equals(this.left, that.left) && Objects.equals(this.right, that.right); - } + public Pair apply(BiConsumer consumer) { + consumer.accept(this.left, this.right); + return this; } @Override public String toString() { return String.format("{%s,%s}", left, right); } + + + public static class Mutable { + private L left; + private R right; + + private Mutable(L left, R right) { + this.left = left; + this.right = right; + } + + @NotNull + @Contract("_, _ -> new") + public static Pair.Mutable of(L1 left, R1 right) { + return new Mutable<>(left, right); + } + + @Contract("-> new") + public Pair immutable() { + return Pair.of(left, right); + } + + public L getLeft() { + return left; + } + + public void setLeft(L left) { + this.left = left; + } + + public R getRight() { + return right; + } + + public void setRight(R right) { + this.right = right; + } + + @Override + public int hashCode() { + return Objects.hash(left, right); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof Mutable that)) return false; + + return Objects.equals(this.left, that.left) && Objects.equals(this.right, that.right); + } + } } diff --git a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeColumn.java b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeColumn.java new file mode 100644 index 000000000..addec2110 --- /dev/null +++ b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeColumn.java @@ -0,0 +1,49 @@ +package com.dfsek.terra.api.world.biome.generation; + +import com.dfsek.terra.api.util.Column; +import com.dfsek.terra.api.world.biome.Biome; + + +class BiomeColumn implements Column { + private final BiomeProvider biomeProvider; + private final int min; + private final int max; + + private final int x; + private final int z; + private final long seed; + + protected BiomeColumn(BiomeProvider biomeProvider, int min, int max, int x, int z, long seed) { + this.biomeProvider = biomeProvider; + this.min = min; + this.max = max; + this.x = x; + this.z = z; + this.seed = seed; + } + + @Override + public int getMinY() { + return min; + } + + @Override + public int getMaxY() { + return max; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getZ() { + return z; + } + + @Override + public Biome get(int y) { + return biomeProvider.getBiome(x, y, z, seed); + } +} diff --git a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeProvider.java b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeProvider.java index 282541720..01ffbda70 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeProvider.java +++ b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeProvider.java @@ -7,17 +7,18 @@ package com.dfsek.terra.api.world.biome.generation; +import org.jetbrains.annotations.Contract; + +import java.util.Optional; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import com.dfsek.terra.api.util.Column; import com.dfsek.terra.api.util.vector.Vector3; import com.dfsek.terra.api.util.vector.Vector3Int; import com.dfsek.terra.api.world.biome.Biome; - import com.dfsek.terra.api.world.info.WorldProperties; -import org.jetbrains.annotations.Contract; - -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - /** * Provides locations of biomes in a world. @@ -62,6 +63,19 @@ public interface BiomeProvider { return getBiome(vector3.getX(), vector3.getY(), vector3.getZ(), seed); } + default Optional getBaseBiome(int x, int z, long seed) { + return Optional.empty(); + } + + + default Column getColumn(int x, int z, WorldProperties properties) { + return getColumn(x, z, properties.getSeed(), properties.getMinHeight(), properties.getMaxHeight()); + } + + default Column getColumn(int x, int z, long seed, int min, int max) { + return new BiomeColumn(this, min, max, x, z, seed); + } + /** * Get all biomes this {@link BiomeProvider} is capable of generating in the world. *

@@ -77,11 +91,15 @@ public interface BiomeProvider { return StreamSupport.stream(getBiomes().spliterator(), false); } - default BiomeProvider caching(int minY, int maxY) { - return new CachingBiomeProvider(this, minY, maxY); + default CachingBiomeProvider caching() { + if(this instanceof CachingBiomeProvider cachingBiomeProvider) { + return cachingBiomeProvider; + } + return new CachingBiomeProvider(this); } - default BiomeProvider caching(WorldProperties worldProperties) { - return caching(worldProperties.getMinHeight(), worldProperties.getMaxHeight()); + + default int resolution() { + return 1; } } diff --git a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/CachingBiomeProvider.java b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/CachingBiomeProvider.java index ee2b41dbc..fff67f75a 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/CachingBiomeProvider.java +++ b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/CachingBiomeProvider.java @@ -1,11 +1,13 @@ package com.dfsek.terra.api.world.biome.generation; -import com.dfsek.terra.api.Handle; -import com.dfsek.terra.api.util.MathUtil; -import com.dfsek.terra.api.world.biome.Biome; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.Scheduler; -import java.util.HashMap; -import java.util.Map; +import java.util.Optional; + +import com.dfsek.terra.api.Handle; +import com.dfsek.terra.api.world.biome.Biome; /** @@ -14,15 +16,26 @@ import java.util.Map; * This is for use in chunk generators, it makes the assumption that the seed remains the same for the duration of its use! */ public class CachingBiomeProvider implements BiomeProvider, Handle { - private final BiomeProvider delegate; - private final int minY; - private final int maxY; - private final Map cache = new HashMap<>(); + protected final BiomeProvider delegate; + private final int res; + private final LoadingCache cache; + private final LoadingCache> baseCache; - protected CachingBiomeProvider(BiomeProvider delegate, int minY, int maxY) { + protected CachingBiomeProvider(BiomeProvider delegate) { this.delegate = delegate; - this.minY = minY; - this.maxY = maxY; + this.res = delegate.resolution(); + this.cache = Caffeine + .newBuilder() + .scheduler(Scheduler.disabledScheduler()) + .initialCapacity(98304) + .maximumSize(98304) // 1 full chunk (high res) + .build(vec -> delegate.getBiome(vec.x * res, vec.y * res, vec.z * res, vec.seed)); + + this.baseCache = Caffeine + .newBuilder() + .maximumSize(256) // 1 full chunk (high res) + .build(vec -> delegate.getBaseBiome(vec.x * res, vec.z * res, vec.seed)); + } @Override @@ -32,17 +45,57 @@ public class CachingBiomeProvider implements BiomeProvider, Handle { @Override public Biome getBiome(int x, int y, int z, long seed) { - if(y >= maxY || y < minY) throw new IllegalArgumentException("Y out of range: " + y + " (min: " + minY + ", max: " + maxY + ")"); - Biome[] biomes = cache.computeIfAbsent(MathUtil.squash(x, z), key -> new Biome[maxY - minY]); - int yi = y - minY; - if(biomes[yi] == null) { - biomes[yi] = delegate.getBiome(x, y, z, seed); - } - return biomes[yi]; + return cache.get(new SeededVector3(x / res, y / res, z / res, seed)); + } + + @Override + public Optional getBaseBiome(int x, int z, long seed) { + return baseCache.get(new SeededVector2(x / res, z / res, seed)); } @Override public Iterable getBiomes() { return delegate.getBiomes(); } + + @Override + public int resolution() { + return delegate.resolution(); + } + + private record SeededVector3(int x, int y, int z, long seed) { + @Override + public boolean equals(Object obj) { + if(obj instanceof SeededVector3 that) { + return this.y == that.y && this.z == that.z && this.x == that.x && this.seed == that.seed; + } + return false; + } + + @Override + public int hashCode() { + int code = x; + code = 31 * code + y; + code = 31 * code + z; + return 31 * code + ((int) (seed ^ (seed >>> 32))); + } + } + + + private record SeededVector2(int x, int z, long seed) { + @Override + public boolean equals(Object obj) { + if(obj instanceof SeededVector2 that) { + return this.z == that.z && this.x == that.x && this.seed == that.seed; + } + return false; + } + + @Override + public int hashCode() { + int code = x; + code = 31 * code + z; + return 31 * code + ((int) (seed ^ (seed >>> 32))); + } + } } diff --git a/common/api/src/main/java/com/dfsek/terra/api/world/chunk/generation/util/Column.java b/common/api/src/main/java/com/dfsek/terra/api/world/chunk/generation/util/Column.java index 6defa986b..c92ca2311 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/world/chunk/generation/util/Column.java +++ b/common/api/src/main/java/com/dfsek/terra/api/world/chunk/generation/util/Column.java @@ -17,18 +17,29 @@ import com.dfsek.terra.api.world.WritableWorld; /** * A single vertical column of a world. + * + * Due to the {@link #clamp(int, int)} method, the height of the column may not always be the same as the world! Be careful! */ public class Column { private final int x; private final int z; + private final int min; + private final int max; private final T world; public Column(int x, int z, T world) { + this(x, z, world, world.getMinHeight(), world.getMaxHeight()); + } + + public Column(int x, int z, T world, int min, int max) { this.x = x; this.z = z; this.world = world; + this.max = max; + this.min = min; } + public int getX() { return x; } @@ -46,11 +57,11 @@ public class Column { } public int getMinY() { - return world.getMinHeight(); + return min; } public int getMaxY() { - return world.getMaxHeight(); + return max; } public void forEach(IntConsumer function) { @@ -59,6 +70,11 @@ public class Column { } } + public Column clamp(int min, int max) { + if(min >= max) throw new IllegalArgumentException("Min greater than or equal to max: " + min + ", " + max); + return new Column<>(x, z, world, min, max); + } + public BinaryColumn newBinaryColumn(IntToBooleanFunction function) { return new BinaryColumn(getMinY(), getMaxY(), function); } diff --git a/common/api/src/main/java/com/dfsek/terra/api/world/util/Interceptors.java b/common/api/src/main/java/com/dfsek/terra/api/world/util/Interceptors.java index c608ea4d9..4b98c8b34 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/world/util/Interceptors.java +++ b/common/api/src/main/java/com/dfsek/terra/api/world/util/Interceptors.java @@ -4,9 +4,9 @@ public final class Interceptors { private static final ReadInterceptor READ_THROUGH = ((x, y, z, world) -> world.getBlockState(x, y, z)); private static final WriteInterceptor WRITE_THROUGH = ((x, y, z, block, world, physics) -> world.setBlockState(x, y, z, block, physics)); - + private Interceptors() { - + } public static ReadInterceptor readThrough() { diff --git a/common/api/src/test/java/util/ColumnTest.java b/common/api/src/test/java/util/ColumnTest.java new file mode 100644 index 000000000..06f4a03e4 --- /dev/null +++ b/common/api/src/test/java/util/ColumnTest.java @@ -0,0 +1,105 @@ +package util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import com.dfsek.terra.api.util.Column; +import com.dfsek.terra.api.util.generic.pair.Pair; +import com.dfsek.terra.api.util.mutable.MutableInteger; + +import static org.junit.jupiter.api.Assertions.*; + + +public class ColumnTest { + private final Column returnY = new ColumnImpl<>(-10, 10, Function.identity()); + private final Column returnPositive = new ColumnImpl<>(-10, 10, i -> i >= 0); + + private final Column returnTrue = new ColumnImpl<>(-10, 10, i -> true); + + @Test + public void testForEach() { + returnY.forEach(Assertions::assertEquals); + MutableInteger test = new MutableInteger(returnY.getMinY()); + returnY.forEach(i -> { + assertEquals(i, test.get()); + test.increment(); + }); + assertEquals(returnY.getMaxY(), test.get()); + } + + @Test + public void testForRanges() { + List, Boolean>> list = new ArrayList<>(); + + returnPositive.forRanges(1, (min, max, p) -> list.add(Pair.of(Pair.of(min, max), p))); + + assertEquals(List.of( + Pair.of(Pair.of(-10, 0), false), + Pair.of(Pair.of(0, 10), true) + ), + list); + } + + @Test + public void testForRangesIndividual() { + List, Integer>> list = new ArrayList<>(); + + returnY.forRanges(1, (min, max, p) -> list.add(Pair.of(Pair.of(min, max), p))); + + assertEquals(IntStream.range(-10, 10).mapToObj(i -> Pair.of(Pair.of(i, i + 1), i)).collect(Collectors.toList()), + list); + } + + @Test + public void testForRangesContiguous() { + List, Boolean>> list = new ArrayList<>(); + + returnTrue.forRanges(1, (min, max, p) -> list.add(Pair.of(Pair.of(min, max), p))); + + assertEquals(List.of(Pair.of(Pair.of(-10, 10), true)), + list); + } + + static class ColumnImpl implements Column { + private final int min; + private final int max; + private final Function p; + + ColumnImpl(int min, int max, Function p) { + this.min = min; + this.max = max; + this.p = p; + } + + @Override + public int getMinY() { + return min; + } + + @Override + public int getMaxY() { + return max; + } + + @Override + public int getX() { + return 0; + } + + @Override + public int getZ() { + return 0; + } + + @Override + public T get(int y) { + return p.apply(y); + } + } +} diff --git a/common/implementation/base/build.gradle.kts b/common/implementation/base/build.gradle.kts index 64c176c77..1910484f0 100644 --- a/common/implementation/base/build.gradle.kts +++ b/common/implementation/base/build.gradle.kts @@ -2,6 +2,8 @@ dependencies { api(project(":common:api")) api(project(":common:implementation:bootstrap-addon-loader")) + testImplementation("org.slf4j", "slf4j-api", Versions.Libraries.slf4j) + implementation("commons-io", "commons-io", Versions.Libraries.Internal.apacheIO) implementation("org.apache.commons", "commons-text", Versions.Libraries.Internal.apacheText) diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/AbstractPlatform.java b/common/implementation/base/src/main/java/com/dfsek/terra/AbstractPlatform.java index fe04ef97e..4ea9466ec 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/AbstractPlatform.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/AbstractPlatform.java @@ -18,6 +18,30 @@ package com.dfsek.terra; import com.dfsek.tectonic.api.TypeRegistry; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import com.dfsek.terra.addon.BootstrapAddonLoader; import com.dfsek.terra.addon.DependencySorter; @@ -49,21 +73,6 @@ import com.dfsek.terra.registry.LockedRegistryImpl; import com.dfsek.terra.registry.OpenRegistryImpl; import com.dfsek.terra.registry.master.ConfigRegistry; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.yaml.snakeyaml.Yaml; - -import java.io.*; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.stream.Collectors; - /** * Skeleton implementation of {@link Platform} @@ -111,8 +120,12 @@ public abstract class AbstractPlatform implements Platform { logger.info("Loading config.yml"); File configFile = new File(getDataFolder(), "config.yml"); if(!configFile.exists()) { - logger.info("Writing new config.yml..."); - FileUtils.copyInputStreamToFile(stream, configFile); + logger.info("Dumping config.yml..."); + if(stream == null) { + logger.warn("Could not find config.yml in JAR"); + } else { + FileUtils.copyInputStreamToFile(stream, configFile); + } } } catch(IOException e) { logger.error("Error loading config.yml resource from jar", e); diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/config/loaders/ProbabilityCollectionLoader.java b/common/implementation/base/src/main/java/com/dfsek/terra/config/loaders/ProbabilityCollectionLoader.java index 01cda5c4b..902bc16d4 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/config/loaders/ProbabilityCollectionLoader.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/config/loaders/ProbabilityCollectionLoader.java @@ -49,6 +49,14 @@ public class ProbabilityCollectionLoader implements TypeLoader> map = (List>) o; + if(map.size() == 1) { + Map entry = map.get(0); + if(entry.size() == 1) { + for(Object value : entry.keySet()) { + return new ProbabilityCollection.Singleton<>(configLoader.loadType(generic, value, depthTracker)); + } + } + } for(int i = 0; i < map.size(); i++) { Map l = map.get(i); for(Entry entry : l.entrySet()) { diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/config/pack/ConfigPackImpl.java b/common/implementation/base/src/main/java/com/dfsek/terra/config/pack/ConfigPackImpl.java index 887e697ae..84f2fb382 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/config/pack/ConfigPackImpl.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/config/pack/ConfigPackImpl.java @@ -231,7 +231,8 @@ public class ConfigPackImpl implements ConfigPack { ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate(); selfLoader.load(packPostTemplate, packManifest); - seededBiomeProvider = packPostTemplate.getProviderBuilder(); + seededBiomeProvider = + template.getBiomeCache() ? packPostTemplate.getProviderBuilder().caching() : packPostTemplate.getProviderBuilder(); checkDeadEntries(); } diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/config/pack/ConfigPackTemplate.java b/common/implementation/base/src/main/java/com/dfsek/terra/config/pack/ConfigPackTemplate.java index b41005a25..3aa0a8c27 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/config/pack/ConfigPackTemplate.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/config/pack/ConfigPackTemplate.java @@ -107,6 +107,10 @@ public class ConfigPackTemplate implements ConfigTemplate { @Value("generator") private @Meta ChunkGeneratorProvider generatorProvider; + @Value("cache.biome.enable") + @Default + private boolean biomeCache = false; + public boolean disableCarvers() { return disableCarvers; } @@ -182,4 +186,8 @@ public class ConfigPackTemplate implements ConfigTemplate { public Map getLocatable() { return locatable; } + + public boolean getBiomeCache() { + return biomeCache; + } } diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java index 98ab127e1..b4ba6dc40 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java @@ -45,7 +45,7 @@ public class ConfigRegistry extends OpenRegistryImpl { public void load(File folder, Platform platform) throws ConfigException { ConfigPack pack = new ConfigPackImpl(folder, platform); - register(pack.getRegistryKey(), pack); + registerChecked(pack.getRegistryKey(), pack); } public boolean loadAll(Platform platform) { @@ -75,6 +75,6 @@ public class ConfigRegistry extends OpenRegistryImpl { public void load(ZipFile file, Platform platform) throws ConfigException { ConfigPackImpl pack = new ConfigPackImpl(file, platform); - register(pack.getRegistryKey(), pack); + registerChecked(pack.getRegistryKey(), pack); } } diff --git a/common/implementation/base/src/test/java/registry/RegistryTest.java b/common/implementation/base/src/test/java/registry/RegistryTest.java index b11e123b6..3f17a1776 100644 --- a/common/implementation/base/src/test/java/registry/RegistryTest.java +++ b/common/implementation/base/src/test/java/registry/RegistryTest.java @@ -50,7 +50,7 @@ public class RegistryTest { test.registerChecked(RegistryKey.parse("test:test"), "bazinga2"); fail("Shouldn't be able to re-register with #registerChecked!"); } catch(DuplicateEntryException ignore) { - + } } @@ -66,7 +66,7 @@ public class RegistryTest { test.register(RegistryKey.parse("test:test"), "bazinga2"); fail("Shouldn't be able to re-register in CheckedRegistry!"); } catch(DuplicateEntryException ignore) { - + } } @@ -90,7 +90,7 @@ public class RegistryTest { test.getByID("test"); fail("Shouldn't be able to get with ambiguous ID!"); } catch(IllegalArgumentException ignore) { - + } } } diff --git a/common/implementation/bootstrap-addon-loader/src/main/java/com/dfsek/terra/addon/BootstrapAddonLoader.java b/common/implementation/bootstrap-addon-loader/src/main/java/com/dfsek/terra/addon/BootstrapAddonLoader.java index 37eba4762..301f276fa 100644 --- a/common/implementation/bootstrap-addon-loader/src/main/java/com/dfsek/terra/addon/BootstrapAddonLoader.java +++ b/common/implementation/bootstrap-addon-loader/src/main/java/com/dfsek/terra/addon/BootstrapAddonLoader.java @@ -84,7 +84,7 @@ public class BootstrapAddonLoader implements BootstrapBaseAddon bootstrapAddons = Files.walk(bootstrapFolder, 1, FileVisitOption.FOLLOW_LINKS)) { return bootstrapAddons.filter(path -> path.toFile().isFile()) .filter(path -> path.toFile().canRead()) @@ -96,7 +96,7 @@ public class BootstrapAddonLoader implements BootstrapBaseAddon 0) { - jvmFlags.add("-XX:ActiveProcessorCount=$throttleCoreCount") -} - - -fun downloadPaperclip(url: String, dir: String) { - val clip = URL(url.replace("%version%", mcVersion)) - val clipReadableByteChannel = Channels.newChannel(clip.openStream()) - val clipFile = file("$testDir/$dir/paperclip.jar") - val clipOutputStream = clipFile.outputStream() - val clipFileChannel = clipOutputStream.channel - clipFileChannel.transferFrom(clipReadableByteChannel, 0, Long.MAX_VALUE) -} - -fun copyTerra(dir: String) { - file("$testDir/$dir").walk().forEach { - if (it.name.startsWith("Terra-bukkit") && it.name.endsWith(".jar")) it.delete() // Delete old Terra jar(s) - } - copy { - from("$buildDir/libs/Terra-bukkit-$version-shaded.jar") - into("$testDir/$dir/plugins/") - } -} - -fun installServer(dir: String) { - // clean - file("$testDir/$dir").deleteRecursively() - file("$testDir/$dir/plugins").mkdirs() - // Cloning test setup. - gitClone("https://github.com/PolyhedralDev/WorldGenTestServer") - // Copying 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() - file("$testDir/$dir/server.properties").writeText(serverText) - val bukkitText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/bukkit.yml").readText() - file("$testDir/$dir/bukkit.yml").writeText(bukkitText.replace("\${world}", "world").replace("\${gen}", "Terra:DEFAULT")) - - println("By proceeding, you are agreeing to the Minecraft EULA: https://account.mojang.com/documents/minecraft_eula") - file("$testDir/$dir/eula.txt").writeText("eula=true") - - // clean up - file("WorldGenTestServer").deleteRecursively() -} - -fun deleteFolder(folder: File) { - if (folder.exists()) folder.deleteRecursively() -} - -fun deleteFile(file: File) { - if (file.exists()) file.delete() -} - -tasks.create("cleanWorlds") { - group = "bukkit" - doFirst { - deleteFolder(file("$testDir/paper/world")) - deleteFolder(file("$testDir/paper/world_nether")) - deleteFolder(file("$testDir/paper/world_the_end")) - - deleteFolder(file("$testDir/purpur/world")) - deleteFolder(file("$testDir/purpur/world_nether")) - deleteFolder(file("$testDir/purpur/world_the_end")) - } -} - -tasks.create("updatePaper") { - group = "bukkit" - doFirst { - deleteFile(file("$testDir/paper/paperclip.jar")) - downloadPaperclip(paperURL, "paper") - } -} - -tasks.create("updatePurpur") { - group = "bukkit" - doFirst { - deleteFile(file("$testDir/paper/paperclip.jar")) - downloadPaperclip(purpurURL, "purpur") - } -} - -tasks.create("installPaper") { - group = "bukkit" - dependsOn("shadowJar") - doFirst { - installServer("paper") - // Downloading latest paper jar. - downloadPaperclip(paperURL, "paper") - } -} - -tasks.create("installPurpur") { - group = "bukkit" - dependsOn("shadowJar") - doFirst { - installServer("purpur") - // Downloading latest paper jar. - downloadPaperclip(purpurURL, "purpur") - } -} - -task(name = "runPaper") { - group = "bukkit" - standardInput = System.`in` - dependsOn("shadowJar") - // Copy Terra into dir - doFirst { - copyTerra("paper") +tasks { + shadowJar { + relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats") + relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib") + relocate("com.google.common", "com.dfsek.terra.lib.google.common") + relocate("org.apache.logging.slf4j", "com.dfsek.terra.lib.slf4j-over-log4j") + exclude("org/slf4j/**") + exclude("org/checkerframework/**") + exclude("org/jetbrains/annotations/**") + exclude("org/intellij/**") + exclude("com/google/errorprone/**") + exclude("com/google/j2objc/**") + exclude("javax/**") } - mainClass.set("io.papermc.paperclip.Paperclip") - jvmArgs = jvmFlags - maxHeapSize = testMem - minHeapSize = testMem - args = listOf("nogui") - workingDir = file("$testDir/paper") - classpath = files("$testDir/paper/paperclip.jar") -} - -task(name = "runPurpur") { - group = "bukkit" - standardInput = System.`in` - dependsOn("shadowJar") - // Copy Terra into dir - doFirst { - copyTerra("purpur") + runServer { + minecraftVersion("1.19") + dependsOn(shadowJar) + pluginJars(shadowJar.get().archiveFile) } - - mainClass.set("io.papermc.paperclip.Paperclip") - jvmArgs = jvmFlags - maxHeapSize = testMem - minHeapSize = testMem - //args = listOf("nogui") - workingDir = file("$testDir/purpur") - classpath = files("$testDir/purpur/paperclip.jar") -} - -tasks.named("shadowJar") { - relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats") - relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib") - relocate("com.google.common", "com.dfsek.terra.lib.google.common") - relocate("org.apache.logging.slf4j", "com.dfsek.terra.lib.slf4j-over-log4j") - exclude("org/slf4j/**") - exclude("org/checkerframework/**") - exclude("org/jetbrains/annotations/**") - exclude("org/intellij/**") - exclude("com/google/errorprone/**") - exclude("com/google/j2objc/**") - exclude("javax/**") } -addonDir(project.file("./target/server/paper/plugins/Terra/addons"), tasks.named("runPaper").get()) -addonDir(project.file("./target/server/purpur/plugins/Terra/addons"), tasks.named("runPurpur").get()) +addonDir(project.file("./target/server/paper/plugins/Terra/addons"), tasks.named("runServer").get()) diff --git a/platforms/bukkit/common/build.gradle.kts b/platforms/bukkit/common/build.gradle.kts index b29891d4d..a806ce672 100644 --- a/platforms/bukkit/common/build.gradle.kts +++ b/platforms/bukkit/common/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { because("Minecraft 1.17+ includes slf4j 1.8.0-beta4, so we need to shade it for other versions.") } - compileOnly("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT") + compileOnly("io.papermc.paper:paper-api:${Versions.Bukkit.paper}") shadedApi("io.papermc", "paperlib", Versions.Bukkit.paperLib) shadedApi("com.google.guava:guava:30.0-jre") diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/BukkitAddon.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/BukkitAddon.java index 38d3ff2dc..ac215b83e 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/BukkitAddon.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/BukkitAddon.java @@ -7,12 +7,8 @@ import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.world.biome.Biome; - import com.dfsek.terra.bukkit.config.VanillaBiomeProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class BukkitAddon implements BaseAddon { private static final Version VERSION = Versions.getVersion(1, 0, 0); diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/PlatformImpl.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/PlatformImpl.java index a58cc1a3d..bba0e1bc1 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/PlatformImpl.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/PlatformImpl.java @@ -20,9 +20,6 @@ package com.dfsek.terra.bukkit; import com.dfsek.tectonic.api.TypeRegistry; import com.dfsek.tectonic.api.depth.DepthTracker; import com.dfsek.tectonic.api.exception.LoadException; - -import com.dfsek.terra.api.addon.BaseAddon; - import org.bukkit.Bukkit; import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; @@ -34,6 +31,7 @@ import java.util.List; import java.util.Locale; import com.dfsek.terra.AbstractPlatform; +import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.handle.ItemHandle; import com.dfsek.terra.api.handle.WorldHandle; diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java index 8c0b226ef..6390444f2 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java @@ -91,7 +91,7 @@ public class TerraBukkitPlugin extends JavaPlugin { Bukkit.getPluginManager().registerEvents(new CommonListener(), this); // Register master event listener PaperUtil.checkPaper(this); - + Initializer.init(platform); } diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java index ac7444da2..8d7302fa7 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java @@ -17,17 +17,15 @@ package com.dfsek.terra.bukkit.generator; -import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState; - -import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.block.data.BlockData; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.LimitedRegion; import org.bukkit.generator.WorldInfo; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; import java.util.Random; @@ -37,12 +35,10 @@ import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper; +import com.dfsek.terra.api.world.info.WorldProperties; import com.dfsek.terra.bukkit.world.BukkitProtoWorld; import com.dfsek.terra.bukkit.world.BukkitWorldProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGenerator implements GeneratorWrapper { private static final Logger LOGGER = LoggerFactory.getLogger(BukkitChunkGeneratorWrapper.class); @@ -50,6 +46,7 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener private ChunkGenerator delegate; private ConfigPack pack; + public BukkitChunkGeneratorWrapper(ChunkGenerator delegate, ConfigPack pack, BlockState air) { this.delegate = delegate; this.pack = pack; @@ -68,7 +65,7 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener @Override public void generateNoise(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) { BukkitWorldProperties properties = new BukkitWorldProperties(worldInfo); - delegate.generateChunkData(new BukkitProtoChunk(chunkData), properties, pack.getBiomeProvider().caching(properties), x, z); + delegate.generateChunkData(new BukkitProtoChunk(chunkData), properties, pack.getBiomeProvider(), x, z); } @Override @@ -79,7 +76,7 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener @Override public void populate(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull LimitedRegion limitedRegion) { - generationStage.populate(new BukkitProtoWorld(limitedRegion, air)); + generationStage.populate(new BukkitProtoWorld(limitedRegion, air, pack.getBiomeProvider())); } }) .collect(Collectors.toList()); @@ -95,13 +92,12 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener public boolean shouldGenerateDecorations() { return true; } - @Override public boolean shouldGenerateMobs() { return true; } - + @Override public boolean shouldGenerateStructures() { return true; @@ -120,4 +116,22 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener public ChunkGenerator getHandle() { return delegate; } + + + private record SeededVector(int x, int z, WorldProperties worldProperties) { + @Override + public boolean equals(Object obj) { + if(obj instanceof SeededVector that) { + return this.z == that.z && this.x == that.x && this.worldProperties.equals(that.worldProperties); + } + return false; + } + + @Override + public int hashCode() { + int code = x; + code = 31 * code + z; + return 31 * code + worldProperties.hashCode(); + } + } } diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/nms/Initializer.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/nms/Initializer.java index b86a37f89..2c8f1c211 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/nms/Initializer.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/nms/Initializer.java @@ -1,21 +1,16 @@ package com.dfsek.terra.bukkit.nms; -import com.dfsek.terra.bukkit.PlatformImpl; -import com.dfsek.terra.bukkit.TerraBukkitPlugin; - import org.bukkit.Bukkit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.reflect.InvocationTargetException; +import com.dfsek.terra.bukkit.PlatformImpl; public interface Initializer { String NMS = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; String TERRA_PACKAGE = Initializer.class.getPackageName(); - void initialize(PlatformImpl plugin); - static void init(PlatformImpl platform) { Logger logger = LoggerFactory.getLogger(Initializer.class); try { @@ -40,4 +35,6 @@ public interface Initializer { logger.error("This is usually due to running Terra on an unsupported Minecraft version."); } } + + void initialize(PlatformImpl plugin); } diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/util/VersionUtil.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/util/VersionUtil.java index 08e9b4864..469582bf2 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/util/VersionUtil.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/util/VersionUtil.java @@ -1,7 +1,5 @@ package com.dfsek.terra.bukkit.util; -import ca.solostudios.strata.Versions; -import ca.solostudios.strata.version.Version; import io.papermc.lib.PaperLib; import org.bukkit.Bukkit; import org.slf4j.Logger; diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/BukkitProtoWorld.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/BukkitProtoWorld.java index 579fc4825..52b3c5855 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/BukkitProtoWorld.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/BukkitProtoWorld.java @@ -31,9 +31,12 @@ public class BukkitProtoWorld implements ProtoWorld { private final LimitedRegion delegate; private final BlockState air; - public BukkitProtoWorld(LimitedRegion delegate, BlockState air) { + private final BiomeProvider biomeProvider; + + public BukkitProtoWorld(LimitedRegion delegate, BlockState air, BiomeProvider provider) { this.delegate = delegate; this.air = air; + this.biomeProvider = provider; } @Override @@ -90,7 +93,7 @@ public class BukkitProtoWorld implements ProtoWorld { @Override public BiomeProvider getBiomeProvider() { - return ((BukkitChunkGeneratorWrapper) delegate.getWorld().getGenerator()).getPack().getBiomeProvider(); + return biomeProvider; } @Override diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/BukkitWorldProperties.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/BukkitWorldProperties.java index e324a62d7..7bd4106c6 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/BukkitWorldProperties.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/BukkitWorldProperties.java @@ -31,4 +31,17 @@ public class BukkitWorldProperties implements WorldProperties { public int getMinHeight() { return delegate.getMinHeight(); } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(obj instanceof WorldProperties that) { + return this.delegate.equals(that.getHandle()); + } + return false; + } } diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/block/data/BukkitBlockState.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/block/data/BukkitBlockState.java index f670d4f03..4a6716826 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/block/data/BukkitBlockState.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/block/data/BukkitBlockState.java @@ -24,7 +24,7 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter; public class BukkitBlockState implements BlockState { - private org.bukkit.block.data.BlockData delegate; + private final org.bukkit.block.data.BlockData delegate; protected BukkitBlockState(org.bukkit.block.data.BlockData delegate) { this.delegate = delegate; diff --git a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/inventory/meta/BukkitDamageable.java b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/inventory/meta/BukkitDamageable.java index 09e2e167b..461806112 100644 --- a/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/inventory/meta/BukkitDamageable.java +++ b/platforms/bukkit/common/src/main/java/com/dfsek/terra/bukkit/world/inventory/meta/BukkitDamageable.java @@ -17,15 +17,13 @@ package com.dfsek.terra.bukkit.world.inventory.meta; -import org.bukkit.inventory.meta.ItemMeta; - import com.dfsek.terra.api.inventory.item.Damageable; import com.dfsek.terra.bukkit.world.inventory.BukkitItemMeta; public class BukkitDamageable extends BukkitItemMeta implements Damageable { public BukkitDamageable(org.bukkit.inventory.meta.Damageable delegate) { - super((ItemMeta) delegate); + super(delegate); } @Override diff --git a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/AwfulBukkitHacks.java b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/AwfulBukkitHacks.java new file mode 100644 index 000000000..e125ffb68 --- /dev/null +++ b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/AwfulBukkitHacks.java @@ -0,0 +1,115 @@ +package com.dfsek.terra.bukkit.nms.v1_18_R2; + +import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.Lifecycle; +import net.minecraft.core.Holder; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.Registry; +import net.minecraft.core.WritableRegistry; +import net.minecraft.data.BuiltinRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.biome.Biome; +import org.bukkit.NamespacedKey; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.dfsek.terra.bukkit.world.BukkitPlatformBiome; +import com.dfsek.terra.registry.master.ConfigRegistry; + + +public class AwfulBukkitHacks { + private static final Logger LOGGER = LoggerFactory.getLogger(NMSBiomeInjector.class); + private static final Map> terraBiomeMap = new HashMap<>(); + + + public static void registerBiomes(ConfigRegistry configRegistry) { + try { + LOGGER.info("Hacking biome registry..."); + WritableRegistry biomeRegistry = (WritableRegistry) Registries.biomeRegistry(); + + Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry) biomeRegistry, false); + + configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> { + try { + BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome(); + NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey(); + ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey()); + Biome platform = NMSBiomeInjector.createBiome( + biome, + biomeRegistry.get(vanillaMinecraftKey) // get + ); + + ResourceKey delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY, new ResourceLocation("terra", + NMSBiomeInjector.createBiomeID( + pack, key))); + + BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform); + biomeRegistry.register(delegateKey, platform, Lifecycle.stable()); + platformBiome.getContext().put(new NMSBiomeInfo(delegateKey)); + + terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location()); + + LOGGER.debug("Registered biome: " + delegateKey); + } catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + })); + + Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry) biomeRegistry, true); // freeze registry again :) + + LOGGER.info("Doing tag garbage...."); + Map, List>> collect = biomeRegistry + .getTags() // streamKeysAndEntries + .collect(HashMap::new, + (map, pair) -> + map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())), + HashMap::putAll); + + terraBiomeMap + .forEach((vb, terraBiomes) -> + NMSBiomeInjector.getEntry(biomeRegistry, vb) + .ifPresentOrElse( + vanilla -> terraBiomes + .forEach(tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb) + .ifPresentOrElse( + terra -> { + LOGGER.debug( + vanilla.unwrapKey() + .orElseThrow() + .location() + + " (vanilla for " + + terra.unwrapKey() + .orElseThrow() + .location() + + ": " + + vanilla.tags() + .toList()); + + vanilla.tags() + .forEach( + tag -> collect + .computeIfAbsent( + tag, + t -> new ArrayList<>()) + .add(terra)); + }, + () -> LOGGER.error( + "No such biome: {}", + tb))), + () -> LOGGER.error("No vanilla biome: {}", vb))); + + biomeRegistry.resetTags(); // clearTags + biomeRegistry.bindTags(ImmutableMap.copyOf(collect)); // populateTags + + } catch(SecurityException | IllegalArgumentException exception) { + throw new RuntimeException(exception); + } + } +} diff --git a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSBiomeInjector.java b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSBiomeInjector.java index d7a03ef1e..6271e4632 100644 --- a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSBiomeInjector.java +++ b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSBiomeInjector.java @@ -1,114 +1,20 @@ package com.dfsek.terra.bukkit.nms.v1_18_R2; -import com.google.common.collect.ImmutableMap; -import com.mojang.serialization.Lifecycle; import net.minecraft.core.Holder; -import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; -import net.minecraft.core.WritableRegistry; -import net.minecraft.data.BuiltinRegistries; -import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.TagKey; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeSpecialEffects; -import org.bukkit.NamespacedKey; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Objects; import java.util.Optional; import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.bukkit.config.VanillaBiomeProperties; -import com.dfsek.terra.bukkit.world.BukkitPlatformBiome; -import com.dfsek.terra.registry.master.ConfigRegistry; public class NMSBiomeInjector { - private static final Logger LOGGER = LoggerFactory.getLogger(NMSBiomeInjector.class); - private static final Map> terraBiomeMap = new HashMap<>(); - - - public static void registerBiomes(ConfigRegistry configRegistry) { - try { - LOGGER.info("Hacking biome registry..."); - WritableRegistry biomeRegistry = (WritableRegistry) Registries.biomeRegistry(); - - Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry) biomeRegistry, false); - - configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> { - try { - BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome(); - NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey(); - ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey()); - Biome platform = createBiome( - biome, - biomeRegistry.get(vanillaMinecraftKey) // get - ); - - ResourceKey delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY, new ResourceLocation("terra", createBiomeID(pack, key))); - - BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform); - biomeRegistry.register(delegateKey, platform, Lifecycle.stable()); - platformBiome.getContext().put(new NMSBiomeInfo(delegateKey)); - - terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location()); - - LOGGER.debug("Registered biome: " + delegateKey); - } catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } - })); - - Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry) biomeRegistry, true); // freeze registry again :) - - LOGGER.info("Doing tag garbage...."); - Map, List>> collect = biomeRegistry - .getTags() // streamKeysAndEntries - .collect(HashMap::new, - (map, pair) -> - map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())), - HashMap::putAll); - - terraBiomeMap - .forEach((vb, terraBiomes) -> - getEntry(biomeRegistry, vb) - .ifPresentOrElse( - vanilla -> terraBiomes - .forEach(tb -> getEntry(biomeRegistry, tb) - .ifPresentOrElse( - terra -> { - LOGGER.debug(vanilla.unwrapKey().orElseThrow().location() + - " (vanilla for " + - terra.unwrapKey().orElseThrow().location() + - ": " + - vanilla.tags().toList()); - - vanilla.tags() - .forEach( - tag -> collect - .computeIfAbsent(tag, - t -> new ArrayList<>()) - .add(terra)); - }, - () -> LOGGER.error( - "No such biome: {}", - tb))), - () -> LOGGER.error("No vanilla biome: {}", vb))); - - biomeRegistry.resetTags(); // clearTags - biomeRegistry.bindTags(ImmutableMap.copyOf(collect)); // populateTags - - } catch(SecurityException | IllegalArgumentException exception) { - throw new RuntimeException(exception); - } - } public static Optional> getEntry(Registry registry, ResourceLocation identifier) { return registry.getOptional(identifier) @@ -116,46 +22,51 @@ public class NMSBiomeInjector { .map(registry::getOrCreateHolder); } - private static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla) + public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Biome.BiomeBuilder builder = new Biome.BiomeBuilder(); // Builder builder.biomeCategory(Reflection.BIOME.getBiomeCategory(vanilla)) .precipitation(vanilla.getPrecipitation()) // getPrecipitation - .mobSpawnSettings(vanilla.getMobSettings()) - .generationSettings(vanilla.getGenerationSettings()) - .temperature(vanilla.getBaseTemperature()) - .downfall(vanilla.getDownfall()); - - + .mobSpawnSettings(vanilla.getMobSettings()) + .generationSettings(vanilla.getGenerationSettings()) + .temperature(vanilla.getBaseTemperature()) + .downfall(vanilla.getDownfall()); + BiomeSpecialEffects.Builder effects = new BiomeSpecialEffects.Builder(); - + effects.grassColorModifier(vanilla.getSpecialEffects().getGrassColorModifier()); - + VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class); - + effects.fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor())) - + .waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor())) - + .waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor())) - + .skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor())); - + if(vanillaBiomeProperties.getFoliageColor() == null) { vanilla.getSpecialEffects().getFoliageColorOverride().ifPresent(effects::foliageColorOverride); } else { effects.foliageColorOverride(vanillaBiomeProperties.getFoliageColor()); } - + if(vanillaBiomeProperties.getGrassColor() == null) { vanilla.getSpecialEffects().getGrassColorOverride().ifPresent(effects::grassColorOverride); } else { effects.grassColorOverride(vanillaBiomeProperties.getGrassColor()); } - + + vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound); + vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound); + vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound); + vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic); + vanilla.getAmbientParticle().ifPresent(effects::ambientParticle); + builder.specialEffects(effects.build()); return builder.build(); // build() diff --git a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSBiomeProvider.java b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSBiomeProvider.java index 6d44d19d5..111b2802b 100644 --- a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSBiomeProvider.java +++ b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSBiomeProvider.java @@ -1,8 +1,5 @@ package com.dfsek.terra.bukkit.nms.v1_18_R2; -import com.dfsek.terra.api.world.biome.generation.BiomeProvider; -import com.dfsek.terra.bukkit.world.BukkitPlatformBiome; - import com.mojang.serialization.Codec; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -11,6 +8,9 @@ import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.Climate.Sampler; import org.jetbrains.annotations.NotNull; +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; +import com.dfsek.terra.bukkit.world.BukkitPlatformBiome; + public class NMSBiomeProvider extends BiomeSource { private final BiomeProvider delegate; diff --git a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSChunkGeneratorDelegate.java b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSChunkGeneratorDelegate.java index 0f8504c44..395ea949c 100644 --- a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSChunkGeneratorDelegate.java +++ b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSChunkGeneratorDelegate.java @@ -1,10 +1,5 @@ package com.dfsek.terra.bukkit.nms.v1_18_R2; -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.util.generic.Lazy; -import com.dfsek.terra.api.world.biome.generation.BiomeProvider; -import com.dfsek.terra.api.world.info.WorldProperties; - import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; @@ -21,7 +16,6 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.biome.Climate; import net.minecraft.world.level.biome.Climate.Sampler; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.GenerationStep; @@ -36,25 +30,33 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Random; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.stream.Collectors; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.util.generic.Lazy; +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; +import com.dfsek.terra.api.world.info.WorldProperties; + public class NMSChunkGeneratorDelegate extends ChunkGenerator { private static final Logger LOGGER = LoggerFactory.getLogger(NMSChunkGeneratorDelegate.class); + private static final Lazy> EMPTY = Lazy.lazy(List::of); private final NMSBiomeProvider biomeSource; private final com.dfsek.terra.api.world.chunk.generation.ChunkGenerator delegate; - private final ChunkGenerator vanilla; private final ConfigPack pack; - private final long seed; - private final Map>> ringPositions = new Object2ObjectArrayMap<>(); - private static final Lazy> EMPTY = Lazy.lazy(List::of); - + private volatile boolean rings = false; public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) { super(Registries.structureSet(), Optional.empty(), biomeProvider, biomeProvider, seed); @@ -66,13 +68,15 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { } @Override - public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull BiomeManager biomeAccess, @NotNull StructureFeatureManager structureAccessor, + public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull BiomeManager biomeAccess, + @NotNull StructureFeatureManager structureAccessor, @NotNull ChunkAccess chunk, GenerationStep.@NotNull Carving generationStep) { // no-op } @Override - public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk, @NotNull StructureFeatureManager structureAccessor) { + public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk, + @NotNull StructureFeatureManager structureAccessor) { vanilla.applyBiomeDecoration(world, chunk, structureAccessor); } @@ -81,8 +85,9 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { return vanilla.getSeaLevel(); } - @Override //fillFromNoise - public @NotNull CompletableFuture fillFromNoise(@NotNull Executor executor, @NotNull Blender blender, @NotNull StructureFeatureManager structureAccessor, + @Override + public @NotNull CompletableFuture fillFromNoise(@NotNull Executor executor, @NotNull Blender blender, + @NotNull StructureFeatureManager structureAccessor, @NotNull ChunkAccess chunk) { return vanilla.fillFromNoise(executor, blender, structureAccessor, chunk); } @@ -97,8 +102,9 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { return ChunkGenerator.CODEC; } - @Override // getColumn + @Override public @NotNull NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor height) { + /* BlockState[] array = new BlockState[height.getHeight()]; WorldProperties properties = new NMSWorldProperties(seed, height); BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); @@ -107,6 +113,8 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { .getHandle()).getState(); } return new NoiseColumn(getMinY(), array); + */ + return vanilla.getBaseColumn(x, z, height); } @Override // withSeed @@ -138,7 +146,7 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { public int getBaseHeight(int x, int z, Heightmap.@NotNull Types heightmap, @NotNull LevelHeightAccessor world) { WorldProperties properties = new NMSWorldProperties(seed, world); int y = properties.getMaxHeight(); - BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); + BiomeProvider biomeProvider = pack.getBiomeProvider(); while(y >= getMinY() && !heightmap.isOpaque().test( ((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) { y--; @@ -153,8 +161,6 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { return ringPositions.getOrDefault(concentricringsstructureplacement, EMPTY).value(); } - private volatile boolean rings = false; - @Override public synchronized void ensureStructuresGenerated() { if(!this.rings) { @@ -219,7 +225,7 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { this.climateSampler()); if(pair != null) { - BlockPos blockposition = (BlockPos) pair.getFirst(); + BlockPos blockposition = pair.getFirst(); k1 = SectionPos.blockToSectionCoord(blockposition.getX()); l1 = SectionPos.blockToSectionCoord(blockposition.getZ()); diff --git a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSInitializer.java b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSInitializer.java index 60c7e1c1d..f724b89f0 100644 --- a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSInitializer.java +++ b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSInitializer.java @@ -9,7 +9,7 @@ import com.dfsek.terra.bukkit.nms.Initializer; public class NMSInitializer implements Initializer { @Override public void initialize(PlatformImpl platform) { - NMSBiomeInjector.registerBiomes(platform.getRawConfigRegistry()); + AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry()); Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin()); } } diff --git a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSInjectListener.java b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSInjectListener.java index 46f4a64c0..55408a136 100644 --- a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSInjectListener.java +++ b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/NMSInjectListener.java @@ -25,15 +25,16 @@ public class NMSInjectListener implements Listener { @EventHandler public void onWorldInit(WorldInitEvent event) { - if (!INJECTED.contains(event.getWorld()) && event.getWorld().getGenerator() instanceof BukkitChunkGeneratorWrapper bukkitChunkGeneratorWrapper) { + if(!INJECTED.contains(event.getWorld()) && + event.getWorld().getGenerator() instanceof BukkitChunkGeneratorWrapper bukkitChunkGeneratorWrapper) { INJECT_LOCK.lock(); INJECTED.add(event.getWorld()); LOGGER.info("Preparing to take over the world: {}", event.getWorld().getName()); CraftWorld craftWorld = (CraftWorld) event.getWorld(); ServerLevel serverWorld = craftWorld.getHandle(); - + ConfigPack pack = bukkitChunkGeneratorWrapper.getPack(); - + ChunkGenerator vanilla = serverWorld.getChunkSource().getGenerator(); NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), vanilla.getBiomeSource(), craftWorld.getSeed()); NMSChunkGeneratorDelegate custom = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed()); diff --git a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/Reflection.java b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/Reflection.java index 53e9e80f9..9e226cb8d 100644 --- a/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/Reflection.java +++ b/platforms/bukkit/nms/v1_18_R2/src/main/java/com/dfsek/terra/bukkit/nms/v1_18_R2/Reflection.java @@ -15,18 +15,21 @@ public class Reflection { static { ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar(); - ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper, Reflection.class.getClassLoader()); + ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper, + Reflection.class.getClassLoader()); MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class); BIOME = reflectionProxyFactory.reflectionProxy(BiomeProxy.class); } + @Proxies(MappedRegistry.class) public interface MappedRegistryProxy { @FieldSetter("frozen") void setFrozen(MappedRegistry instance, boolean frozen); } + @Proxies(Biome.class) public interface BiomeProxy { @FieldGetter("biomeCategory") diff --git a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/AwfulBukkitHacks.java b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/AwfulBukkitHacks.java new file mode 100644 index 000000000..3bce51cdd --- /dev/null +++ b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/AwfulBukkitHacks.java @@ -0,0 +1,116 @@ +package com.dfsek.terra.bukkit.nms.v1_19_R1; + +import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.Lifecycle; +import net.minecraft.core.Holder; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.Registry; +import net.minecraft.core.WritableRegistry; +import net.minecraft.data.BuiltinRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.biome.Biome; +import org.bukkit.NamespacedKey; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import com.dfsek.terra.bukkit.world.BukkitPlatformBiome; +import com.dfsek.terra.registry.master.ConfigRegistry; + + +public class AwfulBukkitHacks { + private static final Logger LOGGER = LoggerFactory.getLogger(AwfulBukkitHacks.class); + + private static final Map> terraBiomeMap = new HashMap<>(); + + public static void registerBiomes(ConfigRegistry configRegistry) { + try { + LOGGER.info("Hacking biome registry..."); + WritableRegistry biomeRegistry = (WritableRegistry) Registries.biomeRegistry(); + + Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry) biomeRegistry, false); + + configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> { + try { + BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome(); + NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey(); + ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey()); + Biome platform = NMSBiomeInjector.createBiome( + biome, + Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)) // get + ); + + ResourceKey delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY, + new ResourceLocation("terra", + NMSBiomeInjector.createBiomeID(pack, key))); + + BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform); + biomeRegistry.register(delegateKey, platform, Lifecycle.stable()); + platformBiome.getContext().put(new NMSBiomeInfo(delegateKey)); + + terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location()); + + LOGGER.debug("Registered biome: " + delegateKey); + } catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + })); + + Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry) biomeRegistry, true); // freeze registry again :) + + LOGGER.info("Doing tag garbage...."); + Map, List>> collect = biomeRegistry + .getTags() // streamKeysAndEntries + .collect(HashMap::new, + (map, pair) -> + map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())), + HashMap::putAll); + + terraBiomeMap + .forEach((vb, terraBiomes) -> + NMSBiomeInjector.getEntry(biomeRegistry, vb) + .ifPresentOrElse( + vanilla -> terraBiomes + .forEach(tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb) + .ifPresentOrElse( + terra -> { + LOGGER.debug( + vanilla.unwrapKey() + .orElseThrow() + .location() + + " (vanilla for " + + terra.unwrapKey() + .orElseThrow() + .location() + + ": " + + vanilla.tags() + .toList()); + + vanilla.tags() + .forEach( + tag -> collect + .computeIfAbsent( + tag, + t -> new ArrayList<>()) + .add(terra)); + }, + () -> LOGGER.error( + "No such biome: {}", + tb))), + () -> LOGGER.error("No vanilla biome: {}", vb))); + + biomeRegistry.resetTags(); + biomeRegistry.bindTags(ImmutableMap.copyOf(collect)); + + } catch(SecurityException | IllegalArgumentException exception) { + throw new RuntimeException(exception); + } + } +} diff --git a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSBiomeInjector.java b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSBiomeInjector.java index 2da3c3f85..8a5d56c35 100644 --- a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSBiomeInjector.java +++ b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSBiomeInjector.java @@ -1,117 +1,28 @@ package com.dfsek.terra.bukkit.nms.v1_19_R1; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSpecialEffects; + +import java.util.Locale; +import java.util.Objects; +import java.util.Optional; + import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.bukkit.config.VanillaBiomeProperties; -import com.dfsek.terra.bukkit.world.BukkitPlatformBiome; -import com.dfsek.terra.registry.master.ConfigRegistry; - -import com.google.common.collect.ImmutableMap; -import com.mojang.serialization.Lifecycle; -import net.minecraft.core.Holder; -import net.minecraft.core.MappedRegistry; -import net.minecraft.core.Registry; -import net.minecraft.core.WritableRegistry; -import net.minecraft.data.BuiltinRegistries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.TagKey; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSpecialEffects; -import org.bukkit.NamespacedKey; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; public class NMSBiomeInjector { - private static final Logger LOGGER = LoggerFactory.getLogger(NMSBiomeInjector.class); - private static final Map> terraBiomeMap = new HashMap<>(); - - - public static void registerBiomes(ConfigRegistry configRegistry) { - try { - LOGGER.info("Hacking biome registry..."); - WritableRegistry biomeRegistry = (WritableRegistry) Registries.biomeRegistry(); - - Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry) biomeRegistry, false); - - configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> { - try { - BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome(); - NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey(); - ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey()); - Biome platform = createBiome( - biome, - Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)) // get - ); - - ResourceKey delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY, - new ResourceLocation("terra", createBiomeID(pack, key))); - - BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform); - biomeRegistry.register(delegateKey, platform, Lifecycle.stable()); - platformBiome.getContext().put(new NMSBiomeInfo(delegateKey)); - - terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location()); - - LOGGER.debug("Registered biome: " + delegateKey); - } catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } - })); - - Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry) biomeRegistry, true); // freeze registry again :) - - LOGGER.info("Doing tag garbage...."); - Map, List>> collect = biomeRegistry - .getTags() // streamKeysAndEntries - .collect(HashMap::new, - (map, pair) -> - map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())), - HashMap::putAll); - - terraBiomeMap - .forEach((vb, terraBiomes) -> - getEntry(biomeRegistry, vb) - .ifPresentOrElse( - vanilla -> terraBiomes - .forEach(tb -> getEntry(biomeRegistry, tb) - .ifPresentOrElse( - terra -> { - LOGGER.debug(vanilla.unwrapKey().orElseThrow().location() + - " (vanilla for " + - terra.unwrapKey().orElseThrow().location() + - ": " + - vanilla.tags().toList()); - - vanilla.tags() - .forEach( - tag -> collect - .computeIfAbsent(tag, - t -> new ArrayList<>()) - .add(terra)); - }, - () -> LOGGER.error( - "No such biome: {}", - tb))), - () -> LOGGER.error("No vanilla biome: {}", vb))); - - biomeRegistry.resetTags(); - biomeRegistry.bindTags(ImmutableMap.copyOf(collect)); - - } catch(SecurityException | IllegalArgumentException exception) { - throw new RuntimeException(exception); - } - } - + public static Optional> getEntry(Registry registry, ResourceLocation identifier) { return registry.getOptional(identifier) .flatMap(registry::getResourceKey) .map(registry::getOrCreateHolderOrThrow); } - private static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla) + public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Biome.BiomeBuilder builder = new Biome.BiomeBuilder(); @@ -150,6 +61,12 @@ public class NMSBiomeInjector { effects.grassColorOverride(vanillaBiomeProperties.getGrassColor()); } + vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound); + vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound); + vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound); + vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic); + vanilla.getAmbientParticle().ifPresent(effects::ambientParticle); + builder.specialEffects(effects.build()); return builder.build(); diff --git a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSBiomeProvider.java b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSBiomeProvider.java index 36433165b..0c5a8ef06 100644 --- a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSBiomeProvider.java +++ b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSBiomeProvider.java @@ -18,7 +18,11 @@ public class NMSBiomeProvider extends BiomeSource { private final Registry biomeRegistry = Registries.biomeRegistry(); public NMSBiomeProvider(BiomeProvider delegate, long seed) { - super(delegate.stream().map(biome -> Registries.biomeRegistry().getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext().get(NMSBiomeInfo.class).biomeKey()))); + super(delegate.stream() + .map(biome -> Registries.biomeRegistry() + .getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext() + .get(NMSBiomeInfo.class) + .biomeKey()))); this.delegate = delegate; this.seed = seed; } @@ -30,6 +34,9 @@ public class NMSBiomeProvider extends BiomeSource { @Override public @NotNull Holder getNoiseBiome(int x, int y, int z, @NotNull Sampler sampler) { - return biomeRegistry.getHolderOrThrow(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed).getPlatformBiome()).getContext().get(NMSBiomeInfo.class).biomeKey()); + return biomeRegistry.getHolderOrThrow(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed) + .getPlatformBiome()).getContext() + .get(NMSBiomeInfo.class) + .biomeKey()); } } diff --git a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSChunkGeneratorDelegate.java b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSChunkGeneratorDelegate.java index b95a7f53c..81933be0f 100644 --- a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSChunkGeneratorDelegate.java +++ b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSChunkGeneratorDelegate.java @@ -16,7 +16,6 @@ import net.minecraft.world.level.StructureManager; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.GenerationStep.Carving; @@ -56,6 +55,8 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { private final ConfigPack pack; private final long seed; + private final Map>> ringPositions = new Object2ObjectArrayMap<>(); + private volatile boolean rings = false; public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) { super(Registries.structureSet(), Optional.empty(), biomeProvider); @@ -119,7 +120,7 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { public int getBaseHeight(int x, int z, @NotNull Types heightmap, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) { WorldProperties properties = new NMSWorldProperties(seed, world); int y = properties.getMaxHeight(); - BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); + BiomeProvider biomeProvider = pack.getBiomeProvider(); while(y >= getMinY() && !heightmap.isOpaque().test( ((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) { y--; @@ -129,6 +130,7 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { @Override public @NotNull NoiseColumn getBaseColumn(int x, int z, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) { + /* BlockState[] array = new BlockState[world.getHeight()]; WorldProperties properties = new NMSWorldProperties(seed, world); BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); @@ -137,16 +139,16 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { .getHandle()).getState(); } return new NoiseColumn(getMinY(), array); + + */ + return vanilla.getBaseColumn(x, z, world, noiseConfig); } - + @Override public void addDebugScreenInfo(@NotNull List text, @NotNull RandomState noiseConfig, @NotNull BlockPos pos) { - + } - private volatile boolean rings = false; - private final Map>> ringPositions = new Object2ObjectArrayMap<>(); - @Override public void ensureStructuresGenerated(@NotNull RandomState noiseConfig) { if(!this.rings) { @@ -158,7 +160,8 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { } @Override - public List getRingPositionsFor(@NotNull ConcentricRingsStructurePlacement structurePlacement, @NotNull RandomState noiseConfig) { + public List getRingPositionsFor(@NotNull ConcentricRingsStructurePlacement structurePlacement, + @NotNull RandomState noiseConfig) { ensureStructuresGenerated(noiseConfig); return ringPositions.get(structurePlacement).value(); } @@ -176,13 +179,15 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator { } } - if (match) { - if (holder.placement() instanceof ConcentricRingsStructurePlacement concentricringsstructureplacement) { - this.ringPositions.put(concentricringsstructureplacement, Lazy.lazy(() -> this.generateRingPositions(holder, noiseConfig, concentricringsstructureplacement))); + if(match) { + if(holder.placement() instanceof ConcentricRingsStructurePlacement concentricringsstructureplacement) { + this.ringPositions.put(concentricringsstructureplacement, Lazy.lazy( + () -> this.generateRingPositions(holder, noiseConfig, concentricringsstructureplacement))); } } }); } + private List generateRingPositions(StructureSet holder, RandomState randomstate, ConcentricRingsStructurePlacement concentricringsstructureplacement) { // Spigot if(concentricringsstructureplacement.count() == 0) { diff --git a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSInitializer.java b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSInitializer.java index 61efc587d..82a293cd1 100644 --- a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSInitializer.java +++ b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSInitializer.java @@ -9,7 +9,7 @@ import com.dfsek.terra.bukkit.nms.Initializer; public class NMSInitializer implements Initializer { @Override public void initialize(PlatformImpl platform) { - NMSBiomeInjector.registerBiomes(platform.getRawConfigRegistry()); + AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry()); Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin()); } } diff --git a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSInjectListener.java b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSInjectListener.java index c647afbd5..d57689a9b 100644 --- a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSInjectListener.java +++ b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/NMSInjectListener.java @@ -25,15 +25,16 @@ public class NMSInjectListener implements Listener { @EventHandler public void onWorldInit(WorldInitEvent event) { - if (!INJECTED.contains(event.getWorld()) && event.getWorld().getGenerator() instanceof BukkitChunkGeneratorWrapper bukkitChunkGeneratorWrapper) { + if(!INJECTED.contains(event.getWorld()) && + event.getWorld().getGenerator() instanceof BukkitChunkGeneratorWrapper bukkitChunkGeneratorWrapper) { INJECT_LOCK.lock(); INJECTED.add(event.getWorld()); LOGGER.info("Preparing to take over the world: {}", event.getWorld().getName()); CraftWorld craftWorld = (CraftWorld) event.getWorld(); ServerLevel serverWorld = craftWorld.getHandle(); - + ConfigPack pack = bukkitChunkGeneratorWrapper.getPack(); - + ChunkGenerator vanilla = serverWorld.getChunkSource().getGenerator(); NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), craftWorld.getSeed()); NMSChunkGeneratorDelegate custom = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed()); diff --git a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/Reflection.java b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/Reflection.java index 157157005..8fa9a0b01 100644 --- a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/Reflection.java +++ b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/Reflection.java @@ -12,11 +12,13 @@ public class Reflection { static { ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar(); - ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper, Reflection.class.getClassLoader()); + ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper, + Reflection.class.getClassLoader()); MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class); } + @Proxies(MappedRegistry.class) public interface MappedRegistryProxy { @FieldSetter("frozen") diff --git a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/Registries.java b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/Registries.java index 622589a77..f1cdc645e 100644 --- a/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/Registries.java +++ b/platforms/bukkit/nms/v1_19_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R1/Registries.java @@ -16,8 +16,8 @@ public class Registries { return dedicatedserver .registryAccess() .registryOrThrow( // getRegistry - key - ); + key + ); } public static Registry biomeRegistry() { diff --git a/platforms/cli/build.gradle.kts b/platforms/cli/build.gradle.kts index 36eb49cdf..e273422af 100644 --- a/platforms/cli/build.gradle.kts +++ b/platforms/cli/build.gradle.kts @@ -1,24 +1,35 @@ -repositories { - maven { url = uri("https://jitpack.io/") } +plugins { + application } +val javaMainClass = "com.dfsek.terra.cli.TerraCLI" + dependencies { - shadedApi("commons-io:commons-io:2.7") - shadedApi("com.github.Querz:NBT:6.1") shadedApi(project(":common:implementation:base")) - shadedImplementation("com.google.guava:guava:31.0.1-jre") + shadedApi("commons-io:commons-io:${Versions.CLI.commonsIO}") + shadedApi("com.github.Querz:NBT:${Versions.CLI.nbt}") - shadedImplementation("ch.qos.logback:logback-classic:1.2.9") + shadedImplementation("com.google.guava:guava:${Versions.CLI.guava}") + + shadedImplementation("ch.qos.logback:logback-classic:${Versions.CLI.logback}") implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama) } -tasks.withType() { +tasks.withType { entryCompression = ZipEntryCompression.STORED manifest { attributes( - "Main-Class" to "com.dfsek.terra.cli.TerraCLI", + "Main-Class" to javaMainClass, ) } -} \ No newline at end of file +} + +application { + mainClass.set(javaMainClass) +} + +tasks.getByName("run").setProperty("workingDir", file("./run")) + +addonDir(project.file("./run/addons"), tasks.named("run").get()) diff --git a/platforms/cli/src/main/java/com/dfsek/terra/cli/block/CLIBlockState.java b/platforms/cli/src/main/java/com/dfsek/terra/cli/block/CLIBlockState.java index 53cbc5e90..026f3dfc5 100644 --- a/platforms/cli/src/main/java/com/dfsek/terra/cli/block/CLIBlockState.java +++ b/platforms/cli/src/main/java/com/dfsek/terra/cli/block/CLIBlockState.java @@ -16,9 +16,9 @@ public class CLIBlockState implements BlockState { public CLIBlockState(String value) { this.value = value; if(value.contains("[")) { - + } else { - + } this.isAir = value.startsWith("minecraft:air"); this.nbt = new CompoundTag(); diff --git a/platforms/cli/src/main/java/com/dfsek/terra/cli/generator/CLIChunkGenerator.java b/platforms/cli/src/main/java/com/dfsek/terra/cli/generator/CLIChunkGenerator.java deleted file mode 100644 index 0b58929b3..000000000 --- a/platforms/cli/src/main/java/com/dfsek/terra/cli/generator/CLIChunkGenerator.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.dfsek.terra.cli.generator; - -import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; -import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper; - - -public class CLIChunkGenerator implements GeneratorWrapper { - @Override - public ChunkGenerator getHandle() { - return null; - } -} diff --git a/platforms/cli/src/main/java/com/dfsek/terra/cli/world/CLIWorld.java b/platforms/cli/src/main/java/com/dfsek/terra/cli/world/CLIWorld.java index c385ff8eb..e281efd0e 100644 --- a/platforms/cli/src/main/java/com/dfsek/terra/cli/world/CLIWorld.java +++ b/platforms/cli/src/main/java/com/dfsek/terra/cli/world/CLIWorld.java @@ -85,8 +85,9 @@ public class CLIWorld implements ServerWorld, NBTSerializable stage.populate(protoWorld)); if(num % 240 == 239) { long time = System.nanoTime(); @@ -224,10 +225,12 @@ public class CLIWorld implements ServerWorld, NBTSerializable { this.z = z; this.world = world; this.chunks = new CLIChunk[32 * 32]; - ; } public CLIChunk get(int x, int z) { diff --git a/platforms/fabric/build.gradle.kts b/platforms/fabric/build.gradle.kts index 962c65a50..7ed3f2e75 100644 --- a/platforms/fabric/build.gradle.kts +++ b/platforms/fabric/build.gradle.kts @@ -1,82 +1,76 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import com.modrinth.minotaur.TaskModrinthUpload -import net.fabricmc.loom.task.RemapJarTask - plugins { - id("fabric-loom").version(Versions.Fabric.loom) - id("com.modrinth.minotaur").version("1.1.0") + id("dev.architectury.loom") version Versions.Mod.architecuryLoom + id("architectury-plugin") version Versions.Mod.architecturyPlugin + id("io.github.juuxel.loom-quiltflower") version Versions.Mod.loomQuiltflower +} + +architectury { + platformSetupLoomIde() + loader("fabric") } dependencies { shadedApi(project(":common:implementation:base")) - minecraft("com.mojang:minecraft:${Versions.Fabric.minecraft}") - mappings("net.fabricmc:yarn:${Versions.Fabric.yarn}:v2") + implementation(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } + "developmentFabric"(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } + shaded(project(path = ":platforms:mixin-common", configuration = "transformProductionFabric")) { isTransitive = false } + implementation(project(path = ":platforms:mixin-lifecycle", configuration = "namedElements")) { isTransitive = false } + "developmentFabric"(project(path = ":platforms:mixin-lifecycle", configuration = "namedElements")) { isTransitive = false } + shaded(project(path = ":platforms:mixin-lifecycle", configuration = "transformProductionFabric")) { isTransitive = false } + + + minecraft("com.mojang:minecraft:${Versions.Mod.minecraft}") + mappings("net.fabricmc:yarn:${Versions.Mod.yarn}:v2") modImplementation("net.fabricmc:fabric-loader:${Versions.Fabric.fabricLoader}") - setOf("fabric-lifecycle-events-v1", "fabric-resource-loader-v0", "fabric-api-base", "fabric-command-api-v2").forEach { apiModule -> + setOf( + "fabric-lifecycle-events-v1", + "fabric-resource-loader-v0", + "fabric-api-base", + "fabric-command-api-v2", + "fabric-networking-api-v1" + ).forEach { apiModule -> val module = fabricApi.module(apiModule, Versions.Fabric.fabricAPI) modImplementation(module) include(module) } - include(modImplementation("me.lucko", "fabric-permissions-api", Versions.Fabric.permissionsAPI)) - include("me.lucko", "fabric-permissions-api", Versions.Fabric.permissionsAPI) - - "compileOnly"("net.fabricmc:sponge-mixin:${Versions.Fabric.mixin}") - "annotationProcessor"("net.fabricmc:sponge-mixin:${Versions.Fabric.mixin}") - "annotationProcessor"("net.fabricmc:fabric-loom:${Versions.Fabric.loom}") - - include(modImplementation("cloud.commandframework", "cloud-fabric", Versions.Libraries.cloud)) + modImplementation("cloud.commandframework", "cloud-fabric", Versions.Libraries.cloud) include("cloud.commandframework", "cloud-fabric", Versions.Libraries.cloud) + + modLocalRuntime("com.github.astei:lazydfu:${Versions.Mod.lazyDfu}") } loom { - accessWidenerPath.set(file("src/main/resources/terra.accesswidener")) + accessWidenerPath.set(project(":platforms:mixin-common").file("src/main/resources/terra.accesswidener")) + mixin { - defaultRefmapName.set("terra-refmap.json") + defaultRefmapName.set("terra.fabric.refmap.json") + } + + launches { + named("client") { + property("fabric.log.level", "debug") + } + named("server") { + property("fabric.log.level", "debug") + } } } -addonDir(project.rootProject.file("./run/config/Terra/addons"), tasks.named("runClient").get()) -addonDir(project.rootProject.file("./run/config/Terra/addons"), tasks.named("runServer").get()) +addonDir(project.file("./run/config/Terra/addons"), tasks.named("configureLaunch").get()) -tasks.withType().configureEach { - options.release.set(17) +tasks { + compileJava { + options.release.set(17) + } + + remapJar { + injectAccessWidener.set(true) + inputFile.set(shadowJar.get().archiveFile) + archiveFileName.set("${rootProject.name.capitalize()}-fabric-${project.version}.jar") + } } - -tasks.getByName("shadowJar") { - exclude("org/slf4j/**") -} - -val remapped = tasks.register("remapShadedJar") { - dependsOn("installAddons") - group = "fabric" - val shadowJar = tasks.getByName("shadowJar") - dependsOn(shadowJar) - inputFile.set(shadowJar.archiveFile) - archiveFileName.set(shadowJar.archiveFileName.get().replace(Regex("-shaded\\.jar$"), "-shaded-mapped.jar")) - addNestedDependencies.set(true) -} - -tasks.named("assemble").configure { - dependsOn("remapShadedJar") -} - -tasks.withType { - finalizedBy(remapped) -} - -tasks.register("publishModrinth") { - dependsOn("remapShadedJar") - group = "fabric" - token = System.getenv("MODRINTH_SECRET") - projectId = "FIlZB9L0" - versionNumber = "${project.version}-fabric" - uploadFile = remapped.get().archiveFile.get().asFile - releaseType = "beta" - addGameVersion(Versions.Fabric.minecraft) - addLoader("fabric") -} \ No newline at end of file diff --git a/platforms/fabric/gradle.properties b/platforms/fabric/gradle.properties new file mode 100644 index 000000000..90ee7a259 --- /dev/null +++ b/platforms/fabric/gradle.properties @@ -0,0 +1 @@ +loom.platform=fabric \ No newline at end of file diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricAddon.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricAddon.java index 347244a54..db98b73df 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricAddon.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricAddon.java @@ -1,80 +1,17 @@ -/* - * This file is part of Terra. - * - * Terra is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Terra is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Terra. If not, see . - */ - package com.dfsek.terra.fabric; -import ca.solostudios.strata.Versions; -import ca.solostudios.strata.version.Version; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.dfsek.terra.api.addon.BaseAddon; -import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; -import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; -import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; -import com.dfsek.terra.api.event.functional.FunctionalEventHandler; -import com.dfsek.terra.api.world.biome.Biome; -import com.dfsek.terra.fabric.config.PostLoadCompatibilityOptions; -import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.fabric.config.VanillaBiomeProperties; +import com.dfsek.terra.mod.MinecraftAddon; +import com.dfsek.terra.mod.ModPlatform; -public final class FabricAddon implements BaseAddon { - private static final Version VERSION = Versions.getVersion(1, 0, 0); - private static final Logger logger = LoggerFactory.getLogger(FabricAddon.class); - private final PlatformImpl terraFabricPlugin; +public class FabricAddon extends MinecraftAddon { - public FabricAddon(PlatformImpl terraFabricPlugin) { - this.terraFabricPlugin = terraFabricPlugin; - } - - @Override - public void initialize() { - terraFabricPlugin.getEventManager() - .getHandler(FunctionalEventHandler.class) - .register(this, ConfigPackPreLoadEvent.class) - .then(event -> event.getPack().getContext().put(event.loadTemplate(new PreLoadCompatibilityOptions()))) - .global(); - - terraFabricPlugin.getEventManager() - .getHandler(FunctionalEventHandler.class) - .register(this, ConfigPackPostLoadEvent.class) - .then(event -> event.getPack().getContext().put(event.loadTemplate(new PostLoadCompatibilityOptions()))) - .priority(100) - .global(); - - terraFabricPlugin.getEventManager() - .getHandler(FunctionalEventHandler.class) - .register(this, ConfigurationLoadEvent.class) - .then(event -> { - if(event.is(Biome.class)) { - event.getLoadedObject(Biome.class).getContext().put(event.load(new VanillaBiomeProperties())); - } - }) - .global(); - } - - @Override - public Version getVersion() { - return VERSION; + public FabricAddon(ModPlatform modPlatform) { + super(modPlatform); } @Override public String getID() { return "terra-fabric"; } -} +} \ No newline at end of file diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java index 66348ed53..54d03961e 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java @@ -18,37 +18,20 @@ package com.dfsek.terra.fabric; import cloud.commandframework.execution.CommandExecutionCoordinator; - import cloud.commandframework.fabric.FabricServerCommandManager; - -import com.dfsek.terra.api.command.CommandSender; -import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent; - import net.fabricmc.api.ModInitializer; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; -import net.minecraft.world.gen.WorldPresets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.dfsek.terra.fabric.data.Codecs; +import com.dfsek.terra.api.command.CommandSender; +import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent; public class FabricEntryPoint implements ModInitializer { private static final Logger logger = LoggerFactory.getLogger(FabricEntryPoint.class); - private static final PlatformImpl TERRA_PLUGIN = new PlatformImpl(); - - - public static PlatformImpl getPlatform() { - return TERRA_PLUGIN; - } - - public static void register() { // register the things - Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); - Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); - } + private static final FabricPlatform TERRA_PLUGIN = new FabricPlatform(); @Override public void onInitialize() { diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricPlatform.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricPlatform.java new file mode 100644 index 000000000..2c85b86ee --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricPlatform.java @@ -0,0 +1,73 @@ +/* + * This file is part of Terra. + * + * Terra is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Terra is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Terra. If not, see . + */ + +package com.dfsek.terra.fabric; + +import ca.solostudios.strata.Versions; +import ca.solostudios.strata.parser.tokenizer.ParseException; +import ca.solostudios.strata.version.Version; +import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Collection; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.dfsek.terra.addon.EphemeralAddon; +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.lifecycle.LifecyclePlatform; + + +public class FabricPlatform extends LifecyclePlatform { + private static final Logger LOGGER = LoggerFactory.getLogger(FabricPlatform.class); + + @Override + protected Collection getPlatformMods() { + return FabricLoader.getInstance().getAllMods().stream().flatMap(mod -> { + String id = mod.getMetadata().getId(); + if(id.equals("terra") || id.equals("minecraft") || id.equals("java")) return Stream.empty(); + try { + Version version = Versions.parseVersion(mod.getMetadata().getVersion().getFriendlyString()); + return Stream.of(new EphemeralAddon(version, "fabric:" + id)); + } catch(ParseException e) { + LOGGER.warn( + "Mod {}, version {} does not follow semantic versioning specification, Terra addons will be unable to depend on " + + "it.", + id, mod.getMetadata().getVersion().getFriendlyString()); + } + return Stream.empty(); + }).collect(Collectors.toList()); + } + + @Override + public @NotNull String platformName() { + return "Fabric"; + } + + @Override + public @NotNull File getDataFolder() { + return new File(FabricLoader.getInstance().getConfigDir().toFile(), "Terra"); + } + + @Override + public BaseAddon getPlatformAddon() { + return new FabricAddon(this); + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java deleted file mode 100644 index fef99d2cd..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Terra is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Terra. If not, see . - */ - -package com.dfsek.terra.fabric; - -import ca.solostudios.strata.Versions; -import ca.solostudios.strata.parser.tokenizer.ParseException; -import ca.solostudios.strata.version.Version; -import com.dfsek.tectonic.api.TypeRegistry; -import com.dfsek.tectonic.api.depth.DepthTracker; -import com.dfsek.tectonic.api.exception.LoadException; -import com.dfsek.terra.fabric.util.BiomeUtil; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.MinecraftVersion; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.BuiltinRegistries; -import net.minecraft.world.biome.Biome.Precipitation; -import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import com.dfsek.terra.AbstractPlatform; -import com.dfsek.terra.addon.EphemeralAddon; -import com.dfsek.terra.api.addon.BaseAddon; -import com.dfsek.terra.api.handle.ItemHandle; -import com.dfsek.terra.api.handle.WorldHandle; -import com.dfsek.terra.api.util.generic.Lazy; -import com.dfsek.terra.api.world.biome.PlatformBiome; -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.handle.FabricItemHandle; -import com.dfsek.terra.fabric.handle.FabricWorldHandle; -import com.dfsek.terra.fabric.util.ProtoPlatformBiome; - - -public class PlatformImpl extends AbstractPlatform { - private static final Logger LOGGER = LoggerFactory.getLogger(PlatformImpl.class); - private final ItemHandle itemHandle = new FabricItemHandle(); - private final WorldHandle worldHandle = new FabricWorldHandle(); - private final Lazy dataFolder = Lazy.lazy(() -> new File(FabricLoader.getInstance().getConfigDir().toFile(), "Terra")); - private MinecraftServer server; - - public PlatformImpl() { - load(); - } - - public void setServer(MinecraftServer server) { - this.server = server; - } - - public MinecraftServer getServer() { - return server; - } - - @Override - public boolean reload() { - getTerraConfig().load(this); - getRawConfigRegistry().clear(); - boolean succeed = getRawConfigRegistry().loadAll(this); - - - if(server != null) { - server.reloadResources(server.getDataPackManager().getNames()).exceptionally(throwable -> { - LOGGER.warn("Failed to execute reload", throwable); - return null; - }).join(); - BiomeUtil.registerBiomes(); - server.getWorlds().forEach(world -> { - if(world.getChunkManager().getChunkGenerator() instanceof FabricChunkGeneratorWrapper chunkGeneratorWrapper) { - getConfigRegistry().get(chunkGeneratorWrapper.getPack().getRegistryKey()).ifPresent(pack -> { - chunkGeneratorWrapper.setPack(pack); - LOGGER.info("Replaced pack in chunk generator for world {}", world); - }); - } - }); - } - return succeed; - } - - @Override - protected Iterable platformAddon() { - List addons = new ArrayList<>(); - - addons.add(new FabricAddon(this)); - - String mcVersion = MinecraftVersion.CURRENT.getReleaseTarget(); - try { - addons.add(new EphemeralAddon(Versions.parseVersion(mcVersion), "minecraft")); - } catch(ParseException e) { - try { - addons.add(new EphemeralAddon(Versions.parseVersion(mcVersion + ".0"), "minecraft")); - } catch(ParseException ex) { - LOGGER.warn("Failed to parse Minecraft version", e); - } - } - - FabricLoader.getInstance().getAllMods().forEach(mod -> { - String id = mod.getMetadata().getId(); - if(id.equals("terra") || id.equals("minecraft") || id.equals("java")) return; - try { - Version version = Versions.parseVersion(mod.getMetadata().getVersion().getFriendlyString()); - addons.add(new EphemeralAddon(version, "fabric:" + id)); - } catch(ParseException e) { - LOGGER.warn( - "Mod {}, version {} does not follow semantic versioning specification, Terra addons will be unable to depend on " + - "it.", - id, mod.getMetadata().getVersion().getFriendlyString()); - } - }); - - return addons; - } - - @Override - public @NotNull String platformName() { - return "Fabric"; - } - - @Override - public @NotNull WorldHandle getWorldHandle() { - return worldHandle; - } - - @Override - public @NotNull File getDataFolder() { - return dataFolder.value(); - } - - @Override - public @NotNull ItemHandle getItemHandle() { - return itemHandle; - } - - @Override - public void register(TypeRegistry registry) { - super.register(registry); - registry.registerLoader(PlatformBiome.class, (type, o, loader, depthTracker) -> parseBiome((String) o, depthTracker)) - .registerLoader(Identifier.class, (type, o, loader, depthTracker) -> { - Identifier identifier = Identifier.tryParse((String) o); - if(identifier == null) - throw new LoadException("Invalid identifier: " + o, depthTracker); - return identifier; - }) - .registerLoader(Precipitation.class, (type, o, loader, depthTracker) -> Precipitation.valueOf(((String) o).toUpperCase( - Locale.ROOT))) - .registerLoader(GrassColorModifier.class, (type, o, loader, depthTracker) -> GrassColorModifier.valueOf(((String) o).toUpperCase( - Locale.ROOT))); - } - - - private ProtoPlatformBiome parseBiome(String id, DepthTracker tracker) throws LoadException { - Identifier identifier = Identifier.tryParse(id); - if(BuiltinRegistries.BIOME.get(identifier) == null) throw new LoadException("Invalid Biome ID: " + identifier, tracker); // failure. - return new ProtoPlatformBiome(identifier); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/VanillaBiomeProperties.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/VanillaBiomeProperties.java deleted file mode 100644 index 889c9148f..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/VanillaBiomeProperties.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.dfsek.terra.fabric.config; - -import com.dfsek.tectonic.api.config.template.ConfigTemplate; -import com.dfsek.tectonic.api.config.template.annotations.Default; -import com.dfsek.tectonic.api.config.template.annotations.Value; -import net.minecraft.world.biome.Biome.Precipitation; -import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; - -import com.dfsek.terra.api.properties.Properties; - - -public class VanillaBiomeProperties implements ConfigTemplate, Properties { - @Value("colors.grass") - @Default - private Integer grassColor = null; - - @Value("colors.fog") - @Default - private Integer fogColor = null; - - @Value("colors.water") - @Default - private Integer waterColor = null; - - @Value("colors.water-fog") - @Default - private Integer waterFogColor = null; - - @Value("colors.foliage") - @Default - private Integer foliageColor = null; - - @Value("colors.sky") - @Default - private Integer skyColor = null; - - @Value("colors.modifier") - @Default - private GrassColorModifier modifier = null; - - @Value("climate.precipitation") - @Default - private Precipitation precipitation = null; - - public Integer getFogColor() { - return fogColor; - } - - public Integer getFoliageColor() { - return foliageColor; - } - - public Integer getGrassColor() { - return grassColor; - } - - public Integer getWaterColor() { - return waterColor; - } - - public Integer getWaterFogColor() { - return waterFogColor; - } - - public Integer getSkyColor() { - return skyColor; - } - - public Precipitation getPrecipitation() { - return precipitation; - } - - public GrassColorModifier getModifier() { - return modifier; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java deleted file mode 100644 index d1d2ec9a9..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.dfsek.terra.fabric.util; - -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.world.biome.Biome; -import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.fabric.config.VanillaBiomeProperties; - -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.BuiltinRegistries; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryKey; -import net.minecraft.world.biome.Biome.Builder; -import net.minecraft.world.biome.BiomeEffects; -import net.minecraft.world.biome.GenerationSettings; -import net.minecraft.world.gen.feature.ConfiguredFeature; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; - - -public final class BiomeUtil { - private static final Logger logger = LoggerFactory.getLogger(BiomeUtil.class); - - private static final Map> - TERRA_BIOME_MAP = new HashMap<>(); - - private BiomeUtil() { - - } - - public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) { - return pack.getID() - .toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT); - } - - public static void registerBiomes() { - logger.info("Registering biomes..."); - FabricEntryPoint.getPlatform().getConfigRegistry().forEach(pack -> { // Register all Terra biomes. - pack.getCheckedRegistry(Biome.class) - .forEach((id, biome) -> registerBiome(biome, pack, id)); - }); - registerFlora(BuiltinRegistries.BIOME); - logger.info("Terra biomes registered."); - } - - /** - * Clones a Vanilla biome and injects Terra data to create a Terra-vanilla biome delegate. - * - * @param biome The Terra BiomeBuilder. - * @param pack The ConfigPack this biome belongs to. - */ - private static void registerBiome(Biome biome, ConfigPack pack, - com.dfsek.terra.api.registry.key.RegistryKey id) { - Registry registry = BuiltinRegistries.BIOME; - RegistryKey vanilla = ((ProtoPlatformBiome) biome.getPlatformBiome()).get(registry); - - - if(pack.getContext().get(PreLoadCompatibilityOptions.class).useVanillaBiomes()) { - ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(vanilla); - } else { - net.minecraft.world.biome.Biome minecraftBiome = createBiome(biome, registry.get(vanilla)); - - Identifier identifier = new Identifier("terra", createBiomeID(pack, id)); - - if(registry.containsId(identifier)) { - ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(FabricUtil.getEntry(registry, identifier) - .orElseThrow() - .getKey() - .orElseThrow()); - } else { - ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(BuiltinRegistries.add(registry, - registerKey(identifier).getValue(), - minecraftBiome).getKey().orElseThrow()); - } - - TERRA_BIOME_MAP.computeIfAbsent(vanilla.getValue(), i -> new ArrayList<>()).add(identifier); - } - } - - public static void registerFlora(Registry biomes) { - logger.info("Injecting flora into Terra biomes..."); - TERRA_BIOME_MAP - .forEach((vb, terraBiomes) -> - biomes.getOrEmpty(vb) - .ifPresentOrElse(vanilla -> terraBiomes - .forEach(tb -> biomes.getOrEmpty(tb) - .ifPresentOrElse( - terra -> { - List> flowerFeatures = List.copyOf(vanilla.getGenerationSettings().getFlowerFeatures()); - logger.debug("Injecting flora into biome {} : {}", tb, flowerFeatures); - ((FloraFeatureHolder) terra.getGenerationSettings()).setFloraFeatures(flowerFeatures); - }, - () -> logger.error( - "No such biome: {}", - tb))), - () -> logger.error("No vanilla biome: {}", vb))); - - } - - public static Map> getTerraBiomeMap() { - return Map.copyOf(TERRA_BIOME_MAP); - } - - private static RegistryKey registerKey(Identifier identifier) { - return RegistryKey.of(Registry.BIOME_KEY, identifier); - } - - public static net.minecraft.world.biome.Biome createBiome(Biome biome, net.minecraft.world.biome.Biome vanilla) { - GenerationSettings.Builder generationSettings = new GenerationSettings.Builder(); - - BiomeEffects.Builder effects = new BiomeEffects.Builder(); - - net.minecraft.world.biome.Biome.Builder builder = new Builder(); - - if(biome.getContext().has(VanillaBiomeProperties.class)) { - VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class); - - effects.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor())) - .waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor())) - .fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor())) - .skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor())) - .grassColorModifier( - Objects.requireNonNullElse(vanillaBiomeProperties.getModifier(), vanilla.getEffects().getGrassColorModifier())); - - - if(vanillaBiomeProperties.getGrassColor() == null) { - vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); - } else { - effects.grassColor(vanillaBiomeProperties.getGrassColor()); - } - - if(vanillaBiomeProperties.getFoliageColor() == null) { - vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); - } else { - effects.foliageColor(vanillaBiomeProperties.getFoliageColor()); - } - - builder.precipitation(Objects.requireNonNullElse(vanillaBiomeProperties.getPrecipitation(), vanilla.getPrecipitation())); - - } else { - effects.waterColor(vanilla.getWaterColor()) - .waterFogColor(vanilla.getWaterFogColor()) - .fogColor(vanilla.getFogColor()) - .skyColor(vanilla.getSkyColor()); - vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); - vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); - - builder.precipitation(vanilla.getPrecipitation()); - } - - return builder - .temperature(vanilla.getTemperature()) - .downfall(vanilla.getDownfall()) - .effects(effects.build()) - .spawnSettings(vanilla.getSpawnSettings()) - .generationSettings(generationSettings.build()) - .build(); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricAdapter.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricAdapter.java deleted file mode 100644 index da6c3f6f8..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricAdapter.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Terra is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Terra. If not, see . - */ - -package com.dfsek.terra.fabric.util; - -import net.minecraft.block.enums.BlockHalf; -import net.minecraft.block.enums.WallShape; -import net.minecraft.block.enums.WireConnection; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.HeightLimitView; - -import com.dfsek.terra.api.block.state.properties.enums.Axis; -import com.dfsek.terra.api.block.state.properties.enums.Half; -import com.dfsek.terra.api.block.state.properties.enums.RailShape; -import com.dfsek.terra.api.block.state.properties.enums.RedstoneConnection; -import com.dfsek.terra.api.block.state.properties.enums.WallHeight; -import com.dfsek.terra.api.util.vector.Vector3; -import com.dfsek.terra.api.world.info.WorldProperties; - - -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 Vector3.of(pos.getX(), pos.getY(), pos.getZ()); - } - - public static Direction adapt(com.dfsek.terra.api.block.state.properties.enums.Direction direction) { - return switch(direction) { - case SOUTH -> Direction.SOUTH; - case NORTH -> Direction.NORTH; - case WEST -> Direction.WEST; - case EAST -> Direction.EAST; - case UP -> Direction.UP; - case DOWN -> Direction.DOWN; - }; - } - - public static WorldProperties adapt(HeightLimitView height, long seed) { - return new WorldProperties() { - @Override - public long getSeed() { - return seed; - } - - @Override - public int getMaxHeight() { - return height.getTopY(); - } - - @Override - public int getMinHeight() { - return height.getBottomY(); - } - - @Override - public Object getHandle() { - return height; - } - }; - } - - public static com.dfsek.terra.api.block.state.properties.enums.Direction adapt(Direction direction) { - return switch(direction) { - case SOUTH -> com.dfsek.terra.api.block.state.properties.enums.Direction.SOUTH; - case NORTH -> com.dfsek.terra.api.block.state.properties.enums.Direction.NORTH; - case WEST -> com.dfsek.terra.api.block.state.properties.enums.Direction.WEST; - case EAST -> com.dfsek.terra.api.block.state.properties.enums.Direction.EAST; - case UP -> com.dfsek.terra.api.block.state.properties.enums.Direction.UP; - case DOWN -> com.dfsek.terra.api.block.state.properties.enums.Direction.DOWN; - }; - } - - public static WallHeight adapt(WallShape shape) { - return switch(shape) { - case LOW -> WallHeight.LOW; - case NONE -> WallHeight.NONE; - case TALL -> WallHeight.TALL; - }; - } - - public static WallShape adapt(WallHeight shape) { - return switch(shape) { - case LOW -> WallShape.LOW; - case NONE -> WallShape.NONE; - case TALL -> WallShape.TALL; - }; - } - - public static RedstoneConnection adapt(WireConnection connection) { - return switch(connection) { - case NONE -> RedstoneConnection.NONE; - case UP -> RedstoneConnection.UP; - case SIDE -> RedstoneConnection.SIDE; - }; - } - - public static WireConnection adapt(RedstoneConnection connection) { - return switch(connection) { - case NONE -> WireConnection.NONE; - case UP -> WireConnection.UP; - case SIDE -> WireConnection.SIDE; - }; - } - - - public static Half adapt(BlockHalf half) { - return switch(half) { - case BOTTOM -> Half.BOTTOM; - case TOP -> Half.TOP; - }; - } - - public static BlockHalf adapt(Half half) { - return switch(half) { - case TOP -> BlockHalf.TOP; - case BOTTOM -> BlockHalf.BOTTOM; - default -> throw new IllegalStateException(); - }; - } - - public static RailShape adapt(net.minecraft.block.enums.RailShape railShape) { - return switch(railShape) { - case EAST_WEST -> RailShape.EAST_WEST; - case NORTH_EAST -> RailShape.NORTH_EAST; - case NORTH_WEST -> RailShape.NORTH_WEST; - case SOUTH_EAST -> RailShape.SOUTH_EAST; - case SOUTH_WEST -> RailShape.SOUTH_WEST; - case NORTH_SOUTH -> RailShape.NORTH_SOUTH; - case ASCENDING_EAST -> RailShape.ASCENDING_EAST; - case ASCENDING_NORTH -> RailShape.ASCENDING_NORTH; - case ASCENDING_SOUTH -> RailShape.ASCENDING_SOUTH; - case ASCENDING_WEST -> RailShape.ASCENDING_WEST; - }; - } - - public static net.minecraft.block.enums.RailShape adapt(RailShape railShape) { - return switch(railShape) { - case EAST_WEST -> net.minecraft.block.enums.RailShape.EAST_WEST; - case NORTH_EAST -> net.minecraft.block.enums.RailShape.NORTH_EAST; - case NORTH_WEST -> net.minecraft.block.enums.RailShape.NORTH_WEST; - case SOUTH_EAST -> net.minecraft.block.enums.RailShape.SOUTH_EAST; - case SOUTH_WEST -> net.minecraft.block.enums.RailShape.SOUTH_WEST; - case NORTH_SOUTH -> net.minecraft.block.enums.RailShape.NORTH_SOUTH; - case ASCENDING_EAST -> net.minecraft.block.enums.RailShape.ASCENDING_EAST; - case ASCENDING_NORTH -> net.minecraft.block.enums.RailShape.ASCENDING_NORTH; - case ASCENDING_SOUTH -> net.minecraft.block.enums.RailShape.ASCENDING_SOUTH; - case ASCENDING_WEST -> net.minecraft.block.enums.RailShape.ASCENDING_WEST; - }; - } - - - public static Axis adapt(Direction.Axis axis) { - return switch(axis) { - case X -> Axis.X; - case Y -> Axis.Y; - case Z -> Axis.Z; - }; - } - - public static Direction.Axis adapt(Axis axis) { - return switch(axis) { - case Z -> Direction.Axis.Z; - case Y -> Direction.Axis.Y; - case X -> Direction.Axis.X; - }; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java deleted file mode 100644 index 7e00aa900..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Terra is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Terra. If not, see . - */ - -package com.dfsek.terra.fabric.util; - -import net.minecraft.block.entity.LootableContainerBlockEntity; -import net.minecraft.block.entity.MobSpawnerBlockEntity; -import net.minecraft.block.entity.SignBlockEntity; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryEntry; -import net.minecraft.world.WorldAccess; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Optional; - -import com.dfsek.terra.api.block.entity.BlockEntity; -import com.dfsek.terra.api.block.entity.Container; -import com.dfsek.terra.api.block.entity.MobSpawner; -import com.dfsek.terra.api.block.entity.Sign; - - -public final class FabricUtil { - private FabricUtil() { - - } - - public static BlockEntity createState(WorldAccess worldAccess, BlockPos pos) { - net.minecraft.block.entity.BlockEntity entity = worldAccess.getBlockEntity(pos); - 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 Optional> getEntry(Registry registry, Identifier identifier) { - return registry.getOrEmpty(identifier) - .flatMap(registry::getKey) - .map(registry::getOrCreateEntry); - } -} diff --git a/platforms/fabric/src/main/resources/fabric.mod.json b/platforms/fabric/src/main/resources/fabric.mod.json index dcc277954..e71bcfeac 100644 --- a/platforms/fabric/src/main/resources/fabric.mod.json +++ b/platforms/fabric/src/main/resources/fabric.mod.json @@ -21,12 +21,13 @@ ] }, "mixins": [ - "terra.mixins.json" + "terra.fabric.mixins.json", + "terra.lifecycle.mixins.json", + "terra.common.mixins.json" ], "depends": { "fabricloader": ">=0.14.2", "java": ">=17", "minecraft": "1.19.x" - }, - "accessWidener": "terra.accesswidener" + } } \ No newline at end of file diff --git a/platforms/fabric/src/main/resources/terra.accesswidener b/platforms/fabric/src/main/resources/terra.accesswidener deleted file mode 100644 index 3fde5170f..000000000 --- a/platforms/fabric/src/main/resources/terra.accesswidener +++ /dev/null @@ -1 +0,0 @@ -accessWidener v1 named diff --git a/platforms/fabric/src/main/resources/terra.fabric.mixins.json b/platforms/fabric/src/main/resources/terra.fabric.mixins.json new file mode 100644 index 000000000..f97889f6d --- /dev/null +++ b/platforms/fabric/src/main/resources/terra.fabric.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.dfsek.terra.fabric.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/platforms/fabric/src/main/resources/terra.mixins.json b/platforms/fabric/src/main/resources/terra.mixins.json deleted file mode 100644 index 9c4e278bc..000000000 --- a/platforms/fabric/src/main/resources/terra.mixins.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "com.dfsek.terra.fabric.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "access.MobSpawnerLogicAccessor", - "access.StateAccessor", - "access.StructureAccessorAccessor", - "compat.GenerationSettingsFloraFeaturesMixin", - "implementations.BiomeMixin", - "implementations.HandleImplementationMixin", - "implementations.block.BlockMixin", - "implementations.block.entity.BlockEntityMixin", - "implementations.block.entity.LootableContainerBlockEntityMixin", - "implementations.block.entity.MobSpawnerBlockEntityMixin", - "implementations.block.entity.SignBlockEntityMixin", - "implementations.block.state.BlockStateMixin", - "implementations.block.state.PropertyMixin", - "implementations.chunk.ChunkRegionMixin", - "implementations.chunk.WorldChunkMixin", - "implementations.chunk.data.ProtoChunkMixin", - "implementations.entity.EntityMixin", - "implementations.entity.EntityTypeMixin", - "implementations.entity.PlayerEntityMixin", - "implementations.entity.ServerCommandSourceMixin", - "implementations.inventory.LockableContainerBlockEntityMixin", - "implementations.inventory.item.ItemMixin", - "implementations.inventory.item.ItemStackMixin", - "implementations.inventory.meta.EnchantmentMixin", - "implementations.inventory.meta.ItemStackDamageableMixin", - "implementations.inventory.meta.ItemStackMetaMixin", - "implementations.world.ChunkRegionMixin", - "implementations.world.ServerWorldMixin", - "lifecycle.DataPackContentsMixin", - "lifecycle.MinecraftServerMixin", - "lifecycle.NoiseConfigMixin", - "lifecycle.RegistryMixin" - ], - "client": [ - "lifecycle.client.MinecraftClientMixin" - ], - "server": [ - "lifecycle.server.ServerMainMixin" - ], - "injectors": { - "defaultRequire": 1 - }, - "refmap": "terra-refmap.json" -} \ No newline at end of file diff --git a/platforms/forge/build.gradle.kts b/platforms/forge/build.gradle.kts new file mode 100644 index 000000000..7cfddab1d --- /dev/null +++ b/platforms/forge/build.gradle.kts @@ -0,0 +1,78 @@ +plugins { + id("dev.architectury.loom") version Versions.Mod.architecuryLoom + id("architectury-plugin") version Versions.Mod.architecturyPlugin + id("io.github.juuxel.loom-quiltflower") version Versions.Mod.loomQuiltflower +} + +architectury { + platformSetupLoomIde() + loader("forge") +} + +dependencies { + annotationProcessor("net.fabricmc:sponge-mixin:${Versions.Mod.mixin}") + annotationProcessor("dev.architectury:architectury-loom:${Versions.Mod.architecuryLoom}") + + shadedApi(project(":common:implementation:base")) + "forgeRuntimeLibrary"(project(":common:implementation:base")) + + implementation(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } + "developmentForge"(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } + shaded(project(path = ":platforms:mixin-common", configuration = "transformProductionForge")) { isTransitive = false } + + forge(group = "net.minecraftforge", name = "forge", version = Versions.Forge.forge) + + minecraft("com.mojang:minecraft:${Versions.Mod.minecraft}") + mappings("net.fabricmc:yarn:${Versions.Mod.yarn}:v2") + + //forge is not ok. + compileOnly("org.burningwave:core:${Versions.Forge.burningwave}") + "forgeRuntimeLibrary"("org.burningwave:core:${Versions.Forge.burningwave}") +} + +loom { + accessWidenerPath.set(project(":platforms:mixin-common").file("src/main/resources/terra.accesswidener")) + + mixin { + defaultRefmapName.set("terra.forge.refmap.json") + } + + launches { + named("client") { + property("fabric.log.level", "debug") + property("mixin.env.disableRefMap", "true") + } + named("server") { + property("fabric.log.level", "debug") + property("mixin.env.disableRefMap", "true") + } + } + + forge { + convertAccessWideners.set(true) + mixinConfig("terra.common.mixins.json") + mixinConfig("terra.forge.mixins.json") + extraAccessWideners.add(loom.accessWidenerPath.get().asFile.name) + } +} + + +addonDir(project.file("./run/config/Terra/addons"), tasks.named("configureLaunch").get()) + +tasks { + jar { + manifest { + attributes( + mapOf( + "Implementation-Title" to rootProject.name, + "Implementation-Version" to project.version, + ) + ) + } + } + + remapJar { + inputFile.set(shadowJar.get().archiveFile) + archiveFileName.set("${rootProject.name.capitalize()}-forge-${project.version}.jar") + } +} \ No newline at end of file diff --git a/platforms/forge/gradle.properties b/platforms/forge/gradle.properties new file mode 100644 index 000000000..82425854e --- /dev/null +++ b/platforms/forge/gradle.properties @@ -0,0 +1 @@ +loom.platform=forge diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java new file mode 100644 index 000000000..07f4dafc9 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java @@ -0,0 +1,167 @@ +package com.dfsek.terra.forge; + +import net.minecraftforge.fml.loading.FMLLoader; +import org.burningwave.core.classes.Classes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileVisitOption; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicReference; +import java.util.jar.JarFile; +import java.util.stream.Stream; + +import com.dfsek.terra.AbstractPlatform; +import com.dfsek.terra.api.addon.bootstrap.BootstrapAddonClassLoader; + + +/** + * Forge is really wacky and screws with class resolution in the addon loader. Loading every single Terra class *manually* on startup + * fixes it. If you know of a better way to fix this, PLEASE let us know. + */ +public final class AwfulForgeHacks { + private static final Logger LOGGER = LoggerFactory.getLogger(AwfulForgeHacks.class); + + /** + * Forge tampers with code source to make the *normal* way of getting the current JAR file useless, so this awful hack is + * needed. + * + * + * Class.class.getProtectionDomain() + * .getCodeSource() + * .getLocation() + * .toURI() + * .getPath() + * + */ + public static JarFile getTerraJar() throws IOException { + LOGGER.info("Scanning for Terra JAR..."); + return Files.walk(Path.of(System.getProperty("user.dir"), "mods"), 1, FileVisitOption.FOLLOW_LINKS) + .filter(it -> it.getFileName().toString().endsWith(".jar")) + .peek(path -> LOGGER.info("Found mod: {}", path)) + .map(Path::toFile) + .flatMap(path -> { + try { + return Stream.of(new JarFile(path)); + } catch(IOException e) { + LOGGER.error("Malformed mod JAR: {}: {}", path, e); + return Stream.of(); + } + }) + .filter(jar -> jar + .stream() + .anyMatch(entry -> entry + .getName() + .equals(ForgeEntryPoint.class.getName().replace('.', '/') + ".class"))) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Could not find Terra JAR")); + } + + public static void loadAllTerraClasses() { + if(FMLLoader.isProduction()) { + try(JarFile jar = getTerraJar()) { + jar.stream() + .forEach(jarEntry -> { + if(jarEntry.getName().startsWith("com/dfsek/terra/forge/mixin") + || jarEntry.getName().startsWith("com/dfsek/terra/mod/mixin")) { + return; + } + if(jarEntry.getName().endsWith(".class")) { + String name = jarEntry.getName().replace('/', '.'); + name = name.substring(0, name.length() - 6); + try { + Class.forName(name); + } catch(ClassNotFoundException | NoClassDefFoundError e) { + LOGGER.warn("Failed to load class {}: {}", name, e); + } + } + }); + } catch(IOException e) { + throw new IllegalStateException("Could not load all Terra classes", e); + } + } else { + // Forgive me for what I'm about to do... + LOGGER.warn( + "I felt a great disturbance in the JVM, as if millions of class not found exceptions suddenly cried out in terror and" + + " were suddenly silenced."); + ArrayList pathsToLoad = new ArrayList<>(); + + Path terraRoot = Path.of(System.getProperty("user.dir")).getParent().getParent().getParent(); + Path commonRoot = terraRoot.resolve("common"); + Path implementationRoot = commonRoot.resolve("implementation"); + + pathsToLoad.add(commonRoot.resolve("api")); + pathsToLoad.add(implementationRoot.resolve("base")); + pathsToLoad.add(implementationRoot.resolve("bootstrap-addon-loader")); + for(Path path : pathsToLoad) { + try { + Path target = path.resolve("build").resolve("classes").resolve("java").resolve("main"); + + BootstrapAddonClassLoader cl = new BootstrapAddonClassLoader(new URL[]{ path.toUri().toURL() }); + + Classes.Loaders omegaCL = Classes.Loaders.create(); + Files.walk(target, Integer.MAX_VALUE, FileVisitOption.FOLLOW_LINKS) + .filter(it -> it.getFileName().toString().endsWith(".class")) + .map(Path::toFile) + .forEach(it -> { + String name = it.getAbsolutePath().replace(target + "/", "").replace('\\', '.').replace('/', '.'); + name = name.substring(0, name.length() - 6); + LOGGER.info("Loading class {}", name); + try { + Class.forName(name); + } catch(ClassNotFoundException e) { + try { + String pathToJar = cl.loadClass(name) + .getProtectionDomain() + .getCodeSource() + .getLocation() + .toURI() + .getPath(); + + cl.addURL(new URL("jar:file:" + pathToJar + "!/")); + Class newClassLoad = Class.forName(name, true, cl); + omegaCL.loadOrDefine(newClassLoad, AbstractPlatform.class.getClassLoader()); + } catch(ClassNotFoundException | URISyntaxException | IOException ex) { + throw new RuntimeException(ex); + } + + } + }); + } catch(IOException e) { + throw new IllegalStateException("Could not load all Terra classes", e); + } + } + } + } + + public enum RegistryStep { + BLOCK, + BIOME, + WORLD_TYPE, + DONE + } + + + public static class RegistrySanityCheck { + private final AtomicReference step = new AtomicReference<>(RegistryStep.BLOCK); + + public void progress(RegistryStep expected, Runnable action) { + step.getAndUpdate(s -> { + if(s != expected) { + LOGGER.error("Registry sanity check failed, expected to find {}, found {}", expected, step); + } + action.run(); + RegistryStep[] registrySteps = RegistryStep.values(); + if(s.ordinal() < registrySteps.length - 1) { + return registrySteps[s.ordinal() + 1]; + } + return s; + }); + } + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java new file mode 100644 index 000000000..e742610cf --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java @@ -0,0 +1,17 @@ +package com.dfsek.terra.forge; + +import com.dfsek.terra.mod.MinecraftAddon; +import com.dfsek.terra.mod.ModPlatform; + + +public class ForgeAddon extends MinecraftAddon { + + public ForgeAddon(ModPlatform modPlatform) { + super(modPlatform); + } + + @Override + public String getID() { + return "terra-forge"; + } +} \ No newline at end of file diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java new file mode 100644 index 000000000..b342e5a11 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -0,0 +1,82 @@ +/* + * This file is part of Terra. + * + * Terra is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Terra is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Terra. If not, see . + */ + +package com.dfsek.terra.forge; + +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.ForgeRegistries.Keys; +import net.minecraftforge.registries.RegisterEvent; +import net.minecraftforge.registries.RegisterEvent.RegisterHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; +import com.dfsek.terra.forge.AwfulForgeHacks.RegistrySanityCheck; +import com.dfsek.terra.forge.AwfulForgeHacks.RegistryStep; +import com.dfsek.terra.forge.util.BiomeUtil; +import com.dfsek.terra.mod.data.Codecs; + + +@Mod("terra") +@EventBusSubscriber(bus = Bus.MOD) +public class ForgeEntryPoint { + public static final String MODID = "terra"; + private static final Logger logger = LoggerFactory.getLogger(ForgeEntryPoint.class); + private static final ForgePlatform TERRA_PLUGIN; + static { + AwfulForgeHacks.loadAllTerraClasses(); + TERRA_PLUGIN = new ForgePlatform(); + } + private final RegistrySanityCheck sanityCheck = new RegistrySanityCheck(); + + public ForgeEntryPoint() { + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + modEventBus.register(this); + } + + public static ForgePlatform getPlatform() { + return TERRA_PLUGIN; + } + + public static void initialize(RegisterHelper helper) { + getPlatform().getEventManager().callEvent( + new PlatformInitializationEvent()); + BiomeUtil.registerBiomes(helper); + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void registerBiomes(RegisterEvent event) { + event.register(Keys.BLOCKS, helper -> sanityCheck.progress(RegistryStep.BLOCK, () -> logger.debug("Block registration detected."))); + event.register(Keys.BIOMES, helper -> sanityCheck.progress(RegistryStep.BIOME, () -> initialize(helper))); + event.register(Registry.WORLD_PRESET_KEY, + helper -> sanityCheck.progress(RegistryStep.WORLD_TYPE, () -> TERRA_PLUGIN.registerWorldTypes(helper::register))); + + + event.register(Registry.CHUNK_GENERATOR_KEY, + helper -> helper.register(new Identifier("terra:terra"), Codecs.MINECRAFT_CHUNK_GENERATOR_WRAPPER)); + event.register(Registry.BIOME_SOURCE_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE)); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgePlatform.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgePlatform.java new file mode 100644 index 000000000..2d8b51c9a --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgePlatform.java @@ -0,0 +1,125 @@ +/* + * This file is part of Terra. + * + * Terra is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Terra is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Terra. If not, see . + */ + +package com.dfsek.terra.forge; + +import ca.solostudios.strata.Versions; +import ca.solostudios.strata.parser.tokenizer.ParseException; +import ca.solostudios.strata.version.Version; +import net.minecraft.MinecraftVersion; +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.fml.loading.FMLLoader; +import net.minecraftforge.server.ServerLifecycleHooks; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import com.dfsek.terra.addon.EphemeralAddon; +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.api.util.generic.Lazy; +import com.dfsek.terra.mod.CommonPlatform; +import com.dfsek.terra.mod.ModPlatform; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; + + +public class ForgePlatform extends ModPlatform { + private static final Logger LOGGER = LoggerFactory.getLogger(ForgePlatform.class); + private final Lazy dataFolder = Lazy.lazy(() -> new File("./config/Terra")); + + public ForgePlatform() { + CommonPlatform.initialize(this); + load(); + } + + @Override + public MinecraftServer getServer() { + return ServerLifecycleHooks.getCurrentServer(); + } + + @Override + public boolean reload() { + getTerraConfig().load(this); + getRawConfigRegistry().clear(); + boolean succeed = getRawConfigRegistry().loadAll(this); + + MinecraftServer server = getServer(); + + if(server != null) { + server.reloadResources(server.getDataPackManager().getNames()).exceptionally(throwable -> { + LOGGER.warn("Failed to execute reload", throwable); + return null; + }).join(); + //BiomeUtil.registerBiomes(); + server.getWorlds().forEach(world -> { + if(world.getChunkManager().getChunkGenerator() instanceof MinecraftChunkGeneratorWrapper chunkGeneratorWrapper) { + getConfigRegistry().get(chunkGeneratorWrapper.getPack().getRegistryKey()).ifPresent(pack -> { + chunkGeneratorWrapper.setPack(pack); + LOGGER.info("Replaced pack in chunk generator for world {}", world); + }); + } + }); + } + return succeed; + } + + @Override + protected Iterable platformAddon() { + List addons = new ArrayList<>(); + + super.platformAddon().forEach(addons::add); + + String mcVersion = MinecraftVersion.CURRENT.getReleaseTarget(); + try { + addons.add(new EphemeralAddon(Versions.parseVersion(mcVersion), "minecraft")); + } catch(ParseException e) { + try { + addons.add(new EphemeralAddon(Versions.parseVersion(mcVersion + ".0"), "minecraft")); + } catch(ParseException ex) { + LOGGER.warn("Failed to parse Minecraft version", e); + } + } + + FMLLoader.getLoadingModList().getMods().forEach(mod -> { + String id = mod.getModId(); + if(id.equals("terra") || id.equals("minecraft") || id.equals("java")) return; + Version version = Versions.getVersion(mod.getVersion().getMajorVersion(), mod.getVersion().getMinorVersion(), + mod.getVersion().getIncrementalVersion()); + addons.add(new EphemeralAddon(version, "forge:" + id)); + }); + + return addons; + } + + @Override + public @NotNull String platformName() { + return "Forge"; + } + + @Override + public @NotNull File getDataFolder() { + return dataFolder.value(); + } + + @Override + public BaseAddon getPlatformAddon() { + return new ForgeAddon(this); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java new file mode 100644 index 000000000..1bdffca2e --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java @@ -0,0 +1,44 @@ +package com.dfsek.terra.forge.mixin.lifecycle; + +import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; +import net.minecraft.world.biome.source.util.MultiNoiseUtil.NoiseHypercube; +import net.minecraft.world.gen.densityfunction.DensityFunction; +import net.minecraft.world.gen.noise.NoiseConfig; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.List; + +import com.dfsek.terra.mod.util.SeedHack; + + +/** + * Hack to map noise sampler to seeds + */ +@Mixin(NoiseConfig.class) +public class NoiseConfigMixin { + @Shadow + @Final + private long legacyWorldSeed; + + @Redirect(method = "(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", + at = @At(value = "NEW", + target = "(Lnet/minecraft/world/gen/densityfunction/DensityFunction;" + + "Lnet/minecraft/world/gen/densityfunction/DensityFunction;" + + "Lnet/minecraft/world/gen/densityfunction/DensityFunction;" + + "Lnet/minecraft/world/gen/densityfunction/DensityFunction;" + + "Lnet/minecraft/world/gen/densityfunction/DensityFunction;" + + "Lnet/minecraft/world/gen/densityfunction/DensityFunction;Ljava/util/List;)" + + "Lnet/minecraft/world/biome/source/util/MultiNoiseUtil$MultiNoiseSampler;")) + private MultiNoiseSampler t(DensityFunction densityFunction, DensityFunction densityFunction2, DensityFunction densityFunction3, + DensityFunction densityFunction4, DensityFunction densityFunction5, DensityFunction densityFunction6, + List list) { + MultiNoiseSampler sampler = new MultiNoiseSampler(densityFunction, densityFunction2, densityFunction3, densityFunction4, + densityFunction5, densityFunction6, list); + SeedHack.register(sampler, legacyWorldSeed); + return sampler; + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/package-info.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/package-info.java similarity index 94% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/package-info.java rename to platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/package-info.java index ad90c31eb..eba8981f7 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/package-info.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/package-info.java @@ -19,4 +19,4 @@ * Mixins that inject behavior into the client/server lifecycle. */ -package com.dfsek.terra.fabric.mixin.lifecycle; \ No newline at end of file +package com.dfsek.terra.forge.mixin.lifecycle; \ No newline at end of file diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java new file mode 100644 index 000000000..177a63f8e --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java @@ -0,0 +1,92 @@ +package com.dfsek.terra.forge.util; + +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.BuiltinRegistries; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.village.VillagerType; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegisterEvent.RegisterHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Objects; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.forge.ForgeEntryPoint; +import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.mod.config.ProtoPlatformBiome; +import com.dfsek.terra.mod.config.VanillaBiomeProperties; +import com.dfsek.terra.mod.mixin.access.VillagerTypeAccessor; +import com.dfsek.terra.mod.util.MinecraftUtil; + + +public final class BiomeUtil { + private static final Logger logger = LoggerFactory.getLogger(BiomeUtil.class); + + + private BiomeUtil() { + + } + + + public static void registerBiomes(RegisterHelper helper) { + logger.info("Registering biomes..."); + ForgeEntryPoint.getPlatform().getConfigRegistry().forEach(pack -> { // Register all Terra biomes. + pack.getCheckedRegistry(Biome.class) + .forEach((id, biome) -> registerBiome(biome, pack, id, helper)); + }); + MinecraftUtil.registerFlora(BuiltinRegistries.BIOME); + logger.info("Terra biomes registered."); + } + + /** + * Clones a Vanilla biome and injects Terra data to create a Terra-vanilla biome delegate. + * + * @param biome The Terra BiomeBuilder. + * @param pack The ConfigPack this biome belongs to. + */ + private static void registerBiome(Biome biome, ConfigPack pack, + com.dfsek.terra.api.registry.key.RegistryKey id, + RegisterHelper helper) { + RegistryKey vanilla = ((ProtoPlatformBiome) biome.getPlatformBiome()).get(BuiltinRegistries.BIOME); + + + if(pack.getContext().get(PreLoadCompatibilityOptions.class).useVanillaBiomes()) { + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(vanilla); + } else { + VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class); + + net.minecraft.world.biome.Biome minecraftBiome = MinecraftUtil.createBiome(biome, + ForgeRegistries.BIOMES.getDelegateOrThrow(vanilla) + .value(), + vanillaBiomeProperties); + + Identifier identifier = new Identifier("terra", MinecraftUtil.createBiomeID(pack, id)); + + if(ForgeRegistries.BIOMES.containsKey(identifier)) { + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(ForgeRegistries.BIOMES.getHolder(identifier) + .orElseThrow() + .getKey() + .orElseThrow()); + } else { + helper.register(MinecraftUtil.registerKey(identifier).getValue(), minecraftBiome); + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(ForgeRegistries.BIOMES.getHolder(identifier) + .orElseThrow() + .getKey() + .orElseThrow()); + } + + Map villagerMap = VillagerTypeAccessor.getBiomeTypeToIdMap(); + + villagerMap.put(RegistryKey.of(Registry.BIOME_KEY, identifier), + Objects.requireNonNullElse(vanillaBiomeProperties.getVillagerType(), + villagerMap.getOrDefault(vanilla, VillagerType.PLAINS))); + + MinecraftUtil.TERRA_BIOME_MAP.computeIfAbsent(vanilla.getValue(), i -> new ArrayList<>()).add(identifier); + } + } +} diff --git a/platforms/forge/src/main/resources/META-INF/mods.toml b/platforms/forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 000000000..ff9e92ada --- /dev/null +++ b/platforms/forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,24 @@ +modLoader = "javafml" +loaderVersion = "[41,)" +license = "GNU General Public License, v3.0" +issueTrackerURL = "https://github.com/PolyhedralDev/Terra/issues" + +[[mods]] +modId = "terra" +version = "@VERSION@" +displayName = "Terra" +description = "@DESCRIPTION@" + +[[dependencies.terra]] +modId = "forge" +mandatory = true +versionRange = "[41,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.terra]] +modId = "minecraft" +mandatory = true +versionRange = "[1.19,)" +ordering = "NONE" +side = "BOTH" \ No newline at end of file diff --git a/platforms/forge/src/main/resources/pack.mcmeta b/platforms/forge/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..5e44f2fa1 --- /dev/null +++ b/platforms/forge/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "Terra Resources", + "pack_format": 9 + } +} diff --git a/platforms/forge/src/main/resources/terra.forge.mixins.json b/platforms/forge/src/main/resources/terra.forge.mixins.json new file mode 100644 index 000000000..25c1c470e --- /dev/null +++ b/platforms/forge/src/main/resources/terra.forge.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.dfsek.terra.forge.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "lifecycle.NoiseConfigMixin" + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/platforms/mixin-common/README.md b/platforms/mixin-common/README.md new file mode 100644 index 000000000..0c411a1bf --- /dev/null +++ b/platforms/mixin-common/README.md @@ -0,0 +1,4 @@ +# mixin-common + +This project contains mixins shared between Forge, Fabric and Quilt, as +well as glue code. \ No newline at end of file diff --git a/platforms/mixin-common/build.gradle.kts b/platforms/mixin-common/build.gradle.kts new file mode 100644 index 000000000..b293f3cfa --- /dev/null +++ b/platforms/mixin-common/build.gradle.kts @@ -0,0 +1,30 @@ +plugins { + id("dev.architectury.loom") version Versions.Mod.architecuryLoom + id("architectury-plugin") version Versions.Mod.architecturyPlugin + id("io.github.juuxel.loom-quiltflower") version Versions.Mod.loomQuiltflower +} + +loom { + accessWidenerPath.set(file("src/main/resources/terra.accesswidener")) + + mixin { + defaultRefmapName.set("terra.common.refmap.json") + } +} + +dependencies { + shadedApi(project(":common:implementation:base")) + + compileOnly("net.fabricmc:sponge-mixin:${Versions.Mod.mixin}") + annotationProcessor("net.fabricmc:sponge-mixin:${Versions.Mod.mixin}") + annotationProcessor("dev.architectury:architectury-loom:${Versions.Mod.architecuryLoom}") + + minecraft("com.mojang:minecraft:${Versions.Mod.minecraft}") + mappings("net.fabricmc:yarn:${Versions.Mod.yarn}:v2") +} + +architectury { + common("fabric", "forge", "quilt") + minecraft = Versions.Mod.minecraft +} + diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java new file mode 100644 index 000000000..97534c8b1 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java @@ -0,0 +1,24 @@ +package com.dfsek.terra.mod; + +import java.util.concurrent.atomic.AtomicReference; + + +public final class CommonPlatform { + private static final AtomicReference platform = new AtomicReference<>(); + + public static ModPlatform get() { + ModPlatform modPlatform = platform.get(); + + if(modPlatform == null) { + throw new IllegalStateException("Platform is not yet initialised!"); + } + + return modPlatform; + } + + public static void initialize(ModPlatform modPlatform) { + if(!platform.compareAndSet(null, modPlatform)) { + throw new IllegalStateException("Platform has already been initialized to " + platform.get()); + } + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java new file mode 100644 index 000000000..fa1214389 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java @@ -0,0 +1,75 @@ +/* + * This file is part of Terra. + * + * Terra is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Terra is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Terra. If not, see . + */ + +package com.dfsek.terra.mod; + +import ca.solostudios.strata.Versions; +import ca.solostudios.strata.version.Version; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; +import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; +import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; +import com.dfsek.terra.api.event.functional.FunctionalEventHandler; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.mod.config.PostLoadCompatibilityOptions; +import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.mod.config.VanillaBiomeProperties; + + +public abstract class MinecraftAddon implements BaseAddon { + private static final Version VERSION = Versions.getVersion(1, 0, 0); + private static final Logger logger = LoggerFactory.getLogger(MinecraftAddon.class); + private final ModPlatform modPlatform; + + public MinecraftAddon(ModPlatform modPlatform) { + this.modPlatform = modPlatform; + } + + @Override + public void initialize() { + modPlatform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigPackPreLoadEvent.class) + .then(event -> event.getPack().getContext().put(event.loadTemplate(new PreLoadCompatibilityOptions()))) + .global(); + + modPlatform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigPackPostLoadEvent.class) + .then(event -> event.getPack().getContext().put(event.loadTemplate(new PostLoadCompatibilityOptions()))) + .priority(100) + .global(); + + modPlatform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigurationLoadEvent.class) + .then(event -> { + if(event.is(Biome.class)) { + event.getLoadedObject(Biome.class).getContext().put(event.load(new VanillaBiomeProperties())); + } + }) + .global(); + } + + @Override + public Version getVersion() { + return VERSION; + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java new file mode 100644 index 000000000..4a6efa188 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java @@ -0,0 +1,117 @@ +package com.dfsek.terra.mod; + +import com.dfsek.tectonic.api.TypeRegistry; +import com.dfsek.tectonic.api.depth.DepthTracker; +import com.dfsek.tectonic.api.exception.LoadException; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.SpawnGroup; +import net.minecraft.server.MinecraftServer; +import net.minecraft.sound.BiomeAdditionsSound; +import net.minecraft.sound.BiomeMoodSound; +import net.minecraft.sound.MusicSound; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.BuiltinRegistries; +import net.minecraft.village.VillagerType; +import net.minecraft.world.biome.Biome.Precipitation; +import net.minecraft.world.biome.Biome.TemperatureModifier; +import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; +import net.minecraft.world.biome.BiomeParticleConfig; +import net.minecraft.world.biome.SpawnSettings; +import net.minecraft.world.biome.SpawnSettings.SpawnEntry; +import net.minecraft.world.gen.WorldPreset; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Locale; +import java.util.function.BiConsumer; + +import com.dfsek.terra.AbstractPlatform; +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.api.handle.ItemHandle; +import com.dfsek.terra.api.handle.WorldHandle; +import com.dfsek.terra.api.world.biome.PlatformBiome; +import com.dfsek.terra.mod.config.BiomeAdditionsSoundTemplate; +import com.dfsek.terra.mod.config.BiomeMoodSoundTemplate; +import com.dfsek.terra.mod.config.BiomeParticleConfigTemplate; +import com.dfsek.terra.mod.config.EntityTypeTemplate; +import com.dfsek.terra.mod.config.MusicSoundTemplate; +import com.dfsek.terra.mod.config.ProtoPlatformBiome; +import com.dfsek.terra.mod.config.SoundEventTemplate; +import com.dfsek.terra.mod.config.SpawnCostConfig; +import com.dfsek.terra.mod.config.SpawnEntryTemplate; +import com.dfsek.terra.mod.config.SpawnGroupTemplate; +import com.dfsek.terra.mod.config.SpawnSettingsTemplate; +import com.dfsek.terra.mod.config.SpawnTypeConfig; +import com.dfsek.terra.mod.config.VillagerTypeTemplate; +import com.dfsek.terra.mod.handle.MinecraftItemHandle; +import com.dfsek.terra.mod.handle.MinecraftWorldHandle; +import com.dfsek.terra.mod.util.PresetUtil; + + +public abstract class ModPlatform extends AbstractPlatform { + private final ItemHandle itemHandle = new MinecraftItemHandle(); + private final WorldHandle worldHandle = new MinecraftWorldHandle(); + + public abstract MinecraftServer getServer(); + + public void registerWorldTypes(BiConsumer registerFunction) { + getRawConfigRegistry() + .forEach(pack -> PresetUtil.createDefault(pack).apply(registerFunction)); + } + + @Override + public void register(TypeRegistry registry) { + super.register(registry); + registry.registerLoader(PlatformBiome.class, (type, o, loader, depthTracker) -> parseBiome((String) o, depthTracker)) + .registerLoader(Identifier.class, (type, o, loader, depthTracker) -> { + Identifier identifier = Identifier.tryParse((String) o); + if(identifier == null) + throw new LoadException("Invalid identifier: " + o, depthTracker); + return identifier; + }) + .registerLoader(Precipitation.class, (type, o, loader, depthTracker) -> Precipitation.valueOf(((String) o).toUpperCase( + Locale.ROOT))) + .registerLoader(GrassColorModifier.class, + (type, o, loader, depthTracker) -> GrassColorModifier.valueOf(((String) o).toUpperCase( + Locale.ROOT))) + .registerLoader(GrassColorModifier.class, + (type, o, loader, depthTracker) -> TemperatureModifier.valueOf(((String) o).toUpperCase( + Locale.ROOT))) + .registerLoader(BiomeParticleConfig.class, BiomeParticleConfigTemplate::new) + .registerLoader(SoundEvent.class, SoundEventTemplate::new) + .registerLoader(BiomeMoodSound.class, BiomeMoodSoundTemplate::new) + .registerLoader(BiomeAdditionsSound.class, BiomeAdditionsSoundTemplate::new) + .registerLoader(MusicSound.class, MusicSoundTemplate::new) + .registerLoader(EntityType.class, EntityTypeTemplate::new) + .registerLoader(SpawnCostConfig.class, SpawnCostConfig::new) + .registerLoader(SpawnEntry.class, SpawnEntryTemplate::new) + .registerLoader(SpawnGroup.class, SpawnGroupTemplate::new) + .registerLoader(SpawnTypeConfig.class, SpawnTypeConfig::new) + .registerLoader(SpawnSettings.class, SpawnSettingsTemplate::new) + .registerLoader(VillagerType.class, VillagerTypeTemplate::new); + } + + private ProtoPlatformBiome parseBiome(String id, DepthTracker tracker) throws LoadException { + Identifier identifier = Identifier.tryParse(id); + if(BuiltinRegistries.BIOME.get(identifier) == null) throw new LoadException("Invalid Biome ID: " + identifier, tracker); // failure. + return new ProtoPlatformBiome(identifier); + } + + @Override + protected Iterable platformAddon() { + return List.of(getPlatformAddon()); + } + + protected abstract BaseAddon getPlatformAddon(); + + @Override + public @NotNull WorldHandle getWorldHandle() { + return worldHandle; + } + + @Override + public @NotNull ItemHandle getItemHandle() { + return itemHandle; + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/BiomeAdditionsSoundTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/BiomeAdditionsSoundTemplate.java new file mode 100644 index 000000000..e9d4a2038 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/BiomeAdditionsSoundTemplate.java @@ -0,0 +1,27 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.sound.BiomeAdditionsSound; +import net.minecraft.sound.SoundEvent; + + +public class BiomeAdditionsSoundTemplate implements ObjectTemplate { + @Value("sound") + @Default + private SoundEvent sound = null; + + @Value("sound-chance") + @Default + private Double soundChance = null; + + @Override + public BiomeAdditionsSound get() { + if(sound == null || soundChance == null) { + return null; + } else { + return new BiomeAdditionsSound(sound, soundChance); + } + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/BiomeMoodSoundTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/BiomeMoodSoundTemplate.java new file mode 100644 index 000000000..081cd0770 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/BiomeMoodSoundTemplate.java @@ -0,0 +1,35 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.sound.BiomeMoodSound; +import net.minecraft.sound.SoundEvent; + + +public class BiomeMoodSoundTemplate implements ObjectTemplate { + @Value("sound") + @Default + private SoundEvent sound = null; + + @Value("cultivation-ticks") + @Default + private Integer soundCultivationTicks = null; + + @Value("spawn-range") + @Default + private Integer soundSpawnRange = null; + + @Value("extra-distance") + @Default + private Double soundExtraDistance = null; + + @Override + public BiomeMoodSound get() { + if(sound == null || soundCultivationTicks == null || soundSpawnRange == null || soundExtraDistance == null) { + return null; + } else { + return new BiomeMoodSound(sound, soundCultivationTicks, soundSpawnRange, soundExtraDistance); + } + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/BiomeParticleConfigTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/BiomeParticleConfigTemplate.java new file mode 100644 index 000000000..538a80870 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/BiomeParticleConfigTemplate.java @@ -0,0 +1,33 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.command.argument.ParticleEffectArgumentType; +import net.minecraft.world.biome.BiomeParticleConfig; + + +public class BiomeParticleConfigTemplate implements ObjectTemplate { + @Value("particle") + @Default + private String particle = null; + + @Value("probability") + @Default + private Integer probability = null; + + @Override + public BiomeParticleConfig get() { + if(particle == null || probability == null) { + return null; + } + + try { + return new BiomeParticleConfig(ParticleEffectArgumentType.readParameters(new StringReader(particle)), probability); + } catch(CommandSyntaxException e) { + throw new RuntimeException(e); + } + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/EntityTypeTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/EntityTypeTemplate.java new file mode 100644 index 000000000..d2e46764d --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/EntityTypeTemplate.java @@ -0,0 +1,20 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.entity.EntityType; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + + +public class EntityTypeTemplate implements ObjectTemplate> { + @Value("id") + @Default + private Identifier id = null; + + @Override + public EntityType get() { + return Registry.ENTITY_TYPE.get(id); + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/MusicSoundTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/MusicSoundTemplate.java new file mode 100644 index 000000000..17745a9af --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/MusicSoundTemplate.java @@ -0,0 +1,35 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.sound.MusicSound; +import net.minecraft.sound.SoundEvent; + + +public class MusicSoundTemplate implements ObjectTemplate { + @Value("sound") + @Default + private SoundEvent sound = null; + + @Value("min-delay") + @Default + private Integer minDelay = null; + + @Value("max-delay") + @Default + private Integer maxDelay = null; + + @Value("replace-current-music") + @Default + private Boolean replaceCurrentMusic = null; + + @Override + public MusicSound get() { + if(sound == null || minDelay == null || maxDelay == null || replaceCurrentMusic == null) { + return null; + } else { + return new MusicSound(sound, minDelay, maxDelay, replaceCurrentMusic); + } + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java index 9a13e0029..a8b457bf5 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.config; +package com.dfsek.terra.mod.config; import com.dfsek.tectonic.api.config.template.ConfigTemplate; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PreLoadCompatibilityOptions.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java similarity index 88% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PreLoadCompatibilityOptions.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java index 8533ef1a0..00825bc5f 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PreLoadCompatibilityOptions.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.config; +package com.dfsek.terra.mod.config; import com.dfsek.tectonic.api.config.template.ConfigTemplate; import com.dfsek.tectonic.api.config.template.annotations.Default; @@ -26,19 +26,19 @@ import com.dfsek.terra.api.properties.Properties; @SuppressWarnings("FieldMayBeFinal") public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties { - @Value("fabric.use-vanilla-biomes") + @Value("minecraft.use-vanilla-biomes") @Default private boolean vanillaBiomes = false; - @Value("fabric.beard.enable") + @Value("minecraft.beard.enable") @Default private boolean beard = true; - @Value("fabric.beard.threshold") + @Value("minecraft.beard.threshold") @Default private double beardThreshold = 0.5; - @Value("fabric.beard.air-threshold") + @Value("minecraft.beard.air-threshold") @Default private double airThreshold = -0.5; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/ProtoPlatformBiome.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java similarity index 89% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/ProtoPlatformBiome.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java index b8262893a..f9524ef58 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/ProtoPlatformBiome.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.util; +package com.dfsek.terra.mod.config; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; @@ -25,6 +25,7 @@ import net.minecraft.world.biome.Biome; import java.util.Objects; import com.dfsek.terra.api.world.biome.PlatformBiome; +import com.dfsek.terra.mod.util.MinecraftUtil; public class ProtoPlatformBiome implements PlatformBiome { @@ -37,7 +38,7 @@ public class ProtoPlatformBiome implements PlatformBiome { } public RegistryKey get(Registry registry) { - return FabricUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow(); + return MinecraftUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow(); } @Override diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SoundEventTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SoundEventTemplate.java new file mode 100644 index 000000000..5e87dc21a --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SoundEventTemplate.java @@ -0,0 +1,29 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.Identifier; + + +public class SoundEventTemplate implements ObjectTemplate { + @Value("id") + @Default + private Identifier id = null; + + @Value("distance-to-travel") + @Default + private Float distanceToTravel = null; + + @Override + public SoundEvent get() { + if(id == null) { + return null; + } else if(distanceToTravel == null) { + return new SoundEvent(id); + } else { + return new SoundEvent(id, distanceToTravel); + } + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnCostConfig.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnCostConfig.java new file mode 100644 index 000000000..3af1ff1b1 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnCostConfig.java @@ -0,0 +1,38 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.entity.EntityType; + + +public class SpawnCostConfig implements ObjectTemplate { + @Value("type") + @Default + private EntityType type = null; + + @Value("mass") + @Default + private Double mass = null; + + @Value("gravity") + @Default + private Double gravity = null; + + public EntityType getType() { + return type; + } + + public Double getMass() { + return mass; + } + + public Double getGravity() { + return gravity; + } + + @Override + public SpawnCostConfig get() { + return this; + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnEntryTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnEntryTemplate.java new file mode 100644 index 000000000..7c203b62e --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnEntryTemplate.java @@ -0,0 +1,31 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.entity.EntityType; +import net.minecraft.world.biome.SpawnSettings.SpawnEntry; + + +public class SpawnEntryTemplate implements ObjectTemplate { + @Value("type") + @Default + private EntityType type = null; + + @Value("weight") + @Default + private Integer weight = null; + + @Value("min-group-size") + @Default + private Integer minGroupSize = null; + + @Value("max-group-size") + @Default + private Integer maxGroupSize = null; + + @Override + public SpawnEntry get() { + return new SpawnEntry(type, weight, minGroupSize, maxGroupSize); + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnGroupTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnGroupTemplate.java new file mode 100644 index 000000000..e6a9143d1 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnGroupTemplate.java @@ -0,0 +1,18 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.entity.SpawnGroup; + + +public class SpawnGroupTemplate implements ObjectTemplate { + @Value("group") + @Default + private String group = null; + + @Override + public SpawnGroup get() { + return SpawnGroup.valueOf(group); + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnSettingsTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnSettingsTemplate.java new file mode 100644 index 000000000..9b72e579c --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnSettingsTemplate.java @@ -0,0 +1,39 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.world.biome.SpawnSettings; + +import java.util.List; + + +public class SpawnSettingsTemplate implements ObjectTemplate { + @Value("spawns") + @Default + private List spawns = null; + + @Value("costs") + @Default + private List costs = null; + + @Value("probability") + @Default + private Float probability = null; + + @Override + public SpawnSettings get() { + SpawnSettings.Builder builder = new SpawnSettings.Builder(); + for(SpawnTypeConfig spawn : spawns) { + builder.spawn(spawn.getGroup(), spawn.getEntry()); + } + for(SpawnCostConfig cost : costs) { + builder.spawnCost(cost.getType(), cost.getMass(), cost.getGravity()); + } + if(probability != null) { + builder.creatureSpawnProbability(probability); + } + + return builder.build(); + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnTypeConfig.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnTypeConfig.java new file mode 100644 index 000000000..0f1eff6b5 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/SpawnTypeConfig.java @@ -0,0 +1,31 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.entity.SpawnGroup; +import net.minecraft.world.biome.SpawnSettings.SpawnEntry; + + +public class SpawnTypeConfig implements ObjectTemplate { + @Value("group") + @Default + private SpawnGroup group = null; + + @Value("entry") + @Default + private SpawnEntry entry = null; + + public SpawnGroup getGroup() { + return group; + } + + public SpawnEntry getEntry() { + return entry; + } + + @Override + public SpawnTypeConfig get() { + return this; + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java new file mode 100644 index 000000000..b5b88a6b9 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java @@ -0,0 +1,164 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.ConfigTemplate; +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import net.minecraft.sound.BiomeAdditionsSound; +import net.minecraft.sound.BiomeMoodSound; +import net.minecraft.sound.MusicSound; +import net.minecraft.sound.SoundEvent; +import net.minecraft.village.VillagerType; +import net.minecraft.world.biome.Biome.Precipitation; +import net.minecraft.world.biome.Biome.TemperatureModifier; +import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; +import net.minecraft.world.biome.BiomeParticleConfig; +import net.minecraft.world.biome.SpawnSettings; + +import com.dfsek.terra.api.properties.Properties; + + +public class VanillaBiomeProperties implements ConfigTemplate, Properties { + @Value("colors.grass") + @Default + private Integer grassColor = null; + + @Value("colors.fog") + @Default + private Integer fogColor = null; + + @Value("colors.water") + @Default + private Integer waterColor = null; + + @Value("colors.water-fog") + @Default + private Integer waterFogColor = null; + + @Value("colors.foliage") + @Default + private Integer foliageColor = null; + + @Value("colors.sky") + @Default + private Integer skyColor = null; + + @Value("colors.modifier") + @Default + private GrassColorModifier grassColorModifier = null; + + @Value("particles") + @Default + private BiomeParticleConfig particleConfig = null; + + @Value("climate.precipitation") + @Default + private Precipitation precipitation = null; + + @Value("climate.temperature") + @Default + private Float temperature = null; + + @Value("climate.temperature-modifier") + @Default + private TemperatureModifier temperatureModifier = null; + + @Value("climate.downfall") + @Default + private Float downfall = null; + + @Value("sound.loop-sound.sound") + @Default + private SoundEvent loopSound = null; + + @Value("sound.mood-sound") + @Default + private BiomeMoodSound moodSound = null; + + @Value("sound.additions-sound") + @Default + private BiomeAdditionsSound additionsSound = null; + + @Value("sound.music") + @Default + private MusicSound music = null; + + @Value("spawning") + @Default + private SpawnSettings spawnSettings = null; + + @Value("villager-type") + @Default + private VillagerType villagerType = null; + + public Integer getGrassColor() { + return grassColor; + } + + public Integer getFogColor() { + return fogColor; + } + + public Integer getWaterColor() { + return waterColor; + } + + public Integer getWaterFogColor() { + return waterFogColor; + } + + public Integer getFoliageColor() { + return foliageColor; + } + + public Integer getSkyColor() { + return skyColor; + } + + public GrassColorModifier getGrassColorModifier() { + return grassColorModifier; + } + + public BiomeParticleConfig getParticleConfig() { + return particleConfig; + } + + public Precipitation getPrecipitation() { + return precipitation; + } + + public Float getTemperature() { + return temperature; + } + + public TemperatureModifier getTemperatureModifier() { + return temperatureModifier; + } + + public Float getDownfall() { + return downfall; + } + + public SoundEvent getLoopSound() { + return loopSound; + } + + public BiomeMoodSound getMoodSound() { + return moodSound; + } + + public BiomeAdditionsSound getAdditionsSound() { + return additionsSound; + } + + public MusicSound getMusic() { + return music; + } + + public SpawnSettings getSpawnSettings() { + return spawnSettings; + } + + public VillagerType getVillagerType() { + return villagerType; + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/VillagerTypeTemplate.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/VillagerTypeTemplate.java new file mode 100644 index 000000000..f8cce4832 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/VillagerTypeTemplate.java @@ -0,0 +1,20 @@ +package com.dfsek.terra.mod.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraft.village.VillagerType; + + +public class VillagerTypeTemplate implements ObjectTemplate { + @Value("id") + @Default + private Identifier id = null; + + @Override + public VillagerType get() { + return Registry.VILLAGER_TYPE.get(id); + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java similarity index 77% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java index a2d2222c7..5f5dd615a 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java @@ -1,10 +1,4 @@ -package com.dfsek.terra.fabric.data; - -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.registry.key.RegistryKey; -import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.generation.TerraBiomeSource; +package com.dfsek.terra.mod.data; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; @@ -12,6 +6,12 @@ import net.minecraft.util.dynamic.RegistryOps; import net.minecraft.util.registry.Registry; import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.registry.key.RegistryKey; +import com.dfsek.terra.mod.CommonPlatform; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.generation.TerraBiomeSource; + public final class Codecs { public static final Codec TERRA_REGISTRY_KEY = RecordCodecBuilder @@ -27,12 +27,12 @@ public final class Codecs { .create(config -> config.group(TERRA_REGISTRY_KEY.fieldOf("pack") .stable() .forGetter(ConfigPack::getRegistryKey)) - .apply(config, config.stable(id -> FabricEntryPoint.getPlatform() - .getConfigRegistry() - .get(id) - .orElseThrow(() -> new IllegalArgumentException( - "No such config pack " + - id))))); + .apply(config, config.stable(id -> CommonPlatform.get() + .getConfigRegistry() + .get(id) + .orElseThrow(() -> new IllegalArgumentException( + "No such config pack " + + id))))); public static final Codec TERRA_BIOME_SOURCE = RecordCodecBuilder .create(instance -> instance.group(RegistryOps.createRegistryCodec(Registry.BIOME_KEY) @@ -44,22 +44,22 @@ public final class Codecs { .forGetter(TerraBiomeSource::getPack)) .apply(instance, instance.stable(TerraBiomeSource::new))); - public static final Codec FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder + public static final Codec MINECRAFT_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder .create( instance -> instance.group( RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY) .fieldOf("structure_registry") .stable() - .forGetter(FabricChunkGeneratorWrapper::getNoiseRegistry), + .forGetter(MinecraftChunkGeneratorWrapper::getNoiseRegistry), TERRA_BIOME_SOURCE.fieldOf("biome_source") .stable() - .forGetter(FabricChunkGeneratorWrapper::getBiomeSource), + .forGetter(MinecraftChunkGeneratorWrapper::getBiomeSource), CONFIG_PACK.fieldOf("pack") .stable() - .forGetter(FabricChunkGeneratorWrapper::getPack), + .forGetter(MinecraftChunkGeneratorWrapper::getPack), ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings") .stable() - .forGetter(FabricChunkGeneratorWrapper::getSettings) - ).apply(instance, instance.stable(FabricChunkGeneratorWrapper::new)) + .forGetter(MinecraftChunkGeneratorWrapper::getSettings) + ).apply(instance, instance.stable(MinecraftChunkGeneratorWrapper::new)) ); } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java similarity index 85% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java index 26bd28dc6..5742120d6 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.generation; +package com.dfsek.terra.mod.generation; import com.mojang.serialization.Codec; import net.minecraft.block.BlockState; @@ -61,14 +61,14 @@ import com.dfsek.terra.api.world.chunk.generation.ProtoWorld; import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified; import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper; import com.dfsek.terra.api.world.info.WorldProperties; -import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.fabric.data.Codecs; -import com.dfsek.terra.fabric.mixin.access.StructureAccessorAccessor; -import com.dfsek.terra.fabric.util.FabricAdapter; +import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.mod.data.Codecs; +import com.dfsek.terra.mod.mixin.access.StructureAccessorAccessor; +import com.dfsek.terra.mod.util.MinecraftAdapter; -public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { - private static final Logger logger = LoggerFactory.getLogger(FabricChunkGeneratorWrapper.class); +public class MinecraftChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { + private static final Logger logger = LoggerFactory.getLogger(MinecraftChunkGeneratorWrapper.class); private final TerraBiomeSource biomeSource; private final Registry noiseRegistry; @@ -76,8 +76,8 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C private ChunkGenerator delegate; private ConfigPack pack; - public FabricChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack, - RegistryEntry settingsSupplier) { + public MinecraftChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack, + RegistryEntry settingsSupplier) { super(noiseRegistry, Optional.empty(), biomeSource); this.noiseRegistry = noiseRegistry; this.pack = configPack; @@ -94,9 +94,9 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override protected Codec getCodec() { - return Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER; + return Codecs.MINECRAFT_CHUNK_GENERATOR_WRAPPER; } - + @Override public void buildSurface(ChunkRegion region, StructureAccessor structures, NoiseConfig noiseConfig, Chunk chunk) { // no op @@ -104,7 +104,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public void populateEntities(ChunkRegion region) { - if (!this.settings.value().mobGenerationDisabled()) { + if(!this.settings.value().mobGenerationDisabled()) { ChunkPos chunkPos = region.getCenterPos(); RegistryEntry registryEntry = region.getBiome(chunkPos.getStartPos().withY(region.getTopY() - 1)); ChunkRandom chunkRandom = new ChunkRandom(new CheckedRandom(RandomSeed.getSeed())); @@ -119,15 +119,14 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C } - @Override public CompletableFuture populateNoise(Executor executor, Blender blender, NoiseConfig noiseConfig, StructureAccessor structureAccessor, Chunk chunk) { return CompletableFuture.supplyAsync(() -> { ProtoWorld world = (ProtoWorld) ((StructureAccessorAccessor) structureAccessor).getWorld(); - BiomeProvider biomeProvider = pack.getBiomeProvider().caching(world); + BiomeProvider biomeProvider = pack.getBiomeProvider(); delegate.generateChunkData((ProtoChunk) chunk, world, biomeProvider, chunk.getPos().x, chunk.getPos().z); - + PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class); if(compatibilityOptions.isBeard()) { beard(structureAccessor, chunk, world, biomeProvider, compatibilityOptions); @@ -137,7 +136,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C } private void beard(StructureAccessor structureAccessor, Chunk chunk, WorldProperties world, BiomeProvider biomeProvider, - PreLoadCompatibilityOptions compatibilityOptions) { + PreLoadCompatibilityOptions compatibilityOptions) { StructureWeightSampler structureWeightSampler = StructureWeightSampler.method_42695(structureAccessor, chunk.getPos()); double threshold = compatibilityOptions.getBeardThreshold(); double airThreshold = compatibilityOptions.getAirThreshold(); @@ -186,21 +185,22 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public int getHeight(int x, int z, Type heightmap, HeightLimitView height, NoiseConfig noiseConfig) { - int y = height.getTopY(); - WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); - BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); - while(y >= getMinimumY() && !heightmap.getBlockPredicate().test( - (BlockState) delegate.getBlock(properties, x, y - 1, z, biomeProvider))) { - y--; + WorldProperties properties = MinecraftAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); + BiomeProvider biomeProvider = pack.getBiomeProvider(); + int min = height.getBottomY(); + for(int y = height.getTopY() - 1; y >= min; y--) { + if(heightmap + .getBlockPredicate() + .test((BlockState) delegate.getBlock(properties, x, y, z, biomeProvider))) return y + 1; } - return y; + return min; } @Override public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView height, NoiseConfig noiseConfig) { BlockState[] array = new BlockState[height.getHeight()]; - WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); - BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); + WorldProperties properties = MinecraftAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); + BiomeProvider biomeProvider = pack.getBiomeProvider(); for(int y = height.getTopY() - 1; y >= height.getBottomY(); y--) { array[y - height.getBottomY()] = (BlockState) delegate.getBlock(properties, x, y, z, biomeProvider); } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java similarity index 90% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java index 17aaa343f..5730cee80 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java @@ -15,18 +15,9 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.generation; - -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.world.biome.generation.BiomeProvider; -import com.dfsek.terra.fabric.data.Codecs; -import com.dfsek.terra.fabric.util.ProtoPlatformBiome; - -import com.dfsek.terra.fabric.util.SeedHack; +package com.dfsek.terra.mod.generation; import com.mojang.serialization.Codec; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryEntry; import net.minecraft.world.biome.source.BiomeSource; @@ -34,9 +25,14 @@ import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Map; import java.util.stream.StreamSupport; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; +import com.dfsek.terra.mod.config.ProtoPlatformBiome; +import com.dfsek.terra.mod.data.Codecs; +import com.dfsek.terra.mod.util.SeedHack; + public class TerraBiomeSource extends BiomeSource { diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricItemHandle.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java similarity index 87% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricItemHandle.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java index beb2ee7a2..5d26b6c43 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricItemHandle.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java @@ -15,9 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.handle; - -import com.dfsek.terra.fabric.FabricEntryPoint; +package com.dfsek.terra.mod.handle; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -32,14 +30,16 @@ import java.util.stream.Collectors; import com.dfsek.terra.api.handle.ItemHandle; import com.dfsek.terra.api.inventory.Item; import com.dfsek.terra.api.inventory.item.Enchantment; +import com.dfsek.terra.mod.CommonPlatform; -public class FabricItemHandle implements ItemHandle { +public class MinecraftItemHandle implements ItemHandle { @Override public Item createItem(String data) { try { - return (Item) new ItemStackArgumentType(new CommandRegistryAccess(FabricEntryPoint.getPlatform().getServer().getRegistryManager())).parse(new StringReader(data)).getItem(); + return (Item) new ItemStackArgumentType(new CommandRegistryAccess( + CommonPlatform.get().getServer().getRegistryManager())).parse(new StringReader(data)).getItem(); } catch(CommandSyntaxException e) { throw new IllegalArgumentException("Invalid item data \"" + data + "\"", e); } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricWorldHandle.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java similarity index 89% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricWorldHandle.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java index ac7a0e248..13eef4b2d 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricWorldHandle.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java @@ -15,16 +15,12 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.handle; +package com.dfsek.terra.mod.handle; -import com.dfsek.terra.fabric.FabricEntryPoint; - -import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.Blocks; import net.minecraft.command.argument.BlockArgumentParser; import net.minecraft.util.Identifier; -import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.util.registry.Registry; import org.jetbrains.annotations.NotNull; @@ -33,7 +29,7 @@ import com.dfsek.terra.api.entity.EntityType; import com.dfsek.terra.api.handle.WorldHandle; -public class FabricWorldHandle implements WorldHandle { +public class MinecraftWorldHandle implements WorldHandle { private static final BlockState AIR = (BlockState) Blocks.AIR.getDefaultState(); diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/BiomeAccessor.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/BiomeAccessor.java new file mode 100644 index 000000000..c51029682 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/BiomeAccessor.java @@ -0,0 +1,12 @@ +package com.dfsek.terra.mod.mixin.access; + +import net.minecraft.world.biome.Biome; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + + +@Mixin(Biome.class) +public interface BiomeAccessor { + @Accessor("weather") + Biome.Weather getWeather(); +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/MobSpawnerLogicAccessor.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/MobSpawnerLogicAccessor.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java index 28cda62be..5289cd427 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/MobSpawnerLogicAccessor.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.access; +package com.dfsek.terra.mod.mixin.access; import net.minecraft.world.MobSpawnerEntry; import net.minecraft.world.MobSpawnerLogic; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StateAccessor.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StateAccessor.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java index 1ec51c2dc..0cee6cbaf 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StateAccessor.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.access; +package com.dfsek.terra.mod.mixin.access; import net.minecraft.state.State; import net.minecraft.state.property.Property; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StructureAccessorAccessor.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StructureAccessorAccessor.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java index da33618d2..b64b47faa 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StructureAccessorAccessor.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.access; +package com.dfsek.terra.mod.mixin.access; import net.minecraft.world.WorldAccess; import net.minecraft.world.gen.StructureAccessor; diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/VillagerTypeAccessor.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/VillagerTypeAccessor.java new file mode 100644 index 000000000..477c0647b --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/VillagerTypeAccessor.java @@ -0,0 +1,18 @@ +package com.dfsek.terra.mod.mixin.access; + +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.village.VillagerType; +import net.minecraft.world.biome.Biome; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + + +@Mixin(VillagerType.class) +public interface VillagerTypeAccessor { + @Accessor("BIOME_TO_TYPE") + static Map, VillagerType> getBiomeTypeToIdMap() { + throw new AssertionError("Untransformed Accessor!"); + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java new file mode 100644 index 000000000..f29e6d259 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java @@ -0,0 +1,28 @@ +package com.dfsek.terra.mod.mixin.fix; + +import net.minecraft.entity.passive.BeeEntity.MoveToFlowerGoal; +import net.minecraft.entity.passive.BeeEntity.MoveToHiveGoal; +import net.minecraft.util.math.random.CheckedRandom; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import com.dfsek.terra.mod.CommonPlatform; + + +/** + * Bees spawning uses world.random without synchronization. This causes issues when spawning bees during world generation. + */ +@Mixin({ + MoveToHiveGoal.class, + MoveToFlowerGoal.class +}) +public class BeeMoveGoalsUnsynchronizedRandomAccessFix { + @Redirect(method = "", + at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;random:Lnet/minecraft/util/math/random/Random;")) + public Random redirectRandomAccess(World instance) { + return new CheckedRandom(CommonPlatform.get().getServer().getTicks()); // replace with new random seeded by tick time. + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java new file mode 100644 index 000000000..f2ab4956a --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java @@ -0,0 +1,30 @@ +package com.dfsek.terra.mod.mixin.fix; + +import net.minecraft.world.gen.structure.NetherFossilStructure; +import net.minecraft.world.gen.structure.Structure.Context; +import net.minecraft.world.gen.structure.Structure.StructurePosition; +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.Optional; + +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; + + +/** + * Disable fossil generation in Terra worlds, as they are very expensive due to consistently triggering cache misses. + *

+ * Currently, on Fabric, Terra cannot be specified as a Nether generator. TODO: logic to turn fossils back on if chunk generator is in + * nether. + */ +@Mixin(NetherFossilStructure.class) +public class NetherFossilOptimization { + @Inject(method = "getStructurePosition", at = @At("HEAD"), cancellable = true) + public void injectFossilPositions(Context context, CallbackInfoReturnable> cir) { + if(context.chunkGenerator() instanceof MinecraftChunkGeneratorWrapper) { + cir.setReturnValue(Optional.empty()); + } + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/compat/GenerationSettingsFloraFeaturesMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java similarity index 89% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/compat/GenerationSettingsFloraFeaturesMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java index f625fb1ba..c254445d1 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/compat/GenerationSettingsFloraFeaturesMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java @@ -1,6 +1,4 @@ -package com.dfsek.terra.fabric.mixin.compat; - -import com.dfsek.terra.fabric.util.FloraFeatureHolder; +package com.dfsek.terra.mod.mixin.implementations.compat; import net.minecraft.world.biome.GenerationSettings; import net.minecraft.world.gen.feature.ConfiguredFeature; @@ -13,6 +11,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.List; +import com.dfsek.terra.mod.mixin_ifaces.FloraFeatureHolder; + @Mixin(GenerationSettings.class) @Implements(@Interface(iface = FloraFeatureHolder.class, prefix = "terra$")) diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/BiomeMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java similarity index 94% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/BiomeMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java index aedbe6332..893921e8e 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/BiomeMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations; +package com.dfsek.terra.mod.mixin.implementations.terra; import net.minecraft.world.biome.Biome; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/HandleImplementationMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/HandleImplementationMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java index edf5d7e69..0257421ca 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/HandleImplementationMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.fabric.mixin.implementations; +package com.dfsek.terra.mod.mixin.implementations.terra; import net.minecraft.block.Block; import net.minecraft.block.BlockState; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/BlockMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/BlockMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java index 8f0167ab6..480e4a86d 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/BlockMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.block; +package com.dfsek.terra.mod.mixin.implementations.terra.block; import net.minecraft.block.Block; import net.minecraft.block.Blocks; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/BlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/BlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java index cb501f580..cfb7b795b 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/BlockEntityMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.block.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.block.entity; import org.spongepowered.asm.mixin.Implements; import org.spongepowered.asm.mixin.Interface; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/LootableContainerBlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java similarity index 94% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/LootableContainerBlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java index ffa217be9..ad237b3b8 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/LootableContainerBlockEntityMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.block.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.block.entity; import net.minecraft.block.entity.LootableContainerBlockEntity; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/MobSpawnerBlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java similarity index 93% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/MobSpawnerBlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java index 2f0363190..f28c27a62 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/MobSpawnerBlockEntityMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.block.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.block.entity; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; @@ -34,8 +34,8 @@ import org.spongepowered.asm.mixin.Shadow; import com.dfsek.terra.api.block.entity.MobSpawner; import com.dfsek.terra.api.block.entity.SerialState; import com.dfsek.terra.api.entity.EntityType; -import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.mixin.access.MobSpawnerLogicAccessor; +import com.dfsek.terra.mod.CommonPlatform; +import com.dfsek.terra.mod.mixin.access.MobSpawnerLogicAccessor; @Mixin(MobSpawnerBlockEntity.class) @@ -116,7 +116,7 @@ public abstract class MobSpawnerBlockEntityMixin extends BlockEntity { public void terra$applyState(String state) { SerialState.parse(state).forEach((k, v) -> { switch(k) { - case "type" -> terra$setSpawnedType(FabricEntryPoint.getPlatform().getWorldHandle().getEntity(v)); + case "type" -> terra$setSpawnedType(CommonPlatform.get().getWorldHandle().getEntity(v)); case "delay" -> terra$setDelay(Integer.parseInt(v)); case "min_delay" -> terra$setMinSpawnDelay(Integer.parseInt(v)); case "max_delay" -> terra$setMaxSpawnDelay(Integer.parseInt(v)); diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/SignBlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/SignBlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java index 675748135..e32d7e053 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/entity/SignBlockEntityMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.block.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.block.entity; import net.minecraft.block.entity.SignBlockEntity; import net.minecraft.text.Text; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/state/BlockStateMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/state/BlockStateMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java index 4963fc4cb..636a3f721 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/state/BlockStateMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.fabric.mixin.implementations.block.state; +package com.dfsek.terra.mod.mixin.implementations.terra.block.state; import com.google.common.collect.ImmutableMap; @@ -18,7 +18,7 @@ import java.util.stream.Collectors; import com.dfsek.terra.api.block.BlockType; import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.properties.Property; -import com.dfsek.terra.fabric.mixin.access.StateAccessor; +import com.dfsek.terra.mod.mixin.access.StateAccessor; @Mixin(AbstractBlockState.class) diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/state/PropertyMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java similarity index 93% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/state/PropertyMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java index c0cb10943..2dd6100d6 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/block/state/PropertyMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.fabric.mixin.implementations.block.state; +package com.dfsek.terra.mod.mixin.implementations.terra.block.state; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/chunk/ChunkRegionMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java similarity index 97% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/chunk/ChunkRegionMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java index 0acb33459..7224f25d1 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/chunk/ChunkRegionMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.chunk; +package com.dfsek.terra.mod.mixin.implementations.terra.chunk; import net.minecraft.util.math.BlockPos; import net.minecraft.world.ChunkRegion; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/chunk/WorldChunkMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java similarity index 97% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/chunk/WorldChunkMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java index f89d96b62..3fb01104d 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/chunk/WorldChunkMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.chunk; +package com.dfsek.terra.mod.mixin.implementations.terra.chunk; import net.minecraft.util.math.BlockPos; import net.minecraft.world.chunk.WorldChunk; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/chunk/data/ProtoChunkMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java similarity index 88% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/chunk/data/ProtoChunkMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java index 627a1766f..25c8f196f 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/chunk/data/ProtoChunkMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java @@ -15,9 +15,10 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.chunk.data; +package com.dfsek.terra.mod.mixin.implementations.terra.chunk.data; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.HeightLimitView; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Implements; import org.spongepowered.asm.mixin.Interface; @@ -34,6 +35,9 @@ public abstract class ProtoChunkMixin { @Shadow public abstract net.minecraft.block.BlockState getBlockState(BlockPos pos); + @Shadow + public abstract HeightLimitView getHeightLimitView(); + public void terra$setBlock(int x, int y, int z, @NotNull BlockState blockState) { ((net.minecraft.world.chunk.Chunk) (Object) this).setBlockState(new BlockPos(x, y, z), (net.minecraft.block.BlockState) blockState, false); @@ -44,6 +48,6 @@ public abstract class ProtoChunkMixin { } public int terra$getMaxHeight() { - return 255; // TODO: 1.17 - Implement dynamic height. + return getHeightLimitView().getTopY(); } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/EntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java similarity index 88% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/EntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java index 42b006cb1..dce95cf19 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/EntityMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java @@ -15,21 +15,18 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.entity; import net.minecraft.entity.Entity; -import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import org.spongepowered.asm.mixin.Implements; import org.spongepowered.asm.mixin.Interface; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import java.util.UUID; - import com.dfsek.terra.api.util.vector.Vector3; import com.dfsek.terra.api.world.ServerWorld; -import com.dfsek.terra.fabric.util.FabricAdapter; +import com.dfsek.terra.mod.util.MinecraftAdapter; @Mixin(Entity.class) @@ -45,7 +42,7 @@ public abstract class EntityMixin { public abstract void teleport(double destX, double destY, double destZ); public Vector3 terra$position() { - return FabricAdapter.adapt(blockPos); + return MinecraftAdapter.adapt(blockPos); } public void terra$position(Vector3 location) { diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/EntityTypeMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java similarity index 94% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/EntityTypeMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java index 3acee886c..a79d4fb0d 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/EntityTypeMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.entity; import net.minecraft.entity.EntityType; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/PlayerEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java similarity index 94% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/PlayerEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java index daf784d88..ec60c9f69 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/PlayerEntityMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.entity; import net.minecraft.entity.player.PlayerEntity; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/ServerCommandSourceMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java similarity index 97% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/ServerCommandSourceMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java index 23cf991c0..f11ee5f73 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/entity/ServerCommandSourceMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.entity; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.server.command.ServerCommandSource; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/LockableContainerBlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/LockableContainerBlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java index bb9ccf63b..90c0275dc 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/LockableContainerBlockEntityMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.inventory; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory; import net.minecraft.block.entity.LockableContainerBlockEntity; import net.minecraft.item.Items; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/item/ItemMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/item/ItemMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java index a7d5da4ed..51687c45a 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/item/ItemMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.inventory.item; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.item; import net.minecraft.item.Item; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/item/ItemStackMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/item/ItemStackMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java index dcddca234..f41bce58d 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/item/ItemStackMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.inventory.item; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/meta/EnchantmentMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/meta/EnchantmentMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java index 3d10a2241..d5394870c 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/meta/EnchantmentMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.inventory.meta; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.meta; import net.minecraft.enchantment.Enchantment; import net.minecraft.util.registry.Registry; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/meta/ItemStackDamageableMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/meta/ItemStackDamageableMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java index 217ff86ba..599dd232d 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/meta/ItemStackDamageableMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.inventory.meta; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.meta; import net.minecraft.item.ItemStack; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/meta/ItemStackMetaMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/meta/ItemStackMetaMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java index 60c33fc68..39974ed26 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/inventory/meta/ItemStackMetaMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.inventory.meta; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.meta; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/package-info.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java similarity index 93% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/package-info.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java index 262b1c464..0d7e843de 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/package-info.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java @@ -20,4 +20,4 @@ * interfaces in Minecraft classes. */ -package com.dfsek.terra.fabric.mixin.implementations; \ No newline at end of file +package com.dfsek.terra.mod.mixin.implementations.terra; \ No newline at end of file diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ChunkRegionMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java similarity index 76% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ChunkRegionMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java index ab00eedd3..64ed28314 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ChunkRegionMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.world; +package com.dfsek.terra.mod.mixin.implementations.terra.world; import net.minecraft.block.FluidBlock; import net.minecraft.fluid.Fluid; @@ -43,20 +43,19 @@ import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.entity.Entity; import com.dfsek.terra.api.entity.EntityType; -import com.dfsek.terra.api.util.vector.Vector3; import com.dfsek.terra.api.world.ServerWorld; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; import com.dfsek.terra.api.world.chunk.generation.ProtoWorld; -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.generation.TerraBiomeSource; -import com.dfsek.terra.fabric.util.FabricUtil; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.util.MinecraftUtil; @Mixin(ChunkRegion.class) @Implements(@Interface(iface = ProtoWorld.class, prefix = "terraWorld$")) public abstract class ChunkRegionMixin { - private ConfigPack config; + private ConfigPack terra$config; + @Shadow @Final @@ -73,20 +72,15 @@ public abstract class ChunkRegionMixin { @Final private MultiTickScheduler fluidTickScheduler; + @Inject(at = @At("RETURN"), method = "(Lnet/minecraft/server/world/ServerWorld;Ljava/util/List;Lnet/minecraft/world/chunk/ChunkStatus;I)V") public void injectConstructor(net.minecraft.server.world.ServerWorld world, List list, ChunkStatus chunkStatus, int i, CallbackInfo ci) { - this.config = ((ServerWorld) world).getPack(); + this.terra$config = ((ServerWorld) world).getPack(); } - public Entity terraWorld$spawnEntity(Vector3 location, EntityType entityType) { - net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType) entityType).create(null); - entity.setPos(location.getX(), location.getY(), location.getZ()); - ((ChunkRegion) (Object) this).spawnEntity(entity); - return (Entity) entity; - } @Intrinsic(displace = true) public void terraWorld$setBlockState(int x, int y, int z, BlockState data, boolean physics) { @@ -105,7 +99,7 @@ public abstract class ChunkRegionMixin { } public int terraWorld$getMaxHeight() { - return (((ChunkRegion) (Object) this).getBottomY()) + ((ChunkRegion) (Object) this).getHeight(); + return world.getTopY(); } @Intrinsic(displace = true) @@ -115,23 +109,19 @@ public abstract class ChunkRegionMixin { } public BlockEntity terraWorld$getBlockEntity(int x, int y, int z) { - return FabricUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); + return MinecraftUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); } public int terraWorld$getMinHeight() { - return ((ChunkRegion) (Object) this).getBottomY(); + return world.getBottomY(); } public ChunkGenerator terraWorld$getGenerator() { - return ((FabricChunkGeneratorWrapper) world.getChunkManager().getChunkGenerator()).getHandle(); + return ((MinecraftChunkGeneratorWrapper) world.getChunkManager().getChunkGenerator()).getHandle(); } - @SuppressWarnings("deprecation") public BiomeProvider terraWorld$getBiomeProvider() { - return ((TerraBiomeSource) ((ChunkRegion) (Object) this).toServerWorld() - .getChunkManager() - .getChunkGenerator() - .getBiomeSource()).getProvider(); + return terra$config.getBiomeProvider(); } public Entity terraWorld$spawnEntity(double x, double y, double z, EntityType entityType) { @@ -154,6 +144,6 @@ public abstract class ChunkRegionMixin { } public ConfigPack terraWorld$getPack() { - return config; + return terra$config; } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ServerWorldMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java similarity index 85% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ServerWorldMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java index 6e1c97f9e..74af91dbc 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ServerWorldMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.world; +package com.dfsek.terra.mod.mixin.implementations.terra.world; import net.minecraft.util.math.BlockPos; import net.minecraft.world.WorldAccess; @@ -33,9 +33,9 @@ import com.dfsek.terra.api.world.ServerWorld; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.chunk.Chunk; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.generation.TerraBiomeSource; -import com.dfsek.terra.fabric.util.FabricUtil; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.generation.TerraBiomeSource; +import com.dfsek.terra.mod.util.MinecraftUtil; @Mixin(net.minecraft.server.world.ServerWorld.class) @@ -73,7 +73,7 @@ public abstract class ServerWorldMixin { } public BlockEntity terra$getBlockEntity(int x, int y, int z) { - return FabricUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); + return MinecraftUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); } public int terra$getMinHeight() { @@ -81,8 +81,8 @@ public abstract class ServerWorldMixin { } public ChunkGenerator terra$getGenerator() { - return ((FabricChunkGeneratorWrapper) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() - .getChunkGenerator()).getHandle(); + return ((MinecraftChunkGeneratorWrapper) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() + .getChunkGenerator()).getHandle(); } public BiomeProvider terra$getBiomeProvider() { @@ -94,8 +94,8 @@ public abstract class ServerWorldMixin { public ConfigPack terra$getPack() { net.minecraft.world.gen.chunk.ChunkGenerator generator = (((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager()).getChunkGenerator(); - if(generator instanceof FabricChunkGeneratorWrapper fabricChunkGeneratorWrapper) { - return fabricChunkGeneratorWrapper.getPack(); + if(generator instanceof MinecraftChunkGeneratorWrapper minecraftChunkGeneratorWrapper) { + return minecraftChunkGeneratorWrapper.getPack(); } return null; } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java similarity index 84% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java index f2e38a11d..a9ecb9354 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java @@ -1,7 +1,5 @@ -package com.dfsek.terra.fabric.mixin.lifecycle; +package com.dfsek.terra.mod.mixin.lifecycle; -import com.dfsek.terra.fabric.util.BiomeUtil; -import com.dfsek.terra.fabric.util.TagUtil; import net.minecraft.server.DataPackContents; import net.minecraft.util.registry.DynamicRegistryManager; import net.minecraft.util.registry.Registry; @@ -11,6 +9,9 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import com.dfsek.terra.mod.util.MinecraftUtil; +import com.dfsek.terra.mod.util.TagUtil; + @Mixin(DataPackContents.class) public class DataPackContentsMixin { @@ -23,6 +24,6 @@ public class DataPackContentsMixin { Registry biomeRegistry = dynamicRegistryManager.get(Registry.BIOME_KEY); TagUtil.registerBiomeTags(biomeRegistry); - BiomeUtil.registerFlora(biomeRegistry); + MinecraftUtil.registerFlora(biomeRegistry); } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FloraFeatureHolder.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java similarity index 82% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FloraFeatureHolder.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java index 9b2157d72..4e7c38dec 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FloraFeatureHolder.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.fabric.util; +package com.dfsek.terra.mod.mixin_ifaces; import net.minecraft.world.gen.feature.ConfiguredFeature; diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java new file mode 100644 index 000000000..2f43913e2 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java @@ -0,0 +1,56 @@ +/* + * This file is part of Terra. + * + * Terra is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Terra is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Terra. If not, see . + */ + +package com.dfsek.terra.mod.util; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.HeightLimitView; + +import com.dfsek.terra.api.util.vector.Vector3; +import com.dfsek.terra.api.world.info.WorldProperties; + + +public final class MinecraftAdapter { + + public static Vector3 adapt(BlockPos pos) { + return Vector3.of(pos.getX(), pos.getY(), pos.getZ()); + } + + public static WorldProperties adapt(HeightLimitView height, long seed) { + return new WorldProperties() { + @Override + public long getSeed() { + return seed; + } + + @Override + public int getMaxHeight() { + return height.getTopY(); + } + + @Override + public int getMinHeight() { + return height.getBottomY(); + } + + @Override + public Object getHandle() { + return height; + } + }; + } +} diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java new file mode 100644 index 000000000..69f91e6f6 --- /dev/null +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java @@ -0,0 +1,176 @@ +package com.dfsek.terra.mod.util; + +import net.minecraft.block.entity.LootableContainerBlockEntity; +import net.minecraft.block.entity.MobSpawnerBlockEntity; +import net.minecraft.block.entity.SignBlockEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryEntry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.WorldAccess; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.Biome.Builder; +import net.minecraft.world.biome.BiomeEffects; +import net.minecraft.world.biome.GenerationSettings; +import net.minecraft.world.gen.feature.ConfiguredFeature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import com.dfsek.terra.api.block.entity.BlockEntity; +import com.dfsek.terra.api.block.entity.Container; +import com.dfsek.terra.api.block.entity.MobSpawner; +import com.dfsek.terra.api.block.entity.Sign; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.mod.config.VanillaBiomeProperties; +import com.dfsek.terra.mod.mixin.access.BiomeAccessor; +import com.dfsek.terra.mod.mixin_ifaces.FloraFeatureHolder; + + +public final class MinecraftUtil { + public static final Logger logger = LoggerFactory.getLogger(MinecraftUtil.class); + public static final Map> + TERRA_BIOME_MAP = new HashMap<>(); + + private MinecraftUtil() { + + } + + public static Optional> getEntry(Registry registry, Identifier identifier) { + return registry.getOrEmpty(identifier) + .flatMap(registry::getKey) + .map(registry::getOrCreateEntry); + } + + public static BlockEntity createState(WorldAccess worldAccess, BlockPos pos) { + net.minecraft.block.entity.BlockEntity entity = worldAccess.getBlockEntity(pos); + 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 void registerFlora(Registry biomes) { + logger.info("Injecting flora into Terra biomes..."); + TERRA_BIOME_MAP + .forEach((vb, terraBiomes) -> + biomes.getOrEmpty(vb) + .ifPresentOrElse(vanilla -> terraBiomes + .forEach(tb -> biomes.getOrEmpty(tb) + .ifPresentOrElse( + terra -> { + List> flowerFeatures = List.copyOf( + vanilla.getGenerationSettings() + .getFlowerFeatures()); + logger.debug("Injecting flora into biome" + + " {} : {}", tb, + flowerFeatures); + ((FloraFeatureHolder) terra.getGenerationSettings()).setFloraFeatures( + flowerFeatures); + }, + () -> logger.error( + "No such biome: {}", + tb))), + () -> logger.error("No vanilla biome: {}", vb))); + + } + + public static Map> getTerraBiomeMap() { + return Map.copyOf(TERRA_BIOME_MAP); + } + + public static RegistryKey registerKey(Identifier identifier) { + return RegistryKey.of(Registry.BIOME_KEY, identifier); + } + + public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla, + VanillaBiomeProperties vanillaBiomeProperties) { + GenerationSettings.Builder generationSettings = new GenerationSettings.Builder(); + + BiomeEffects.Builder effects = new BiomeEffects.Builder(); + + net.minecraft.world.biome.Biome.Builder builder = new Builder(); + + effects.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor())) + .waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor())) + .fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor())) + .skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor())) + .grassColorModifier( + Objects.requireNonNullElse(vanillaBiomeProperties.getGrassColorModifier(), + vanilla.getEffects().getGrassColorModifier())); + + if(vanillaBiomeProperties.getFoliageColor() == null) { + vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); + } else { + effects.foliageColor(vanillaBiomeProperties.getFoliageColor()); + } + + if(vanillaBiomeProperties.getGrassColor() == null) { + vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); + } else { + effects.grassColor(vanillaBiomeProperties.getGrassColor()); + } + + if(vanillaBiomeProperties.getParticleConfig() == null) { + vanilla.getEffects().getParticleConfig().ifPresent(effects::particleConfig); + } else { + effects.particleConfig(vanillaBiomeProperties.getParticleConfig()); + } + + if(vanillaBiomeProperties.getLoopSound() == null) { + vanilla.getEffects().getLoopSound().ifPresent(effects::loopSound); + } else { + effects.loopSound(vanillaBiomeProperties.getLoopSound()); + } + + if(vanillaBiomeProperties.getMoodSound() == null) { + vanilla.getEffects().getMoodSound().ifPresent(effects::moodSound); + } else { + effects.moodSound(vanillaBiomeProperties.getMoodSound()); + } + + if(vanillaBiomeProperties.getAdditionsSound() == null) { + vanilla.getEffects().getAdditionsSound().ifPresent(effects::additionsSound); + } else { + effects.additionsSound(vanillaBiomeProperties.getAdditionsSound()); + } + + if(vanillaBiomeProperties.getMusic() == null) { + vanilla.getEffects().getMusic().ifPresent(effects::music); + } else { + effects.music(vanillaBiomeProperties.getMusic()); + } + + builder.precipitation(Objects.requireNonNullElse(vanillaBiomeProperties.getPrecipitation(), vanilla.getPrecipitation())); + + builder.temperature(Objects.requireNonNullElse(vanillaBiomeProperties.getTemperature(), vanilla.getTemperature())); + + builder.downfall(Objects.requireNonNullElse(vanillaBiomeProperties.getDownfall(), vanilla.getDownfall())); + + builder.temperatureModifier(Objects.requireNonNullElse(vanillaBiomeProperties.getTemperatureModifier(), + ((BiomeAccessor) ((Object) vanilla)).getWeather().temperatureModifier())); + + builder.spawnSettings(Objects.requireNonNullElse(vanillaBiomeProperties.getSpawnSettings(), vanilla.getSpawnSettings())); + + return builder + .effects(effects.build()) + .generationSettings(generationSettings.build()) + .build(); + } + + public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) { + return pack.getID() + .toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT); + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java similarity index 64% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java index 2e935d889..f4fd942c8 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java @@ -1,9 +1,4 @@ -package com.dfsek.terra.fabric.util; - -import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; -import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.generation.TerraBiomeSource; +package com.dfsek.terra.mod.util; import net.minecraft.structure.StructureSet; import net.minecraft.util.Identifier; @@ -29,19 +24,17 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.util.generic.pair.Pair; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.generation.TerraBiomeSource; -public class LifecycleUtil { - private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleUtil.class); - + +public class PresetUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(PresetUtil.class); private static final List PRESETS = new ArrayList<>(); - public static void initialize() { - FabricEntryPoint.getPlatform().getEventManager().callEvent( - new PlatformInitializationEvent()); - BiomeUtil.registerBiomes(); - - - LOGGER.info("Registering Terra world types..."); - + + public static Pair createDefault(ConfigPack pack) { Registry dimensionTypeRegistry = BuiltinRegistries.DIMENSION_TYPE; Registry chunkGeneratorSettingsRegistry = BuiltinRegistries.CHUNK_GENERATOR_SETTINGS; Registry structureSetRegistry = BuiltinRegistries.STRUCTURE_SET; @@ -68,30 +61,25 @@ public class LifecycleUtil { RegistryEntry overworldDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.OVERWORLD); RegistryEntry overworld = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.OVERWORLD); - FabricEntryPoint - .getPlatform() - .getRawConfigRegistry() - .forEach((id, pack) -> { - Identifier generatorID = Identifier.of("terra", pack.getID().toLowerCase(Locale.ROOT) + "/" + pack.getNamespace().toLowerCase( - Locale.ROOT)); - - PRESETS.add(generatorID); - - TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); - ChunkGenerator generator = new FabricChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); - - DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); - WorldPreset preset = new WorldPreset( - Map.of( - DimensionOptions.OVERWORLD, dimensionOptions, - DimensionOptions.NETHER, netherDimensionOptions, - DimensionOptions.END, endDimensionOptions - ) - ); - BuiltinRegistries.add(BuiltinRegistries.WORLD_PRESET, generatorID, preset); - LOGGER.info("Registered world type \"{}\"", generatorID); - } - ); + + Identifier generatorID = Identifier.of("terra", pack.getID().toLowerCase(Locale.ROOT) + "/" + pack.getNamespace().toLowerCase( + Locale.ROOT)); + + PRESETS.add(generatorID); + + TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); + ChunkGenerator generator = new MinecraftChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); + + DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); + WorldPreset preset = new WorldPreset( + Map.of( + DimensionOptions.OVERWORLD, dimensionOptions, + DimensionOptions.NETHER, netherDimensionOptions, + DimensionOptions.END, endDimensionOptions + ) + ); + LOGGER.info("Created world type \"{}\"", generatorID); + return Pair.of(generatorID, preset); } public static List getPresets() { diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java index f0c59fc00..74f9173ab 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.fabric.util; +package com.dfsek.terra.mod.util; import it.unimi.dsi.fastutil.objects.Object2LongMap; import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java index 7a52ff376..8edf50afc 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.fabric.util; +package com.dfsek.terra.mod.util; import com.google.common.collect.ImmutableMap; import net.minecraft.tag.TagKey; @@ -36,9 +36,9 @@ public final class TagUtil { logger.info("Doing preset tag garbage...."); Map, List>> collect = tagsToMutableMap(registry); - LifecycleUtil + PresetUtil .getPresets() - .forEach(id -> FabricUtil + .forEach(id -> MinecraftUtil .getEntry(registry, id) .ifPresentOrElse( preset -> collect @@ -54,14 +54,14 @@ public final class TagUtil { logger.info("Doing biome tag garbage...."); Map, List>> collect = tagsToMutableMap(registry); - BiomeUtil + MinecraftUtil .getTerraBiomeMap() .forEach((vb, terraBiomes) -> - FabricUtil + MinecraftUtil .getEntry(registry, vb) .ifPresentOrElse( vanilla -> terraBiomes - .forEach(tb -> FabricUtil + .forEach(tb -> MinecraftUtil .getEntry(registry, tb) .ifPresentOrElse( terra -> { diff --git a/platforms/mixin-common/src/main/resources/terra.accesswidener b/platforms/mixin-common/src/main/resources/terra.accesswidener new file mode 100644 index 000000000..4f59bb962 --- /dev/null +++ b/platforms/mixin-common/src/main/resources/terra.accesswidener @@ -0,0 +1,2 @@ +accessWidener v1 named +accessible class net/minecraft/world/biome/Biome$Weather \ No newline at end of file diff --git a/platforms/mixin-common/src/main/resources/terra.common.mixins.json b/platforms/mixin-common/src/main/resources/terra.common.mixins.json new file mode 100644 index 000000000..d4402241c --- /dev/null +++ b/platforms/mixin-common/src/main/resources/terra.common.mixins.json @@ -0,0 +1,49 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.dfsek.terra.mod.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "access.BiomeAccessor", + "access.MobSpawnerLogicAccessor", + "access.StateAccessor", + "access.StructureAccessorAccessor", + "access.VillagerTypeAccessor", + "fix.BeeMoveGoalsUnsynchronizedRandomAccessFix", + "fix.NetherFossilOptimization", + "implementations.compat.GenerationSettingsFloraFeaturesMixin", + "implementations.terra.BiomeMixin", + "implementations.terra.HandleImplementationMixin", + "implementations.terra.block.BlockMixin", + "implementations.terra.block.entity.BlockEntityMixin", + "implementations.terra.block.entity.LootableContainerBlockEntityMixin", + "implementations.terra.block.entity.MobSpawnerBlockEntityMixin", + "implementations.terra.block.entity.SignBlockEntityMixin", + "implementations.terra.block.state.BlockStateMixin", + "implementations.terra.block.state.PropertyMixin", + "implementations.terra.chunk.ChunkRegionMixin", + "implementations.terra.chunk.WorldChunkMixin", + "implementations.terra.chunk.data.ProtoChunkMixin", + "implementations.terra.entity.EntityMixin", + "implementations.terra.entity.EntityTypeMixin", + "implementations.terra.entity.PlayerEntityMixin", + "implementations.terra.entity.ServerCommandSourceMixin", + "implementations.terra.inventory.LockableContainerBlockEntityMixin", + "implementations.terra.inventory.item.ItemMixin", + "implementations.terra.inventory.item.ItemStackMixin", + "implementations.terra.inventory.meta.EnchantmentMixin", + "implementations.terra.inventory.meta.ItemStackDamageableMixin", + "implementations.terra.inventory.meta.ItemStackMetaMixin", + "implementations.terra.world.ChunkRegionMixin", + "implementations.terra.world.ServerWorldMixin", + "lifecycle.DataPackContentsMixin" + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "terra.common.refmap.json" +} \ No newline at end of file diff --git a/platforms/mixin-lifecycle/README.md b/platforms/mixin-lifecycle/README.md new file mode 100644 index 000000000..6c2c62cba --- /dev/null +++ b/platforms/mixin-lifecycle/README.md @@ -0,0 +1,3 @@ +# mixin-lifecycle + +This project contains lifecycle mixins shared between Fabric and Quilt. \ No newline at end of file diff --git a/platforms/mixin-lifecycle/build.gradle.kts b/platforms/mixin-lifecycle/build.gradle.kts new file mode 100644 index 000000000..0a9e71d7c --- /dev/null +++ b/platforms/mixin-lifecycle/build.gradle.kts @@ -0,0 +1,41 @@ +plugins { + id("dev.architectury.loom") version Versions.Mod.architecuryLoom + id("architectury-plugin") version Versions.Mod.architecturyPlugin + id("io.github.juuxel.loom-quiltflower") version Versions.Mod.loomQuiltflower +} + +dependencies { + shadedApi(project(":common:implementation:base")) + + compileOnly("net.fabricmc:sponge-mixin:${Versions.Mod.mixin}") + annotationProcessor("net.fabricmc:sponge-mixin:${Versions.Mod.mixin}") + annotationProcessor("dev.architectury:architectury-loom:${Versions.Mod.architecuryLoom}") + + implementation(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } + + minecraft("com.mojang:minecraft:${Versions.Mod.minecraft}") + mappings("net.fabricmc:yarn:${Versions.Mod.yarn}:v2") +} + +loom { + accessWidenerPath.set(project(":platforms:mixin-common").file("src/main/resources/terra.accesswidener")) + + mixin { + defaultRefmapName.set("terra.lifecycle.refmap.json") + } +} + +tasks { + compileJava { + options.release.set(17) + } + + remapJar { + inputFile.set(shadowJar.get().archiveFile) + } +} + +architectury { + common("fabric", "quilt") + minecraft = Versions.Mod.minecraft +} \ No newline at end of file diff --git a/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/LifecyclePlatform.java b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/LifecyclePlatform.java new file mode 100644 index 000000000..f218380d7 --- /dev/null +++ b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/LifecyclePlatform.java @@ -0,0 +1,88 @@ +package com.dfsek.terra.lifecycle; + +import ca.solostudios.strata.Versions; +import ca.solostudios.strata.parser.tokenizer.ParseException; +import net.minecraft.MinecraftVersion; +import net.minecraft.server.MinecraftServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.dfsek.terra.addon.EphemeralAddon; +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.lifecycle.util.BiomeUtil; +import com.dfsek.terra.mod.CommonPlatform; +import com.dfsek.terra.mod.ModPlatform; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; + + +public abstract class LifecyclePlatform extends ModPlatform { + private static final Logger LOGGER = LoggerFactory.getLogger(LifecyclePlatform.class); + private static MinecraftServer server; + + public LifecyclePlatform() { + CommonPlatform.initialize(this); + load(); + } + + @Override + public MinecraftServer getServer() { + return server; + } + + public static void setServer(MinecraftServer server) { + LifecyclePlatform.server = server; + } + + @Override + public boolean reload() { + getTerraConfig().load(this); + getRawConfigRegistry().clear(); + boolean succeed = getRawConfigRegistry().loadAll(this); + + + if(server != null) { + server.reloadResources(server.getDataPackManager().getNames()).exceptionally(throwable -> { + LOGGER.warn("Failed to execute reload", throwable); + return null; + }).join(); + BiomeUtil.registerBiomes(); + server.getWorlds().forEach(world -> { + if(world.getChunkManager().getChunkGenerator() instanceof MinecraftChunkGeneratorWrapper chunkGeneratorWrapper) { + getConfigRegistry().get(chunkGeneratorWrapper.getPack().getRegistryKey()).ifPresent(pack -> { + chunkGeneratorWrapper.setPack(pack); + LOGGER.info("Replaced pack in chunk generator for world {}", world); + }); + } + }); + } + return succeed; + } + + @Override + protected Iterable platformAddon() { + List addons = new ArrayList<>(); + + super.platformAddon().forEach(addons::add); + + String mcVersion = MinecraftVersion.CURRENT.getReleaseTarget(); + try { + addons.add(new EphemeralAddon(Versions.parseVersion(mcVersion), "minecraft")); + } catch(ParseException e) { + try { + addons.add(new EphemeralAddon(Versions.parseVersion(mcVersion + ".0"), "minecraft")); + } catch(ParseException ex) { + LOGGER.warn("Failed to parse Minecraft version", e); + } + } + + addons.addAll(getPlatformMods()); + + return addons; + } + + protected abstract Collection getPlatformMods(); +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/NoiseConfigMixin.java similarity index 73% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java rename to platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/NoiseConfigMixin.java index 6f9af2ed8..2793aa500 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java +++ b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/NoiseConfigMixin.java @@ -1,10 +1,7 @@ -package com.dfsek.terra.fabric.mixin.lifecycle; - -import com.dfsek.terra.fabric.util.SeedHack; +package com.dfsek.terra.lifecycle.mixin; import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; import net.minecraft.util.registry.Registry; -import net.minecraft.world.biome.source.util.MultiNoiseUtil; import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; import net.minecraft.world.gen.noise.NoiseConfig; @@ -15,6 +12,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import com.dfsek.terra.mod.util.SeedHack; + /** * Hack to map noise sampler to seeds @@ -25,8 +24,10 @@ public class NoiseConfigMixin { @Final private MultiNoiseSampler multiNoiseSampler; - @Inject(method = "(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At("TAIL")) - private void mapMultiNoise(ChunkGeneratorSettings chunkGeneratorSettings, Registry noiseRegistry, long seed, CallbackInfo ci) { + @Inject(method = "(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", + at = @At("TAIL")) + private void mapMultiNoise(ChunkGeneratorSettings chunkGeneratorSettings, + Registry noiseRegistry, long seed, CallbackInfo ci) { SeedHack.register(multiNoiseSampler, seed); } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/RegistryMixin.java b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/RegistryMixin.java similarity index 70% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/RegistryMixin.java rename to platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/RegistryMixin.java index 0f6ccd532..8e2c12c70 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/RegistryMixin.java +++ b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/RegistryMixin.java @@ -1,5 +1,4 @@ -package com.dfsek.terra.fabric.mixin.lifecycle; - +package com.dfsek.terra.lifecycle.mixin; import net.minecraft.util.registry.Registry; import org.spongepowered.asm.mixin.Mixin; @@ -7,14 +6,13 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.dfsek.terra.fabric.FabricEntryPoint; +import com.dfsek.terra.lifecycle.util.RegistryUtil; -// Register Terra things to the builtin registries. @Mixin(Registry.class) public class RegistryMixin { @Inject(method = "", at = @At("RETURN")) private static void registerTerraGenerators(CallbackInfo ci) { - FabricEntryPoint.register(); + RegistryUtil.register(); } -} +} \ No newline at end of file diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/MinecraftServerMixin.java b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/lifecycle/MinecraftServerMixin.java similarity index 81% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/MinecraftServerMixin.java rename to platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/lifecycle/MinecraftServerMixin.java index 2a545ebf0..25ac340d0 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/MinecraftServerMixin.java +++ b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/lifecycle/MinecraftServerMixin.java @@ -1,14 +1,11 @@ -package com.dfsek.terra.fabric.mixin.lifecycle; +package com.dfsek.terra.lifecycle.mixin.lifecycle; -import com.mojang.authlib.GameProfileRepository; -import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.datafixers.DataFixer; import net.minecraft.resource.ResourcePackManager; import net.minecraft.server.MinecraftServer; import net.minecraft.server.SaveLoader; import net.minecraft.server.WorldGenerationProgressListenerFactory; import net.minecraft.util.ApiServices; -import net.minecraft.util.UserCache; import net.minecraft.world.level.storage.LevelStorage; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -17,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.net.Proxy; -import com.dfsek.terra.fabric.FabricEntryPoint; +import com.dfsek.terra.lifecycle.LifecyclePlatform; @Mixin(MinecraftServer.class) @@ -30,6 +27,6 @@ public class MinecraftServerMixin { private void injectConstructor(Thread serverThread, LevelStorage.Session session, ResourcePackManager dataPackManager, SaveLoader saveLoader, Proxy proxy, DataFixer dataFixer, ApiServices apiServices, WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory, CallbackInfo ci) { - FabricEntryPoint.getPlatform().setServer((MinecraftServer) (Object) this); + LifecyclePlatform.setServer((MinecraftServer) (Object) this); } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/client/MinecraftClientMixin.java b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/lifecycle/client/MinecraftClientMixin.java similarity index 85% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/client/MinecraftClientMixin.java rename to platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/lifecycle/client/MinecraftClientMixin.java index 620ebf100..30f092786 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/client/MinecraftClientMixin.java +++ b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/lifecycle/client/MinecraftClientMixin.java @@ -15,9 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.lifecycle.client; - -import com.dfsek.terra.fabric.util.LifecycleUtil; +package com.dfsek.terra.lifecycle.mixin.lifecycle.client; import net.minecraft.client.MinecraftClient; import net.minecraft.client.RunArgs; @@ -26,9 +24,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; -import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.util.BiomeUtil; +import com.dfsek.terra.lifecycle.util.LifecycleUtil; @Mixin(MinecraftClient.class) diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/server/ServerMainMixin.java b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/lifecycle/server/ServerMainMixin.java similarity index 83% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/server/ServerMainMixin.java rename to platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/lifecycle/server/ServerMainMixin.java index ecf5e933b..e2e52bd2a 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/server/ServerMainMixin.java +++ b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/mixin/lifecycle/server/ServerMainMixin.java @@ -15,10 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.lifecycle.server; - -import com.dfsek.terra.fabric.util.BiomeUtil; -import com.dfsek.terra.fabric.util.LifecycleUtil; +package com.dfsek.terra.lifecycle.mixin.lifecycle.server; import net.minecraft.server.Main; import org.spongepowered.asm.mixin.Mixin; @@ -26,8 +23,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; -import com.dfsek.terra.fabric.FabricEntryPoint; +import com.dfsek.terra.lifecycle.util.LifecycleUtil; @Mixin(Main.class) diff --git a/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/util/BiomeUtil.java b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/util/BiomeUtil.java new file mode 100644 index 000000000..f0d3e06e6 --- /dev/null +++ b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/util/BiomeUtil.java @@ -0,0 +1,86 @@ +package com.dfsek.terra.lifecycle.util; + +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.BuiltinRegistries; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.village.VillagerType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Objects; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.mod.CommonPlatform; +import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.mod.config.ProtoPlatformBiome; +import com.dfsek.terra.mod.config.VanillaBiomeProperties; +import com.dfsek.terra.mod.mixin.access.VillagerTypeAccessor; +import com.dfsek.terra.mod.util.MinecraftUtil; + + +public final class BiomeUtil { + private static final Logger logger = LoggerFactory.getLogger(BiomeUtil.class); + + private BiomeUtil() { + + } + + public static void registerBiomes() { + logger.info("Registering biomes..."); + CommonPlatform.get().getConfigRegistry().forEach(pack -> { // Register all Terra biomes. + pack.getCheckedRegistry(Biome.class) + .forEach((id, biome) -> registerBiome(biome, pack, id)); + }); + MinecraftUtil.registerFlora(BuiltinRegistries.BIOME); + logger.info("Terra biomes registered."); + } + + /** + * Clones a Vanilla biome and injects Terra data to create a Terra-vanilla biome delegate. + * + * @param biome The Terra BiomeBuilder. + * @param pack The ConfigPack this biome belongs to. + */ + private static void registerBiome(Biome biome, ConfigPack pack, + com.dfsek.terra.api.registry.key.RegistryKey id) { + Registry registry = BuiltinRegistries.BIOME; + RegistryKey vanilla = ((ProtoPlatformBiome) biome.getPlatformBiome()).get(registry); + + + if(pack.getContext().get(PreLoadCompatibilityOptions.class).useVanillaBiomes()) { + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(vanilla); + } else { + VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class); + + net.minecraft.world.biome.Biome minecraftBiome = MinecraftUtil.createBiome(biome, registry.get(vanilla), + vanillaBiomeProperties); + + Identifier identifier = new Identifier("terra", MinecraftUtil.createBiomeID(pack, id)); + + if(registry.containsId(identifier)) { + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(MinecraftUtil.getEntry(registry, identifier) + .orElseThrow() + .getKey() + .orElseThrow()); + } else { + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(BuiltinRegistries.add(registry, + MinecraftUtil.registerKey(identifier) + .getValue(), + minecraftBiome).getKey().orElseThrow()); + } + + Map villagerMap = VillagerTypeAccessor.getBiomeTypeToIdMap(); + + villagerMap.put(RegistryKey.of(Registry.BIOME_KEY, identifier), + Objects.requireNonNullElse(vanillaBiomeProperties.getVillagerType(), + villagerMap.getOrDefault(vanilla, VillagerType.PLAINS))); + + MinecraftUtil.TERRA_BIOME_MAP.computeIfAbsent(vanilla.getValue(), i -> new ArrayList<>()).add(identifier); + } + } + +} diff --git a/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/util/LifecycleUtil.java b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/util/LifecycleUtil.java new file mode 100644 index 000000000..498de58aa --- /dev/null +++ b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/util/LifecycleUtil.java @@ -0,0 +1,19 @@ +package com.dfsek.terra.lifecycle.util; + +import net.minecraft.util.registry.BuiltinRegistries; + +import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; +import com.dfsek.terra.mod.CommonPlatform; + + +public final class LifecycleUtil { + private LifecycleUtil() { + + } + + public static void initialize() { + CommonPlatform.get().getEventManager().callEvent(new PlatformInitializationEvent()); + BiomeUtil.registerBiomes(); + CommonPlatform.get().registerWorldTypes((id, preset) -> BuiltinRegistries.add(BuiltinRegistries.WORLD_PRESET, id, preset)); + } +} diff --git a/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/util/RegistryUtil.java b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/util/RegistryUtil.java new file mode 100644 index 000000000..9f17b89e3 --- /dev/null +++ b/platforms/mixin-lifecycle/src/main/java/com/dfsek/terra/lifecycle/util/RegistryUtil.java @@ -0,0 +1,18 @@ +package com.dfsek.terra.lifecycle.util; + +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import com.dfsek.terra.mod.data.Codecs; + + +public final class RegistryUtil { + private RegistryUtil() { + + } + + public static void register() { + Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.MINECRAFT_CHUNK_GENERATOR_WRAPPER); + Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); + } +} diff --git a/platforms/mixin-lifecycle/src/main/resources/terra.lifecycle.mixins.json b/platforms/mixin-lifecycle/src/main/resources/terra.lifecycle.mixins.json new file mode 100644 index 000000000..7ec5e4d95 --- /dev/null +++ b/platforms/mixin-lifecycle/src/main/resources/terra.lifecycle.mixins.json @@ -0,0 +1,21 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.dfsek.terra.lifecycle.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "NoiseConfigMixin", + "RegistryMixin", + "lifecycle.MinecraftServerMixin" + ], + "client": [ + "lifecycle.client.MinecraftClientMixin" + ], + "server": [ + "lifecycle.server.ServerMainMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "terra.lifecycle.refmap.json" +} \ No newline at end of file diff --git a/platforms/quilt/build.gradle.kts b/platforms/quilt/build.gradle.kts new file mode 100644 index 000000000..940045d47 --- /dev/null +++ b/platforms/quilt/build.gradle.kts @@ -0,0 +1,79 @@ +plugins { + id("dev.architectury.loom") version Versions.Mod.architecuryLoom + id("architectury-plugin") version Versions.Mod.architecturyPlugin + id("io.github.juuxel.loom-quiltflower") version Versions.Mod.loomQuiltflower +} + +architectury { + platformSetupLoomIde() + loader("quilt") +} + +dependencies { + shadedApi(project(":common:implementation:base")) + + annotationProcessor("net.fabricmc:sponge-mixin:${Versions.Mod.mixin}") + annotationProcessor("dev.architectury:architectury-loom:${Versions.Mod.architecuryLoom}") + + + implementation(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } + "developmentQuilt"(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } + shaded(project(path = ":platforms:mixin-common", configuration = "transformProductionQuilt")) { isTransitive = false } + + implementation(project(path = ":platforms:mixin-lifecycle", configuration = "namedElements")) { isTransitive = false } + "developmentQuilt"(project(path = ":platforms:mixin-lifecycle", configuration = "namedElements")) { isTransitive = false } + shaded(project(path = ":platforms:mixin-lifecycle", configuration = "transformProductionQuilt")) { isTransitive = false } + + minecraft("com.mojang:minecraft:${Versions.Mod.minecraft}") + mappings("net.fabricmc:yarn:${Versions.Mod.yarn}:v2") + + modImplementation("org.quiltmc:quilt-loader:${Versions.Quilt.quiltLoader}") + + modImplementation("org.quiltmc.quilted-fabric-api:quilted-fabric-api:${Versions.Quilt.fabricApi}") + + modImplementation("cloud.commandframework", "cloud-fabric", Versions.Libraries.cloud) { + exclude("net.fabricmc") + exclude("net.fabricmc.fabric-api") + } + include("cloud.commandframework", "cloud-fabric", Versions.Libraries.cloud) { + exclude("net.fabricmc") + exclude("net.fabricmc.fabric-api") + } + + modLocalRuntime("com.github.astei:lazydfu:${Versions.Mod.lazyDfu}") { + exclude("net.fabricmc") + exclude("net.fabricmc.fabric-api") + } +} + +loom { + accessWidenerPath.set(project(":platforms:mixin-common").file("src/main/resources/terra.accesswidener")) + + mixin { + defaultRefmapName.set("terra.quilt.refmap.json") + } + + launches { + named("client") { + property("fabric.log.level", "debug") + } + named("server") { + property("fabric.log.level", "debug") + } + } +} + + +addonDir(project.file("./run/config/Terra/addons"), tasks.named("configureLaunch").get()) + +tasks { + compileJava { + options.release.set(17) + } + + remapJar { + injectAccessWidener.set(true) + inputFile.set(shadowJar.get().archiveFile) + archiveFileName.set("${rootProject.name.capitalize()}-quilt-${project.version}.jar") + } +} diff --git a/platforms/quilt/gradle.properties b/platforms/quilt/gradle.properties new file mode 100644 index 000000000..96758ce85 --- /dev/null +++ b/platforms/quilt/gradle.properties @@ -0,0 +1 @@ +loom.platform=quilt \ No newline at end of file diff --git a/platforms/quilt/src/main/java/com/dfsek/terra/quilt/AwfulQuiltHacks.java b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/AwfulQuiltHacks.java new file mode 100644 index 000000000..6dbcbaff4 --- /dev/null +++ b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/AwfulQuiltHacks.java @@ -0,0 +1,44 @@ +package com.dfsek.terra.quilt; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; + + +/** + * So you want to Mixin into Authlib/Brigadier/DataFixerUpper, on Fabric you'll need this guy. + * + *

YOU SHOULD ONLY USE THIS CLASS DURING "preLaunch" and ONLY TARGET A CLASS WHICH IS NOT ANY CLASS YOU MIXIN TO. + *

+ * This will likely not work on Gson because FabricLoader has some special logic related to Gson. + */ +public final class AwfulQuiltHacks { + private static final ClassLoader KNOT_CLASSLOADER = Thread.currentThread().getContextClassLoader(); + private static final Method ADD_URL_METHOD; + static { + Method tempAddUrlMethod = null; + try { + tempAddUrlMethod = KNOT_CLASSLOADER.getClass().getMethod("addURL", URL.class); + tempAddUrlMethod.setAccessible(true); + } catch(ReflectiveOperationException e) { + throw new RuntimeException("Failed to load Classloader fields", e); + } + + ADD_URL_METHOD = tempAddUrlMethod; + } + + private AwfulQuiltHacks() { } + + /** + * Hackily load the package which a mixin may exist within. + *

+ * YOU SHOULD NOT TARGET A CLASS WHICH YOU MIXIN TO. + * + * @param pathOfAClass The path of any class within the package. + */ + public static void hackilyLoadForMixin(String pathOfAClass) + throws ClassNotFoundException, InvocationTargetException, IllegalAccessException { + URL url = Class.forName(pathOfAClass).getProtectionDomain().getCodeSource().getLocation(); + ADD_URL_METHOD.invoke(KNOT_CLASSLOADER, url); + } +} diff --git a/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltAddon.java b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltAddon.java new file mode 100644 index 000000000..f0767fdcf --- /dev/null +++ b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltAddon.java @@ -0,0 +1,17 @@ +package com.dfsek.terra.quilt; + +import com.dfsek.terra.mod.MinecraftAddon; +import com.dfsek.terra.mod.ModPlatform; + + +public class QuiltAddon extends MinecraftAddon { + + public QuiltAddon(ModPlatform modPlatform) { + super(modPlatform); + } + + @Override + public String getID() { + return "terra-quilt"; + } +} \ No newline at end of file diff --git a/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltEntryPoint.java b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltEntryPoint.java new file mode 100644 index 000000000..88f676daf --- /dev/null +++ b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltEntryPoint.java @@ -0,0 +1,52 @@ +/* + * This file is part of Terra. + * + * Terra is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Terra is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Terra. If not, see . + */ + +package com.dfsek.terra.quilt; + +import cloud.commandframework.execution.CommandExecutionCoordinator; +import cloud.commandframework.fabric.FabricServerCommandManager; +import net.minecraft.server.command.ServerCommandSource; +import org.quiltmc.loader.api.ModContainer; +import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.dfsek.terra.api.command.CommandSender; +import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent; + + +public class QuiltEntryPoint implements ModInitializer { + private static final Logger logger = LoggerFactory.getLogger(QuiltEntryPoint.class); + + private static final QuiltPlatform TERRA_PLUGIN = new QuiltPlatform(); + + @Override + public void onInitialize(ModContainer container) { + logger.info("Initializing Terra Quilt mod..."); + + FabricServerCommandManager manager = new FabricServerCommandManager<>( + CommandExecutionCoordinator.simpleCoordinator(), + serverCommandSource -> (CommandSender) serverCommandSource, + commandSender -> (ServerCommandSource) commandSender + ); + + + manager.brigadierManager().setNativeNumberSuggestions(false); + + TERRA_PLUGIN.getEventManager().callEvent(new CommandRegistrationEvent(manager)); + } +} diff --git a/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltPlatform.java b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltPlatform.java new file mode 100644 index 000000000..dfc1a7a18 --- /dev/null +++ b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltPlatform.java @@ -0,0 +1,73 @@ +/* + * This file is part of Terra. + * + * Terra is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Terra is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Terra. If not, see . + */ + +package com.dfsek.terra.quilt; + +import ca.solostudios.strata.Versions; +import ca.solostudios.strata.parser.tokenizer.ParseException; +import ca.solostudios.strata.version.Version; +import org.jetbrains.annotations.NotNull; +import org.quiltmc.loader.api.QuiltLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Collection; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.dfsek.terra.addon.EphemeralAddon; +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.lifecycle.LifecyclePlatform; + + +public class QuiltPlatform extends LifecyclePlatform { + private static final Logger LOGGER = LoggerFactory.getLogger(QuiltPlatform.class); + + @Override + protected Collection getPlatformMods() { + return QuiltLoader.getAllMods().stream().flatMap(mod -> { + String id = mod.metadata().id(); + if(id.equals("terra") || id.equals("minecraft") || id.equals("java")) return Stream.empty(); + try { + Version version = Versions.parseVersion(mod.metadata().version().raw()); + return Stream.of(new EphemeralAddon(version, "quilt:" + id)); + } catch(ParseException e) { + LOGGER.warn( + "Mod {}, version {} does not follow semantic versioning specification, Terra addons will be unable to depend on " + + "it.", + id, mod.metadata().version().raw()); + } + return Stream.empty(); + }).collect(Collectors.toList()); + } + + @Override + public @NotNull String platformName() { + return "Quilt"; + } + + @Override + public @NotNull File getDataFolder() { + return new File(QuiltLoader.getConfigDir().toFile(), "Terra"); + } + + @Override + public BaseAddon getPlatformAddon() { + return new QuiltAddon(this); + } +} diff --git a/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltPreLaunchEntryPoint.java b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltPreLaunchEntryPoint.java new file mode 100644 index 000000000..e4d8cc0aa --- /dev/null +++ b/platforms/quilt/src/main/java/com/dfsek/terra/quilt/QuiltPreLaunchEntryPoint.java @@ -0,0 +1,22 @@ +package com.dfsek.terra.quilt; + +import cloud.commandframework.brigadier.BrigadierMappingBuilder; +import org.quiltmc.loader.api.ModContainer; +import org.quiltmc.loader.api.QuiltLoader; +import org.quiltmc.loader.api.entrypoint.PreLaunchEntrypoint; + +import java.lang.reflect.InvocationTargetException; + + +public class QuiltPreLaunchEntryPoint implements PreLaunchEntrypoint { + @Override + public void onPreLaunch(ModContainer mod) { + if(QuiltLoader.isDevelopmentEnvironment()) { + try { + AwfulQuiltHacks.hackilyLoadForMixin(BrigadierMappingBuilder.class.getName()); + } catch(ClassNotFoundException | InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/platforms/quilt/src/main/resources/assets/terra/icon.png b/platforms/quilt/src/main/resources/assets/terra/icon.png new file mode 100644 index 000000000..a8f458866 Binary files /dev/null and b/platforms/quilt/src/main/resources/assets/terra/icon.png differ diff --git a/platforms/quilt/src/main/resources/assets/terra/lang/en_us.json b/platforms/quilt/src/main/resources/assets/terra/lang/en_us.json new file mode 100644 index 000000000..116199214 --- /dev/null +++ b/platforms/quilt/src/main/resources/assets/terra/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "generator.terra": "Terra" +} + diff --git a/platforms/quilt/src/main/resources/quilt.mod.json b/platforms/quilt/src/main/resources/quilt.mod.json new file mode 100644 index 000000000..0f53988ec --- /dev/null +++ b/platforms/quilt/src/main/resources/quilt.mod.json @@ -0,0 +1,55 @@ +{ + "schema_version": 1, + "quilt_loader": { + "group": "com.dfsek", + "id": "terra", + "version": "@VERSION@", + "metadata": { + "name": "Terra", + "description": "@DESCRIPTION@", + "authors": [ + "dfsek" + ], + "contact": { + "homepage": "@WIKI@", + "sources": "@SOURCE@", + "issues": "@ISSUES@" + }, + "license": "@LICENSE@", + "icon": "assets/terra/icon.png" + }, + "environment": "*", + "intermediate_mappings": "net.fabricmc:intermediary", + "entrypoints": { + "init": [ + "com.dfsek.terra.quilt.QuiltEntryPoint" + ], + "pre_launch": [ + "com.dfsek.terra.quilt.QuiltPreLaunchEntryPoint" + ] + }, + "depends": [ + { + "id": "quilt_loader", + "version": ">=0.17.0" + }, + { + "id": "java", + "version": ">=17" + }, + { + "id": "minecraft", + "version": "1.19.x" + }, + { + "id": "quilted_fabric_api", + "versions": ">=2.0.0-" + } + ] + }, + "mixin": [ + "terra.quilt.mixins.json", + "terra.lifecycle.mixins.json", + "terra.common.mixins.json" + ] +} \ No newline at end of file diff --git a/platforms/quilt/src/main/resources/terra.quilt.mixins.json b/platforms/quilt/src/main/resources/terra.quilt.mixins.json new file mode 100644 index 000000000..91f51b344 --- /dev/null +++ b/platforms/quilt/src/main/resources/terra.quilt.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.dfsek.terra.quilt.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/platforms/sponge/build.gradle.kts b/platforms/sponge/build.gradle.kts.disabled similarity index 100% rename from platforms/sponge/build.gradle.kts rename to platforms/sponge/build.gradle.kts.disabled diff --git a/settings.gradle.kts b/settings.gradle.kts index 7a34493bb..7a1cdc8a0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,9 +24,18 @@ include(":platforms:bukkit:common") pluginManagement { repositories { - maven("https://maven.fabricmc.net") { - name = "Fabric" - } gradlePluginPortal() + maven("https://maven.fabricmc.net") { + name = "Fabric Maven" + } + maven("https://maven.architectury.dev/") { + name = "Architectury Maven" + } + maven("https://files.minecraftforge.net/maven/") { + name = "Forge Maven" + } + maven("https://maven.quiltmc.org/repository/release/") { + name = "Quilt" + } } }