Compare commits

..

75 Commits

Author SHA1 Message Date
dfsek 9abac34b83 Merge pull request #323 from PolyhedralDev/ver/6.1.2
Reimplement Cloud and update Bukkit implementation to 1.19 with Paperweight
2022-06-12 22:26:43 -07:00
dfsek a94c0adeb5 bump versions 2022-06-12 22:22:50 -07:00
dfsek e2088bbbb8 implement stronghold hack on 1.19 bukkit 2022-06-12 22:20:47 -07:00
dfsek 1d7ddc2844 remove ReloadCommandMixin 2022-06-12 21:57:47 -07:00
dfsek 443b372736 reimplement Cloud in Fabric 2022-06-12 21:57:19 -07:00
dfsek 170b3d95ea fix vanilla features generating in terra biomes 2022-06-12 21:57:10 -07:00
dfsek ee88f9e75f apply downfall to 1.19 NMS biomes 2022-06-12 21:36:29 -07:00
dfsek fbc1a38a8d depend on Cloud again in Fabric 2022-06-12 21:33:45 -07:00
dfsek d333b186b1 update cloud to 1.70-SNAPSHOT 2022-06-12 21:31:12 -07:00
dfsek 2363ad8c6c fix reflection proxies 2022-06-12 21:24:19 -07:00
dfsek 55686e2704 shade reflection remapper 2022-06-12 21:20:35 -07:00
dfsek 5a445fefac fix bukkit reobf nms shadow 2022-06-12 20:47:59 -07:00
dfsek 2c85284cfb improve bukkit build 2022-06-12 20:27:14 -07:00
dfsek 0c2a8c6bbc use mapped 1.18 NMS 2022-06-12 18:13:00 -07:00
dfsek b3efaa4f6a use paperweight for 1.18.2 2022-06-12 17:33:14 -07:00
dfsek 69b994df0d 1.19 bukkit compiles now 2022-06-12 17:04:00 -07:00
dfsek 2141e7489e add 1.19 NMS module 2022-06-12 16:12:21 -07:00
dfsek f4f0dca3bd add papermc maven to build setting 2022-06-12 14:33:31 -07:00
dfsek d93f11b5f2 fix resource dumping on windows 2022-06-07 18:39:43 -07:00
dfsek 6f41d16408 bump version 2022-06-07 18:36:41 -07:00
dfsek 0feae25be5 Merge pull request #318 from PolyhedralDev/dev/1.19
Update to 1.19
2022-06-07 15:40:41 -07:00
dfsek d0069ffe83 bump version 2022-06-07 15:13:19 -07:00
dfsek cec83aeb78 Merge pull request #317 from PolyhedralDev/ver/6.0.1
Update addons when new minor and patch versions are available
2022-06-07 15:06:21 -07:00
dfsek c468054bbe spawn entity in serverworld with no world object 2022-06-07 15:05:47 -07:00
dfsek 372931a9c5 fix chunkregion entity spawn crash 2022-06-07 13:56:02 -07:00
dfsek 9a640de8d3 fix file dumping 2022-06-07 11:38:53 -07:00
dfsek f4968e1509 downgrade loom 2022-06-07 11:38:40 -07:00
dfsek 1858bab210 only remove old resources if replacement exists 2022-06-07 11:19:53 -07:00
dfsek c811fd31b1 warn about nonexistent classpath resources 2022-06-07 11:17:07 -07:00
dfsek 098cb740dd fix addon check on fresh install 2022-06-07 11:02:58 -07:00
dfsek 9ac63ce469 fix (??) Loom issues 2022-06-07 11:01:14 -07:00
dfsek db0067a6d9 improve addonDir addon installation 2022-06-07 10:19:42 -07:00
dfsek 5de8df188a specify failed addon path 2022-06-07 08:53:57 -07:00
dfsek fa66bd3c42 create addon dir if it doesn't exist 2022-06-07 08:32:55 -07:00
dfsek e89d473669 update to 1.19 2022-06-07 08:24:58 -07:00
dfsek 90f3138395 Merge remote-tracking branch 'origin/ver/6.0.1' into dev/1.19 2022-06-07 08:18:05 -07:00
dfsek 4e789479e4 update loom 2022-06-07 08:13:59 -07:00
dfsek 3fbb93d157 Merge pull request #312 from duplexsystem/patch-1
Fix fabric config
2022-06-07 00:39:51 -07:00
dfsek 90a48345c2 automatically update addons when minor & patch versions are changed 2022-06-07 00:39:05 -07:00
dfsek 7c00cad4c9 add Pair function API 2022-06-07 00:38:09 -07:00
solo 963e070f92 Merge pull request #313 from duplexsystem/patch-2
fix new lines in PULL_REQUEST_TEMPLATE.md so that check boxes render …
2022-06-06 12:53:05 -04:00
dfsek 908a5dc309 use main executor for generation 2022-06-05 20:59:37 -07:00
dfsek 3adcdb4019 implement air threshold in beardifier 2022-06-05 19:28:08 -07:00
dfsek fbbf09a937 fix beardification 2022-06-05 18:55:43 -07:00
dfsek 254bc93f93 remove unneeded seed from TerraBiomeSource 2022-06-05 17:48:12 -07:00
dfsek ed7bfd2d68 register normal tag to Terra world presets 2022-06-05 17:18:24 -07:00
dfsek 76e8c2d2b1 tag collection util method 2022-06-05 16:57:43 -07:00
dfsek b0aca47e74 registerTags -> registerBiomeTags 2022-06-05 16:56:43 -07:00
dfsek 5d703327db bump versions 2022-06-04 15:11:59 -07:00
dfsek 5ebe09444b Merge pull request #314 from PolyhedralDev/ver/6.0.1
Patch version 6.0.1
2022-06-04 15:05:22 -07:00
dfsek 136ceddff5 getOrDefault with empty list 2022-06-04 14:27:48 -07:00
dfsek b4bee3a65d add ReloadCommandMixin 2022-06-04 01:15:53 -07:00
dfsek f870dab568 correct key used to register world type 2022-06-04 00:36:36 -07:00
dfsek 7027574d35 Merge remote-tracking branch 'origin/ver/6.0.1' into dev/1.19 2022-06-04 00:11:58 -07:00
dfsek c55c19a32e reduce seed hack console spam 2022-06-03 22:36:56 -07:00
dfsek f05e4c1852 register terra world preset 2022-06-03 22:32:30 -07:00
dfsek 1eb2d5c3ac fix mapping change in BeardGenerator 2022-06-03 20:39:14 -07:00
dfsek 3b98f8c0ab add seed hack for biome provider 2022-06-03 20:39:05 -07:00
dfsek 229886d84c update to minecraft 1.19-rc2 2022-06-03 17:24:44 -07:00
dfsek c1dc637eb2 fix run task addon dependency 2022-06-02 22:05:24 -07:00
dfsek a5db29f2ad fix TerraScript EqualsStatement 2022-06-02 22:04:52 -07:00
dfsek 20e6b8bb63 promote terrascript log function to info level 2022-06-02 22:03:36 -07:00
Zoë c7f6e34647 fix new lines in PULL_REQUEST_TEMPLATE.md so that check boxes render correctly on github 2022-06-02 23:44:05 -04:00
Zoë dc59bb5d2e Fix fabric config
the config.yml in the fabric implementation is outdated and presumably unneeded
2022-06-02 23:40:30 -04:00
dfsek 64f66474b1 remove fabric command api dependency 2022-06-02 08:16:25 -07:00
dfsek d4abedaa05 remove cloud Fabric dependency entirely 2022-06-02 08:11:09 -07:00
dfsek 6e18978586 use default block registry 2022-06-02 08:07:21 -07:00
dfsek 5b2e8b7fbd temporarily disable Cloud 2022-06-02 08:05:09 -07:00
dfsek 2608e94980 fix run task addon dependency 2022-06-02 07:47:31 -07:00
dfsek 1d469687cb Merge branch 'master' into dev/1.19 2022-06-02 07:19:14 -07:00
dfsek a9248435a2 Merge pull request #227 from PolyhedralDev/ver/6.0.0
Major Version 6.0 Tracking PR
2022-06-01 11:01:24 -07:00
dfsek d07f9fe341 clean up BeardGenerator 2022-05-30 20:44:29 -07:00
dfsek 9c9487ced6 1.19 fabric compiles now 2022-05-30 20:44:04 -07:00
dfsek 9d131a8992 update FabricChunkGeneratorWrapper 2022-05-30 19:55:42 -07:00
dfsek cd57a32f31 update build to support 1.19 2022-05-30 19:48:37 -07:00
65 changed files with 1545 additions and 964 deletions
+5 -9
View File
@@ -72,19 +72,15 @@
- [ ] Bug Fix <!-- Anything which fixes an issue in Terra. -->
- [ ] Build system <!-- Anything which pretain to the build system. -->
- [ ]
Documentation <!-- Anything which adds or improves documentation for existing features. -->
- [ ] Documentation <!-- Anything which adds or improves documentation for existing features. -->
- [ ] New Feature <!-- Anything which adds new functionality to Terra. -->
- [ ] Performance <!-- Anything which is imrpoves the performance of Terra. -->
- [ ]
Refactoring <!-- Anything which does not add any new code, only moves code around. -->
- [ ]
Repository <!-- Anything which affects the repository. Eg. changes to the `README.md` file. -->
- [ ] Refactoring <!-- Anything which does not add any new code, only moves code around. -->
- [ ] Repository <!-- Anything which affects the repository. Eg. changes to the `README.md` file. -->
- [ ] Revert <!-- Anything which reverts previous commits. -->
- [ ] Style <!-- Anything which updates style. -->
- [ ] Tests <!-- Anything which adds or updates tests. -->
- [ ]
Translation <!-- Anything which is internationalizing the Terra program to other languages. -->
- [ ] Translation <!-- Anything which is internationalizing the Terra program to other languages. -->
#### Compatiblity
@@ -119,4 +115,4 @@
<!--
If it only introduces small changes, you don't need to add tests.
But if you add big changes, you should probably at least write *some* testing, where applicable.
-->
-->
+3 -3
View File
@@ -1,8 +1,8 @@
preRelease(true)
versionProjects(":common:api", version("6.0.0"))
versionProjects(":common:implementation", version("6.0.0"))
versionProjects(":platforms", version("6.0.0"))
versionProjects(":common:api", version("6.1.2"))
versionProjects(":common:implementation", version("6.1.2"))
versionProjects(":platforms", version("6.1.2"))
allprojects {
+16 -2
View File
@@ -3,16 +3,30 @@ plugins {
kotlin("jvm") version embeddedKotlinVersion
}
buildscript {
configurations.all {
resolutionStrategy {
force("org.ow2.asm:asm:9.3") // TODO: remove when ShadowJar updates ASM version
force("org.ow2.asm:asm-commons:9.3")
}
}
}
repositories {
mavenCentral()
gradlePluginPortal()
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven("https://papermc.io/repo/repository/maven-public/") {
name = "PaperMC"
}
}
dependencies {
implementation("gradle.plugin.com.github.jengelman.gradle.plugins:shadow:+")
implementation("org.ow2.asm:asm:9.2")
implementation("org.ow2.asm:asm-tree:9.2")
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.3.5")
implementation("org.ow2.asm:asm:9.3")
implementation("org.ow2.asm:asm-tree:9.3")
implementation("com.dfsek.tectonic:common:4.2.0")
implementation("org.yaml:snakeyaml:1.27")
}
+26 -21
View File
@@ -3,7 +3,6 @@ import java.io.File
import java.util.function.Predicate
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.extra
import kotlin.streams.asStream
@@ -12,27 +11,33 @@ import kotlin.streams.asStream
* Configures a directory where addons will be put.
*/
fun Project.addonDir(dir: File, task: Task) {
task.doFirst {
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()
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)
}
}
}
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)
}
fun matchingAddons(dir: File, matcher: Predicate<File>): Set<File> {
+15 -8
View File
@@ -7,16 +7,19 @@ 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
import org.yaml.snakeyaml.DumperOptions
import org.yaml.snakeyaml.Yaml
fun Project.configureDistribution() {
apply(plugin = "com.github.johnrengelman.shadow")
@@ -29,13 +32,17 @@ fun Project.configureDistribution() {
}
}
val installAddons = tasks.create("installAddons") {
group = "terra"
val compileAddons = tasks.create("compileAddons") {
forSubProjects(":common:addons") {
afterEvaluate {
dependsOn(getJarTask())
}
}
}
val installAddons = tasks.create("installAddons") {
group = "terra"
dependsOn(compileAddons)
doLast {
// https://github.com/johnrengelman/shadow/issues/111
@@ -44,18 +51,18 @@ fun Project.configureDistribution() {
FileSystems.newFileSystem(dest, mapOf("create" to "false"), null).use { fs ->
forSubProjects(":common:addons") {
val jar = getJarTask()
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()}");
if(!Files.exists(addonPath)) {
if (!Files.exists(addonPath)) {
Files.createDirectories(addonPath.parent)
Files.createFile(addonPath)
Files.copy(jar.archiveFile.get().asFile.toPath(), addonPath, StandardCopyOption.REPLACE_EXISTING)
}
}
}
}
@@ -120,7 +127,7 @@ fun Project.configureDistribution() {
relocate("com.dfsek.paralithic", "com.dfsek.terra.lib.paralithic")
relocate("org.json", "com.dfsek.terra.lib.json")
relocate("org.yaml", "com.dfsek.terra.lib.yaml")
finalizedBy(installAddons)
}
+6 -4
View File
@@ -4,7 +4,7 @@ object Versions {
const val paralithic = "0.7.0"
const val strata = "1.1.1"
const val cloud = "1.6.2"
const val cloud = "1.7.0-SNAPSHOT"
const val slf4j = "1.7.36"
const val log4j_slf4j_impl = "2.14.1"
@@ -19,10 +19,12 @@ object Versions {
object Fabric {
const val fabricLoader = "0.14.2"
const val fabricAPI = "0.53.4+1.18.2"
const val minecraft = "1.18.2"
const val yarn = "$minecraft+build.3"
const val fabricAPI = "0.55.1+1.19"
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"
}
object Bukkit {
@@ -1,6 +1,6 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
version = version("1.0.0")
version = version("1.0.1")
dependencies {
api("commons-io:commons-io:2.7")
@@ -32,7 +32,7 @@ public class EqualsStatement extends BinaryOperation<Object, Boolean> {
return FastMath.abs(l.doubleValue() - r.doubleValue()) <= EPSILON;
}
return left.equals(rightUnwrapped);
return leftUnwrapped.equals(rightUnwrapped);
}
@@ -99,7 +99,7 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
.registerFunction("rotationDegrees", new ZeroArgFunctionBuilder<>(arguments -> arguments.getRotation().getDegrees(),
Returnable.ReturnType.NUMBER))
.registerFunction("print",
new UnaryStringFunctionBuilder(string -> LOGGER.debug("[TerraScript:{}] {}", id, string)))
new UnaryStringFunctionBuilder(string -> LOGGER.info("[TerraScript:{}] {}", id, string)))
.registerFunction("abs", new UnaryNumberFunctionBuilder(number -> FastMath.abs(number.doubleValue())))
.registerFunction("pow2", new UnaryNumberFunctionBuilder(number -> FastMath.pow2(number.doubleValue())))
.registerFunction("pow", new BinaryNumberFunctionBuilder(
@@ -11,6 +11,10 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
public final class Pair<L, R> {
@@ -18,6 +22,38 @@ public final class Pair<L, R> {
private final L left;
private final R right;
public static <L, R, T> Function<Pair<L, R>, Pair<T, R>> mapLeft(Function<L, T> function) {
return pair -> of(function.apply(pair.left), pair.right);
}
public static <L, R, T> Function<Pair<L, R>, Pair<L, T>> mapRight(Function<R, T> function) {
return pair -> of(pair.left, function.apply(pair.right));
}
public static <L> Predicate<Pair<L, ?>> testLeft(Predicate<L> predicate) {
return pair -> predicate.test(pair.left);
}
public static <R> Predicate<Pair<?, R>> testRight(Predicate<R> predicate) {
return pair -> predicate.test(pair.right);
}
public static <L> Consumer<Pair<L, ?>> consumeLeft(Consumer<L> consumer) {
return pair -> consumer.accept(pair.left);
}
public static <R> Consumer<Pair<?, R>> consumeRight(Consumer<R> consumer) {
return pair -> consumer.accept(pair.right);
}
public static <R> Function<Pair<?, R>, R> unwrapRight() {
return pair -> pair.right;
}
public static <L> Function<Pair<L, ?>, L> unwrapLeft() {
return pair -> pair.left;
}
private Pair(L left, R right) {
this.left = left;
this.right = right;
@@ -108,4 +144,9 @@ public final class Pair<L, R> {
return Objects.equals(this.left, that.left) && Objects.equals(this.right, that.right);
}
}
@Override
public String toString() {
return String.format("{%s,%s}", left, right);
}
}
@@ -18,27 +18,6 @@
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.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import com.dfsek.terra.addon.BootstrapAddonLoader;
import com.dfsek.terra.addon.DependencySorter;
@@ -58,6 +37,7 @@ import com.dfsek.terra.api.profiler.Profiler;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.api.util.mutable.MutableBoolean;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.GenericLoaders;
@@ -69,6 +49,21 @@ 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}
@@ -113,8 +108,10 @@ public abstract class AbstractPlatform implements Platform {
logger.info("Initializing Terra...");
try(InputStream stream = getClass().getResourceAsStream("/config.yml")) {
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);
}
} catch(IOException e) {
@@ -212,24 +209,85 @@ public abstract class AbstractPlatform implements Platform {
logger.info("No resources config found. Skipping resource dumping.");
return;
}
Path data = getDataFolder().toPath();
Path addonsPath = data.resolve("addons");
Files.createDirectories(addonsPath);
Set<Pair<Path, String>> paths = Files
.walk(addonsPath)
.map(path -> Pair.of(path, data.relativize(path).toString()))
.map(Pair.mapRight(s -> {
if(s.contains("+")) { // remove commit hash
return s.substring(0, s.lastIndexOf('+'));
}
return s;
}))
.filter(Pair.testRight(s -> s.contains("."))) // remove patch version
.map(Pair.mapRight(s -> s.substring(0, s.lastIndexOf('.'))))
.filter(Pair.testRight(s -> s.contains("."))) // remove minor version
.map(Pair.mapRight(s -> s.substring(0, s.lastIndexOf('.'))))
.collect(Collectors.toSet());
Set<String> pathsNoMajor = paths
.stream()
.filter(Pair.testRight(s -> s.contains(".")))
.map(Pair.mapRight(s -> s.substring(0, s.lastIndexOf('.')))) // remove major version
.map(Pair.unwrapRight())
.collect(Collectors.toSet());
String resourceYaml = IOUtils.toString(resourcesConfig, StandardCharsets.UTF_8);
Map<String, List<String>> resources = new Yaml().load(resourceYaml);
resources.forEach((dir, entries) -> entries.forEach(entry -> {
String resourcePath = String.format("%s/%s", dir, entry);
String resourceClassPath = dir + "/" + entry;
String resourcePath = resourceClassPath.replace('/', File.separatorChar);
File resource = new File(getDataFolder(), resourcePath);
if(resource.exists())
return; // dont overwrite
logger.info("Dumping resource {}...", resource.getAbsolutePath());
try {
try(InputStream is = getClass().getResourceAsStream("/" + resourceClassPath)) {
if(is == null) {
logger.error("Resource {} doesn't exist on the classpath!", resourcePath);
return;
}
paths
.stream()
.filter(Pair.testRight(resourcePath::startsWith))
.forEach(Pair.consumeLeft(path -> {
logger.info("Removing outdated resource {}, replacing with {}", path, resourcePath);
try {
Files.delete(path);
} catch(IOException e) {
throw new UncheckedIOException(e);
}
}));
if(pathsNoMajor
.stream()
.anyMatch(resourcePath::startsWith) && // if any share name
paths
.stream()
.map(Pair.unwrapRight())
.noneMatch(resourcePath::startsWith)) { // but dont share major version
logger.warn(
"Addon {} has a new major version available. It will not be automatically updated; you will need to " +
"ensure " +
"compatibility and update manually.",
resourcePath);
}
logger.info("Dumping resource {}...", resource.getAbsolutePath());
resource.getParentFile().mkdirs();
resource.createNewFile();
} catch(IOException e) {
throw new UncheckedIOException(e);
}
logger.debug("Copying resource {}", resourcePath);
try(InputStream is = getClass().getResourceAsStream("/" + resourcePath);
OutputStream os = new FileOutputStream(resource)) {
IOUtils.copy(is, os);
try(OutputStream os = new FileOutputStream(resource)) {
IOUtils.copy(is, os);
}
} catch(IOException e) {
throw new UncheckedIOException(e);
}
@@ -74,21 +74,24 @@ public class BootstrapAddonLoader implements BootstrapBaseAddon<BootstrapBaseAdd
}
} catch(IOException e) {
throw new UncheckedIOException(e);
throw new AddonLoadException("Failed to load addon from path " + addonPath, e);
}
}
@Override
public Iterable<BootstrapBaseAddon<?>> loadAddons(Path addonsFolder, BootstrapAddonClassLoader parent) {
Path bootstrapFolder = addonsFolder.resolve("bootstrap");
logger.debug("Loading bootstrap addons from {}", bootstrapFolder);
try(Stream<Path> bootstrapAddons = Files.walk(bootstrapFolder, 1, FileVisitOption.FOLLOW_LINKS)) {
return bootstrapAddons.filter(path -> path.toFile().isFile())
.filter(path -> path.toFile().canRead())
.filter(path -> path.toString().endsWith(".jar"))
.map(path -> loadAddon(path, parent))
.collect(Collectors.toList());
try {
Path bootstrapFolder = addonsFolder.resolve("bootstrap");
Files.createDirectories(bootstrapFolder);
logger.debug("Loading bootstrap addons from {}", bootstrapFolder);
try(Stream<Path> bootstrapAddons = Files.walk(bootstrapFolder, 1, FileVisitOption.FOLLOW_LINKS)) {
return bootstrapAddons.filter(path -> path.toFile().isFile())
.filter(path -> path.toFile().canRead())
.filter(path -> path.toString().endsWith(".jar"))
.map(path -> loadAddon(path, parent))
.collect(Collectors.toList());
}
} catch(IOException e) {
throw new UncheckedIOException(e);
}
+10 -1
View File
@@ -4,6 +4,9 @@ import java.nio.channels.Channels
import java.nio.file.Files
import java.nio.file.StandardCopyOption
plugins {
id("xyz.jpenilla.run-paper") version "1.0.6"
}
val mcVersion = "1.18.2"
val testDir = "target/server"
@@ -13,9 +16,15 @@ val paperBuild = 350
val paperURL = "https://papermc.io/api/v2/projects/paper/versions/%version%/builds/$paperBuild/downloads/paper-%version%-$paperBuild.jar"
val purpurURL = "https://api.purpurmc.org/v2/purpur/%version%/latest/download"
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
shaded(project(":platforms:bukkit:common"))
shaded(project(":platforms:bukkit:nms:v1_18_R2"))
shaded(project(":platforms:bukkit:nms:v1_18_R2", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R1", configuration = "reobf"))
shaded("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT")
}
val throttleCoreCount = 0
+14 -3
View File
@@ -1,6 +1,17 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
compileOnly("io.papermc.paper:paper-api:1.18.2-R0.1-20220519.005047-123")
compileOnly(group = "org.spigotmc", name = "spigot", version = "1.18.2-R0.1-SNAPSHOT")
paperDevBundle("1.18.2-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT")
}
tasks {
assemble {
dependsOn("reobfJar")
}
}
@@ -1,10 +1,10 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import com.dfsek.terra.api.properties.Properties;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.BiomeBase;
public record NMSBiomeInfo(ResourceKey<BiomeBase> biomeKey) implements Properties {
public record NMSBiomeInfo(ResourceKey<Biome> biomeKey) implements Properties {
}
@@ -3,23 +3,19 @@ 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.IRegistry;
import net.minecraft.core.IRegistryWritable;
import net.minecraft.core.RegistryMaterials;
import net.minecraft.data.RegistryGeneration;
import net.minecraft.resources.MinecraftKey;
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.BiomeBase;
import net.minecraft.world.level.biome.BiomeFog;
import net.minecraft.world.level.biome.BiomeFog.GrassColor;
import net.minecraft.world.level.biome.BiomeSettingsGeneration;
import net.minecraft.world.level.biome.BiomeSettingsMobs;
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.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -29,7 +25,6 @@ import java.util.Objects;
import java.util.Optional;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
@@ -37,49 +32,48 @@ import com.dfsek.terra.registry.master.ConfigRegistry;
public class NMSBiomeInjector {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSBiomeInjector.class);
private static final Map<MinecraftKey, List<MinecraftKey>> terraBiomeMap = new HashMap<>();
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
IRegistryWritable<BiomeBase> biomeRegistry = (IRegistryWritable<BiomeBase>) Registries.biomeRegistry();
Field frozen = RegistryMaterials.class.getDeclaredField("bL"); // registry frozen field
frozen.setAccessible(true);
frozen.set(biomeRegistry, false);
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) Registries.biomeRegistry();
configRegistry.forEach(pack -> pack.getRegistry(Biome.class).forEach((key, biome) -> {
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();
MinecraftKey vanillaMinecraftKey = new MinecraftKey(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
BiomeBase platform = createBiome(
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = createBiome(
biome,
biomeRegistry.a(vanillaMinecraftKey) // get
biomeRegistry.get(vanillaMinecraftKey) // get
);
ResourceKey<BiomeBase> delegateKey = ResourceKey.a(IRegistry.aP, new MinecraftKey("terra", createBiomeID(pack, key)));
ResourceKey<Biome> delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY, new ResourceLocation("terra", createBiomeID(pack, key)));
RegistryGeneration.a(RegistryGeneration.i, delegateKey, platform);
biomeRegistry.a(delegateKey, platform, Lifecycle.stable());
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.a());
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
frozen.set(biomeRegistry, true); // freeze registry again :)
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<TagKey<BiomeBase>, List<Holder<BiomeBase>>> collect = biomeRegistry
.g() // streamKeysAndEntries
Map<TagKey<Biome>, List<Holder<Biome>>> collect = biomeRegistry
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().a().toList())),
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
terraBiomeMap
@@ -90,13 +84,13 @@ public class NMSBiomeInjector {
.forEach(tb -> getEntry(biomeRegistry, tb)
.ifPresentOrElse(
terra -> {
LOGGER.debug(vanilla.e().orElseThrow().a() +
LOGGER.debug(vanilla.unwrapKey().orElseThrow().location() +
" (vanilla for " +
terra.e().orElseThrow().a() +
terra.unwrapKey().orElseThrow().location() +
": " +
vanilla.c().toList());
vanilla.tags().toList());
vanilla.c()
vanilla.tags()
.forEach(
tag -> collect
.computeIfAbsent(tag,
@@ -108,77 +102,63 @@ public class NMSBiomeInjector {
tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.k(); // clearTags
biomeRegistry.a(ImmutableMap.copyOf(collect)); // populateTags
biomeRegistry.resetTags(); // clearTags
biomeRegistry.bindTags(ImmutableMap.copyOf(collect)); // populateTags
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException exception) {
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}
}
public static <T> Optional<Holder<T>> getEntry(IRegistry<T> registry, MinecraftKey identifier) {
return registry.b(identifier)
.flatMap(registry::c)
.map(registry::c);
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.map(registry::getOrCreateHolder);
}
private static BiomeBase createBiome(Biome biome, BiomeBase vanilla)
private static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
BiomeBase.a builder = new BiomeBase.a(); // Builder
Field f = BiomeBase.class.getDeclaredField("l"); // category
f.setAccessible(true);
builder.a((BiomeBase.Geography) f.get(vanilla))
.a(vanilla.c()); // getPrecipitation
Biome.BiomeBuilder builder = new Biome.BiomeBuilder(); // Builder
Field biomeSettingMobsField = BiomeBase.class.getDeclaredField("k"); // spawn settings
biomeSettingMobsField.setAccessible(true);
BiomeSettingsMobs biomeSettingMobs = (BiomeSettingsMobs) biomeSettingMobsField.get(vanilla);
builder.a(biomeSettingMobs);
BiomeSettingsGeneration.a generationBuilder = new BiomeSettingsGeneration.a(); // builder
builder.a(generationBuilder.a())
.a(vanilla.c())
.b(vanilla.h()) // precipitation
.a(vanilla.i()); // temp
BiomeFog.a effects = new BiomeFog.a(); // Builder
effects.a(GrassColor.a); // magic
builder.biomeCategory(Reflection.BIOME.getBiomeCategory(vanilla))
.precipitation(vanilla.getPrecipitation()) // getPrecipitation
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings())
.temperature(vanilla.getBaseTemperature())
.downfall(vanilla.getDownfall());
BiomeSpecialEffects.Builder effects = new BiomeSpecialEffects.Builder();
effects.grassColorModifier(vanilla.getSpecialEffects().getGrassColorModifier());
VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class);
// fog
effects.a(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.f()));
// water
effects.b(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.k()));
// water fog
effects.c(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.l()));
// sky
effects.d(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.a()));
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.j().e().ifPresent(effects::e);
vanilla.getSpecialEffects().getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
} else {
// foliage
effects.e(vanillaBiomeProperties.getFoliageColor());
effects.foliageColorOverride(vanillaBiomeProperties.getFoliageColor());
}
if(vanillaBiomeProperties.getGrassColor() == null) {
vanilla.j().f().ifPresent(effects::f);
vanilla.getSpecialEffects().getGrassColorOverride().ifPresent(effects::grassColorOverride);
} else {
// grass
effects.f(vanillaBiomeProperties.getGrassColor());
effects.grassColorOverride(vanillaBiomeProperties.getGrassColor());
}
builder.specialEffects(effects.build());
builder.a(effects.a()); // build()
return builder.a(); // build()
return builder.build(); // build()
}
public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) {
@@ -1,54 +1,49 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.IRegistry;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.BiomeBase;
import net.minecraft.world.level.biome.Climate.Sampler;
import net.minecraft.world.level.biome.WorldChunkManager;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;
import com.dfsek.terra.api.util.generic.Lazy;
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;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate.Sampler;
import org.jetbrains.annotations.NotNull;
public class NMSBiomeProvider extends WorldChunkManager {
public class NMSBiomeProvider extends BiomeSource {
private final BiomeProvider delegate;
private final WorldChunkManager vanilla;
private final BiomeSource vanilla;
private final long seed;
private final Registry<Biome> biomeRegistry = Registries.biomeRegistry();
private static final Lazy<IRegistry<BiomeBase>> biomeRegistry = Lazy.lazy(() -> {
DedicatedServer dedicatedserver = ((CraftServer) Bukkit.getServer()).getServer();
return dedicatedserver.aU().b(IRegistry.aP);
});
public NMSBiomeProvider(BiomeProvider delegate, WorldChunkManager vanilla, long seed) {
super(delegate.stream().map(biome -> biomeRegistry.value().g(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext().get(NMSBiomeInfo.class).biomeKey())));
public NMSBiomeProvider(BiomeProvider delegate, BiomeSource vanilla, long seed) {
super(delegate.stream()
.map(biome -> Registries.biomeRegistry()
.getOrCreateHolder(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey())));
this.delegate = delegate;
this.vanilla = vanilla;
this.seed = seed;
}
@Override
protected Codec<? extends WorldChunkManager> a() {
return WorldChunkManager.a;
protected Codec<? extends BiomeSource> codec() {
return BiomeSource.CODEC;
}
@Override
public WorldChunkManager a(long seed) {
return withSeed(seed);
}
public WorldChunkManager withSeed(long seed) {
public @NotNull BiomeSource withSeed(long seed) {
return new NMSBiomeProvider(delegate, vanilla, seed);
}
@Override
public Holder<BiomeBase> getNoiseBiome(int x, int y, int z, Sampler sampler) {
//return CraftBlock.biomeToBiomeBase(biomeRegistry.value(), ((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed).getPlatformBiome()).getHandle());
return biomeRegistry.value().g(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed).getPlatformBiome()).getContext().get(NMSBiomeInfo.class).biomeKey());
public @NotNull Holder<Biome> getNoiseBiome(int x, int y, int z, @NotNull Sampler sampler) {
return biomeRegistry.getOrCreateHolder(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed).getPlatformBiome())
.getContext()
.get(NMSBiomeInfo.class)
.biomeKey());
}
}
@@ -8,31 +8,30 @@ 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;
import net.minecraft.core.BlockPosition;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IRegistryCustom;
import net.minecraft.core.SectionPosition;
import net.minecraft.server.level.RegionLimitedWorldAccess;
import net.minecraft.world.level.BlockColumn;
import net.minecraft.world.level.ChunkCoordIntPair;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.biome.BiomeBase;
import net.minecraft.world.level.NoiseColumn;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.biome.Climate;
import net.minecraft.world.level.biome.Climate.Sampler;
import net.minecraft.world.level.block.state.IBlockData;
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.chunk.IChunkAccess;
import net.minecraft.world.level.levelgen.ChunkGeneratorAbstract;
import net.minecraft.world.level.levelgen.HeightMap;
import net.minecraft.world.level.levelgen.WorldGenStage;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.blending.Blender;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement;
import net.minecraft.world.level.levelgen.structure.templatesystem.DefinedStructureManager;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,8 +52,8 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private final long seed;
private final Map<ConcentricRingsStructurePlacement, Lazy<List<ChunkCoordIntPair>>> h = new Object2ObjectArrayMap<>();
private final Map<ConcentricRingsStructurePlacement, Lazy<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap<>();
private static final Lazy<List<ChunkPos>> EMPTY = Lazy.lazy(List::of);
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
@@ -66,103 +65,100 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator {
this.seed = seed;
}
@Override //applyCarvers
public void a(RegionLimitedWorldAccess regionlimitedworldaccess, long var2, BiomeManager var4, StructureManager var5,
IChunkAccess ichunkaccess, WorldGenStage.Features var7) {
@Override
public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull BiomeManager biomeAccess, @NotNull StructureFeatureManager structureAccessor,
@NotNull ChunkAccess chunk, GenerationStep.@NotNull Carving generationStep) {
// no-op
}
@Override // getSeaLevel
public int g() {
return vanilla.g();
}
@Override //fillFromNoise
public CompletableFuture<IChunkAccess> a(Executor executor, Blender blender, StructureManager structuremanager,
IChunkAccess ichunkaccess) {
return vanilla.a(executor, blender, structuremanager, ichunkaccess);
}
@Override //buildSurface. Used to be buildBase
public void a(RegionLimitedWorldAccess regionlimitedworldaccess, StructureManager structuremanager, IChunkAccess ichunkaccess) {
@Override
public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk, @NotNull StructureFeatureManager structureAccessor) {
vanilla.applyBiomeDecoration(world, chunk, structureAccessor);
}
@Override
protected Codec<? extends ChunkGenerator> b() {
return ChunkGeneratorAbstract.a;
public int getSeaLevel() {
return vanilla.getSeaLevel();
}
@Override //fillFromNoise
public @NotNull CompletableFuture<ChunkAccess> fillFromNoise(@NotNull Executor executor, @NotNull Blender blender, @NotNull StructureFeatureManager structureAccessor,
@NotNull ChunkAccess chunk) {
return vanilla.fillFromNoise(executor, blender, structureAccessor, chunk);
}
@Override
public void buildSurface(@NotNull WorldGenRegion region, @NotNull StructureFeatureManager structures, @NotNull ChunkAccess chunk) {
// no-op
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return ChunkGenerator.CODEC;
}
@Override // getColumn
public BlockColumn a(int x, int z, LevelHeightAccessor height) {
IBlockData[] array = new IBlockData[height.v_()];
public @NotNull NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor height) {
BlockState[] array = new BlockState[height.getHeight()];
WorldProperties properties = new NMSWorldProperties(seed, height);
BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties);
for(int y = properties.getMaxHeight() - 1; y >= properties.getMinHeight(); y--) {
array[y - properties.getMinHeight()] = ((CraftBlockData) delegate.getBlock(properties, x, y, z, biomeProvider)
.getHandle()).getState();
}
return new BlockColumn(getMinimumY(), array);
return new NoiseColumn(getMinY(), array);
}
@Override // withSeed
public ChunkGenerator a(long seed) {
public @NotNull ChunkGenerator withSeed(long seed) {
return new NMSChunkGeneratorDelegate(vanilla, pack, biomeSource, seed);
}
//spawnOriginalMobs
public void a(RegionLimitedWorldAccess regionlimitedworldaccess) {
vanilla.a(regionlimitedworldaccess);
}
// getGenDepth
public int f() {
return vanilla.f();
}
// climateSampler
public Sampler d() {
return Climate.a();
}
//getMinY
@Override
public int h() {
return vanilla.h();
public void spawnOriginalMobs(@NotNull WorldGenRegion regionlimitedworldaccess) {
vanilla.spawnOriginalMobs(regionlimitedworldaccess);
}
@Override // getBaseHeight
public int a(int x, int z, HeightMap.Type heightmap, LevelHeightAccessor height) {
WorldProperties properties = new NMSWorldProperties(seed, height);
@Override
public int getGenDepth() {
return vanilla.getGenDepth();
}
@Override
public @NotNull Sampler climateSampler() {
return Climate.empty();
}
@Override
public int getMinY() {
return vanilla.getMinY();
}
@Override
public int getBaseHeight(int x, int z, Heightmap.@NotNull Types heightmap, @NotNull LevelHeightAccessor world) {
WorldProperties properties = new NMSWorldProperties(seed, world);
int y = properties.getMaxHeight();
BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties);
while(y >= getMinimumY() && !heightmap.e().test(
while(y >= getMinY() && !heightmap.isOpaque().test(
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
y--;
}
return y;
}
@Override
public void a(IRegistryCustom iregistrycustom, StructureManager structuremanager, IChunkAccess ichunkaccess,
DefinedStructureManager definedstructuremanager, long i) {
super.a(iregistrycustom, structuremanager, ichunkaccess, definedstructuremanager, i);
}
@Nullable
@Override
public List<ChunkCoordIntPair> a(ConcentricRingsStructurePlacement concentricringsstructureplacement) {
this.i();
return this.h.get(concentricringsstructureplacement).value();
public List<ChunkPos> getRingPositionsFor(@NotNull ConcentricRingsStructurePlacement concentricringsstructureplacement) {
ensureStructuresGenerated();
return ringPositions.getOrDefault(concentricringsstructureplacement, EMPTY).value();
}
private volatile boolean rings = false;
@Override
public synchronized void i() {
public synchronized void ensureStructuresGenerated() {
if(!this.rings) {
super.i();
super.ensureStructuresGenerated();
this.populateStrongholdData();
this.rings = true;
}
@@ -170,70 +166,82 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private void populateStrongholdData() {
LOGGER.info("Generating safe stronghold data. This may take up to a minute.");
Set<Holder<BiomeBase>> set = this.d.b();
a().map(h -> h.a()).forEach((holder) -> { // we dont need the spigot crap because it doesnt touch concentric.
StructurePlacement structureplacement = holder.b();
Set<Holder<Biome>> set = this.runtimeBiomeSource.possibleBiomes();
possibleStructureSets().map(Holder::value).forEach((holder) -> { // we dont need the spigot crap because it doesnt touch concentric.
StructurePlacement structureplacement = holder.placement();
if(structureplacement instanceof ConcentricRingsStructurePlacement concentricringsstructureplacement) {
if(holder.a().stream().anyMatch((structureset_a1) -> structureset_a1.a(set::contains))) {
this.h.put(concentricringsstructureplacement,
Lazy.lazy(() -> this.generateRingPositions(holder, concentricringsstructureplacement)));
if(holder.structures().stream().anyMatch((structureset_a1) -> structureset_a1.generatesInMatchingBiome(set::contains))) {
this.ringPositions.put(concentricringsstructureplacement,
Lazy.lazy(() -> this.generateRingPositions(holder, concentricringsstructureplacement)));
}
}
});
}
private List<ChunkCoordIntPair> generateRingPositions(StructureSet holder,
ConcentricRingsStructurePlacement concentricringsstructureplacement) {
if(concentricringsstructureplacement.d() == 0) {
private List<ChunkPos> generateRingPositions(StructureSet holder,
ConcentricRingsStructurePlacement concentricringsstructureplacement) { // Spigot
if(concentricringsstructureplacement.count() == 0) {
return List.of();
}
List<ChunkCoordIntPair> list = new ArrayList<>();
Set<Holder<BiomeBase>> set = holder.a().stream().flatMap((structureset_a) -> (structureset_a.a().a()).a().a()).collect(
Collectors.toSet());
int i = concentricringsstructureplacement.b();
int j = concentricringsstructureplacement.d();
int k = concentricringsstructureplacement.c();
List<ChunkPos> list = new ArrayList<>();
Set<Holder<Biome>> set = holder
.structures()
.stream()
.flatMap((structureset_a) -> structureset_a.structure().value().biomes().stream())
.collect(Collectors.toSet());
int i = concentricringsstructureplacement.distance();
int j = concentricringsstructureplacement.count();
int k = concentricringsstructureplacement.spread();
Random random = new Random();
random.setSeed(this.j);
double d0 = random.nextDouble() * Math.PI * 2.0;
// Paper start
if(this.conf.strongholdSeed != null && this.structureSets.getResourceKey(holder).orElse(null) ==
net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS) {
random.setSeed(this.conf.strongholdSeed);
} else {
// Paper end
random.setSeed(this.ringPlacementSeed);
} // Paper
double d0 = random.nextDouble() * 3.141592653589793D * 2.0D;
int l = 0;
int i1 = 0;
for(int j1 = 0; j1 < j; ++j1) {
double d1 = (double) (4 * i + i * i1 * 6) + (random.nextDouble() - 0.5) * (double) i * 2.5;
double d1 = (double) (4 * i + i * i1 * 6) + (random.nextDouble() - 0.5D) * (double) i * 2.5D;
int k1 = (int) Math.round(Math.cos(d0) * d1);
int l1 = (int) Math.round(Math.sin(d0) * d1);
int i2 = SectionPosition.a(k1, 8);
int j2 = SectionPosition.a(l1, 8);
int i2 = SectionPos.sectionToBlockCoord(k1, 8);
int j2 = SectionPos.sectionToBlockCoord(l1, 8);
Objects.requireNonNull(set);
Pair<BlockPosition, Holder<BiomeBase>> pair = this.c.a(i2, 0, j2, 112, set::contains, random, this.d());
Pair<BlockPos, Holder<Biome>> pair = this.biomeSource.findBiomeHorizontal(i2, 0, j2, 112, set::contains, random,
this.climateSampler());
if(pair != null) {
BlockPosition blockposition = pair.getFirst();
k1 = SectionPosition.a(blockposition.u());
l1 = SectionPosition.a(blockposition.w());
BlockPos blockposition = (BlockPos) pair.getFirst();
k1 = SectionPos.blockToSectionCoord(blockposition.getX());
l1 = SectionPos.blockToSectionCoord(blockposition.getZ());
}
list.add(new ChunkCoordIntPair(k1, l1));
d0 += 6.283185307179586 / (double) k;
list.add(new ChunkPos(k1, l1));
d0 += 6.283185307179586D / (double) k;
++l;
if(l == k) {
++i1;
l = 0;
k += 2 * k / (i1 + 1);
k = Math.min(k, j - j1);
d0 += random.nextDouble() * Math.PI * 2.0;
d0 += random.nextDouble() * 3.141592653589793D * 2.0D;
}
}
return list;
return list;
}
public int getMinimumY() {
return h();
}
@Override //addDebugScreenInfo
public void a(List<String> arg0, BlockPosition arg1) {
@Override
public void addDebugScreenInfo(@NotNull List<String> arg0, @NotNull BlockPos arg1) {
}
}
@@ -1,6 +1,6 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.server.level.WorldServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
@@ -30,21 +30,21 @@ public class NMSInjectListener implements Listener {
INJECTED.add(event.getWorld());
LOGGER.info("Preparing to take over the world: {}", event.getWorld().getName());
CraftWorld craftWorld = (CraftWorld) event.getWorld();
WorldServer serverWorld = craftWorld.getHandle();
ServerLevel serverWorld = craftWorld.getHandle();
ConfigPack pack = bukkitChunkGeneratorWrapper.getPack();
ChunkGenerator vanilla = serverWorld.k().g();
NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), vanilla.e(), craftWorld.getSeed());
ChunkGenerator vanilla = serverWorld.getChunkSource().getGenerator();
NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), vanilla.getBiomeSource(), craftWorld.getSeed());
NMSChunkGeneratorDelegate custom = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed());
custom.conf = vanilla.conf; // world config from Spigot
serverWorld.k().a.u = custom;
serverWorld.getChunkSource().chunkMap.generator = custom;
LOGGER.info("Successfully injected into world.");
serverWorld.k().a.u.i(); // generate stronghold data now
serverWorld.getChunkSource().chunkMap.generator.ensureStructuresGenerated(); // generate stronghold data now
INJECT_LOCK.unlock();
}
@@ -26,11 +26,11 @@ public class NMSWorldProperties implements WorldProperties {
@Override
public int getMaxHeight() {
return height.ag();
return height.getMaxBuildHeight();
}
@Override
public int getMinHeight() {
return height.u_();
return height.getMinBuildHeight();
}
}
@@ -0,0 +1,35 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.core.MappedRegistry;
import net.minecraft.world.level.biome.Biome;
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
import xyz.jpenilla.reflectionremapper.proxy.ReflectionProxyFactory;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldGetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldSetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
public static final BiomeProxy BIOME;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
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")
Biome.BiomeCategory getBiomeCategory(Biome instance);
}
}
@@ -1,30 +1,30 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.core.IRegistry;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.BiomeBase;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;
public class Registries {
private static <T> IRegistry<T> getRegistry(ResourceKey<IRegistry<T>> key) {
private static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.aU() // getRegistryManager
.b( // getRegistry
key
);
.registryAccess()
.registryOrThrow( // getRegistry
key
);
}
public static IRegistry<BiomeBase> biomeRegistry() {
return getRegistry(IRegistry.aP);
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registry.BIOME_REGISTRY);
}
public static IRegistry<StructureSet> structureSet() {
return getRegistry(IRegistry.aM);
public static Registry<StructureSet> structureSet() {
return getRegistry(Registry.STRUCTURE_SET_REGISTRY);
}
}
@@ -0,0 +1,17 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle("1.19-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT")
}
tasks {
assemble {
dependsOn("reobfJar")
}
}
@@ -0,0 +1,10 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import com.dfsek.terra.api.properties.Properties;
public record NMSBiomeInfo(ResourceKey<Biome> biomeKey) implements Properties {
}
@@ -0,0 +1,162 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
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<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) Registries.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = createBiome(
biome,
Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)) // get
);
ResourceKey<Biome> 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<TagKey<Biome>, List<Holder<Biome>>> collect = biomeRegistry
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
terraBiomeMap
.forEach((vb, terraBiomes) ->
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 <T> Optional<Holder<T>> getEntry(Registry<T> 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)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder();
builder
.precipitation(vanilla.getPrecipitation())
.downfall(vanilla.getDownfall())
.temperature(vanilla.getBaseTemperature())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings());
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 {
// grass
effects.grassColorOverride(vanillaBiomeProperties.getGrassColor());
}
builder.specialEffects(effects.build());
return builder.build();
}
public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) {
return pack.getID()
.toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT);
}
}
@@ -0,0 +1,35 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate.Sampler;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
public class NMSBiomeProvider extends BiomeSource {
private final BiomeProvider delegate;
private final long seed;
private final Registry<Biome> 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())));
this.delegate = delegate;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends BiomeSource> codec() {
return BiomeSource.CODEC;
}
@Override
public @NotNull Holder<Biome> 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());
}
}
@@ -0,0 +1,241 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.NoiseColumn;
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;
import net.minecraft.world.level.levelgen.Heightmap.Types;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.blending.Blender;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import net.minecraft.world.level.levelgen.structure.StructureSet.StructureSelectionEntry;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Stream;
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 final com.dfsek.terra.api.world.chunk.generation.ChunkGenerator delegate;
private final ChunkGenerator vanilla;
private final ConfigPack pack;
private final long seed;
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
super(Registries.structureSet(), Optional.empty(), biomeProvider);
this.delegate = pack.getGeneratorProvider().newInstance(pack);
this.vanilla = vanilla;
this.pack = pack;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return ChunkGenerator.CODEC;
}
@Override
public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull RandomState noiseConfig, @NotNull BiomeManager world,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk, @NotNull Carving carverStep) {
// no-op
}
@Override
public void buildSurface(@NotNull WorldGenRegion region, @NotNull StructureManager structures, @NotNull RandomState noiseConfig,
@NotNull ChunkAccess chunk) {
// no-op
}
@Override
public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk,
@NotNull StructureManager structureAccessor) {
vanilla.applyBiomeDecoration(world, chunk, structureAccessor);
}
@Override
public void spawnOriginalMobs(@NotNull WorldGenRegion region) {
vanilla.spawnOriginalMobs(region);
}
@Override
public int getGenDepth() {
return vanilla.getGenDepth();
}
@Override
public @NotNull CompletableFuture<ChunkAccess> fillFromNoise(@NotNull Executor executor, @NotNull Blender blender,
@NotNull RandomState noiseConfig,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk) {
return vanilla.fillFromNoise(executor, blender, noiseConfig, structureAccessor, chunk);
}
@Override
public int getSeaLevel() {
return vanilla.getSeaLevel();
}
@Override
public int getMinY() {
return vanilla.getMinY();
}
@Override
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);
while(y >= getMinY() && !heightmap.isOpaque().test(
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
y--;
}
return y;
}
@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);
for(int y = properties.getMaxHeight() - 1; y >= properties.getMinHeight(); y--) {
array[y - properties.getMinHeight()] = ((CraftBlockData) delegate.getBlock(properties, x, y, z, biomeProvider)
.getHandle()).getState();
}
return new NoiseColumn(getMinY(), array);
}
@Override
public void addDebugScreenInfo(@NotNull List<String> text, @NotNull RandomState noiseConfig, @NotNull BlockPos pos) {
}
private volatile boolean rings = false;
private final Map<ConcentricRingsStructurePlacement, Lazy<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap<>();
@Override
public void ensureStructuresGenerated(@NotNull RandomState noiseConfig) {
if(!this.rings) {
super.ensureStructuresGenerated(noiseConfig);
this.populateStrongholdData(noiseConfig);
this.rings = true;
}
}
@Override
public List<ChunkPos> getRingPositionsFor(@NotNull ConcentricRingsStructurePlacement structurePlacement, @NotNull RandomState noiseConfig) {
ensureStructuresGenerated(noiseConfig);
return ringPositions.get(structurePlacement).value();
}
private void populateStrongholdData(RandomState noiseConfig) {
LOGGER.info("Generating safe stronghold data. This may take up to a minute.");
Set<Holder<Biome>> set = this.biomeSource.possibleBiomes();
possibleStructureSets().map(Holder::value).forEach((holder) -> {
boolean match = false;
for(StructureSelectionEntry structureset_a : holder.structures()) {
Structure structure = structureset_a.structure().value();
Stream<Holder<Biome>> stream = structure.biomes().stream();
if(stream.anyMatch(set::contains)) {
match = true;
}
}
if (match) {
if (holder.placement() instanceof ConcentricRingsStructurePlacement concentricringsstructureplacement) {
this.ringPositions.put(concentricringsstructureplacement, Lazy.lazy(() -> this.generateRingPositions(holder, noiseConfig, concentricringsstructureplacement)));
}
}
});
}
private List<ChunkPos> generateRingPositions(StructureSet holder, RandomState randomstate,
ConcentricRingsStructurePlacement concentricringsstructureplacement) { // Spigot
if(concentricringsstructureplacement.count() == 0) {
return List.of();
}
List<ChunkPos> list = new ArrayList<>();
int i = concentricringsstructureplacement.distance();
int j = concentricringsstructureplacement.count();
int k = concentricringsstructureplacement.spread();
HolderSet<Biome> holderset = concentricringsstructureplacement.preferredBiomes();
RandomSource randomsource = RandomSource.create();
if(this.conf.strongholdSeed != null && this.structureSets.getResourceKey(holder).orElse(null) ==
net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS) {
randomsource.setSeed(this.conf.strongholdSeed);
} else {
randomsource.setSeed(randomstate.legacyLevelSeed());
}
double d0 = randomsource.nextDouble() * 3.141592653589793D * 2.0D;
int l = 0;
int i1 = 0;
for(int j1 = 0; j1 < j; ++j1) {
double d1 = (double) (4 * i + i * i1 * 6) + (randomsource.nextDouble() - 0.5D) * (double) i * 2.5D;
int k1 = (int) Math.round(Math.cos(d0) * d1);
int l1 = (int) Math.round(Math.sin(d0) * d1);
int i2 = SectionPos.sectionToBlockCoord(k1, 8);
int j2 = SectionPos.sectionToBlockCoord(l1, 8);
Objects.requireNonNull(holderset);
Pair<BlockPos, Holder<Biome>> pair = this.biomeSource.findBiomeHorizontal(i2, 0, j2, 112, holderset::contains, randomsource,
randomstate.sampler());
if(pair != null) {
BlockPos blockposition = pair.getFirst();
k1 = SectionPos.blockToSectionCoord(blockposition.getX());
l1 = SectionPos.blockToSectionCoord(blockposition.getZ());
}
list.add(new ChunkPos(k1, l1));
d0 += 6.283185307179586D / (double) k;
++l;
if(l == k) {
++i1;
l = 0;
k += 2 * k / (i1 + 1);
k = Math.min(k, j - j1);
d0 += randomsource.nextDouble() * 3.141592653589793D * 2.0D;
}
}
return list;
}
}
@@ -0,0 +1,15 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import org.bukkit.Bukkit;
import com.dfsek.terra.bukkit.PlatformImpl;
import com.dfsek.terra.bukkit.nms.Initializer;
public class NMSInitializer implements Initializer {
@Override
public void initialize(PlatformImpl platform) {
NMSBiomeInjector.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}
@@ -0,0 +1,50 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.generator.BukkitChunkGeneratorWrapper;
public class NMSInjectListener implements Listener {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSInjectListener.class);
private static final Set<World> INJECTED = new HashSet<>();
private static final ReentrantLock INJECT_LOCK = new ReentrantLock();
@EventHandler
public void onWorldInit(WorldInitEvent event) {
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());
custom.conf = vanilla.conf; // world config from Spigot
serverWorld.getChunkSource().chunkMap.generator = custom;
LOGGER.info("Successfully injected into world.");
INJECT_LOCK.unlock();
}
}
}
@@ -0,0 +1,36 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.world.level.LevelHeightAccessor;
import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSWorldProperties implements WorldProperties {
private final long seed;
private final LevelHeightAccessor height;
public NMSWorldProperties(long seed, LevelHeightAccessor height) {
this.seed = seed;
this.height = height;
}
@Override
public Object getHandle() {
return height;
}
@Override
public long getSeed() {
return seed;
}
@Override
public int getMaxHeight() {
return height.getMaxBuildHeight();
}
@Override
public int getMinHeight() {
return height.getMinBuildHeight();
}
}
@@ -0,0 +1,25 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.core.MappedRegistry;
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
import xyz.jpenilla.reflectionremapper.proxy.ReflectionProxyFactory;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldSetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper, Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
}
@@ -0,0 +1,30 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
public class Registries {
private static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.registryAccess()
.registryOrThrow( // getRegistry
key
);
}
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registry.BIOME_REGISTRY);
}
public static Registry<StructureSet> structureSet() {
return getRegistry(Registry.STRUCTURE_SET_REGISTRY);
}
}
+6 -2
View File
@@ -3,7 +3,7 @@ import com.modrinth.minotaur.TaskModrinthUpload
import net.fabricmc.loom.task.RemapJarTask
plugins {
id("fabric-loom").version("0.11-SNAPSHOT")
id("fabric-loom").version(Versions.Fabric.loom)
id("com.modrinth.minotaur").version("1.1.0")
}
@@ -15,7 +15,7 @@ dependencies {
modImplementation("net.fabricmc:fabric-loader:${Versions.Fabric.fabricLoader}")
setOf("fabric-command-api-v1", "fabric-lifecycle-events-v1", "fabric-resource-loader-v0", "fabric-api-base").forEach { apiModule ->
setOf("fabric-lifecycle-events-v1", "fabric-resource-loader-v0", "fabric-api-base", "fabric-command-api-v2").forEach { apiModule ->
val module = fabricApi.module(apiModule, Versions.Fabric.fabricAPI)
modImplementation(module)
include(module)
@@ -24,6 +24,10 @@ dependencies {
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))
include("cloud.commandframework", "cloud-fabric", Versions.Libraries.cloud)
}
@@ -18,16 +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.api.command.CommandSender;
import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent;
import com.dfsek.terra.fabric.data.Codecs;
@@ -29,7 +29,6 @@ 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.Category;
import net.minecraft.world.biome.Biome.Precipitation;
import net.minecraft.world.biome.BiomeEffects.GrassColorModifier;
import org.jetbrains.annotations.NotNull;
@@ -39,6 +38,7 @@ 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;
@@ -68,6 +68,10 @@ public class PlatformImpl extends AbstractPlatform {
this.server = server;
}
public MinecraftServer getServer() {
return server;
}
@Override
public boolean reload() {
getTerraConfig().load(this);
@@ -157,9 +161,10 @@ public class PlatformImpl extends AbstractPlatform {
throw new LoadException("Invalid identifier: " + o, depthTracker);
return identifier;
})
.registerLoader(Precipitation.class, (type, o, loader, depthTracker) -> Precipitation.byName((String) o))
.registerLoader(Category.class, (type, o, loader, depthTracker) -> Category.byName((String) o))
.registerLoader(GrassColorModifier.class, (type, o, loader, depthTracker) -> GrassColorModifier.byName((String) o));
.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)));
}
@@ -38,6 +38,10 @@ public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties {
@Default
private double beardThreshold = 0.5;
@Value("fabric.beard.air-threshold")
@Default
private double airThreshold = -0.5;
public boolean useVanillaBiomes() {
return vanillaBiomes;
}
@@ -49,4 +53,8 @@ public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties {
public double getBeardThreshold() {
return beardThreshold;
}
public double getAirThreshold() {
return airThreshold;
}
}
@@ -3,7 +3,6 @@ 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.Category;
import net.minecraft.world.biome.Biome.Precipitation;
import net.minecraft.world.biome.BiomeEffects.GrassColorModifier;
@@ -43,10 +42,6 @@ public class VanillaBiomeProperties implements ConfigTemplate, Properties {
@Default
private Precipitation precipitation = null;
@Value("climate.category")
@Default
private Category category = null;
public Integer getFogColor() {
return fogColor;
}
@@ -71,10 +66,6 @@ public class VanillaBiomeProperties implements ConfigTemplate, Properties {
return skyColor;
}
public Category getCategory() {
return category;
}
public Precipitation getPrecipitation() {
return precipitation;
}
@@ -39,32 +39,27 @@ public final class Codecs {
.fieldOf("biome_registry")
.stable()
.forGetter(TerraBiomeSource::getBiomeRegistry),
Codec.LONG.fieldOf("seed")
.stable()
.forGetter(TerraBiomeSource::getSeed),
CONFIG_PACK.fieldOf("pack")
.stable()
.forGetter(TerraBiomeSource::getPack))
.apply(instance, instance.stable(TerraBiomeSource::new)));
public static final Codec<FabricChunkGeneratorWrapper> FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder.create(
instance -> instance.group(
RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY)
.fieldOf("structure_registry")
.stable()
.forGetter(FabricChunkGeneratorWrapper::getNoiseRegistry),
TERRA_BIOME_SOURCE.fieldOf("biome_source")
.stable()
.forGetter(FabricChunkGeneratorWrapper::getBiomeSource),
Codec.LONG.fieldOf("seed")
.stable()
.forGetter(FabricChunkGeneratorWrapper::getSeed),
CONFIG_PACK.fieldOf("pack")
.stable()
.forGetter(FabricChunkGeneratorWrapper::getPack),
ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings")
.stable()
.forGetter(FabricChunkGeneratorWrapper::getSettings)
).apply(instance, instance.stable(FabricChunkGeneratorWrapper::new))
);
public static final Codec<FabricChunkGeneratorWrapper> FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder
.create(
instance -> instance.group(
RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY)
.fieldOf("structure_registry")
.stable()
.forGetter(FabricChunkGeneratorWrapper::getNoiseRegistry),
TERRA_BIOME_SOURCE.fieldOf("biome_source")
.stable()
.forGetter(FabricChunkGeneratorWrapper::getBiomeSource),
CONFIG_PACK.fieldOf("pack")
.stable()
.forGetter(FabricChunkGeneratorWrapper::getPack),
ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings")
.stable()
.forGetter(FabricChunkGeneratorWrapper::getSettings)
).apply(instance, instance.stable(FabricChunkGeneratorWrapper::new))
);
}
@@ -1,178 +0,0 @@
package com.dfsek.terra.fabric.generation;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectList;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import net.minecraft.block.BlockState;
import net.minecraft.structure.JigsawJunction;
import net.minecraft.structure.PoolStructurePiece;
import net.minecraft.structure.StructurePiece;
import net.minecraft.structure.StructureStart;
import net.minecraft.structure.pool.StructurePool.Projection;
import net.minecraft.util.Util;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.StructureAccessor;
import net.minecraft.world.gen.StructureWeightType;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
import com.dfsek.terra.api.world.info.WorldProperties;
// net.minecraft.world.gen.StructureWeightSampler
public class BeardGenerator {
private static final float[] STRUCTURE_WEIGHT_TABLE = Util.make(new float[13824], array -> {
for(int i = 0; i < 24; ++i) {
for(int j = 0; j < 24; ++j) {
for(int k = 0; k < 24; ++k) {
array[i * 24 * 24 + j * 24 + k] = (float) calculateStructureWeight(j - 12, k - 12, i - 12);
}
}
}
});
private final ObjectList<StructurePiece> pieces;
private final ObjectList<JigsawJunction> junctions;
private final ObjectListIterator<StructurePiece> pieceIterator;
private final ObjectListIterator<JigsawJunction> junctionIterator;
private final Chunk chunk;
private final int minY;
private final int maxY;
private final double threshold;
public BeardGenerator(StructureAccessor structureAccessor, Chunk chunk, double threshold) {
this.chunk = chunk;
this.threshold = threshold;
ChunkPos chunkPos = chunk.getPos();
int i = chunkPos.getStartX();
int j = chunkPos.getStartZ();
this.junctions = new ObjectArrayList<>(32);
this.pieces = new ObjectArrayList<>(10);
int minY = chunk.getBottomY();
int maxY = chunk.getTopY();
for(StructureStart start : structureAccessor.method_41035(ChunkSectionPos.from(chunk),
configuredStructureFeature -> configuredStructureFeature.field_37144)) {
for(StructurePiece structurePiece : start.getChildren()) {
if(!structurePiece.intersectsChunk(chunkPos, 12)) continue;
if(structurePiece instanceof PoolStructurePiece poolStructurePiece) {
Projection projection = poolStructurePiece.getPoolElement().getProjection();
if(projection == Projection.RIGID) {
this.pieces.add(poolStructurePiece);
}
for(JigsawJunction jigsawJunction : poolStructurePiece.getJunctions()) {
int k = jigsawJunction.getSourceX();
int l = jigsawJunction.getSourceZ();
if(k <= i - 12 || l <= j - 12 || k >= i + 15 + 12 || l >= j + 15 + 12) continue;
maxY = Math.max(maxY, jigsawJunction.getSourceGroundY());
minY = Math.min(minY, jigsawJunction.getSourceGroundY());
this.junctions.add(jigsawJunction);
}
continue;
}
maxY = Math.max(maxY, structurePiece.getCenter().getY());
minY = Math.min(minY, structurePiece.getCenter().getY());
this.pieces.add(structurePiece);
}
}
this.pieceIterator = this.pieces.iterator();
this.junctionIterator = this.junctions.iterator();
this.minY = minY;
this.maxY = maxY;
}
private static double getMagnitudeWeight(int x, int y, int z) {
double d = MathHelper.magnitude(x, (double) y / 2.0, z);
return MathHelper.clampedLerpFromProgress(d, 0.0, 6.0, 1.0, 0.0);
}
/**
* Gets the structure weight from the array from the given position, or 0 if the position is out of bounds.
*/
private static double getStructureWeight(int x, int y, int z) {
int xOffset = x + 12;
int yOffset = y + 12;
int zOffset = z + 12;
if(xOffset < 0 || xOffset >= 24) {
return 0.0;
}
if(yOffset < 0 || yOffset >= 24) {
return 0.0;
}
if(zOffset < 0 || zOffset >= 24) {
return 0.0;
}
return STRUCTURE_WEIGHT_TABLE[zOffset * 24 * 24 + xOffset * 24 + yOffset];
}
/**
* Calculates the structure weight for the given position.
* <p>The weight increases as x and z approach {@code (0, 0)}, and positive y values make the weight negative while negative y
* values make the weight positive.
*/
private static double calculateStructureWeight(int x, int y, int z) {
double horizontalDistanceSquared = x * x + z * z;
double yOffset = y + 0.5;
double verticalSquared = yOffset * yOffset;
double naturalDistance = Math.pow(Math.E, -(verticalSquared / 16.0 + horizontalDistanceSquared / 16.0));
double inverseSquareRootDistance = -yOffset * MathHelper.fastInverseSqrt(verticalSquared / 2.0 + horizontalDistanceSquared / 2.0) /
2.0;
return inverseSquareRootDistance * naturalDistance;
}
public void generate(ChunkGenerator generator, WorldProperties worldProperties, BiomeProvider biomeProvider) {
int xi = chunk.getPos().x << 4;
int zi = chunk.getPos().z << 4;
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
int depth = 0;
for(int y = maxY; y >= minY; y--) {
if(calculateNoise(x + xi, y, z + zi) > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), (BlockState) generator
.getPalette(x + xi, y, z + zi, worldProperties, biomeProvider)
.get(depth, x + xi, y, z + zi, worldProperties.getSeed()), false);
depth++;
} else {
depth = 0;
}
}
}
}
}
public double calculateNoise(int x, int y, int z) {
double noise = 0.0;
while(this.pieceIterator.hasNext()) {
StructurePiece structurePiece = this.pieceIterator.next();
BlockBox blockBox = structurePiece.getBoundingBox();
int structureX = Math.max(0, Math.max(blockBox.getMinX() - x, x - blockBox.getMaxX()));
int structureY = y - (blockBox.getMinY() + (structurePiece instanceof PoolStructurePiece
? ((PoolStructurePiece) structurePiece).getGroundLevelDelta()
: 0));
int structureZ = Math.max(0, Math.max(blockBox.getMinZ() - z, z - blockBox.getMaxZ()));
StructureWeightType structureWeightType = structurePiece.getWeightType();
if(structureWeightType == StructureWeightType.BURY) {
noise += getMagnitudeWeight(structureX, structureY, structureZ);
continue;
}
if(structureWeightType != StructureWeightType.BEARD) continue;
noise += getStructureWeight(structureX, structureY, structureZ) * 0.8;
}
this.pieceIterator.back(this.pieces.size());
while(this.junctionIterator.hasNext()) {
JigsawJunction structurePiece = this.junctionIterator.next();
int structureX = x - structurePiece.getSourceX();
int structureY = y - structurePiece.getSourceGroundY();
int structureZ = z - structurePiece.getSourceZ();
noise += getStructureWeight(structureX, structureY, structureZ) * 0.4;
}
this.junctionIterator.back(this.junctions.size());
return noise;
}
}
@@ -17,32 +17,34 @@
package com.dfsek.terra.fabric.generation;
import com.dfsek.terra.api.world.info.WorldProperties;
import com.mojang.serialization.Codec;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.structure.StructureSet;
import net.minecraft.util.Util;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.random.CheckedRandom;
import net.minecraft.util.math.random.ChunkRandom;
import net.minecraft.util.math.random.RandomSeed;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.world.ChunkRegion;
import net.minecraft.world.HeightLimitView;
import net.minecraft.world.Heightmap;
import net.minecraft.world.Heightmap.Type;
import net.minecraft.world.SpawnHelper;
import net.minecraft.world.StructureWorldAccess;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.source.BiomeAccess;
import net.minecraft.world.biome.source.util.MultiNoiseUtil;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.GenerationStep.Carver;
import net.minecraft.world.gen.StructureAccessor;
import net.minecraft.world.gen.StructureWeightSampler;
import net.minecraft.world.gen.chunk.Blender;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
import net.minecraft.world.gen.chunk.VerticalBlockSample;
import net.minecraft.world.gen.random.AtomicSimpleRandom;
import net.minecraft.world.gen.random.ChunkRandom;
import net.minecraft.world.gen.random.RandomSeed;
import net.minecraft.world.gen.densityfunction.DensityFunction.UnblendedNoisePos;
import net.minecraft.world.gen.noise.NoiseConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,6 +60,7 @@ import com.dfsek.terra.api.world.chunk.generation.ProtoChunk;
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;
@@ -67,16 +70,15 @@ import com.dfsek.terra.fabric.util.FabricAdapter;
public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper {
private static final Logger logger = LoggerFactory.getLogger(FabricChunkGeneratorWrapper.class);
private final long seed;
private final TerraBiomeSource biomeSource;
private final Registry<StructureSet> noiseRegistry;
private final RegistryEntry<ChunkGeneratorSettings> settings;
private ChunkGenerator delegate;
private ConfigPack pack;
public FabricChunkGeneratorWrapper(Registry<StructureSet> noiseRegistry, TerraBiomeSource biomeSource, long seed, ConfigPack configPack,
public FabricChunkGeneratorWrapper(Registry<StructureSet> noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack,
RegistryEntry<ChunkGeneratorSettings> settingsSupplier) {
super(noiseRegistry, Optional.empty(), biomeSource, biomeSource, seed);
super(noiseRegistry, Optional.empty(), biomeSource);
this.noiseRegistry = noiseRegistry;
this.pack = configPack;
this.settings = settingsSupplier;
@@ -84,8 +86,6 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
this.delegate = pack.getGeneratorProvider().newInstance(pack);
logger.info("Loading world with config pack {}", pack.getID());
this.biomeSource = biomeSource;
this.seed = seed;
}
public Registry<StructureSet> getNoiseRegistry() {
@@ -96,29 +96,21 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
protected Codec<? extends net.minecraft.world.gen.chunk.ChunkGenerator> getCodec() {
return Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER;
}
@Override
public net.minecraft.world.gen.chunk.ChunkGenerator withSeed(long seed) {
return new FabricChunkGeneratorWrapper(noiseRegistry, (TerraBiomeSource) this.biomeSource.withSeed(seed), seed, pack, settings);
}
@Override
public MultiNoiseUtil.MultiNoiseSampler getMultiNoiseSampler() {
return MultiNoiseUtil.method_40443(); // zero
}
@Override
public void buildSurface(ChunkRegion region, StructureAccessor structures, Chunk chunk) {
public void buildSurface(ChunkRegion region, StructureAccessor structures, NoiseConfig noiseConfig, Chunk chunk) {
// no op
}
@Override
public void populateEntities(ChunkRegion region) {
ChunkPos chunkPos = region.getCenterPos();
RegistryEntry<Biome> biome = region.getBiome(chunkPos.getStartPos().withY(region.getTopY() - 1));
ChunkRandom chunkRandom = new ChunkRandom(new AtomicSimpleRandom(RandomSeed.getSeed()));
chunkRandom.setPopulationSeed(region.getSeed(), chunkPos.getStartX(), chunkPos.getStartZ());
SpawnHelper.populateEntities(region, biome, chunkPos, chunkRandom);
if (!this.settings.value().mobGenerationDisabled()) {
ChunkPos chunkPos = region.getCenterPos();
RegistryEntry<Biome> registryEntry = region.getBiome(chunkPos.getStartPos().withY(region.getTopY() - 1));
ChunkRandom chunkRandom = new ChunkRandom(new CheckedRandom(RandomSeed.getSeed()));
chunkRandom.setPopulationSeed(region.getSeed(), chunkPos.getStartX(), chunkPos.getStartZ());
SpawnHelper.populateEntities(region, registryEntry, chunkPos, chunkRandom);
}
}
@Override
@@ -126,20 +118,49 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
return settings.value().generationShapeConfig().height();
}
@Override
public CompletableFuture<Chunk> populateNoise(Executor executor, Blender arg, StructureAccessor structureAccessor, Chunk chunk) {
public CompletableFuture<Chunk> 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);
delegate.generateChunkData((ProtoChunk) chunk, world, biomeProvider, chunk.getPos().x, chunk.getPos().z);
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
new BeardGenerator(structureAccessor, chunk, compatibilityOptions.getBeardThreshold()).generate(delegate, world,
biomeProvider);
beard(structureAccessor, chunk, world, biomeProvider, compatibilityOptions);
}
return chunk;
}, executor);
}, Util.getMainWorkerExecutor());
}
private void beard(StructureAccessor structureAccessor, Chunk chunk, WorldProperties world, BiomeProvider biomeProvider,
PreLoadCompatibilityOptions compatibilityOptions) {
StructureWeightSampler structureWeightSampler = StructureWeightSampler.method_42695(structureAccessor, chunk.getPos());
double threshold = compatibilityOptions.getBeardThreshold();
double airThreshold = compatibilityOptions.getAirThreshold();
int xi = chunk.getPos().x << 4;
int zi = chunk.getPos().z << 4;
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
int depth = 0;
for(int y = world.getMaxHeight(); y >= world.getMinHeight(); y--) {
double noise = structureWeightSampler.sample(new UnblendedNoisePos(x + xi, y, z + zi));
if(noise > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), (BlockState) delegate
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed()), false);
depth++;
} else if(noise < airThreshold) {
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.getDefaultState(), false);
} else {
depth = 0;
}
}
}
}
}
@Override
@@ -162,10 +183,11 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
return settings.value().generationShapeConfig().minimumY();
}
@Override
public int getHeight(int x, int z, Heightmap.Type heightmap, HeightLimitView height) {
public int getHeight(int x, int z, Type heightmap, HeightLimitView height, NoiseConfig noiseConfig) {
int y = height.getTopY();
WorldProperties properties = FabricAdapter.adapt(height, seed);
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))) {
@@ -175,9 +197,9 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
}
@Override
public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView height) {
public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView height, NoiseConfig noiseConfig) {
BlockState[] array = new BlockState[height.getHeight()];
WorldProperties properties = FabricAdapter.adapt(height, seed);
WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed());
BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties);
for(int y = height.getTopY() - 1; y >= height.getBottomY(); y--) {
array[y - height.getBottomY()] = (BlockState) delegate.getBlock(properties, x, y, z, biomeProvider);
@@ -186,7 +208,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
}
@Override
public void getDebugHudText(List<String> text, BlockPos pos) {
public void getDebugHudText(List<String> text, NoiseConfig noiseConfig, BlockPos pos) {
}
@@ -203,9 +225,9 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
}
@Override
public void carve(ChunkRegion chunkRegion, long seed, BiomeAccess biomeAccess, StructureAccessor structureAccessor, Chunk chunk,
GenerationStep.Carver generationStep) {
public void carve(ChunkRegion chunkRegion, long seed, NoiseConfig noiseConfig, BiomeAccess world, StructureAccessor structureAccessor,
Chunk chunk, Carver carverStep) {
// no op
}
@Override
@@ -213,10 +235,6 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
return delegate;
}
public long getSeed() {
return seed;
}
public RegistryEntry<ChunkGeneratorSettings> getSettings() {
return settings;
}
@@ -22,7 +22,11 @@ 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;
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;
@@ -30,6 +34,7 @@ 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;
@@ -37,17 +42,15 @@ public class TerraBiomeSource extends BiomeSource {
private static final Logger LOGGER = LoggerFactory.getLogger(TerraBiomeSource.class);
private final Registry<net.minecraft.world.biome.Biome> biomeRegistry;
private final long seed;
private ConfigPack pack;
public TerraBiomeSource(Registry<net.minecraft.world.biome.Biome> biomes, long seed, ConfigPack pack) {
public TerraBiomeSource(Registry<net.minecraft.world.biome.Biome> biomes, ConfigPack pack) {
super(StreamSupport
.stream(pack.getBiomeProvider()
.getBiomes()
.spliterator(), false)
.map(b -> biomes.getOrCreateEntry(((ProtoPlatformBiome) b.getPlatformBiome()).getDelegate())));
this.biomeRegistry = biomes;
this.seed = seed;
this.pack = pack;
LOGGER.debug("Biomes: " + getBiomes());
@@ -58,17 +61,12 @@ public class TerraBiomeSource extends BiomeSource {
return Codecs.TERRA_BIOME_SOURCE;
}
@Override
public BiomeSource withSeed(long seed) {
return new TerraBiomeSource(this.biomeRegistry, seed, pack);
}
@Override
public RegistryEntry<net.minecraft.world.biome.Biome> getBiome(int biomeX, int biomeY, int biomeZ, MultiNoiseSampler noiseSampler) {
return biomeRegistry
.entryOf(((ProtoPlatformBiome) pack
.getBiomeProvider()
.getBiome(biomeX << 2, biomeY << 2, biomeZ << 2, seed)
.getBiome(biomeX << 2, biomeY << 2, biomeZ << 2, SeedHack.getSeed(noiseSampler))
.getPlatformBiome()).getDelegate()
);
}
@@ -88,8 +86,4 @@ public class TerraBiomeSource extends BiomeSource {
public void setPack(ConfigPack pack) {
this.pack = pack;
}
public long getSeed() {
return seed;
}
}
@@ -1,51 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.fabric.generation;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.world.GeneratorType;
import net.minecraft.structure.StructureSet;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
import com.dfsek.terra.api.config.ConfigPack;
@Environment(EnvType.CLIENT)
public class TerraGeneratorType extends GeneratorType {
private final ConfigPack pack;
public TerraGeneratorType(ConfigPack pack) {
super("terra." + pack.getID());
this.pack = pack;
}
@Override
protected ChunkGenerator getChunkGenerator(DynamicRegistryManager manager, long seed) {
Registry<ChunkGeneratorSettings> chunkGeneratorSettingsRegistry = manager.get(Registry.CHUNK_GENERATOR_SETTINGS_KEY);
RegistryEntry<ChunkGeneratorSettings>
settingsSupplier = chunkGeneratorSettingsRegistry.getEntry(ChunkGeneratorSettings.OVERWORLD).orElseThrow();
Registry<StructureSet> noiseRegistry = manager.get(Registry.STRUCTURE_SET_KEY);
return new FabricChunkGeneratorWrapper(noiseRegistry, new TerraBiomeSource(manager.get(Registry.BIOME_KEY), seed, pack), seed, pack,
settingsSupplier);
}
}
@@ -17,8 +17,11 @@
package com.dfsek.terra.fabric.handle;
import com.dfsek.terra.fabric.FabricEntryPoint;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.command.argument.ItemStackArgumentType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
@@ -36,7 +39,7 @@ public class FabricItemHandle implements ItemHandle {
@Override
public Item createItem(String data) {
try {
return (Item) new ItemStackArgumentType().parse(new StringReader(data)).getItem();
return (Item) new ItemStackArgumentType(new CommandRegistryAccess(FabricEntryPoint.getPlatform().getServer().getRegistryManager())).parse(new StringReader(data)).getItem();
} catch(CommandSyntaxException e) {
throw new IllegalArgumentException("Invalid item data \"" + data + "\"", e);
}
@@ -17,11 +17,14 @@
package com.dfsek.terra.fabric.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;
@@ -36,9 +39,8 @@ public class FabricWorldHandle implements WorldHandle {
@Override
public @NotNull BlockState createBlockState(@NotNull String data) {
BlockArgumentParser parser = new BlockArgumentParser(new StringReader(data), true);
try {
net.minecraft.block.BlockState state = parser.parse(true).getBlockState();
net.minecraft.block.BlockState state = BlockArgumentParser.block(Registry.BLOCK, data, true).blockState();
if(state == null) throw new IllegalArgumentException("Invalid data: " + data);
return (BlockState) state;
} catch(CommandSyntaxException e) {
@@ -1,39 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.fabric.mixin.access;
import net.minecraft.client.world.GeneratorType;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(GeneratorType.class)
public interface GeneratorTypeAccessor {
@Accessor("VALUES")
static List<GeneratorType> getValues() {
throw new UnsupportedOperationException();
}
@Mutable
@Accessor("displayName")
void setDisplayName(Text translationKey);
}
@@ -18,7 +18,6 @@
package com.dfsek.terra.fabric.mixin.implementations.block.entity;
import net.minecraft.block.entity.SignBlockEntity;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
@@ -42,19 +41,19 @@ public abstract class SignBlockEntityMixin {
public abstract void setTextOnRow(int row, Text text);
public void terra$setLine(int index, @NotNull String line) throws IndexOutOfBoundsException {
setTextOnRow(index, new LiteralText(line));
setTextOnRow(index, Text.literal(line));
}
public @NotNull String[] terra$getLines() {
String[] lines = new String[texts.length];
for(int i = 0; i < texts.length; i++) {
lines[i] = texts[i].asString();
lines[i] = texts[i].getString();
}
return lines;
}
public @NotNull String terra$getLine(int index) throws IndexOutOfBoundsException {
return texts[index].asString();
return texts[index].getString();
}
public void terra$applyState(String state) {
@@ -44,9 +44,6 @@ public abstract class EntityMixin {
@Shadow
public abstract void teleport(double destX, double destY, double destZ);
@Shadow
public abstract void sendSystemMessage(Text message, UUID senderUuid);
public Vector3 terra$position() {
return FabricAdapter.adapt(blockPos);
}
@@ -20,7 +20,6 @@ package com.dfsek.terra.fabric.mixin.implementations.entity;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Implements;
@@ -49,7 +48,7 @@ public abstract class ServerCommandSourceMixin {
public abstract net.minecraft.entity.@Nullable Entity getEntity();
public void terra$sendMessage(String message) {
sendFeedback(new LiteralText(message), true);
sendFeedback(Text.literal(message), true);
}
@Nullable
@@ -81,10 +81,8 @@ public abstract class ChunkRegionMixin {
this.config = ((ServerWorld) world).getPack();
}
@SuppressWarnings("deprecation")
public Entity terraWorld$spawnEntity(Vector3 location, EntityType entityType) {
net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType<?>) entityType).create(
((ChunkRegion) (Object) this).toServerWorld());
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;
@@ -42,8 +42,7 @@ import com.dfsek.terra.fabric.util.FabricUtil;
@Implements(@Interface(iface = ServerWorld.class, prefix = "terra$"))
public abstract class ServerWorldMixin {
public Entity terra$spawnEntity(double x, double y, double z, EntityType entityType) {
net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType<?>) entityType).create(
((net.minecraft.server.world.ServerWorld) (Object) this));
net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType<?>) entityType).create(null);
entity.setPos(x, y, z);
((net.minecraft.server.world.ServerWorld) (Object) this).spawnEntity(entity);
return (Entity) entity;
@@ -19,8 +19,10 @@ public class DataPackContentsMixin {
*/
@Inject(method = "refresh(Lnet/minecraft/util/registry/DynamicRegistryManager;)V", at = @At("RETURN"))
private void injectReload(DynamicRegistryManager dynamicRegistryManager, CallbackInfo ci) {
TagUtil.registerWorldPresetTags(dynamicRegistryManager.get(Registry.WORLD_PRESET_KEY));
Registry<Biome> biomeRegistry = dynamicRegistryManager.get(Registry.BIOME_KEY);
TagUtil.registerTags(biomeRegistry);
TagUtil.registerBiomeTags(biomeRegistry);
BiomeUtil.registerFlora(biomeRegistry);
}
}
@@ -7,6 +7,7 @@ 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;
@@ -23,13 +24,11 @@ import com.dfsek.terra.fabric.FabricEntryPoint;
public class MinecraftServerMixin {
@Inject(method = "<init>(Ljava/lang/Thread;Lnet/minecraft/world/level/storage/LevelStorage$Session;" +
"Lnet/minecraft/resource/ResourcePackManager;Lnet/minecraft/server/SaveLoader;Ljava/net/Proxy;" +
"Lcom/mojang/datafixers/DataFixer;Lcom/mojang/authlib/minecraft/MinecraftSessionService;" +
"Lcom/mojang/authlib/GameProfileRepository;Lnet/minecraft/util/UserCache;" +
"Lcom/mojang/datafixers/DataFixer;Lnet/minecraft/util/ApiServices;" +
"Lnet/minecraft/server/WorldGenerationProgressListenerFactory;)V",
at = @At("RETURN"))
private void injectConstructor(Thread serverThread, LevelStorage.Session session, ResourcePackManager dataPackManager,
SaveLoader saveLoader, Proxy proxy, DataFixer dataFixer, MinecraftSessionService sessionService,
GameProfileRepository gameProfileRepo, UserCache userCache,
SaveLoader saveLoader, Proxy proxy, DataFixer dataFixer, ApiServices apiServices,
WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory, CallbackInfo ci) {
FabricEntryPoint.getPlatform().setServer((MinecraftServer) (Object) this);
}
@@ -0,0 +1,32 @@
package com.dfsek.terra.fabric.mixin.lifecycle;
import com.dfsek.terra.fabric.util.SeedHack;
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;
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.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* Hack to map noise sampler to seeds
*/
@Mixin(NoiseConfig.class)
public class NoiseConfigMixin {
@Shadow
@Final
private MultiNoiseSampler multiNoiseSampler;
@Inject(method = "<init>(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At("TAIL"))
private void mapMultiNoise(ChunkGeneratorSettings chunkGeneratorSettings, Registry<DoublePerlinNoiseSampler.NoiseParameters> noiseRegistry, long seed, CallbackInfo ci) {
SeedHack.register(multiNoiseSampler, seed);
}
}
@@ -17,11 +17,10 @@
package com.dfsek.terra.fabric.mixin.lifecycle.client;
import com.dfsek.terra.fabric.util.BiomeUtil;
import com.dfsek.terra.fabric.util.LifecycleUtil;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.RunArgs;
import net.minecraft.client.world.GeneratorType;
import net.minecraft.text.LiteralText;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -29,8 +28,7 @@ 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.generation.TerraGeneratorType;
import com.dfsek.terra.fabric.mixin.access.GeneratorTypeAccessor;
import com.dfsek.terra.fabric.util.BiomeUtil;
@Mixin(MinecraftClient.class)
@@ -42,13 +40,6 @@ public class MinecraftClientMixin {
// sorta arbitrary position, after mod init, before window opens
shift = At.Shift.BEFORE))
public void injectConstructor(RunArgs args, CallbackInfo callbackInfo) {
FabricEntryPoint.getPlatform().getEventManager().callEvent(new PlatformInitializationEvent());
FabricEntryPoint.getPlatform().getConfigRegistry().forEach(pack -> {
final GeneratorType generatorType = new TerraGeneratorType(pack);
//noinspection ConstantConditions
((GeneratorTypeAccessor) generatorType).setDisplayName(new LiteralText("Terra:" + pack.getID()));
GeneratorTypeAccessor.getValues().add(1, generatorType);
});
BiomeUtil.registerBiomes();
LifecycleUtil.initialize();
}
}
@@ -1,111 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.fabric.mixin.lifecycle.server;
import net.minecraft.server.dedicated.ServerPropertiesHandler;
import net.minecraft.structure.StructureSet;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.dimension.DimensionOptions;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.GeneratorOptions;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Locale;
import java.util.Random;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.fabric.FabricEntryPoint;
import com.dfsek.terra.fabric.PlatformImpl;
import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper;
import com.dfsek.terra.fabric.generation.TerraBiomeSource;
@Mixin(GeneratorOptions.class)
public abstract class GeneratorOptionsMixin {
@Inject(method = "fromProperties(Lnet/minecraft/util/registry/DynamicRegistryManager;" +
"Lnet/minecraft/server/dedicated/ServerPropertiesHandler$WorldGenProperties;)" +
"Lnet/minecraft/world/gen/GeneratorOptions;",
at = @At("HEAD"),
cancellable = true)
private static void fromProperties(DynamicRegistryManager manager,
ServerPropertiesHandler.WorldGenProperties properties,
CallbackInfoReturnable<GeneratorOptions> cir) {
if(properties.levelType() == null) {
return;
}
PlatformImpl main = FabricEntryPoint.getPlatform();
String levelType = properties.levelType();
if(levelType.toLowerCase(Locale.ROOT).startsWith("terra")) {
String seedProperty = properties.levelSeed();
long seed = new Random().nextLong();
if(seedProperty != null) {
try {
long m = Long.parseLong(seedProperty);
if(m != 0L) {
seed = m;
}
} catch(NumberFormatException exception) {
seed = seedProperty.hashCode();
}
}
boolean generateStructures = properties.generateStructures();
Registry<DimensionType> dimensionTypes = manager.get(Registry.DIMENSION_TYPE_KEY);
Registry<Biome> biomeRegistry = manager.get(Registry.BIOME_KEY);
Registry<DimensionOptions> dimensionOptions = DimensionType.createDefaultDimensionOptions(manager, seed, false);
Registry<ChunkGeneratorSettings> chunkGeneratorSettingsRegistry = manager.get(Registry.CHUNK_GENERATOR_SETTINGS_KEY);
RegistryEntry<ChunkGeneratorSettings>
settingsSupplier = chunkGeneratorSettingsRegistry.getEntry(ChunkGeneratorSettings.OVERWORLD).orElseThrow();
Registry<StructureSet> noiseRegistry = manager.get(Registry.STRUCTURE_SET_KEY);
String pack = levelType.substring(levelType.indexOf(":") + 1);
CheckedRegistry<ConfigPack> configRegistry = main.getConfigRegistry();
ConfigPack config = configRegistry
.getByID(pack)
.or(() -> configRegistry.getByID(pack.toUpperCase(Locale.ROOT)))
.orElseThrow(() -> new IllegalArgumentException("No such pack " + pack));
cir.setReturnValue(
new GeneratorOptions(seed,
generateStructures,
false,
GeneratorOptions
.getRegistryWithReplacedOverworldGenerator(
dimensionTypes,
dimensionOptions,
new FabricChunkGeneratorWrapper(noiseRegistry,
new TerraBiomeSource(biomeRegistry, seed, config),
seed,
config,
settingsSupplier))));
}
}
}
@@ -18,6 +18,8 @@
package com.dfsek.terra.fabric.mixin.lifecycle.server;
import com.dfsek.terra.fabric.util.BiomeUtil;
import com.dfsek.terra.fabric.util.LifecycleUtil;
import net.minecraft.server.Main;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -37,9 +39,6 @@ public class ServerMainMixin {
// after registry manager creation
)
private static void injectConstructor(String[] args, CallbackInfo ci) {
FabricEntryPoint.getPlatform().getEventManager().callEvent(
new PlatformInitializationEvent()); // Load during MinecraftServer construction, after other mods have registered blocks
// and stuff
BiomeUtil.registerBiomes();
LifecycleUtil.initialize();
}
}
@@ -137,12 +137,9 @@ public final class BiomeUtil {
effects.foliageColor(vanillaBiomeProperties.getFoliageColor());
}
builder.precipitation(Objects.requireNonNullElse(vanillaBiomeProperties.getPrecipitation(), vanilla.getPrecipitation()))
.category(Objects.requireNonNullElse(vanillaBiomeProperties.getCategory(), vanilla.getCategory()));
builder.precipitation(Objects.requireNonNullElse(vanillaBiomeProperties.getPrecipitation(), vanilla.getPrecipitation()));
} else {
effects.waterColor(vanilla.getWaterColor())
.waterFogColor(vanilla.getWaterFogColor())
.fogColor(vanilla.getFogColor())
@@ -150,11 +147,9 @@ public final class BiomeUtil {
vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor);
vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor);
builder.precipitation(vanilla.getPrecipitation())
.category(vanilla.getCategory());
builder.precipitation(vanilla.getPrecipitation());
}
return builder
.temperature(vanilla.getTemperature())
.downfall(vanilla.getDownfall())
@@ -0,0 +1,100 @@
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;
import net.minecraft.structure.StructureSet;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.noise.DoublePerlinNoiseSampler.NoiseParameters;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.source.MultiNoiseBiomeSource;
import net.minecraft.world.biome.source.TheEndBiomeSource;
import net.minecraft.world.dimension.DimensionOptions;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.dimension.DimensionTypes;
import net.minecraft.world.gen.WorldPreset;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
import net.minecraft.world.gen.chunk.NoiseChunkGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class LifecycleUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleUtil.class);
private static final List<Identifier> PRESETS = new ArrayList<>();
public static void initialize() {
FabricEntryPoint.getPlatform().getEventManager().callEvent(
new PlatformInitializationEvent());
BiomeUtil.registerBiomes();
LOGGER.info("Registering Terra world types...");
Registry<DimensionType> dimensionTypeRegistry = BuiltinRegistries.DIMENSION_TYPE;
Registry<ChunkGeneratorSettings> chunkGeneratorSettingsRegistry = BuiltinRegistries.CHUNK_GENERATOR_SETTINGS;
Registry<StructureSet> structureSetRegistry = BuiltinRegistries.STRUCTURE_SET;
Registry<NoiseParameters> noiseParametersRegistry = BuiltinRegistries.NOISE_PARAMETERS;
Registry<Biome> biomeRegistry = BuiltinRegistries.BIOME;
RegistryEntry<DimensionType> theNetherDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_NETHER);
RegistryEntry<ChunkGeneratorSettings>
netherChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.NETHER);
DimensionOptions netherDimensionOptions = new DimensionOptions(theNetherDimensionType,
new NoiseChunkGenerator(structureSetRegistry,
noiseParametersRegistry,
MultiNoiseBiomeSource.Preset.NETHER.getBiomeSource(
biomeRegistry),
netherChunkGeneratorSettings));
RegistryEntry<DimensionType> theEndDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_END);
RegistryEntry<ChunkGeneratorSettings> endChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry(
ChunkGeneratorSettings.END);
DimensionOptions endDimensionOptions = new DimensionOptions(theEndDimensionType,
new NoiseChunkGenerator(structureSetRegistry, noiseParametersRegistry,
new TheEndBiomeSource(biomeRegistry),
endChunkGeneratorSettings));
RegistryEntry<DimensionType> overworldDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.OVERWORLD);
RegistryEntry<ChunkGeneratorSettings> 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);
}
);
}
public static List<Identifier> getPresets() {
return PRESETS;
}
}
@@ -0,0 +1,29 @@
package com.dfsek.terra.fabric.util;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Holder for hacky biome source seed workaround
*/
public class SeedHack {
private static final Logger LOGGER = LoggerFactory.getLogger(SeedHack.class);
private static final Object2LongMap<MultiNoiseSampler> seedMap = new Object2LongOpenHashMap<>();
public static long getSeed(MultiNoiseSampler sampler) {
if(!seedMap.containsKey(sampler)) {
throw new IllegalArgumentException("Sampler is not registered: " + sampler);
}
return seedMap.getLong(sampler);
}
public static void register(MultiNoiseSampler sampler, long seed) {
LOGGER.info("Registered seed {} to sampler {}", seed, sampler.hashCode());
seedMap.put(sampler, seed);
}
}
@@ -2,9 +2,11 @@ package com.dfsek.terra.fabric.util;
import com.google.common.collect.ImmutableMap;
import net.minecraft.tag.TagKey;
import net.minecraft.tag.WorldPresetTags;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.WorldPreset;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -21,48 +23,72 @@ public final class TagUtil {
}
public static void registerTags(Registry<Biome> registry) {
logger.info("Doing tag garbage....");
Map<TagKey<Biome>, List<RegistryEntry<Biome>>> collect = registry
private static <T> Map<TagKey<T>, List<RegistryEntry<T>>> tagsToMutableMap(Registry<T> registry) {
return registry
.streamTagsAndEntries()
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
}
public static void registerWorldPresetTags(Registry<WorldPreset> registry) {
logger.info("Doing preset tag garbage....");
Map<TagKey<WorldPreset>, List<RegistryEntry<WorldPreset>>> collect = tagsToMutableMap(registry);
LifecycleUtil
.getPresets()
.forEach(id -> FabricUtil
.getEntry(registry, id)
.ifPresentOrElse(
preset -> collect
.computeIfAbsent(WorldPresetTags.NORMAL, tag -> new ArrayList<>())
.add(preset),
() -> logger.error("Preset {} does not exist!", id)));
registry.clearTags();
registry.populateTags(ImmutableMap.copyOf(collect));
}
public static void registerBiomeTags(Registry<Biome> registry) {
logger.info("Doing biome tag garbage....");
Map<TagKey<Biome>, List<RegistryEntry<Biome>>> collect = tagsToMutableMap(registry);
BiomeUtil
.getTerraBiomeMap()
.forEach((vb, terraBiomes) ->
FabricUtil.getEntry(registry, vb)
.ifPresentOrElse(vanilla -> terraBiomes
.forEach(tb -> FabricUtil
.getEntry(registry, tb)
.ifPresentOrElse(
terra -> {
logger.debug(
vanilla.getKey()
.orElseThrow()
.getValue() +
" (vanilla for " +
terra.getKey()
.orElseThrow()
.getValue() +
": " +
vanilla.streamTags()
.toList());
vanilla.streamTags()
.forEach(
tag -> collect
.computeIfAbsent(
tag,
t -> new ArrayList<>())
.add(terra));
},
() -> logger.error(
"No such biome: {}",
tb))),
() -> logger.error("No vanilla biome: {}", vb)));
FabricUtil
.getEntry(registry, vb)
.ifPresentOrElse(
vanilla -> terraBiomes
.forEach(tb -> FabricUtil
.getEntry(registry, tb)
.ifPresentOrElse(
terra -> {
logger.debug(
vanilla.getKey()
.orElseThrow()
.getValue() +
" (vanilla for " +
terra.getKey()
.orElseThrow()
.getValue() +
": " +
vanilla.streamTags()
.toList());
vanilla.streamTags()
.forEach(
tag -> collect
.computeIfAbsent(
tag,
t -> new ArrayList<>())
.add(terra));
},
() -> logger.error(
"No such biome: {}",
tb))),
() -> logger.error("No vanilla biome: {}", vb)));
registry.clearTags();
registry.populateTags(ImmutableMap.copyOf(collect));
@@ -1,9 +0,0 @@
debug: false
data-save: PT6M
language: "en_us"
fail-type: SHUTDOWN
dump-default: true
biome-search-resolution: 4
cache-size: 384
master-disable:
caves: false
@@ -26,7 +26,7 @@
"depends": {
"fabricloader": ">=0.14.2",
"java": ">=17",
"minecraft": "1.18.x"
"minecraft": "1.19.x"
},
"accessWidener": "terra.accesswidener"
}
@@ -1,5 +1 @@
accessWidener v1 named
extendable method net/minecraft/client/world/GeneratorType <init> (Ljava/lang/String;)V
accessible method net/minecraft/world/biome/Biome getCategory ()Lnet/minecraft/world/biome/Biome$Category;
@@ -1,51 +1,50 @@
{
"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.RegistryMixin"
],
"client": [
"access.GeneratorTypeAccessor",
"lifecycle.client.MinecraftClientMixin"
],
"server": [
"lifecycle.server.GeneratorOptionsMixin",
"lifecycle.server.ServerMainMixin"
],
"injectors": {
"defaultRequire": 1
},
"refmap": "terra-refmap.json"
"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"
}
+1 -1
View File
@@ -24,7 +24,7 @@ include(":platforms:bukkit:common")
pluginManagement {
repositories {
maven(url = "https://maven.fabricmc.net") {
maven("https://maven.fabricmc.net") {
name = "Fabric"
}
gradlePluginPortal()