mirror of
https://github.com/PaperMC/Paper.git
synced 2025-07-26 09:42:06 -07:00
Adventure 4.23.0 (#12690)
This commit is contained in:
@@ -11,7 +11,7 @@ java {
|
||||
|
||||
val annotationsVersion = "26.0.2"
|
||||
// Keep in sync with paper-server adventure-text-serializer-ansi dep
|
||||
val adventureVersion = "4.21.0"
|
||||
val adventureVersion = "4.23.0"
|
||||
val bungeeCordChatVersion = "1.21-R0.2-deprecated+build.21"
|
||||
val slf4jVersion = "2.0.16"
|
||||
val log4jVersion = "2.24.1"
|
||||
|
@@ -37,7 +37,7 @@ public enum SoundCategory implements Sound.Source.Provider {
|
||||
case PLAYERS -> Sound.Source.PLAYER;
|
||||
case AMBIENT -> Sound.Source.AMBIENT;
|
||||
case VOICE -> Sound.Source.VOICE;
|
||||
case UI -> throw new UnsupportedOperationException("Waiting on adventure release for the UI sound source"); // todo adventure
|
||||
case UI -> Sound.Source.UI;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -134,7 +134,7 @@ dependencies {
|
||||
implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
|
||||
implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21
|
||||
implementation("net.minecrell:terminalconsoleappender:1.3.0")
|
||||
implementation("net.kyori:adventure-text-serializer-ansi:4.21.0") // Keep in sync with adventureVersion from Paper-API build file
|
||||
implementation("net.kyori:adventure-text-serializer-ansi:4.23.0") // Keep in sync with adventureVersion from Paper-API build file
|
||||
runtimeConfiguration(sourceSets.main.map { it.runtimeClasspath })
|
||||
|
||||
/*
|
||||
|
@@ -2610,7 +2610,7 @@
|
||||
if (!this.receivedMovementThisTick) {
|
||||
this.player.setKnownMovement(Vec3.ZERO);
|
||||
}
|
||||
@@ -2078,4 +_,17 @@
|
||||
@@ -2078,4 +_,29 @@
|
||||
interface EntityInteraction {
|
||||
InteractionResult run(ServerPlayer player, Entity entity, InteractionHand hand);
|
||||
}
|
||||
@@ -2627,4 +2627,16 @@
|
||||
+ return event;
|
||||
+ }
|
||||
+ // Paper end - Add fail move event
|
||||
+
|
||||
+ // Paper start - Implement click callbacks with custom click action
|
||||
+ @Override
|
||||
+ public void handleCustomClickAction(final net.minecraft.network.protocol.common.ServerboundCustomClickActionPacket packet) {
|
||||
+ super.handleCustomClickAction(packet);
|
||||
+ if (packet.id().equals(io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CLICK_CALLBACK_RESOURCE_LOCATION)) {
|
||||
+ packet.payload().ifPresent(tag ->
|
||||
+ io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.tryRunCallback(this.player.getBukkitEntity(), tag)
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Implement click callbacks with custom click action
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package io.papermc.paper.adventure;
|
||||
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
@@ -14,6 +15,7 @@ import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.kyori.adventure.text.BlockNBTComponent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.EntityNBTComponent;
|
||||
@@ -37,6 +39,9 @@ import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.minecraft.commands.arguments.selector.SelectorPattern;
|
||||
import net.minecraft.core.UUIDUtil;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.nbt.TagParser;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.ComponentSerialization;
|
||||
import net.minecraft.network.chat.contents.KeybindContents;
|
||||
@@ -44,6 +49,7 @@ import net.minecraft.network.chat.contents.ScoreContents;
|
||||
import net.minecraft.network.chat.contents.TranslatableContents;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.item.Item;
|
||||
@@ -63,7 +69,14 @@ import static net.kyori.adventure.text.TranslationArgument.numeric;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
public final class AdventureCodecs {
|
||||
|
||||
public static final Codec<BinaryTagHolder> BINARY_TAG_HOLDER_CODEC = ExtraCodecs.NBT.flatComapMap(tag -> BinaryTagHolder.encode(tag, PaperAdventure.NBT_CODEC), api -> {
|
||||
try {
|
||||
final Tag tag = api.get(PaperAdventure.NBT_CODEC);
|
||||
return DataResult.success(tag);
|
||||
} catch (CommandSyntaxException e) {
|
||||
return DataResult.error(e::getMessage);
|
||||
}
|
||||
});
|
||||
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);
|
||||
|
||||
@@ -89,27 +102,37 @@ public final class AdventureCodecs {
|
||||
return Key.parseable(s) ? DataResult.success(Key.key(s)) : DataResult.error(() -> "Cannot convert " + s + " to adventure Key");
|
||||
}, Key::asString);
|
||||
|
||||
static final Function<ClickEvent, String> TEXT_PAYLOAD_EXTRACTOR = a -> ((ClickEvent.Payload.Text) a.payload()).value();
|
||||
|
||||
/*
|
||||
* Click
|
||||
*/
|
||||
static final MapCodec<ClickEvent> OPEN_URL_CODEC = mapCodec((instance) -> instance.group(
|
||||
ExtraCodecs.UNTRUSTED_URI.fieldOf("url").forGetter(a -> URI.create(!a.value().contains("://") ? "https://" + a.value() : a.value()))
|
||||
ExtraCodecs.UNTRUSTED_URI.fieldOf("url").forGetter(a -> {
|
||||
final String url = ((ClickEvent.Payload.Text) a.payload()).value();
|
||||
return URI.create(!url.contains("://") ? "https://" + url : url);
|
||||
}
|
||||
)
|
||||
).apply(instance, (url) -> ClickEvent.openUrl(url.toString())));
|
||||
static final MapCodec<ClickEvent> OPEN_FILE_CODEC = mapCodec((instance) -> instance.group(
|
||||
Codec.STRING.fieldOf("path").forGetter(ClickEvent::value)
|
||||
Codec.STRING.fieldOf("path").forGetter(TEXT_PAYLOAD_EXTRACTOR)
|
||||
).apply(instance, ClickEvent::openFile));
|
||||
static final MapCodec<ClickEvent> RUN_COMMAND_CODEC = mapCodec((instance) -> instance.group(
|
||||
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(ClickEvent::value)
|
||||
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(TEXT_PAYLOAD_EXTRACTOR)
|
||||
).apply(instance, ClickEvent::runCommand));
|
||||
static final MapCodec<ClickEvent> SUGGEST_COMMAND_CODEC = mapCodec((instance) -> instance.group(
|
||||
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(ClickEvent::value)
|
||||
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(TEXT_PAYLOAD_EXTRACTOR)
|
||||
).apply(instance, ClickEvent::suggestCommand));
|
||||
static final MapCodec<ClickEvent> CHANGE_PAGE_CODEC = mapCodec((instance) -> instance.group(
|
||||
ExtraCodecs.POSITIVE_INT.fieldOf("page").forGetter(a -> Integer.parseInt(a.value()))
|
||||
ExtraCodecs.POSITIVE_INT.fieldOf("page").forGetter(a -> ((ClickEvent.Payload.Int) a.payload()).integer())
|
||||
).apply(instance, ClickEvent::changePage));
|
||||
static final MapCodec<ClickEvent> COPY_TO_CLIPBOARD_CODEC = mapCodec((instance) -> instance.group(
|
||||
Codec.STRING.fieldOf("value").forGetter(ClickEvent::value)
|
||||
Codec.STRING.fieldOf("value").forGetter(TEXT_PAYLOAD_EXTRACTOR)
|
||||
).apply(instance, ClickEvent::copyToClipboard));
|
||||
static final MapCodec<ClickEvent> CUSTOM_CODEC = mapCodec((instance) -> instance.group(
|
||||
KEY_CODEC.fieldOf("id").forGetter(a -> ((ClickEvent.Payload.Custom) a.payload()).key()),
|
||||
BINARY_TAG_HOLDER_CODEC.fieldOf("payload").forGetter(a -> ((ClickEvent.Payload.Custom) a.payload()).nbt())
|
||||
).apply(instance, ClickEvent::custom));
|
||||
|
||||
static final ClickEventType OPEN_URL_CLICK_EVENT_TYPE = new ClickEventType(OPEN_URL_CODEC, "open_url");
|
||||
static final ClickEventType OPEN_FILE_CLICK_EVENT_TYPE = new ClickEventType(OPEN_FILE_CODEC, "open_file");
|
||||
@@ -117,7 +140,8 @@ public final class AdventureCodecs {
|
||||
static final ClickEventType SUGGEST_COMMAND_CLICK_EVENT_TYPE = new ClickEventType(SUGGEST_COMMAND_CODEC, "suggest_command");
|
||||
static final ClickEventType CHANGE_PAGE_CLICK_EVENT_TYPE = new ClickEventType(CHANGE_PAGE_CODEC, "change_page");
|
||||
static final ClickEventType COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE = new ClickEventType(COPY_TO_CLIPBOARD_CODEC, "copy_to_clipboard");
|
||||
static final Codec<ClickEventType> CLICK_EVENT_TYPE_CODEC = StringRepresentable.fromValues(() -> new ClickEventType[]{OPEN_URL_CLICK_EVENT_TYPE, OPEN_FILE_CLICK_EVENT_TYPE, RUN_COMMAND_CLICK_EVENT_TYPE, SUGGEST_COMMAND_CLICK_EVENT_TYPE, CHANGE_PAGE_CLICK_EVENT_TYPE, COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE});
|
||||
static final ClickEventType CUSTOM_CLICK_EVENT_TYPE = new ClickEventType(CUSTOM_CODEC, "custom");
|
||||
static final Codec<ClickEventType> CLICK_EVENT_TYPE_CODEC = StringRepresentable.fromValues(() -> new ClickEventType[]{OPEN_URL_CLICK_EVENT_TYPE, OPEN_FILE_CLICK_EVENT_TYPE, RUN_COMMAND_CLICK_EVENT_TYPE, SUGGEST_COMMAND_CLICK_EVENT_TYPE, CHANGE_PAGE_CLICK_EVENT_TYPE, COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE, CUSTOM_CLICK_EVENT_TYPE});
|
||||
|
||||
record ClickEventType(MapCodec<ClickEvent> codec, String id) implements StringRepresentable {
|
||||
@Override
|
||||
@@ -126,22 +150,16 @@ public final class AdventureCodecs {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Function<ClickEvent, ClickEventType> GET_CLICK_EVENT_TYPE = he -> {
|
||||
if (he.action() == ClickEvent.Action.OPEN_URL) {
|
||||
return OPEN_URL_CLICK_EVENT_TYPE;
|
||||
} else if (he.action() == ClickEvent.Action.OPEN_FILE) {
|
||||
return OPEN_FILE_CLICK_EVENT_TYPE;
|
||||
} else if (he.action() == ClickEvent.Action.RUN_COMMAND) {
|
||||
return RUN_COMMAND_CLICK_EVENT_TYPE;
|
||||
} else if (he.action() == ClickEvent.Action.SUGGEST_COMMAND) {
|
||||
return SUGGEST_COMMAND_CLICK_EVENT_TYPE;
|
||||
} else if (he.action() == ClickEvent.Action.CHANGE_PAGE) {
|
||||
return CHANGE_PAGE_CLICK_EVENT_TYPE;
|
||||
} else if (he.action() == ClickEvent.Action.COPY_TO_CLIPBOARD) {
|
||||
return COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE;
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
private static final Function<ClickEvent, ClickEventType> GET_CLICK_EVENT_TYPE =
|
||||
he -> switch (he.action()) {
|
||||
case OPEN_URL -> OPEN_URL_CLICK_EVENT_TYPE;
|
||||
case OPEN_FILE -> OPEN_FILE_CLICK_EVENT_TYPE;
|
||||
case RUN_COMMAND -> RUN_COMMAND_CLICK_EVENT_TYPE;
|
||||
case SUGGEST_COMMAND -> SUGGEST_COMMAND_CLICK_EVENT_TYPE;
|
||||
case CHANGE_PAGE -> CHANGE_PAGE_CLICK_EVENT_TYPE;
|
||||
case COPY_TO_CLIPBOARD -> COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE;
|
||||
case SHOW_DIALOG -> throw new UnsupportedOperationException(); // todo: dialog codec with dialog "api"
|
||||
case CUSTOM -> CUSTOM_CLICK_EVENT_TYPE;
|
||||
};
|
||||
|
||||
static final Codec<ClickEvent> CLICK_EVENT_CODEC = CLICK_EVENT_TYPE_CODEC.dispatch("action", GET_CLICK_EVENT_TYPE, ClickEventType::codec);
|
||||
|
@@ -35,8 +35,6 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import net.kyori.adventure.translation.TranslationRegistry;
|
||||
import net.kyori.adventure.translation.Translator;
|
||||
import net.kyori.adventure.util.Codec;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
@@ -78,16 +76,16 @@ import static java.util.Objects.requireNonNull;
|
||||
public final class PaperAdventure {
|
||||
private static final Pattern LOCALIZATION_PATTERN = Pattern.compile("%(?:(\\d+)\\$)?s");
|
||||
public static final ComponentFlattener FLATTENER = ComponentFlattener.basic().toBuilder()
|
||||
.nestingLimit(30) // todo: should this be configurable? a system property or config value?
|
||||
.complexMapper(TranslatableComponent.class, (translatable, consumer) -> {
|
||||
if (!Language.getInstance().has(translatable.key())) {
|
||||
for (final Translator source : GlobalTranslator.translator().sources()) {
|
||||
if (source instanceof TranslationRegistry registry && registry.contains(translatable.key())) {
|
||||
final Language language = Language.getInstance();
|
||||
final @Nullable String fallback = translatable.fallback();
|
||||
if (!language.has(translatable.key()) && (fallback == null || !language.has(fallback))) {
|
||||
if (GlobalTranslator.translator().canTranslate(translatable.key(), Locale.US)) {
|
||||
consumer.accept(GlobalTranslator.render(translatable, Locale.US));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
final @Nullable String fallback = translatable.fallback();
|
||||
final @NotNull String translated = Language.getInstance().getOrDefault(translatable.key(), fallback != null ? fallback : translatable.key());
|
||||
|
||||
final Matcher matcher = LOCALIZATION_PATTERN.matcher(translated);
|
||||
@@ -379,6 +377,7 @@ public final class PaperAdventure {
|
||||
case PLAYER -> SoundSource.PLAYERS;
|
||||
case AMBIENT -> SoundSource.AMBIENT;
|
||||
case VOICE -> SoundSource.VOICE;
|
||||
case UI -> SoundSource.UI;
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -1,24 +1,33 @@
|
||||
package io.papermc.paper.adventure.providers;
|
||||
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.event.ClickCallback;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage") // permitted provider
|
||||
public class ClickCallbackProviderImpl implements ClickCallback.Provider {
|
||||
private static final Key CLICK_CALLBACK_KEY = Key.key("paper", "click_callback");
|
||||
private static final String ID_KEY = "id";
|
||||
|
||||
public static final ResourceLocation CLICK_CALLBACK_RESOURCE_LOCATION = PaperAdventure.asVanilla(CLICK_CALLBACK_KEY);
|
||||
public static final CallbackManager CALLBACK_MANAGER = new CallbackManager();
|
||||
|
||||
@Override
|
||||
public @NotNull ClickEvent create(final @NotNull ClickCallback<Audience> callback, final ClickCallback.@NotNull Options options) {
|
||||
return ClickEvent.runCommand("/paper:callback " + CALLBACK_MANAGER.addCallback(callback, options));
|
||||
final CompoundTag tag = new CompoundTag();
|
||||
tag.putString(ID_KEY, CALLBACK_MANAGER.addCallback(callback, options).toString());
|
||||
return ClickEvent.custom(CLICK_CALLBACK_KEY, PaperAdventure.asBinaryTagHolder(tag));
|
||||
}
|
||||
|
||||
public static final class CallbackManager {
|
||||
@@ -48,12 +57,21 @@ public class ClickCallbackProviderImpl implements ClickCallback.Provider {
|
||||
}
|
||||
}
|
||||
|
||||
public void runCallback(final @NotNull Audience audience, final UUID id) {
|
||||
public void tryRunCallback(final @NotNull Audience audience, final Tag tag) {
|
||||
tag.asCompound().flatMap(t -> t.getString(ID_KEY)).ifPresent(s -> {
|
||||
final UUID id;
|
||||
try {
|
||||
id = UUID.fromString(s);
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
return;
|
||||
}
|
||||
|
||||
final StoredCallback callback = this.callbacks.get(id);
|
||||
if (callback != null && callback.valid()) { //TODO Message if expired/invalid?
|
||||
if (callback != null && callback.valid()) {
|
||||
callback.takeUse();
|
||||
callback.callback.accept(audience);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,35 +0,0 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import io.papermc.paper.adventure.providers.ClickCallbackProviderImpl;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
import java.util.UUID;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
public class CallbackCommand extends Command {
|
||||
|
||||
protected CallbackCommand(final String name) {
|
||||
super(name);
|
||||
this.description = "ClickEvent callback";
|
||||
this.usageMessage = "/callback <uuid>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final CommandSender sender, final String commandLabel, final String[] args) {
|
||||
if (args.length != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final UUID id;
|
||||
try {
|
||||
id = UUID.fromString(args[0]);
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClickCallbackProviderImpl.CALLBACK_MANAGER.runCallback(sender, id);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -23,7 +23,6 @@ public final class PaperCommands {
|
||||
|
||||
public static void registerCommands(final MinecraftServer server) {
|
||||
COMMANDS.put("paper", new PaperCommand("paper"));
|
||||
COMMANDS.put("callback", new CallbackCommand("callback"));
|
||||
COMMANDS.put("mspt", new MSPTCommand("mspt"));
|
||||
|
||||
COMMANDS.forEach((s, command) -> {
|
||||
|
@@ -29,6 +29,7 @@ import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import net.kyori.adventure.pointer.PointersSupplier;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
@@ -157,6 +158,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
public static final int CUSTOM_DIMENSION_OFFSET = 10;
|
||||
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
||||
private static final PointersSupplier<World> POINTERS_SUPPLIER = PointersSupplier.<World>builder()
|
||||
.resolving(net.kyori.adventure.identity.Identity.NAME, World::getName)
|
||||
.resolving(net.kyori.adventure.identity.Identity.UUID, World::getUID)
|
||||
.build();
|
||||
|
||||
private final ServerLevel world;
|
||||
private WorldBorder worldBorder;
|
||||
@@ -168,7 +173,6 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this);
|
||||
private final Object2IntOpenHashMap<SpawnCategory> spawnCategoryLimit = new Object2IntOpenHashMap<>();
|
||||
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftWorld.DATA_TYPE_REGISTRY);
|
||||
private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
|
||||
// Paper start - void damage configuration
|
||||
private boolean voidDamageEnabled;
|
||||
private float voidDamageAmount;
|
||||
@@ -2481,14 +2485,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
// Paper start - implement pointers
|
||||
@Override
|
||||
public net.kyori.adventure.pointer.Pointers pointers() {
|
||||
if (this.adventure$pointers == null) {
|
||||
this.adventure$pointers = net.kyori.adventure.pointer.Pointers.builder()
|
||||
.withDynamic(net.kyori.adventure.identity.Identity.NAME, this::getName)
|
||||
.withDynamic(net.kyori.adventure.identity.Identity.UUID, this::getUID)
|
||||
.build();
|
||||
}
|
||||
|
||||
return this.adventure$pointers;
|
||||
return POINTERS_SUPPLIER.view(this);
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package org.bukkit.craftbukkit.command;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import net.kyori.adventure.pointer.PointersSupplier;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -12,8 +13,12 @@ import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public abstract class ServerCommandSender implements CommandSender {
|
||||
private static final PointersSupplier<ServerCommandSender> POINTERS_SUPPLIER = PointersSupplier.<ServerCommandSender>builder()
|
||||
.resolving(net.kyori.adventure.identity.Identity.DISPLAY_NAME, ServerCommandSender::name)
|
||||
.resolving(net.kyori.adventure.permission.PermissionChecker.POINTER, serverCommandSender -> serverCommandSender::permissionValue)
|
||||
.build();
|
||||
|
||||
public final PermissibleBase perm;
|
||||
private net.kyori.adventure.pointer.Pointers adventure$pointers;
|
||||
|
||||
protected ServerCommandSender() {
|
||||
this.perm = new PermissibleBase(this);
|
||||
@@ -126,13 +131,6 @@ public abstract class ServerCommandSender implements CommandSender {
|
||||
|
||||
@Override
|
||||
public net.kyori.adventure.pointer.Pointers pointers() {
|
||||
if (this.adventure$pointers == null) {
|
||||
this.adventure$pointers = net.kyori.adventure.pointer.Pointers.builder()
|
||||
.withDynamic(net.kyori.adventure.identity.Identity.DISPLAY_NAME, this::name)
|
||||
.withStatic(net.kyori.adventure.permission.PermissionChecker.POINTER, this::permissionValue)
|
||||
.build();
|
||||
}
|
||||
|
||||
return this.adventure$pointers;
|
||||
return POINTERS_SUPPLIER.view(this);
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import io.papermc.paper.entity.LookAnchor;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import net.kyori.adventure.pointer.PointersSupplier;
|
||||
import net.kyori.adventure.util.TriState;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@@ -85,13 +86,17 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
|
||||
private static PermissibleBase perm;
|
||||
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
||||
static final PointersSupplier<org.bukkit.entity.Entity> POINTERS_SUPPLIER = PointersSupplier.<org.bukkit.entity.Entity>builder()
|
||||
.resolving(net.kyori.adventure.identity.Identity.DISPLAY_NAME, org.bukkit.entity.Entity::name)
|
||||
.resolving(net.kyori.adventure.identity.Identity.UUID, org.bukkit.entity.Entity::getUniqueId)
|
||||
.resolving(net.kyori.adventure.permission.PermissionChecker.POINTER, entity1 -> entity1::permissionValue)
|
||||
.build();
|
||||
|
||||
protected final CraftServer server;
|
||||
protected Entity entity;
|
||||
private final EntityType entityType;
|
||||
private EntityDamageEvent lastDamageEvent;
|
||||
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftEntity.DATA_TYPE_REGISTRY);
|
||||
protected net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
|
||||
// Paper start - Folia shedulers
|
||||
public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this);
|
||||
private final io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler apiScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler(this);
|
||||
@@ -670,15 +675,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
|
||||
@Override
|
||||
public net.kyori.adventure.pointer.Pointers pointers() {
|
||||
if (this.adventure$pointers == null) {
|
||||
this.adventure$pointers = net.kyori.adventure.pointer.Pointers.builder()
|
||||
.withDynamic(net.kyori.adventure.identity.Identity.DISPLAY_NAME, this::name)
|
||||
.withDynamic(net.kyori.adventure.identity.Identity.UUID, this::getUniqueId)
|
||||
.withStatic(net.kyori.adventure.permission.PermissionChecker.POINTER, this::permissionValue)
|
||||
.build();
|
||||
}
|
||||
|
||||
return this.adventure$pointers;
|
||||
return POINTERS_SUPPLIER.view(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -44,6 +44,8 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.pointer.PointersSupplier;
|
||||
import net.kyori.adventure.util.TriState;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.minecraft.advancements.AdvancementProgress;
|
||||
@@ -213,6 +215,12 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
@DelegateDeserialization(CraftOfflinePlayer.class)
|
||||
public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
private static final PointersSupplier<Player> POINTERS_SUPPLIER = PointersSupplier.<Player>builder()
|
||||
.parent(CraftEntity.POINTERS_SUPPLIER)
|
||||
.resolving(Identity.NAME, Player::getName)
|
||||
.resolving(Identity.DISPLAY_NAME, Player::displayName)
|
||||
.resolving(Identity.LOCALE, Player::locale)
|
||||
.build();
|
||||
|
||||
private long firstPlayed = 0;
|
||||
private long lastPlayed = 0;
|
||||
@@ -3283,17 +3291,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public net.kyori.adventure.pointer.Pointers pointers() {
|
||||
if (this.adventure$pointers == null) {
|
||||
this.adventure$pointers = net.kyori.adventure.pointer.Pointers.builder()
|
||||
.withDynamic(net.kyori.adventure.identity.Identity.DISPLAY_NAME, this::displayName)
|
||||
.withDynamic(net.kyori.adventure.identity.Identity.NAME, this::getName)
|
||||
.withDynamic(net.kyori.adventure.identity.Identity.UUID, this::getUniqueId)
|
||||
.withStatic(net.kyori.adventure.permission.PermissionChecker.POINTER, this::permissionValue)
|
||||
.withDynamic(net.kyori.adventure.identity.Identity.LOCALE, this::locale)
|
||||
.build();
|
||||
}
|
||||
|
||||
return this.adventure$pointers;
|
||||
return POINTERS_SUPPLIER.view(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -11,11 +11,14 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.kyori.adventure.text.BlockNBTComponent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
@@ -106,23 +109,35 @@ class AdventureCodecsTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = PARAMETERIZED_NAME)
|
||||
@EnumSource(value = ClickEvent.Action.class, mode = EnumSource.Mode.EXCLUDE, names = {"OPEN_FILE"})
|
||||
@EnumSource(value = ClickEvent.Action.class, mode = EnumSource.Mode.EXCLUDE, names = {"OPEN_FILE", "SHOW_DIALOG", "CUSTOM"})
|
||||
void testClickEvent(final ClickEvent.Action action) {
|
||||
final ClickEvent event = ClickEvent.clickEvent(action, action.name().equals("OPEN_URL") ? "https://google.com" : "1337");
|
||||
final Tag result = CLICK_EVENT_CODEC.encodeStart(NbtOps.INSTANCE, event).result().orElseThrow();
|
||||
final ClickEvent event = switch (action) {
|
||||
case OPEN_URL -> openUrl("https://google.com");
|
||||
case RUN_COMMAND -> ClickEvent.runCommand("/say hello");
|
||||
case SUGGEST_COMMAND -> suggestCommand("/suggest hello");
|
||||
case CHANGE_PAGE -> ClickEvent.changePage(2);
|
||||
case COPY_TO_CLIPBOARD -> ClickEvent.copyToClipboard("clipboard content");
|
||||
case CUSTOM -> ClickEvent.custom(key("test"), BinaryTagHolder.binaryTagHolder("3"));
|
||||
case SHOW_DIALOG, OPEN_FILE -> throw new IllegalArgumentException();
|
||||
};
|
||||
final Tag result = CLICK_EVENT_CODEC.encodeStart(NbtOps.INSTANCE, event).result().orElseThrow(() -> new RuntimeException("Failed to encode ClickEvent: " + event));
|
||||
final net.minecraft.network.chat.ClickEvent nms = net.minecraft.network.chat.ClickEvent.CODEC.decode(NbtOps.INSTANCE, result).result().orElseThrow().getFirst();
|
||||
assertEquals(event.action().toString(), nms.action().getSerializedName());
|
||||
switch (nms) {
|
||||
case net.minecraft.network.chat.ClickEvent.OpenUrl(java.net.URI uri) ->
|
||||
assertEquals(event.value(), uri.toString());
|
||||
case net.minecraft.network.chat.ClickEvent.OpenUrl(URI uri) ->
|
||||
assertEquals(((ClickEvent.Payload.Text) event.payload()).value(), uri.toString());
|
||||
case net.minecraft.network.chat.ClickEvent.SuggestCommand(String command) ->
|
||||
assertEquals(event.value(), command);
|
||||
assertEquals(((ClickEvent.Payload.Text) event.payload()).value(), command);
|
||||
case net.minecraft.network.chat.ClickEvent.RunCommand(String command) ->
|
||||
assertEquals(event.value(), command);
|
||||
assertEquals(((ClickEvent.Payload.Text) event.payload()).value(), command);
|
||||
case net.minecraft.network.chat.ClickEvent.CopyToClipboard(String value) ->
|
||||
assertEquals(event.value(), value);
|
||||
assertEquals(((ClickEvent.Payload.Text) event.payload()).value(), value);
|
||||
case net.minecraft.network.chat.ClickEvent.ChangePage(int page) ->
|
||||
assertEquals(event.value(), String.valueOf(page));
|
||||
assertEquals(((ClickEvent.Payload.Int) event.payload()).integer(), page);
|
||||
case net.minecraft.network.chat.ClickEvent.Custom(ResourceLocation id, Optional<Tag> payload) -> {
|
||||
assertEquals(((ClickEvent.Payload.Custom) event.payload()).key().toString(), id.toString());
|
||||
assertEquals(((ClickEvent.Payload.Custom) event.payload()).nbt(), payload.orElseThrow().asString());
|
||||
}
|
||||
default -> throw new AssertionError("Unexpected ClickEvent type: " + nms.getClass());
|
||||
}
|
||||
}
|
||||
@@ -294,10 +309,10 @@ class AdventureCodecsTest {
|
||||
.clickEvent(openUrl("https://github.com"))
|
||||
.build(),
|
||||
style()
|
||||
.hoverEvent(HoverEvent.showEntity(HoverEvent.ShowEntity.showEntity(
|
||||
Key.key(Key.MINECRAFT_NAMESPACE, "pig"),
|
||||
.hoverEvent(showEntity(HoverEvent.ShowEntity.showEntity(
|
||||
key(Key.MINECRAFT_NAMESPACE, "pig"),
|
||||
UUID.randomUUID(),
|
||||
Component.text("Dolores", TextColor.color(0x0a1ab9))
|
||||
text("Dolores", color(0x0a1ab9))
|
||||
)))
|
||||
.build()
|
||||
);
|
||||
|
Reference in New Issue
Block a user