From ca274b8d9015c8934b616e4f9d8d286287697240 Mon Sep 17 00:00:00 2001 From: Hex27 Date: Wed, 23 Oct 2024 22:31:12 +0100 Subject: [PATCH] Updated to v17.0.0 --- buildProj/build.gradle.kts | 1 + .../terraform/biome/flat/SavannaHandler.java | 2 +- .../terraform/coregen/NaturalSpawnType.java | 2 +- .../org/terraform/coregen/TerraLootTable.java | 9 + .../bukkit/TerraformAnimalPopulator.java | 14 +- .../org/terraform/main/config/TConfig.java | 9 + .../structure/small/WitchHutPopulator.java | 16 + .../org/terraform/utils/version/Version.java | 1 + common/src/main/resources/plugin.yml | 2 +- .../terraform/v1_18_R2/PopulatorDataICA.java | 1 + .../terraform/v1_19_R3/PopulatorDataICA.java | 1 + .../terraform/v1_20_R1/PopulatorDataICA.java | 1 + .../terraform/v1_20_R2/PopulatorDataICA.java | 1 + .../terraform/v1_20_R3/PopulatorDataICA.java | 1 + .../terraform/v1_20_R4/PopulatorDataICA.java | 1 + .../terraform/v1_21_R1/PopulatorDataICA.java | 1 + implementation/v1_21_R2/.gitignore | 1 + implementation/v1_21_R2/build.gradle.kts | 10 + .../terraform/v1_21_R2/BlockDataFixer.java | 76 +++ .../v1_21_R2/CustomBiomeHandler.java | 288 ++++++++++ .../v1_21_R2/LootTableTranslator.java | 122 +++++ .../v1_21_R2/MapRenderWorldProviderBiome.java | 62 +++ .../terraform/v1_21_R2/NMSChunkGenerator.java | 510 ++++++++++++++++++ .../org/terraform/v1_21_R2/NMSInjector.java | 170 ++++++ .../org/terraform/v1_21_R2/PopulatorData.java | 304 +++++++++++ .../terraform/v1_21_R2/PopulatorDataICA.java | 267 +++++++++ .../v1_21_R2/TerraformWorldProviderBiome.java | 78 +++ settings.gradle.kts | 1 + 28 files changed, 1948 insertions(+), 4 deletions(-) create mode 100644 implementation/v1_21_R2/.gitignore create mode 100644 implementation/v1_21_R2/build.gradle.kts create mode 100644 implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/BlockDataFixer.java create mode 100644 implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/CustomBiomeHandler.java create mode 100644 implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/LootTableTranslator.java create mode 100644 implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/MapRenderWorldProviderBiome.java create mode 100644 implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/NMSChunkGenerator.java create mode 100644 implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/NMSInjector.java create mode 100644 implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/PopulatorData.java create mode 100644 implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/PopulatorDataICA.java create mode 100644 implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/TerraformWorldProviderBiome.java diff --git a/buildProj/build.gradle.kts b/buildProj/build.gradle.kts index 4192ddfa..6026fe1f 100644 --- a/buildProj/build.gradle.kts +++ b/buildProj/build.gradle.kts @@ -17,6 +17,7 @@ dependencies { implementation(project(":implementation:v1_20_R3")) implementation(project(":implementation:v1_20_R4")) implementation(project(":implementation:v1_21_R1")) + implementation(project(":implementation:v1_21_R2")) implementation("com.github.AvarionMC:yaml:1.1.3") } diff --git a/common/src/main/java/org/terraform/biome/flat/SavannaHandler.java b/common/src/main/java/org/terraform/biome/flat/SavannaHandler.java index 907911c0..2ff0e157 100644 --- a/common/src/main/java/org/terraform/biome/flat/SavannaHandler.java +++ b/common/src/main/java/org/terraform/biome/flat/SavannaHandler.java @@ -94,7 +94,7 @@ public void populateSmallItems(TerraformWorld world, .isSolid()) { // Dense grass - if (GenUtils.chance(random, 5, 10)) { + if (GenUtils.chance(random, TConfig.c.BIOME_SAVANNA_TALLGRASSCHANCE, 10000)) { PlantBuilder.TALL_GRASS.build(data, rawX, surfaceY + 1, rawZ); } } diff --git a/common/src/main/java/org/terraform/coregen/NaturalSpawnType.java b/common/src/main/java/org/terraform/coregen/NaturalSpawnType.java index d8a23eb4..c755afde 100644 --- a/common/src/main/java/org/terraform/coregen/NaturalSpawnType.java +++ b/common/src/main/java/org/terraform/coregen/NaturalSpawnType.java @@ -1,5 +1,5 @@ package org.terraform.coregen; public enum NaturalSpawnType { - GUARDIAN, PILLAGER + GUARDIAN, PILLAGER, WITCH } diff --git a/common/src/main/java/org/terraform/coregen/TerraLootTable.java b/common/src/main/java/org/terraform/coregen/TerraLootTable.java index 559203eb..bcf715fc 100644 --- a/common/src/main/java/org/terraform/coregen/TerraLootTable.java +++ b/common/src/main/java/org/terraform/coregen/TerraLootTable.java @@ -104,7 +104,16 @@ public enum TerraLootTable { SHEPHERD_GIFT("gameplay/hero_of_the_village/shepherd_gift"), TOOLSMITH_GIFT("gameplay/hero_of_the_village/toolsmith_gift"), WEAPONSMITH_GIFT("gameplay/hero_of_the_village/weaponsmith_gift"), + UNEMPLOYED_GIFT("gameplay/hero_of_the_village/unemployed_gift"), + BABY_VILLAGER_GIFT("gameplay/hero_of_the_village/baby_gift"), SNIFFER_DIGGING("gameplay/sniffer_digging"), + CHICKEN_LAY("gameplay/chicken_lay"), + ARMADILLO_SHED("gameplay/armadillo_shed"), + SHEAR_MOOSHROOM("gameplay/mooshroom"), + SHEAR_RED_MOOSHROOM("gameplay/mooshroom/red"), + SHEAR_BROWN_MOOSHROOM("gameplay/mooshroom/brown"), + SHEAR_SNOW_GOLEM("gameplay/snow_golem"), + SHEAR_SHEEP("gameplay/sheep"), PANDA_SNEEZE("gameplay/panda_sneeze"), PIGLIN_BARTERING("gameplay/piglin_bartering"), SPAWNER_TRIAL_CHAMBER_KEY("spawners/trial_chamber/key"), diff --git a/common/src/main/java/org/terraform/coregen/bukkit/TerraformAnimalPopulator.java b/common/src/main/java/org/terraform/coregen/bukkit/TerraformAnimalPopulator.java index 75a98de2..8102a3dd 100644 --- a/common/src/main/java/org/terraform/coregen/bukkit/TerraformAnimalPopulator.java +++ b/common/src/main/java/org/terraform/coregen/bukkit/TerraformAnimalPopulator.java @@ -20,7 +20,7 @@ public class TerraformAnimalPopulator extends BlockPopulator { private static final AnimalPopulator[] ANIMAL_POPULATORS = { null, // Slot for goat null, // Slot for armadillo - + null, // Slot for frog new AnimalPopulator(EntityType.PIG, TConfig.c.ANIMALS_PIG_MINHERDSIZE, TConfig.c.ANIMALS_PIG_MAXHERDSIZE, @@ -359,6 +359,18 @@ public TerraformAnimalPopulator(TerraformWorld tw) { BiomeBank.BADLANDS_CANYON ); } + if (Version.isAtLeast(19)) { + ANIMAL_POPULATORS[2] = new AnimalPopulator(EntityType.valueOf("FROG"), + TConfig.c.ANIMALS_FROG_MINHERDSIZE, + TConfig.c.ANIMALS_FROG_MAXHERDSIZE, + TConfig.c.ANIMALS_FROG_CHANCE, + true, + BiomeBank.SWAMP, + BiomeBank.MUDDY_BOG, + BiomeBank.MUDFLATS, + BiomeBank.MANGROVE + ); + } } @Override diff --git a/common/src/main/java/org/terraform/main/config/TConfig.java b/common/src/main/java/org/terraform/main/config/TConfig.java index 182c6ca7..48c34c18 100644 --- a/common/src/main/java/org/terraform/main/config/TConfig.java +++ b/common/src/main/java/org/terraform/main/config/TConfig.java @@ -226,6 +226,8 @@ public static void init(final File f) throws IOException { public int BIOME_ERODED_PLAINS_WEIGHT = 6; @YamlKey("biome.savanna.weight") public int BIOME_SAVANNA_WEIGHT = 6; + @YamlKey("biome.savanna.tallgrass-chance-of-10000") + public int BIOME_SAVANNA_TALLGRASSCHANCE = 5000; @YamlKey("biome.muddybog.weight") public int BIOME_MUDDYBOG_WEIGHT = 2; @YamlKey("biome.forest.weight") @@ -625,6 +627,13 @@ public static void init(final File f) throws IOException { public int ANIMALS_TURTLE_MAXHERDSIZE = 5; @YamlKey("animals.turtle.chance") public int ANIMALS_TURTLE_CHANCE = 1; + // FROG + @YamlKey("animals.frog.min-herd-size") + public int ANIMALS_FROG_MINHERDSIZE = 2; + @YamlKey("animals.frog.max-herd-size") + public int ANIMALS_FROG_MAXHERDSIZE = 5; + @YamlKey("animals.frog.chance") + public int ANIMALS_FROG_CHANCE = 1; // DOLPHIN @YamlKey("animals.dolphin.min-herd-size") public int ANIMALS_DOLPHIN_MINHERDSIZE = 1; diff --git a/common/src/main/java/org/terraform/structure/small/WitchHutPopulator.java b/common/src/main/java/org/terraform/structure/small/WitchHutPopulator.java index 1b9f7e3a..dc5122ce 100644 --- a/common/src/main/java/org/terraform/structure/small/WitchHutPopulator.java +++ b/common/src/main/java/org/terraform/structure/small/WitchHutPopulator.java @@ -8,9 +8,11 @@ import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; import org.terraform.biome.BiomeBank; +import org.terraform.coregen.NaturalSpawnType; import org.terraform.coregen.TerraLootTable; import org.terraform.coregen.bukkit.TerraformGenerator; import org.terraform.coregen.populatordata.PopulatorDataAbstract; +import org.terraform.coregen.populatordata.PopulatorDataPostGen; import org.terraform.data.MegaChunk; import org.terraform.data.SimpleBlock; import org.terraform.data.TerraformWorld; @@ -26,6 +28,7 @@ import java.io.FileNotFoundException; import java.util.EnumSet; import java.util.Locale; +import java.util.Objects; import java.util.Random; public class WitchHutPopulator extends MultiMegaChunkStructurePopulator { @@ -89,6 +92,19 @@ public void spawnSwampHut(TerraformWorld tw, TerraformGeneratorPlugin.logger.stackTrace(e); } + //Register this as a swamp hut with custom spawns + //7x7x9 (x,y,z) + Objects.requireNonNull(TerraformGeneratorPlugin.injector.getICAData(data)) + .registerNaturalSpawns( + NaturalSpawnType.WITCH, + x - 3, + y, + z - 4, + x + 3, + y + 7, + z + 4 + ); + } private boolean rollSpawnRatio(@NotNull TerraformWorld tw, int chunkX, int chunkZ) { diff --git a/common/src/main/java/org/terraform/utils/version/Version.java b/common/src/main/java/org/terraform/utils/version/Version.java index 427105a8..fe8f9da5 100644 --- a/common/src/main/java/org/terraform/utils/version/Version.java +++ b/common/src/main/java/org/terraform/utils/version/Version.java @@ -42,6 +42,7 @@ public enum SupportedVersion { V_1_20_R3("v1_20_R3", 20.3, 20.4), V_1_20_R4("v1_20_R4", 20.5, 20.6), V_1_21_R1("v1_21_R1", 21.0, 21.1), + V_1_21_R2("v1_21_R2", 21.2, 21.3), ; private final double[] versionDouble; private final String packageName; diff --git a/common/src/main/resources/plugin.yml b/common/src/main/resources/plugin.yml index cfcdfa5c..a33a4c22 100644 --- a/common/src/main/resources/plugin.yml +++ b/common/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: TerraformGenerator author: Hex_27 -version: 16.5.0 +version: 17.0.0 api-version: 1.18 description: World Generator main: org.terraform.main.TerraformGeneratorPlugin diff --git a/implementation/v1_18_R2/src/main/java/org/terraform/v1_18_R2/PopulatorDataICA.java b/implementation/v1_18_R2/src/main/java/org/terraform/v1_18_R2/PopulatorDataICA.java index 3cb47892..8a2e09ad 100644 --- a/implementation/v1_18_R2/src/main/java/org/terraform/v1_18_R2/PopulatorDataICA.java +++ b/implementation/v1_18_R2/src/main/java/org/terraform/v1_18_R2/PopulatorDataICA.java @@ -156,6 +156,7 @@ public void registerNaturalSpawns(@NotNull NaturalSpawnType type, int x0, int y0 ResourceKey> structureKey = switch (type) { case GUARDIAN -> BuiltinStructures.l; // Ocean Monument case PILLAGER -> BuiltinStructures.a; // Pillager Outpost + case WITCH -> BuiltinStructures.j; // Swamp Hut }; // Monument CraftServer craftserver = (CraftServer) Bukkit.getServer(); diff --git a/implementation/v1_19_R3/src/main/java/org/terraform/v1_19_R3/PopulatorDataICA.java b/implementation/v1_19_R3/src/main/java/org/terraform/v1_19_R3/PopulatorDataICA.java index cd84e484..5947465c 100644 --- a/implementation/v1_19_R3/src/main/java/org/terraform/v1_19_R3/PopulatorDataICA.java +++ b/implementation/v1_19_R3/src/main/java/org/terraform/v1_19_R3/PopulatorDataICA.java @@ -159,6 +159,7 @@ public void registerNaturalSpawns(@NotNull NaturalSpawnType type, int x0, int y0 ResourceKey structureKey = switch (type) { case GUARDIAN -> BuiltinStructures.l; // Ocean Monument case PILLAGER -> BuiltinStructures.a; // Pillager Outpost + case WITCH -> BuiltinStructures.j; // Swamp Hut }; // ax is STRUCTURE diff --git a/implementation/v1_20_R1/src/main/java/org/terraform/v1_20_R1/PopulatorDataICA.java b/implementation/v1_20_R1/src/main/java/org/terraform/v1_20_R1/PopulatorDataICA.java index f789a080..bd2dbcb6 100644 --- a/implementation/v1_20_R1/src/main/java/org/terraform/v1_20_R1/PopulatorDataICA.java +++ b/implementation/v1_20_R1/src/main/java/org/terraform/v1_20_R1/PopulatorDataICA.java @@ -175,6 +175,7 @@ public void registerNaturalSpawns(@NotNull NaturalSpawnType type, int x0, int y0 ResourceKey structureKey = switch (type) { case GUARDIAN -> BuiltinStructures.l; // Ocean Monument case PILLAGER -> BuiltinStructures.a; // Pillager Outpost + case WITCH -> BuiltinStructures.j; // Swamp Hut }; // ax is STRUCTURE diff --git a/implementation/v1_20_R2/src/main/java/org/terraform/v1_20_R2/PopulatorDataICA.java b/implementation/v1_20_R2/src/main/java/org/terraform/v1_20_R2/PopulatorDataICA.java index f1f28fdf..88ea8b5a 100644 --- a/implementation/v1_20_R2/src/main/java/org/terraform/v1_20_R2/PopulatorDataICA.java +++ b/implementation/v1_20_R2/src/main/java/org/terraform/v1_20_R2/PopulatorDataICA.java @@ -175,6 +175,7 @@ public void registerNaturalSpawns(@NotNull NaturalSpawnType type, int x0, int y0 ResourceKey structureKey = switch (type) { case GUARDIAN -> BuiltinStructures.l; // Ocean Monument case PILLAGER -> BuiltinStructures.a; // Pillager Outpost + case WITCH -> BuiltinStructures.j; // Swamp Hut }; // az is STRUCTURE diff --git a/implementation/v1_20_R3/src/main/java/org/terraform/v1_20_R3/PopulatorDataICA.java b/implementation/v1_20_R3/src/main/java/org/terraform/v1_20_R3/PopulatorDataICA.java index 93156af7..91673505 100644 --- a/implementation/v1_20_R3/src/main/java/org/terraform/v1_20_R3/PopulatorDataICA.java +++ b/implementation/v1_20_R3/src/main/java/org/terraform/v1_20_R3/PopulatorDataICA.java @@ -171,6 +171,7 @@ public void registerNaturalSpawns(@NotNull NaturalSpawnType type, int x0, int y0 ResourceKey structureKey = switch (type) { case GUARDIAN -> BuiltinStructures.l; // Ocean Monument case PILLAGER -> BuiltinStructures.a; // Pillager Outpost + case WITCH -> BuiltinStructures.j; // Swamp Hut }; // aD is STRUCTURE diff --git a/implementation/v1_20_R4/src/main/java/org/terraform/v1_20_R4/PopulatorDataICA.java b/implementation/v1_20_R4/src/main/java/org/terraform/v1_20_R4/PopulatorDataICA.java index e5b1dbf0..5f39a39d 100644 --- a/implementation/v1_20_R4/src/main/java/org/terraform/v1_20_R4/PopulatorDataICA.java +++ b/implementation/v1_20_R4/src/main/java/org/terraform/v1_20_R4/PopulatorDataICA.java @@ -171,6 +171,7 @@ public void registerNaturalSpawns(@NotNull NaturalSpawnType type, int x0, int y0 ResourceKey structureKey = switch (type) { case GUARDIAN -> BuiltinStructures.l; // Ocean Monument case PILLAGER -> BuiltinStructures.a; // Pillager Outpost + case WITCH -> BuiltinStructures.j; // Swamp Hut }; // bc is registryAccess diff --git a/implementation/v1_21_R1/src/main/java/org/terraform/v1_21_R1/PopulatorDataICA.java b/implementation/v1_21_R1/src/main/java/org/terraform/v1_21_R1/PopulatorDataICA.java index 6bb39907..9d2a9415 100644 --- a/implementation/v1_21_R1/src/main/java/org/terraform/v1_21_R1/PopulatorDataICA.java +++ b/implementation/v1_21_R1/src/main/java/org/terraform/v1_21_R1/PopulatorDataICA.java @@ -171,6 +171,7 @@ public void registerNaturalSpawns(@NotNull NaturalSpawnType type, int x0, int y0 ResourceKey structureKey = switch (type) { case GUARDIAN -> BuiltinStructures.l; // Ocean Monument case PILLAGER -> BuiltinStructures.a; // Pillager Outpost + case WITCH -> BuiltinStructures.j; // Swamp Hut }; // bc is registryAccess diff --git a/implementation/v1_21_R2/.gitignore b/implementation/v1_21_R2/.gitignore new file mode 100644 index 00000000..84c048a7 --- /dev/null +++ b/implementation/v1_21_R2/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/implementation/v1_21_R2/build.gradle.kts b/implementation/v1_21_R2/build.gradle.kts new file mode 100644 index 00000000..e281165a --- /dev/null +++ b/implementation/v1_21_R2/build.gradle.kts @@ -0,0 +1,10 @@ +dependencies { + implementation(project(":common")) + compileOnly(group = "org.spigotmc", name = "spigot", version = "1.21.2-R0.1-SNAPSHOT") + compileOnly("org.jetbrains:annotations:20.1.0") + compileOnly("com.github.AvarionMC:yaml:1.1.3") +} +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/BlockDataFixer.java b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/BlockDataFixer.java new file mode 100644 index 00000000..59f59c2b --- /dev/null +++ b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/BlockDataFixer.java @@ -0,0 +1,76 @@ +package org.terraform.v1_21_R2; + +import org.bukkit.Tag; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Wall; +import org.bukkit.block.data.type.Wall.Height; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.terraform.coregen.BlockDataFixerAbstract; +import org.terraform.data.SimpleBlock; +import org.terraform.utils.BlockUtils; + +public class BlockDataFixer extends BlockDataFixerAbstract { + + // --------[1.16 stuff] + public static void correctWallData(@NotNull SimpleBlock target) { + if (!(target.getBlockData() instanceof Wall data)) { + return; + } + for (BlockFace face : BlockUtils.directBlockFaces) { + if (target.getRelative(face).isSolid() && !target.getRelative(face) + .getType() + .toString() + .contains("PRESSURE_PLATE")) + { + data.setHeight(face, Height.LOW); + if (target.getRelative(BlockFace.UP).isSolid()) { + data.setHeight(face, Height.TALL); + } + } + else { + data.setHeight(face, Height.NONE); + } + } + + // target.setBlockData(data); + } + + public static void correctSurroundingWallData(@NotNull SimpleBlock target) { + if (!(target.getBlockData() instanceof Wall)) { + return; + } + + correctWallData(target); + for (BlockFace face : BlockUtils.directBlockFaces) { + if (Tag.WALLS.isTagged(target.getRelative(face).getType())) { + correctWallData(target.getRelative(face)); + } + } + } + + @Override + public String updateSchematic(double schematicVersion, String schematic) { + return schematic; + } + + @Override + public void correctFacing(Vector v, @Nullable SimpleBlock b, @Nullable BlockData data, BlockFace face) { + if (data == null && b != null) { + data = b.getBlockData(); + } + + if (!hasFlushed && data instanceof Wall) { + this.pushChanges(v); + return; + } + + if (data instanceof Wall && b != null) { + // 1.16 stuff. + correctSurroundingWallData(b); + } + } + +} diff --git a/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/CustomBiomeHandler.java b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/CustomBiomeHandler.java new file mode 100644 index 00000000..a941c47c --- /dev/null +++ b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/CustomBiomeHandler.java @@ -0,0 +1,288 @@ +package org.terraform.v1_21_R2; + +import net.minecraft.core.Holder; +import net.minecraft.core.IRegistry; +import net.minecraft.core.IRegistryWritable; +import net.minecraft.core.RegistryMaterials; +import net.minecraft.tags.TagKey; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.MinecraftKey; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ReloadableServerRegistries; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.world.level.biome.*; +import net.minecraft.world.level.biome.BiomeFog.GrassColor; +import org.bukkit.Bukkit; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.v1_21_R2.CraftServer; +import org.bukkit.craftbukkit.v1_21_R2.block.CraftBiome; +import org.jetbrains.annotations.NotNull; +import org.terraform.biome.custombiomes.CustomBiomeType; +import org.terraform.main.TerraformGeneratorPlugin; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; +import java.util.stream.Collectors; + +public class CustomBiomeHandler { + + public static final HashMap> terraformGenBiomeRegistry = new HashMap<>(); + + public static IRegistry getBiomeRegistry() + { + // aI is BIOME + // ba is registryAccess + // a is lookup (for an optional) + return MinecraftServer.getServer().ba().a(Registries.aI).orElseThrow(); + } + + public static void init() { + CraftServer craftserver = (CraftServer) Bukkit.getServer(); + DedicatedServer dedicatedserver = craftserver.getServer(); + IRegistryWritable registrywritable = (IRegistryWritable) getBiomeRegistry(); + + // This thing isn't actually writable, so we have to forcefully UNFREEZE IT + // l is frozen + try { + Field frozen = RegistryMaterials.class.getDeclaredField("l"); + frozen.setAccessible(true); + frozen.set(registrywritable, false); + TerraformGeneratorPlugin.logger.info("Unfreezing biome registry..."); + } + catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e1) { + TerraformGeneratorPlugin.logger.stackTrace(e1); + } + + //p is createRegistrationLookup + //b is getOrThrow + //a is value() + Holder forestbiome = registrywritable.p().b(Biomes.i); // forest + + for (CustomBiomeType type : CustomBiomeType.values()) { + if (type == CustomBiomeType.NONE) { + continue; + } + + try { + assert forestbiome != null; + registerCustomBiomeBase(type, dedicatedserver, registrywritable, forestbiome); + TerraformGeneratorPlugin.logger.info("Registered custom biome: " + type.toString() + .toLowerCase(Locale.ENGLISH)); + } + catch (Throwable e) { + TerraformGeneratorPlugin.logger.error("Failed to register custom biome: " + type.getKey()); + TerraformGeneratorPlugin.logger.stackTrace(e); + } + } + + try { + Field frozen = RegistryMaterials.class.getDeclaredField("l"); + frozen.setAccessible(true); + frozen.set(registrywritable, true); + TerraformGeneratorPlugin.logger.info("Freezing biome registry"); + } + catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e1) { + TerraformGeneratorPlugin.logger.stackTrace(e1); + } + + } + + private static void registerCustomBiomeBase(@NotNull CustomBiomeType biomeType, + DedicatedServer dedicatedserver, + @NotNull IRegistryWritable registrywritable, + @NotNull Holder forestBiomeHolder) throws Throwable + { + + BiomeBase forestbiome = forestBiomeHolder.a(); + + // be is reloadableRegistries() + // a is get() + // b is DEFAULT_REGISTRATION_INFO + Field defaultRegInfoField = ReloadableServerRegistries.class.getDeclaredField("b"); + defaultRegInfoField.setAccessible(true); + Object regInfo = defaultRegInfoField.get(null); + + // aI is BIOME + ResourceKey newKey = ResourceKey.a( + Registries.aI, + MinecraftKey.a("terraformgenerator", biomeType.toString().toLowerCase(Locale.ENGLISH)) + ); + + // BiomeBase.a is BiomeBuilder + BiomeBase.a newBiomeBuilder = new BiomeBase.a(); + + // BiomeBase.b is ClimateSettings + // d is temperatureModifier + // This temperature modifier stuff is more cleanly handled below. + // Class climateSettingsClass = Class.forName("net.minecraft.world.level.biome.BiomeBase.b"); + // Field temperatureModififierField = climateSettingsClass.getDeclaredField("d"); + // temperatureModififierField.setAccessible(true); + + // i is climateSettings + newBiomeBuilder.a(forestbiome.c()); // c is getPrecipitation + + // k is mobSettings + Field biomeSettingMobsField = BiomeBase.class.getDeclaredField("k"); + biomeSettingMobsField.setAccessible(true); + BiomeSettingsMobs biomeSettingMobs = (BiomeSettingsMobs) biomeSettingMobsField.get(forestbiome); + newBiomeBuilder.a(biomeSettingMobs); + + // j is generationSettings + Field biomeSettingGenField = BiomeBase.class.getDeclaredField("j"); + biomeSettingGenField.setAccessible(true); + BiomeSettingsGeneration biomeSettingGen = (BiomeSettingsGeneration) biomeSettingGenField.get(forestbiome); + newBiomeBuilder.a(biomeSettingGen); + + newBiomeBuilder.a(0.7F); // Temperature of biome + newBiomeBuilder.b(biomeType.getRainFall()); // Downfall of biome + + // BiomeBase.TemperatureModifier.a will make your biome normal + // BiomeBase.TemperatureModifier.b will make your biome frozen + if (biomeType.isCold()) { + newBiomeBuilder.a(BiomeBase.TemperatureModifier.b); + } + else { + newBiomeBuilder.a(BiomeBase.TemperatureModifier.a); + } + + BiomeFog.a newFog = new BiomeFog.a(); + newFog.a(GrassColor.a); // This doesn't affect the actual final grass color, just leave this line as it is or you will get errors + + // Set biome colours. If field is empty, default to forest color + + // fogcolor + newFog.a(biomeType.getFogColor().isEmpty() ? forestbiome.e() : Integer.parseInt(biomeType.getFogColor(), 16)); + + // water color i is getWaterColor + newFog.b(biomeType.getWaterColor().isEmpty() + ? forestbiome.i() + : Integer.parseInt(biomeType.getWaterColor(), 16)); + + // water fog color j is getWaterFogColor + newFog.c(biomeType.getWaterFogColor().isEmpty() + ? forestbiome.j() + : Integer.parseInt(biomeType.getWaterFogColor(), 16)); + + // sky color + newFog.d(biomeType.getSkyColor().isEmpty() ? forestbiome.a() : Integer.parseInt(biomeType.getSkyColor(), 16)); + + + // Unnecessary values; can be removed safely if you don't want to change them + + // foliage color (leaves, fines and more) f is getFoliageColor + newFog.e(biomeType.getFoliageColor().isEmpty() + ? forestbiome.f() + : Integer.parseInt(biomeType.getFoliageColor(), 16)); + + // grass blocks color + newFog.f(biomeType.getGrassColor().isEmpty() + ? Integer.parseInt("79C05A", 16) + : Integer.parseInt(biomeType.getGrassColor(), 16)); + + + newBiomeBuilder.a(newFog.a()); + + BiomeBase biome = newBiomeBuilder.a(); // biomebuilder.build(); + + // Inject into the data registry for biomes + // RegistryGeneration.a(RegistryGeneration.i, newKey, biome); + + // p is createRegistrationLookup + // a is get. This replaced a contains() check. + // get().b() is get().isBound(). If it is bound, its used. + if (registrywritable.p().a(newKey).isPresent() + && registrywritable.p().a(newKey).get().b()) { + TerraformGeneratorPlugin.logger.info(newKey + " was already registered. Was there a plugin/server reload?"); + return; + } + + // Inject into the biome registry + // al is BIOMES + // aW is registryAccess + // d is registryOrThrow + // RegistryMaterials registry = (RegistryMaterials) getBiomeRegistry(); + + // Inject unregisteredIntrusiveHolders with a new map to allow intrusive holders + // m is unregisteredIntrusiveHolders + // Field unregisteredIntrusiveHolders = RegistryMaterials.class.getDeclaredField("m"); + // unregisteredIntrusiveHolders.setAccessible(true); + // unregisteredIntrusiveHolders.set(registrywritable, new IdentityHashMap<>()); + + // f is createIntrusiveHolder + // registrywritable.f(biome); + + // a is RegistryMaterials.register + // Holder.c is Holder.Reference + Method register = registrywritable.getClass().getDeclaredMethod("a", + net.minecraft.resources.ResourceKey.class, + Object.class, + Class.forName("net.minecraft.core.RegistrationInfo") + ); + register.setAccessible(true); + Holder.c holder = (Holder.c) register.invoke(registrywritable, newKey, biome, regInfo); + + // Holder.Reference.bindValue + Method bindValue = Holder.c.class.getDeclaredMethod("b", Object.class); + bindValue.setAccessible(true); + bindValue.invoke(holder, biome); + + + //Biomes also have TagKeys (See minecraft.tags.BiomeTags) + // Clone the plains tag keys + //forestBiomeHolder.tags().toList() + Set> tags = new HashSet>(); + forestBiomeHolder.c().forEach(tags::add); + + // Holder.Reference.bindTags + Method bindTags = Holder.c.class.getDeclaredMethod("a",java.util.Collection.class); + bindTags.setAccessible(true); + bindTags.invoke(holder, tags); + + + // what the fuck is happening here 23/4/2024 + + // Make unregisteredIntrusiveHolders null again to remove potential for undefined behaviour + // unregisteredIntrusiveHolders.set(registrywritable, null); + + // There is a slightly cleaner way this can be done (void bindValue(T value) + // instead of the whole unregistered intrusive holders stuff), + // but it also involves reflection so I don't want to + // change this out just yet. Consider for the next version. + terraformGenBiomeRegistry.put(biomeType, newKey); + + } + + + public static Set> biomeListToBiomeBaseSet(@NotNull IRegistry registry) { + + List> biomeBases = new ArrayList<>(); + + for (Biome biome : Biome.values()) { + if (biome == null || biome == Biome.CUSTOM) { + continue; + } + try { + // Preconditions.checkArgument(biome != Biome.CUSTOM, "Cannot use the biome %s", biome); + biomeBases.add(CraftBiome.bukkitToMinecraftHolder(biome)); + } + catch (Throwable e) { + TerraformGeneratorPlugin.logger.info("Ignoring biome " + biome); + } + } + + for (CustomBiomeType cbt : CustomBiomeType.values()) { + if (cbt == CustomBiomeType.NONE) { + continue; + } + ResourceKey rkey = CustomBiomeHandler.terraformGenBiomeRegistry.get(cbt); + // TerraformGeneratorPlugin.logger.info(cbt + " --- " + rkey); + // Holder.c is Holder.Reference. It implements Holder. No idk why. + Optional> holder = registry.a(rkey); + holder.ifPresent(biomeBases::add); + } + + return Set.copyOf(biomeBases); + } +} diff --git a/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/LootTableTranslator.java b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/LootTableTranslator.java new file mode 100644 index 00000000..f49aab5f --- /dev/null +++ b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/LootTableTranslator.java @@ -0,0 +1,122 @@ +package org.terraform.v1_21_R2; + +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.LootTables; +import org.terraform.coregen.TerraLootTable; + +import java.util.HashMap; + +public class LootTableTranslator { + + // I am indeed formally trained to properly structure my code + // I have however elected to completely ignore said training here + public static final HashMap> translationMap = new HashMap<>() {{ + put(TerraLootTable.SPAWN_BONUS_CHEST, LootTables.a); + put(TerraLootTable.END_CITY_TREASURE, LootTables.b); + put(TerraLootTable.SIMPLE_DUNGEON, LootTables.c); + put(TerraLootTable.VILLAGE_WEAPONSMITH, LootTables.d); + put(TerraLootTable.VILLAGE_TOOLSMITH, LootTables.e); + put(TerraLootTable.VILLAGE_ARMORER, LootTables.f); + put(TerraLootTable.VILLAGE_CARTOGRAPHER, LootTables.g); + put(TerraLootTable.VILLAGE_MASON, LootTables.h); + put(TerraLootTable.VILLAGE_SHEPHERD, LootTables.i); + put(TerraLootTable.VILLAGE_BUTCHER, LootTables.j); + put(TerraLootTable.VILLAGE_FLETCHER, LootTables.k); + put(TerraLootTable.VILLAGE_FISHER, LootTables.l); + put(TerraLootTable.VILLAGE_TANNERY, LootTables.m); + put(TerraLootTable.VILLAGE_TEMPLE, LootTables.n); + put(TerraLootTable.VILLAGE_DESERT_HOUSE, LootTables.o); + put(TerraLootTable.VILLAGE_PLAINS_HOUSE, LootTables.p); + put(TerraLootTable.VILLAGE_TAIGA_HOUSE, LootTables.q); + put(TerraLootTable.VILLAGE_SNOWY_HOUSE, LootTables.r); + put(TerraLootTable.VILLAGE_SAVANNA_HOUSE, LootTables.s); + put(TerraLootTable.ABANDONED_MINESHAFT, LootTables.t); + put(TerraLootTable.NETHER_BRIDGE, LootTables.u); + put(TerraLootTable.STRONGHOLD_LIBRARY, LootTables.v); + put(TerraLootTable.STRONGHOLD_CROSSING, LootTables.w); + put(TerraLootTable.STRONGHOLD_CORRIDOR, LootTables.x); + put(TerraLootTable.DESERT_PYRAMID, LootTables.y); + put(TerraLootTable.JUNGLE_TEMPLE, LootTables.z); + put(TerraLootTable.JUNGLE_TEMPLE_DISPENSER, LootTables.A); + put(TerraLootTable.IGLOO_CHEST, LootTables.B); + put(TerraLootTable.WOODLAND_MANSION, LootTables.C); + put(TerraLootTable.UNDERWATER_RUIN_SMALL, LootTables.D); + put(TerraLootTable.UNDERWATER_RUIN_BIG, LootTables.E); + put(TerraLootTable.BURIED_TREASURE, LootTables.F); + put(TerraLootTable.SHIPWRECK_MAP, LootTables.G); + put(TerraLootTable.SHIPWRECK_SUPPLY, LootTables.H); + put(TerraLootTable.SHIPWRECK_TREASURE, LootTables.I); + put(TerraLootTable.PILLAGER_OUTPOST, LootTables.J); + put(TerraLootTable.BASTION_TREASURE, LootTables.K); + put(TerraLootTable.BASTION_OTHER, LootTables.L); + put(TerraLootTable.BASTION_BRIDGE, LootTables.M); + put(TerraLootTable.BASTION_HOGLIN_STABLE, LootTables.N); + put(TerraLootTable.ANCIENT_CITY, LootTables.O); + put(TerraLootTable.ANCIENT_CITY_ICE_BOX, LootTables.P); + put(TerraLootTable.RUINED_PORTAL, LootTables.Q); + put(TerraLootTable.TRIAL_CHAMBERS_REWARD, LootTables.R); + put(TerraLootTable.TRIAL_CHAMBERS_REWARD_COMMON, LootTables.S); + put(TerraLootTable.TRIAL_CHAMBERS_REWARD_RARE, LootTables.T); + put(TerraLootTable.TRIAL_CHAMBERS_REWARD_UNIQUE, LootTables.U); + put(TerraLootTable.TRIAL_CHAMBERS_REWARD_OMINOUS, LootTables.V); + put(TerraLootTable.TRIAL_CHAMBERS_REWARD_OMINOUS_COMMON, LootTables.W); + put(TerraLootTable.TRIAL_CHAMBERS_REWARD_OMINOUS_RARE, LootTables.X); + put(TerraLootTable.TRIAL_CHAMBERS_REWARD_OMINOUS_UNIQUE, LootTables.Y); + put(TerraLootTable.TRIAL_CHAMBERS_SUPPLY, LootTables.Z); + put(TerraLootTable.TRIAL_CHAMBERS_CORRIDOR, LootTables.aa); + put(TerraLootTable.TRIAL_CHAMBERS_INTERSECTION, LootTables.ab); + put(TerraLootTable.TRIAL_CHAMBERS_INTERSECTION_BARREL, LootTables.ac); + put(TerraLootTable.TRIAL_CHAMBERS_ENTRANCE, LootTables.ad); + put(TerraLootTable.TRIAL_CHAMBERS_CORRIDOR_DISPENSER, LootTables.ae); + put(TerraLootTable.TRIAL_CHAMBERS_CHAMBER_DISPENSER, LootTables.af); + put(TerraLootTable.TRIAL_CHAMBERS_WATER_DISPENSER, LootTables.ag); + put(TerraLootTable.TRIAL_CHAMBERS_CORRIDOR_POT, LootTables.ah); + put(TerraLootTable.EQUIPMENT_TRIAL_CHAMBER, LootTables.ai); + put(TerraLootTable.EQUIPMENT_TRIAL_CHAMBER_RANGED, LootTables.aj); + put(TerraLootTable.EQUIPMENT_TRIAL_CHAMBER_MELEE, LootTables.ak); + put(TerraLootTable.FISHING, LootTables.am); + put(TerraLootTable.FISHING_JUNK, LootTables.an); + put(TerraLootTable.FISHING_TREASURE, LootTables.ao); + put(TerraLootTable.FISHING_FISH, LootTables.ap); + put(TerraLootTable.CAT_MORNING_GIFT, LootTables.aq); + put(TerraLootTable.ARMORER_GIFT, LootTables.ar); + put(TerraLootTable.BUTCHER_GIFT, LootTables.as); + put(TerraLootTable.CARTOGRAPHER_GIFT, LootTables.at); + put(TerraLootTable.CLERIC_GIFT, LootTables.au); + put(TerraLootTable.FARMER_GIFT, LootTables.av); + put(TerraLootTable.FISHERMAN_GIFT, LootTables.aw); + put(TerraLootTable.FLETCHER_GIFT, LootTables.ax); + put(TerraLootTable.LEATHERWORKER_GIFT, LootTables.ay); + put(TerraLootTable.LIBRARIAN_GIFT, LootTables.az); + put(TerraLootTable.MASON_GIFT, LootTables.aA); + put(TerraLootTable.SHEPHERD_GIFT, LootTables.aB); + put(TerraLootTable.TOOLSMITH_GIFT, LootTables.aC); + put(TerraLootTable.WEAPONSMITH_GIFT, LootTables.aD); + put(TerraLootTable.UNEMPLOYED_GIFT, LootTables.aE); + put(TerraLootTable.BABY_VILLAGER_GIFT, LootTables.aF); + put(TerraLootTable.SNIFFER_DIGGING, LootTables.aG); + put(TerraLootTable.PANDA_SNEEZE, LootTables.aH); + put(TerraLootTable.CHICKEN_LAY, LootTables.aI); + put(TerraLootTable.ARMADILLO_SHED, LootTables.aJ); + put(TerraLootTable.PIGLIN_BARTERING, LootTables.aK); + put(TerraLootTable.SPAWNER_TRIAL_CHAMBER_KEY, LootTables.aL); + put(TerraLootTable.SPAWNER_TRIAL_CHAMBER_CONSUMABLES, LootTables.aM); + put(TerraLootTable.SPAWNER_OMINOUS_TRIAL_CHAMBER_KEY, LootTables.aN); + put(TerraLootTable.SPAWNER_OMINOUS_TRIAL_CHAMBER_CONSUMABLES, LootTables.aO); + put(TerraLootTable.SPAWNER_TRIAL_ITEMS_TO_DROP_WHEN_OMINOUS, LootTables.aP); + put(TerraLootTable.BOGGED_SHEAR, LootTables.aQ); + put(TerraLootTable.SHEAR_MOOSHROOM, LootTables.aR); + put(TerraLootTable.SHEAR_RED_MOOSHROOM, LootTables.aS); + put(TerraLootTable.SHEAR_BROWN_MOOSHROOM, LootTables.aT); + put(TerraLootTable.SHEAR_SNOW_GOLEM, LootTables.aU); + put(TerraLootTable.SHEAR_SHEEP, LootTables.aV); + put(TerraLootTable.DESERT_WELL_ARCHAEOLOGY, LootTables.aX); + put(TerraLootTable.DESERT_PYRAMID_ARCHAEOLOGY, LootTables.aY); + put(TerraLootTable.TRAIL_RUINS_ARCHAEOLOGY_COMMON, LootTables.aZ); + put(TerraLootTable.TRAIL_RUINS_ARCHAEOLOGY_RARE, LootTables.ba); + put(TerraLootTable.OCEAN_RUIN_WARM_ARCHAEOLOGY, LootTables.bb); + put(TerraLootTable.OCEAN_RUIN_COLD_ARCHAEOLOGY, LootTables.bc); + }}; + +} diff --git a/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/MapRenderWorldProviderBiome.java b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/MapRenderWorldProviderBiome.java new file mode 100644 index 00000000..9e2826b5 --- /dev/null +++ b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/MapRenderWorldProviderBiome.java @@ -0,0 +1,62 @@ +package org.terraform.v1_21_R2; + +import com.mojang.serialization.MapCodec; +import net.minecraft.core.Holder; +import net.minecraft.core.IRegistry; +import net.minecraft.world.level.biome.BiomeBase; +import net.minecraft.world.level.biome.Climate.Sampler; +import net.minecraft.world.level.biome.WorldChunkManager; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.v1_21_R2.block.CraftBiome; +import org.terraform.coregen.HeightMap; +import org.terraform.data.TerraformWorld; +import org.terraform.main.config.TConfig; + +import java.util.Set; +import java.util.stream.Stream; + +public class MapRenderWorldProviderBiome extends WorldChunkManager { + @SuppressWarnings("unused") + private static final boolean debug = false; + private final TerraformWorld tw; + private final Set> biomeList; + private final Holder river; + private final Holder plains; + + public MapRenderWorldProviderBiome(TerraformWorld tw, WorldChunkManager delegate) { + // super(biomeListToBiomeBaseList(CustomBiomeHandler.getBiomeRegistry())); + this.biomeList = CustomBiomeHandler.biomeListToBiomeBaseSet(CustomBiomeHandler.getBiomeRegistry()); + this.tw = tw; + IRegistry registry = CustomBiomeHandler.getBiomeRegistry(); + this.river = CraftBiome.bukkitToMinecraftHolder(Biome.RIVER); + this.plains = CraftBiome.bukkitToMinecraftHolder(Biome.PLAINS); + } + + @Override + public Stream> b() + { + return this.biomeList.stream(); + } + + @Override // c is getPossibleBiomes + public Set> c() + { + return this.biomeList; + } + + @Override + protected MapCodec a() { + throw new UnsupportedOperationException("Cannot serialize MapRenderWorldProviderBiome"); + } + + @Override + public Holder getNoiseBiome(int x, int y, int z, Sampler arg3) { + // Used to be attempted for cave gen. That didn't work, so now, this is + // for optimising cartographers and buried treasure. + // This will return river or plains depending on whether + // the area is submerged. + + return HeightMap.getBlockHeight(tw, x, z) <= TConfig.c.HEIGHT_MAP_SEA_LEVEL ? river : plains; + } + +} diff --git a/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/NMSChunkGenerator.java b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/NMSChunkGenerator.java new file mode 100644 index 00000000..990ef310 --- /dev/null +++ b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/NMSChunkGenerator.java @@ -0,0 +1,510 @@ +package org.terraform.v1_21_R2; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.MapCodec; +import it.unimi.dsi.fastutil.ints.IntArraySet; +import it.unimi.dsi.fastutil.objects.ObjectArraySet; +import net.minecraft.*; +import net.minecraft.core.*; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.MinecraftKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.RegionLimitedWorldAccess; +import net.minecraft.server.level.WorldServer; +import net.minecraft.world.level.BlockColumn; +import net.minecraft.world.level.ChunkCoordIntPair; +import net.minecraft.world.level.GeneratorAccessSeed; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.biome.*; +import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.levelgen.*; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureBoundingBox; +import net.minecraft.world.level.levelgen.structure.StructureSet; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement; +import net.minecraft.world.level.levelgen.structure.structures.BuriedTreasureStructure; +import net.minecraft.world.level.levelgen.structure.structures.JigsawStructure; +import net.minecraft.world.level.levelgen.structure.structures.OceanMonumentStructure; +import net.minecraft.world.level.levelgen.structure.structures.StrongholdStructure; +import net.minecraft.world.level.levelgen.structure.structures.WoodlandMansionStructure; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.jetbrains.annotations.NotNull; +import org.terraform.coregen.bukkit.TerraformGenerator; +import org.terraform.data.MegaChunk; +import org.terraform.data.TerraformWorld; +import org.terraform.main.TerraformGeneratorPlugin; +import org.terraform.main.config.TConfig; +import org.terraform.structure.SingleMegaChunkStructurePopulator; +import org.terraform.structure.StructureLocator; +import org.terraform.structure.StructurePopulator; +import org.terraform.structure.StructureRegistry; +import org.terraform.structure.VanillaStructurePopulator; +import org.terraform.structure.monument.MonumentPopulator; +import org.terraform.structure.pillager.mansion.MansionPopulator; +import org.terraform.structure.small.buriedtreasure.BuriedTreasurePopulator; +import org.terraform.structure.stronghold.StrongholdPopulator; +import org.terraform.structure.trialchamber.TrialChamberPopulator; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class NMSChunkGenerator extends ChunkGenerator { + private final @NotNull ChunkGenerator delegate; + private final @NotNull TerraformWorld tw; + private final @NotNull MapRenderWorldProviderBiome mapRendererBS; + private final @NotNull TerraformWorldProviderBiome twBS; + private final @NotNull Method tryGenerateStructure; + private final ArrayList possibleStructureSets = new ArrayList<>(); + + private final @NotNull Method getWriteableArea; + private final @NotNull Supplier featuresPerStep; + + public NMSChunkGenerator(String worldName, long seed, @NotNull ChunkGenerator delegate) + throws NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalAccessException + { + super( + delegate.d(), // WorldChunkManager d() is getBiomeSource() + delegate.d); // Idk what generationSettingsGetter is + tw = TerraformWorld.get(worldName, seed); + this.delegate = delegate; + + // Set the long term biome handler to this one. The normal behaving one + // is initiated inside the cave carver + mapRendererBS = new MapRenderWorldProviderBiome(tw, delegate.d()); + twBS = new TerraformWorldProviderBiome(TerraformWorld.get(worldName, seed), delegate.d()); + + //This is needed for addVanillaFeatures + Field f = ChunkGenerator.class.getDeclaredField("c"); + f.setAccessible(true); + featuresPerStep = (Supplier) f.get(delegate); + + getWriteableArea = ChunkGenerator.class.getDeclaredMethod("a", IChunkAccess.class); + getWriteableArea.setAccessible(true); + + // This is tryGenerateStructure + // Register VanillaStructurePopulators to allow Minecraft to properly + // handle them + for(StructurePopulator pop : StructureRegistry.getAllPopulators()) + { + if(pop instanceof VanillaStructurePopulator vsp) + { + possibleStructureSets.add(MinecraftKey.a(vsp.structureRegistryKey)); // MinecraftKey.create + } + } + tryGenerateStructure = ChunkGenerator.class.getDeclaredMethod("a", + StructureSet.a.class, + StructureManager.class, + IRegistryCustom.class, + RandomState.class, + StructureTemplateManager.class, + long.class, + IChunkAccess.class, + ChunkCoordIntPair.class, + SectionPosition.class); + tryGenerateStructure.setAccessible(true); + } + + + @Override // getBiomeSource + public @NotNull WorldChunkManager d() { + return mapRendererBS; + } + + public @NotNull TerraformWorld getTerraformWorld() { + return tw; + } + + @Override + protected @NotNull MapCodec b() { + return MapCodec.unit(null); + } + + @Override // createBiomes + public @NotNull CompletableFuture a(RandomState randomstate, Blender blender, StructureManager structuremanager, @NotNull IChunkAccess ichunkaccess) + { + return CompletableFuture.supplyAsync(() -> { + return ichunkaccess; // Don't do any calculations here, biomes are set in applyCarvers + }, SystemUtils.g().a("init_biomes")); + } + + @Override // findNearestMapFeature + public Pair> a(WorldServer worldserver, @NotNull HolderSet holderset, + @NotNull BlockPosition blockposition, int i, boolean flag) { + + int pX = blockposition.u(); // getX + int pZ = blockposition.w(); // getZ + + for(Holder holder:holderset) { + Structure feature = holder.a(); + // StructureGenerator structuregenerator = feature.; + TerraformGeneratorPlugin.logger.info("Vanilla locate for " + feature.getClass().getName() + " invoked."); + + if (holder.a().getClass() == StrongholdStructure.class) { // stronghold + int[] coords = new StrongholdPopulator().getNearestFeature(tw, pX, pZ); + return new Pair<>(new BlockPosition(coords[0], 20, coords[1]), holder); + } + else if(!TConfig.c.DEVSTUFF_VANILLA_LOCATE_DISABLE) + { + if (holder.a().getClass() == OceanMonumentStructure.class) { // Monument + + int[] coords = StructureLocator.locateSingleMegaChunkStructure(tw, pX, pZ, new MonumentPopulator(), TConfig.c.DEVSTUFF_VANILLA_LOCATE_TIMEOUTMILLIS); + + return new Pair<> + (new BlockPosition(coords[0], 50, coords[1]), holder); + } else if (holder.a().getClass() == WoodlandMansionStructure.class) { // Mansion + + int[] coords = StructureLocator.locateSingleMegaChunkStructure(tw, pX, pZ, new MansionPopulator(), TConfig.c.DEVSTUFF_VANILLA_LOCATE_TIMEOUTMILLIS); + + return new Pair<> + (new BlockPosition(coords[0], 50, coords[1]), holder); + } else if (holder.a() instanceof JigsawStructure + //aU is structure + && MinecraftServer.getServer().ba().a(Registries.aU).orElseThrow().a(MinecraftKey.a("trial_chambers")) == holder.a() + ) { // Trial Chamber + + int[] coords = StructureLocator.locateSingleMegaChunkStructure(tw, pX, pZ, new TrialChamberPopulator(), TConfig.c.DEVSTUFF_VANILLA_LOCATE_TIMEOUTMILLIS); + + return new Pair<> + (new BlockPosition(coords[0], 50, coords[1]), holder); + } else if (holder.a().getClass() == BuriedTreasureStructure.class) { + // Buried Treasure + int[] coords = StructureLocator.locateMultiMegaChunkStructure(tw, new MegaChunk(pX, 0, pZ), new BuriedTreasurePopulator(), TConfig.c.DEVSTUFF_VANILLA_LOCATE_TIMEOUTMILLIS); + if(coords == null) return null; + return new Pair<> + (new BlockPosition(coords[0], 50, coords[1]), holder); + } + } + } + return null; + } + + @Override // applyBiomeDecoration + public void a(GeneratorAccessSeed generatoraccessseed, IChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.a(generatoraccessseed, ichunkaccess, structuremanager); + + // This triggers structure gen. Needed for VanillaStructurePopulator + addVanillaDecorations(generatoraccessseed,ichunkaccess, structuremanager); + } + + //This has to be overridden because calling the normal one will make vanilla + // generate ores. The giant commented swath of stuff did it + @Override + public void addVanillaDecorations(GeneratorAccessSeed generatoraccessseed, IChunkAccess ichunkaccess, StructureManager structuremanager) { // CraftBukkit + ChunkCoordIntPair chunkcoordintpair = ichunkaccess.f(); //getPos + + //debugVoidTerrain + if (!SharedConstants.a(chunkcoordintpair)) { + //SectionPosition.of(...,generatoraccessseed.getMinSection()) + SectionPosition sectionposition = SectionPosition.a(chunkcoordintpair, generatoraccessseed.ao()); + BlockPosition blockposition = sectionposition.j(); //origin() + + //generatoraccessseed.registryAccess().lookupOrThrow(Registries.STRUCTURE); + IRegistry iregistry = generatoraccessseed.K_().e(Registries.aU); + + //iregistry.stream() + Map> map = (Map) iregistry.s().collect(Collectors.groupingBy((structure) -> { + //structure.step() + return structure.c().ordinal(); + })); + List list = (List) featuresPerStep.get(); //this.featuresPerStep + SeededRandom seededrandom = new SeededRandom(new XoroshiroRandomSource(RandomSupport.a())); //generateUniqueSeed + //seededrandom.setDecorationSeed(generatoraccessseed.getSeed(), blockposition.getX(), blockposition.getZ()) + long i = seededrandom.a(generatoraccessseed.D(), blockposition.u(), blockposition.w()); + Set> set = new ObjectArraySet(); +// ChunkCoordIntPair.rangeClosed(sectionposition.chunk(),... + ChunkCoordIntPair.a(sectionposition.r(), 1).forEach((chunkcoordintpair1) -> { +// IChunkAccess ichunkaccess1 = generatoraccessseed.getChunk(chunkcoordintpair1.x, chunkcoordintpair1.z); + IChunkAccess ichunkaccess1 = generatoraccessseed.a(chunkcoordintpair1.h, chunkcoordintpair1.i); + ChunkSection[] achunksection = ichunkaccess1.d(); //getSections + int j = achunksection.length; + + for (int k = 0; k < j; ++k) { + ChunkSection chunksection = achunksection[k]; + //getBiomes + PalettedContainerRO> palettedcontainerro = chunksection.i(); // CraftBukkit - decompile error + + Objects.requireNonNull(set); + palettedcontainerro.a(set::add); //getAll + } + + }); + //set.retainAll(this.biomeSource.possibleBiomes()); + set.retainAll(this.b.c()); + int j = list.size(); + + try { + //generatoraccessseed.registryAccess().lookupOrThrow(Registries.PLACED_FEATURE); + IRegistry iregistry1 = generatoraccessseed.K_().e(Registries.aT); + int k = Math.max(WorldGenStage.Decoration.values().length, j); + + for (int l = 0; l < k; ++l) { + int i1 = 0; + Iterator iterator; + CrashReportSystemDetails crashreportsystemdetails; + + if (structuremanager.a()) { //shouldGenerateStructures + List list1 = (List) map.getOrDefault(l, Collections.emptyList()); + + for (iterator = list1.iterator(); iterator.hasNext(); ++i1) { + Structure structure = (Structure) iterator.next(); + + seededrandom.b(i, i1, l); //setFeatureSeed + Supplier supplier = () -> { + //getResourceKey + Optional optional = iregistry.d(structure).map(Object::toString); + + Objects.requireNonNull(structure); + return (String) optional.orElseGet(structure::toString); + }; + + try { + //setCurrentlyGenerating + generatoraccessseed.a(supplier); + //startsForStructure + structuremanager.a(sectionposition, structure).forEach((structurestart) -> { + //placeInChunk(...getWritableArea...) + try{ + structurestart.a(generatoraccessseed, structuremanager, this, + seededrandom, (StructureBoundingBox) getWriteableArea.invoke(null,ichunkaccess), + chunkcoordintpair); + }catch(IllegalAccessException | InvocationTargetException e){ + CrashReport crashreport = CrashReport.a(e, "TerraformGenerator"); + throw new ReportedException(crashreport); + } + }); + } catch (Exception exception) { + //forThrowable + CrashReport crashreport = CrashReport.a(exception, "Feature placement"); + + crashreportsystemdetails = crashreport.a("Feature"); //addCategory + Objects.requireNonNull(supplier); + crashreportsystemdetails.a("Description", supplier::get); //setDetail + throw new ReportedException(crashreport); + } + } + } + + /* + if (l < j) { + IntArraySet intarrayset = new IntArraySet(); + + iterator = set.iterator(); + + while (iterator.hasNext()) { + Holder holder = (Holder) iterator.next(); + List> list2 = ((BiomeSettingsGeneration) this.generationSettingsGetter.apply(holder)).features(); + + if (l < list2.size()) { + HolderSet holderset = (HolderSet) list2.get(l); + FeatureSorter.b featuresorter_b = (FeatureSorter.b) list.get(l); + + holderset.stream().map(Holder::value).forEach((placedfeature) -> { + intarrayset.add(featuresorter_b.indexMapping().applyAsInt(placedfeature)); + }); + } + } + + int j1 = intarrayset.size(); + int[] aint = intarrayset.toIntArray(); + + Arrays.sort(aint); + FeatureSorter.b featuresorter_b1 = (FeatureSorter.b) list.get(l); + + for (int k1 = 0; k1 < j1; ++k1) { + int l1 = aint[k1]; + PlacedFeature placedfeature = (PlacedFeature) featuresorter_b1.features().get(l1); + Supplier supplier1 = () -> { + Optional optional = iregistry1.getResourceKey(placedfeature).map(Object::toString); + + Objects.requireNonNull(placedfeature); + return (String) optional.orElseGet(placedfeature::toString); + }; + + seededrandom.setFeatureSeed(i, l1, l); + + try { + generatoraccessseed.setCurrentlyGenerating(supplier1); + placedfeature.placeWithBiomeCheck(generatoraccessseed, this, seededrandom, blockposition); + } catch (Exception exception1) { + //forThrowable + CrashReport crashreport1 = CrashReport.a(exception1, "Feature placement"); + + crashreportsystemdetails = crashreport1.a("Feature"); //addCategory + Objects.requireNonNull(supplier1); + crashreportsystemdetails.a("Description", supplier1::get); //setDetail + throw new ReportedException(crashreport1); + } + } + } + */ + } + + generatoraccessseed.a((Supplier) null); //setCurrentlyGenerating + } catch (Exception exception2) { + //forThrowable + CrashReport crashreport2 = CrashReport.a(exception2, "Biome decoration"); + + crashreport2.a("Generation") //addCategory + .a("CenterX", (Object) chunkcoordintpair.e) //setDetail + .a("CenterZ", (Object) chunkcoordintpair.f) //setDetail + .a("Decoration Seed", (Object) i); //setDetail + throw new ReportedException(crashreport2); + } + } + } + + + @Override // applyCarvers + public void a(RegionLimitedWorldAccess regionlimitedworldaccess, long seed, + RandomState randomstate, BiomeManager biomemanager, + StructureManager structuremanager, @NotNull IChunkAccess ichunkaccess) + { + // POPULATES BIOMES. IMPORTANT + // (net.minecraft.world.level.biome.BiomeResolver,net.minecraft.world.level.biome.Climate$Sampler) + // Use twBS as it is the biome provider that actually calculates biomes. + // The other one only returns river/plains + ichunkaccess.a(this.twBS, null); // This can be null as its passed into twBS + + // Call delegate applyCarvers to apply spigot ChunkGenerator; + delegate.a(regionlimitedworldaccess, seed, randomstate, biomemanager,structuremanager, ichunkaccess); + } + + @Override // getSeaLevel + public int e() { + return delegate.e(); + } + + /** + * Overridden to allow VanillaStructurePopulator to work. + * The code comes from createStructures, but with a lot of the in-built + * checks cut out and replaced with TFG code. + */ + @Override + public void a(IRegistryCustom iregistrycustom, @NotNull ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, @NotNull IChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) { + ChunkCoordIntPair chunkcoordintpair = ichunkaccess.f(); // getPos + SectionPosition sectionposition = SectionPosition.a(ichunkaccess); // bottomOf + RandomState randomstate = chunkgeneratorstructurestate.c(); // randomState + MegaChunk mc = new MegaChunk(chunkcoordintpair.h, chunkcoordintpair.i); + SingleMegaChunkStructurePopulator[] spops = StructureRegistry.getLargeStructureForMegaChunk(tw, mc); + int[] centerCoords = mc.getCenterBiomeSectionChunkCoords(); + + for(SingleMegaChunkStructurePopulator pop:spops) + { + if(!(pop instanceof VanillaStructurePopulator vpop)) continue; + // possibleStructureSets + possibleStructureSets + .stream().filter((resourceLoc)->{ + return vpop.structureRegistryKey.equals(resourceLoc.a()); // MinecraftKey.getPath() + }) + .map((resourceLoc)-> MinecraftServer.getServer().ba().a(Registries.aW).orElseThrow().a(resourceLoc)) + .forEach((structureSet) -> { + StructurePlacement structureplacement = structureSet.b(); // placement() + List list = structureSet.a(); // structures() + + // This will be true depending on the structure manager + if (centerCoords[0] == chunkcoordintpair.h + && centerCoords[1] == chunkcoordintpair.i) { + + // d() -> getLevelSeed() + try{ + Object retVal = tryGenerateStructure.invoke(this, list.getFirst(), structuremanager, iregistrycustom, randomstate, + structuretemplatemanager, chunkgeneratorstructurestate.d(), + ichunkaccess, chunkcoordintpair, sectionposition); + TerraformGeneratorPlugin.logger.info(chunkcoordintpair.e + "," + chunkcoordintpair.f + " will spawn a vanilla structure, with tryGenerateStructure == " + retVal); + } + catch(Throwable t) + { + TerraformGeneratorPlugin.logger.info(chunkcoordintpair.e + "," + chunkcoordintpair.f + " Failed to generate a vanilla structure"); + TerraformGeneratorPlugin.logger.stackTrace(t); + } + } + }); + } + } + @Override // createReferences. Structure related + public void a(GeneratorAccessSeed gas,StructureManager manager,IChunkAccess ica) + { + delegate.a(gas, manager, ica); + } + + @Override // getSpawnHeight + public int a(LevelHeightAccessor levelheightaccessor) { + return 64; + } + + @Override // fillFromNoise + public CompletableFuture a(Blender blender, + RandomState randomstate, StructureManager structuremanager, + IChunkAccess ichunkaccess) { + return delegate.a(blender, + randomstate, structuremanager, + ichunkaccess); + } + + @Override // buildSurface. Used to be buildBase + public void a(RegionLimitedWorldAccess regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, IChunkAccess ichunkaccess) + { + delegate.a(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + + @Override // getBaseColumn + public BlockColumn a(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return this.delegate.a(i,j,levelheightaccessor,randomstate); + } + + // spawnOriginalMobs + public void a(RegionLimitedWorldAccess regionlimitedworldaccess) { + this.delegate.a(regionlimitedworldaccess); + } + + + // getSeaLevel + @Override + public int f() { + return TerraformGenerator.seaLevel; + } + + // getMinY + @Override + public int g() { + return this.delegate.g(); + } + + @Override // getFirstFreeHeight + public int b(int i, int j, HeightMap.Type heightmap_type, + LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return this.a(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + + @Override // getFirstOccupiedHeight + public int c(int i, int j, HeightMap.Type heightmap_type, + LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return this.a(i, j, heightmap_type, levelheightaccessor, randomstate) - 1; + } + + @Override // getBaseHeight + public int a(int i, int j, HeightMap.Type heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + // return delegate.a(x, z, var2, var3); + return 100; + // return org.terraform.coregen.HeightMap.getBlockHeight(tw, x, z); + } + + // private static boolean biomeDebug = false; + + + @Override // addDebugScreenInfo + public void a(List list, RandomState randomstate, BlockPosition blockposition) { + + } + +} diff --git a/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/NMSInjector.java b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/NMSInjector.java new file mode 100644 index 00000000..25d0ce5b --- /dev/null +++ b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/NMSInjector.java @@ -0,0 +1,170 @@ +package org.terraform.v1_21_R2; + +import net.minecraft.server.level.PlayerChunkMap; +import net.minecraft.server.level.WorldServer; +import net.minecraft.world.level.GeneratorAccessSeed; +import net.minecraft.world.level.block.entity.TileEntityBeehive; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.IChunkAccess; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.WorldGenContext; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.Beehive; +import org.bukkit.craftbukkit.v1_21_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R2.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.v1_21_R2.generator.CraftLimitedRegion; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.terraform.coregen.BlockDataFixerAbstract; +import org.terraform.coregen.NMSInjectorAbstract; +import org.terraform.coregen.populatordata.PopulatorDataAbstract; +import org.terraform.coregen.populatordata.PopulatorDataICAAbstract; +import org.terraform.coregen.populatordata.PopulatorDataPostGen; +import org.terraform.coregen.populatordata.PopulatorDataSpigotAPI; +import org.terraform.data.TerraformWorld; +import org.terraform.main.TerraformGeneratorPlugin; +import org.terraform.utils.GenUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class NMSInjector extends NMSInjectorAbstract { + + // private boolean heightInjectSuccess = true; + + private static @Nullable Method getTileEntity = null; + + @Override + public void startupTasks() { + // Inject new biomes + CustomBiomeHandler.init(); + } + + @Override + public @NotNull BlockDataFixerAbstract getBlockDataFixer() { + return new BlockDataFixer(); + } + + @Override + public boolean attemptInject(@NotNull World world) { + try { + CraftWorld cw = (CraftWorld) world; + WorldServer ws = cw.getHandle(); + + // Force world to correct height + TerraformWorld.get(world).minY = -64; + TerraformWorld.get(world).maxY = 320; + + // k is getChunkSource, g is getChunkGenerator() + ChunkGenerator delegate = ws.m().g(); + + TerraformGeneratorPlugin.logger.info("NMSChunkGenerator Delegate is of type " + delegate.getClass() + .getSimpleName()); + + // String worldname, + // int seed, + // WorldChunkManager worldchunkmanager, + // WorldChunkManager worldchunkmanager1, + // StructureSettings structuresettings, + // long i + NMSChunkGenerator bpg = new NMSChunkGenerator(world.getName(), (int) world.getSeed(), delegate); + + // Inject TerraformGenerator NMS chunk generator into playerchunkmap AND worldgencontext + PlayerChunkMap pcm = ws.m().a; // getChunkProvider().PlayerChunkMap + // worldGenContext stores chunkGenerator, not pcm + // R is worldGenContext + Field wgc = pcm.getClass().getDeclaredField("R"); + wgc.setAccessible(true); + WorldGenContext worldGenContext = (WorldGenContext) wgc.get(pcm); + // b is chunkGenerator + wgc.set(pcm, + new WorldGenContext(worldGenContext.a(), + bpg, + worldGenContext.c(), + worldGenContext.d(), + worldGenContext.e(), + worldGenContext.f() + ) + ); + TerraformGeneratorPlugin.logger.info("Post injection: getChunkSource().getChunkGenerator() is of type " + + ws.m().g().getClass().getSimpleName()); + } + catch (Throwable e) { + TerraformGeneratorPlugin.logger.stackTrace(e); + return false; + } + + return true; + } + + @Override + public @NotNull PopulatorDataICAAbstract getICAData(@NotNull Chunk chunk) { + // ChunKStatus.FULL + IChunkAccess ica = ((CraftChunk) chunk).getHandle(ChunkStatus.n); + CraftWorld cw = (CraftWorld) chunk.getWorld(); + WorldServer ws = cw.getHandle(); + + TerraformWorld tw = TerraformWorld.get(chunk.getWorld()); + // return new PopulatorData(new RegionLimitedWorldAccess(ws, list), null, chunk.getX(), chunk.getZ()); + return new PopulatorDataICA(new PopulatorDataPostGen(chunk), tw, ws, ica, chunk.getX(), chunk.getZ()); + } + + @Override + public PopulatorDataICAAbstract getICAData(PopulatorDataAbstract data) { + // This is for the damn bees + if (data instanceof PopulatorDataSpigotAPI pdata) { + GeneratorAccessSeed gas = ((CraftLimitedRegion) pdata.lr).getHandle(); + WorldServer ws = gas.getMinecraftWorld(); + TerraformWorld tw = TerraformWorld.get(ws.getWorld().getName(), ws.D()); // C is getSeed() + return new PopulatorDataICA( + data, + tw, + ws, + gas.a(data.getChunkX(), data.getChunkZ()), + data.getChunkX(), + data.getChunkZ() + ); + } + if (data instanceof PopulatorDataPostGen gdata) { + return getICAData(gdata.getChunk()); + } + + return null; + } + + @Override + public void storeBee(Beehive hive) { + try { + if (getTileEntity == null) { + getTileEntity = CraftBlockEntityState.class.getDeclaredMethod("getTileEntity"); + getTileEntity.setAccessible(true); + } + TileEntityBeehive teb = (TileEntityBeehive) getTileEntity.invoke(hive); + // + // NBTTagCompound nbttagcompound = new NBTTagCompound(); + // nbttagcompound.a("id", "minecraft:bee"); + // TileEntityBeehive.storeBee + // TileEntityBeehive.Occupant.create(1) + // Copied from world\level\levelgen\feature\treedecorators\WorldGenFeatureTreeBeehive.java + teb.a(TileEntityBeehive.c.a(GenUtils.RANDOMIZER.nextInt(599))); + + } + catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + @Override + public int getMinY() { + return -64; + } + + @Override + public int getMaxY() { + return 320; + } + +} diff --git a/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/PopulatorData.java b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/PopulatorData.java new file mode 100644 index 00000000..9d40bf1e --- /dev/null +++ b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/PopulatorData.java @@ -0,0 +1,304 @@ +package org.terraform.v1_21_R2; + +import net.minecraft.core.BlockPosition; +import net.minecraft.world.entity.EntityInsentient; +import net.minecraft.world.entity.EntityTypes; +import net.minecraft.world.level.GeneratorAccessSeed; +import net.minecraft.world.level.block.entity.*; +import net.minecraft.world.level.chunk.IChunkAccess; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Biome; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_21_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R2.generator.CraftLimitedRegion; +import org.bukkit.craftbukkit.v1_21_R2.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_21_R2.util.RandomSourceWrapper; +import org.bukkit.entity.EntityType; +import org.jetbrains.annotations.NotNull; +import org.terraform.coregen.TerraLootTable; +import org.terraform.coregen.bukkit.NativeGeneratorPatcherPopulator; +import org.terraform.coregen.populatordata.IPopulatorDataBaseHeightAccess; +import org.terraform.coregen.populatordata.IPopulatorDataBeehiveEditor; +import org.terraform.coregen.populatordata.PopulatorDataAbstract; +import org.terraform.data.TerraformWorld; +import org.terraform.main.TerraformGeneratorPlugin; +import org.terraform.main.config.TConfig; +import org.terraform.utils.GenUtils; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Optional; +import java.util.Random; + +public class PopulatorData extends PopulatorDataAbstract + implements IPopulatorDataBaseHeightAccess, IPopulatorDataBeehiveEditor +{ + private static final HashMap> entityTypesDict = new HashMap<>(); + final GeneratorAccessSeed rlwa; + final IChunkAccess ica; + private final int chunkX; + private final int chunkZ; + private final NMSChunkGenerator gen; + private int radius = 1; + + public PopulatorData(GeneratorAccessSeed rlwa, IChunkAccess ica, NMSChunkGenerator gen, int chunkX, int chunkZ) { + this.rlwa = rlwa; + this.chunkX = chunkX; + this.chunkZ = chunkZ; + this.gen = gen; + this.ica = ica; + + if (entityTypesDict.isEmpty()) { + for (EntityType type : EntityType.values()) { + if (type == EntityType.UNKNOWN) { + continue; + } + try { + // EntityTypes.byString + Optional> et = EntityTypes.a("minecraft:" + type.toString() + .toLowerCase(Locale.ENGLISH)); + et.ifPresent(entityTypes -> entityTypesDict.put(type, entityTypes)); + } + catch (IllegalArgumentException e) { + TerraformGeneratorPlugin.logger.stackTrace(e); + } + } + } + } + + public void setRadius(int radius) { + this.radius = radius; + } + + public Material getType(int x, int y, int z) { + try { + // return rlwa.getType(x, y, z); + return CraftMagicNumbers.getMaterial(rlwa.a_(new BlockPosition(x, y, z)).b()); + } + catch (Exception e) { + Bukkit.getLogger() + .info("Error chunk: " + + chunkX + + "," + + chunkZ + + "--- Block Coords: " + + 16 * chunkX + + "," + + 16 * chunkZ + + " for coords " + + x + + "," + + y + + "," + + z); + TerraformGeneratorPlugin.logger.stackTrace(e); + } + return null; + } + + public BlockData getBlockData(int x, int y, int z) { + // return rlwa.getBlockData(x,y,z); + return CraftBlockData.fromData(rlwa.a_(new BlockPosition(x, y, z))); + } + + @Override + public void setType(int x, int y, int z, @NotNull Material type) { + if (Math.abs((x >> 4) - chunkX) > radius || Math.abs((z >> 4) - chunkZ) > radius) { + if (radius > 0) { + NativeGeneratorPatcherPopulator.pushChange(rlwa.getMinecraftWorld().getWorld().getName(), + x, + y, + z, + Bukkit.createBlockData(type) + ); + } + else { + TerraformGeneratorPlugin.logger.stackTrace(new Exception( + "Tried to call adjacent chunk with populator radius 0: (" + + x + + "," + + y + + "," + + z + + ") for chunk (" + + chunkX + + "," + + chunkZ + + ")")); + } + } + else { + rlwa.a(new BlockPosition(x, y, z), ((CraftBlockData) Bukkit.createBlockData(type)).getState(), 0); + } + } + + @Override + public void setBlockData(int x, int y, int z, @NotNull BlockData data) { + if (Math.abs((x >> 4) - chunkX) > radius || Math.abs((z >> 4) - chunkZ) > radius) { + if (radius > 0) { + NativeGeneratorPatcherPopulator.pushChange(rlwa.getMinecraftWorld().getWorld().getName(), + x, + y, + z, + data + ); + } + else { + TerraformGeneratorPlugin.logger.stackTrace(new Exception( + "Tried to call adjacent chunk with populator radius 0: (" + + x + + "," + + y + + "," + + z + + ") for chunk (" + + chunkX + + "," + + chunkZ + + ")")); + } + } + else { + rlwa.a(new BlockPosition(x, y, z), ((CraftBlockData) data).getState(), 0); + } + } + + // wtf + public Biome getBiome(int rawX, int rawZ) { + TerraformWorld tw = gen.getTerraformWorld(); + return tw.getBiomeBank(rawX, rawZ).getHandler().getBiome(); + } + + @Override + public int getChunkX() { + return chunkX; + } + + @Override + public int getChunkZ() { + return chunkZ; + } + + @Override + public void addEntity(int rawX, int rawY, int rawZ, @NotNull EntityType type) { + if (Math.abs((rawX >> 4) - chunkX) > 1 || Math.abs((rawZ >> 4) - chunkZ) > 1) { + TerraformGeneratorPlugin.logger.info("Failed to spawn " + type + " as it was out of bounds."); + return; + } + + // Use this method for thread safety. + CraftLimitedRegion clr = new CraftLimitedRegion(rlwa, ica.f()); + net.minecraft.world.entity.Entity e = clr.createEntity(new Location(gen.getTerraformWorld().getWorld(), + rawX, + rawY, + rawZ), type.getEntityClass(), true); + // EntityInsentient.setPersistenceRequired() + if (e instanceof EntityInsentient) { + ((EntityInsentient) e).fF(); + } + rlwa.b(e); + // TerraformGeneratorPlugin.logger.info("Spawned " + e.getType() + " at " + rawX + " " + rawY + " " + rawZ); + } + + @Override + public void setSpawner(int rawX, int rawY, int rawZ, EntityType type) { + if (!TConfig.areAnimalsEnabled()) { + return; + } + + BlockPosition pos = new BlockPosition(rawX, rawY, rawZ); + + setType(rawX, rawY, rawZ, Material.SPAWNER); + Optional opt = rlwa.a(pos, TileEntityTypes.j); + + if (opt.isPresent()) { + TileEntityMobSpawner tileentity = opt.get(); + try { + // Refer to WorldGenDungeons + // TileEntityMobSpawner tileentitymobspawner = (TileEntityMobSpawner) tileentity; + // + // tileentitymobspawner.setEntityId(this.randomEntityId(randomsource), randomsource); + + // Fetch from ENTITY_TYPE (Q)'s map + // q is ENTITY_TYPE + EntityTypes nmsEntity = entityTypesDict.get(type); + if (nmsEntity == null) { + TerraformGeneratorPlugin.logger.error(type + " was not present in the entityTypesDict."); + } + tileentity.a(nmsEntity, new RandomSourceWrapper(new Random())); + } + catch (IllegalArgumentException | SecurityException e) { + TerraformGeneratorPlugin.logger.stackTrace(e); + } + } + else { + TerraformGeneratorPlugin.logger.error("Failed to fetch mob spawner entity at (" + + "," + + rawX + + "," + + rawY + + "," + + rawZ + + ")"); + } + } + + @Override + public void lootTableChest(int x, int y, int z, TerraLootTable table) { + BlockPosition pos = new BlockPosition(x, y, z); + + // getBlockEntity + TileEntity te = rlwa.c_(pos); + if (te instanceof TileEntityLootable) { + ((TileEntityLootable) te).a(LootTableTranslator.translationMap.get(table)); + } + else if (te instanceof BrushableBlockEntity) + // BrushableBlockEntity.setLootTable + { + ((BrushableBlockEntity) te).a(LootTableTranslator.translationMap.get(table), + gen.getTerraformWorld().getHashedRand(x, y, z).nextLong() + ); + } + + // TileEntityLootable.a(rlwa, RandomSource.a(gen.getTerraformWorld().getHashedRand(x, y, z).nextLong()), pos, LootTableTranslator.translationMap.get(table)); + } + + @Override + public TerraformWorld getTerraformWorld() { + return gen.getTerraformWorld(); + } + + @Override + public int getBaseHeight(int rawX, int rawZ) { + // (int i, int j, HeightMap.Type heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) + return 100; + // return gen.a(rawX, rawZ, HeightMap.Type.a, this.rlwa); + } + + @Override + public void setBeehiveWithBee(int rawX, int rawY, int rawZ) { + BlockPosition pos = new BlockPosition(rawX, rawY, rawZ); + // TerraformGeneratorPlugin.logger.info(IRegistry.X.b(EntityTypes.h).toString()); + setType(rawX, rawY, rawZ, Material.BEE_NEST); + + try { + // TerraformGeneratorPlugin.logger.error("Failed to set beehive at (" + rawX + "," + rawY + "," + rawZ + ") " + BuiltInRegistries.h.b(entityTypesDict.get(EntityType.BEE))); + TileEntityBeehive tileentity = (TileEntityBeehive) rlwa.c_(pos); + if (tileentity == null) { // retry? + setType(rawX, rawY, rawZ, Material.BEE_NEST); + tileentity = (TileEntityBeehive) rlwa.c_(pos); + } + // + // NBTTagCompound nbttagcompound = new NBTTagCompound(); + // nbttagcompound.a("id", "minecraft:bee"); + // TileEntityBeehive.storeBee + // TileEntityBeehive.Occupant.create(1) + tileentity.a(TileEntityBeehive.c.a(GenUtils.RANDOMIZER.nextInt(599))); + } + catch (NullPointerException | IllegalArgumentException | SecurityException e) { + TerraformGeneratorPlugin.logger.stackTrace(e); + } + } +} diff --git a/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/PopulatorDataICA.java b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/PopulatorDataICA.java new file mode 100644 index 00000000..cd756597 --- /dev/null +++ b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/PopulatorDataICA.java @@ -0,0 +1,267 @@ +package org.terraform.v1_21_R2; + +import net.minecraft.core.BlockPosition; +import net.minecraft.core.Holder; +import net.minecraft.core.IRegistry; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.WorldServer; +import net.minecraft.util.RandomSource; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityTypes; +import net.minecraft.world.entity.vehicle.EntityMinecartChest; +import net.minecraft.world.level.ChunkCoordIntPair; +import net.minecraft.world.level.biome.BiomeBase; +import net.minecraft.world.level.block.entity.BrushableBlockEntity; +import net.minecraft.world.level.block.entity.TileEntity; +import net.minecraft.world.level.block.entity.TileEntityLootable; +import net.minecraft.world.level.block.state.IBlockData; +import net.minecraft.world.level.chunk.IChunkAccess; +import net.minecraft.world.level.levelgen.structure.*; +import net.minecraft.world.level.levelgen.structure.pieces.PiecesContainer; +import net.minecraft.world.level.levelgen.structure.structures.OceanMonumentPieces; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Biome; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_21_R2.block.CraftBiome; +import org.bukkit.craftbukkit.v1_21_R2.block.data.CraftBlockData; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.jetbrains.annotations.NotNull; +import org.terraform.biome.custombiomes.CustomBiomeType; +import org.terraform.coregen.NaturalSpawnType; +import org.terraform.coregen.TerraLootTable; +import org.terraform.coregen.populatordata.PopulatorDataAbstract; +import org.terraform.coregen.populatordata.PopulatorDataICABiomeWriterAbstract; +import org.terraform.data.TerraformWorld; +import org.terraform.main.TerraformGeneratorPlugin; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Optional; +import java.util.Random; + +public class PopulatorDataICA extends PopulatorDataICABiomeWriterAbstract { + private final PopulatorDataAbstract parent; + private final IChunkAccess ica; + private final int chunkX; + private final int chunkZ; + private final WorldServer ws; + private final TerraformWorld tw; + + public PopulatorDataICA(PopulatorDataAbstract parent, + TerraformWorld tw, + WorldServer ws, + IChunkAccess ica, + int chunkX, + int chunkZ) + { + this.ica = ica; + this.parent = parent; + this.chunkX = chunkX; + this.chunkZ = chunkZ; + this.ws = ws; + this.tw = tw; + } + + public @NotNull Material getType(int x, int y, int z) { + // return parent.getType(x, y, z); + IBlockData ibd = ica.a_(new BlockPosition(x, y, z)); // getState + return CraftBlockData.fromData(ibd).getMaterial(); + } + + public BlockData getBlockData(int x, int y, int z) { + // return parent.getBlockData(x, y, z); + IBlockData ibd = ica.a_(new BlockPosition(x, y, z)); // getState + return CraftBlockData.fromData(ibd); + } + + @Override + public void setBiome(int rawX, int rawY, int rawZ, CustomBiomeType cbt, Biome fallback) { + IRegistry biomeRegistry = CustomBiomeHandler.getBiomeRegistry(); + Holder targetBiome; + if (cbt == CustomBiomeType.NONE) { + + targetBiome = CraftBiome.bukkitToMinecraftHolder(fallback); + } + else { + ResourceKey rkey = CustomBiomeHandler.terraformGenBiomeRegistry.get(cbt);// ResourceKey.a(IRegistry.aP, new MinecraftKey(cbt.getKey())); + Optional> optHolder = biomeRegistry.a(rkey); // lookup + if (optHolder.isEmpty()) { + TerraformGeneratorPlugin.logger.error("Custom biome was not found in the vanilla registry!"); + targetBiome = CraftBiome.bukkitToMinecraftHolder(fallback); + } + else { + targetBiome = optHolder.get(); + } + } + + ica.setBiome(rawX >> 2, rawY >> 2, rawZ >> 2, targetBiome); + } + + @Override + public void setBiome(int rawX, int rawY, int rawZ, Biome biome) { + // TerraformGeneratorPlugin.logger.info("Set " + rawX + "," + rawY + "," + rawZ + " to " + biome); + ica.setBiome(rawX >> 2, rawY >> 2, rawZ >> 2, CraftBiome.bukkitToMinecraftHolder(biome)); + } + + @Override + public void setType(int x, int y, int z, @NotNull Material type) { + // parent.setType(x, y, z, type); + ica.a(new BlockPosition(x, y, z), ((CraftBlockData) Bukkit.createBlockData(type)).getState(), false); + + // ica.setType(new BlockPosition(x, y, z), ((CraftBlockData) Bukkit.createBlockData(type)).getState(), false); + } + + @Override + public void setBlockData(int x, int y, int z, @NotNull BlockData data) { + // parent.setBlockData(x, y, z, data); + ica.a(new BlockPosition(x, y, z), ((CraftBlockData) data).getState(), false); + + } + + public Biome getBiome(int rawX, int rawZ) { + return parent.getBiome(rawX, rawZ); + // return tw.getBiomeBank(rawX, rawZ).getHandler().getBiome();// BiomeBank.calculateBiome(tw,tw.getTemperature(rawX, rawZ), y).getHandler().getBiome();// Biome.valueOf(ica + // .getBiome(rawX, rawY, rawZ).l().replace("biome.minecraft.", "").toUpperCase(Locale.ENGLISH)); + } + + @Override + public int getChunkX() { + return chunkX; + } + + @Override + public int getChunkZ() { + return chunkZ; + } + + @Override + public void addEntity(int rawX, int rawY, int rawZ, EntityType type) { + parent.addEntity(rawX, rawY, rawZ, type); + } + + @Override + public void setSpawner(int rawX, int rawY, int rawZ, EntityType type) { + parent.setSpawner(rawX, rawY, rawZ, type); + } + + @Override + public void lootTableChest(int x, int y, int z, TerraLootTable table) { + BlockPosition pos = new BlockPosition(x, y, z); + + // getBlockEntity + TileEntity te = ica.c_(pos); + if (te instanceof TileEntityLootable) { + ((TileEntityLootable) te).a(LootTableTranslator.translationMap.get(table)); + } + else if (te instanceof BrushableBlockEntity) + // BrushableBlockEntity.setLootTable + { + ((BrushableBlockEntity) te).a(LootTableTranslator.translationMap.get(table), + tw.getHashedRand(x, y, z).nextLong() + ); + } + } + + @SuppressWarnings("deprecation") + @Override + public void registerNaturalSpawns(@NotNull NaturalSpawnType type, int x0, int y0, int z0, int x1, int y1, int z1) { + ResourceKey structureKey = switch (type) { + case GUARDIAN -> BuiltinStructures.l; // Ocean Monument + case PILLAGER -> BuiltinStructures.a; // Pillager Outpost + case WITCH -> BuiltinStructures.j; // Swamp Hut + }; + + // ba is registryAccess + // a is lookup + // aU is STRUCTURE + IRegistry featureRegistry = MinecraftServer.getServer().ba().a(Registries.aU).orElseThrow(); + + Structure structureFeature = featureRegistry.a(structureKey).get().a(); + + try { + // Something's broken about EnumDirection's import. Might be a temporary thing. + Class enumDirectionClass = Class.forName("net.minecraft.core.EnumDirection"); + Field enumDirectionA = enumDirectionClass.getField("a"); + enumDirectionA.setAccessible(true); + Class oceanMonumentPiecesHClass = OceanMonumentPieces.h.class; + StructurePiece customBoundPiece = (StructurePiece) oceanMonumentPiecesHClass.getConstructor( + RandomSource.class, + int.class, + int.class, + enumDirectionClass + ).newInstance(RandomSource.a(), x0, z0, enumDirectionA.get(null)); + + PiecesContainer container = new PiecesContainer(new ArrayList<>() {{ + add(customBoundPiece); + }}); + + StructureStart start = new StructureStart(structureFeature, + new ChunkCoordIntPair(chunkX, chunkZ), + 0, + container + ); + + Field i = StructureStart.class.getDeclaredField("h"); // boundingBox + i.setAccessible(true); + i.set(start, new StructureBoundingBox(x0, y0, z0, x1, y1, z1)); + + // ws.a() is getStructureManager + // a is setStartForStructure + /*setStartForStructure( + * SectionPosition sectionposition, + * Structure structure, + * StructureStart structurestart, + * StructureAccess structureaccess)**/ + // ws.a().a(SectionPosition.a(x0,y0,z0), structureFeature, start, ica); + + ica.a(structureFeature, start); + // ws.a().a( // setStartForFeature + // structureFeature, + // start); + + // addReferenceForFeature + ica.a(structureFeature, new ChunkCoordIntPair(chunkX, chunkZ).a()); // a is toLong + } + catch (NoSuchMethodException | + InstantiationException | + InvocationTargetException | + ClassNotFoundException | + NoSuchFieldException | + IllegalArgumentException | + IllegalAccessException e) { + TerraformGeneratorPlugin.logger.stackTrace(e); + } + } + + @SuppressWarnings("deprecation") + @Override + public void spawnMinecartWithChest(int x, int y, int z, TerraLootTable table, @NotNull Random random) { + //EntityTypes.CHEST_MINECART.create(generatoraccessseed.getLevel(), EntitySpawnReason.CHUNK_GENERATION); + EntityMinecartChest entityminecartchest = (EntityMinecartChest) EntityTypes.y.a( + ws.getMinecraftWorld(), EntitySpawnReason.b); + + //For whatever reason, the mineshaft code does a null check. + if(entityminecartchest != null) + { + entityminecartchest.a( + (float) x + 0.5F, + (float) y + 0.5F, + (float) z + 0.5F + ); + entityminecartchest.a(LootTableTranslator.translationMap.get(table), random.nextLong()); + ws.addFreshEntity(entityminecartchest, SpawnReason.CHUNK_GEN); + } + } + + + @Override + public TerraformWorld getTerraformWorld() { + return tw; + } + +} diff --git a/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/TerraformWorldProviderBiome.java b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/TerraformWorldProviderBiome.java new file mode 100644 index 00000000..0a771f5c --- /dev/null +++ b/implementation/v1_21_R2/src/main/java/org/terraform/v1_21_R2/TerraformWorldProviderBiome.java @@ -0,0 +1,78 @@ +package org.terraform.v1_21_R2; + +import com.mojang.serialization.MapCodec; +import net.minecraft.core.Holder; +import net.minecraft.core.IRegistry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.biome.BiomeBase; +import net.minecraft.world.level.biome.Climate.Sampler; +import net.minecraft.world.level.biome.WorldChunkManager; +import org.bukkit.craftbukkit.v1_21_R2.block.CraftBiome; +import org.jetbrains.annotations.Nullable; +import org.terraform.biome.BiomeBank; +import org.terraform.biome.custombiomes.CustomBiomeType; +import org.terraform.data.TerraformWorld; +import org.terraform.main.TerraformGeneratorPlugin; + +import java.util.Optional; +import java.util.Set; +import java.util.stream.Stream; + +public class TerraformWorldProviderBiome extends WorldChunkManager { + @SuppressWarnings("unused") + private static final boolean debug = false; + private final TerraformWorld tw; + private final IRegistry registry; + private final Set> biomeList; + + public TerraformWorldProviderBiome(TerraformWorld tw, WorldChunkManager delegate) { + // super(biomeListToBiomeBaseList(CustomBiomeHandler.getBiomeRegistry())); + this.biomeList = CustomBiomeHandler.biomeListToBiomeBaseSet(CustomBiomeHandler.getBiomeRegistry()); + this.tw = tw; + this.registry = CustomBiomeHandler.getBiomeRegistry(); + } + + @Override + public Stream> b() + { + return this.biomeList.stream(); + } + + @Override // c is getPossibleBiomes + public Set> c() + { + return this.biomeList; + } + + @Override + protected MapCodec a() { + throw new UnsupportedOperationException("Cannot serialize TerraformWorldProviderBiome"); + } + + @Override + public @Nullable Holder getNoiseBiome(int x, int y, int z, Sampler arg3) { + // Used for biome generation in NMSChunkGenerator. + // Left shift x and z + BiomeBank bank = tw.getBiomeBank(x << 2, z << 2); + if (bank.getHandler().getCustomBiome() == CustomBiomeType.NONE) { + + return CraftBiome.bukkitToMinecraftHolder(bank.getHandler().getBiome()); + } + else { + ResourceKey rkey = CustomBiomeHandler.terraformGenBiomeRegistry.get(bank.getHandler() + .getCustomBiome()); // ResourceKey.a(IRegistry.aP, new MinecraftKey(bank.getHandler().getCustomBiome().getKey())); + Optional> holder = registry.a(rkey); + if (holder.isEmpty()) { + TerraformGeneratorPlugin.logger.error("Custom biome was not found in the vanilla registry!"); + } + + if (holder.isPresent()) { + return holder.get(); + } + else { + return CraftBiome.bukkitToMinecraftHolder(bank.getHandler().getBiome()); + } + } + } + +} diff --git a/settings.gradle.kts b/settings.gradle.kts index ee0d753a..e57af039 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,4 +6,5 @@ include("implementation:v1_20_R2") include("implementation:v1_20_R3") include("implementation:v1_20_R4") include("implementation:v1_21_R1") +include("implementation:v1_21_R2") include("buildProj")