diff --git a/platforms/bukkit/build.gradle.kts b/platforms/bukkit/build.gradle.kts index 52bcba095..331941410 100644 --- a/platforms/bukkit/build.gradle.kts +++ b/platforms/bukkit/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { 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("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper) } diff --git a/platforms/bukkit/nms/v1_19_R3/build.gradle.kts b/platforms/bukkit/nms/v1_19_R3/build.gradle.kts index 96f9038d8..5b92e7ab2 100644 --- a/platforms/bukkit/nms/v1_19_R3/build.gradle.kts +++ b/platforms/bukkit/nms/v1_19_R3/build.gradle.kts @@ -6,7 +6,7 @@ repositories { dependencies { api(project(":platforms:bukkit:common")) - paperDevBundle(Versions.Bukkit.paperDevBundle) + paperDevBundle("1.19.4-R0.1-SNAPSHOT") implementation("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT") } diff --git a/platforms/bukkit/nms/v1_20_R1/build.gradle.kts b/platforms/bukkit/nms/v1_20_R1/build.gradle.kts new file mode 100644 index 000000000..96f9038d8 --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/build.gradle.kts @@ -0,0 +1,17 @@ +apply(plugin = "io.papermc.paperweight.userdev") + +repositories { + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") +} + +dependencies { + api(project(":platforms:bukkit:common")) + paperDevBundle(Versions.Bukkit.paperDevBundle) + implementation("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT") +} + +tasks { + assemble { + dependsOn("reobfJar") + } +} \ No newline at end of file diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/AwfulBukkitHacks.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/AwfulBukkitHacks.java new file mode 100644 index 000000000..6ce0cc9a5 --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/AwfulBukkitHacks.java @@ -0,0 +1,101 @@ +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> terraBiomeMap = new HashMap<>(); + + public static void registerBiomes(ConfigRegistry configRegistry) { + try { + LOGGER.info("Hacking biome registry..."); + WritableRegistry biomeRegistry = (WritableRegistry) 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 delegateKey = ResourceKey.create( + Registries.BIOME, + new ResourceLocation("terra", NMSBiomeInjector.createBiomeID(pack, key)) + ); + + Reference 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, List>> collect = biomeRegistry + .getTags() // streamKeysAndEntries + .collect(HashMap::new, + (map, pair) -> + map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())), + HashMap::putAll); + + terraBiomeMap + .forEach((vb, terraBiomes) -> + NMSBiomeInjector.getEntry(biomeRegistry, vb).ifPresentOrElse( + vanilla -> terraBiomes.forEach( + tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb).ifPresentOrElse( + terra -> { + LOGGER.debug("{} (vanilla 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); + } + } +} + diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSBiomeInfo.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSBiomeInfo.java new file mode 100644 index 000000000..816d96068 --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSBiomeInfo.java @@ -0,0 +1,10 @@ +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 biomeKey) implements Properties { +} diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSBiomeInjector.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSBiomeInjector.java new file mode 100644 index 000000000..f7bedfd0f --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSBiomeInjector.java @@ -0,0 +1,83 @@ +package com.dfsek.terra.bukkit.nms.v1_19_R3; + +import net.minecraft.core.Holder; +import java.util.stream.Stream; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +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 java.util.function.Function; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.bukkit.config.VanillaBiomeProperties; + +import static net.minecraft.world.level.biome.Biome.ClimateSettings; +import static net.minecraft.world.level.biome.Biome.Precipitation; + +public class NMSBiomeInjector { + + public static Optional> getEntry(Registry 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); + } +} diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSBiomeProvider.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSBiomeProvider.java new file mode 100644 index 000000000..52711f0ec --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSBiomeProvider.java @@ -0,0 +1,47 @@ +package com.dfsek.terra.bukkit.nms.v1_19_R3; + +import com.mojang.serialization.Codec; +import net.minecraft.core.Holder; +import java.util.stream.Stream; +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 biomeRegistry = RegistryFetcher.biomeRegistry(); + + public NMSBiomeProvider(BiomeProvider delegate, long seed) { + super(); + this.delegate = delegate; + this.seed = seed; + } + @Override + protected Stream> collectPossibleBiomes() { + return delegate.stream() + .map(biome -> RegistryFetcher.biomeRegistry() + .getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext() + .get(NMSBiomeInfo.class) + .biomeKey())); + } + + @Override + protected @NotNull Codec codec() { + return BiomeSource.CODEC; + } + + @Override + public @NotNull Holder getNoiseBiome(int x, int y, int z, @NotNull Sampler sampler) { + return biomeRegistry.getHolderOrThrow(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed) + .getPlatformBiome()).getContext() + .get(NMSBiomeInfo.class) + .biomeKey()); + } +} diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSChunkGeneratorDelegate.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSChunkGeneratorDelegate.java new file mode 100644 index 000000000..78eda7e32 --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSChunkGeneratorDelegate.java @@ -0,0 +1,173 @@ +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.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 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 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 text, @NotNull RandomState noiseConfig, @NotNull BlockPos pos) { + + } +} diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSInitializer.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSInitializer.java new file mode 100644 index 000000000..99797e8ab --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSInitializer.java @@ -0,0 +1,15 @@ +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()); + } +} diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSInjectListener.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSInjectListener.java new file mode 100644 index 000000000..46b479860 --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSInjectListener.java @@ -0,0 +1,48 @@ +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 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(); + } + } +} diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSWorldProperties.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSWorldProperties.java new file mode 100644 index 000000000..0c88eec33 --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/NMSWorldProperties.java @@ -0,0 +1,36 @@ +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(); + } +} diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/Reflection.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/Reflection.java new file mode 100644 index 000000000..a10837e11 --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/Reflection.java @@ -0,0 +1,52 @@ +package com.dfsek.terra.bukkit.nms.v1_19_R3; + +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; + +import java.util.Objects; + + +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") + void invokeBindValue(Reference instance, T value); + } +} diff --git a/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/RegistryFetcher.java b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/RegistryFetcher.java new file mode 100644 index 000000000..4c5c704b1 --- /dev/null +++ b/platforms/bukkit/nms/v1_20_R1/src/main/java/com/dfsek/terra/bukkit/nms/v1_19_R3/RegistryFetcher.java @@ -0,0 +1,25 @@ +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 net.minecraft.world.level.levelgen.structure.StructureSet; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_19_R3.CraftServer; + + +public class RegistryFetcher { + private static Registry getRegistry(ResourceKey> key) { + CraftServer craftserver = (CraftServer) Bukkit.getServer(); + DedicatedServer dedicatedserver = craftserver.getServer(); + return dedicatedserver + .registryAccess() + .registryOrThrow(key); + } + + public static Registry biomeRegistry() { + return getRegistry(Registries.BIOME); + } +}