From a345ec2e354df9a55e0fbb0df3727477fc20e6ef Mon Sep 17 00:00:00 2001 From: CraftBukkit/Spigot Date: Tue, 30 May 2023 19:05:48 +1000 Subject: [PATCH] SPIGOT-7195, SPIGOT-7197: Add DataPack API By: Doc --- .../packs/repository/ResourcePackLoader.patch | 29 +++++ .../minecraft/world/flag/FeatureFlag.patch | 11 ++ .../world/flag/FeatureFlagRegistry.patch | 11 ++ .../bukkit/craftbukkit/CraftFeatureFlag.java | 51 +++++++++ .../org/bukkit/craftbukkit/CraftServer.java | 20 ++++ .../org/bukkit/craftbukkit/CraftWorld.java | 7 ++ .../craftbukkit/packs/CraftDataPack.java | 95 ++++++++++++++++ .../packs/CraftDataPackManager.java | 102 ++++++++++++++++++ .../craftbukkit/util/CraftMagicNumbers.java | 8 ++ 9 files changed, 334 insertions(+) create mode 100644 paper-server/nms-patches/net/minecraft/server/packs/repository/ResourcePackLoader.patch create mode 100644 paper-server/nms-patches/net/minecraft/world/flag/FeatureFlag.patch create mode 100644 paper-server/nms-patches/net/minecraft/world/flag/FeatureFlagRegistry.patch create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/CraftFeatureFlag.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/packs/CraftDataPack.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/packs/CraftDataPackManager.java diff --git a/paper-server/nms-patches/net/minecraft/server/packs/repository/ResourcePackLoader.patch b/paper-server/nms-patches/net/minecraft/server/packs/repository/ResourcePackLoader.patch new file mode 100644 index 0000000000..fc4a06aa80 --- /dev/null +++ b/paper-server/nms-patches/net/minecraft/server/packs/repository/ResourcePackLoader.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/server/packs/repository/ResourcePackLoader.java ++++ b/net/minecraft/server/packs/repository/ResourcePackLoader.java +@@ -20,7 +20,7 @@ + + private static final Logger LOGGER = LogUtils.getLogger(); + private final String id; +- private final ResourcePackLoader.c resources; ++ public final ResourcePackLoader.c resources; // PAIL private -> public + private final IChatBaseComponent title; + private final IChatBaseComponent description; + private final EnumResourcePackVersion compatibility; +@@ -59,7 +59,7 @@ + try { + IResourcePack iresourcepack = resourcepackloader_c.open(s); + +- ResourcePackLoader.a resourcepackloader_a; ++ ResourcePackLoader.a resourcepackloader_a = null; // CraftBukkit - decompile fix + label53: + { + FeatureFlagsMetadataSection featureflagsmetadatasection; +@@ -93,7 +93,7 @@ + iresourcepack.close(); + } + +- return featureflagsmetadatasection; ++ return resourcepackloader_a; // CraftBukkit - decompile fix + } + + if (iresourcepack != null) { diff --git a/paper-server/nms-patches/net/minecraft/world/flag/FeatureFlag.patch b/paper-server/nms-patches/net/minecraft/world/flag/FeatureFlag.patch new file mode 100644 index 0000000000..afcc4f6a6a --- /dev/null +++ b/paper-server/nms-patches/net/minecraft/world/flag/FeatureFlag.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/flag/FeatureFlag.java ++++ b/net/minecraft/world/flag/FeatureFlag.java +@@ -2,7 +2,7 @@ + + public class FeatureFlag { + +- final FeatureFlagUniverse universe; ++ public final FeatureFlagUniverse universe; // PAIL public + final long mask; + + FeatureFlag(FeatureFlagUniverse featureflaguniverse, int i) { diff --git a/paper-server/nms-patches/net/minecraft/world/flag/FeatureFlagRegistry.patch b/paper-server/nms-patches/net/minecraft/world/flag/FeatureFlagRegistry.patch new file mode 100644 index 0000000000..2e179d81fb --- /dev/null +++ b/paper-server/nms-patches/net/minecraft/world/flag/FeatureFlagRegistry.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/flag/FeatureFlagRegistry.java ++++ b/net/minecraft/world/flag/FeatureFlagRegistry.java +@@ -20,7 +20,7 @@ + + private static final Logger LOGGER = LogUtils.getLogger(); + private final FeatureFlagUniverse universe; +- private final Map names; ++ public final Map names; // PAIL public + private final FeatureFlagSet allFlags; + + FeatureFlagRegistry(FeatureFlagUniverse featureflaguniverse, FeatureFlagSet featureflagset, Map map) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftFeatureFlag.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftFeatureFlag.java new file mode 100644 index 0000000000..f14219aed9 --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftFeatureFlag.java @@ -0,0 +1,51 @@ +package org.bukkit.craftbukkit; + +import java.util.HashSet; +import java.util.Set; +import net.minecraft.resources.MinecraftKey; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.flag.FeatureFlags; +import org.bukkit.FeatureFlag; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.jetbrains.annotations.NotNull; + +public class CraftFeatureFlag implements FeatureFlag { + + private final NamespacedKey namespacedKey; + private final net.minecraft.world.flag.FeatureFlag featureFlag; + + public CraftFeatureFlag(MinecraftKey minecraftKey, net.minecraft.world.flag.FeatureFlag featureFlag) { + this.namespacedKey = CraftNamespacedKey.fromMinecraft(minecraftKey); + this.featureFlag = featureFlag; + } + + public net.minecraft.world.flag.FeatureFlag getHandle() { + return this.featureFlag; + } + + @NotNull + @Override + public NamespacedKey getKey() { + return this.namespacedKey; + } + + @Override + public String toString() { + return "CraftDataPack{key=" + this.getKey() + ",keyUniverse=" + this.getHandle().universe.toString() + "}"; + } + + public static Set getFromNMS(FeatureFlagSet featureFlagSet) { + Set set = new HashSet<>(); + FeatureFlags.REGISTRY.names.forEach((minecraftkey, featureflag) -> { + if (featureFlagSet.contains(featureflag)) { + set.add(new CraftFeatureFlag(minecraftkey, featureflag)); + } + }); + return set; + } + + public static CraftFeatureFlag getFromNMS(NamespacedKey namespacedKey) { + return FeatureFlags.REGISTRY.names.entrySet().stream().filter(entry -> CraftNamespacedKey.fromMinecraft(entry.getKey()).equals(namespacedKey)).findFirst().map(entry -> new CraftFeatureFlag(entry.getKey(), entry.getValue())).orElse(null); + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 09418b6e25..a211da846f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -33,6 +33,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -180,6 +181,7 @@ import org.bukkit.craftbukkit.map.CraftMapView; import org.bukkit.craftbukkit.metadata.EntityMetadataStore; import org.bukkit.craftbukkit.metadata.PlayerMetadataStore; import org.bukkit.craftbukkit.metadata.WorldMetadataStore; +import org.bukkit.craftbukkit.packs.CraftDataPackManager; import org.bukkit.craftbukkit.potion.CraftPotionBrewer; import org.bukkit.craftbukkit.profile.CraftPlayerProfile; import org.bukkit.craftbukkit.scheduler.CraftScheduler; @@ -233,6 +235,7 @@ import org.bukkit.inventory.StonecuttingRecipe; import org.bukkit.loot.LootTable; import org.bukkit.map.MapPalette; import org.bukkit.map.MapView; +import org.bukkit.packs.DataPackManager; import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permission; import org.bukkit.plugin.Plugin; @@ -285,6 +288,7 @@ public final class CraftServer implements Server { private WarningState warningState = WarningState.DEFAULT; public String minimumAPI; public CraftScoreboardManager scoreboardManager; + public CraftDataPackManager dataPackManager; public boolean playerCommandState; private boolean printSaveWarning; private CraftIconCache icon; @@ -310,6 +314,7 @@ public final class CraftServer implements Server { })); this.serverVersion = CraftServer.class.getPackage().getImplementationVersion(); this.structureManager = new CraftStructureManager(console.getStructureManager()); + this.dataPackManager = new CraftDataPackManager(this.getServer().getPackRepository()); Bukkit.setServer(this); @@ -681,6 +686,21 @@ public final class CraftServer implements Server { return this.configuration.getBoolean("settings.query-plugins"); } + @Override + public List getInitialEnabledPacks() { + return Collections.unmodifiableList(this.getProperties().initialDataPackConfiguration.getEnabled()); + } + + @Override + public List getInitialDisabledPacks() { + return Collections.unmodifiableList(this.getProperties().initialDataPackConfiguration.getDisabled()); + } + + @Override + public DataPackManager getDataPackManager() { + return this.dataPackManager; + } + @Override public String getResourcePack() { return this.getServer().getServerResourcePack().map(MinecraftServer.ServerResourcePackInfo::url).orElse(""); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index aba7b9e850..16360a0392 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -55,6 +55,7 @@ import net.minecraft.world.entity.player.EntityHuman; import net.minecraft.world.entity.projectile.EntityArrow; import net.minecraft.world.entity.projectile.EntityTippedArrow; import net.minecraft.world.entity.raid.PersistentRaid; +import net.minecraft.world.flag.FeatureFlags; import net.minecraft.world.level.ChunkCoordIntPair; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.RayTrace; @@ -73,6 +74,7 @@ import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Difficulty; import org.bukkit.Effect; +import org.bukkit.FeatureFlag; import org.bukkit.FluidCollisionMode; import org.bukkit.GameRule; import org.bukkit.Location; @@ -1900,6 +1902,11 @@ public class CraftWorld extends CraftRegionAccessor implements World { return persistentDataContainer; } + @Override + public Set getFeatureFlags() { + return CraftFeatureFlag.getFromNMS(this.getHandle().enabledFeatures()).stream().map(FeatureFlag.class::cast).collect(Collectors.toUnmodifiableSet()); + } + public void storeBukkitValues(NBTTagCompound c) { if (!this.persistentDataContainer.isEmpty()) { c.put("BukkitValues", this.persistentDataContainer.toTagCompound()); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/packs/CraftDataPack.java b/paper-server/src/main/java/org/bukkit/craftbukkit/packs/CraftDataPack.java new file mode 100644 index 0000000000..8f22b453a6 --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/packs/CraftDataPack.java @@ -0,0 +1,95 @@ +package org.bukkit.craftbukkit.packs; + +import java.util.Set; +import java.util.stream.Collectors; +import net.minecraft.server.packs.repository.PackSource; +import net.minecraft.server.packs.repository.ResourcePackLoader; +import org.bukkit.Bukkit; +import org.bukkit.FeatureFlag; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.CraftFeatureFlag; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.packs.DataPack; + +public class CraftDataPack implements DataPack { + + private final ResourcePackLoader handle; + + public CraftDataPack(ResourcePackLoader handler) { + this.handle = handler; + } + + public ResourcePackLoader getHandle() { + return this.handle; + } + + public String getRawId() { + return getHandle().getId(); + } + + @Override + public String getTitle() { + return CraftChatMessage.fromComponent(this.getHandle().getTitle()); + } + + @Override + public String getDescription() { + return CraftChatMessage.fromComponent(this.getHandle().getDescription()); + } + + @Override + public int getPackFormat() { + ResourcePackLoader.a info = ResourcePackLoader.readPackInfo(this.getRawId(), this.getHandle().resources); + return (info == null) ? 0 : info.format(); + } + + @Override + public boolean isRequired() { + return getHandle().isRequired(); + } + + @Override + public Compatibility getCompatibility() { + return switch (this.getHandle().getCompatibility()) { + case COMPATIBLE -> Compatibility.COMPATIBLE; + case TOO_NEW -> Compatibility.NEW; + case TOO_OLD -> Compatibility.OLD; + }; + } + + @Override + public boolean isEnabled() { + return ((CraftServer) Bukkit.getServer()).getServer().getPackRepository().getSelectedIds().contains(getRawId()); + } + + @Override + public DataPack.Source getSource() { + if (this.getHandle().getPackSource() == PackSource.BUILT_IN) { + return Source.BUILT_IN; + } else if (this.getHandle().getPackSource() == PackSource.FEATURE) { + return Source.FEATURE; + } else if (this.getHandle().getPackSource() == PackSource.WORLD) { + return Source.WORLD; + } else if (this.getHandle().getPackSource() == PackSource.SERVER) { + return Source.SERVER; + } + return Source.DEFAULT; + } + + @Override + public Set getRequestedFeatures() { + return CraftFeatureFlag.getFromNMS(this.getHandle().getRequestedFeatures()).stream().map(FeatureFlag.class::cast).collect(Collectors.toUnmodifiableSet()); + } + + @Override + public NamespacedKey getKey() { + return NamespacedKey.fromString(getRawId()); + } + + @Override + public String toString() { + String requestedFeatures = getRequestedFeatures().stream().map(featureFlag -> featureFlag.getKey().toString()).collect(Collectors.joining(",")); + return "CraftDataPack{rawId=" + this.getRawId() + ",id=" + this.getKey() + ",title=" + this.getTitle() + ",description=" + this.getDescription() + ",packformat=" + this.getPackFormat() + ",compatibility=" + this.getCompatibility() + ",source=" + this.getSource() + ",enabled=" + this.isEnabled() + ",requestedFeatures=[" + requestedFeatures + "]}"; + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/packs/CraftDataPackManager.java b/paper-server/src/main/java/org/bukkit/craftbukkit/packs/CraftDataPackManager.java new file mode 100644 index 0000000000..b4f8408419 --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/packs/CraftDataPackManager.java @@ -0,0 +1,102 @@ +package org.bukkit.craftbukkit.packs; + +import com.google.common.base.Preconditions; +import java.util.Collection; +import java.util.Objects; +import java.util.stream.Collectors; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.MinecraftKey; +import net.minecraft.server.packs.repository.ResourcePackLoader; +import net.minecraft.server.packs.repository.ResourcePackRepository; +import net.minecraft.world.entity.EntityTypes; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.packs.DataPack; +import org.bukkit.packs.DataPackManager; + +public class CraftDataPackManager implements DataPackManager { + + private final ResourcePackRepository handle; + + public CraftDataPackManager(ResourcePackRepository resourcePackRepository) { + this.handle = resourcePackRepository; + } + + public ResourcePackRepository getHandle() { + return this.handle; + } + + @Override + public Collection getDataPacks() { + // Based in the command for datapacks need reload for get the updated list of datapacks + this.getHandle().reload(); + + Collection availablePacks = this.getHandle().getAvailablePacks(); + return availablePacks.stream().map(CraftDataPack::new).collect(Collectors.toUnmodifiableList()); + } + + @Override + public DataPack getDataPack(NamespacedKey namespacedKey) { + Preconditions.checkArgument(namespacedKey != null, "namespacedKey cannot be null"); + + return new CraftDataPack(this.getHandle().getPack(namespacedKey.getKey())); + } + + @Override + public Collection getEnabledDataPacks(World world) { + Preconditions.checkArgument(world != null, "world cannot be null"); + + CraftWorld craftWorld = ((CraftWorld) world); + return craftWorld.getHandle().serverLevelData.getDataConfiguration().dataPacks().getEnabled().stream().map(packName -> { + ResourcePackLoader resourcePackLoader = this.getHandle().getPack(packName); + if (resourcePackLoader != null) { + return new CraftDataPack(resourcePackLoader); + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toUnmodifiableList()); + } + + @Override + public Collection getDisabledDataPacks(World world) { + Preconditions.checkArgument(world != null, "world cannot be null"); + + CraftWorld craftWorld = ((CraftWorld) world); + return craftWorld.getHandle().serverLevelData.getDataConfiguration().dataPacks().getDisabled().stream().map(packName -> { + ResourcePackLoader resourcePackLoader = this.getHandle().getPack(packName); + if (resourcePackLoader != null) { + return new CraftDataPack(resourcePackLoader); + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toUnmodifiableList()); + } + + @Override + public boolean isEnabledByFeature(Material material, World world) { + Preconditions.checkArgument(material != null, "material cannot be null"); + Preconditions.checkArgument(material.isItem() || material.isBlock(), "material need to be a item or block"); + Preconditions.checkArgument(world != null, "world cannot be null"); + + CraftWorld craftWorld = ((CraftWorld) world); + if (material.isItem()) { + return CraftMagicNumbers.getItem(material).isEnabled(craftWorld.getHandle().enabledFeatures()); + } else if (material.isBlock()) { + return CraftMagicNumbers.getBlock(material).isEnabled(craftWorld.getHandle().enabledFeatures()); + } + return false; + } + + @Override + public boolean isEnabledByFeature(EntityType entityType, World world) { + Preconditions.checkArgument(entityType != null, "entityType cannot be null"); + Preconditions.checkArgument(world != null, "world cannot be null"); + Preconditions.checkArgument(entityType != EntityType.UNKNOWN, "EntityType.UNKNOWN its not allowed here"); + + CraftWorld craftWorld = ((CraftWorld) world); + EntityTypes nmsEntity = BuiltInRegistries.ENTITY_TYPE.get(new MinecraftKey(entityType.getKey().getKey())); + return nmsEntity.isEnabled(craftWorld.getHandle().enabledFeatures()); + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java index 178a32989d..68fe752dad 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -45,6 +45,7 @@ import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.material.FluidType; import net.minecraft.world.level.storage.SavedFile; import org.bukkit.Bukkit; +import org.bukkit.FeatureFlag; import org.bukkit.Fluid; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -55,6 +56,7 @@ import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.CraftEquipmentSlot; +import org.bukkit.craftbukkit.CraftFeatureFlag; import org.bukkit.craftbukkit.attribute.CraftAttributeInstance; import org.bukkit.craftbukkit.attribute.CraftAttributeMap; import org.bukkit.craftbukkit.block.CraftBlock; @@ -387,6 +389,12 @@ public final class CraftMagicNumbers implements UnsafeValues { return nmsItemStack.getItem().getDescriptionId(nmsItemStack); } + @Override + public FeatureFlag getFeatureFlag(NamespacedKey namespacedKey) { + Preconditions.checkArgument(namespacedKey != null, "NamespaceKey cannot be null"); + return CraftFeatureFlag.getFromNMS(namespacedKey); + } + /** * This helper class represents the different NBT Tags. *