Dialog API (#12671)
This commit is contained in:
@@ -23867,7 +23867,7 @@ index 46de98a6bbbae48c4837e1e588ba198a363d2dde..fd3553bdc1c3cdbf6aa3dc00e0a4987f
|
||||
thread1 -> {
|
||||
DedicatedServer dedicatedServer1 = new DedicatedServer(
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 75aba65cbe1a943f21c7464ff9465e64f63e8e5b..32475c0958fd7e0f1f9b494b0cc78a4a718d12b8 100644
|
||||
index 03a616fc9b0325aa163fe4950ec4ce9ffdd3a9ea..b6aee251027cf124d6597137abefc7fd177358c9 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -173,7 +173,7 @@ import net.minecraft.world.phys.Vec2;
|
||||
@@ -24059,7 +24059,7 @@ index 75aba65cbe1a943f21c7464ff9465e64f63e8e5b..32475c0958fd7e0f1f9b494b0cc78a4a
|
||||
return true;
|
||||
} else {
|
||||
boolean ret = false; // Paper - force execution of all worlds, do not just bias the first
|
||||
@@ -2478,6 +2566,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2479,6 +2567,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,10 +48,10 @@ index 0000000000000000000000000000000000000000..24a2090e068ad3c0d08705050944abdf
|
||||
+ }
|
||||
+}
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index cff9d761dfee8a90b19fb2f3e678f99a39fc000c..0a260fdf6b198a8ab52e60bf6db2fb5eab719c48 100644
|
||||
index 41e24da7f0c120af96446603d234ddd417b0de60..7c5b6973769f6eda97f5a08a974b43a98f276ac7 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1718,6 +1718,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1719,6 +1719,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
|
||||
serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
|
||||
serverLevel.updateLagCompensationTick(); // Paper - lag compensation
|
||||
|
||||
+9
-9
@@ -6,10 +6,10 @@ Subject: [PATCH] Optimise collision checking in player move packet handling
|
||||
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index ff2f83dc1cbf10baccd07e65c894dff1d2f9a3cf..63d01c3753b865532a222b5b7408c8857c064d55 100644
|
||||
index 08aba415735733f5968fd032ab7ca249cdcf6cde..ee4397711625344622c81424afd11fd6d967efba 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -594,6 +594,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -606,6 +606,7 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
rootVehicle.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
|
||||
@@ -17,7 +17,7 @@ index ff2f83dc1cbf10baccd07e65c894dff1d2f9a3cf..63d01c3753b865532a222b5b7408c885
|
||||
double verticalDelta = d4;
|
||||
d3 = d - rootVehicle.getX();
|
||||
d4 = d1 - rootVehicle.getY();
|
||||
@@ -605,12 +606,21 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -617,12 +618,21 @@ public class ServerGamePacketListenerImpl
|
||||
d7 = d3 * d3 + d4 * d4 + d5 * d5;
|
||||
boolean flag1 = false;
|
||||
if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
|
||||
@@ -42,7 +42,7 @@ index ff2f83dc1cbf10baccd07e65c894dff1d2f9a3cf..63d01c3753b865532a222b5b7408c885
|
||||
rootVehicle.absSnapTo(x, y, z, f, f1);
|
||||
this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle));
|
||||
rootVehicle.removeLatestMovementRecording();
|
||||
@@ -689,9 +699,32 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -701,9 +711,32 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
private boolean noBlocksAround(Entity entity) {
|
||||
@@ -78,7 +78,7 @@ index ff2f83dc1cbf10baccd07e65c894dff1d2f9a3cf..63d01c3753b865532a222b5b7408c885
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1467,7 +1500,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1479,7 +1512,7 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ index ff2f83dc1cbf10baccd07e65c894dff1d2f9a3cf..63d01c3753b865532a222b5b7408c885
|
||||
d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -1506,6 +1539,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1518,6 +1551,7 @@ public class ServerGamePacketListenerImpl
|
||||
boolean flag1 = this.player.verticalCollisionBelow;
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
|
||||
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||
@@ -95,7 +95,7 @@ index ff2f83dc1cbf10baccd07e65c894dff1d2f9a3cf..63d01c3753b865532a222b5b7408c885
|
||||
// Paper start - prevent position desync
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
return; // ... thanks Mojang for letting move calls teleport across dimensions.
|
||||
@@ -1538,7 +1572,17 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1550,7 +1584,17 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
// Paper start - Add fail move event
|
||||
@@ -114,7 +114,7 @@ index ff2f83dc1cbf10baccd07e65c894dff1d2f9a3cf..63d01c3753b865532a222b5b7408c885
|
||||
if (!allowMovement) {
|
||||
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
|
||||
toX, toY, toZ, toYaw, toPitch, false);
|
||||
@@ -1674,7 +1718,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1686,7 +1730,7 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
private boolean updateAwaitingTeleport() {
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
@@ -123,7 +123,7 @@ index ff2f83dc1cbf10baccd07e65c894dff1d2f9a3cf..63d01c3753b865532a222b5b7408c885
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
this.teleport(
|
||||
this.awaitingPositionFromClient.x,
|
||||
@@ -1693,6 +1737,33 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1705,6 +1749,33 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ index 962084054c0208470d0c3c99c5dca6327c9b8752..2abc21102bbd2da79dc0c50826cff7da
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index 140f0ac42626662354e9b5386d91f1b096a945a3..2e7c4c74818befd25e296b58ef9f20319544c2fb 100644
|
||||
index 1b42d5e9f9fd07f99009de6f4483648f416db733..08c59d603fca038fc2dde36384eea1b6c971e659 100644
|
||||
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
@@ -38,12 +38,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
@@ -137,7 +137,7 @@ index 140f0ac42626662354e9b5386d91f1b096a945a3..2e7c4c74818befd25e296b58ef9f2031
|
||||
// Paper end
|
||||
}
|
||||
|
||||
@@ -93,13 +95,41 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
@@ -99,13 +101,41 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
|
||||
@Override
|
||||
public void handleKeepAlive(ServerboundKeepAlivePacket packet) {
|
||||
@@ -185,7 +185,7 @@ index 140f0ac42626662354e9b5386d91f1b096a945a3..2e7c4c74818befd25e296b58ef9f2031
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -220,20 +250,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
@@ -232,20 +262,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
protected void keepConnectionAlive() {
|
||||
Profiler.get().push("keepAlive");
|
||||
long millis = Util.getMillis();
|
||||
@@ -223,7 +223,7 @@ index 140f0ac42626662354e9b5386d91f1b096a945a3..2e7c4c74818befd25e296b58ef9f2031
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,6 +446,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
@@ -425,6 +458,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
}
|
||||
|
||||
protected CommonListenerCookie createCookie(ClientInformation clientInformation) {
|
||||
|
||||
@@ -20,7 +20,7 @@ index 5f2deeb5cc01d8bbeb7449bd4e59c466b3dfdf57..82824ae7ffbced513a8bcace684af949
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 0a260fdf6b198a8ab52e60bf6db2fb5eab719c48..52fa5112cd90ba766c94512a02401dd3aee82cc9 100644
|
||||
index 382d2b6b53bd144f4d56dccdc603ed0da8fe07a7..7aac2a6889af3edaebfaf94deecbf00d00758b68 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1654,33 +1654,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -63,9 +63,9 @@ index 0a260fdf6b198a8ab52e60bf6db2fb5eab719c48..52fa5112cd90ba766c94512a02401dd3
|
||||
- });
|
||||
- // Paper end - Folia scheduler API
|
||||
+ // Paper end - optimise Folia entity scheduler
|
||||
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.ADVENTURE_CLICK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||
profilerFiller.push("commandFunctions");
|
||||
this.getFunctions().tick();
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index da880f52920b1101f23ef94f3fd0dbdea218c373..3d2c0a4d3a1f9d3e5cc6cd0cdb988ae1205de821 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
|
||||
@@ -984,7 +984,7 @@
|
||||
ObjectArrayList<GameProfile> list = new ObjectArrayList<>(min);
|
||||
int randomInt = Mth.nextInt(this.random, 0, players.size() - min);
|
||||
|
||||
@@ -1040,17 +_,75 @@
|
||||
@@ -1040,17 +_,76 @@
|
||||
protected void tickChildren(BooleanSupplier hasTimeLeft) {
|
||||
ProfilerFiller profilerFiller = Profiler.get();
|
||||
this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing());
|
||||
@@ -1012,7 +1012,8 @@
|
||||
+ }
|
||||
+ });
|
||||
+ // Paper end - Folia scheduler API
|
||||
+ io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||
+ io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.ADVENTURE_CLICK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||
+ io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||
profilerFiller.push("commandFunctions");
|
||||
this.getFunctions().tick();
|
||||
profilerFiller.popPush("levels");
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
--- a/net/minecraft/server/dialog/body/ItemBody.java
|
||||
+++ b/net/minecraft/server/dialog/body/ItemBody.java
|
||||
@@ -15,8 +_,8 @@
|
||||
PlainMessage.CODEC.optionalFieldOf("description").forGetter(ItemBody::description),
|
||||
Codec.BOOL.optionalFieldOf("show_decorations", true).forGetter(ItemBody::showDecorations),
|
||||
Codec.BOOL.optionalFieldOf("show_tooltip", true).forGetter(ItemBody::showTooltip),
|
||||
- ExtraCodecs.intRange(1, 256).optionalFieldOf("width", 16).forGetter(ItemBody::width),
|
||||
- ExtraCodecs.intRange(1, 256).optionalFieldOf("height", 16).forGetter(ItemBody::height)
|
||||
+ ExtraCodecs.intRange(1, 256).optionalFieldOf("width", 16).forGetter(ItemBody::width), // Paper - diff on change - update builder defaults/limits
|
||||
+ ExtraCodecs.intRange(1, 256).optionalFieldOf("height", 16).forGetter(ItemBody::height) // Paper - diff on change - update builder defaults/limits
|
||||
)
|
||||
.apply(instance, ItemBody::new)
|
||||
);
|
||||
+21
-2
@@ -27,7 +27,7 @@
|
||||
|
||||
public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) {
|
||||
this.server = server;
|
||||
@@ -52,6 +_,11 @@
|
||||
@@ -52,7 +_,18 @@
|
||||
this.keepAliveTime = Util.getMillis();
|
||||
this.latency = cookie.latency();
|
||||
this.transferred = cookie.transferred();
|
||||
@@ -37,8 +37,15 @@
|
||||
+ this.pluginMessagerChannels = cookie.channels();
|
||||
+ // Paper end
|
||||
}
|
||||
+
|
||||
+ // Paper start - configuration phase API
|
||||
+ public abstract io.papermc.paper.connection.PlayerCommonConnection getApiConnection();
|
||||
+
|
||||
+ public abstract net.kyori.adventure.audience.Audience getAudience();
|
||||
+ // Paper end - configuration phase API
|
||||
|
||||
private void close() {
|
||||
if (!this.closed) {
|
||||
@@ -82,7 +_,7 @@
|
||||
this.latency = (this.latency * 3 + i) / 4;
|
||||
this.keepAlivePending = false;
|
||||
@@ -48,7 +55,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +_,76 @@
|
||||
@@ -90,14 +_,88 @@
|
||||
public void handlePong(ServerboundPongPacket packet) {
|
||||
}
|
||||
|
||||
@@ -124,6 +131,18 @@
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCustomClickAction(ServerboundCustomClickActionPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.server);
|
||||
this.server.handleCustomClickAction(packet.id(), packet.payload());
|
||||
+ // Paper start - Implement click callbacks with custom click action
|
||||
+ final io.papermc.paper.event.player.PaperPlayerCustomClickEvent event = new io.papermc.paper.event.player.PaperPlayerCustomClickEvent(io.papermc.paper.adventure.PaperAdventure.asAdventure(packet.id()), this.getApiConnection(), packet.payload().orElse(null));
|
||||
+ event.callEvent();
|
||||
+ io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.tryRunCallback(this.getAudience(), packet.id(), packet.payload());
|
||||
+ io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.ADVENTURE_CLICK_MANAGER.tryRunCallback(this.getAudience(), packet.id(), packet.payload());
|
||||
+ // Paper end - Implement click callbacks with custom click action
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,21 +_,46 @@
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.server);
|
||||
|
||||
+16
-2
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
@@ -47,11 +_,13 @@
|
||||
@@ -47,12 +_,26 @@
|
||||
public ClientInformation clientInformation;
|
||||
@Nullable
|
||||
private SynchronizeRegistriesTask synchronizeRegistriesTask;
|
||||
@@ -10,10 +10,24 @@
|
||||
super(server, connection, cookie);
|
||||
this.gameProfile = cookie.gameProfile();
|
||||
this.clientInformation = cookie.clientInformation();
|
||||
- }
|
||||
+ this.paperConnection = new io.papermc.paper.connection.PaperPlayerConfigurationConnection(this); // Paper
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - configuration phase API
|
||||
+ @Override
|
||||
+ public io.papermc.paper.connection.PlayerCommonConnection getApiConnection() {
|
||||
+ return this.paperConnection;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.kyori.adventure.audience.Audience getAudience() {
|
||||
+ return this.paperConnection.getAudience();
|
||||
+ }
|
||||
+ // Paper end - configuration phase API
|
||||
|
||||
@Override
|
||||
protected GameProfile playerProfile() {
|
||||
@@ -61,6 +_,11 @@
|
||||
|
||||
@Override
|
||||
|
||||
+17
-15
@@ -83,17 +83,31 @@
|
||||
|
||||
public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie cookie) {
|
||||
super(server, connection, cookie);
|
||||
@@ -268,7 +_,9 @@
|
||||
@@ -268,8 +_,22 @@
|
||||
player.connection = this;
|
||||
player.getTextFilter().join();
|
||||
this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(player.getUUID(), server::enforceSecureProfile);
|
||||
- this.chatMessageChain = new FutureChain(server);
|
||||
- }
|
||||
+ this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat
|
||||
+ this.tickEndEvent = new io.papermc.paper.event.packet.ClientTickEndEvent(player.getBukkitEntity()); // Paper - add client tick end event
|
||||
+ this.playerGameConnection = new io.papermc.paper.connection.PaperPlayerGameConnection(this); // Paper
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - configuration phase API
|
||||
+ @Override
|
||||
+ public io.papermc.paper.connection.PlayerCommonConnection getApiConnection() {
|
||||
+ return this.playerGameConnection;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.kyori.adventure.audience.Audience getAudience() {
|
||||
+ return this.getCraftPlayer();
|
||||
+ }
|
||||
+ // Paper end - configuration phase API
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
@@ -288,8 +_,8 @@
|
||||
this.knownMovePacketCount = this.receivedMovePacketCount;
|
||||
if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger() && !this.player.isDeadOrDying()) {
|
||||
@@ -2610,7 +2624,7 @@
|
||||
if (!this.receivedMovementThisTick) {
|
||||
this.player.setKnownMovement(Vec3.ZERO);
|
||||
}
|
||||
@@ -2078,4 +_,92 @@
|
||||
@@ -2078,4 +_,80 @@
|
||||
interface EntityInteraction {
|
||||
InteractionResult run(ServerPlayer player, Entity entity, InteractionHand hand);
|
||||
}
|
||||
@@ -2628,18 +2642,6 @@
|
||||
+ }
|
||||
+ // 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
|
||||
+
|
||||
+ // Paper start - add utilities
|
||||
+ public org.bukkit.craftbukkit.entity.CraftPlayer getCraftPlayer() {
|
||||
+ return this.player == null ? null : this.player.getBukkitEntity();
|
||||
|
||||
@@ -5,6 +5,9 @@ import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.registry.data.dialog.PaperDialogCodecs;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -13,7 +16,7 @@ import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import java.util.function.Supplier;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.kyori.adventure.text.BlockNBTComponent;
|
||||
@@ -36,12 +39,12 @@ 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;
|
||||
import net.kyori.adventure.util.Index;
|
||||
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;
|
||||
@@ -49,7 +52,6 @@ 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;
|
||||
@@ -98,7 +100,7 @@ public final class AdventureCodecs {
|
||||
}
|
||||
});
|
||||
|
||||
static final Codec<Key> KEY_CODEC = Codec.STRING.comapFlatMap(s -> {
|
||||
public static final Codec<Key> KEY_CODEC = Codec.STRING.comapFlatMap(s -> {
|
||||
return Key.parseable(s) ? DataResult.success(Key.key(s)) : DataResult.error(() -> "Cannot convert " + s + " to adventure Key");
|
||||
}, Key::asString);
|
||||
|
||||
@@ -129,6 +131,10 @@ public final class AdventureCodecs {
|
||||
static final MapCodec<ClickEvent> COPY_TO_CLIPBOARD_CODEC = mapCodec((instance) -> instance.group(
|
||||
Codec.STRING.fieldOf("value").forGetter(TEXT_PAYLOAD_EXTRACTOR)
|
||||
).apply(instance, ClickEvent::copyToClipboard));
|
||||
// needs to be lazy loaded due to depending on PaperDialogCodecs static init
|
||||
static final MapCodec<ClickEvent> SHOW_DIALOG_CODEC = MapCodec.recursive("show_dialog", ignored -> mapCodec((instance) -> instance.group(
|
||||
PaperDialogCodecs.DIALOG_CODEC.fieldOf("dialog").forGetter(a -> (Dialog) ((ClickEvent.Payload.Dialog) a.payload()).dialog())
|
||||
).apply(instance, ClickEvent::showDialog)));
|
||||
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())
|
||||
@@ -140,17 +146,19 @@ 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 ClickEventType SHOW_DIALOG_CLICK_EVENT_TYPE = new ClickEventType(SHOW_DIALOG_CODEC, "show_dialog");
|
||||
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});
|
||||
public static final Supplier<ClickEventType[]> CLICK_EVENT_TYPES = () -> 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, SHOW_DIALOG_CLICK_EVENT_TYPE, CUSTOM_CLICK_EVENT_TYPE};
|
||||
static final Codec<ClickEventType> CLICK_EVENT_TYPE_CODEC = StringRepresentable.fromValues(CLICK_EVENT_TYPES);
|
||||
|
||||
record ClickEventType(MapCodec<ClickEvent> codec, String id) implements StringRepresentable {
|
||||
public record ClickEventType(MapCodec<ClickEvent> codec, String id) implements StringRepresentable {
|
||||
@Override
|
||||
public String getSerializedName() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Function<ClickEvent, ClickEventType> GET_CLICK_EVENT_TYPE =
|
||||
public 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;
|
||||
@@ -158,7 +166,7 @@ public final class AdventureCodecs {
|
||||
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 SHOW_DIALOG -> SHOW_DIALOG_CLICK_EVENT_TYPE;
|
||||
case CUSTOM -> CUSTOM_CLICK_EVENT_TYPE;
|
||||
};
|
||||
|
||||
@@ -450,6 +458,23 @@ public final class AdventureCodecs {
|
||||
return component;
|
||||
}
|
||||
|
||||
public static final Codec<BinaryTagHolder> BINARY_TAG_HOLDER_COMPOUND_CODEC = CompoundTag.CODEC.flatComapMap(PaperAdventure::asBinaryTagHolder, api -> {
|
||||
try {
|
||||
final Tag tag = api.get(PaperAdventure.NBT_CODEC);
|
||||
if (!(tag instanceof final CompoundTag compoundTag)) {
|
||||
return DataResult.error(() -> "Expected a CompoundTag, but got " + tag.getClass().getSimpleName());
|
||||
}
|
||||
return DataResult.success(compoundTag);
|
||||
} catch (CommandSyntaxException e) {
|
||||
return DataResult.error(e::getMessage);
|
||||
}
|
||||
});
|
||||
|
||||
public static <T> Codec<T> indexCodec(final Index<String, T> index) {
|
||||
return Codec.of(Codec.STRING.comap(index::keyOrThrow), Codec.STRING.map(index::valueOrThrow));
|
||||
|
||||
}
|
||||
|
||||
private AdventureCodecs() {
|
||||
}
|
||||
}
|
||||
|
||||
+92
-36
@@ -1,15 +1,22 @@
|
||||
package io.papermc.paper.adventure.providers;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.dialog.PaperDialogResponseView;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogActionCallback;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
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.core.UUIDUtil;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@@ -17,30 +24,81 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@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";
|
||||
private static final Key ADVENTURE_CLICK_CALLBACK_KEY = Key.key("paper", "click_callback");
|
||||
public static final Key DIALOG_CLICK_CALLBACK_KEY = Key.key("paper", "dialog_click_callback");
|
||||
public 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();
|
||||
public static final AdventureClick ADVENTURE_CLICK_MANAGER = new AdventureClick();
|
||||
public static final DialogClickManager DIALOG_CLICK_MANAGER = new DialogClickManager();
|
||||
|
||||
@Override
|
||||
public @NotNull ClickEvent create(final @NotNull ClickCallback<Audience> callback, final ClickCallback.@NotNull Options 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));
|
||||
tag.store(ID_KEY, UUIDUtil.CODEC, ADVENTURE_CLICK_MANAGER.addCallback(callback, options));
|
||||
return ClickEvent.custom(ADVENTURE_CLICK_CALLBACK_KEY, PaperAdventure.asBinaryTagHolder(tag));
|
||||
}
|
||||
|
||||
public static final class CallbackManager {
|
||||
public static final class AdventureClick extends CallbackManager<ClickCallback<Audience>, UUID> {
|
||||
|
||||
private final Map<UUID, StoredCallback> callbacks = new HashMap<>();
|
||||
private final Queue<StoredCallback> queue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private CallbackManager() {
|
||||
private AdventureClick() {
|
||||
super(PaperAdventure.asVanilla(ADVENTURE_CLICK_CALLBACK_KEY)::equals);
|
||||
}
|
||||
|
||||
public UUID addCallback(final @NotNull ClickCallback<Audience> callback, final ClickCallback.@NotNull Options options) {
|
||||
final UUID id = UUID.randomUUID();
|
||||
this.queue.add(new StoredCallback(callback, options, id));
|
||||
return this.addCallback(UUID.randomUUID(), callback, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
void doRunCallback(final @NotNull Audience audience, final Key key, final Tag tag) {
|
||||
tag.asCompound().ifPresent(t -> {
|
||||
final Optional<UUID> id = t.read(ID_KEY, UUIDUtil.CODEC);
|
||||
if (id.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
this.tryConsumeCallback(id.get(), callback -> {
|
||||
callback.accept(audience);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static final class DialogClickManager extends CallbackManager<DialogActionCallback, UUID> {
|
||||
|
||||
public DialogClickManager() {
|
||||
super(PaperAdventure.asVanilla(DIALOG_CLICK_CALLBACK_KEY)::equals);
|
||||
}
|
||||
|
||||
@Override
|
||||
void doRunCallback(final @NotNull Audience audience, final Key key, final Tag tag) {
|
||||
tag.asCompound().ifPresent(t -> {
|
||||
final Optional<UUID> id = t.read(ID_KEY, UUIDUtil.CODEC);
|
||||
if (id.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
this.tryConsumeCallback(id.get(), callback -> {
|
||||
callback.accept(PaperDialogResponseView.createUnvalidatedResponse(t), audience);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract static class CallbackManager<C, I> {
|
||||
|
||||
private final Predicate<ResourceLocation> locationPredicate;
|
||||
protected final Map<I, StoredCallback<C, I>> callbacks = new HashMap<>();
|
||||
private final Queue<StoredCallback<C, I>> queue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
protected CallbackManager(final Predicate<ResourceLocation> locationPredicate) {
|
||||
this.locationPredicate = locationPredicate;
|
||||
}
|
||||
|
||||
protected CallbackManager() {
|
||||
this.locationPredicate = Predicates.alwaysTrue();
|
||||
}
|
||||
|
||||
public I addCallback(final I id, final @NotNull C callback, final ClickCallback.@NotNull Options options) {
|
||||
this.queue.add(new StoredCallback<>(callback, options, id));
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -51,38 +109,36 @@ public class ClickCallbackProviderImpl implements ClickCallback.Provider {
|
||||
}
|
||||
|
||||
// Add entries from queue
|
||||
StoredCallback callback;
|
||||
StoredCallback<C, I> callback;
|
||||
while ((callback = this.queue.poll()) != null) {
|
||||
this.callbacks.put(callback.id(), callback);
|
||||
}
|
||||
}
|
||||
|
||||
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 void tryConsumeCallback(final I key, final Consumer<? super C> callbackConsumer) {
|
||||
final StoredCallback<C, I> callback = this.callbacks.get(key);
|
||||
if (callback != null && callback.valid()) {
|
||||
callback.takeUse();
|
||||
callbackConsumer.accept(callback.callback);
|
||||
}
|
||||
}
|
||||
|
||||
final StoredCallback callback = this.callbacks.get(id);
|
||||
if (callback != null && callback.valid()) {
|
||||
callback.takeUse();
|
||||
callback.callback.accept(audience);
|
||||
}
|
||||
});
|
||||
abstract void doRunCallback(final @NotNull Audience audience, final Key key, final Tag tag);
|
||||
|
||||
public final void tryRunCallback(final @NotNull Audience audience, final ResourceLocation key, final Optional<? extends Tag> tag) {
|
||||
if (!this.locationPredicate.test(key) || tag.isEmpty()) return;
|
||||
this.doRunCallback(audience, PaperAdventure.asAdventure(key), tag.get());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class StoredCallback {
|
||||
public static final class StoredCallback<C, I> {
|
||||
private final long startedAt = System.nanoTime();
|
||||
private final ClickCallback<Audience> callback;
|
||||
private final C callback;
|
||||
private final long lifetime;
|
||||
private final UUID id;
|
||||
private final I id;
|
||||
private int remainingUses;
|
||||
|
||||
private StoredCallback(final @NotNull ClickCallback<Audience> callback, final ClickCallback.@NotNull Options options, final UUID id) {
|
||||
private StoredCallback(final @NotNull C callback, final ClickCallback.@NotNull Options options, final I id) {
|
||||
long lifetimeValue;
|
||||
this.callback = callback;
|
||||
try {
|
||||
@@ -95,7 +151,7 @@ public class ClickCallbackProviderImpl implements ClickCallback.Provider {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void takeUse() {
|
||||
private void takeUse() {
|
||||
if (this.remainingUses != ClickCallback.UNLIMITED_USES) {
|
||||
this.remainingUses--;
|
||||
}
|
||||
@@ -110,11 +166,11 @@ public class ClickCallbackProviderImpl implements ClickCallback.Provider {
|
||||
return System.nanoTime() - this.startedAt >= this.lifetime;
|
||||
}
|
||||
|
||||
public boolean valid() {
|
||||
return hasRemainingUses() && !expired();
|
||||
private boolean valid() {
|
||||
return this.hasRemainingUses() && !this.expired();
|
||||
}
|
||||
|
||||
public UUID id() {
|
||||
public I id() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
+25
-15
@@ -3,26 +3,31 @@ package io.papermc.paper.connection;
|
||||
import com.destroystokyo.paper.profile.CraftPlayerProfile;
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.dialog.PaperDialog;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.dialog.DialogLike;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.pointer.Pointers;
|
||||
import net.kyori.adventure.resource.ResourcePackCallback;
|
||||
import net.kyori.adventure.resource.ResourcePackInfo;
|
||||
import net.kyori.adventure.resource.ResourcePackRequest;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.common.ClientboundResourcePackPopPacket;
|
||||
import net.minecraft.network.protocol.common.ClientboundResourcePackPushPacket;
|
||||
import net.minecraft.network.protocol.common.ClientboundShowDialogPacket;
|
||||
import net.minecraft.network.protocol.configuration.ClientboundResetChatPacket;
|
||||
import net.minecraft.server.level.ClientInformation;
|
||||
import net.minecraft.server.network.ConfigurationTask;
|
||||
import net.minecraft.server.network.ServerConfigurationPacketListenerImpl;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PaperPlayerConfigurationConnection extends PaperCommonConnection<ServerConfigurationPacketListenerImpl> implements PlayerConfigurationConnection, Audience, PluginMessageBridgeImpl {
|
||||
|
||||
private @Nullable Pointers adventurePointers;
|
||||
@@ -37,13 +42,13 @@ public class PaperPlayerConfigurationConnection extends PaperCommonConnection<Se
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendResourcePacks(ResourcePackRequest request) {
|
||||
final List<ClientboundResourcePackPushPacket> packs = new java.util.ArrayList<>(request.packs().size());
|
||||
public void sendResourcePacks(final ResourcePackRequest request) {
|
||||
final List<ClientboundResourcePackPushPacket> packs = new ArrayList<>(request.packs().size());
|
||||
if (request.replace()) {
|
||||
this.clearResourcePacks();
|
||||
}
|
||||
final net.minecraft.network.chat.Component prompt = PaperAdventure.asVanilla(request.prompt());
|
||||
for (final java.util.Iterator<ResourcePackInfo> iter = request.packs().iterator(); iter.hasNext(); ) {
|
||||
final Component prompt = PaperAdventure.asVanilla(request.prompt());
|
||||
for (final Iterator<ResourcePackInfo> iter = request.packs().iterator(); iter.hasNext(); ) {
|
||||
final ResourcePackInfo pack = iter.next();
|
||||
packs.add(new ClientboundResourcePackPushPacket(pack.id(), pack.uri().toASCIIString(), pack.hash(), request.required(), iter.hasNext() ? Optional.empty() : Optional.ofNullable(prompt)));
|
||||
if (request.callback() != ResourcePackCallback.noOp()) {
|
||||
@@ -54,7 +59,7 @@ public class PaperPlayerConfigurationConnection extends PaperCommonConnection<Se
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeResourcePacks(UUID id, UUID... others) {
|
||||
public void removeResourcePacks(final UUID id, final UUID... others) {
|
||||
net.kyori.adventure.util.MonkeyBars.nonEmptyArrayToList(pack -> new ClientboundResourcePackPopPacket(Optional.of(pack)), id, others).forEach(this.handle::send);
|
||||
}
|
||||
|
||||
@@ -63,13 +68,18 @@ public class PaperPlayerConfigurationConnection extends PaperCommonConnection<Se
|
||||
this.handle.send(new ClientboundResourcePackPopPacket(Optional.empty()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDialog(final DialogLike dialog) {
|
||||
this.handle.send(new ClientboundShowDialogPacket(PaperDialog.bukkitToMinecraftHolder((Dialog) dialog)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointers pointers() {
|
||||
if (this.adventurePointers == null) {
|
||||
this.adventurePointers = Pointers.builder()
|
||||
.withDynamic(Identity.NAME, () -> this.handle.getOwner().getName())
|
||||
.withDynamic(Identity.UUID, () -> this.handle.getOwner().getId())
|
||||
.build();
|
||||
.withDynamic(Identity.NAME, () -> this.handle.getOwner().getName())
|
||||
.withDynamic(Identity.UUID, () -> this.handle.getOwner().getId())
|
||||
.build();
|
||||
}
|
||||
|
||||
return this.adventurePointers;
|
||||
@@ -92,7 +102,7 @@ public class PaperPlayerConfigurationConnection extends PaperCommonConnection<Se
|
||||
|
||||
@Override
|
||||
public void completeReconfiguration() {
|
||||
ConfigurationTask task = this.handle.currentTask;
|
||||
final ConfigurationTask task = this.handle.currentTask;
|
||||
if (task != null) {
|
||||
// This means that the player is going through the normal configuration process, or is already returning to the game phase.
|
||||
// Be safe and just ignore, as many plugins may call this.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package io.papermc.paper.dialog;
|
||||
|
||||
import io.papermc.paper.registry.HolderableBase;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import org.bukkit.craftbukkit.CraftRegistry;
|
||||
|
||||
public final class PaperDialog extends HolderableBase<net.minecraft.server.dialog.Dialog> implements Dialog {
|
||||
|
||||
public static net.minecraft.server.dialog.Dialog bukkitToMinecraft(final Dialog bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraft(bukkit);
|
||||
}
|
||||
|
||||
public static Holder<net.minecraft.server.dialog.Dialog> bukkitToMinecraftHolder(final Dialog bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public static Dialog minecraftToBukkit(final net.minecraft.server.dialog.Dialog minecraft) {
|
||||
return CraftRegistry.minecraftToBukkit(minecraft, Registries.DIALOG);
|
||||
}
|
||||
|
||||
public static Dialog minecraftHolderToBukkit(final Holder<net.minecraft.server.dialog.Dialog> minecraft) {
|
||||
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.DIALOG);
|
||||
}
|
||||
|
||||
public PaperDialog(final Holder<net.minecraft.server.dialog.Dialog> holder) {
|
||||
super(holder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package io.papermc.paper.dialog;
|
||||
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public class PaperDialogResponseView implements DialogResponseView {
|
||||
|
||||
private final CompoundTag payload;
|
||||
|
||||
private PaperDialogResponseView(final CompoundTag payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public static DialogResponseView createUnvalidatedResponse(final CompoundTag tag) {
|
||||
return new PaperDialogResponseView(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryTagHolder payload() {
|
||||
return BinaryTagHolder.encode(this.payload, PaperAdventure.NBT_CODEC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getText(final String key) {
|
||||
if (!this.payload.contains(key)) {
|
||||
return null;
|
||||
}
|
||||
return this.payload.getString(key).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Boolean getBoolean(final String key) {
|
||||
if (!this.payload.contains(key)) {
|
||||
return null;
|
||||
}
|
||||
return this.payload.getBoolean(key).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Float getFloat(final String key) {
|
||||
if (!this.payload.contains(key)) {
|
||||
return null;
|
||||
}
|
||||
return this.payload.getFloat(key).orElse(null);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package io.papermc.paper.event.player;
|
||||
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.connection.PlayerCommonConnection;
|
||||
import io.papermc.paper.dialog.DialogResponseView;
|
||||
import io.papermc.paper.dialog.PaperDialogResponseView;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public class PaperPlayerCustomClickEvent extends PlayerCustomClickEvent {
|
||||
|
||||
private final @Nullable Tag payload;
|
||||
private @Nullable BinaryTagHolder apiPayload;
|
||||
|
||||
private @Nullable DialogResponseView rawResponse;
|
||||
|
||||
public PaperPlayerCustomClickEvent(final Key key, final PlayerCommonConnection commonConnection, final @Nullable Tag payload) {
|
||||
super(key, commonConnection);
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable BinaryTagHolder getTag() {
|
||||
if (this.apiPayload == null && this.payload != null) {
|
||||
this.apiPayload = BinaryTagHolder.encode(this.payload, PaperAdventure.NBT_CODEC);
|
||||
}
|
||||
return this.apiPayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DialogResponseView getDialogResponseView() {
|
||||
if (this.payload == null || !(this.payload instanceof final CompoundTag compoundPayload)) {
|
||||
return null;
|
||||
}
|
||||
if (this.rawResponse == null) {
|
||||
this.rawResponse = PaperDialogResponseView.createUnvalidatedResponse(compoundPayload);
|
||||
}
|
||||
return this.rawResponse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@NullMarked
|
||||
package io.papermc.paper.event.player;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -4,6 +4,8 @@ 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.dialog.Dialog;
|
||||
import io.papermc.paper.dialog.PaperDialog;
|
||||
import io.papermc.paper.registry.data.PaperBannerPatternRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperCatTypeRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperChickenVariantRegistryEntry;
|
||||
@@ -18,6 +20,7 @@ import io.papermc.paper.registry.data.PaperPaintingVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperPigVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperSoundEventRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperWolfVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.dialog.PaperDialogRegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
@@ -132,6 +135,7 @@ public final class PaperRegistries {
|
||||
start(Registries.CHICKEN_VARIANT, RegistryKey.CHICKEN_VARIANT).craft(Chicken.Variant.class, CraftChicken.CraftVariant::new).writable(PaperChickenVariantRegistryEntry.PaperBuilder::new),
|
||||
start(Registries.COW_VARIANT, RegistryKey.COW_VARIANT).craft(Cow.Variant.class, CraftCow.CraftVariant::new).writable(PaperCowVariantRegistryEntry.PaperBuilder::new),
|
||||
start(Registries.PIG_VARIANT, RegistryKey.PIG_VARIANT).craft(Pig.Variant.class, CraftPig.CraftVariant::new).writable(PaperPigVariantRegistryEntry.PaperBuilder::new),
|
||||
start(Registries.DIALOG, RegistryKey.DIALOG).craft(Dialog.class, PaperDialog::new, true).writable(PaperDialogRegistryEntry.PaperBuilder::new),
|
||||
|
||||
// api-only
|
||||
start(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE).apiOnly(PaperSimpleRegistry::entityType),
|
||||
@@ -161,13 +165,13 @@ public final class PaperRegistries {
|
||||
}
|
||||
|
||||
@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);
|
||||
public static <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> RegistryEntryMeta.Buildable<M, T, B> getBuildableMeta(final RegistryKey<T> registryKey) {
|
||||
final RegistryEntry<M, T> entry = getEntry(registryKey);
|
||||
if (entry == null) {
|
||||
throw new IllegalArgumentException("No registry entry for " + resourceKey);
|
||||
throw new IllegalArgumentException("No registry entry for " + registryKey);
|
||||
}
|
||||
if (!(entry.meta() instanceof final RegistryEntryMeta.Buildable<M, T, ?> buildableMeta)) {
|
||||
throw new IllegalArgumentException("Registry entry for " + resourceKey + " is not buildable");
|
||||
throw new IllegalArgumentException("Registry entry for " + registryKey + " is not buildable");
|
||||
}
|
||||
return (RegistryEntryMeta.Buildable<M, T, B>) buildableMeta;
|
||||
}
|
||||
|
||||
+9
-2
@@ -1,15 +1,22 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.registry.RegistryBuilderFactory;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.data.dialog.DialogRegistryEntry;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import org.bukkit.MusicInstrument;
|
||||
|
||||
public final class InlinedRegistryBuilderProviderImpl implements InlinedRegistryBuilderProvider {
|
||||
|
||||
@Override
|
||||
public MusicInstrument createInstrument(final Consumer<RegistryBuilderFactory<MusicInstrument, ? extends InstrumentRegistryEntry.Builder>> value) {
|
||||
return Conversions.global().createApiInstanceFromBuilder(Registries.INSTRUMENT, value);
|
||||
return Conversions.global().createApiInstanceFromBuilder(RegistryKey.INSTRUMENT, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog createDialog(final Consumer<RegistryBuilderFactory<Dialog, ? extends DialogRegistryEntry.Builder>> value) {
|
||||
return Conversions.global().createApiInstanceFromBuilder(RegistryKey.DIALOG, value);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,13 +3,13 @@ package io.papermc.paper.registry.data;
|
||||
import io.papermc.paper.registry.PaperRegistries;
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.RegistryBuilderFactory;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.TypedKey;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import io.papermc.paper.registry.holder.PaperRegistryHolders;
|
||||
import io.papermc.paper.registry.holder.RegistryHolder;
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.item.Instrument;
|
||||
@@ -77,7 +77,7 @@ public class PaperInstrumentRegistryEntry implements InstrumentRegistryEntry {
|
||||
|
||||
@Override
|
||||
public Builder soundEvent(final Consumer<RegistryBuilderFactory<Sound, ? extends SoundEventRegistryEntry.Builder>> soundEvent) {
|
||||
this.soundEvent = this.conversions.createHolderFromBuilder(Registries.SOUND_EVENT, asArgument(soundEvent, "soundEvent"));
|
||||
this.soundEvent = this.conversions.createHolderFromBuilder(RegistryKey.SOUND_EVENT, asArgument(soundEvent, "soundEvent"));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -3,6 +3,7 @@ package io.papermc.paper.registry.data;
|
||||
import io.papermc.paper.registry.PaperRegistries;
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.RegistryBuilderFactory;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.TypedKey;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import io.papermc.paper.registry.holder.PaperRegistryHolders;
|
||||
@@ -10,7 +11,6 @@ import io.papermc.paper.registry.holder.RegistryHolder;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.item.JukeboxSong;
|
||||
@@ -80,7 +80,7 @@ public class PaperJukeboxSongRegistryEntry implements JukeboxSongRegistryEntry {
|
||||
|
||||
@Override
|
||||
public JukeboxSongRegistryEntry.Builder soundEvent(final Consumer<RegistryBuilderFactory<Sound, ? extends SoundEventRegistryEntry.Builder>> soundEvent) {
|
||||
this.soundEvent = this.conversions.createHolderFromBuilder(Registries.SOUND_EVENT, asArgument(soundEvent, "soundEvent"));
|
||||
this.soundEvent = this.conversions.createHolderFromBuilder(RegistryKey.SOUND_EVENT, asArgument(soundEvent, "soundEvent"));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package io.papermc.paper.registry.data.dialog;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.server.dialog.CommonButtonData;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record ActionButtonImpl(Component label, @Nullable Component tooltip, int width, @Nullable DialogAction action) implements ActionButton {
|
||||
|
||||
public static final class BuilderImpl implements ActionButton.Builder {
|
||||
|
||||
private final Component label;
|
||||
private @Nullable Component tooltip;
|
||||
private int width = CommonButtonData.DEFAULT_WIDTH;
|
||||
private @Nullable DialogAction action;
|
||||
|
||||
public BuilderImpl(final Component label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder tooltip(final @Nullable Component tooltip) {
|
||||
this.tooltip = tooltip;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder width(final int width) {
|
||||
Preconditions.checkArgument(width >= 1 && width <= 1024, "Width must be between 1 and 1024");
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder action(final @Nullable DialogAction action) {
|
||||
this.action = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionButton build() {
|
||||
return new ActionButtonImpl(this.label, this.tooltip, this.width, this.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package io.papermc.paper.registry.data.dialog;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.input.DialogInput;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record DialogBaseImpl(
|
||||
Component title,
|
||||
@Nullable Component externalTitle,
|
||||
boolean canCloseWithEscape,
|
||||
boolean pause,
|
||||
DialogAfterAction afterAction,
|
||||
@Unmodifiable List<DialogBody> body,
|
||||
@Unmodifiable List<DialogInput> inputs
|
||||
) implements DialogBase {
|
||||
|
||||
public DialogBaseImpl {
|
||||
Preconditions.checkArgument(!pause || afterAction != DialogAfterAction.NONE);
|
||||
body = List.copyOf(body);
|
||||
inputs = List.copyOf(inputs);
|
||||
}
|
||||
|
||||
public static final class BuilderImpl implements DialogBase.Builder {
|
||||
|
||||
private final Component title;
|
||||
private @Nullable Component externalTitle;
|
||||
private boolean canCloseWithEscape = true;
|
||||
private boolean pause = true;
|
||||
private DialogAfterAction afterAction = DialogAfterAction.CLOSE;
|
||||
private List<DialogBody> body = Collections.emptyList();
|
||||
private List<DialogInput> inputs = Collections.emptyList();
|
||||
|
||||
public BuilderImpl(final Component title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl externalTitle(final @Nullable Component externalTitle) {
|
||||
this.externalTitle = externalTitle;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl canCloseWithEscape(final boolean canCloseWithEscape) {
|
||||
this.canCloseWithEscape = canCloseWithEscape;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl pause(final boolean pause) {
|
||||
this.pause = pause;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl afterAction(final DialogAfterAction afterAction) {
|
||||
this.afterAction = afterAction;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl body(final List<? extends DialogBody> body) {
|
||||
this.body = List.copyOf(body);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl inputs(final List<? extends DialogInput> inputs) {
|
||||
this.inputs = List.copyOf(inputs);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogBase build() {
|
||||
return new DialogBaseImpl(this.title, this.externalTitle, this.canCloseWithEscape, this.pause, this.afterAction, this.body, this.inputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
package io.papermc.paper.registry.data.dialog;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import io.papermc.paper.adventure.AdventureCodecs;
|
||||
import io.papermc.paper.dialog.PaperDialog;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.body.ItemDialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.body.PlainMessageDialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.input.BooleanDialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.input.DialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.input.NumberRangeDialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.input.SingleOptionDialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.input.TextDialogInput;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.MappedRegistry;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.dialog.CommonButtonData;
|
||||
import net.minecraft.server.dialog.Dialog;
|
||||
import net.minecraft.server.dialog.action.ParsedTemplate;
|
||||
import net.minecraft.server.dialog.body.PlainMessage;
|
||||
import net.minecraft.server.dialog.input.TextInput;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
|
||||
import static io.papermc.paper.util.PaperCodecs.registryFileDecoderFor;
|
||||
|
||||
public final class PaperDialogCodecs {
|
||||
|
||||
private PaperDialogCodecs() {
|
||||
}
|
||||
|
||||
// dialog actions
|
||||
private static final MapCodec<DialogAction.CommandTemplateAction> COMMAND_TEMPLATE_ACTION_CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||||
instance.group(Codec.STRING.fieldOf("template").forGetter(DialogAction.CommandTemplateAction::template))
|
||||
.apply(instance, DialogAction::commandTemplate)
|
||||
);
|
||||
private static final MapCodec<DialogAction.CustomClickAction> CUSTOM_ALL_ACTION_CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||||
instance.group(AdventureCodecs.KEY_CODEC.fieldOf("id").forGetter(DialogAction.CustomClickAction::id), AdventureCodecs.BINARY_TAG_HOLDER_COMPOUND_CODEC.optionalFieldOf("additions").forGetter(action -> Optional.ofNullable(action.additions())))
|
||||
.apply(instance, (key, binaryTagHolder) -> DialogAction.customClick(key, binaryTagHolder.orElse(null)))
|
||||
);
|
||||
private static final Map<AdventureCodecs.ClickEventType, MapCodec<DialogAction.StaticAction>> STATIC_ACTION_CODECS = Arrays.stream(AdventureCodecs.CLICK_EVENT_TYPES.get()).collect(Collectors.toMap(Function.identity(), type -> type.codec().xmap(DialogAction::staticAction, DialogAction.StaticAction::value)));
|
||||
private static final Registry<MapCodec<? extends DialogAction>> DIALOG_ACTION_TYPES = Util.make(() -> {
|
||||
final MappedRegistry<MapCodec<? extends DialogAction>> registry = new MappedRegistry<>(ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(ResourceLocation.PAPER_NAMESPACE, "dialog_action_type")), Lifecycle.experimental());
|
||||
STATIC_ACTION_CODECS.forEach((clickType, actionCodec) -> {
|
||||
Registry.register(registry, clickType.getSerializedName(), actionCodec);
|
||||
});
|
||||
Registry.register(registry, "dynamic/run_command", COMMAND_TEMPLATE_ACTION_CODEC);
|
||||
Registry.register(registry, "dynamic/custom", CUSTOM_ALL_ACTION_CODEC);
|
||||
return registry.freeze();
|
||||
});
|
||||
private static final Function<DialogAction, MapCodec<? extends DialogAction>> GET_DIALOG_ACTION_TYPE = dialogAction -> switch (dialogAction) {
|
||||
case DialogAction.CommandTemplateAction $ -> COMMAND_TEMPLATE_ACTION_CODEC;
|
||||
case DialogAction.CustomClickAction $ -> CUSTOM_ALL_ACTION_CODEC;
|
||||
case DialogAction.StaticAction action -> STATIC_ACTION_CODECS.get(AdventureCodecs.GET_CLICK_EVENT_TYPE.apply(action.value()));
|
||||
};
|
||||
private static final Codec<DialogAction> DIALOG_ACTION_CODEC = DIALOG_ACTION_TYPES.byNameCodec().dispatch(GET_DIALOG_ACTION_TYPE, Function.identity());
|
||||
|
||||
// buttons
|
||||
public static final Codec<ActionButton> ACTION_BUTTON_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
AdventureCodecs.COMPONENT_CODEC.fieldOf("label").forGetter(ActionButton::label),
|
||||
AdventureCodecs.COMPONENT_CODEC.optionalFieldOf("tooltip").forGetter(button -> Optional.ofNullable(button.tooltip())),
|
||||
Dialog.WIDTH_CODEC.optionalFieldOf("width", CommonButtonData.DEFAULT_WIDTH).forGetter(ActionButton::width),
|
||||
DIALOG_ACTION_CODEC.optionalFieldOf("action").forGetter(button -> Optional.ofNullable(button.action()))
|
||||
).apply(instance, (label, tooltip, width, action) -> ActionButton.create(label, tooltip.orElse(null), width, action.orElse(null))));
|
||||
|
||||
// dialog bodies
|
||||
private static final MapCodec<PlainMessageDialogBody> PLAIN_MESSAGE_BODY_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
AdventureCodecs.COMPONENT_CODEC.fieldOf("contents").forGetter(PlainMessageDialogBody::contents),
|
||||
Dialog.WIDTH_CODEC.optionalFieldOf("width", PlainMessage.DEFAULT_WIDTH).forGetter(PlainMessageDialogBody::width)
|
||||
).apply(instance, DialogBody::plainMessage)
|
||||
);
|
||||
private static final Codec<PlainMessageDialogBody> SIMPLE_PLAIN_MESSAGE_BODY_CODEC = Codec.withAlternative(PLAIN_MESSAGE_BODY_CODEC.codec(), AdventureCodecs.COMPONENT_CODEC, component -> DialogBody.plainMessage(component, PlainMessage.DEFAULT_WIDTH));
|
||||
private static final MapCodec<ItemDialogBody> ITEM_BODY_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ItemStack.STRICT_CODEC.xmap(CraftItemStack::asBukkitCopy, CraftItemStack::asNMSCopy).fieldOf("item").forGetter(ItemDialogBody::item),
|
||||
SIMPLE_PLAIN_MESSAGE_BODY_CODEC.optionalFieldOf("description").forGetter(body -> Optional.ofNullable(body.description())),
|
||||
Codec.BOOL.optionalFieldOf("show_decorations", true).forGetter(ItemDialogBody::showDecorations),
|
||||
Codec.BOOL.optionalFieldOf("show_tooltip", true).forGetter(ItemDialogBody::showTooltip),
|
||||
ExtraCodecs.intRange(1, 256).optionalFieldOf("width", 16).forGetter(ItemDialogBody::width),
|
||||
ExtraCodecs.intRange(1, 256).optionalFieldOf("height", 16).forGetter(ItemDialogBody::height)
|
||||
).apply(instance, (itemStack, plainMessageBody, showDecorations, showTooltip, width, height) -> DialogBody.item(itemStack, plainMessageBody.orElse(null), showDecorations, showTooltip, width, height))
|
||||
);
|
||||
private static final Registry<MapCodec<? extends DialogBody>> DIALOG_BODY_TYPES = Util.make(() -> {
|
||||
final MappedRegistry<MapCodec<? extends DialogBody>> registry = new MappedRegistry<>(ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(ResourceLocation.PAPER_NAMESPACE, "dialog_body_type")), Lifecycle.experimental());
|
||||
Registry.register(registry, "item", ITEM_BODY_CODEC);
|
||||
Registry.register(registry, "plain_message", PLAIN_MESSAGE_BODY_CODEC);
|
||||
return registry.freeze();
|
||||
});
|
||||
private static final Function<DialogBody, MapCodec<? extends DialogBody>> GET_DIALOG_BODY_TYPE = dialogAction -> switch (dialogAction) {
|
||||
case PlainMessageDialogBody $ -> PLAIN_MESSAGE_BODY_CODEC;
|
||||
case ItemDialogBody $ -> ITEM_BODY_CODEC;
|
||||
};
|
||||
private static final Codec<DialogBody> DIALOG_BODY_CODEC = DIALOG_BODY_TYPES.byNameCodec().dispatch(GET_DIALOG_BODY_TYPE, Function.identity());
|
||||
private static final Codec<List<DialogBody>> DIALOG_BODY_LIST_CODEC = ExtraCodecs.compactListCodec(DIALOG_BODY_CODEC);
|
||||
|
||||
// input types
|
||||
private static final MapCodec<BooleanDialogInput> BOOLEAN_DIALOG_INPUT_TYPE_MAP_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ParsedTemplate.VARIABLE_CODEC.fieldOf("key").forGetter(DialogInput::key),
|
||||
AdventureCodecs.COMPONENT_CODEC.fieldOf("label").forGetter(BooleanDialogInput::label),
|
||||
Codec.BOOL.optionalFieldOf("initial", false).forGetter(BooleanDialogInput::initial),
|
||||
Codec.STRING.optionalFieldOf("on_true", "true").forGetter(BooleanDialogInput::onTrue),
|
||||
Codec.STRING.optionalFieldOf("on_false", "false").forGetter(BooleanDialogInput::onFalse)
|
||||
).apply(instance, DialogInput::bool));
|
||||
private static final MapCodec<NumberRangeDialogInput> NUMBER_RANGE_INPUT_MAP_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ParsedTemplate.VARIABLE_CODEC.fieldOf("key").forGetter(DialogInput::key),
|
||||
Dialog.WIDTH_CODEC.optionalFieldOf("width", PlainMessage.DEFAULT_WIDTH).forGetter(NumberRangeDialogInput::width),
|
||||
AdventureCodecs.COMPONENT_CODEC.fieldOf("label").forGetter(NumberRangeDialogInput::label),
|
||||
Codec.STRING.optionalFieldOf("label_format", "options.generic_value").forGetter(NumberRangeDialogInput::labelFormat),
|
||||
Codec.FLOAT.fieldOf("start").forGetter(NumberRangeDialogInput::start),
|
||||
Codec.FLOAT.fieldOf("end").forGetter(NumberRangeDialogInput::end),
|
||||
Codec.FLOAT.optionalFieldOf("initial").forGetter(type -> Optional.ofNullable(type.initial())),
|
||||
ExtraCodecs.POSITIVE_FLOAT.optionalFieldOf("step").forGetter(type -> Optional.ofNullable(type.step()))
|
||||
).apply(instance, (key, width, label, labelFormat, start, end, initial, step) -> DialogInput.numberRange(key, width, label, labelFormat, start, end, initial.orElse(null), step.orElse(null))));
|
||||
private static final Codec<SingleOptionDialogInput.OptionEntry> SINGLE_OPTION_DIALOG_INPUT_ENTRY_FULL_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Codec.STRING.fieldOf("id").forGetter(SingleOptionDialogInput.OptionEntry::id),
|
||||
AdventureCodecs.COMPONENT_CODEC.optionalFieldOf("display").forGetter(entry -> Optional.ofNullable(entry.display())),
|
||||
Codec.BOOL.optionalFieldOf("initial", false).forGetter(SingleOptionDialogInput.OptionEntry::initial)
|
||||
).apply(instance, (id, display, initial) -> SingleOptionDialogInput.OptionEntry.create(id, display.orElse(null), initial)));
|
||||
private static final Codec<SingleOptionDialogInput.OptionEntry> SINGLE_OPTION_DIALOG_INPUT_ENTRY_CODEC = Codec.withAlternative(
|
||||
SINGLE_OPTION_DIALOG_INPUT_ENTRY_FULL_CODEC, Codec.STRING, string -> SingleOptionDialogInput.OptionEntry.create(string, null, false)
|
||||
);
|
||||
private static final MapCodec<SingleOptionDialogInput> SINGLE_OPTION_DIALOG_INPUT_TYPE_MAP_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ParsedTemplate.VARIABLE_CODEC.fieldOf("key").forGetter(DialogInput::key),
|
||||
Dialog.WIDTH_CODEC.optionalFieldOf("width", PlainMessage.DEFAULT_WIDTH).forGetter(SingleOptionDialogInput::width),
|
||||
ExtraCodecs.nonEmptyList(SINGLE_OPTION_DIALOG_INPUT_ENTRY_CODEC.listOf()).fieldOf("options").forGetter(SingleOptionDialogInput::entries),
|
||||
AdventureCodecs.COMPONENT_CODEC.fieldOf("label").forGetter(SingleOptionDialogInput::label),
|
||||
Codec.BOOL.optionalFieldOf("label_visible", true).forGetter(SingleOptionDialogInput::labelVisible)
|
||||
).apply(instance, DialogInput::singleOption));
|
||||
private static final Codec<TextDialogInput.MultilineOptions> TEXT_DIALOG_INPUT_MULTILINE_OPTIONS_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
ExtraCodecs.POSITIVE_INT.optionalFieldOf("max_lines").forGetter(options -> Optional.ofNullable(options.maxLines())),
|
||||
ExtraCodecs.intRange(1, TextInput.MultilineOptions.MAX_HEIGHT).optionalFieldOf("height").forGetter(options -> Optional.ofNullable(options.height()))
|
||||
).apply(instance, (maxLines, height) -> TextDialogInput.MultilineOptions.create(maxLines.orElse(null), height.orElse(null))));
|
||||
private static final MapCodec<TextDialogInput> TEXT_DIALOG_INPUT_TYPE_MAP_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ParsedTemplate.VARIABLE_CODEC.fieldOf("key").forGetter(DialogInput::key),
|
||||
Dialog.WIDTH_CODEC.optionalFieldOf("width", PlainMessage.DEFAULT_WIDTH).forGetter(TextDialogInput::width),
|
||||
AdventureCodecs.COMPONENT_CODEC.fieldOf("label").forGetter(TextDialogInput::label),
|
||||
Codec.BOOL.optionalFieldOf("label_visible", true).forGetter(TextDialogInput::labelVisible),
|
||||
Codec.STRING.optionalFieldOf("initial", "").forGetter(TextDialogInput::initial),
|
||||
ExtraCodecs.POSITIVE_INT.optionalFieldOf("max_length", 32).forGetter(TextDialogInput::maxLength),
|
||||
TEXT_DIALOG_INPUT_MULTILINE_OPTIONS_CODEC.optionalFieldOf("multiline").forGetter(inputType -> Optional.ofNullable(inputType.multiline()))
|
||||
).apply(instance, (key, width, label, labelVisible, initial, maxLength, multilineOptions) ->
|
||||
DialogInput.text(key, width, label, labelVisible, initial, maxLength, multilineOptions.orElse(null))
|
||||
));
|
||||
private static final Registry<MapCodec<? extends DialogInput>> DIALOG_INPUT_TYPES = Util.make(() -> {
|
||||
final MappedRegistry<MapCodec<? extends DialogInput>> registry = new MappedRegistry<>(ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(ResourceLocation.PAPER_NAMESPACE, "dialog_input_type")), Lifecycle.experimental());
|
||||
Registry.register(registry, "boolean", BOOLEAN_DIALOG_INPUT_TYPE_MAP_CODEC);
|
||||
Registry.register(registry, "number_range", NUMBER_RANGE_INPUT_MAP_CODEC);
|
||||
Registry.register(registry, "single_option", SINGLE_OPTION_DIALOG_INPUT_TYPE_MAP_CODEC);
|
||||
Registry.register(registry, "text", TEXT_DIALOG_INPUT_TYPE_MAP_CODEC);
|
||||
return registry.freeze();
|
||||
});
|
||||
private static final Function<DialogInput, MapCodec<? extends DialogInput>> GET_DIALOG_INPUT_TYPE_TYPE = dialogAction -> switch (dialogAction) {
|
||||
case TextDialogInput $ -> TEXT_DIALOG_INPUT_TYPE_MAP_CODEC;
|
||||
case SingleOptionDialogInput $ -> SINGLE_OPTION_DIALOG_INPUT_TYPE_MAP_CODEC;
|
||||
case NumberRangeDialogInput $ -> NUMBER_RANGE_INPUT_MAP_CODEC;
|
||||
case BooleanDialogInput $ -> BOOLEAN_DIALOG_INPUT_TYPE_MAP_CODEC;
|
||||
};
|
||||
private static final Codec<DialogInput> DIALOG_INPUT_CODEC = DIALOG_INPUT_TYPES.byNameCodec().dispatchMap(GET_DIALOG_INPUT_TYPE_TYPE, Function.identity()).codec();
|
||||
|
||||
// dialog base / common dialog data
|
||||
public static final Codec<DialogBase> DIALOG_BASE_CODEC = RecordCodecBuilder.<DialogBase>mapCodec(instance -> instance.group(
|
||||
AdventureCodecs.COMPONENT_CODEC.fieldOf("title").forGetter(DialogBase::title),
|
||||
AdventureCodecs.COMPONENT_CODEC.optionalFieldOf("external_title").forGetter(base -> Optional.ofNullable(base.externalTitle())),
|
||||
Codec.BOOL.optionalFieldOf("can_close_with_escape", true).forGetter(DialogBase::canCloseWithEscape),
|
||||
Codec.BOOL.optionalFieldOf("pause", true).forGetter(DialogBase::pause),
|
||||
AdventureCodecs.indexCodec(DialogBase.DialogAfterAction.NAMES).optionalFieldOf("after_action", DialogBase.DialogAfterAction.CLOSE).forGetter(DialogBase::afterAction),
|
||||
DIALOG_BODY_LIST_CODEC.optionalFieldOf("body", List.of()).forGetter(DialogBase::body),
|
||||
DIALOG_INPUT_CODEC.listOf().optionalFieldOf("inputs", List.of()).forGetter(DialogBase::inputs)
|
||||
).apply(instance, (title, externalTitle, canCloseWithEsc, pause, afterAction, body, inputs) -> DialogBase.create(title, externalTitle.orElse(null), canCloseWithEsc, pause, afterAction, body, inputs))
|
||||
).codec();
|
||||
|
||||
public static final Codec<io.papermc.paper.dialog.Dialog> DIALOG_CODEC = Codec.of(Dialog.CODEC.comap(PaperDialog::bukkitToMinecraftHolder), registryFileDecoderFor(Dialog.DIRECT_CODEC, PaperDialog::minecraftHolderToBukkit, RegistryKey.DIALOG, true));
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
package io.papermc.paper.registry.data.dialog;
|
||||
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.adventure.providers.ClickCallbackProviderImpl;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.registry.data.dialog.action.CommandTemplateActionImpl;
|
||||
import io.papermc.paper.registry.data.dialog.action.CustomClickActionImpl;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogActionCallback;
|
||||
import io.papermc.paper.registry.data.dialog.action.StaticActionImpl;
|
||||
import io.papermc.paper.registry.data.dialog.body.ItemDialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.body.ItemDialogBodyImpl;
|
||||
import io.papermc.paper.registry.data.dialog.body.PlainMessageBodyImpl;
|
||||
import io.papermc.paper.registry.data.dialog.body.PlainMessageDialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.input.BooleanDialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.input.BooleanDialogInputImpl;
|
||||
import io.papermc.paper.registry.data.dialog.input.NumberRangeDialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.input.NumberRangeDialogInputImpl;
|
||||
import io.papermc.paper.registry.data.dialog.input.SingleOptionDialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.input.SingleOptionDialogInputImpl;
|
||||
import io.papermc.paper.registry.data.dialog.input.TextDialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.input.TextDialogInputImpl;
|
||||
import io.papermc.paper.registry.data.dialog.type.ConfirmationType;
|
||||
import io.papermc.paper.registry.data.dialog.type.ConfirmationTypeImpl;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogListType;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogListTypeImpl;
|
||||
import io.papermc.paper.registry.data.dialog.type.MultiActionType;
|
||||
import io.papermc.paper.registry.data.dialog.type.MultiActionTypeImpl;
|
||||
import io.papermc.paper.registry.data.dialog.type.NoticeType;
|
||||
import io.papermc.paper.registry.data.dialog.type.NoticeTypeImpl;
|
||||
import io.papermc.paper.registry.data.dialog.type.ServerLinksType;
|
||||
import io.papermc.paper.registry.data.dialog.type.ServerLinksTypeImpl;
|
||||
import io.papermc.paper.registry.set.RegistrySet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickCallback;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.minecraft.core.UUIDUtil;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public final class PaperDialogInstancesProvider implements DialogInstancesProvider {
|
||||
|
||||
@Override
|
||||
public DialogBase.Builder dialogBaseBuilder(final Component title) {
|
||||
return new DialogBaseImpl.BuilderImpl(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionButton.Builder actionButtonBuilder(final Component label) {
|
||||
return new ActionButtonImpl.BuilderImpl(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogAction.CustomClickAction register(final DialogActionCallback callback, final ClickCallback.Options options) {
|
||||
final UUID id = ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.addCallback(UUID.randomUUID(), callback, options);
|
||||
final CompoundTag tag = new CompoundTag();
|
||||
tag.store(ClickCallbackProviderImpl.ID_KEY, UUIDUtil.CODEC, id);
|
||||
return DialogAction.customClick(ClickCallbackProviderImpl.DIALOG_CLICK_CALLBACK_KEY, BinaryTagHolder.encode(tag, PaperAdventure.NBT_CODEC));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogAction.StaticAction staticAction(final ClickEvent value) {
|
||||
return new StaticActionImpl(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogAction.CommandTemplateAction commandTemplate(final String template) {
|
||||
return new CommandTemplateActionImpl(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogAction.CustomClickAction customClick(final Key id, final @Nullable BinaryTagHolder additions) {
|
||||
return new CustomClickActionImpl(id, additions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDialogBody.Builder itemDialogBodyBuilder(final ItemStack itemStack) {
|
||||
return new ItemDialogBodyImpl.BuilderImpl(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlainMessageDialogBody plainMessageDialogBody(final Component component) {
|
||||
return new PlainMessageBodyImpl(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlainMessageDialogBody plainMessageDialogBody(final Component component, final int width) {
|
||||
return new PlainMessageBodyImpl(component, width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanDialogInput.Builder booleanBuilder(final String key, final Component label) {
|
||||
return new BooleanDialogInputImpl.BuilderImpl(key, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberRangeDialogInput.Builder numberRangeBuilder(final String key, final Component label, final float start, final float end) {
|
||||
return new NumberRangeDialogInputImpl.BuilderImpl(key, label, start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleOptionDialogInput.Builder singleOptionBuilder(final String key, final Component label, final List<SingleOptionDialogInput.OptionEntry> entries) {
|
||||
return new SingleOptionDialogInputImpl.BuilderImpl(key, entries, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleOptionDialogInput.OptionEntry singleOptionEntry(final String id, final @Nullable Component display, final boolean initial) {
|
||||
return new SingleOptionDialogInputImpl.SingleOptionEntryImpl(id, display, initial);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDialogInput.Builder textBuilder(final String key, final Component label) {
|
||||
return new TextDialogInputImpl.BuilderImpl(key, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDialogInput.MultilineOptions multilineOptions(final @Nullable Integer maxLines, final @Nullable Integer height) {
|
||||
return new TextDialogInputImpl.MultilineOptionsImpl(maxLines, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfirmationType confirmation(final ActionButton yesButton, final ActionButton noButton) {
|
||||
return new ConfirmationTypeImpl(yesButton, noButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogListType.Builder dialogList(final RegistrySet<Dialog> dialogs) {
|
||||
return new DialogListTypeImpl.BuilderImpl(dialogs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiActionType.Builder multiAction(final List<ActionButton> actions) {
|
||||
return new MultiActionTypeImpl.BuilderImpl(actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoticeType notice() {
|
||||
return new NoticeTypeImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoticeType notice(final ActionButton action) {
|
||||
return new NoticeTypeImpl(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerLinksType serverLinks(final @Nullable ActionButton exitAction, final int columns, final int buttonWidth) {
|
||||
return new ServerLinksTypeImpl(exitAction, columns, buttonWidth);
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package io.papermc.paper.registry.data.dialog;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import io.papermc.paper.registry.set.RegistryValueSetBuilder;
|
||||
import io.papermc.paper.registry.set.RegistryValueSetBuilderImpl;
|
||||
import net.minecraft.server.dialog.CommonDialogData;
|
||||
import net.minecraft.server.dialog.Dialog;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperDialogRegistryEntry implements DialogRegistryEntry {
|
||||
|
||||
protected @Nullable DialogBase dialogBase;
|
||||
protected @Nullable DialogType dialogType;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperDialogRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable Dialog internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) return;
|
||||
|
||||
final CommonDialogData common = internal.common();
|
||||
this.dialogBase = conversions.convert(common, PaperDialogCodecs.DIALOG_BASE_CODEC, CommonDialogData.MAP_CODEC.codec());
|
||||
|
||||
this.dialogType = PaperDialogs.extractSpecialty(internal, conversions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogBase base() {
|
||||
return asConfigured(this.dialogBase, "dialogBase");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogType type() {
|
||||
return asConfigured(this.dialogType, "dialogSpecialty");
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperDialogRegistryEntry implements Builder, PaperRegistryBuilder<Dialog, io.papermc.paper.dialog.Dialog> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable Dialog internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistryValueSetBuilder<io.papermc.paper.dialog.Dialog, Builder> registryValueSet() {
|
||||
return new RegistryValueSetBuilderImpl<>(RegistryKey.DIALOG, this.conversions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder base(final DialogBase dialogBase) {
|
||||
this.dialogBase = asArgument(dialogBase, "dialogBase");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder type(final DialogType dialogType) {
|
||||
this.dialogType = asArgument(dialogType, "dialogSpecialty");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog build() {
|
||||
return PaperDialogs.constructDialog(this.base(), this.type(), this.conversions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package io.papermc.paper.registry.data.dialog;
|
||||
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.data.dialog.type.ConfirmationType;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogListType;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||
import io.papermc.paper.registry.data.dialog.type.MultiActionType;
|
||||
import io.papermc.paper.registry.data.dialog.type.NoticeType;
|
||||
import io.papermc.paper.registry.data.dialog.type.ServerLinksType;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import io.papermc.paper.registry.set.PaperRegistrySets;
|
||||
import io.papermc.paper.registry.set.RegistrySet;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.server.dialog.CommonDialogData;
|
||||
import net.minecraft.server.dialog.ConfirmationDialog;
|
||||
import net.minecraft.server.dialog.Dialog;
|
||||
import net.minecraft.server.dialog.DialogListDialog;
|
||||
import net.minecraft.server.dialog.MultiActionDialog;
|
||||
import net.minecraft.server.dialog.NoticeDialog;
|
||||
import net.minecraft.server.dialog.ServerLinksDialog;
|
||||
|
||||
public final class PaperDialogs {
|
||||
|
||||
private PaperDialogs() {
|
||||
}
|
||||
|
||||
public static DialogType extractSpecialty(final Dialog nmsDialog, final Conversions conversions) {
|
||||
final Function<net.minecraft.server.dialog.ActionButton, ActionButton> convertButton = button -> conversions.convert(button, PaperDialogCodecs.ACTION_BUTTON_CODEC, net.minecraft.server.dialog.ActionButton.CODEC);
|
||||
return switch (nmsDialog) {
|
||||
case final ConfirmationDialog conf ->
|
||||
DialogType.confirmation(convertButton.apply(conf.yesButton()), convertButton.apply(conf.noButton()));
|
||||
case final DialogListDialog list -> {
|
||||
final RegistrySet<io.papermc.paper.dialog.Dialog> apiSet = PaperRegistrySets.convertToApiWithDirects(RegistryKey.DIALOG, list.dialogs());
|
||||
yield DialogType.dialogList(
|
||||
apiSet,
|
||||
list.exitAction().map(convertButton).orElse(null),
|
||||
list.columns(),
|
||||
list.buttonWidth()
|
||||
);
|
||||
}
|
||||
case final MultiActionDialog multi ->
|
||||
DialogType.multiAction(multi.actions().stream().map(convertButton).toList(), multi.exitAction().map(convertButton).orElse(null), multi.columns());
|
||||
case final NoticeDialog notice -> DialogType.notice(convertButton.apply(notice.action()));
|
||||
case final ServerLinksDialog links ->
|
||||
DialogType.serverLinks(links.exitAction().map(convertButton).orElse(null), links.columns(), links.buttonWidth());
|
||||
default -> throw new IllegalArgumentException("Unsupported dialog type: " + nmsDialog.getClass().getName());
|
||||
};
|
||||
}
|
||||
|
||||
public static Dialog constructDialog(final DialogBase dialogBase, final DialogType dialogType, final Conversions conversions) {
|
||||
final Function<ActionButton, net.minecraft.server.dialog.ActionButton> convertButton = button -> conversions.convert(button, net.minecraft.server.dialog.ActionButton.CODEC, PaperDialogCodecs.ACTION_BUTTON_CODEC);
|
||||
final CommonDialogData common = conversions.convert(dialogBase, CommonDialogData.MAP_CODEC.codec(), PaperDialogCodecs.DIALOG_BASE_CODEC);
|
||||
switch (dialogType) {
|
||||
case final ConfirmationType conf -> {
|
||||
return new ConfirmationDialog(common, convertButton.apply(conf.yesButton()), convertButton.apply(conf.noButton()));
|
||||
}
|
||||
case final DialogListType list -> {
|
||||
return new DialogListDialog(
|
||||
common,
|
||||
PaperRegistrySets.convertToNmsWithDirects(Registries.DIALOG, conversions.lookup(), list.dialogs()),
|
||||
Optional.ofNullable(list.exitAction()).map(convertButton),
|
||||
list.columns(),
|
||||
list.buttonWidth()
|
||||
);
|
||||
}
|
||||
case final MultiActionType multi -> {
|
||||
return new MultiActionDialog(
|
||||
common,
|
||||
multi.actions().stream().map(convertButton).toList(),
|
||||
Optional.ofNullable(multi.exitAction()).map(convertButton),
|
||||
multi.columns()
|
||||
);
|
||||
}
|
||||
case final NoticeType notice -> {
|
||||
return new NoticeDialog(common, convertButton.apply(notice.action()));
|
||||
}
|
||||
case final ServerLinksType links -> {
|
||||
return new ServerLinksDialog(common, Optional.ofNullable(links.exitAction()).map(convertButton), links.columns(), links.buttonWidth());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package io.papermc.paper.registry.data.dialog.action;
|
||||
|
||||
import net.minecraft.commands.functions.StringTemplate;
|
||||
|
||||
public record CommandTemplateActionImpl(String template) implements DialogAction.CommandTemplateAction {
|
||||
|
||||
public CommandTemplateActionImpl {
|
||||
StringTemplate.fromString(template);
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package io.papermc.paper.registry.data.dialog.action;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record CustomClickActionImpl(Key id, @Nullable BinaryTagHolder additions) implements DialogAction.CustomClickAction {
|
||||
|
||||
public CustomClickActionImpl {
|
||||
if (additions != null) {
|
||||
try {
|
||||
final Tag tag = additions.get(PaperAdventure.NBT_CODEC);
|
||||
Preconditions.checkArgument(tag instanceof CompoundTag, "Additions must be a compound tag");
|
||||
} catch (final CommandSyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package io.papermc.paper.registry.data.dialog.action;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
public record StaticActionImpl(ClickEvent value) implements DialogAction.StaticAction {
|
||||
|
||||
public StaticActionImpl {
|
||||
Preconditions.checkArgument(value.action().readable(), "action must be readable");
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package io.papermc.paper.registry.data.dialog.body;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record ItemDialogBodyImpl(
|
||||
ItemStack item, @Nullable PlainMessageDialogBody description, boolean showDecorations, boolean showTooltip, int width, int height
|
||||
) implements ItemDialogBody {
|
||||
|
||||
public static final class BuilderImpl implements ItemDialogBody.Builder {
|
||||
|
||||
private final ItemStack item;
|
||||
private @Nullable PlainMessageDialogBody description;
|
||||
private boolean showDecorations = true;
|
||||
private boolean showTooltip = true;
|
||||
private int width = 16;
|
||||
private int height = 16;
|
||||
|
||||
public BuilderImpl(final ItemStack item) {
|
||||
net.minecraft.world.item.ItemStack.validateStrict(CraftItemStack.unwrap(item)).getOrThrow();
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDialogBody.Builder description(final @Nullable PlainMessageDialogBody description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDialogBody.Builder showDecorations(final boolean showDecorations) {
|
||||
this.showDecorations = showDecorations;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDialogBody.Builder showTooltip(final boolean showTooltip) {
|
||||
this.showTooltip = showTooltip;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDialogBody.Builder width(final int width) {
|
||||
Preconditions.checkArgument(width >= 1 && width <= 256, "Width must be between 1 and 256");
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDialogBody.Builder height(final int height) {
|
||||
Preconditions.checkArgument(this.width >= 1 && this.width <= 256, "Width must be between 1 and 256");
|
||||
this.height = height;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDialogBody build() {
|
||||
return new ItemDialogBodyImpl(this.item, this.description, this.showDecorations, this.showTooltip, this.width, this.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package io.papermc.paper.registry.data.dialog.body;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.server.dialog.body.PlainMessage;
|
||||
|
||||
public record PlainMessageBodyImpl(Component contents, int width) implements PlainMessageDialogBody {
|
||||
|
||||
public PlainMessageBodyImpl {
|
||||
Preconditions.checkArgument(width >= 1 && width <= 1024, "Width must be between 1 and 1024");
|
||||
}
|
||||
|
||||
public PlainMessageBodyImpl(final Component contents) {
|
||||
this(contents, PlainMessage.DEFAULT_WIDTH);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package io.papermc.paper.registry.data.dialog.input;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.commands.functions.StringTemplate;
|
||||
|
||||
public record BooleanDialogInputImpl(String key, Component label, boolean initial, String onTrue, String onFalse) implements BooleanDialogInput {
|
||||
|
||||
public static final class BuilderImpl implements BooleanDialogInput.Builder {
|
||||
|
||||
private final String key;
|
||||
private final Component label;
|
||||
private boolean initial = false;
|
||||
private String onTrue = "true";
|
||||
private String onFalse = "false";
|
||||
|
||||
public BuilderImpl(final String key, final Component label) {
|
||||
Preconditions.checkArgument(StringTemplate.isValidVariableName(key), "key must be a valid input name");
|
||||
this.key = key;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanDialogInput.Builder initial(final boolean initial) {
|
||||
this.initial = initial;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanDialogInput.Builder onTrue(final String onTrue) {
|
||||
this.onTrue = onTrue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanDialogInput.Builder onFalse(final String onFalse) {
|
||||
this.onFalse = onFalse;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanDialogInput build() {
|
||||
return new BooleanDialogInputImpl(this.key, this.label, this.initial, this.onTrue, this.onFalse);
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package io.papermc.paper.registry.data.dialog.input;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.commands.functions.StringTemplate;
|
||||
import net.minecraft.server.dialog.body.PlainMessage;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record NumberRangeDialogInputImpl(
|
||||
String key,
|
||||
int width,
|
||||
Component label,
|
||||
String labelFormat,
|
||||
float start,
|
||||
float end,
|
||||
@Nullable Float initial,
|
||||
@Nullable Float step
|
||||
) implements NumberRangeDialogInput {
|
||||
|
||||
public static final class BuilderImpl implements NumberRangeDialogInput.Builder {
|
||||
|
||||
private final String key;
|
||||
private final Component label;
|
||||
private final float start;
|
||||
private final float end;
|
||||
private int width = PlainMessage.DEFAULT_WIDTH;
|
||||
private String labelFormat = "options.generic_value";
|
||||
private @Nullable Float initial = null;
|
||||
private @Nullable Float step = null;
|
||||
|
||||
public BuilderImpl(final String key, final Component label, final float start, final float end) {
|
||||
Preconditions.checkArgument(StringTemplate.isValidVariableName(key), "key must be a valid input name");
|
||||
this.key = key;
|
||||
this.label = label;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl width(final int width) {
|
||||
Preconditions.checkArgument(width >= 1 && width <= 1024, "width must be between 1 and 1024");
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl labelFormat(final String labelFormat) {
|
||||
this.labelFormat = labelFormat;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl initial(final @Nullable Float initial) {
|
||||
if (initial != null) {
|
||||
Preconditions.checkArgument(initial >= this.start && initial <= this.end, "initial must be within the range");
|
||||
}
|
||||
this.initial = initial;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl step(final @Nullable Float step) {
|
||||
Preconditions.checkArgument(step == null || step > 0, "step must be null or greater than 0");
|
||||
this.step = step;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberRangeDialogInput build() {
|
||||
return new NumberRangeDialogInputImpl(this.key, this.width, this.label, this.labelFormat, this.start, this.end, this.initial, this.step);
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package io.papermc.paper.registry.data.dialog.input;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.commands.functions.StringTemplate;
|
||||
import net.minecraft.server.dialog.body.PlainMessage;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public record SingleOptionDialogInputImpl(
|
||||
String key,
|
||||
int width,
|
||||
List<SingleOptionDialogInput.OptionEntry> entries,
|
||||
Component label,
|
||||
boolean labelVisible
|
||||
) implements SingleOptionDialogInput {
|
||||
|
||||
public SingleOptionDialogInputImpl {
|
||||
entries = List.copyOf(entries);
|
||||
}
|
||||
|
||||
public record SingleOptionEntryImpl(String id, @Nullable Component display, boolean initial) implements OptionEntry {
|
||||
}
|
||||
|
||||
public static final class BuilderImpl implements SingleOptionDialogInput.Builder {
|
||||
|
||||
private final String key;
|
||||
private int width = PlainMessage.DEFAULT_WIDTH;
|
||||
private final List<OptionEntry> entries;
|
||||
private final Component label;
|
||||
private boolean labelVisible = true;
|
||||
|
||||
public BuilderImpl(final String key, final List<OptionEntry> entries, final Component label) {
|
||||
Preconditions.checkArgument(StringTemplate.isValidVariableName(key), "key must be a valid input name");
|
||||
this.key = key;
|
||||
Preconditions.checkArgument(!entries.isEmpty(), "entries must not be empty");
|
||||
Preconditions.checkArgument(entries.stream().filter(OptionEntry::initial).count() <= 1, "only 1 option can be initially selected");
|
||||
this.entries = entries;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl width(final int width) {
|
||||
Preconditions.checkArgument(width >= 1 && width <= 1024, "width must be between 1 and 1024");
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl labelVisible(final boolean labelVisible) {
|
||||
this.labelVisible = labelVisible;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleOptionDialogInput build() {
|
||||
return new SingleOptionDialogInputImpl(this.key, this.width, this.entries, this.label, this.labelVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package io.papermc.paper.registry.data.dialog.input;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.commands.functions.StringTemplate;
|
||||
import net.minecraft.server.dialog.body.PlainMessage;
|
||||
import net.minecraft.server.dialog.input.TextInput;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record TextDialogInputImpl(
|
||||
String key,
|
||||
int width,
|
||||
Component label,
|
||||
boolean labelVisible,
|
||||
String initial,
|
||||
int maxLength,
|
||||
TextDialogInput.@Nullable MultilineOptions multiline
|
||||
) implements TextDialogInput {
|
||||
|
||||
public record MultilineOptionsImpl(@Nullable Integer maxLines, @Nullable Integer height) implements MultilineOptions {
|
||||
public MultilineOptionsImpl {
|
||||
Preconditions.checkArgument(maxLines == null || maxLines > 0, "maxLines must be null or greater than 0");
|
||||
Preconditions.checkArgument(height == null || (height >= 1 && height <= TextInput.MultilineOptions.MAX_HEIGHT), "height must be null or between 1 and 512");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class BuilderImpl implements TextDialogInput.Builder {
|
||||
|
||||
private final String key;
|
||||
private int width = PlainMessage.DEFAULT_WIDTH;
|
||||
private final Component label;
|
||||
private boolean labelVisible = true;
|
||||
private String initial = "";
|
||||
private int maxLength = 32;
|
||||
private TextDialogInput.@Nullable MultilineOptions multiline = null;
|
||||
|
||||
public BuilderImpl(final String key, final Component label) {
|
||||
Preconditions.checkArgument(StringTemplate.isValidVariableName(key), "key must be a valid input name");
|
||||
this.key = key;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDialogInput.Builder width(final int width) {
|
||||
Preconditions.checkArgument(width >= 1 && width <= 1024, "width must be between 1 and 1024");
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDialogInput.Builder labelVisible(final boolean labelVisible) {
|
||||
this.labelVisible = labelVisible;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDialogInput.Builder initial(final String initial) {
|
||||
this.initial = initial;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDialogInput.Builder maxLength(final int maxLength) {
|
||||
Preconditions.checkArgument(maxLength > 0, "maxLength must be greater than 0");
|
||||
this.maxLength = maxLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDialogInput.Builder multiline(final TextDialogInput.@Nullable MultilineOptions multiline) {
|
||||
this.multiline = multiline;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDialogInput build() {
|
||||
Preconditions.checkState(this.initial.length() <= this.maxLength, "The initial value must be less than or equal to the maximum length.");
|
||||
return new TextDialogInputImpl(this.key, this.width, this.label, this.labelVisible, this.initial, this.maxLength, this.multiline);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package io.papermc.paper.registry.data.dialog.type;
|
||||
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
|
||||
public record ConfirmationTypeImpl(ActionButton yesButton, ActionButton noButton) implements ConfirmationType {
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package io.papermc.paper.registry.data.dialog.type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import io.papermc.paper.registry.set.RegistrySet;
|
||||
import net.minecraft.server.dialog.CommonButtonData;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record DialogListTypeImpl(
|
||||
RegistrySet<Dialog> dialogs,
|
||||
@Nullable ActionButton exitAction,
|
||||
int columns,
|
||||
int buttonWidth
|
||||
) implements DialogListType {
|
||||
|
||||
public static final class BuilderImpl implements DialogListType.Builder {
|
||||
|
||||
private final RegistrySet<Dialog> dialogs;
|
||||
private @Nullable ActionButton exitAction;
|
||||
private int columns = 2;
|
||||
private int buttonWidth = CommonButtonData.DEFAULT_WIDTH;
|
||||
|
||||
public BuilderImpl(final RegistrySet<Dialog> dialogs) {
|
||||
this.dialogs = dialogs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogListType.Builder exitAction(final @Nullable ActionButton exitAction) {
|
||||
this.exitAction = exitAction;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogListType.Builder columns(final int columns) {
|
||||
Preconditions.checkArgument(columns > 0, "columns must be greater than 0");
|
||||
this.columns = columns;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogListType.Builder buttonWidth(final int buttonWidth) {
|
||||
Preconditions.checkArgument(buttonWidth >= 1 && buttonWidth <= 1024, "buttonWidth must be between 1 and 1024");
|
||||
this.buttonWidth = buttonWidth;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogListType build() {
|
||||
return new DialogListTypeImpl(this.dialogs, this.exitAction, this.columns, this.buttonWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package io.papermc.paper.registry.data.dialog.type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import java.util.List;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record MultiActionTypeImpl(
|
||||
List<ActionButton> actions,
|
||||
@Nullable ActionButton exitAction,
|
||||
int columns
|
||||
) implements MultiActionType {
|
||||
|
||||
public MultiActionTypeImpl {
|
||||
actions = List.copyOf(actions);
|
||||
}
|
||||
|
||||
public static final class BuilderImpl implements MultiActionType.Builder {
|
||||
private final List<ActionButton> actions;
|
||||
private @Nullable ActionButton exitAction = null;
|
||||
private int columns = 2;
|
||||
|
||||
public BuilderImpl(final List<ActionButton> actions) {
|
||||
Preconditions.checkArgument(!actions.isEmpty(), "actions cannot be empty");
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder exitAction(final @org.jetbrains.annotations.Nullable ActionButton exitAction) {
|
||||
this.exitAction = exitAction;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder columns(final int columns) {
|
||||
Preconditions.checkArgument(columns > 0, "columns must be greater than 0");
|
||||
this.columns = columns;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiActionType build() {
|
||||
return new MultiActionTypeImpl(this.actions, this.exitAction, this.columns);
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package io.papermc.paper.registry.data.dialog.type;
|
||||
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import net.minecraft.server.dialog.CommonButtonData;
|
||||
|
||||
import static net.kyori.adventure.text.Component.translatable;
|
||||
|
||||
public record NoticeTypeImpl(ActionButton action) implements NoticeType {
|
||||
|
||||
public static final ActionButton DEFAULT_ACTION = ActionButton.builder(translatable("gui.ok")).width(CommonButtonData.DEFAULT_WIDTH).build();
|
||||
|
||||
public NoticeTypeImpl() {
|
||||
this(DEFAULT_ACTION);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package io.papermc.paper.registry.data.dialog.type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record ServerLinksTypeImpl(
|
||||
@Nullable ActionButton exitAction,
|
||||
int columns,
|
||||
int buttonWidth
|
||||
) implements ServerLinksType {
|
||||
|
||||
public ServerLinksTypeImpl {
|
||||
Preconditions.checkArgument(columns > 0, "columns must be greater than 0");
|
||||
Preconditions.checkArgument(buttonWidth >= 1 && buttonWidth <= 1024, "buttonWidth must be between 1 and 1024");
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package io.papermc.paper.registry.data.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JavaOps;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.adventure.WrapperAwareSerializer;
|
||||
import io.papermc.paper.registry.PaperRegistries;
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.PaperRegistryBuilderFactory;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||
import java.util.function.Consumer;
|
||||
@@ -36,10 +38,20 @@ public class Conversions {
|
||||
|
||||
private final RegistryOps.RegistryInfoLookup lookup;
|
||||
private final WrapperAwareSerializer serializer;
|
||||
private final RegistryOps<Object> javaOps;
|
||||
|
||||
public Conversions(final RegistryOps.RegistryInfoLookup lookup) {
|
||||
this.lookup = lookup;
|
||||
this.serializer = new WrapperAwareSerializer(() -> RegistryOps.create(JavaOps.INSTANCE, lookup));
|
||||
this.javaOps = RegistryOps.create(JavaOps.INSTANCE, lookup);
|
||||
}
|
||||
|
||||
public <OUT, IN> OUT convert(final IN in, final Codec<OUT> outCodec, final Codec<IN> inCodec) {
|
||||
final Object obj = inCodec.encodeStart(this.javaOps, in)
|
||||
.getOrThrow(s -> new RuntimeException("Failed to encode input: " + in + "; " + s));
|
||||
return outCodec.decode(this.javaOps, obj)
|
||||
.getOrThrow(s -> new RuntimeException("Failed to decode to output: " + obj + "; " + s))
|
||||
.getFirst();
|
||||
}
|
||||
|
||||
public RegistryOps.RegistryInfoLookup lookup() {
|
||||
@@ -74,20 +86,20 @@ public class Conversions {
|
||||
);
|
||||
}
|
||||
|
||||
private static <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> RegistryEntryMeta.Buildable<M, A, B> getDirectHolderBuildableMeta(final ResourceKey<? extends Registry<M>> registryKey) {
|
||||
private static <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> RegistryEntryMeta.Buildable<M, A, B> getDirectHolderBuildableMeta(final RegistryKey<A> registryKey) {
|
||||
final RegistryEntryMeta.Buildable<M, A, B> buildableMeta = PaperRegistries.getBuildableMeta(registryKey);
|
||||
Preconditions.checkArgument(buildableMeta.registryTypeMapper().supportsDirectHolders(), "Registry type mapper must support direct holders");
|
||||
return buildableMeta;
|
||||
}
|
||||
|
||||
public <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> A createApiInstanceFromBuilder(final ResourceKey<? extends Registry<M>> registryKey, final Consumer<? super PaperRegistryBuilderFactory<M, A, B>> value) {
|
||||
public <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> A createApiInstanceFromBuilder(final RegistryKey<A> registryKey, final Consumer<? super PaperRegistryBuilderFactory<M, A, B>> value) {
|
||||
final RegistryEntryMeta.Buildable<M, A, B> meta = getDirectHolderBuildableMeta(registryKey);
|
||||
final PaperRegistryBuilderFactory<M, A, B> builderFactory = this.createRegistryBuilderFactory(registryKey, meta);
|
||||
value.accept(builderFactory);
|
||||
return meta.registryTypeMapper().createBukkit(Holder.direct(builderFactory.requireBuilder().build()));
|
||||
}
|
||||
|
||||
public <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> Holder<M> createHolderFromBuilder(final ResourceKey<? extends Registry<M>> registryKey, final Consumer<? super PaperRegistryBuilderFactory<M, A, B>> value) {
|
||||
public <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> Holder<M> createHolderFromBuilder(final RegistryKey<A> registryKey, final Consumer<? super PaperRegistryBuilderFactory<M, A, B>> value) {
|
||||
final RegistryEntryMeta.Buildable<M, A, B> meta = getDirectHolderBuildableMeta(registryKey);
|
||||
final PaperRegistryBuilderFactory<M, A, B> builderFactory = this.createRegistryBuilderFactory(registryKey, meta);
|
||||
value.accept(builderFactory);
|
||||
@@ -95,11 +107,12 @@ public class Conversions {
|
||||
}
|
||||
|
||||
private <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> PaperRegistryBuilderFactory<M, A, B> createRegistryBuilderFactory(
|
||||
final ResourceKey<? extends Registry<M>> registryKey,
|
||||
final RegistryKey<A> registryKey,
|
||||
final RegistryEntryMeta.Buildable<M, A, B> buildableMeta
|
||||
) {
|
||||
final HolderLookup.RegistryLookup<M> lookupForBuilders = this.lookup.lookupForValueCopyViaBuilders().lookupOrThrow(registryKey);
|
||||
return new PaperRegistryBuilderFactory<>(registryKey, this, buildableMeta.builderFiller(), lookupForBuilders::getValueForCopying);
|
||||
final ResourceKey<? extends Registry<M>> resourceRegistryKey = PaperRegistries.registryToNms(registryKey);
|
||||
final HolderLookup.RegistryLookup<M> lookupForBuilders = this.lookup.lookupForValueCopyViaBuilders().lookupOrThrow(resourceRegistryKey);
|
||||
return new PaperRegistryBuilderFactory<>(resourceRegistryKey, this, buildableMeta.builderFiller(), lookupForBuilders::getValueForCopying);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,10 +37,6 @@ public class RegistryEntryBuilder<M, A extends Keyed> { // TODO remove Keyed
|
||||
return new RegistryEntryImpl<>(new RegistryEntryMeta.ApiOnly<>(this.mcKey, this.apiKey, apiRegistrySupplier));
|
||||
}
|
||||
|
||||
public CraftStage<M, A> craft(final Class<?> classToPreload, final BiFunction<? super NamespacedKey, M, ? extends A> minecraftToBukkit) {
|
||||
return new CraftStage<>(this.mcKey, this.apiKey, classToPreload, new RegistryTypeMapper<>(minecraftToBukkit));
|
||||
}
|
||||
|
||||
public CraftStage<M, A> craft(final Class<?> classToPreload, final Function<Holder<M>, ? extends A> minecraftToBukkit) {
|
||||
return this.craft(classToPreload, minecraftToBukkit, false);
|
||||
}
|
||||
|
||||
@@ -18,9 +18,7 @@ import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public record NamedRegistryKeySetImpl<T extends Keyed, M>( // TODO remove Keyed
|
||||
TagKey<T> tagKey,
|
||||
HolderSet.Named<M> namedSet
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.papermc.paper.registry.set;
|
||||
import io.papermc.paper.registry.PaperRegistries;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.TypedKey;
|
||||
import io.papermc.paper.util.Holderable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.minecraft.core.Holder;
|
||||
@@ -11,6 +12,7 @@ import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.craftbukkit.CraftRegistry;
|
||||
|
||||
public final class PaperRegistrySets {
|
||||
|
||||
@@ -25,6 +27,30 @@ public final class PaperRegistrySets {
|
||||
}
|
||||
}
|
||||
|
||||
public static <A extends Keyed, M> HolderSet<M> convertToNmsWithDirects(final ResourceKey<? extends Registry<M>> resourceKey, final RegistryOps.RegistryInfoLookup lookup, final RegistrySet<A> registrySet) { // TODO remove Keyed
|
||||
if (registrySet instanceof NamedRegistryKeySetImpl<A, ?>) {
|
||||
return ((NamedRegistryKeySetImpl<A, M>) registrySet).namedSet();
|
||||
} else if (registrySet.isEmpty()) {
|
||||
return HolderSet.empty();
|
||||
} else if (registrySet instanceof final RegistryValueSet<A> valueSet) {
|
||||
final List<Holder<M>> directs = new ArrayList<>(valueSet.values().size());
|
||||
for (final A value : valueSet) {
|
||||
if (!(value instanceof final Holderable<?> holderable)) {
|
||||
throw new UnsupportedOperationException("Cannot convert a registry set containing non-holderable values");
|
||||
}
|
||||
directs.add(((Holderable<M>) holderable).getHolder());
|
||||
}
|
||||
return HolderSet.direct(directs);
|
||||
} else if (registrySet instanceof final RegistryKeySet<A> keySet) {
|
||||
final RegistryOps.RegistryInfo<M> registryInfo = lookup.lookup(resourceKey).orElseThrow();
|
||||
return HolderSet.direct(key -> {
|
||||
return registryInfo.getter().getOrThrow(PaperRegistries.toNms(key));
|
||||
}, keySet.values());
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot convert a registry set of type " + registrySet.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static <A extends Keyed, M> RegistryKeySet<A> convertToApi(final RegistryKey<A> registryKey, final HolderSet<M> holders) { // TODO remove Keyed
|
||||
if (holders instanceof final HolderSet.Named<M> named) {
|
||||
return new NamedRegistryKeySetImpl<>(PaperRegistries.fromNms(named.key()), named);
|
||||
@@ -40,6 +66,30 @@ public final class PaperRegistrySets {
|
||||
}
|
||||
}
|
||||
|
||||
public static <A extends Keyed, M> RegistrySet<A> convertToApiWithDirects(final RegistryKey<A> registryKey, final HolderSet<M> holders) { // TODO remove Keyed
|
||||
if (holders instanceof final HolderSet.Named<M> named) {
|
||||
return new NamedRegistryKeySetImpl<>(PaperRegistries.fromNms(named.key()), named);
|
||||
} else {
|
||||
if (holders.size() == 0) {
|
||||
return RegistrySet.keySet(registryKey);
|
||||
}
|
||||
if (holders.get(0) instanceof Holder.Direct<M>) {
|
||||
final List<A> directs = new ArrayList<>(holders.size());
|
||||
final ResourceKey<? extends Registry<M>> nmsRegistryKey = PaperRegistries.registryToNms(registryKey);
|
||||
for (final Holder<M> holder : holders) {
|
||||
directs.add(CraftRegistry.minecraftHolderToBukkit(holder, nmsRegistryKey));
|
||||
}
|
||||
return RegistrySet.valueSet(registryKey, directs);
|
||||
} else {
|
||||
final List<TypedKey<A>> keys = new ArrayList<>(holders.size());
|
||||
for (final Holder<M> holder : holders) {
|
||||
keys.add(PaperRegistries.fromNms(((Holder.Reference<M>) holder).key()));
|
||||
}
|
||||
return RegistrySet.keySet(registryKey, keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PaperRegistrySets() {
|
||||
}
|
||||
}
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package io.papermc.paper.registry.set;
|
||||
|
||||
import io.papermc.paper.registry.RegistryBuilder;
|
||||
import io.papermc.paper.registry.RegistryBuilderFactory;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import org.bukkit.Keyed;
|
||||
|
||||
public class RegistryValueSetBuilderImpl<M, API extends Keyed, BUILDER extends RegistryBuilder<API>> implements RegistryValueSetBuilder<API, BUILDER> { // TODO remove Keyed
|
||||
|
||||
private final RegistryKey<API> registryKey;
|
||||
private final Conversions conversions;
|
||||
private final List<API> instances = new ArrayList<>();
|
||||
|
||||
public RegistryValueSetBuilderImpl(final RegistryKey<API> registryKey, final Conversions conversions) {
|
||||
this.registryKey = registryKey;
|
||||
this.conversions = conversions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistryValueSetBuilder<API, BUILDER> add(final Consumer<RegistryBuilderFactory<API, ? extends BUILDER>> builder) {
|
||||
this.instances.add(this.conversions.createApiInstanceFromBuilder(this.registryKey, builder));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistryValueSet<API> build() {
|
||||
return RegistrySet.valueSet(this.registryKey, this.instances);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package io.papermc.paper.util;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.Decoder;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import io.papermc.paper.adventure.AdventureCodecs;
|
||||
import io.papermc.paper.registry.RegistryAccess;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.TypedKey;
|
||||
import java.util.function.Function;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.Registry;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public final class PaperCodecs {
|
||||
|
||||
public static <A extends Keyed, M> Decoder<A> registryFileDecoderFor(final Decoder<? extends M> directNmsDecoder, final Function<? super Holder<M>, A> directHolderConverter, final RegistryKey<A> registryKey, final boolean allowInline) { // TODO remove Keyed
|
||||
final Decoder.Terminal<A> terminalDecoder = directNmsDecoder.map(nms -> directHolderConverter.apply(Holder.direct(nms))).terminal();
|
||||
return Decoder.ofTerminal(new Decoder.Terminal<>() {
|
||||
@Override
|
||||
public <T> DataResult<A> decode(final DynamicOps<T> ops, final T input) {
|
||||
// logic based on RegistryFileCodec
|
||||
if (ops instanceof RegistryOps<?>) {
|
||||
// Pretty sure we can just use our RegistryAccess here. These codecs aren't ever
|
||||
// used for deserialization, so we don't need to rely on different implementations
|
||||
// of HolderGetter like vanilla's RegistryFileCodec does. We are always just
|
||||
// getting existing dialog elements, never creating empty reference holders.
|
||||
final Registry<A> registry = RegistryAccess.registryAccess().getRegistry(registryKey);
|
||||
final DataResult<Pair<Key, T>> keyDataResult = AdventureCodecs.KEY_CODEC.decode(ops, input);
|
||||
if (keyDataResult.result().isEmpty()) {
|
||||
return !allowInline ? DataResult.error(() -> "Inline definitions not allowed here") : terminalDecoder.decode(ops, input);
|
||||
}
|
||||
final Pair<Key, T> pair = keyDataResult.result().get();
|
||||
final TypedKey<A> elementKey = TypedKey.create(registryKey, pair.getFirst());
|
||||
final A value = registry.get(elementKey);
|
||||
if (value == null) {
|
||||
return DataResult.error(() -> "Failed to get element " + elementKey);
|
||||
}
|
||||
return DataResult.success(value);
|
||||
} else {
|
||||
return terminalDecoder.decode(ops, input);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private PaperCodecs() {
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public class CraftArt extends OldEnumHolderable<Art, PaintingVariant> implements
|
||||
}
|
||||
|
||||
public static Holder<PaintingVariant> bukkitToMinecraftHolder(Art bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.PAINTING_VARIANT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftArt(Holder<PaintingVariant> paintingVariant) {
|
||||
|
||||
@@ -21,7 +21,7 @@ public class CraftJukeboxSong extends HolderableBase<net.minecraft.world.item.Ju
|
||||
}
|
||||
|
||||
public static Holder<net.minecraft.world.item.JukeboxSong> bukkitToMinecraftHolder(JukeboxSong bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.JUKEBOX_SONG);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftJukeboxSong(final Holder<net.minecraft.world.item.JukeboxSong> holder) {
|
||||
|
||||
@@ -28,7 +28,7 @@ public class CraftMusicInstrument extends MusicInstrument implements io.papermc.
|
||||
}
|
||||
|
||||
public static Holder<Instrument> bukkitToMinecraftHolder(MusicInstrument bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.INSTRUMENT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public static Object bukkitToString(MusicInstrument bukkit) {
|
||||
|
||||
@@ -99,28 +99,18 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
||||
* @param bukkit the bukkit representation
|
||||
* @return the minecraft representation of the bukkit value
|
||||
*/
|
||||
public static <B extends Keyed, M> M bukkitToMinecraft(B bukkit) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <B extends Keyed, M> M bukkitToMinecraft(final B bukkit) {
|
||||
Preconditions.checkArgument(bukkit != null);
|
||||
|
||||
return ((Handleable<M>) bukkit).getHandle();
|
||||
}
|
||||
|
||||
public static <B extends Keyed, M> Holder<M> bukkitToMinecraftHolder(B bukkit, ResourceKey<net.minecraft.core.Registry<M>> registryKey) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <B extends Keyed, M> Holder<M> bukkitToMinecraftHolder(final B bukkit) {
|
||||
Preconditions.checkArgument(bukkit != null);
|
||||
// Paper start - support direct Holder
|
||||
if (bukkit instanceof io.papermc.paper.util.Holderable<?>) {
|
||||
return ((io.papermc.paper.util.Holderable<M>) bukkit).getHolder();
|
||||
}
|
||||
// Paper end - support direct Holder
|
||||
|
||||
net.minecraft.core.Registry<M> registry = CraftRegistry.getMinecraftRegistry(registryKey);
|
||||
|
||||
if (registry.wrapAsHolder(CraftRegistry.bukkitToMinecraft(bukkit)) instanceof Holder.Reference<M> holder) {
|
||||
return holder;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("No Reference holder found for " + bukkit
|
||||
+ ", this can happen if a plugin creates its own registry entry with out properly registering it.");
|
||||
return ((Holderable<M>) bukkit).getHolder();
|
||||
}
|
||||
|
||||
// Paper start - fixup upstream being dum
|
||||
|
||||
@@ -23,7 +23,7 @@ public class CraftSound extends OldEnumHolderable<Sound, SoundEvent> implements
|
||||
}
|
||||
|
||||
public static Holder<SoundEvent> bukkitToMinecraftHolder(Sound bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.SOUND_EVENT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftSound(Holder<SoundEvent> soundEffect) {
|
||||
|
||||
@@ -43,7 +43,7 @@ public class CraftAttribute extends OldEnumHolderable<Attribute, net.minecraft.w
|
||||
}
|
||||
|
||||
public static Holder<net.minecraft.world.entity.ai.attributes.Attribute> bukkitToMinecraftHolder(Attribute bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.ATTRIBUTE);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public static String bukkitToString(Attribute bukkit) {
|
||||
|
||||
@@ -36,7 +36,7 @@ public class CraftBiome extends OldEnumHolderable<Biome, net.minecraft.world.lev
|
||||
if (bukkit == Biome.CUSTOM) {
|
||||
return null;
|
||||
}
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.BIOME);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftBiome(final Holder<net.minecraft.world.level.biome.Biome> holder) {
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ public class CraftPatternType extends OldEnumHolderable<PatternType, BannerPatte
|
||||
}
|
||||
|
||||
public static Holder<BannerPattern> bukkitToMinecraftHolder(PatternType bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.BANNER_PATTERN);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftPatternType(Holder<BannerPattern> bannerPatternType) {
|
||||
|
||||
@@ -79,7 +79,7 @@ public class CraftDamageType extends HolderableBase<net.minecraft.world.damageso
|
||||
}
|
||||
|
||||
public static Holder<net.minecraft.world.damagesource.DamageType> bukkitToMinecraftHolder(DamageType bukkitDamageType) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkitDamageType, Registries.DAMAGE_TYPE);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkitDamageType);
|
||||
}
|
||||
|
||||
public static net.minecraft.world.damagesource.DamageType bukkitToMinecraft(DamageType bukkitDamageType) {
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public class CraftEnchantment extends Enchantment implements Holderable<net.mine
|
||||
}
|
||||
|
||||
public static Holder<net.minecraft.world.item.enchantment.Enchantment> bukkitToMinecraftHolder(Enchantment bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.ENCHANTMENT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public static String bukkitToString(Enchantment bukkit) {
|
||||
|
||||
@@ -59,7 +59,7 @@ public class CraftCat extends CraftTameableAnimal implements Cat {
|
||||
}
|
||||
|
||||
public static Holder<CatVariant> bukkitToMinecraftHolder(Type bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.CAT_VARIANT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftType(final Holder<CatVariant> holder) {
|
||||
|
||||
@@ -49,7 +49,7 @@ public class CraftChicken extends CraftAnimals implements Chicken {
|
||||
}
|
||||
|
||||
public static Holder<ChickenVariant> bukkitToMinecraftHolder(Variant bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.CHICKEN_VARIANT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public class CraftCow extends CraftAbstractCow implements Cow {
|
||||
}
|
||||
|
||||
public static Holder<CowVariant> bukkitToMinecraftHolder(Variant bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.COW_VARIANT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftVariant(final Holder<CowVariant> holder) {
|
||||
|
||||
@@ -63,7 +63,7 @@ public class CraftFrog extends CraftAnimals implements org.bukkit.entity.Frog {
|
||||
}
|
||||
|
||||
public static Holder<FrogVariant> bukkitToMinecraftHolder(Variant bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.FROG_VARIANT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
public CraftVariant(final Holder<FrogVariant> holder) {
|
||||
super(holder, count++);
|
||||
|
||||
@@ -97,7 +97,7 @@ public class CraftPig extends CraftAnimals implements Pig {
|
||||
}
|
||||
|
||||
public static Holder<PigVariant> bukkitToMinecraftHolder(Variant bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.PIG_VARIANT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftVariant(final Holder<PigVariant> holder) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -178,7 +178,7 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
|
||||
}
|
||||
|
||||
public static Holder<VillagerType> bukkitToMinecraftHolder(Type bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.VILLAGER_TYPE);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftType(final Holder<VillagerType> holder){
|
||||
@@ -194,7 +194,7 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
|
||||
}
|
||||
|
||||
public static Holder<VillagerProfession> bukkitToMinecraftHolder(Profession bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.VILLAGER_PROFESSION);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public static Profession minecraftToBukkit(VillagerProfession minecraft) {
|
||||
|
||||
@@ -105,7 +105,7 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf {
|
||||
}
|
||||
|
||||
public static Holder<WolfVariant> bukkitToMinecraftHolder(Variant bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.WOLF_VARIANT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftVariant(final Holder<WolfVariant> holder) {
|
||||
@@ -128,7 +128,7 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf {
|
||||
}
|
||||
|
||||
public static Holder<WolfSoundVariant> bukkitToMinecraftHolder(SoundVariant bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.WOLF_SOUND_VARIANT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftSoundVariant(final Holder<WolfSoundVariant> holder) {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class CraftTrimMaterial extends HolderableBase<net.minecraft.world.item.e
|
||||
}
|
||||
|
||||
public static Holder<net.minecraft.world.item.equipment.trim.TrimMaterial> bukkitToMinecraftHolder(TrimMaterial bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.TRIM_MATERIAL);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public static Object bukkitToObject(TrimMaterial bukkit) {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class CraftTrimPattern extends HolderableBase<net.minecraft.world.item.eq
|
||||
}
|
||||
|
||||
public static Holder<net.minecraft.world.item.equipment.trim.TrimPattern> bukkitToMinecraftHolder(TrimPattern bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.TRIM_PATTERN);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public static Object bukkitToObject(TrimPattern bukkit) {
|
||||
|
||||
@@ -26,7 +26,7 @@ public final class CraftMapCursor {
|
||||
}
|
||||
|
||||
public static Holder<MapDecorationType> bukkitToMinecraftHolder(MapCursor.Type bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.MAP_DECORATION_TYPE);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
public CraftType(final Holder<MapDecorationType> holder) {
|
||||
|
||||
@@ -38,7 +38,7 @@ public class CraftPotionEffectType extends PotionEffectType implements Holderabl
|
||||
}
|
||||
|
||||
public static Holder<MobEffect> bukkitToMinecraftHolder(PotionEffectType bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.MOB_EFFECT);
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit);
|
||||
}
|
||||
|
||||
private final Holder<MobEffect> holder;
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
io.papermc.paper.registry.data.dialog.PaperDialogInstancesProvider
|
||||
@@ -270,7 +270,7 @@ public class RegistryConversionTest {
|
||||
Joiner.on('\n').withKeyValueSeparator(" got: ").join(notMatching)));
|
||||
}
|
||||
|
||||
static final Set<RegistryKey<?>> IGNORE_FOR_DIRECT_HOLDER = Set.of(RegistryKey.TRIM_MATERIAL, RegistryKey.TRIM_PATTERN, RegistryKey.INSTRUMENT, RegistryKey.BANNER_PATTERN, RegistryKey.SOUND_EVENT); // Paper
|
||||
static final Set<RegistryKey<?>> IGNORE_FOR_DIRECT_HOLDER = Set.of(RegistryKey.TRIM_MATERIAL, RegistryKey.TRIM_PATTERN, RegistryKey.INSTRUMENT, RegistryKey.BANNER_PATTERN, RegistryKey.SOUND_EVENT, RegistryKey.DIALOG); // Paper
|
||||
|
||||
/**
|
||||
* Minecraft registry can return a default key / value
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.bukkit.support.provider;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.dialog.PaperDialog;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
@@ -115,6 +117,7 @@ public class RegistriesArgumentProvider implements ArgumentsProvider {
|
||||
register(RegistryKey.CHICKEN_VARIANT, Chicken.Variant.class, Registries.CHICKEN_VARIANT, CraftChicken.CraftVariant.class, ChickenVariant.class);
|
||||
register(RegistryKey.COW_VARIANT, Cow.Variant.class, Registries.COW_VARIANT, CraftCow.CraftVariant.class, CowVariant.class);
|
||||
register(RegistryKey.PIG_VARIANT, Pig.Variant.class, Registries.PIG_VARIANT, CraftPig.CraftVariant.class, PigVariant.class);
|
||||
register(RegistryKey.DIALOG, Dialog.class, Registries.DIALOG, PaperDialog.class, net.minecraft.server.dialog.Dialog.class);
|
||||
}
|
||||
|
||||
private static void register(RegistryKey registryKey, Class bukkit, ResourceKey registry, Class craft, Class minecraft) { // Paper
|
||||
|
||||
Reference in New Issue
Block a user