Merge remote-tracking branch 'upstream/main' into update
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package io.papermc.paper;
|
||||
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageEffect;
|
||||
import org.bukkit.damage.DamageEffect;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public class PaperServerInternalAPIBridge implements InternalAPIBridge {
|
||||
public static final PaperServerInternalAPIBridge INSTANCE = new PaperServerInternalAPIBridge();
|
||||
|
||||
@Override
|
||||
public DamageEffect getDamageEffect(final String key) {
|
||||
return CraftDamageEffect.getById(key);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import com.mojang.serialization.DynamicOps;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -37,6 +36,7 @@ import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.DataComponentValue;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.ShadowColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
@@ -79,6 +79,8 @@ public final class AdventureCodecs {
|
||||
public static final Codec<Component> COMPONENT_CODEC = recursive("adventure Component", AdventureCodecs::createCodec);
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, Component> STREAM_COMPONENT_CODEC = ByteBufCodecs.fromCodecWithRegistriesTrusted(COMPONENT_CODEC);
|
||||
|
||||
static final Codec<ShadowColor> SHADOW_COLOR_CODEC = ExtraCodecs.ARGB_COLOR_CODEC.xmap(ShadowColor::shadowColor, ShadowColor::value);
|
||||
|
||||
static final Codec<TextColor> TEXT_COLOR_CODEC = Codec.STRING.comapFlatMap(s -> {
|
||||
if (s.startsWith("#")) {
|
||||
@Nullable TextColor value = TextColor.fromHexString(s);
|
||||
@@ -220,6 +222,7 @@ public final class AdventureCodecs {
|
||||
public static final MapCodec<Style> STYLE_MAP_CODEC = mapCodec((instance) -> {
|
||||
return instance.group(
|
||||
TEXT_COLOR_CODEC.optionalFieldOf("color").forGetter(nullableGetter(Style::color)),
|
||||
SHADOW_COLOR_CODEC.optionalFieldOf("shadow_color").forGetter(nullableGetter(Style::shadowColor)),
|
||||
Codec.BOOL.optionalFieldOf("bold").forGetter(decorationGetter(TextDecoration.BOLD)),
|
||||
Codec.BOOL.optionalFieldOf("italic").forGetter(decorationGetter(TextDecoration.ITALIC)),
|
||||
Codec.BOOL.optionalFieldOf("underlined").forGetter(decorationGetter(TextDecoration.UNDERLINED)),
|
||||
@@ -229,9 +232,10 @@ public final class AdventureCodecs {
|
||||
HOVER_EVENT_CODEC.optionalFieldOf("hoverEvent").forGetter(nullableGetter(Style::hoverEvent)),
|
||||
Codec.STRING.optionalFieldOf("insertion").forGetter(nullableGetter(Style::insertion)),
|
||||
KEY_CODEC.optionalFieldOf("font").forGetter(nullableGetter(Style::font))
|
||||
).apply(instance, (textColor, bold, italic, underlined, strikethrough, obfuscated, clickEvent, hoverEvent, insertion, font) -> {
|
||||
).apply(instance, (textColor, shadowColor, bold, italic, underlined, strikethrough, obfuscated, clickEvent, hoverEvent, insertion, font) -> {
|
||||
return Style.style(builder -> {
|
||||
textColor.ifPresent(builder::color);
|
||||
shadowColor.ifPresent(builder::shadowColor);
|
||||
bold.ifPresent(styleBooleanConsumer(builder, TextDecoration.BOLD));
|
||||
italic.ifPresent(styleBooleanConsumer(builder, TextDecoration.ITALIC));
|
||||
underlined.ifPresent(styleBooleanConsumer(builder, TextDecoration.UNDERLINED));
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class EntityCommand implements PaperSubcommand {
|
||||
if (args.length == 1) {
|
||||
return CommandUtil.getListMatchingLast(sender, args, "help", "list");
|
||||
} else if (args.length == 2) {
|
||||
return CommandUtil.getListMatchingLast(sender, args, BuiltInRegistries.ENTITY_TYPE.keySet().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new));
|
||||
return CommandUtil.getListMatchingLast(sender, args, BuiltInRegistries.ENTITY_TYPE.keySet());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@@ -53,7 +53,8 @@ interface RemovedConfigurations {
|
||||
path("entities", "spawning", "despawn-ranges", "hard"),
|
||||
path("fixes", "fix-curing-zombie-villager-discount-exploit"),
|
||||
path("entities", "mob-effects", "undead-immune-to-certain-effects"),
|
||||
path("entities", "entities-target-with-follow-range")
|
||||
path("entities", "entities-target-with-follow-range"),
|
||||
path("environment", "disable-teleportation-suffocation-check")
|
||||
};
|
||||
// spawn.keep-spawn-loaded and spawn.keep-spawn-loaded-range are no longer used, but kept
|
||||
// in the world default config for compatibility with old worlds being migrated to use the gamerule
|
||||
|
||||
@@ -445,7 +445,6 @@ public class WorldConfiguration extends ConfigurationPart {
|
||||
public int portalSearchRadius = 128;
|
||||
public int portalCreateRadius = 16;
|
||||
public boolean portalSearchVanillaDimensionScaling = true;
|
||||
public boolean disableTeleportationSuffocationCheck = false;
|
||||
public IntOr.Disabled netherCeilingVoidDamageHeight = IntOr.Disabled.DISABLED;
|
||||
public int maxFluidTicks = 65536;
|
||||
public int maxBlockTicks = 65536;
|
||||
|
||||
@@ -2,71 +2,25 @@ package io.papermc.paper.datapack;
|
||||
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.event.server.ServerResourcesReloadedEvent;
|
||||
import io.papermc.paper.world.flag.PaperFeatureFlagProviderImpl;
|
||||
import java.util.ArrayList;
|
||||
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.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.packs.repository.Pack;
|
||||
import net.minecraft.server.packs.repository.PackSource;
|
||||
import org.bukkit.FeatureFlag;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
public class PaperDatapack 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);
|
||||
}
|
||||
@NullMarked
|
||||
public class PaperDatapack extends PaperDiscoveredDatapack implements Datapack {
|
||||
|
||||
private final Pack pack;
|
||||
private final boolean enabled;
|
||||
|
||||
PaperDatapack(final Pack pack, final boolean enabled) {
|
||||
super(pack);
|
||||
this.pack = pack;
|
||||
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
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
@@ -76,7 +30,7 @@ public class PaperDatapack implements Datapack {
|
||||
public void setEnabled(final boolean enabled) {
|
||||
final MinecraftServer server = MinecraftServer.getServer();
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatapackSource getSource() {
|
||||
return PACK_SOURCES.computeIfAbsent(this.pack.location().source(), source -> new DatapackSourceImpl(source.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component computeDisplayName() {
|
||||
return PaperAdventure.asAdventure(this.pack.getChatLink(this.enabled));
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
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.buildOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DiscoveredDatapack discoverPack(final URI uri, final String id, final Consumer<Configurer> configurer) throws IOException {
|
||||
Preconditions.checkState(this.owner != null, "Discovering packs is not supported outside of lifecycle events");
|
||||
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, "Discovering packs is not supported outside of lifecycle events");
|
||||
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 {
|
||||
Preconditions.checkState(this.owner != null, "Discovering packs is not supported outside of lifecycle events");
|
||||
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));
|
||||
return null;
|
||||
} 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.autoEnableOnServerStart,
|
||||
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 autoEnableOnServerStart = 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 autoEnableOnServerStart(final boolean autoEnableOnServerStart) {
|
||||
this.autoEnableOnServerStart = autoEnableOnServerStart;
|
||||
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,69 @@
|
||||
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)
|
||||
.put(PluginPackSource.INSTANCE, DatapackSource.PLUGIN)
|
||||
.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;
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,9 @@ import io.papermc.paper.plugin.storage.ProviderStorage;
|
||||
import io.papermc.paper.plugin.storage.ServerPluginProviderStorage;
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Used by the server to register/load plugin bootstrappers and plugins.
|
||||
|
||||
@@ -4,10 +4,13 @@ import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.PaperDataComponentType;
|
||||
import io.papermc.paper.registry.data.PaperBannerPatternRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperDamageTypeRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperPaintingVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
@@ -102,11 +105,11 @@ public final class PaperRegistries {
|
||||
start(Registries.STRUCTURE, RegistryKey.STRUCTURE).craft(Structure.class, CraftStructure::new).build().delayed(),
|
||||
start(Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL).craft(TrimMaterial.class, CraftTrimMaterial::new).build().delayed(),
|
||||
start(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN).craft(TrimPattern.class, CraftTrimPattern::new).build().delayed(),
|
||||
start(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE).craft(DamageType.class, CraftDamageType::new).build().delayed(),
|
||||
start(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE).craft(DamageType.class, CraftDamageType::new).writable(PaperDamageTypeRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).build().delayed(),
|
||||
start(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT).craft(Enchantment.class, CraftEnchantment::new).serializationUpdater(FieldRename.ENCHANTMENT_RENAME).writable(PaperEnchantmentRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG).craft(JukeboxSong.class, CraftJukeboxSong::new).build().delayed(),
|
||||
start(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN).craft(PatternType.class, CraftPatternType::new).build().delayed(),
|
||||
start(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN).craft(PatternType.class, CraftPatternType::new).writable(PaperBannerPatternRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT).craft(Art.class, CraftArt::new).writable(PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.INSTRUMENT, RegistryKey.INSTRUMENT).craft(MusicInstrument.class, CraftMusicInstrument::new).build().delayed(),
|
||||
|
||||
@@ -136,6 +139,18 @@ public final class PaperRegistries {
|
||||
return (RegistryEntry<M, T>) BY_REGISTRY_KEY.get(registryKey);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> RegistryEntryMeta.Buildable<M, T, B> getBuildableMeta(final ResourceKey<? extends Registry<M>> resourceKey) {
|
||||
final RegistryEntry<M, T> entry = getEntry(resourceKey);
|
||||
if (entry == null) {
|
||||
throw new IllegalArgumentException("No registry entry for " + resourceKey);
|
||||
}
|
||||
if (!(entry.meta() instanceof final RegistryEntryMeta.Buildable<M, T, ?> buildableMeta)) {
|
||||
throw new IllegalArgumentException("Registry entry for " + resourceKey + " is not buildable");
|
||||
}
|
||||
return (RegistryEntryMeta.Buildable<M, T, B>) buildableMeta;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <M, T> RegistryKey<T> registryFromNms(final ResourceKey<? extends Registry<M>> registryResourceKey) {
|
||||
return (RegistryKey<T>) Objects.requireNonNull(BY_RESOURCE_KEY.get(registryResourceKey), registryResourceKey + " doesn't have an api RegistryKey").apiKey();
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.stream.Collectors;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.craftbukkit.CraftRegistry;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -72,7 +73,7 @@ public class PaperRegistryAccess implements RegistryAccess {
|
||||
if (PaperRegistries.getEntry(key) == null) {
|
||||
throw new NoSuchElementException(key + " is not a valid registry key");
|
||||
}
|
||||
final @Nullable RegistryHolder<T> registryHolder = (RegistryHolder<T>) this.registries.get(key);
|
||||
final RegistryHolder<T> registryHolder = (RegistryHolder<T>) this.registries.get(key);
|
||||
if (registryHolder == null) {
|
||||
throw new IllegalArgumentException(key + " points to a registry that is not available yet");
|
||||
}
|
||||
@@ -104,13 +105,22 @@ public class PaperRegistryAccess implements RegistryAccess {
|
||||
this.registerRegistry(resourceKey, registry, false);
|
||||
}
|
||||
|
||||
public <M> void lockReferenceHolders(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey) {
|
||||
final RegistryEntry<M, Keyed> entry = PaperRegistries.getEntry(resourceKey);
|
||||
if (entry == null || !(entry.meta() instanceof final RegistryEntryMeta.ServerSide<M, Keyed> serverSide) || !serverSide.registryTypeMapper().supportsDirectHolders()) {
|
||||
return;
|
||||
}
|
||||
final CraftRegistry<?, M> registry = (CraftRegistry<?, M>) this.getRegistry(entry.apiKey());
|
||||
registry.lockReferenceHolders();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // this method should be called right after any new MappedRegistry instances are created to later be used by the server.
|
||||
private <M, B extends Keyed, R extends Registry<B>> void registerRegistry(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey, final net.minecraft.core.Registry<M> registry, final boolean replace) {
|
||||
final @Nullable RegistryEntry<M, B> entry = PaperRegistries.getEntry(resourceKey);
|
||||
final RegistryEntry<M, B> entry = PaperRegistries.getEntry(resourceKey);
|
||||
if (entry == null) { // skip registries that don't have API entries
|
||||
return;
|
||||
}
|
||||
final @Nullable RegistryHolder<B> registryHolder = (RegistryHolder<B>) this.registries.get(entry.apiKey());
|
||||
final RegistryHolder<B> registryHolder = (RegistryHolder<B>) this.registries.get(entry.apiKey());
|
||||
if (registryHolder == null || replace) {
|
||||
// if the holder doesn't exist yet, or is marked as "replaceable", put it in the map.
|
||||
this.registries.put(entry.apiKey(), entry.createRegistryHolder(registry));
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package io.papermc.paper.registry;
|
||||
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import java.util.function.Function;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.bukkit.Keyed;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public class PaperRegistryBuilderFactory<M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> implements RegistryBuilderFactory<A, B> { // TODO remove Keyed
|
||||
|
||||
private final Conversions conversions;
|
||||
private final PaperRegistryBuilder.Filler<M, A, B> builderFiller;
|
||||
private final Function<? super ResourceLocation, ? extends @Nullable M> existingValueGetter;
|
||||
private @Nullable B builder;
|
||||
|
||||
public PaperRegistryBuilderFactory(final Conversions conversions, final PaperRegistryBuilder.Filler<M, A, B> builderFiller, final Function<? super ResourceLocation, ? extends @Nullable M> existingValueGetter) {
|
||||
this.conversions = conversions;
|
||||
this.builderFiller = builderFiller;
|
||||
this.existingValueGetter = existingValueGetter;
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
if (this.builder != null) {
|
||||
throw new IllegalStateException("Already created a builder");
|
||||
}
|
||||
}
|
||||
|
||||
public B requireBuilder() {
|
||||
if (this.builder == null) {
|
||||
throw new IllegalStateException("Builder not created yet");
|
||||
}
|
||||
return this.builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B empty() {
|
||||
this.validate();
|
||||
return this.builder = this.builderFiller.create(this.conversions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public B copyFrom(final TypedKey<A> key) {
|
||||
this.validate();
|
||||
final M existing = this.existingValueGetter.apply(PaperAdventure.asVanilla(key));
|
||||
if (existing == null) {
|
||||
throw new IllegalArgumentException("Key " + key + " doesn't exist");
|
||||
}
|
||||
return this.builder = this.builderFiller.fill(this.conversions, existing);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package io.papermc.paper.registry;
|
||||
import io.papermc.paper.registry.set.NamedRegistryKeySetImpl;
|
||||
import io.papermc.paper.registry.tag.Tag;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
@@ -51,4 +52,9 @@ public class PaperSimpleRegistry<T extends Enum<T> & Keyed, M> extends Registry.
|
||||
final HolderSet.Named<M> namedHolderSet = this.nmsRegistry.get(PaperRegistries.toNms(key)).orElseThrow();
|
||||
return new NamedRegistryKeySetImpl<>(key, namedHolderSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Tag<T>> getTags() {
|
||||
return this.nmsRegistry.getTags().<Tag<T>>map(NamedRegistryKeySetImpl::new).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,15 @@ package io.papermc.paper.registry;
|
||||
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import io.papermc.paper.registry.entry.RegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||
import io.papermc.paper.registry.entry.RegistryTypeMapper;
|
||||
import io.papermc.paper.registry.event.WritableRegistry;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.core.MappedRegistry;
|
||||
import net.minecraft.core.RegistrationInfo;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.craftbukkit.CraftRegistry;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
|
||||
public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends CraftRegistry<T, M> {
|
||||
|
||||
@@ -33,16 +28,16 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
public void register(final TypedKey<T> key, final Consumer<? super B> value, final Conversions conversions) {
|
||||
public void register(final TypedKey<T> key, final Consumer<RegistryBuilderFactory<T, B>> value, final Conversions conversions) {
|
||||
final ResourceKey<M> resourceKey = PaperRegistries.toNms(key);
|
||||
this.registry.validateWrite(resourceKey);
|
||||
final B builder = this.newBuilder(conversions);
|
||||
value.accept(builder);
|
||||
final PaperRegistryBuilderFactory<M, T, B> builderFactory = new PaperRegistryBuilderFactory<>(conversions, this.meta.builderFiller(), this.registry.temporaryUnfrozenMap::get);
|
||||
value.accept(builderFactory);
|
||||
PaperRegistryListenerManager.INSTANCE.registerWithListeners(
|
||||
this.registry,
|
||||
this.meta,
|
||||
resourceKey,
|
||||
builder,
|
||||
builderFactory.requireBuilder(),
|
||||
FROM_PLUGIN,
|
||||
conversions
|
||||
);
|
||||
@@ -52,10 +47,6 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
|
||||
return new ApiWritableRegistry(conversions);
|
||||
}
|
||||
|
||||
protected B newBuilder(final Conversions conversions) {
|
||||
return this.meta.builderFiller().create(conversions);
|
||||
}
|
||||
|
||||
public class ApiWritableRegistry implements WritableRegistry<T, B> {
|
||||
|
||||
private final Conversions conversions;
|
||||
@@ -65,7 +56,7 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(final TypedKey<T> key, final Consumer<? super B> value) {
|
||||
public void registerWith(final TypedKey<T> key, final Consumer<RegistryBuilderFactory<T, B>> value) {
|
||||
WritableCraftRegistry.this.register(key, value, this.conversions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.registry.PaperRegistries;
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.PaperRegistryBuilderFactory;
|
||||
import io.papermc.paper.registry.RegistryBuilderFactory;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import org.bukkit.Art;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.craftbukkit.CraftRegistry;
|
||||
|
||||
@SuppressWarnings("BoundedWildcard")
|
||||
public final class InlinedRegistryBuilderProviderImpl implements InlinedRegistryBuilderProvider {
|
||||
|
||||
private static <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> A create(final ResourceKey<? extends Registry<M>> registryKey, final Consumer<PaperRegistryBuilderFactory<M, A, B>> value) {
|
||||
final RegistryEntryMeta.Buildable<M, A, B> buildableMeta = PaperRegistries.getBuildableMeta(registryKey);
|
||||
Preconditions.checkArgument(buildableMeta.registryTypeMapper().supportsDirectHolders(), "Registry type mapper must support direct holders");
|
||||
final PaperRegistryBuilderFactory<M, A, B> builderFactory = new PaperRegistryBuilderFactory<>(Conversions.global(), buildableMeta.builderFiller(), CraftRegistry.getMinecraftRegistry(buildableMeta.mcKey())::getValue);
|
||||
value.accept(builderFactory);
|
||||
return buildableMeta.registryTypeMapper().convertDirectHolder(Holder.direct(builderFactory.requireBuilder().build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Art createPaintingVariant(final Consumer<RegistryBuilderFactory<Art, ? extends PaintingVariantRegistryEntry.Builder>> value) {
|
||||
return create(Registries.PAINTING_VARIANT, value::accept);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.entity.BannerPattern;
|
||||
import org.bukkit.block.banner.PatternType;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.*;
|
||||
|
||||
public class PaperBannerPatternRegistryEntry implements BannerPatternRegistryEntry {
|
||||
|
||||
protected @Nullable ResourceLocation assetId;
|
||||
protected @Nullable String translationKey;
|
||||
|
||||
public PaperBannerPatternRegistryEntry(
|
||||
final Conversions ignoredConversions,
|
||||
final @Nullable BannerPattern internal
|
||||
) {
|
||||
if (internal == null) return;
|
||||
|
||||
this.assetId = internal.assetId();
|
||||
this.translationKey = internal.translationKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Key assetId() {
|
||||
return PaperAdventure.asAdventure(asConfigured(this.assetId, "assetId"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translationKey() {
|
||||
return asConfigured(this.translationKey, "translationKey");
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperBannerPatternRegistryEntry implements Builder, PaperRegistryBuilder<BannerPattern, PatternType> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable BannerPattern internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder assetId(final Key assetId) {
|
||||
this.assetId = PaperAdventure.asVanilla(asArgument(assetId, "assetId"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder translationKey(final String translationKey) {
|
||||
this.translationKey = asArgument(translationKey, "translationKey");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BannerPattern build() {
|
||||
return new BannerPattern(
|
||||
asConfigured(this.assetId, "assetId"),
|
||||
this.translationKey()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.damagesource.DamageEffects;
|
||||
import net.minecraft.world.damagesource.DamageScaling;
|
||||
import net.minecraft.world.damagesource.DamageType;
|
||||
import net.minecraft.world.damagesource.DeathMessageType;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageEffect;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageType;
|
||||
import org.bukkit.damage.DamageEffect;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperDamageTypeRegistryEntry implements DamageTypeRegistryEntry {
|
||||
|
||||
protected @Nullable String messageId;
|
||||
protected @Nullable Float exhaustion;
|
||||
protected @Nullable DamageScaling damageScaling;
|
||||
protected DamageEffects damageEffects = DamageEffects.HURT;
|
||||
protected DeathMessageType deathMessageType = DeathMessageType.DEFAULT;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperDamageTypeRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable DamageType internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) return;
|
||||
|
||||
this.messageId = internal.msgId();
|
||||
this.exhaustion = internal.exhaustion();
|
||||
this.damageScaling = internal.scaling();
|
||||
this.damageEffects = internal.effects();
|
||||
this.deathMessageType = internal.deathMessageType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String messageId() {
|
||||
return asConfigured(messageId, "messsageId");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float exhaustion() {
|
||||
return asConfigured(exhaustion, "exhaustion");
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.damage.DamageScaling damageScaling() {
|
||||
return CraftDamageType.damageScalingToBukkit(asConfigured(this.damageScaling, "damageScaling"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DamageEffect damageEffect() {
|
||||
return CraftDamageEffect.toBukkit(damageEffects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.damage.DeathMessageType deathMessageType() {
|
||||
return CraftDamageType.deathMessageTypeToBukkit(deathMessageType);
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperDamageTypeRegistryEntry implements DamageTypeRegistryEntry.Builder, PaperRegistryBuilder<DamageType, org.bukkit.damage.DamageType> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable DamageType internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder messageId(final String messageId) {
|
||||
this.messageId = messageId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder exhaustion(final float exhaustion) {
|
||||
this.exhaustion = exhaustion;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder damageScaling(final org.bukkit.damage.DamageScaling scaling) {
|
||||
this.damageScaling = CraftDamageType.damageScalingToNMS(scaling);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder damageEffect(final DamageEffect effect) {
|
||||
this.damageEffects = ((CraftDamageEffect) effect).getHandle();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder deathMessageType(final org.bukkit.damage.DeathMessageType deathMessageType) {
|
||||
this.deathMessageType = CraftDamageType.deathMessageTypeToNMS(deathMessageType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DamageType build() {
|
||||
return new DamageType(
|
||||
asConfigured(this.messageId, "messsageId"),
|
||||
asConfigured(this.damageScaling, "scaling"),
|
||||
asConfigured(this.exhaustion, "exhaustion"),
|
||||
this.damageEffects,
|
||||
this.deathMessageType
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package io.papermc.paper.registry.legacy;
|
||||
|
||||
import io.papermc.paper.registry.tag.Tag;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
@@ -38,11 +39,6 @@ public final class DelayedRegistry<T extends Keyed, R extends Registry<T>> imple
|
||||
return this.delegate().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getOrThrow(final NamespacedKey key) {
|
||||
return this.delegate().getOrThrow(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return this.delegate().iterator();
|
||||
@@ -67,4 +63,9 @@ public final class DelayedRegistry<T extends Keyed, R extends Registry<T>> imple
|
||||
public @NonNull Tag<T> getTag(final TagKey<T> key) {
|
||||
return this.delegate().getTag(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Tag<T>> getTags() {
|
||||
return this.delegate().getTags();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@ public record NamedRegistryKeySetImpl<T extends Keyed, M>( // TODO remove Keyed
|
||||
HolderSet.Named<M> namedSet
|
||||
) implements Tag<T>, org.bukkit.Tag<T> {
|
||||
|
||||
public NamedRegistryKeySetImpl(final HolderSet.Named<M> namedSet) {
|
||||
this(PaperRegistries.fromNms(namedSet.key()), namedSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Unmodifiable Collection<TypedKey<T>> values() {
|
||||
final ImmutableList.Builder<TypedKey<T>> builder = ImmutableList.builder();
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.bukkit.util.OldEnum;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@SuppressWarnings({"removal", "DeprecatedIsStillUsed"})
|
||||
@Deprecated
|
||||
@NullMarked
|
||||
public abstract class OldEnumHolderable<A extends OldEnum<A>, M> implements Holderable<M>, OldEnum<A>, Keyed {
|
||||
@@ -43,7 +43,7 @@ public abstract class OldEnumHolderable<A extends OldEnum<A>, M> implements Hold
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int compareTo(A other) {
|
||||
public int compareTo(final A other) {
|
||||
this.checkIsReference();
|
||||
return this.ordinal - other.ordinal();
|
||||
}
|
||||
@@ -83,6 +83,10 @@ public abstract class OldEnumHolderable<A extends OldEnum<A>, M> implements Hold
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.name != null) {
|
||||
// TODO remove in next feature release or 1.22
|
||||
return this.name;
|
||||
}
|
||||
return this.implToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,9 +41,6 @@ public class CraftMusicInstrument extends MusicInstrument implements io.papermc.
|
||||
return io.papermc.paper.util.Holderable.fromBukkitSerializationObject(string, Instrument.CODEC, Registry.INSTRUMENT); // Paper - switch to Holder
|
||||
}
|
||||
|
||||
private final NamespacedKey key;
|
||||
private final Instrument handle;
|
||||
|
||||
// Paper start - switch to Holder
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
@@ -63,8 +60,6 @@ public class CraftMusicInstrument extends MusicInstrument implements io.papermc.
|
||||
private final Holder<Instrument> holder;
|
||||
public CraftMusicInstrument(Holder<Instrument> holder) {
|
||||
this.holder = holder;
|
||||
this.key = holder.unwrapKey().map(io.papermc.paper.util.MCUtil::fromResourceKey).orElse(null);
|
||||
this.handle = holder.value();
|
||||
// Paper end - switch to Holder
|
||||
}
|
||||
|
||||
|
||||
@@ -2,67 +2,30 @@ package org.bukkit.craftbukkit;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||
import io.papermc.paper.registry.set.NamedRegistryKeySetImpl;
|
||||
import io.papermc.paper.registry.tag.Tag;
|
||||
import io.papermc.paper.util.Holderable;
|
||||
import java.util.Collection;
|
||||
import io.papermc.paper.util.MCUtil;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Stream;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderOwner;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import org.bukkit.Art;
|
||||
import org.bukkit.Fluid;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.JukeboxSong;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.MusicInstrument;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.BlockType;
|
||||
import org.bukkit.block.banner.PatternType;
|
||||
import org.bukkit.craftbukkit.attribute.CraftAttribute;
|
||||
import org.bukkit.craftbukkit.block.CraftBiome;
|
||||
import org.bukkit.craftbukkit.block.CraftBlockType;
|
||||
import org.bukkit.craftbukkit.block.banner.CraftPatternType;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageType;
|
||||
import org.bukkit.craftbukkit.enchantments.CraftEnchantment;
|
||||
import org.bukkit.craftbukkit.entity.CraftCat;
|
||||
import org.bukkit.craftbukkit.entity.CraftFrog;
|
||||
import org.bukkit.craftbukkit.entity.CraftVillager;
|
||||
import org.bukkit.craftbukkit.entity.CraftWolf;
|
||||
import org.bukkit.craftbukkit.generator.structure.CraftStructure;
|
||||
import org.bukkit.craftbukkit.generator.structure.CraftStructureType;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemType;
|
||||
import org.bukkit.craftbukkit.inventory.CraftMenuType;
|
||||
import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial;
|
||||
import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern;
|
||||
import org.bukkit.craftbukkit.legacy.FieldRename;
|
||||
import org.bukkit.craftbukkit.map.CraftMapCursor;
|
||||
import org.bukkit.craftbukkit.potion.CraftPotionEffectType;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||
import org.bukkit.craftbukkit.util.Handleable;
|
||||
import org.bukkit.damage.DamageType;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Cat;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Frog;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.entity.Wolf;
|
||||
import org.bukkit.generator.structure.Structure;
|
||||
import org.bukkit.generator.structure.StructureType;
|
||||
import org.bukkit.inventory.ItemType;
|
||||
import org.bukkit.inventory.MenuType;
|
||||
import org.bukkit.inventory.meta.trim.TrimMaterial;
|
||||
import org.bukkit.inventory.meta.trim.TrimPattern;
|
||||
import org.bukkit.map.MapCursor;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
||||
@@ -78,7 +41,7 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
||||
return CraftRegistry.registry;
|
||||
}
|
||||
|
||||
public static <E> net.minecraft.core.Registry<E> getMinecraftRegistry(ResourceKey<net.minecraft.core.Registry<E>> key) {
|
||||
public static <E> net.minecraft.core.Registry<E> getMinecraftRegistry(ResourceKey<? extends net.minecraft.core.Registry<E>> key) {
|
||||
return CraftRegistry.getMinecraftRegistry().lookupOrThrow(key);
|
||||
}
|
||||
|
||||
@@ -202,7 +165,8 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
||||
private final net.minecraft.core.Registry<M> minecraftRegistry;
|
||||
private final io.papermc.paper.registry.entry.RegistryTypeMapper<M, B> minecraftToBukkit; // Paper - switch to Holder
|
||||
private final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater; // Paper - rename to make it *clear* what it is *only* for
|
||||
private boolean init;
|
||||
private final InvalidHolderOwner invalidHolderOwner = new InvalidHolderOwner();
|
||||
private boolean lockReferenceHolders;
|
||||
|
||||
public CraftRegistry(Class<?> bukkitClass, net.minecraft.core.Registry<M> minecraftRegistry, BiFunction<? super NamespacedKey, M, B> minecraftToBukkit, BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater) { // Paper - relax preload class
|
||||
// Paper start - switch to Holder
|
||||
@@ -217,6 +181,22 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
||||
this.minecraftRegistry = minecraftRegistry;
|
||||
this.minecraftToBukkit = minecraftToBukkit;
|
||||
this.serializationUpdater = serializationUpdater;
|
||||
this.lockReferenceHolders = !this.minecraftToBukkit.supportsDirectHolders();
|
||||
}
|
||||
|
||||
public void lockReferenceHolders() {
|
||||
Preconditions.checkState(this.cache.isEmpty(), "Registry %s is already loaded", this.minecraftRegistry.key());
|
||||
|
||||
try {
|
||||
Class.forName(this.bukkitClass.getName()); // this should always trigger the initialization of the class
|
||||
} catch (final ClassNotFoundException e) {
|
||||
throw new IllegalStateException("Failed to load class " + this.bukkitClass.getSimpleName(), e);
|
||||
}
|
||||
if (!this.minecraftToBukkit.supportsDirectHolders()) {
|
||||
return;
|
||||
}
|
||||
Preconditions.checkState(!this.lockReferenceHolders, "Reference holders are already locked");
|
||||
this.lockReferenceHolders = true;
|
||||
}
|
||||
|
||||
// Paper - inline into CraftRegistry#get(Registry, NamespacedKey, ApiVersion) above
|
||||
@@ -228,28 +208,19 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// Make sure that the bukkit class is loaded before creating an instance.
|
||||
// This ensures that only one instance with a given key is created.
|
||||
//
|
||||
// Without this code (when bukkit class is not loaded):
|
||||
// Registry#get -> #createBukkit -> (load class -> create default) -> put in cache
|
||||
// Result: Registry#get != <bukkitClass>.<field> for possible one registry item
|
||||
//
|
||||
// With this code (when bukkit class is not loaded):
|
||||
// Registry#get -> (load class -> create default) -> Registry#get -> get from cache
|
||||
// Result: Registry#get == <bukkitClass>.<field>
|
||||
if (!this.init) {
|
||||
this.init = true;
|
||||
try {
|
||||
Class.forName(this.bukkitClass.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Could not load registry class " + this.bukkitClass, e);
|
||||
}
|
||||
|
||||
return this.get(namespacedKey);
|
||||
final Optional<Holder.Reference<M>> holderOptional = this.minecraftRegistry.get(CraftNamespacedKey.toMinecraft(namespacedKey));
|
||||
final Holder.Reference<M> holder;
|
||||
if (holderOptional.isPresent()) {
|
||||
holder = holderOptional.get();
|
||||
} else if (!this.lockReferenceHolders && this.minecraftToBukkit.supportsDirectHolders()) { // only works if its Holderable
|
||||
// we lock the reference holders after the preload class has been initialized
|
||||
// this is to support the vanilla mechanic of preventing vanilla registry entries being loaded. We need
|
||||
// to create something to fill the API constant fields, so we create a dummy reference holder.
|
||||
holder = Holder.Reference.createStandAlone(this.invalidHolderOwner, MCUtil.toResourceKey(this.minecraftRegistry.key(), namespacedKey));
|
||||
} else {
|
||||
holder = null;
|
||||
}
|
||||
|
||||
B bukkit = this.createBukkit(namespacedKey, this.minecraftRegistry.get(CraftNamespacedKey.toMinecraft(namespacedKey)).orElse(null)); // Paper - switch to Holder
|
||||
final B bukkit = this.createBukkit(namespacedKey, holder);
|
||||
if (bukkit == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -304,7 +275,7 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
||||
if (value instanceof Holderable<?> holderable) {
|
||||
return holderable.getKeyOrNull();
|
||||
}
|
||||
return Registry.super.getKey(value);
|
||||
return value.getKey();
|
||||
}
|
||||
// Paper end - improve Registry
|
||||
|
||||
@@ -319,5 +290,13 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
||||
final net.minecraft.core.HolderSet.Named<M> namedHolderSet = this.minecraftRegistry.get(io.papermc.paper.registry.PaperRegistries.toNms(key)).orElseThrow();
|
||||
return new io.papermc.paper.registry.set.NamedRegistryKeySetImpl<>(key, namedHolderSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Tag<B>> getTags() {
|
||||
return this.minecraftRegistry.getTags().<Tag<B>>map(NamedRegistryKeySetImpl::new).toList();
|
||||
}
|
||||
// Paper end - RegistrySet API
|
||||
|
||||
final class InvalidHolderOwner implements HolderOwner<M> {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2182,7 +2182,8 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
receivers == null ? this.getHandle().players() : receivers.stream().map(player -> ((CraftPlayer) player).getHandle()).collect(java.util.stream.Collectors.toList()), // Paper - Particle API
|
||||
sender != null ? ((CraftPlayer) sender).getHandle() : null, // Sender // Paper - Particle API
|
||||
CraftParticle.createParticleParam(particle, data), // Particle
|
||||
false, force,
|
||||
force,
|
||||
false,
|
||||
x, y, z, // Position
|
||||
count, // Count
|
||||
offsetX, offsetY, offsetZ, // Random offset
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.bukkit.craftbukkit.enchantments;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.util.Holderable;
|
||||
import java.util.Locale;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.contents.TranslatableContents;
|
||||
import net.minecraft.tags.EnchantmentTags;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
@@ -13,13 +13,12 @@ import org.bukkit.craftbukkit.CraftRegistry;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.legacy.FieldRename;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
import org.bukkit.craftbukkit.util.Handleable;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.enchantments.EnchantmentWrapper;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class CraftEnchantment extends Enchantment implements Handleable<net.minecraft.world.item.enchantment.Enchantment> {
|
||||
public class CraftEnchantment extends Enchantment implements Holderable<net.minecraft.world.item.enchantment.Enchantment> {
|
||||
|
||||
public static Enchantment minecraftToBukkit(net.minecraft.world.item.enchantment.Enchantment minecraft) {
|
||||
return CraftRegistry.minecraftToBukkit(minecraft, Registries.ENCHANTMENT, Registry.ENCHANTMENT);
|
||||
@@ -56,22 +55,20 @@ public class CraftEnchantment extends Enchantment implements Handleable<net.mine
|
||||
return CraftRegistry.get(Registry.ENCHANTMENT, key, ApiVersion.CURRENT);
|
||||
}
|
||||
|
||||
private final NamespacedKey key;
|
||||
private final Holder<net.minecraft.world.item.enchantment.Enchantment> handle;
|
||||
|
||||
public CraftEnchantment(NamespacedKey key, net.minecraft.world.item.enchantment.Enchantment handle) {
|
||||
this.key = key;
|
||||
this.handle = CraftRegistry.getMinecraftRegistry(Registries.ENCHANTMENT).wrapAsHolder(handle);
|
||||
public CraftEnchantment(Holder<net.minecraft.world.item.enchantment.Enchantment> holder) {
|
||||
this.handle = holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.item.enchantment.Enchantment getHandle() {
|
||||
return this.handle.value();
|
||||
public Holder<net.minecraft.world.item.enchantment.Enchantment> getHolder() {
|
||||
return this.handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
return this.key;
|
||||
return Holderable.super.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -251,24 +248,16 @@ public class CraftEnchantment extends Enchantment implements Handleable<net.mine
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(other instanceof CraftEnchantment)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.getKey().equals(((Enchantment) other).getKey());
|
||||
return Holderable.super.implEquals(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.getKey().hashCode();
|
||||
return Holderable.super.implHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftEnchantment[" + this.getKey() + "]";
|
||||
return Holderable.super.implToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Pose;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
@@ -955,7 +956,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
@Override
|
||||
public String getAsString() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
if (!this.getHandle().saveAsPassenger(tag, false)) {
|
||||
if (!this.getHandle().saveAsPassenger(tag, false, false, false)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -988,7 +989,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
|
||||
private Entity copy(net.minecraft.world.level.Level level) {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
this.getHandle().saveAsPassenger(compoundTag, false);
|
||||
this.getHandle().saveAsPassenger(compoundTag, false, true, true);
|
||||
|
||||
return net.minecraft.world.entity.EntityType.loadEntityRecursive(compoundTag, level, EntitySpawnReason.LOAD, java.util.function.Function.identity());
|
||||
}
|
||||
@@ -1224,17 +1225,19 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
}
|
||||
// Paper end - tracked players API
|
||||
|
||||
// Paper start - raw entity serialization API
|
||||
@Override
|
||||
public boolean spawnAt(Location location, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
|
||||
public boolean spawnAt(Location location, CreatureSpawnEvent.SpawnReason reason) {
|
||||
Preconditions.checkNotNull(location, "location cannot be null");
|
||||
Preconditions.checkNotNull(reason, "reason cannot be null");
|
||||
this.entity.setLevel(((CraftWorld) location.getWorld()).getHandle());
|
||||
this.entity.setPos(location.getX(), location.getY(), location.getZ());
|
||||
this.entity.setRot(location.getYaw(), location.getPitch());
|
||||
return !this.entity.valid && this.entity.level().addFreshEntity(this.entity, reason);
|
||||
final boolean spawned = !this.entity.valid && this.entity.level().addFreshEntity(this.entity, reason);
|
||||
if (!spawned) return false; // Do not attempt to spawn rest if root was not spawned in
|
||||
// Like net.minecraft.world.level.ServerLevelAccessor.addFreshEntityWithPassengers(net.minecraft.world.entity.Entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason)
|
||||
this.entity.getIndirectPassengers().forEach(e -> e.level().addFreshEntity(e, reason));
|
||||
return true;
|
||||
}
|
||||
// Paper end - raw entity serialization API
|
||||
|
||||
// Paper start - entity powdered snow API
|
||||
@Override
|
||||
|
||||
@@ -66,7 +66,7 @@ public class CraftEntitySnapshot implements EntitySnapshot {
|
||||
|
||||
public static CraftEntitySnapshot create(CraftEntity entity) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
if (!entity.getHandle().saveAsPassenger(tag, false)) {
|
||||
if (!entity.getHandle().saveAsPassenger(tag, false, false, false)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@@ -19,6 +20,7 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntitySpawnReason;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.HumanoidArm;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
@@ -48,13 +50,14 @@ import org.bukkit.craftbukkit.inventory.CraftInventoryView;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.inventory.CraftMerchantCustom;
|
||||
import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
import org.bukkit.craftbukkit.util.CraftChatMessage;
|
||||
import org.bukkit.craftbukkit.util.CraftLocation;
|
||||
import org.bukkit.entity.Firework;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -66,6 +69,8 @@ import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
private CraftInventoryPlayer inventory;
|
||||
@@ -801,6 +806,47 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
// Paper end - Fix HumanEntity#drop not updating the client inv
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Item dropItem(final int slot, final int amount, final boolean throwRandomly, final @Nullable Consumer<Item> entityOperation) {
|
||||
Preconditions.checkArgument(slot >= 0 && slot < this.inventory.getSize(), "Slot %s is not a valid inventory slot.", slot);
|
||||
|
||||
return internalDropItemFromInventory(this.inventory.getItem(slot), amount, throwRandomly, entityOperation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Item dropItem(final @NotNull EquipmentSlot slot, final int amount, final boolean throwRandomly, final @Nullable Consumer<Item> entityOperation) {
|
||||
return internalDropItemFromInventory(this.inventory.getItem(slot), amount, throwRandomly, entityOperation);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Item internalDropItemFromInventory(final ItemStack originalItemStack, final int amount, final boolean throwRandomly, final @Nullable Consumer<Item> entityOperation) {
|
||||
if (originalItemStack == null || originalItemStack.isEmpty() || amount <= 0) return null;
|
||||
|
||||
final net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.unwrap(originalItemStack);
|
||||
final net.minecraft.world.item.ItemStack dropContent = nmsItemStack.split(amount);
|
||||
|
||||
// This will return the itemstack back to its original amount in case events fail
|
||||
final ItemEntity droppedEntity = this.getHandle().drop(dropContent, throwRandomly, true, true, entityOperation);
|
||||
return droppedEntity == null ? null : (Item) droppedEntity.getBukkitEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Item dropItem(final ItemStack itemStack, final boolean throwRandomly, final @Nullable Consumer<Item> entityOperation) {
|
||||
// This method implementation differs from the previous dropItem implementations, as it does not source
|
||||
// its itemstack from the players inventory. As such, we cannot reuse #internalDropItemFromInventory.
|
||||
Preconditions.checkArgument(itemStack != null, "Cannot drop a null itemstack");
|
||||
if (itemStack.isEmpty()) return null;
|
||||
|
||||
final net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
|
||||
// Do *not* call the event here, the item is not in the player inventory, they are not dropping it / do not need recovering logic (which would be a dupe).
|
||||
final ItemEntity droppedEntity = this.getHandle().drop(nmsItemStack, throwRandomly, true, false, entityOperation);
|
||||
return droppedEntity == null ? null : (Item) droppedEntity.getBukkitEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getExhaustion() {
|
||||
return this.getHandle().getFoodData().exhaustionLevel;
|
||||
|
||||
@@ -16,7 +16,7 @@ public class CraftPainting extends CraftHanging implements Painting {
|
||||
|
||||
@Override
|
||||
public Art getArt() {
|
||||
return org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.ART, this.getHandle().getVariant()).orElseThrow(() -> new IllegalStateException("Inlined painting variants are not supported yet in the API!")); // Paper
|
||||
return CraftArt.minecraftHolderToBukkit(this.getHandle().getVariant());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2983,7 +2983,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) {
|
||||
ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(CraftParticle.createParticleParam(particle, data), false, force, x, y, z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count); // Paper - fix x/y/z precision loss
|
||||
ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(CraftParticle.createParticleParam(particle, data), force, false, x, y, z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count); // Paper - fix x/y/z precision loss
|
||||
this.getHandle().connection.send(packetplayoutworldparticles);
|
||||
}
|
||||
|
||||
|
||||
@@ -291,13 +291,13 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyBiomeDecoration(WorldGenLevel world, ChunkAccess chunk, StructureManager structureAccessor) {
|
||||
public void applyBiomeDecoration(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager) {
|
||||
WorldgenRandom random = CustomChunkGenerator.getSeededRandom();
|
||||
int x = chunk.getPos().x;
|
||||
int z = chunk.getPos().z;
|
||||
|
||||
random.setSeed(Mth.getSeed(x, "should-decoration".hashCode(), z) ^ world.getSeed());
|
||||
super.applyBiomeDecoration(world, chunk, structureAccessor, this.generator.shouldGenerateDecorations(this.world.getWorld(), new RandomSourceWrapper.RandomWrapper(random), x, z));
|
||||
random.setSeed(Mth.getSeed(x, "should-decoration".hashCode(), z) ^ level.getSeed());
|
||||
super.applyBiomeDecoration(level, chunk, structureManager, this.generator.shouldGenerateDecorations(this.world.getWorld(), new RandomSourceWrapper.RandomWrapper(random), x, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,9 +13,9 @@ public class CraftBlockInventoryHolder implements BlockInventoryHolder {
|
||||
private final Block block;
|
||||
private final Inventory inventory;
|
||||
|
||||
public CraftBlockInventoryHolder(LevelAccessor world, BlockPos pos, Container inv) {
|
||||
this.block = CraftBlock.at(world, pos);
|
||||
this.inventory = new CraftInventory(inv);
|
||||
public CraftBlockInventoryHolder(LevelAccessor levelAccessor, BlockPos pos, Container container) {
|
||||
this.block = CraftBlock.at(levelAccessor, pos);
|
||||
this.inventory = new CraftInventory(container);
|
||||
}
|
||||
// Paper start - Add missing InventoryHolders
|
||||
public CraftBlockInventoryHolder(net.minecraft.world.inventory.ContainerLevelAccess levelAccess, Inventory inventory) {
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.google.common.collect.ImmutableMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.advancements.critereon.ItemPredicate;
|
||||
import net.minecraft.advancements.critereon.MinMaxBounds;
|
||||
import net.minecraft.core.Holder;
|
||||
@@ -25,6 +27,7 @@ import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.material.MaterialData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@DelegateDeserialization(ItemStack.class)
|
||||
public final class CraftItemStack extends ItemStack {
|
||||
@@ -467,6 +470,11 @@ public final class CraftItemStack extends ItemStack {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component effectiveName() {
|
||||
return this.handle == null ? Component.empty() : PaperAdventure.asAdventure(this.handle.getStyledHoverName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSimilar(ItemStack stack) {
|
||||
if (stack == null) {
|
||||
|
||||
@@ -30,9 +30,6 @@ public class CraftTrimMaterial implements TrimMaterial, io.papermc.paper.util.Ho
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.TRIM_MATERIAL); // Paper - switch to Holder
|
||||
}
|
||||
|
||||
private final NamespacedKey key;
|
||||
private final net.minecraft.world.item.equipment.trim.TrimMaterial handle;
|
||||
|
||||
// Paper start - switch to Holder
|
||||
private final Holder<net.minecraft.world.item.equipment.trim.TrimMaterial> holder;
|
||||
|
||||
@@ -64,8 +61,6 @@ public class CraftTrimMaterial implements TrimMaterial, io.papermc.paper.util.Ho
|
||||
}
|
||||
|
||||
public CraftTrimMaterial(final Holder<net.minecraft.world.item.equipment.trim.TrimMaterial> holder) {
|
||||
this.key = holder.unwrapKey().map(io.papermc.paper.util.MCUtil::fromResourceKey).orElse(null);
|
||||
this.handle = holder.value();
|
||||
this.holder = holder;
|
||||
// Paper end - switch to Holder
|
||||
}
|
||||
@@ -84,14 +79,14 @@ public class CraftTrimMaterial implements TrimMaterial, io.papermc.paper.util.Ho
|
||||
@NotNull
|
||||
@Override
|
||||
public String getTranslationKey() {
|
||||
if (!(this.handle.description().getContents() instanceof TranslatableContents)) throw new UnsupportedOperationException("Description isn't translatable!"); // Paper
|
||||
return ((TranslatableContents) this.handle.description().getContents()).getKey();
|
||||
if (!(this.getHandle().description().getContents() instanceof TranslatableContents)) throw new UnsupportedOperationException("Description isn't translatable!"); // Paper
|
||||
return ((TranslatableContents) this.getHandle().description().getContents()).getKey();
|
||||
}
|
||||
|
||||
// Paper start - adventure
|
||||
@Override
|
||||
public net.kyori.adventure.text.Component description() {
|
||||
return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.handle.description());
|
||||
return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getHandle().description());
|
||||
}
|
||||
// Paper end - adventure
|
||||
}
|
||||
|
||||
@@ -30,9 +30,6 @@ public class CraftTrimPattern implements TrimPattern, io.papermc.paper.util.Hold
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.TRIM_PATTERN); // Paper - switch to Holder
|
||||
}
|
||||
|
||||
private final NamespacedKey key;
|
||||
private final net.minecraft.world.item.equipment.trim.TrimPattern handle;
|
||||
|
||||
// Paper start - switch to Holder
|
||||
private final Holder<net.minecraft.world.item.equipment.trim.TrimPattern> holder; // Paper - switch to Holder
|
||||
|
||||
@@ -64,8 +61,6 @@ public class CraftTrimPattern implements TrimPattern, io.papermc.paper.util.Hold
|
||||
}
|
||||
|
||||
public CraftTrimPattern(Holder<net.minecraft.world.item.equipment.trim.TrimPattern> handle) {
|
||||
this.key = handle.unwrapKey().map(io.papermc.paper.util.MCUtil::fromResourceKey).orElse(null);
|
||||
this.handle = handle.value();
|
||||
this.holder = handle;
|
||||
// Paper end - switch to Holder
|
||||
}
|
||||
@@ -84,14 +79,14 @@ public class CraftTrimPattern implements TrimPattern, io.papermc.paper.util.Hold
|
||||
@NotNull
|
||||
@Override
|
||||
public String getTranslationKey() {
|
||||
if (!(this.handle.description().getContents() instanceof TranslatableContents)) throw new UnsupportedOperationException("Description isn't translatable!"); // Paper
|
||||
return ((TranslatableContents) this.handle.description().getContents()).getKey();
|
||||
if (!(this.getHandle().description().getContents() instanceof TranslatableContents)) throw new UnsupportedOperationException("Description isn't translatable!"); // Paper
|
||||
return ((TranslatableContents) this.getHandle().description().getContents()).getKey();
|
||||
}
|
||||
|
||||
// Paper start - adventure
|
||||
@Override
|
||||
public net.kyori.adventure.text.Component description() {
|
||||
return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.handle.description());
|
||||
return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getHandle().description());
|
||||
}
|
||||
// Paper end - adventure
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class CraftEnchantmentView extends CraftInventoryView<EnchantmentMenu, En
|
||||
|
||||
@Override
|
||||
public void setOffers(@NotNull final EnchantmentOffer[] offers) {
|
||||
Preconditions.checkArgument(offers.length != 3, "There must be 3 offers given");
|
||||
Preconditions.checkArgument(offers.length == 3, "There must be 3 offers given");
|
||||
IdMap<Holder<Enchantment>> registry = CraftRegistry.getMinecraftRegistry().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap();
|
||||
for (int i = 0; i < offers.length; i++) {
|
||||
final EnchantmentOffer offer = offers[i];
|
||||
|
||||
@@ -282,6 +282,7 @@ public class FieldRename {
|
||||
.change("PONDER", "PONDER_GOAT_HORN")
|
||||
.change("SING", "SING_GOAT_HORN")
|
||||
.change("SEEK", "SEEK_GOAT_HORN")
|
||||
.change("FEEL", "FEEL_GOAT_HORN")
|
||||
.change("ADMIRE", "ADMIRE_GOAT_HORN")
|
||||
.change("CALL", "CALL_GOAT_HORN")
|
||||
.change("YEARN", "YEARN_GOAT_HORN")
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@@ -19,9 +20,9 @@ import org.bukkit.map.MapView;
|
||||
|
||||
public final class CraftMapView implements MapView {
|
||||
|
||||
private final Map<CraftPlayer, RenderData> renderCache = new HashMap<CraftPlayer, RenderData>();
|
||||
private final List<MapRenderer> renderers = new ArrayList<MapRenderer>();
|
||||
private final Map<MapRenderer, Map<CraftPlayer, CraftMapCanvas>> canvases = new HashMap<MapRenderer, Map<CraftPlayer, CraftMapCanvas>>();
|
||||
private final Map<CraftPlayer, RenderData> renderCache = new WeakHashMap<>();
|
||||
private final List<MapRenderer> renderers = new ArrayList<>();
|
||||
private final Map<MapRenderer, Map<CraftPlayer, CraftMapCanvas>> canvases = new HashMap<>();
|
||||
protected final MapItemSavedData worldMap;
|
||||
|
||||
public CraftMapView(MapItemSavedData worldMap) {
|
||||
@@ -99,7 +100,7 @@ public final class CraftMapView implements MapView {
|
||||
public void addRenderer(MapRenderer renderer) {
|
||||
if (!this.renderers.contains(renderer)) {
|
||||
this.renderers.add(renderer);
|
||||
this.canvases.put(renderer, new HashMap<CraftPlayer, CraftMapCanvas>());
|
||||
this.canvases.put(renderer, new WeakHashMap<>());
|
||||
renderer.initialize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Multimap;
|
||||
@@ -13,24 +14,34 @@ import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Stream;
|
||||
import io.papermc.paper.entity.EntitySerializationFlag;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.advancements.AdvancementHolder;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.item.ItemParser;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.datafix.DataFixers;
|
||||
import net.minecraft.util.datafix.fixes.References;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.alchemy.Potion;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
@@ -43,6 +54,7 @@ import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.UnsafeValues;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.advancement.Advancement;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.attribute.AttributeModifier;
|
||||
@@ -51,10 +63,12 @@ import org.bukkit.block.data.BlockData;
|
||||
// import org.bukkit.craftbukkit.CraftFeatureFlag; // Paper
|
||||
import org.bukkit.craftbukkit.CraftRegistry;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.craftbukkit.block.CraftBiome;
|
||||
import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageEffect;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageSourceBuilder;
|
||||
import org.bukkit.craftbukkit.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.legacy.CraftLegacy;
|
||||
import org.bukkit.craftbukkit.legacy.FieldRename;
|
||||
@@ -466,12 +480,6 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
return new CraftPotionType(namespacedKey, potionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DamageEffect getDamageEffect(String key) {
|
||||
Preconditions.checkArgument(key != null, "key cannot be null");
|
||||
return CraftDamageEffect.getById(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DamageSource.Builder createDamageSourceBuilder(DamageType damageType) {
|
||||
return new CraftDamageSourceBuilder(damageType);
|
||||
@@ -513,7 +521,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
Preconditions.checkNotNull(item, "null cannot be serialized");
|
||||
Preconditions.checkArgument(item.getType() != Material.AIR, "air cannot be serialized");
|
||||
|
||||
return serializeNbtToBytes((net.minecraft.nbt.CompoundTag) (item instanceof CraftItemStack ? ((CraftItemStack) item).handle : CraftItemStack.asNMSCopy(item)).save(MinecraftServer.getServer().registryAccess()));
|
||||
return serializeNbtToBytes((CompoundTag) (item instanceof CraftItemStack ? ((CraftItemStack) item).handle : CraftItemStack.asNMSCopy(item)).save(MinecraftServer.getServer().registryAccess()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -521,9 +529,9 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
Preconditions.checkNotNull(data, "null cannot be deserialized");
|
||||
Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing");
|
||||
|
||||
net.minecraft.nbt.CompoundTag compound = deserializeNbtFromBytes(data);
|
||||
CompoundTag compound = deserializeNbtFromBytes(data);
|
||||
final int dataVersion = compound.getInt("DataVersion");
|
||||
compound = ca.spottedleaf.moonrise.common.PlatformHooks.get().convertNBT(References.ITEM_STACK, MinecraftServer.getServer().fixerUpper, compound, dataVersion, this.getDataVersion()); // Paper - possibly use dataconverter
|
||||
compound = PlatformHooks.get().convertNBT(References.ITEM_STACK, MinecraftServer.getServer().fixerUpper, compound, dataVersion, this.getDataVersion()); // Paper - possibly use dataconverter
|
||||
return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow());
|
||||
}
|
||||
|
||||
@@ -558,32 +566,98 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serializeEntity(org.bukkit.entity.Entity entity) {
|
||||
public byte[] serializeEntity(org.bukkit.entity.Entity entity, EntitySerializationFlag... serializationFlags) {
|
||||
Preconditions.checkNotNull(entity, "null cannot be serialized");
|
||||
Preconditions.checkArgument(entity instanceof org.bukkit.craftbukkit.entity.CraftEntity, "only CraftEntities can be serialized");
|
||||
Preconditions.checkArgument(entity instanceof CraftEntity, "Only CraftEntities can be serialized");
|
||||
|
||||
net.minecraft.nbt.CompoundTag compound = new net.minecraft.nbt.CompoundTag();
|
||||
((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().serializeEntity(compound);
|
||||
Set<EntitySerializationFlag> flags = Set.of(serializationFlags);
|
||||
final boolean serializePassangers = flags.contains(EntitySerializationFlag.PASSENGERS);
|
||||
final boolean forceSerialization = flags.contains(EntitySerializationFlag.FORCE);
|
||||
final boolean allowPlayerSerialization = flags.contains(EntitySerializationFlag.PLAYER);
|
||||
final boolean allowMiscSerialization = flags.contains(EntitySerializationFlag.MISC);
|
||||
final boolean includeNonSaveable = allowPlayerSerialization || allowMiscSerialization;
|
||||
|
||||
net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle();
|
||||
(serializePassangers ? nmsEntity.getSelfAndPassengers() : Stream.of(nmsEntity)).forEach(e -> {
|
||||
// Ensure force flag is not needed
|
||||
Preconditions.checkArgument(
|
||||
(e.getBukkitEntity().isValid() && e.getBukkitEntity().isPersistent()) || forceSerialization,
|
||||
"Cannot serialize invalid or non-persistent entity %s(%s) without the FORCE flag",
|
||||
e.getType().toShortString(),
|
||||
e.getStringUUID()
|
||||
);
|
||||
|
||||
if (e instanceof Player) {
|
||||
// Ensure player flag is not needed
|
||||
Preconditions.checkArgument(
|
||||
allowPlayerSerialization,
|
||||
"Cannot serialize player(%s) without the PLAYER flag",
|
||||
e.getStringUUID()
|
||||
);
|
||||
} else {
|
||||
// Ensure player flag is not needed
|
||||
Preconditions.checkArgument(
|
||||
nmsEntity.getType().canSerialize() || allowMiscSerialization,
|
||||
"Cannot serialize misc non-saveable entity %s(%s) without the MISC flag",
|
||||
e.getType().toShortString(),
|
||||
e.getStringUUID()
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
CompoundTag compound = new CompoundTag();
|
||||
if (serializePassangers) {
|
||||
if (!nmsEntity.saveAsPassenger(compound, true, includeNonSaveable, forceSerialization)) {
|
||||
throw new IllegalArgumentException("Couldn't serialize entity");
|
||||
}
|
||||
} else {
|
||||
List<net.minecraft.world.entity.Entity> pass = new ArrayList<>(nmsEntity.getPassengers());
|
||||
nmsEntity.passengers = com.google.common.collect.ImmutableList.of();
|
||||
boolean serialized = nmsEntity.saveAsPassenger(compound, true, includeNonSaveable, forceSerialization);
|
||||
nmsEntity.passengers = com.google.common.collect.ImmutableList.copyOf(pass);
|
||||
if (!serialized) {
|
||||
throw new IllegalArgumentException("Couldn't serialize entity");
|
||||
}
|
||||
}
|
||||
return serializeNbtToBytes(compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.entity.Entity deserializeEntity(byte[] data, org.bukkit.World world, boolean preserveUUID) {
|
||||
public org.bukkit.entity.Entity deserializeEntity(byte[] data, World world, boolean preserveUUID, boolean preservePassengers) {
|
||||
Preconditions.checkNotNull(data, "null cannot be deserialized");
|
||||
Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing");
|
||||
Preconditions.checkArgument(data.length > 0, "Cannot deserialize empty data");
|
||||
|
||||
net.minecraft.nbt.CompoundTag compound = deserializeNbtFromBytes(data);
|
||||
CompoundTag compound = deserializeNbtFromBytes(data);
|
||||
int dataVersion = compound.getInt("DataVersion");
|
||||
compound = ca.spottedleaf.moonrise.common.PlatformHooks.get().convertNBT(References.ENTITY, MinecraftServer.getServer().fixerUpper, compound, dataVersion, this.getDataVersion()); // Paper - possibly use dataconverter
|
||||
if (!preserveUUID) {
|
||||
// Generate a new UUID so we don't have to worry about deserializing the same entity twice
|
||||
compound.remove("UUID");
|
||||
compound = PlatformHooks.get().convertNBT(References.ENTITY, MinecraftServer.getServer().fixerUpper, compound, dataVersion, this.getDataVersion()); // Paper - possibly use dataconverter
|
||||
if (!preservePassengers) {
|
||||
compound.remove("Passengers");
|
||||
}
|
||||
return net.minecraft.world.entity.EntityType.create(compound, ((org.bukkit.craftbukkit.CraftWorld) world).getHandle(), net.minecraft.world.entity.EntitySpawnReason.LOAD)
|
||||
.orElseThrow(() -> new IllegalArgumentException("An ID was not found for the data. Did you downgrade?")).getBukkitEntity();
|
||||
net.minecraft.world.entity.Entity nmsEntity = deserializeEntity(compound, ((CraftWorld) world).getHandle(), preserveUUID);
|
||||
return nmsEntity.getBukkitEntity();
|
||||
}
|
||||
|
||||
private byte[] serializeNbtToBytes(net.minecraft.nbt.CompoundTag compound) {
|
||||
private net.minecraft.world.entity.Entity deserializeEntity(CompoundTag compound, ServerLevel world, boolean preserveUUID) {
|
||||
if (!preserveUUID) {
|
||||
// Generate a new UUID, so we don't have to worry about deserializing the same entity twice
|
||||
compound.remove("UUID");
|
||||
}
|
||||
net.minecraft.world.entity.Entity nmsEntity = net.minecraft.world.entity.EntityType.create(compound, world, net.minecraft.world.entity.EntitySpawnReason.LOAD)
|
||||
.orElseThrow(() -> new IllegalArgumentException("An ID was not found for the data. Did you downgrade?"));
|
||||
if (compound.contains("Passengers", Tag.TAG_LIST)) {
|
||||
ListTag passengersCompound = compound.getList("Passengers", Tag.TAG_COMPOUND);
|
||||
for (Tag tag : passengersCompound) {
|
||||
if (!(tag instanceof CompoundTag serializedPassenger)) {
|
||||
continue;
|
||||
}
|
||||
net.minecraft.world.entity.Entity passengerEntity = deserializeEntity(serializedPassenger, world, preserveUUID);
|
||||
passengerEntity.startRiding(nmsEntity, true);
|
||||
}
|
||||
}
|
||||
return nmsEntity;
|
||||
}
|
||||
|
||||
private byte[] serializeNbtToBytes(CompoundTag compound) {
|
||||
compound.putInt("DataVersion", getDataVersion());
|
||||
java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();
|
||||
try {
|
||||
@@ -597,8 +671,8 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
private net.minecraft.nbt.CompoundTag deserializeNbtFromBytes(byte[] data) {
|
||||
net.minecraft.nbt.CompoundTag compound;
|
||||
private CompoundTag deserializeNbtFromBytes(byte[] data) {
|
||||
CompoundTag compound;
|
||||
try {
|
||||
compound = net.minecraft.nbt.NbtIo.readCompressed(
|
||||
new java.io.ByteArrayInputStream(data), net.minecraft.nbt.NbtAccounter.unlimitedHeap()
|
||||
|
||||
@@ -613,8 +613,8 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) {
|
||||
return this.handle.clip(raytrace1, blockposition);
|
||||
public BlockHitResult clip(ClipContext traverseContext, BlockPos traversePos) {
|
||||
return this.handle.clip(traverseContext, traversePos);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
io.papermc.paper.PaperServerInternalAPIBridge
|
||||
@@ -0,0 +1 @@
|
||||
io.papermc.paper.registry.data.InlinedRegistryBuilderProviderImpl
|
||||
@@ -22,6 +22,7 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.ShadowColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
@@ -278,6 +279,7 @@ class AdventureCodecsTest {
|
||||
style(TextDecoration.BOLD.withState(TextDecoration.State.NOT_SET)),
|
||||
style()
|
||||
.font(key("kyori", "kittens"))
|
||||
.shadowColor(ShadowColor.fromHexString("#FF00AAFF"))
|
||||
.color(NamedTextColor.RED)
|
||||
.decoration(TextDecoration.BOLD, true)
|
||||
.clickEvent(openUrl("https://github.com"))
|
||||
|
||||
@@ -25,7 +25,7 @@ public class RegistryLoadOrderTest {
|
||||
|
||||
private static boolean initInterface = false;
|
||||
private static boolean initAbstract = false;
|
||||
private static org.bukkit.Registry<Keyed> registry; // Paper - remap fix
|
||||
private static Registry<Keyed> registry;
|
||||
|
||||
public static Stream<Arguments> data() {
|
||||
return Stream.of(
|
||||
@@ -60,6 +60,7 @@ public class RegistryLoadOrderTest {
|
||||
|
||||
RegistryLoadOrderTest.registry = new CraftRegistry<>(keyedClass, minecraftRegistry, minecraftToBukkit, (namespacedKey, apiVersion) -> namespacedKey);
|
||||
this.testClassNotLoaded(init.get());
|
||||
((CraftRegistry<?, ?>) RegistryLoadOrderTest.registry).lockReferenceHolders();
|
||||
|
||||
Object testOne = RegistryLoadOrderTest.registry.get(new NamespacedKey("bukkit", "test-one"));
|
||||
Object otherTestOne = RegistryLoadOrderTest.registry.get(new NamespacedKey("bukkit", "test-one"));
|
||||
|
||||
Reference in New Issue
Block a user