From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: dfsek Date: Wed, 16 Sep 2020 01:12:29 -0700 Subject: [PATCH] Add StructuresLocateEvent Co-authored-by: Jake Potrebic diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java index 6f39e343147803e15e7681c993b8797a629702e7..cbff75f19e54b37c762b209b04f6d4799152cf5b 100644 --- a/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -1,8 +1,13 @@ package io.papermc.paper.registry; +import io.papermc.paper.world.structure.ConfiguredStructure; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; import org.bukkit.Keyed; public record RegistryKey(Class apiClass, ResourceKey> resourceKey) { + + public static final RegistryKey> CONFIGURED_STRUCTURE_REGISTRY = new RegistryKey<>(ConfiguredStructure.class, Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY); + } diff --git a/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java b/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java new file mode 100644 index 0000000000000000000000000000000000000000..41f6c2e1e60fc32e6393097711412ca2ad643e57 --- /dev/null +++ b/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java @@ -0,0 +1,42 @@ +package io.papermc.paper.world.structure; + +import io.papermc.paper.registry.PaperRegistry; +import io.papermc.paper.registry.RegistryKey; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; +import net.minecraft.world.level.levelgen.feature.StructureFeature; +import org.bukkit.NamespacedKey; +import org.bukkit.StructureType; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; + +import java.util.Objects; +import java.util.function.Supplier; + +@DefaultQualifier(NonNull.class) +public final class PaperConfiguredStructure { + + private PaperConfiguredStructure() { + } + + public static void init() { + new ConfiguredStructureRegistry().register(); + } + + static final class ConfiguredStructureRegistry extends PaperRegistry> { + + private static final Supplier>> STRUCTURE_FEATURE_REGISTRY = registryFor(Registry.STRUCTURE_FEATURE_REGISTRY); + + public ConfiguredStructureRegistry() { + super(RegistryKey.CONFIGURED_STRUCTURE_REGISTRY); + } + + @Override + public ConfiguredStructure convertToApi(NamespacedKey key, ConfiguredStructureFeature nms) { + final ResourceLocation structureFeatureLoc = Objects.requireNonNull(STRUCTURE_FEATURE_REGISTRY.get().getKey(nms.feature)); + final StructureType structureType = Objects.requireNonNull(StructureType.getStructureTypes().get(structureFeatureLoc.getPath()), structureFeatureLoc + " could not be converted to an API type"); + return new ConfiguredStructure(key, structureType); + } + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 9941456a019a34384f892c44df3c73f9416bd560..d109ef77109fbeb710eafb55a38c803b9bb37d73 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -2032,7 +2032,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop>> findNearestMapFeature(ServerLevel worldserver, HolderSet> holderset, BlockPos center, int radius, boolean skipExistingChunks) { + // Paper start - StructureLocateEvent + final org.bukkit.World world = worldserver.getWorld(); + final org.bukkit.Location origin = net.minecraft.server.MCUtil.toLocation(worldserver, center); + final var paperRegistry = io.papermc.paper.registry.PaperRegistry.getRegistry(io.papermc.paper.registry.RegistryKey.CONFIGURED_STRUCTURE_REGISTRY); + final List configuredStructures = new ArrayList<>(); + for (Holder> holder : holderset) { + configuredStructures.add(paperRegistry.convertToApi(holder)); + } + final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(world, origin, configuredStructures, radius, skipExistingChunks); + if (!event.callEvent()) { + return null; + } + if (event.getResult() != null) { + return Pair.of(net.minecraft.server.MCUtil.toBlockPosition(event.getResult().position()), paperRegistry.getMinecraftHolder(event.getResult().configuredStructure())); + } + center = net.minecraft.server.MCUtil.toBlockPosition(event.getOrigin()); + radius = event.getRadius(); + skipExistingChunks = event.shouldFindUnexplored(); + holderset = HolderSet.direct(paperRegistry::getMinecraftHolder, event.getConfiguredStructures()); + // Paper end Set> set = (Set) holderset.stream().flatMap((holder) -> { return ((ConfiguredStructureFeature) holder.value()).biomes().stream(); }).collect(Collectors.toSet()); diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/ConfiguredStructureFeature.java b/src/main/java/net/minecraft/world/level/levelgen/feature/ConfiguredStructureFeature.java index af9ef29f5c5a600e4544ba735c833699cc93f93a..473a54963fbe08beeff26a828827f9f72d8a29b8 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/feature/ConfiguredStructureFeature.java +++ b/src/main/java/net/minecraft/world/level/levelgen/feature/ConfiguredStructureFeature.java @@ -38,6 +38,7 @@ public class ConfiguredStructureFeature biomes; public final Map spawnOverrides; public final boolean adaptNoise; + static { io.papermc.paper.world.structure.PaperConfiguredStructure.init(); } // Paper public ConfiguredStructureFeature(F feature, FC config, HolderSet biomes, boolean bl, Map map) { this.feature = feature; diff --git a/src/test/java/io/papermc/paper/world/structure/ConfiguredStructureTest.java b/src/test/java/io/papermc/paper/world/structure/ConfiguredStructureTest.java new file mode 100644 index 0000000000000000000000000000000000000000..29c0209327374d5a4dad4e3bacdba7fa56d80749 --- /dev/null +++ b/src/test/java/io/papermc/paper/world/structure/ConfiguredStructureTest.java @@ -0,0 +1,89 @@ +package io.papermc.paper.world.structure; + +import io.papermc.paper.registry.Reference; +import net.minecraft.data.BuiltinRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.Bootstrap; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; +import net.minecraft.world.level.levelgen.structure.BuiltinStructures; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.support.AbstractTestingBase; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.StringJoiner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class ConfiguredStructureTest extends AbstractTestingBase { + + private static final Map BUILT_IN_STRUCTURES = new LinkedHashMap<>(); + private static final Map> DEFAULT_CONFIGURED_STRUCTURES = new LinkedHashMap<>(); + + private static PrintStream out; + + @BeforeClass + public static void collectStructures() throws ReflectiveOperationException { + out = System.out; + System.setOut(Bootstrap.STDOUT); + for (Field field : BuiltinStructures.class.getDeclaredFields()) { + if (field.getType().equals(ResourceKey.class) && Modifier.isStatic(field.getModifiers())) { + BUILT_IN_STRUCTURES.put(((ResourceKey) field.get(null)).location(), field.getName()); + } + } + for (Field field : ConfiguredStructure.class.getDeclaredFields()) { + if (field.getType().equals(Reference.class) && Modifier.isStatic(field.getModifiers())) { + final Reference ref = (Reference) field.get(null); + DEFAULT_CONFIGURED_STRUCTURES.put(ref.getKey(), ref); + } + } + } + + @Test + public void testMinecraftToApi() { + assertEquals("configured structure maps should be the same size", BUILT_IN_STRUCTURES.size(), BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE.size()); + + Map> missing = new LinkedHashMap<>(); + for (ConfiguredStructureFeature feature : BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE) { + final ResourceLocation key = BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE.getKey(feature); + assertNotNull("Missing built-in registry key", key); + if (DEFAULT_CONFIGURED_STRUCTURES.get(CraftNamespacedKey.fromMinecraft(key)) == null) { + missing.put(key, feature); + } + } + + assertTrue(printMissing(missing), missing.isEmpty()); + } + + @Test + public void testApiToMinecraft() { + for (NamespacedKey apiKey : DEFAULT_CONFIGURED_STRUCTURES.keySet()) { + assertTrue(apiKey + " does not have a minecraft counterpart", BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE.containsKey(CraftNamespacedKey.toMinecraft(apiKey))); + } + } + + private static String printMissing(Map> missing) { + final StringJoiner joiner = new StringJoiner("\n", "Missing: \n", ""); + + missing.forEach((key, configuredFeature) -> { + joiner.add("public static final Reference " + BUILT_IN_STRUCTURES.get(key) + " = create(\"" + key.getPath() + "\");"); + }); + + return joiner.toString(); + } + + @AfterClass + public static void after() { + System.setOut(out); + } +}