Paper/patches/server/0536-Add-StructuresLocateEvent.patch
Nassim Jahnke c0936a71bd
Updated Upstream (Bukkit/CraftBukkit/Spigot) (#9440)
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:
01aa02eb PR-858: Add LivingEntity#playHurtAnimation()
9421320f PR-884: Refinements to new ban API for improved compatibility and correctness
37a60b45 SPIGOT-6455, SPIGOT-7030, PR-750: Improve ban API
4eeb174b All smithing inventories are now the new smithing inventory
f2bb168e PR-880: Add methods to get/set FallingBlock CancelDrop
e7a807fa PR-879: Add Player#sendHealthUpdate()
692b8e96 SPIGOT-7370: Remove float value conversion in plugin.yml
2d033390 SPIGOT-7403: Add direct API for waxed signs
16a08373 PR-876: Add missing Raider API and 'no action ticks'

CraftBukkit Changes:
b60a95c8c PR-1189: Add LivingEntity#playHurtAnimation()
95c335c63 PR-1226: Fix VehicleEnterEvent not being called for certain entities
0a0fc3bee PR-1227: Refinements to new ban API for improved compatibility and correctness
0d0b1e5dc Revert bad change to PathfinderGoalSit causing all cats to sit
648196070 SPIGOT-6455, SPIGOT-7030, PR-1054: Improve ban API
31fe848d6 All smithing inventories are now the new smithing inventory
9a919a143 SPIGOT-7416: SmithItemEvent not firing in Smithing Table
9f64f0d22 PR-1221: Add methods to get/set FallingBlock CancelDrop
3be9ac171 PR-1220: Add Player#sendHealthUpdate()
c1279f775 PR-1209: Clean up various patches
c432e4397 Fix Raider#setCelebrating() implementation
504d96665 SPIGOT-7403: Add direct API for waxed signs
c68c1f1b3 PR-1216: Add missing Raider API and 'no action ticks'
85b89c3dd Increase outdated build delay

Spigot Changes:
9ebce8af Rebuild patches
64b565e6 Rebuild patches
2023-07-04 10:22:56 +02:00

196 lines
10 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/world/structure/PaperConfiguredStructure.java b/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java
new file mode 100644
index 0000000000000000000000000000000000000000..09837f6e6c6ab8a1df2aacdb86646993123dd424
--- /dev/null
+++ b/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java
@@ -0,0 +1,35 @@
+package io.papermc.paper.world.structure;
+
+import java.util.Objects;
+import net.minecraft.core.Registry;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.level.levelgen.structure.Structure;
+import org.bukkit.NamespacedKey;
+import org.bukkit.StructureType;
+import org.bukkit.craftbukkit.CraftRegistry;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+@Deprecated(forRemoval = true)
+public final class PaperConfiguredStructure {
+
+ private PaperConfiguredStructure() {
+ }
+
+ @Deprecated(forRemoval = true)
+ public static final class LegacyRegistry extends CraftRegistry<ConfiguredStructure, Structure> {
+
+ public LegacyRegistry(final Registry<Structure> minecraftRegistry) {
+ super(minecraftRegistry, LegacyRegistry::minecraftToBukkit);
+ }
+
+ private static @Nullable ConfiguredStructure minecraftToBukkit(NamespacedKey key, Structure nms) {
+ final ResourceLocation structureTypeLoc = Objects.requireNonNull(BuiltInRegistries.STRUCTURE_TYPE.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 4da303d7e15496f04f0e27bfb613176bc2a72b76..3c7920721914588a3e7eaf1faff46f7305823416 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -121,6 +121,24 @@ public abstract class ChunkGenerator {
@Nullable
public Pair<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel world, HolderSet<Structure> structures, BlockPos center, int radius, boolean skipReferencedStructures) {
+ // Paper start - StructuresLocateEvent
+ final org.bukkit.World bukkitWorld = world.getWorld();
+ final org.bukkit.Location origin = io.papermc.paper.util.MCUtil.toLocation(world, center);
+ final List<org.bukkit.generator.structure.Structure> apiStructures = structures.stream().map(Holder::value).map(nms -> org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(nms, world.registryAccess())).toList();
+ if (!apiStructures.isEmpty()) {
+ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, radius, skipReferencedStructures);
+ if (!event.callEvent()) {
+ return null;
+ }
+ if (event.getResult() != null) {
+ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), world.registryAccess().registryOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(event.getResult().structure())));
+ }
+ center = io.papermc.paper.util.MCUtil.toBlockPosition(event.getOrigin());
+ radius = event.getRadius();
+ skipReferencedStructures = event.shouldFindUnexplored();
+ structures = HolderSet.direct(api -> world.registryAccess().registryOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(api)), event.getStructures());
+ }
+ // Paper end
ChunkGeneratorStructureState chunkgeneratorstructurestate = world.getChunkSource().getGeneratorState();
Map<StructurePlacement, Set<Holder<Structure>>> map = new Object2ObjectArrayMap();
Iterator iterator = structures.iterator();
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java
index 8e1a6206eafdf4160aef280710f0912a0664536f..15abd319ac51a97cdb07da85e815ea93ff45431a 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java
@@ -37,6 +37,11 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
return new CraftRegistry<>(registryHolder.registryOrThrow(Registries.TRIM_PATTERN), CraftTrimPattern::new);
}
// TODO registry modification API
+ // Paper start - remove this after a while along with all ConfiguredStructure stuff
+ if (bukkitClass == io.papermc.paper.world.structure.ConfiguredStructure.class) {
+ return new io.papermc.paper.world.structure.PaperConfiguredStructure.LegacyRegistry(registryHolder.registryOrThrow(Registries.STRUCTURE));
+ }
+ // Paper end
return null;
}
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..102b99691b53f5e3c14999d3c281b0301b9665d5
--- /dev/null
+++ b/src/test/java/io/papermc/paper/world/structure/ConfiguredStructureTest.java
@@ -0,0 +1,96 @@
+package io.papermc.paper.world.structure;
+
+import io.papermc.paper.registry.Reference;
+import net.minecraft.core.Registry;
+import net.minecraft.core.registries.Registries;
+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;
+
+@Deprecated(forRemoval = true)
+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() {
+ Registry<Structure> structureRegistry = AbstractTestingBase.REGISTRY_CUSTOM.registryOrThrow(Registries.STRUCTURE);
+ assertEquals("configured structure maps should be the same size", BUILT_IN_STRUCTURES.size(), structureRegistry.size());
+
+ Map<ResourceLocation, Structure> missing = new LinkedHashMap<>();
+ for (Structure feature : structureRegistry) {
+ final ResourceLocation key = structureRegistry.getKey(feature);
+ assertNotNull("Missing built-in registry key", key);
+ if (key.equals(BuiltinStructures.ANCIENT_CITY.location()) || key.equals(BuiltinStructures.TRAIL_RUINS.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() {
+ Registry<Structure> structureRegistry = AbstractTestingBase.REGISTRY_CUSTOM.registryOrThrow(Registries.STRUCTURE);
+ for (NamespacedKey apiKey : DEFAULT_CONFIGURED_STRUCTURES.keySet()) {
+ assertTrue(apiKey + " does not have a minecraft counterpart", structureRegistry.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);
+ }
+}