Compare commits

..

55 Commits

Author SHA1 Message Date
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
46 changed files with 656 additions and 720 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.0"))
versionProjects(":common:implementation", version("6.1.0"))
versionProjects(":platforms", version("6.1.0"))
allprojects {
+11 -2
View File
@@ -3,6 +3,15 @@ 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()
@@ -11,8 +20,8 @@ repositories {
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("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)
}
+5 -3
View File
@@ -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,84 @@ 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 resourcePath = dir + File.separatorChar + entry;
File resource = new File(getDataFolder(), resourcePath);
if(resource.exists())
return; // dont overwrite
logger.info("Dumping resource {}...", resource.getAbsolutePath());
try {
try(InputStream is = getClass().getResourceAsStream("/" + resourcePath)) {
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);
}
@@ -54,7 +54,7 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private final long seed;
private final Map<ConcentricRingsStructurePlacement, Lazy<List<ChunkCoordIntPair>>> h = new Object2ObjectArrayMap<>();
private static final Lazy<List<ChunkCoordIntPair>> EMPTY = Lazy.lazy(List::of);
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
@@ -154,7 +154,7 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator {
@Override
public List<ChunkCoordIntPair> a(ConcentricRingsStructurePlacement concentricringsstructureplacement) {
this.i();
return this.h.get(concentricringsstructureplacement).value();
return this.h.getOrDefault(concentricringsstructureplacement, EMPTY).value();
}
private volatile boolean rings = false;
+8 -4
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").forEach { apiModule ->
val module = fabricApi.module(apiModule, Versions.Fabric.fabricAPI)
modImplementation(module)
include(module)
@@ -24,8 +24,12 @@ dependencies {
include(modImplementation("me.lucko", "fabric-permissions-api", Versions.Fabric.permissionsAPI))
include("me.lucko", "fabric-permissions-api", Versions.Fabric.permissionsAPI)
include(modImplementation("cloud.commandframework", "cloud-fabric", Versions.Libraries.cloud))
include("cloud.commandframework", "cloud-fabric", Versions.Libraries.cloud)
"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)
}
loom {
@@ -17,17 +17,13 @@
package com.dfsek.terra.fabric;
import cloud.commandframework.execution.CommandExecutionCoordinator;
import cloud.commandframework.fabric.FabricServerCommandManager;
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;
@@ -49,7 +45,7 @@ public class FabricEntryPoint implements ModInitializer {
@Override
public void onInitialize() {
logger.info("Initializing Terra Fabric mod...");
/*
FabricServerCommandManager<CommandSender> manager = new FabricServerCommandManager<>(
CommandExecutionCoordinator.simpleCoordinator(),
serverCommandSource -> (CommandSender) serverCommandSource,
@@ -60,5 +56,7 @@ public class FabricEntryPoint implements ModInitializer {
manager.brigadierManager().setNativeNumberSuggestions(false);
TERRA_PLUGIN.getEventManager().callEvent(new CommandRegistrationEvent(manager));
TODO: re-enable when Cloud updates
*/
}
}
@@ -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) {
@@ -0,0 +1,25 @@
package com.dfsek.terra.fabric.mixin;
import com.dfsek.terra.fabric.FabricEntryPoint;
import net.minecraft.server.command.ReloadCommand;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;
import org.checkerframework.checker.units.qual.A;
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.CallbackInfo;
import java.util.Collection;
@Mixin(ReloadCommand.class)
public class ReloadCommandMixin {
@Inject(method = "tryReloadDataPacks", at = @At("HEAD"))
private static void inject(Collection<String> dataPacks, ServerCommandSource source, CallbackInfo ci) {
source.sendFeedback(Text.literal("Reloading Terra..."), true);
FabricEntryPoint.getPlatform().reload();
source.sendFeedback(Text.literal("Done."), true);
}
}
@@ -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,51 @@
{
"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": [
"ReloadCommandMixin",
"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"
}