Add datapack registration lifecycle event

This commit is contained in:
Jake Potrebic 2024-05-12 17:34:17 -07:00
parent 11c39637de
commit e19e1abd1e
No known key found for this signature in database
GPG Key ID: ECE0B3C133C016C5
5 changed files with 226 additions and 0 deletions

View File

@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 12 May 2024 17:30:54 -0700
Subject: [PATCH] Add datapack registration lifecycle event
diff --git a/src/main/java/io/papermc/paper/datapack/DatapackRegistrar.java b/src/main/java/io/papermc/paper/datapack/DatapackRegistrar.java
new file mode 100644
index 0000000000000000000000000000000000000000..d7ef489f36be63b667a61898179cfbf3e89f429e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/datapack/DatapackRegistrar.java
@@ -0,0 +1,16 @@
+package io.papermc.paper.datapack;
+
+import io.papermc.paper.plugin.lifecycle.event.registrar.Registrar;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Path;
+import net.kyori.adventure.text.Component;
+import org.jetbrains.annotations.NotNull;
+
+public interface DatapackRegistrar extends Registrar {
+
+ void addDatapack(@NotNull URI uri, @NotNull String id, @NotNull Component title) throws IOException;
+
+ void addDatapack(@NotNull Path path, @NotNull String id, @NotNull Component title) throws IOException;
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java
index 1fab48593c567fe05b085ac6e12dc22556cf0b92..180b4545ad3693c86a612043c3cb0c4b76248630 100644
--- a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java
@@ -5,6 +5,7 @@ import io.papermc.paper.plugin.bootstrap.BootstrapContext;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
+import io.papermc.paper.plugin.lifecycle.event.registrar.RegistrarEvent;
import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.ApiStatus;
@@ -24,6 +25,8 @@ public final class LifecycleEvents {
*/
public static final LifecycleEventType.Prioritizable<LifecycleEventOwner, ReloadableRegistrarEvent<Commands>> COMMANDS = prioritized("commands", LifecycleEventOwner.class);
+ public static final LifecycleEventType.Prioritizable<BootstrapContext, RegistrarEvent<io.papermc.paper.datapack.DatapackRegistrar>> DATAPACK_REGISTRATION = prioritized("datapack_registration", BootstrapContext.class);
+
//<editor-fold desc="helper methods" defaultstate="collapsed">
@ApiStatus.Internal
private static <E extends LifecycleEvent> LifecycleEventType.Monitorable<Plugin, E> plugin(final String name) {

View File

@ -0,0 +1,146 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 12 May 2024 17:30:50 -0700
Subject: [PATCH] Add datapack registration lifecycle event
== AT ==
public net/minecraft/server/packs/repository/FolderRepositorySource$FolderPackDetector
public net/minecraft/server/packs/repository/FolderRepositorySource$FolderPackDetector <init>(Lnet/minecraft/world/level/validation/DirectoryValidator;)V
diff --git a/src/main/java/io/papermc/paper/datapack/PluginDatapackRepositorySource.java b/src/main/java/io/papermc/paper/datapack/PluginDatapackRepositorySource.java
new file mode 100644
index 0000000000000000000000000000000000000000..8279142e5ece897c0e0a2f1d1bf34933eb38edfa
--- /dev/null
+++ b/src/main/java/io/papermc/paper/datapack/PluginDatapackRepositorySource.java
@@ -0,0 +1,87 @@
+package io.papermc.paper.datapack;
+
+import com.mojang.logging.LogUtils;
+import io.papermc.paper.adventure.PaperAdventure;
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner;
+import io.papermc.paper.plugin.lifecycle.event.registrar.PaperRegistrar;
+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Consumer;
+import net.kyori.adventure.text.Component;
+import net.minecraft.server.packs.PackLocationInfo;
+import net.minecraft.server.packs.PackSelectionConfig;
+import net.minecraft.server.packs.PackType;
+import net.minecraft.server.packs.VanillaPackResourcesBuilder;
+import net.minecraft.server.packs.repository.FolderRepositorySource;
+import net.minecraft.server.packs.repository.Pack;
+import net.minecraft.server.packs.repository.PackDetector;
+import net.minecraft.server.packs.repository.RepositorySource;
+import net.minecraft.world.level.validation.ContentValidationException;
+import net.minecraft.world.level.validation.DirectoryValidator;
+import net.minecraft.world.level.validation.ForbiddenSymlinkInfo;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.slf4j.Logger;
+
+import static java.util.Objects.requireNonNull;
+
+@DefaultQualifier(NonNull.class)
+public class PluginDatapackRepositorySource implements RepositorySource {
+
+ private static final Logger LOGGER = LogUtils.getLogger();
+ // TODO make this configurable when the plugin adds the pack
+ private static final PackSelectionConfig DISCOVERED_PACK_SELECTION_CONFIG = new PackSelectionConfig(false, Pack.Position.TOP, false);
+
+ private final DirectoryValidator validator;
+
+ public PluginDatapackRepositorySource(final DirectoryValidator validator) {
+ this.validator = validator;
+ }
+
+ @Override
+ public void loadPacks(final Consumer<Pack> packAdder) {
+
+ class RegistrarImpl implements PaperRegistrar<BootstrapContext>, DatapackRegistrar {
+
+ private final PackDetector<Pack.ResourcesSupplier> detector = new FolderRepositorySource.FolderPackDetector(PluginDatapackRepositorySource.this.validator);
+ private @Nullable BootstrapContext owner;
+
+ @Override
+ public void setCurrentContext(final @Nullable BootstrapContext owner) {
+ this.owner = owner;
+ }
+
+ @Override
+ public void addDatapack(final URI uri, final String id, final Component title) throws IOException {
+ this.addDatapack(VanillaPackResourcesBuilder.safeGetPath(uri), id, title);
+ }
+
+ @Override
+ public void addDatapack(final Path path, final String id, final Component title) throws IOException {
+ final List<ForbiddenSymlinkInfo> badLinks = new ArrayList<>();
+ final Pack.@Nullable ResourcesSupplier resourcesSupplier = this.detector.detectPackResources(path, badLinks);
+ if (!badLinks.isEmpty()) {
+ LOGGER.warn("Ignoring potential pack entry: {}", ContentValidationException.getMessage(path, badLinks));
+ } else if (resourcesSupplier != null) {
+ final String packId = requireNonNull(this.owner).getPluginMeta().getName() + "/" + id;
+ final PackLocationInfo locInfo = new PackLocationInfo(packId, PaperAdventure.asVanilla(title), PluginPackSource.INSTANCE, Optional.empty());
+ final @Nullable Pack pack = Pack.readMetaAndCreate(locInfo, resourcesSupplier, PackType.SERVER_DATA, DISCOVERED_PACK_SELECTION_CONFIG);
+ if (pack != null) {
+ packAdder.accept(pack);
+ }
+ } else {
+ LOGGER.info("Found non-pack entry '{}', ignoring", path);
+ }
+ }
+ }
+
+ LifecycleEventRunner.INSTANCE.callStaticRegistrarEvent(LifecycleEvents.DATAPACK_REGISTRATION, new RegistrarImpl(), BootstrapContext.class);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/datapack/PluginPackSource.java b/src/main/java/io/papermc/paper/datapack/PluginPackSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..dfea23ddde7b929f4d47c5de9539cf8bb96bcfff
--- /dev/null
+++ b/src/main/java/io/papermc/paper/datapack/PluginPackSource.java
@@ -0,0 +1,26 @@
+package io.papermc.paper.datapack;
+
+import net.minecraft.ChatFormatting;
+import net.minecraft.network.chat.Component;
+import net.minecraft.server.packs.repository.PackSource;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+final class PluginPackSource implements PackSource {
+
+ static final PackSource INSTANCE = new PluginPackSource();
+
+ private PluginPackSource() {
+ }
+
+ @Override
+ public Component decorate(final Component packDisplayName) {
+ return Component.translatable("pack.nameAndSource", packDisplayName, "plugin").withStyle(ChatFormatting.GRAY);
+ }
+
+ @Override
+ public boolean shouldAddAutomatically() {
+ return true;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/packs/repository/ServerPacksSource.java b/src/main/java/net/minecraft/server/packs/repository/ServerPacksSource.java
index def8ed40ef732b512a07fe50449c77a860b97462..72c39887631916a7e448123fa793057779e75c53 100644
--- a/src/main/java/net/minecraft/server/packs/repository/ServerPacksSource.java
+++ b/src/main/java/net/minecraft/server/packs/repository/ServerPacksSource.java
@@ -82,6 +82,7 @@ public class ServerPacksSource extends BuiltInPackSource {
public static PackRepository createPackRepository(Path dataPacksPath, DirectoryValidator symlinkFinder) {
return new PackRepository(
new ServerPacksSource(symlinkFinder), new FolderRepositorySource(dataPacksPath, PackType.SERVER_DATA, PackSource.WORLD, symlinkFinder)
+ , new io.papermc.paper.datapack.PluginDatapackRepositorySource(symlinkFinder) // Paper - event for finding custom datapacks
);
}

View File

@ -1,14 +1,33 @@
package io.papermc.testplugin;
import io.papermc.paper.datapack.DatapackRegistrar;
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
import org.jetbrains.annotations.NotNull;
import static net.kyori.adventure.text.Component.text;
public class TestPluginBootstrap implements PluginBootstrap {
@Override
public void bootstrap(@NotNull BootstrapContext context) {
// io.papermc.testplugin.brigtests.Registration.registerViaBootstrap(context);
final LifecycleEventManager<BootstrapContext> manager = context.getLifecycleManager();
manager.registerEventHandler(LifecycleEvents.DATAPACK_REGISTRATION, event -> {
final DatapackRegistrar registrar = event.registrar();
try {
final URI uri = Objects.requireNonNull(TestPluginBootstrap.class.getResource("/pack")).toURI();
registrar.addDatapack(uri, "test", text("HEY THERE"));
} catch (final URISyntaxException | IOException e) {
throw new RuntimeException(e);
}
});
}
}

View File

@ -0,0 +1,6 @@
{
"values": [
"minecraft:zombie",
"minecraft:spider"
]
}

View File

@ -0,0 +1,6 @@
{
"pack":{
"pack_format": 41,
"description": "Test datapack for tags"
}
}