mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-25 22:10:21 +01:00
Add datapack registration lifecycle event
This commit is contained in:
parent
d0d0efee02
commit
b71ad2ebb3
17 changed files with 697 additions and 110 deletions
|
@ -110,6 +110,8 @@ public net.minecraft.server.network.ServerLoginPacketListenerImpl connection
|
||||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl state
|
public net.minecraft.server.network.ServerLoginPacketListenerImpl state
|
||||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl$State
|
public net.minecraft.server.network.ServerLoginPacketListenerImpl$State
|
||||||
public net.minecraft.server.packs.VanillaPackResourcesBuilder safeGetPath(Ljava/net/URI;)Ljava/nio/file/Path;
|
public net.minecraft.server.packs.VanillaPackResourcesBuilder safeGetPath(Ljava/net/URI;)Ljava/nio/file/Path;
|
||||||
|
public net.minecraft.server.packs.repository.FolderRepositorySource$FolderPackDetector
|
||||||
|
public net.minecraft.server.packs.repository.FolderRepositorySource$FolderPackDetector <init>(Lnet/minecraft/world/level/validation/DirectoryValidator;)V
|
||||||
public net.minecraft.server.packs.repository.Pack resources
|
public net.minecraft.server.packs.repository.Pack resources
|
||||||
public net.minecraft.server.players.PlayerList playerIo
|
public net.minecraft.server.players.PlayerList playerIo
|
||||||
public net.minecraft.server.players.PlayerList players
|
public net.minecraft.server.players.PlayerList players
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package io.papermc.paper.datapack;
|
package io.papermc.paper.datapack;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import org.bukkit.FeatureFlag;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,50 +10,9 @@ import org.jspecify.annotations.NullMarked;
|
||||||
* won't be updated as datapacks are updated.
|
* won't be updated as datapacks are updated.
|
||||||
*/
|
*/
|
||||||
@NullMarked
|
@NullMarked
|
||||||
public interface Datapack {
|
@ApiStatus.NonExtendable
|
||||||
|
public interface Datapack extends DiscoveredDatapack {
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the name/id of this datapack.
|
|
||||||
*
|
|
||||||
* @return the name of the pack
|
|
||||||
*/
|
|
||||||
@Contract(pure = true)
|
|
||||||
String getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the title component of this datapack.
|
|
||||||
*
|
|
||||||
* @return the title
|
|
||||||
*/
|
|
||||||
Component getTitle();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the description component of this datapack.
|
|
||||||
*
|
|
||||||
* @return the description
|
|
||||||
*/
|
|
||||||
Component getDescription();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets if this datapack is required to be enabled.
|
|
||||||
*
|
|
||||||
* @return true if the pack is required
|
|
||||||
*/
|
|
||||||
boolean isRequired();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the compatibility status of this pack.
|
|
||||||
*
|
|
||||||
* @return the compatibility of the pack
|
|
||||||
*/
|
|
||||||
Compatibility getCompatibility();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the set of required features for this datapack.
|
|
||||||
*
|
|
||||||
* @return the set of required features
|
|
||||||
*/
|
|
||||||
@Unmodifiable Set<FeatureFlag> getRequiredFeatures();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the enabled state of this pack.
|
* Gets the enabled state of this pack.
|
||||||
|
@ -74,13 +31,6 @@ public interface Datapack {
|
||||||
*/
|
*/
|
||||||
void setEnabled(boolean enabled);
|
void setEnabled(boolean enabled);
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the source for this datapack.
|
|
||||||
*
|
|
||||||
* @return the pack source
|
|
||||||
*/
|
|
||||||
DatapackSource getSource();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the component vanilla Minecraft uses
|
* Computes the component vanilla Minecraft uses
|
||||||
* to display this datapack. Includes the {@link #getSource()},
|
* to display this datapack. Includes the {@link #getSource()},
|
||||||
|
@ -96,4 +46,11 @@ public interface Datapack {
|
||||||
TOO_NEW,
|
TOO_NEW,
|
||||||
COMPATIBLE,
|
COMPATIBLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position of the pack in the load order.
|
||||||
|
*/
|
||||||
|
enum Position {
|
||||||
|
TOP, BOTTOM
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
package io.papermc.paper.datapack;
|
||||||
|
|
||||||
|
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||||
|
import io.papermc.paper.plugin.lifecycle.event.registrar.Registrar;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The registrar for datapacks. The event for this registrar
|
||||||
|
* is called anytime the game tries to discover datapacks at any of the
|
||||||
|
* configured locations. This means that if a datapack should stay available to the server,
|
||||||
|
* it must always be discovered whenever this event fires.
|
||||||
|
* <p>An example of a plugin loading a datapack from within it's own jar is below</p>
|
||||||
|
* <pre>{@code
|
||||||
|
* public class YourPluginBootstrap implements PluginBootstrap {
|
||||||
|
* @Override
|
||||||
|
* public void bootstrap(BoostrapContext context) {
|
||||||
|
* final LifecycleEventManager<BootstrapContext> manager = context.getLifecycleManager();
|
||||||
|
* manager.registerEventHandler(LifecycleEvents.DATAPACK_DISCOVERY, event -> {
|
||||||
|
* DatapackRegistrar registrar = event.registrar();
|
||||||
|
* try {
|
||||||
|
* final URI uri = Objects.requireNonNull(
|
||||||
|
* YourPluginBootstrap.class.getResource("/pack")
|
||||||
|
* ).toURI();
|
||||||
|
* registrar.discoverPack(uri, "packId");
|
||||||
|
* } catch (final URISyntaxException | IOException e) {
|
||||||
|
* throw new RuntimeException(e);
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
* @see io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents#DATAPACK_DISCOVERY
|
||||||
|
*/
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public interface DatapackRegistrar extends Registrar {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a datapack with the specified name has been discovered.
|
||||||
|
*
|
||||||
|
* @param name the name of the pack
|
||||||
|
* @return true if the pack has been discovered
|
||||||
|
* @see Datapack#getName()
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
|
boolean hasPackDiscovered(@NonNull String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a discovered datapack by its name.
|
||||||
|
*
|
||||||
|
* @param name the name of the pack
|
||||||
|
* @return the datapack
|
||||||
|
* @throws java.util.NoSuchElementException if the pack is not discovered
|
||||||
|
* @see Datapack#getName()
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
|
@NonNull DiscoveredDatapack getDiscoveredPack(@NonNull String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a discovered datapack by its name.
|
||||||
|
*
|
||||||
|
* @param name the name of the pack
|
||||||
|
* @return true if the pack was removed
|
||||||
|
* @see Datapack#getName()
|
||||||
|
*/
|
||||||
|
@Contract(mutates = "this")
|
||||||
|
boolean removeDiscoveredPack(@NonNull String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all discovered datapacks.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable map of discovered packs
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
|
@Unmodifiable @NonNull Map<String, DiscoveredDatapack> getDiscoveredPacks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovers a datapack at the specified {@link URI} with the id.
|
||||||
|
* <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||||||
|
*
|
||||||
|
* @param uri the location of the pack
|
||||||
|
* @param id a unique id (will be combined with plugin for the datapacks name)
|
||||||
|
* @return the discovered datapack (or null if it failed)
|
||||||
|
* @throws IOException if any IO error occurs
|
||||||
|
*/
|
||||||
|
default @Nullable DiscoveredDatapack discoverPack(final @NonNull URI uri, final @NonNull String id) throws IOException {
|
||||||
|
return this.discoverPack(uri, id, c -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovers a datapack at the specified {@link URI} with the id.
|
||||||
|
* <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||||||
|
*
|
||||||
|
* @param uri the location of the pack
|
||||||
|
* @param id a unique id (will be combined with plugin for the datapacks name)
|
||||||
|
* @param configurer a configurer for extra options
|
||||||
|
* @return the discovered datapack (or null if it failed)
|
||||||
|
* @throws IOException if any IO error occurs
|
||||||
|
*/
|
||||||
|
@Nullable DiscoveredDatapack discoverPack(@NonNull URI uri, @NonNull String id, @NonNull Consumer<Configurer> configurer) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovers a datapack at the specified {@link Path} with the id.
|
||||||
|
* <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||||||
|
*
|
||||||
|
* @param path the location of the pack
|
||||||
|
* @param id a unique id (will be combined with plugin for the datapacks name)
|
||||||
|
* @return the discovered datapack (or null if it failed)
|
||||||
|
* @throws IOException if any IO error occurs
|
||||||
|
*/
|
||||||
|
default @Nullable DiscoveredDatapack discoverPack(final @NonNull Path path, final @NonNull String id) throws IOException {
|
||||||
|
return this.discoverPack(path, id, c -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovers a datapack at the specified {@link Path} with the id.
|
||||||
|
* <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||||||
|
*
|
||||||
|
* @param path the location of the pack
|
||||||
|
* @param id a unique id (will be combined with plugin for the datapacks name)
|
||||||
|
* @param configurer a configurer for extra options
|
||||||
|
* @return the discovered datapack (or null if it failed)
|
||||||
|
* @throws IOException if any IO error occurs
|
||||||
|
*/
|
||||||
|
@Nullable DiscoveredDatapack discoverPack(@NonNull Path path, @NonNull String id, @NonNull Consumer<Configurer> configurer) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovers a datapack at the specified {@link URI} with the id.
|
||||||
|
* <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||||||
|
*
|
||||||
|
* @param pluginMeta the plugin which will be the "owner" of this datapack
|
||||||
|
* @param uri the location of the pack
|
||||||
|
* @param id a unique id (will be combined with plugin for the datapacks name)
|
||||||
|
* @param configurer a configurer for extra options
|
||||||
|
* @return the discovered datapack (or null if it failed)
|
||||||
|
* @throws IOException if any IO error occurs
|
||||||
|
*/
|
||||||
|
@Nullable DiscoveredDatapack discoverPack(@NonNull PluginMeta pluginMeta, @NonNull URI uri, @NonNull String id, @NonNull Consumer<Configurer> configurer) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovers a datapack at the specified {@link Path} with the id.
|
||||||
|
* <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||||||
|
*
|
||||||
|
* @param pluginMeta the plugin which will be the "owner" of this datapack
|
||||||
|
* @param path the location of the pack
|
||||||
|
* @param id a unique id (will be combined with plugin for the datapacks name)
|
||||||
|
* @param configurer a configurer for extra options
|
||||||
|
* @return the discovered datapack (or null if it failed)
|
||||||
|
* @throws IOException if any IO error occurs
|
||||||
|
*/
|
||||||
|
@Nullable DiscoveredDatapack discoverPack(@NonNull PluginMeta pluginMeta, @NonNull Path path, @NonNull String id, @NonNull Consumer<Configurer> configurer) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures additional, optional, details about a datapack.
|
||||||
|
*/
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
interface Configurer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the title of the datapack from the default which
|
||||||
|
* is just the "id" in the {@code registerPack} methods.
|
||||||
|
*
|
||||||
|
* @param title the new title
|
||||||
|
* @return the configurer for chaining
|
||||||
|
*/
|
||||||
|
@Contract(value = "_ -> this", mutates = "this")
|
||||||
|
@NonNull Configurer title(@NonNull Component title);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if this pack is required. Defaults to false.
|
||||||
|
* A required pack cannot be disabled once enabled. Marking
|
||||||
|
* a pack as required <b>does not</b> mean it will immediately be enabled
|
||||||
|
* upon discovery. It may be enabled if this event was fired
|
||||||
|
* due to a pending (re)load.
|
||||||
|
*
|
||||||
|
* @param required true to require the pack
|
||||||
|
* @return the configurer for chaining
|
||||||
|
*/
|
||||||
|
@Contract(value = "_ -> this", mutates = "this")
|
||||||
|
@NonNull Configurer required(boolean required);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the position in the
|
||||||
|
* load order of this datapack.
|
||||||
|
*
|
||||||
|
* @param fixed won't move around in the load order as packs are added/removed
|
||||||
|
* @param position try to insert at the top of the order or bottom
|
||||||
|
* @return the configurer for chaining
|
||||||
|
*/
|
||||||
|
@Contract(value = "_, _ -> this", mutates = "this")
|
||||||
|
@NonNull Configurer position(boolean fixed, Datapack.@NonNull Position position);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package io.papermc.paper.datapack;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.FeatureFlag;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a snapshot of a discovered datapack on the server. It
|
||||||
|
* won't be updated as datapacks are updated.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
|
public interface DiscoveredDatapack {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name/id of this datapack.
|
||||||
|
*
|
||||||
|
* @return the name of the pack
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the title component of this datapack.
|
||||||
|
*
|
||||||
|
* @return the title
|
||||||
|
*/
|
||||||
|
Component getTitle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description component of this datapack.
|
||||||
|
*
|
||||||
|
* @return the description
|
||||||
|
*/
|
||||||
|
Component getDescription();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if this datapack is required to be enabled.
|
||||||
|
*
|
||||||
|
* @return true if the pack is required
|
||||||
|
*/
|
||||||
|
boolean isRequired();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the compatibility status of this pack.
|
||||||
|
*
|
||||||
|
* @return the compatibility of the pack
|
||||||
|
*/
|
||||||
|
Datapack.Compatibility getCompatibility();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the set of required features for this datapack.
|
||||||
|
*
|
||||||
|
* @return the set of required features
|
||||||
|
*/
|
||||||
|
@Unmodifiable
|
||||||
|
Set<FeatureFlag> getRequiredFeatures();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the source for this datapack.
|
||||||
|
*
|
||||||
|
* @return the pack source
|
||||||
|
*/
|
||||||
|
DatapackSource getSource();
|
||||||
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
package io.papermc.paper.plugin.lifecycle.event.types;
|
package io.papermc.paper.plugin.lifecycle.event.types;
|
||||||
|
|
||||||
import io.papermc.paper.command.brigadier.Commands;
|
import io.papermc.paper.command.brigadier.Commands;
|
||||||
|
import io.papermc.paper.datapack.DatapackRegistrar;
|
||||||
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
||||||
import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
||||||
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
|
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
|
||||||
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
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 io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
@ -32,6 +34,14 @@ public final class LifecycleEvents {
|
||||||
*/
|
*/
|
||||||
public static final TagEventTypeProvider TAGS = LifecycleEventTypeProvider.provider().tagProvider();
|
public static final TagEventTypeProvider TAGS = LifecycleEventTypeProvider.provider().tagProvider();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event is for informing the server about any available datapacks from other sources such as inside a plugin's jar. You
|
||||||
|
* can register a handler for this event only in {@link io.papermc.paper.plugin.bootstrap.PluginBootstrap#bootstrap(BootstrapContext)}.
|
||||||
|
* @see DatapackRegistrar an example of a datapack being discovered
|
||||||
|
*/
|
||||||
|
public static final LifecycleEventType.Prioritizable<BootstrapContext, RegistrarEvent<DatapackRegistrar>> DATAPACK_DISCOVERY = bootstrapPrioritized("datapack_discovery");
|
||||||
|
|
||||||
//<editor-fold desc="helper methods" defaultstate="collapsed">
|
//<editor-fold desc="helper methods" defaultstate="collapsed">
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
static <E extends LifecycleEvent> LifecycleEventType.Monitorable<Plugin, E> plugin(final String name) {
|
static <E extends LifecycleEvent> LifecycleEventType.Monitorable<Plugin, E> plugin(final String name) {
|
||||||
|
|
|
@ -1232,6 +1232,15 @@
|
||||||
},
|
},
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
|
@@ -1550,7 +_,7 @@
|
||||||
|
DataPackConfig dataPackConfig = initialDataConfig.dataPacks();
|
||||||
|
FeatureFlagSet featureFlagSet = initMode ? FeatureFlagSet.of() : initialDataConfig.enabledFeatures();
|
||||||
|
FeatureFlagSet featureFlagSet1 = initMode ? FeatureFlags.REGISTRY.allFlags() : initialDataConfig.enabledFeatures();
|
||||||
|
- packRepository.reload();
|
||||||
|
+ packRepository.reload(true); // Paper - will load resource packs
|
||||||
|
if (safeMode) {
|
||||||
|
return configureRepositoryWithSelection(packRepository, List.of("vanilla"), featureFlagSet, false);
|
||||||
|
} else {
|
||||||
@@ -1652,10 +_,11 @@
|
@@ -1652,10 +_,11 @@
|
||||||
if (this.isEnforceWhitelist()) {
|
if (this.isEnforceWhitelist()) {
|
||||||
PlayerList playerList = commandSource.getServer().getPlayerList();
|
PlayerList playerList = commandSource.getServer().getPlayerList();
|
||||||
|
|
|
@ -9,6 +9,15 @@
|
||||||
LOGGER.warn("Failed to execute reload", throwable);
|
LOGGER.warn("Failed to execute reload", throwable);
|
||||||
source.sendFailure(Component.translatable("commands.reload.failure"));
|
source.sendFailure(Component.translatable("commands.reload.failure"));
|
||||||
return null;
|
return null;
|
||||||
|
@@ -24,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Collection<String> discoverNewPacks(PackRepository packRepository, WorldData worldData, Collection<String> selectedIds) {
|
||||||
|
- packRepository.reload();
|
||||||
|
+ packRepository.reload(true); // Paper - will perform a full reload
|
||||||
|
Collection<String> list = Lists.newArrayList(selectedIds);
|
||||||
|
Collection<String> disabled = worldData.getDataConfiguration().dataPacks().getDisabled();
|
||||||
|
|
||||||
@@ -36,6 +_,16 @@
|
@@ -36,6 +_,16 @@
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
--- a/net/minecraft/server/packs/repository/PackRepository.java
|
||||||
|
+++ b/net/minecraft/server/packs/repository/PackRepository.java
|
||||||
|
@@ -21,9 +_,13 @@
|
||||||
|
private final Set<RepositorySource> sources;
|
||||||
|
private Map<String, Pack> available = ImmutableMap.of();
|
||||||
|
private List<Pack> selected = ImmutableList.of();
|
||||||
|
+ private final net.minecraft.world.level.validation.DirectoryValidator validator; // Paper - add validator
|
||||||
|
|
||||||
|
- public PackRepository(RepositorySource... sources) {
|
||||||
|
- this.sources = ImmutableSet.copyOf(sources);
|
||||||
|
+ // Paper start - add validator
|
||||||
|
+ public PackRepository(net.minecraft.world.level.validation.DirectoryValidator validator, RepositorySource... providers) {
|
||||||
|
+ this.validator = validator;
|
||||||
|
+ // Paper end - add validator
|
||||||
|
+ this.sources = ImmutableSet.copyOf(providers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String displayPackList(Collection<Pack> packs) {
|
||||||
|
@@ -31,9 +_,14 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reload() {
|
||||||
|
+ // Paper start - perform a full reload
|
||||||
|
+ this.reload(false);
|
||||||
|
+ }
|
||||||
|
+ public void reload(boolean addRequiredPacks) {
|
||||||
|
+ // Paper end
|
||||||
|
List<String> list = this.selected.stream().map(Pack::getId).collect(ImmutableList.toImmutableList());
|
||||||
|
this.available = this.discoverAvailable();
|
||||||
|
- this.selected = this.rebuildSelected(list);
|
||||||
|
+ this.selected = this.rebuildSelected(list, addRequiredPacks); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Pack> discoverAvailable() {
|
||||||
|
@@ -43,16 +_,23 @@
|
||||||
|
repositorySource.loadPacks(pack -> map.put(pack.getId(), pack));
|
||||||
|
}
|
||||||
|
|
||||||
|
- return ImmutableMap.copyOf(map);
|
||||||
|
+ // Paper start - custom plugin-loaded datapacks
|
||||||
|
+ final io.papermc.paper.datapack.PaperDatapackRegistrar registrar = new io.papermc.paper.datapack.PaperDatapackRegistrar(this.validator, map);
|
||||||
|
+ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callStaticRegistrarEvent(io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.DATAPACK_DISCOVERY,
|
||||||
|
+ registrar,
|
||||||
|
+ io.papermc.paper.plugin.bootstrap.BootstrapContext.class
|
||||||
|
+ );
|
||||||
|
+ return ImmutableMap.copyOf(registrar.discoveredPacks);
|
||||||
|
+ // Paper end - custom plugin-loaded datapacks
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAbleToClearAnyPack() {
|
||||||
|
- List<Pack> list = this.rebuildSelected(List.of());
|
||||||
|
+ List<Pack> list = this.rebuildSelected(List.of(), false); // Paper - add willReload boolean
|
||||||
|
return !this.selected.equals(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelected(Collection<String> ids) {
|
||||||
|
- this.selected = this.rebuildSelected(ids);
|
||||||
|
+ this.selected = this.rebuildSelected(ids, false); // Paper - add willReload boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addPack(String id) {
|
||||||
|
@@ -79,11 +_,11 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- private List<Pack> rebuildSelected(Collection<String> ids) {
|
||||||
|
+ private List<Pack> rebuildSelected(Collection<String> ids, boolean addRequiredPacks) { // Paper - add addRequiredPacks boolean
|
||||||
|
List<Pack> list = this.getAvailablePacks(ids).collect(Util.toMutableList());
|
||||||
|
|
||||||
|
for (Pack pack : this.available.values()) {
|
||||||
|
- if (pack.isRequired() && !list.contains(pack)) {
|
||||||
|
+ if (pack.isRequired() && !list.contains(pack) && addRequiredPacks) { // Paper - add addRequiredPacks boolean
|
||||||
|
pack.getDefaultPosition().insert(list, pack, Pack::selectionConfig, false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@
|
||||||
.applyDevelopmentConfig()
|
.applyDevelopmentConfig()
|
||||||
.pushJarResources()
|
.pushJarResources()
|
||||||
.build(VANILLA_PACK_INFO);
|
.build(VANILLA_PACK_INFO);
|
||||||
@@ -68,7 +_,18 @@
|
@@ -68,15 +_,26 @@
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
protected Pack createBuiltinPack(String id, Pack.ResourcesSupplier resources, Component title) {
|
protected Pack createBuiltinPack(String id, Pack.ResourcesSupplier resources, Component title) {
|
||||||
|
@ -29,3 +29,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PackRepository createPackRepository(Path folder, DirectoryValidator validator) {
|
public static PackRepository createPackRepository(Path folder, DirectoryValidator validator) {
|
||||||
|
- return new PackRepository(new ServerPacksSource(validator), new FolderRepositorySource(folder, PackType.SERVER_DATA, PackSource.WORLD, validator));
|
||||||
|
+ return new PackRepository(validator, new ServerPacksSource(validator), new FolderRepositorySource(folder, PackType.SERVER_DATA, PackSource.WORLD, validator)); // Paper - add validator
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PackRepository createVanillaTrustedRepository() {
|
||||||
|
- return new PackRepository(new ServerPacksSource(new DirectoryValidator(path -> true)));
|
||||||
|
+ return new PackRepository(new DirectoryValidator(path -> true), new ServerPacksSource(new DirectoryValidator(path -> true))); // Paper - add validator
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PackRepository createPackRepository(LevelStorageSource.LevelStorageAccess level) {
|
||||||
|
|
|
@ -2,71 +2,25 @@ package io.papermc.paper.datapack;
|
||||||
|
|
||||||
import io.papermc.paper.adventure.PaperAdventure;
|
import io.papermc.paper.adventure.PaperAdventure;
|
||||||
import io.papermc.paper.event.server.ServerResourcesReloadedEvent;
|
import io.papermc.paper.event.server.ServerResourcesReloadedEvent;
|
||||||
import io.papermc.paper.world.flag.PaperFeatureFlagProviderImpl;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.packs.repository.Pack;
|
import net.minecraft.server.packs.repository.Pack;
|
||||||
import net.minecraft.server.packs.repository.PackSource;
|
import org.jspecify.annotations.NullMarked;
|
||||||
import org.bukkit.FeatureFlag;
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
|
||||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
|
||||||
|
|
||||||
@DefaultQualifier(NonNull.class)
|
@NullMarked
|
||||||
public class PaperDatapack implements Datapack {
|
public class PaperDatapack extends PaperDiscoveredDatapack implements Datapack {
|
||||||
|
|
||||||
private static final Map<PackSource, DatapackSource> PACK_SOURCES = new ConcurrentHashMap<>();
|
|
||||||
static {
|
|
||||||
PACK_SOURCES.put(PackSource.DEFAULT, DatapackSource.DEFAULT);
|
|
||||||
PACK_SOURCES.put(PackSource.BUILT_IN, DatapackSource.BUILT_IN);
|
|
||||||
PACK_SOURCES.put(PackSource.FEATURE, DatapackSource.FEATURE);
|
|
||||||
PACK_SOURCES.put(PackSource.WORLD, DatapackSource.WORLD);
|
|
||||||
PACK_SOURCES.put(PackSource.SERVER, DatapackSource.SERVER);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Pack pack;
|
private final Pack pack;
|
||||||
private final boolean enabled;
|
private final boolean enabled;
|
||||||
|
|
||||||
PaperDatapack(final Pack pack, final boolean enabled) {
|
PaperDatapack(final Pack pack, final boolean enabled) {
|
||||||
|
super(pack);
|
||||||
this.pack = pack;
|
this.pack = pack;
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return this.pack.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getTitle() {
|
|
||||||
return PaperAdventure.asAdventure(this.pack.getTitle());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getDescription() {
|
|
||||||
return PaperAdventure.asAdventure(this.pack.getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRequired() {
|
|
||||||
return this.pack.isRequired();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Compatibility getCompatibility() {
|
|
||||||
return Datapack.Compatibility.valueOf(this.pack.getCompatibility().name());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<FeatureFlag> getRequiredFeatures() {
|
|
||||||
return PaperFeatureFlagProviderImpl.fromNms(this.pack.getRequestedFeatures());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
return this.enabled;
|
return this.enabled;
|
||||||
|
@ -76,7 +30,7 @@ public class PaperDatapack implements Datapack {
|
||||||
public void setEnabled(final boolean enabled) {
|
public void setEnabled(final boolean enabled) {
|
||||||
final MinecraftServer server = MinecraftServer.getServer();
|
final MinecraftServer server = MinecraftServer.getServer();
|
||||||
final List<Pack> enabledPacks = new ArrayList<>(server.getPackRepository().getSelectedPacks());
|
final List<Pack> enabledPacks = new ArrayList<>(server.getPackRepository().getSelectedPacks());
|
||||||
final @Nullable Pack packToChange = server.getPackRepository().getPack(this.getName());
|
final Pack packToChange = server.getPackRepository().getPack(this.getName());
|
||||||
if (packToChange == null) {
|
if (packToChange == null) {
|
||||||
throw new IllegalStateException("Cannot toggle state of pack that doesn't exist: " + this.getName());
|
throw new IllegalStateException("Cannot toggle state of pack that doesn't exist: " + this.getName());
|
||||||
}
|
}
|
||||||
|
@ -91,11 +45,6 @@ public class PaperDatapack implements Datapack {
|
||||||
server.reloadResources(enabledPacks.stream().map(Pack::getId).toList(), ServerResourcesReloadedEvent.Cause.PLUGIN);
|
server.reloadResources(enabledPacks.stream().map(Pack::getId).toList(), ServerResourcesReloadedEvent.Cause.PLUGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DatapackSource getSource() {
|
|
||||||
return PACK_SOURCES.computeIfAbsent(this.pack.location().source(), source -> new DatapackSourceImpl(source.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component computeDisplayName() {
|
public Component computeDisplayName() {
|
||||||
return PaperAdventure.asAdventure(this.pack.getChatLink(this.enabled));
|
return PaperAdventure.asAdventure(this.pack.getChatLink(this.enabled));
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
package io.papermc.paper.datapack;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.mojang.logging.LogUtils;
|
||||||
|
import io.papermc.paper.adventure.PaperAdventure;
|
||||||
|
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
||||||
|
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||||
|
import io.papermc.paper.plugin.lifecycle.event.registrar.PaperRegistrar;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
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.world.level.validation.ContentValidationException;
|
||||||
|
import net.minecraft.world.level.validation.DirectoryValidator;
|
||||||
|
import net.minecraft.world.level.validation.ForbiddenSymlinkInfo;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
@NullMarked
|
||||||
|
public class PaperDatapackRegistrar implements PaperRegistrar<BootstrapContext>, DatapackRegistrar {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||||
|
|
||||||
|
private final PackDetector<Pack.ResourcesSupplier> detector;
|
||||||
|
public final Map<String, Pack> discoveredPacks;
|
||||||
|
private @Nullable BootstrapContext owner;
|
||||||
|
|
||||||
|
public PaperDatapackRegistrar(final DirectoryValidator symlinkValidator, final Map<String, Pack> discoveredPacks) {
|
||||||
|
this.detector = new FolderRepositorySource.FolderPackDetector(symlinkValidator);
|
||||||
|
this.discoveredPacks = discoveredPacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentContext(final @Nullable BootstrapContext owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPackDiscovered(final String name) {
|
||||||
|
return this.discoveredPacks.containsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DiscoveredDatapack getDiscoveredPack(final String name) {
|
||||||
|
if (!this.hasPackDiscovered(name)) {
|
||||||
|
throw new NoSuchElementException("No pack with id " + name + " was discovered");
|
||||||
|
}
|
||||||
|
return new PaperDiscoveredDatapack(this.discoveredPacks.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeDiscoveredPack(final String name) {
|
||||||
|
return this.discoveredPacks.remove(name) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Unmodifiable Map<String, DiscoveredDatapack> getDiscoveredPacks() {
|
||||||
|
final ImmutableMap.Builder<String, DiscoveredDatapack> builder = ImmutableMap.builderWithExpectedSize(this.discoveredPacks.size());
|
||||||
|
for (final Map.Entry<String, Pack> entry : this.discoveredPacks.entrySet()) {
|
||||||
|
builder.put(entry.getKey(), new PaperDiscoveredDatapack(entry.getValue()));
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable DiscoveredDatapack discoverPack(final URI uri, final String id, final Consumer<Configurer> configurer) throws IOException {
|
||||||
|
Preconditions.checkState(this.owner != null, "Cannot register a datapack without specifying a PluginMeta yet");
|
||||||
|
return this.discoverPack(this.owner.getPluginMeta(), uri, id, configurer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable DiscoveredDatapack discoverPack(final Path path, final String id, final Consumer<Configurer> configurer) throws IOException {
|
||||||
|
Preconditions.checkState(this.owner != null, "Cannot register a datapack without specifying a PluginMeta yet");
|
||||||
|
return this.discoverPack(this.owner.getPluginMeta(), path, id, configurer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable DiscoveredDatapack discoverPack(final PluginMeta pluginMeta, final URI uri, final String id, final Consumer<Configurer> configurer) throws IOException {
|
||||||
|
return this.discoverPack(pluginMeta, VanillaPackResourcesBuilder.safeGetPath(uri), id, configurer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable DiscoveredDatapack discoverPack(final PluginMeta pluginMeta, final Path path, final String id, final Consumer<Configurer> configurer) throws IOException {
|
||||||
|
final List<ForbiddenSymlinkInfo> badLinks = new ArrayList<>();
|
||||||
|
final Pack.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 = pluginMeta.getName() + "/" + id;
|
||||||
|
final ConfigurerImpl configurerImpl = new ConfigurerImpl(Component.text(packId));
|
||||||
|
configurer.accept(configurerImpl);
|
||||||
|
final PackLocationInfo locInfo = new PackLocationInfo(packId,
|
||||||
|
PaperAdventure.asVanilla(configurerImpl.title),
|
||||||
|
PluginPackSource.INSTANCE,
|
||||||
|
Optional.empty()
|
||||||
|
);
|
||||||
|
final Pack pack = Pack.readMetaAndCreate(locInfo,
|
||||||
|
resourcesSupplier,
|
||||||
|
PackType.SERVER_DATA,
|
||||||
|
new PackSelectionConfig(
|
||||||
|
configurerImpl.required,
|
||||||
|
configurerImpl.position,
|
||||||
|
configurerImpl.fixedPosition
|
||||||
|
));
|
||||||
|
if (pack != null) {
|
||||||
|
this.discoveredPacks.put(packId, pack);
|
||||||
|
return new PaperDiscoveredDatapack(pack);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
LOGGER.info("Found non-pack entry '{}', ignoring", path);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class ConfigurerImpl implements Configurer {
|
||||||
|
|
||||||
|
private Component title;
|
||||||
|
private boolean required = false;
|
||||||
|
private boolean fixedPosition = false;
|
||||||
|
private Pack.Position position = Pack.Position.TOP;
|
||||||
|
|
||||||
|
ConfigurerImpl(final Component title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Configurer title(final Component title) {
|
||||||
|
this.title = title;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Configurer required(final boolean required) {
|
||||||
|
this.required = required;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Configurer position(final boolean fixed, final Datapack.Position position) {
|
||||||
|
this.fixedPosition = fixed;
|
||||||
|
this.position = switch (position) {
|
||||||
|
case TOP -> Pack.Position.TOP;
|
||||||
|
case BOTTOM -> Pack.Position.BOTTOM;
|
||||||
|
};
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package io.papermc.paper.datapack;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import io.papermc.paper.adventure.PaperAdventure;
|
||||||
|
import io.papermc.paper.world.flag.PaperFeatureFlagProviderImpl;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.minecraft.server.packs.repository.Pack;
|
||||||
|
import net.minecraft.server.packs.repository.PackSource;
|
||||||
|
import org.bukkit.FeatureFlag;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
|
||||||
|
@NullMarked
|
||||||
|
public class PaperDiscoveredDatapack implements DiscoveredDatapack {
|
||||||
|
|
||||||
|
private static final Map<PackSource, DatapackSource> PACK_SOURCES;
|
||||||
|
static {
|
||||||
|
PACK_SOURCES = ImmutableMap.<PackSource, DatapackSource>builder()
|
||||||
|
.put(PackSource.DEFAULT, DatapackSource.DEFAULT)
|
||||||
|
.put(PackSource.BUILT_IN, DatapackSource.BUILT_IN)
|
||||||
|
.put(PackSource.FEATURE, DatapackSource.FEATURE)
|
||||||
|
.put(PackSource.WORLD, DatapackSource.WORLD)
|
||||||
|
.put(PackSource.SERVER, DatapackSource.SERVER)
|
||||||
|
.buildOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Pack pack;
|
||||||
|
|
||||||
|
PaperDiscoveredDatapack(final Pack pack) {
|
||||||
|
this.pack = pack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return this.pack.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getTitle() {
|
||||||
|
return PaperAdventure.asAdventure(this.pack.getTitle());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getDescription() {
|
||||||
|
return PaperAdventure.asAdventure(this.pack.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRequired() {
|
||||||
|
return this.pack.isRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Datapack.Compatibility getCompatibility() {
|
||||||
|
return Datapack.Compatibility.valueOf(this.pack.getCompatibility().name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<FeatureFlag> getRequiredFeatures() {
|
||||||
|
return PaperFeatureFlagProviderImpl.fromNms(this.pack.getRequestedFeatures());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatapackSource getSource() {
|
||||||
|
return PACK_SOURCES.computeIfAbsent(this.pack.location().source(), source -> new DatapackSourceImpl(source.toString()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package io.papermc.paper.datapack;
|
||||||
|
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.packs.repository.PackSource;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
|
||||||
|
@NullMarked
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,14 @@
|
||||||
package io.papermc.testplugin;
|
package io.papermc.testplugin;
|
||||||
|
|
||||||
|
import io.papermc.paper.datapack.DatapackRegistrar;
|
||||||
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
||||||
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
|
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 org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class TestPluginBootstrap implements PluginBootstrap {
|
public class TestPluginBootstrap implements PluginBootstrap {
|
||||||
|
@ -9,6 +16,16 @@ public class TestPluginBootstrap implements PluginBootstrap {
|
||||||
@Override
|
@Override
|
||||||
public void bootstrap(@NotNull BootstrapContext context) {
|
public void bootstrap(@NotNull BootstrapContext context) {
|
||||||
// io.papermc.testplugin.brigtests.Registration.registerViaBootstrap(context);
|
// io.papermc.testplugin.brigtests.Registration.registerViaBootstrap(context);
|
||||||
|
final LifecycleEventManager<BootstrapContext> manager = context.getLifecycleManager();
|
||||||
|
manager.registerEventHandler(LifecycleEvents.DATAPACK_DISCOVERY, event -> {
|
||||||
|
final DatapackRegistrar registrar = event.registrar();
|
||||||
|
try {
|
||||||
|
final URI uri = Objects.requireNonNull(TestPluginBootstrap.class.getResource("/pack")).toURI();
|
||||||
|
registrar.discoverPack(uri, "test");
|
||||||
|
} catch (final URISyntaxException | IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"values": [
|
||||||
|
"minecraft:zombie",
|
||||||
|
"minecraft:spider"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"values": [
|
||||||
|
"minecraft:stone_bricks",
|
||||||
|
"minecraft:string"
|
||||||
|
]
|
||||||
|
}
|
6
test-plugin/src/main/resources/pack/tags/pack.mcmeta
Normal file
6
test-plugin/src/main/resources/pack/tags/pack.mcmeta
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"pack":{
|
||||||
|
"pack_format": 41,
|
||||||
|
"description": "Test datapack for tags"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue