diff options
Diffstat (limited to 'patches/server/0572-Add-StructuresLocateEvent.patch')
-rw-r--r-- | patches/server/0572-Add-StructuresLocateEvent.patch | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/patches/server/0572-Add-StructuresLocateEvent.patch b/patches/server/0572-Add-StructuresLocateEvent.patch new file mode 100644 index 0000000000..c8d1241689 --- /dev/null +++ b/patches/server/0572-Add-StructuresLocateEvent.patch @@ -0,0 +1,214 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dfsek <[email protected]> +Date: Wed, 16 Sep 2020 01:12:29 -0700 +Subject: [PATCH] Add StructuresLocateEvent + +Co-authored-by: Jake Potrebic <[email protected]> + +diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java +index 6f39e343147803e15e7681c993b8797a629702e7..87154ae69788249960bca376aafd90bf64d5bfe7 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.structure.Structure; + import org.bukkit.Keyed; + + public record RegistryKey<API extends Keyed, MINECRAFT>(Class<API> apiClass, ResourceKey<? extends Registry<MINECRAFT>> resourceKey) { ++ ++ public static final RegistryKey<ConfiguredStructure, Structure> CONFIGURED_STRUCTURE_REGISTRY = new RegistryKey<>(ConfiguredStructure.class, Registry.STRUCTURE_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..423bf87ebda7ea266dc7b48cbfadbc8551180721 +--- /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.structure.Structure; ++import org.bukkit.NamespacedKey; ++import org.bukkit.StructureType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++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<ConfiguredStructure, Structure> { ++ ++ private static final Supplier<Registry<Structure>> STRUCTURE_FEATURE_REGISTRY = registryFor(Registry.STRUCTURE_REGISTRY); ++ ++ public ConfiguredStructureRegistry() { ++ super(RegistryKey.CONFIGURED_STRUCTURE_REGISTRY); ++ } ++ ++ @Override ++ public @Nullable ConfiguredStructure convertToApi(NamespacedKey key, Structure nms) { ++ final ResourceLocation structureTypeLoc = Objects.requireNonNull(Registry.STRUCTURE_TYPES.getKey(nms.type()), "unexpected structure type " + nms.type()); ++ final @Nullable StructureType structureType = StructureType.getStructureTypes().get(structureTypeLoc.getPath()); ++ return structureType == null ? null : new ConfiguredStructure(key, structureType); ++ } ++ } ++} +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +index b1eecc184bc9daf0a9c7db8da06e11bfb63d9d88..28f01f29796a8a8e6e6331da5525a4306d78230e 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -295,6 +295,26 @@ public abstract class ChunkGenerator { + + @Nullable + public Pair<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel world, HolderSet<Structure> structures, BlockPos center, int radius, boolean skipReferencedStructures) { ++ // Paper start - StructureLocateEvent ++ final org.bukkit.World bukkitWorld = world.getWorld(); ++ final org.bukkit.Location origin = net.minecraft.server.MCUtil.toLocation(world, center); ++ final var paperRegistry = io.papermc.paper.registry.PaperRegistry.getRegistry(io.papermc.paper.registry.RegistryKey.CONFIGURED_STRUCTURE_REGISTRY); ++ final List<io.papermc.paper.world.structure.ConfiguredStructure> configuredStructures = new ArrayList<>(); ++ paperRegistry.convertToApi(structures, configuredStructures::add, false); // gracefully handle missing api, use tests to check (or exclude) ++ if (!configuredStructures.isEmpty()) { ++ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, configuredStructures, radius, skipReferencedStructures); ++ 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(); ++ skipReferencedStructures = event.shouldFindUnexplored(); ++ structures = HolderSet.direct(paperRegistry::getMinecraftHolder, event.getConfiguredStructures()); ++ } ++ // Paper end + Map<StructurePlacement, Set<Holder<Structure>>> map = new Object2ObjectArrayMap(); + Iterator iterator = structures.iterator(); + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/Structure.java b/src/main/java/net/minecraft/world/level/levelgen/structure/Structure.java +index 737956b316c02e4ccdc6eef8de4a0a299d36b9ca..b8649eab719a1b71dc686386a8db756eefb9802e 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/Structure.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/Structure.java +@@ -41,6 +41,7 @@ public abstract class Structure { + public static final Codec<Structure> DIRECT_CODEC = Registry.STRUCTURE_TYPES.byNameCodec().dispatch(Structure::type, StructureType::codec); + public static final Codec<Holder<Structure>> CODEC = RegistryFileCodec.create(Registry.STRUCTURE_REGISTRY, DIRECT_CODEC); + protected final Structure.StructureSettings settings; ++ static { io.papermc.paper.world.structure.PaperConfiguredStructure.init(); } // Paper + + public static <S extends Structure> RecordCodecBuilder<S, Structure.StructureSettings> settingsCodec(RecordCodecBuilder.Instance<S> instance) { + return Structure.StructureSettings.CODEC.forGetter((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..61efebe1d363b34e2043ccc4c6e28bb714c2fa31 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/world/structure/ConfiguredStructureTest.java +@@ -0,0 +1,92 @@ ++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.structure.Structure; ++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<ResourceLocation, String> BUILT_IN_STRUCTURES = new LinkedHashMap<>(); ++ private static final Map<NamespacedKey, Reference<?>> 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.STRUCTURES.size()); ++ ++ Map<ResourceLocation, Structure> missing = new LinkedHashMap<>(); ++ for (Structure feature : BuiltinRegistries.STRUCTURES) { ++ final ResourceLocation key = BuiltinRegistries.STRUCTURES.getKey(feature); ++ assertNotNull("Missing built-in registry key", key); ++ if (key.equals(BuiltinStructures.ANCIENT_CITY.location())) { ++ continue; // TODO remove when upstream adds "jigsaw" StructureType ++ } ++ 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.STRUCTURES.containsKey(CraftNamespacedKey.toMinecraft(apiKey))); ++ } ++ } ++ ++ private static String printMissing(Map<ResourceLocation, Structure> missing) { ++ final StringJoiner joiner = new StringJoiner("\n", "Missing: \n", ""); ++ ++ missing.forEach((key, configuredFeature) -> { ++ joiner.add("public static final Reference<ConfiguredStructure> " + BUILT_IN_STRUCTURES.get(key) + " = create(\"" + key.getPath() + "\");"); ++ }); ++ ++ return joiner.toString(); ++ } ++ ++ @AfterClass ++ public static void after() { ++ System.setOut(out); ++ } ++} |