Paper/patches/server/0571-Add-StructuresLocateEvent.patch
Nassim Jahnke ef0e5a642d
Updated Upstream (Bukkit/CraftBukkit/Spigot)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

Bukkit Changes:
9ae3f10f SPIGOT-3842: Add Player#fireworkBoost() and expand Firework API
48c0c547 PR-786: Add methods to get sounds from entities

CraftBukkit Changes:
5cc9c022a SPIGOT-7152: Handle hand item changing during air interact event
4ffa1acf6 SPIGOT-7154: Players get kicked when interacting with a conversation
4daa21123 SPIGOT-3842: Add Player#fireworkBoost() and expand Firework API
e5d6a9bbf PR-1100: Add methods to get sounds from entities
b7e9f1c8b SPIGOT-7146: Reduce use of Material switch in ItemMeta

Spigot Changes:
4c157bb4 Rebuild patches
2022-09-12 13:31:45 +02:00

215 lines
11 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: dfsek <dfsek@protonmail.com>
Date: Wed, 16 Sep 2020 01:12:29 -0700
Subject: [PATCH] Add StructuresLocateEvent
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
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);
+ }
+}