Merge pull request #437 from PolyhedralDev/dev/1.20.3

Dev/1.20.3
This commit is contained in:
Zoë 2023-12-09 15:13:11 -07:00 committed by GitHub
commit 2a92d76276
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 117 additions and 3312 deletions

View File

@ -17,10 +17,10 @@ repositories {
dependencies {
//TODO Allow pulling from Versions.kt
implementation("com.github.johnrengelman", "shadow", "8.1.1")
implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "1.5.6")
implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "1.5.11")
implementation("org.ow2.asm", "asm", "9.5")
implementation("org.ow2.asm", "asm-tree", "9.5")
implementation("com.dfsek.tectonic", "common", "4.2.0")
implementation("org.ow2.asm", "asm", "9.6")
implementation("org.ow2.asm", "asm-tree", "9.6")
implementation("com.dfsek.tectonic", "common", "4.2.1")
implementation("org.yaml", "snakeyaml", "2.2")
}

View File

@ -48,17 +48,14 @@ fun Project.configureDependencies() {
maven("https://jitpack.io") {
name = "JitPack"
}
maven("https://nexuslite.gcnt.net/repos/other/") {
name = "GCNT"
}
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.0")
compileOnly("org.jetbrains:annotations:23.0.0")
testImplementation("org.junit.jupiter", "junit-jupiter-api", Versions.Libraries.Internal.junit)
testImplementation("org.junit.jupiter", "junit-jupiter-engine", Versions.Libraries.Internal.junit)
compileOnly("org.jetbrains", "annotations", Versions.Libraries.Internal.jetBrainsAnnotations)
compileOnly("com.google.guava:guava:30.0-jre")
testImplementation("com.google.guava:guava:30.0-jre")
compileOnly("com.google.guava", "guava", Versions.Libraries.Internal.guava)
testImplementation("com.google.guava", "guava", Versions.Libraries.Internal.guava)
}
}

View File

@ -6,21 +6,25 @@ object Versions {
const val cloud = "1.8.4"
const val caffeine = "3.1.8"
const val slf4j = "2.0.9"
const val log4j_slf4j_impl = "2.20.0"
object Internal {
const val shadow = "8.1.1"
const val apacheText = "1.10.0"
const val apacheIO = "2.14.0"
const val apacheText = "1.11.0"
const val apacheIO = "2.15.1"
const val guava = "32.1.3-jre"
const val asm = "9.5"
const val asm = "9.6"
const val snakeYml = "2.2"
const val jetBrainsAnnotations = "24.1.0"
const val junit = "5.10.1"
}
}
object Fabric {
const val fabricAPI = "0.90.0+${Mod.minecraft}"
const val fabricAPI = "0.91.2+${Mod.minecraft}"
}
//
// object Quilt {
@ -31,30 +35,28 @@ object Versions {
object Mod {
const val mixin = "0.12.5+mixin.0.8.5"
const val minecraft = "1.20.2"
const val yarn = "$minecraft+build.4"
const val fabricLoader = "0.14.23"
const val minecraft = "1.20.4"
const val yarn = "$minecraft+build.1"
const val fabricLoader = "0.15.1"
const val architecuryLoom = "1.3.357"
const val architecturyPlugin = "3.4.146"
const val loomVineflower = "1.11.0"
}
object Forge {
const val forge = "${Mod.minecraft}-48.0.13"
const val burningwave = "12.63.0"
}
const val architecuryLoom = "1.4.369"
const val architecturyPlugin = "3.4.151"
}
//
// object Forge {
// const val forge = "${Mod.minecraft}-48.0.13"
// const val burningwave = "12.63.0"
// }
object Bukkit {
const val paper = "1.18.2-R0.1-SNAPSHOT"
const val paperLib = "1.0.5"
const val foliaLib = "0.2.5"
const val minecraft = "1.20.2"
const val reflectionRemapper = "0.1.0-SNAPSHOT"
const val paperDevBundle = "1.20.2-R0.1-SNAPSHOT"
const val runPaper = "2.2.0"
const val paperWeight = "1.5.6"
const val minecraft = "1.20.4"
const val paperBuild = "$minecraft-R0.1-20231209.173338-2"
const val paper = paperBuild
const val paperLib = "1.0.8"
const val reflectionRemapper = "0.1.0"
const val paperDevBundle = paperBuild
const val runPaper = "2.2.2"
const val paperWeight = "1.5.11"
}
//
@ -66,6 +68,6 @@ object Versions {
//
object CLI {
const val nbt = "6.1"
const val logback = "1.4.11"
const val logback = "1.4.14"
}
}

View File

@ -6,6 +6,6 @@ dependencies {
api("com.dfsek.tectonic", "common", Versions.Libraries.tectonic)
api("com.github.ben-manes.caffeine:caffeine:3.1.0")
api("com.github.ben-manes.caffeine", "caffeine", Versions.Libraries.caffeine)
}

Binary file not shown.

View File

@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

14
gradlew vendored
View File

@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@ -202,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \

View File

@ -10,19 +10,13 @@ repositories {
dependencies {
shaded(project(":platforms:bukkit:common"))
shaded(project(":platforms:bukkit:nms:v1_18_R2", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R1", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R2", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R3", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_20_R1", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_20_R2", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_20_R3", configuration = "reobf"))
shaded("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
tasks {
shadowJar {
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
relocate("com.tcoded.folialib", "com.dfsek.terra.lib.folialib")
relocate("com.google.common", "com.dfsek.terra.lib.google.common")
relocate("org.apache.logging.slf4j", "com.dfsek.terra.lib.slf4j-over-log4j")
exclude("org/slf4j/**")

View File

@ -8,9 +8,7 @@ dependencies {
compileOnly("io.papermc.paper", "paper-api", Versions.Bukkit.paper)
shadedApi("io.papermc", "paperlib", Versions.Bukkit.paperLib)
// TODO: 2023-11-08 When we drop support for 1.18 and 1.19, we can remove FoliaLib and instead use `RegionScheduler`,
// AsyncScheduler, or GlobalRegionScheduler.
shadedApi("com.tcoded", "FoliaLib", Versions.Bukkit.foliaLib)
shadedApi("com.google.guava", "guava", Versions.Libraries.Internal.guava)
shadedApi("cloud.commandframework", "cloud-paper", Versions.Libraries.cloud)

View File

@ -84,8 +84,8 @@ public class PlatformImpl extends AbstractPlatform {
}
@Override
public void runPossiblyUnsafeTask(@NotNull Runnable task) {
plugin.getFoliaLib().getImpl().runAsync(task);
public void runPossiblyUnsafeTask(@NotNull Runnable runnable) {
plugin.getGlobalRegionScheduler().run(plugin, task -> runnable.run());
}
@Override

View File

@ -21,7 +21,8 @@ import cloud.commandframework.brigadier.CloudBrigadierManager;
import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.execution.CommandExecutionCoordinator;
import cloud.commandframework.paper.PaperCommandManager;
import com.tcoded.folialib.FoliaLib;
import io.papermc.paper.threadedregions.scheduler.AsyncScheduler;
import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler;
import org.bukkit.Bukkit;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
@ -32,6 +33,7 @@ import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.dfsek.terra.api.command.CommandSender;
import com.dfsek.terra.api.config.ConfigPack;
@ -51,7 +53,9 @@ public class TerraBukkitPlugin extends JavaPlugin {
private final PlatformImpl platform = new PlatformImpl(this);
private final Map<String, com.dfsek.terra.api.world.chunk.generation.ChunkGenerator> generatorMap = new HashMap<>();
private final FoliaLib foliaLib = new FoliaLib(this);
private AsyncScheduler asyncScheduler = this.getServer().getAsyncScheduler();
private GlobalRegionScheduler globalRegionScheduler = this.getServer().getGlobalRegionScheduler();
@Override
public void onEnable() {
@ -116,6 +120,9 @@ public class TerraBukkitPlugin extends JavaPlugin {
if(!VersionUtil.getSpigotVersionInfo().isSpigot())
logger.error("YOU ARE RUNNING A CRAFTBUKKIT OR BUKKIT SERVER. PLEASE UPGRADE TO PAPER.");
if(!VersionUtil.getSpigotVersionInfo().isPaper())
logger.error("YOU ARE RUNNING A SPIGOT SERVER. PLEASE UPGRADE TO PAPER.");
if(VersionUtil.getSpigotVersionInfo().isMohist()) {
if(System.getProperty("IKnowMohistCausesLotsOfIssuesButIWillUseItAnyways") == null) {
Runnable runnable = () -> { // scary big block of text
@ -159,7 +166,7 @@ public class TerraBukkitPlugin extends JavaPlugin {
""".strip());
};
runnable.run();
foliaLib.getImpl().runLaterAsync(runnable, 200L);
asyncScheduler.runDelayed(this, task -> runnable.run(), 200L, TimeUnit.SECONDS);
// Bukkit.shutdown(); // we're not *that* evil
Bukkit.getPluginManager().disablePlugin(this);
return false;
@ -187,7 +194,11 @@ public class TerraBukkitPlugin extends JavaPlugin {
}), platform.getRawConfigRegistry().getByID(id).orElseThrow(), platform.getWorldHandle().air());
}
public FoliaLib getFoliaLib() {
return foliaLib;
public AsyncScheduler getAsyncScheduler() {
return asyncScheduler;
}
public GlobalRegionScheduler getGlobalRegionScheduler() {
return globalRegionScheduler;
}
}

View File

@ -29,16 +29,28 @@ import com.dfsek.terra.api.handle.WorldHandle;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BukkitWorldHandle implements WorldHandle {
private final BlockState air;
private static final Logger logger = LoggerFactory.getLogger(BukkitWorldHandle.class);
public BukkitWorldHandle() {
this.air = BukkitBlockState.newInstance(Material.AIR.createBlockData());
}
@Override
public synchronized @NotNull BlockState createBlockState(@NotNull String data) {
if(data.equals("minecraft:grass")) { //TODO: remove in 7.0
data = "minecraft:short_grass";
logger.warn(
"Translating minecraft:grass to minecraft:short_grass. In 1.20.3 minecraft:grass was renamed to minecraft:short_grass" +
". You are advised to preform this rename in your config backs as this translation will be removed in the next major " +
"version of Terra.");
}
org.bukkit.block.data.BlockData bukkitData = Bukkit.createBlockData(
data); // somehow bukkit managed to make this not thread safe! :)
return BukkitBlockState.newInstance(bukkitData);

View File

@ -19,6 +19,8 @@ package com.dfsek.terra.bukkit.util;
import io.papermc.lib.PaperLib;
import java.util.concurrent.TimeUnit;
import com.dfsek.terra.bukkit.TerraBukkitPlugin;
import static io.papermc.lib.PaperLib.suggestPaper;
@ -26,10 +28,10 @@ import static io.papermc.lib.PaperLib.suggestPaper;
public final class PaperUtil {
public static void checkPaper(TerraBukkitPlugin plugin) {
plugin.getFoliaLib().getImpl().runLaterAsync(() -> {
plugin.getAsyncScheduler().runDelayed(plugin, task -> {
if(!PaperLib.isPaper()) {
suggestPaper(plugin);
}
}, 100L);
}, 100L, TimeUnit.SECONDS);
}
}

View File

@ -4,6 +4,6 @@ version: "@VERSION@"
load: "STARTUP"
author: dfsek
website: "@WIKI@"
api-version: "1.13"
api-version: "1.20"
description: "@DESCRIPTION@"
folia-supported: true

View File

@ -1,17 +0,0 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle("1.18.2-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
tasks {
assemble {
dependsOn("reobfJar")
}
}

View File

@ -1,115 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSBiomeInjector.class);
private static final Map<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 = NMSBiomeInjector.createBiome(
biome,
biomeRegistry.get(vanillaMinecraftKey) // get
);
ResourceKey<Biome> delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY, new ResourceLocation("terra",
NMSBiomeInjector.createBiomeID(
pack, key)));
BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform);
biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
platformBiome.getContext().put(new NMSBiomeInfo(delegateKey));
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<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) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb)
.ifPresentOrElse(
vanilla -> terraBiomes
.forEach(tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb)
.ifPresentOrElse(
terra -> {
LOGGER.debug(
vanilla.unwrapKey()
.orElseThrow()
.location() +
" (vanilla for " +
terra.unwrapKey()
.orElseThrow()
.location() +
": " +
vanilla.tags()
.toList());
vanilla.tags()
.forEach(
tag -> collect
.computeIfAbsent(
tag,
t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error(
"No such biome: {}",
tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.resetTags(); // clearTags
biomeRegistry.bindTags(ImmutableMap.copyOf(collect)); // populateTags
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}
}
}

View File

@ -1,10 +0,0 @@
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;
public record NMSBiomeInfo(ResourceKey<Biome> biomeKey) implements Properties {
}

View File

@ -1,79 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.map(registry::getOrCreateHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder(); // Builder
builder.biomeCategory(Reflection.BIOME.getBiomeCategory(vanilla))
.precipitation(vanilla.getPrecipitation()) // getPrecipitation
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings())
.temperature(vanilla.getBaseTemperature())
.downfall(vanilla.getDownfall());
BiomeSpecialEffects.Builder effects = new BiomeSpecialEffects.Builder();
effects.grassColorModifier(vanilla.getSpecialEffects().getGrassColorModifier());
VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class);
effects.fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor()))
.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor()))
.waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor()))
.skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor()));
if(vanillaBiomeProperties.getFoliageColor() == null) {
vanilla.getSpecialEffects().getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
} else {
effects.foliageColorOverride(vanillaBiomeProperties.getFoliageColor());
}
if(vanillaBiomeProperties.getGrassColor() == null) {
vanilla.getSpecialEffects().getGrassColorOverride().ifPresent(effects::grassColorOverride);
} else {
effects.grassColorOverride(vanillaBiomeProperties.getGrassColor());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build(); // build()
}
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);
}
}

View File

@ -1,49 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
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 BiomeSource vanilla;
private final long seed;
private final Registry<Biome> biomeRegistry = Registries.biomeRegistry();
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 BiomeSource> codec() {
return BiomeSource.CODEC;
}
@Override
public @NotNull BiomeSource withSeed(long seed) {
return new NMSBiomeProvider(delegate, vanilla, seed);
}
@Override
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());
}
}

View File

@ -1,254 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
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.SectionPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
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.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
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 org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.util.generic.Lazy;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSChunkGeneratorDelegate.class);
private static final Lazy<List<ChunkPos>> EMPTY = Lazy.lazy(List::of);
private final NMSBiomeProvider biomeSource;
private final com.dfsek.terra.api.world.chunk.generation.ChunkGenerator delegate;
private final ChunkGenerator vanilla;
private final ConfigPack pack;
private final long seed;
private final Map<ConcentricRingsStructurePlacement, Lazy<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap<>();
private volatile boolean rings = false;
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
super(Registries.structureSet(), Optional.empty(), biomeProvider, biomeProvider, seed);
this.delegate = pack.getGeneratorProvider().newInstance(pack);
this.vanilla = vanilla;
this.biomeSource = biomeProvider;
this.pack = pack;
this.seed = seed;
}
@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
public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk,
@NotNull StructureFeatureManager structureAccessor) {
vanilla.applyBiomeDecoration(world, chunk, structureAccessor);
}
@Override
public int getSeaLevel() {
return vanilla.getSeaLevel();
}
@Override
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
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 NoiseColumn(getMinY(), array);
*/
return vanilla.getBaseColumn(x, z, height);
}
@Override // withSeed
public @NotNull ChunkGenerator withSeed(long seed) {
return new NMSChunkGeneratorDelegate(vanilla, pack, biomeSource, seed);
}
@Override
public void spawnOriginalMobs(@NotNull WorldGenRegion regionlimitedworldaccess) {
vanilla.spawnOriginalMobs(regionlimitedworldaccess);
}
@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();
while(y >= getMinY() && !heightmap.isOpaque().test(
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
y--;
}
return y;
}
@Nullable
@Override
public List<ChunkPos> getRingPositionsFor(@NotNull ConcentricRingsStructurePlacement concentricringsstructureplacement) {
ensureStructuresGenerated();
return ringPositions.getOrDefault(concentricringsstructureplacement, EMPTY).value();
}
@Override
public synchronized void ensureStructuresGenerated() {
if(!this.rings) {
super.ensureStructuresGenerated();
this.populateStrongholdData();
this.rings = true;
}
}
private void populateStrongholdData() {
LOGGER.info("Generating safe stronghold data. This may take up to a minute.");
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.structures().stream().anyMatch((structureset_a1) -> structureset_a1.generatesInMatchingBiome(set::contains))) {
this.ringPositions.put(concentricringsstructureplacement,
Lazy.lazy(() -> this.generateRingPositions(holder, concentricringsstructureplacement)));
}
}
});
}
private List<ChunkPos> generateRingPositions(StructureSet holder,
ConcentricRingsStructurePlacement concentricringsstructureplacement) { // Spigot
if(concentricringsstructureplacement.count() == 0) {
return List.of();
}
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();
// 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.5D) * (double) i * 2.5D;
int k1 = (int) Math.round(MathUtil.cos(d0) * d1);
int l1 = (int) Math.round(MathUtil.sin(d0) * d1);
int i2 = SectionPos.sectionToBlockCoord(k1, 8);
int j2 = SectionPos.sectionToBlockCoord(l1, 8);
Objects.requireNonNull(set);
Pair<BlockPos, Holder<Biome>> pair = this.biomeSource.findBiomeHorizontal(i2, 0, j2, 112, set::contains, random,
this.climateSampler());
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 += random.nextDouble() * 3.141592653589793D * 2.0D;
}
}
return list;
}
@Override
public void addDebugScreenInfo(@NotNull List<String> arg0, @NotNull BlockPos arg1) {
}
}

View File

@ -1,15 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
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) {
AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}

View File

@ -1,53 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
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;
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(), vanilla.getBiomeSource(), 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.");
serverWorld.getChunkSource().chunkMap.generator.ensureStructuresGenerated(); // generate stronghold data now
INJECT_LOCK.unlock();
}
}
}

View File

@ -1,36 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
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();
}
}

View File

@ -1,38 +0,0 @@
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);
}
}

View File

@ -1,30 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
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_18_R2.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);
}
}

View File

@ -1,17 +0,0 @@
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", Versions.Bukkit.reflectionRemapper)
}
tasks {
assemble {
dependsOn("reobfJar")
}
}

View File

@ -1,116 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(AwfulBukkitHacks.class);
private static final Map<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 = NMSBiomeInjector.createBiome(
biome,
Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)) // get
);
ResourceKey<Biome> delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY,
new ResourceLocation("terra",
NMSBiomeInjector.createBiomeID(pack, key)));
BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform);
biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
platformBiome.getContext().put(new NMSBiomeInfo(delegateKey));
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<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) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb)
.ifPresentOrElse(
vanilla -> terraBiomes
.forEach(tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb)
.ifPresentOrElse(
terra -> {
LOGGER.debug(
vanilla.unwrapKey()
.orElseThrow()
.location() +
" (vanilla for " +
terra.unwrapKey()
.orElseThrow()
.location() +
": " +
vanilla.tags()
.toList());
vanilla.tags()
.forEach(
tag -> collect
.computeIfAbsent(
tag,
t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error(
"No such biome: {}",
tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.resetTags();
biomeRegistry.bindTags(ImmutableMap.copyOf(collect));
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}
}
}

View File

@ -1,79 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.map(registry::getOrCreateHolderOrThrow);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder();
builder
.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());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build();
}
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);
}
}

View File

@ -1,42 +0,0 @@
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());
}
}

View File

@ -1,291 +0,0 @@
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.LevelAccessor;
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.Blocks;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.Beardifier;
import net.minecraft.world.level.levelgen.DensityFunction.SinglePointContext;
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.MathUtil;
import com.dfsek.terra.api.util.generic.Lazy;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.info.WorldProperties;
import com.dfsek.terra.bukkit.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.bukkit.world.BukkitWorldProperties;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
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;
private final Map<ConcentricRingsStructurePlacement, Lazy<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap<>();
private volatile boolean rings = false;
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)
.thenApply(c -> {
LevelAccessor level = Reflection.STRUCTURE_MANAGER.getLevel(structureAccessor);
BiomeProvider biomeProvider = pack.getBiomeProvider();
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
beard(structureAccessor, chunk, new BukkitWorldProperties(level.getMinecraftWorld().getWorld()),
biomeProvider, compatibilityOptions);
}
return c;
});
}
private void beard(StructureManager structureAccessor, ChunkAccess chunk, WorldProperties world, BiomeProvider biomeProvider,
PreLoadCompatibilityOptions compatibilityOptions) {
Beardifier structureWeightSampler = Beardifier.forStructuresInChunk(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.compute(new SinglePointContext(x + xi, y, z + zi));
if(noise > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), ((CraftBlockData) ((BukkitBlockState) delegate
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed())).getHandle()).getState(), false);
depth++;
} else if(noise < airThreshold) {
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.defaultBlockState(), false);
} else {
depth = 0;
}
}
}
}
}
@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();
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);
*/
return vanilla.getBaseColumn(x, z, world, noiseConfig);
}
@Override
public void addDebugScreenInfo(@NotNull List<String> text, @NotNull RandomState noiseConfig, @NotNull BlockPos pos) {
}
@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(MathUtil.cos(d0) * d1);
int l1 = (int) Math.round(MathUtil.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;
}
}

View File

@ -1,51 +0,0 @@
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();
}
}
}

View File

@ -1,39 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.core.MappedRegistry;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.StructureManager;
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 StructureManagerProxy STRUCTURE_MANAGER;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper,
Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
STRUCTURE_MANAGER = reflectionProxyFactory.reflectionProxy(StructureManagerProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
@Proxies(StructureManager.class)
public interface StructureManagerProxy {
@FieldGetter("level")
LevelAccessor getLevel(StructureManager instance);
}
}

View File

@ -1,30 +0,0 @@
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);
}
}

View File

@ -1,17 +0,0 @@
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.3-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
tasks {
assemble {
dependsOn("reobfJar")
}
}

View File

@ -1,100 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(AwfulBukkitHacks.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) RegistryFetcher.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(biome, Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)));
ResourceKey<Biome> delegateKey = ResourceKey.create(
Registries.BIOME,
new ResourceLocation("terra", NMSBiomeInjector.createBiomeID(pack, key))
);
Reference<Biome> holder = biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
Reflection.REFERENCE.invokeBindValue(holder, platform); // IMPORTANT: bind holder.
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) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb).ifPresentOrElse(
vanilla -> terraBiomes.forEach(
tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb).ifPresentOrElse(
terra -> {
LOGGER.debug("{} (vanilla for {}): {}",
vanilla.unwrapKey().orElseThrow().location(),
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);
}
}
}

View File

@ -1,10 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
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 {
}

View File

@ -1,79 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.flatMap(registry::getHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder();
builder
.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());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build();
}
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);
}
}

View File

@ -1,42 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
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 = RegistryFetcher.biomeRegistry();
public NMSBiomeProvider(BiomeProvider delegate, long seed) {
super(delegate.stream()
.map(biome -> RegistryFetcher.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());
}
}

View File

@ -1,174 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.LevelAccessor;
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.BiomeManager;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.Beardifier;
import net.minecraft.world.level.levelgen.DensityFunction.SinglePointContext;
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 org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.info.WorldProperties;
import com.dfsek.terra.bukkit.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.bukkit.world.BukkitWorldProperties;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
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(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)
.thenApply(c -> {
LevelAccessor level = Reflection.STRUCTURE_MANAGER.getLevel(structureAccessor);
BiomeProvider biomeProvider = pack.getBiomeProvider();
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
beard(structureAccessor, chunk, new BukkitWorldProperties(level.getMinecraftWorld().getWorld()),
biomeProvider, compatibilityOptions);
}
return c;
});
}
private void beard(StructureManager structureAccessor, ChunkAccess chunk, WorldProperties world, BiomeProvider biomeProvider,
PreLoadCompatibilityOptions compatibilityOptions) {
Beardifier structureWeightSampler = Beardifier.forStructuresInChunk(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.compute(new SinglePointContext(x + xi, y, z + zi));
if(noise > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), ((CraftBlockData) ((BukkitBlockState) delegate
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed())).getHandle()).getState(), false);
depth++;
} else if(noise < airThreshold) {
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.defaultBlockState(), false);
} else {
depth = 0;
}
}
}
}
}
@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();
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);
*/
return vanilla.getBaseColumn(x, z, world, noiseConfig);
}
@Override
public void addDebugScreenInfo(@NotNull List<String> text, @NotNull RandomState noiseConfig, @NotNull BlockPos pos) {
}
}

View File

@ -1,15 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
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) {
AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}

View File

@ -1,36 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
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();
}
}

View File

@ -1,52 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.StructureManager;
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.MethodName;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
public static final StructureManagerProxy STRUCTURE_MANAGER;
public static final ReferenceProxy REFERENCE;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper,
Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
STRUCTURE_MANAGER = reflectionProxyFactory.reflectionProxy(StructureManagerProxy.class);
REFERENCE = reflectionProxyFactory.reflectionProxy(ReferenceProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
@Proxies(StructureManager.class)
public interface StructureManagerProxy {
@FieldGetter("level")
LevelAccessor getLevel(StructureManager instance);
}
@Proxies(Holder.Reference.class)
public interface ReferenceProxy {
@MethodName("bindValue")
<T> void invokeBindValue(Reference<T> instance, T value);
}
}

View File

@ -1,24 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R2.CraftServer;
public class RegistryFetcher {
private static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.registryAccess()
.registryOrThrow(key);
}
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registries.BIOME);
}
}

View File

@ -1,17 +0,0 @@
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.4-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
tasks {
assemble {
dependsOn("reobfJar")
}
}

View File

@ -1,101 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(AwfulBukkitHacks.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) RegistryFetcher.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(biome, Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)));
ResourceKey<Biome> delegateKey = ResourceKey.create(
Registries.BIOME,
new ResourceLocation("terra", NMSBiomeInjector.createBiomeID(pack, key))
);
Reference<Biome> holder = biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
Reflection.REFERENCE.invokeBindValue(holder, platform); // IMPORTANT: bind holder.
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) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb).ifPresentOrElse(
vanilla -> terraBiomes.forEach(
tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb).ifPresentOrElse(
terra -> {
LOGGER.debug("{} (vanilla for {}): {}",
vanilla.unwrapKey().orElseThrow().location(),
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);
}
}
}

View File

@ -1,10 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
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 {
}

View File

@ -1,49 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
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 java.util.stream.Stream;
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 = RegistryFetcher.biomeRegistry();
public NMSBiomeProvider(BiomeProvider delegate, long seed) {
super();
this.delegate = delegate;
this.seed = seed;
}
@Override
protected Stream<Holder<Biome>> collectPossibleBiomes() {
return delegate.stream()
.map(biome -> RegistryFetcher.biomeRegistry()
.getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey()));
}
@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());
}
}

View File

@ -1,171 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.LevelAccessor;
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.BiomeManager;
import net.minecraft.world.level.block.Blocks;
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.Beardifier;
import net.minecraft.world.level.levelgen.DensityFunction.SinglePointContext;
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 org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.info.WorldProperties;
import com.dfsek.terra.bukkit.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.bukkit.world.BukkitWorldProperties;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
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(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)
.thenApply(c -> {
LevelAccessor level = Reflection.STRUCTURE_MANAGER.getLevel(structureAccessor);
BiomeProvider biomeProvider = pack.getBiomeProvider();
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
beard(structureAccessor, chunk, new BukkitWorldProperties(level.getMinecraftWorld().getWorld()),
biomeProvider, compatibilityOptions);
}
return c;
});
}
private void beard(StructureManager structureAccessor, ChunkAccess chunk, WorldProperties world, BiomeProvider biomeProvider,
PreLoadCompatibilityOptions compatibilityOptions) {
Beardifier structureWeightSampler = Beardifier.forStructuresInChunk(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.compute(new SinglePointContext(x + xi, y, z + zi));
if(noise > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), ((CraftBlockData) ((BukkitBlockState) delegate
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed())).getHandle()).getState(), false);
depth++;
} else if(noise < airThreshold) {
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.defaultBlockState(), false);
} else {
depth = 0;
}
}
}
}
}
@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();
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();
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) {
}
}

View File

@ -1,15 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
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) {
AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}

View File

@ -1,48 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R3.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());
serverWorld.getChunkSource().chunkMap.generator = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed());
LOGGER.info("Successfully injected into world.");
INJECT_LOCK.unlock();
}
}
}

View File

@ -1,36 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
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();
}
}

View File

@ -1,24 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R3.CraftServer;
public class RegistryFetcher {
private static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.registryAccess()
.registryOrThrow(key);
}
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registries.BIOME);
}
}

View File

@ -1,17 +0,0 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle("1.20.1-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
tasks {
assemble {
dependsOn("reobfJar")
}
}

View File

@ -1,101 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(AwfulBukkitHacks.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) RegistryFetcher.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(biome, Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)));
ResourceKey<Biome> delegateKey = ResourceKey.create(
Registries.BIOME,
new ResourceLocation("terra", NMSBiomeInjector.createBiomeID(pack, key))
);
Reference<Biome> holder = biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
Reflection.REFERENCE.invokeBindValue(holder, platform); // IMPORTANT: bind holder.
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) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb).ifPresentOrElse(
vanilla -> terraBiomes.forEach(
tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb).ifPresentOrElse(
terra -> {
LOGGER.debug("{} (vanilla for {}): {}",
vanilla.unwrapKey().orElseThrow().location(),
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);
}
}
}

View File

@ -1,10 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_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 {
}

View File

@ -1,78 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.flatMap(registry::getHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder();
builder
.downfall(vanilla.climateSettings.downfall())
.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());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build();
}
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);
}
}

View File

@ -1,15 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_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) {
AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}

View File

@ -1,48 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_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());
serverWorld.getChunkSource().chunkMap.generator = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed());
LOGGER.info("Successfully injected into world.");
INJECT_LOCK.unlock();
}
}
}

View File

@ -1,36 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_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();
}
}

View File

@ -1,52 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.StructureManager;
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.MethodName;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
public static final StructureManagerProxy STRUCTURE_MANAGER;
public static final ReferenceProxy REFERENCE;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper,
Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
STRUCTURE_MANAGER = reflectionProxyFactory.reflectionProxy(StructureManagerProxy.class);
REFERENCE = reflectionProxyFactory.reflectionProxy(ReferenceProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
@Proxies(StructureManager.class)
public interface StructureManagerProxy {
@FieldGetter("level")
LevelAccessor getLevel(StructureManager instance);
}
@Proxies(Holder.Reference.class)
public interface ReferenceProxy {
@MethodName("bindValue")
<T> void invokeBindValue(Reference<T> instance, T value);
}
}

View File

@ -1,10 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
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 {
}

View File

@ -1,78 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.flatMap(registry::getHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder();
builder
.downfall(vanilla.climateSettings.downfall())
.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());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build();
}
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);
}
}

View File

@ -1,49 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
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 java.util.stream.Stream;
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 = RegistryFetcher.biomeRegistry();
public NMSBiomeProvider(BiomeProvider delegate, long seed) {
super();
this.delegate = delegate;
this.seed = seed;
}
@Override
protected Stream<Holder<Biome>> collectPossibleBiomes() {
return delegate.stream()
.map(biome -> RegistryFetcher.biomeRegistry()
.getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey()));
}
@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());
}
}

View File

@ -1,171 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.LevelAccessor;
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.BiomeManager;
import net.minecraft.world.level.block.Blocks;
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.Beardifier;
import net.minecraft.world.level.levelgen.DensityFunction.SinglePointContext;
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 org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.info.WorldProperties;
import com.dfsek.terra.bukkit.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.bukkit.world.BukkitWorldProperties;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
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(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)
.thenApply(c -> {
LevelAccessor level = Reflection.STRUCTURE_MANAGER.getLevel(structureAccessor);
BiomeProvider biomeProvider = pack.getBiomeProvider();
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
beard(structureAccessor, chunk, new BukkitWorldProperties(level.getMinecraftWorld().getWorld()),
biomeProvider, compatibilityOptions);
}
return c;
});
}
private void beard(StructureManager structureAccessor, ChunkAccess chunk, WorldProperties world, BiomeProvider biomeProvider,
PreLoadCompatibilityOptions compatibilityOptions) {
Beardifier structureWeightSampler = Beardifier.forStructuresInChunk(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.compute(new SinglePointContext(x + xi, y, z + zi));
if(noise > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), ((CraftBlockData) ((BukkitBlockState) delegate
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed())).getHandle()).getState(), false);
depth++;
} else if(noise < airThreshold) {
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.defaultBlockState(), false);
} else {
depth = 0;
}
}
}
}
}
@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();
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();
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) {
}
}

View File

@ -1,15 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
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) {
AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}

View File

@ -1,48 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R2.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());
serverWorld.getChunkSource().chunkMap.generator = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed());
LOGGER.info("Successfully injected into world.");
INJECT_LOCK.unlock();
}
}
}

View File

@ -1,36 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
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();
}
}

View File

@ -1,52 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.StructureManager;
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.MethodName;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
public static final StructureManagerProxy STRUCTURE_MANAGER;
public static final ReferenceProxy REFERENCE;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper,
Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
STRUCTURE_MANAGER = reflectionProxyFactory.reflectionProxy(StructureManagerProxy.class);
REFERENCE = reflectionProxyFactory.reflectionProxy(ReferenceProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
@Proxies(StructureManager.class)
public interface StructureManagerProxy {
@FieldGetter("level")
LevelAccessor getLevel(StructureManager instance);
}
@Proxies(Holder.Reference.class)
public interface ReferenceProxy {
@MethodName("bindValue")
<T> void invokeBindValue(Reference<T> instance, T value);
}
}

View File

@ -1,24 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
public class RegistryFetcher {
private static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.registryAccess()
.registryOrThrow(key);
}
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registries.BIOME);
}
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_20_R2;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
@ -19,7 +19,7 @@ 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 org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import org.bukkit.Bukkit;

View File

@ -1,9 +1,9 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import net.minecraft.world.level.LevelHeightAccessor;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
package com.dfsek.terra.bukkit.nms.v1_20_R3;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
@ -6,7 +6,7 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
public class RegistryFetcher {

View File

@ -3,7 +3,6 @@ import java.util.*
plugins {
id("dev.architectury.loom") version Versions.Mod.architecuryLoom
id("architectury-plugin") version Versions.Mod.architecturyPlugin
id("io.github.juuxel.loom-vineflower") version Versions.Mod.loomVineflower
}
architectury {

View File

@ -26,9 +26,9 @@
"terra.common.mixins.json"
],
"depends": {
"fabricloader": ">=0.14.2",
"fabricloader": ">=0.15.1",
"java": ">=17",
"minecraft": "1.20.x",
"minecraft": ">=1.20.4",
"fabric": "*"
}
}

View File

@ -1,7 +1,6 @@
plugins {
id("dev.architectury.loom") version Versions.Mod.architecuryLoom
id("architectury-plugin") version Versions.Mod.architecturyPlugin
id("io.github.juuxel.loom-vineflower") version Versions.Mod.loomVineflower
}
loom {
@ -24,7 +23,7 @@ dependencies {
}
architectury {
common("fabric", "forge")
common("fabric")
minecraft = Versions.Mod.minecraft
}

View File

@ -23,6 +23,8 @@ import net.minecraft.command.argument.BlockArgumentParser;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.entity.EntityType;
@ -31,11 +33,21 @@ import com.dfsek.terra.api.handle.WorldHandle;
public class MinecraftWorldHandle implements WorldHandle {
private static final BlockState AIR = (BlockState) Blocks.AIR.getDefaultState();
private static final Logger logger = LoggerFactory.getLogger(MinecraftWorldHandle.class);
@Override
public @NotNull BlockState createBlockState(@NotNull String data) {
try {
if(data.equals("minecraft:grass")) { //TODO: remove in 7.0
data = "minecraft:short_grass";
logger.warn(
"Translating minecraft:grass to minecraft:short_grass. In 1.20.3 minecraft:grass was renamed to minecraft:short_grass" +
". You are advised to preform this rename in your config backs as this translation will be removed in the next major " +
"version of Terra.");
}
net.minecraft.block.BlockState state = BlockArgumentParser.block(Registries.BLOCK.getReadOnlyWrapper(), data, true)
.blockState();
if(state == null) throw new IllegalArgumentException("Invalid data: " + data);

View File

@ -17,8 +17,8 @@
package com.dfsek.terra.mod.mixin.access;
import net.minecraft.world.MobSpawnerEntry;
import net.minecraft.world.MobSpawnerLogic;
import net.minecraft.block.spawner.MobSpawnerEntry;
import net.minecraft.block.spawner.MobSpawnerLogic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

View File

@ -21,11 +21,11 @@ import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.MobSpawnerBlockEntity;
import net.minecraft.block.spawner.MobSpawnerLogic;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.MobSpawnerLogic;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
@ -50,7 +50,7 @@ public abstract class MobSpawnerBlockEntityMixin extends BlockEntity {
public abstract MobSpawnerLogic getLogic();
@Shadow
public abstract void setEntityType(net.minecraft.entity.EntityType<?> entityType, Random random);
public abstract void method_46408(net.minecraft.entity.EntityType<?> entityType, Random random);
public EntityType terra$getSpawnedType() {
return (EntityType) Registries.ENTITY_TYPE.get(
@ -58,7 +58,7 @@ public abstract class MobSpawnerBlockEntityMixin extends BlockEntity {
}
public void terra$setSpawnedType(@NotNull EntityType creatureType) {
setEntityType((net.minecraft.entity.EntityType<?>) creatureType, world.getRandom());
method_46408((net.minecraft.entity.EntityType<?>) creatureType, world.getRandom());
}
public int terra$getDelay() {

View File

@ -1,7 +1,6 @@
plugins {
id("dev.architectury.loom") version Versions.Mod.architecuryLoom
id("architectury-plugin") version Versions.Mod.architecturyPlugin
id("io.github.juuxel.loom-vineflower") version Versions.Mod.loomVineflower
}
dependencies {