diff --git a/api/pom.xml b/api/pom.xml
index b050e847..fdf519e1 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -31,6 +31,12 @@
${project.version}
compile
+
+ net.md-5
+ bungeecord-dialog
+ ${project.version}
+ compile
+
net.md-5
bungeecord-event
diff --git a/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java b/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java
index 17dd8694..1c0714f4 100644
--- a/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java
+++ b/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java
@@ -12,6 +12,7 @@ import net.md_5.bungee.api.SkinConfiguration;
import net.md_5.bungee.api.Title;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.config.ServerInfo;
+import net.md_5.bungee.api.dialog.Dialog;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.score.Scoreboard;
import org.jetbrains.annotations.ApiStatus;
@@ -390,4 +391,23 @@ public interface ProxiedPlayer extends Connection, CommandSender
* @return the brand of the client, or null if not received yet
*/
String getClientBrand();
+
+ /**
+ * Clear the player's open dialog.
+ *
+ * @throws IllegalStateException if the players version is not at least
+ * 1.21.6
+ */
+ @ApiStatus.Experimental
+ void clearDialog();
+
+ /**
+ * Show a dialog to the player.
+ *
+ * @param dialog the dialog to show
+ * @throws IllegalStateException if the players version is not at least
+ * 1.21.6
+ */
+ @ApiStatus.Experimental
+ void showDialog(Dialog dialog);
}
diff --git a/api/src/main/java/net/md_5/bungee/api/event/CustomClickEvent.java b/api/src/main/java/net/md_5/bungee/api/event/CustomClickEvent.java
new file mode 100644
index 00000000..01d065c4
--- /dev/null
+++ b/api/src/main/java/net/md_5/bungee/api/event/CustomClickEvent.java
@@ -0,0 +1,43 @@
+package net.md_5.bungee.api.event;
+
+import java.util.Map;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+import net.md_5.bungee.api.plugin.Cancellable;
+import net.md_5.bungee.api.plugin.Event;
+
+/**
+ * Called after a {@link ProxiedPlayer} runs a custom action from a chat event
+ * or form submission.
+ */
+@Data
+@ToString(callSuper = false)
+@EqualsAndHashCode(callSuper = false)
+public class CustomClickEvent extends Event implements Cancellable
+{
+
+ /**
+ * Map key containing the form action, if available.
+ */
+ public static final String ACTION_KEY = "action";
+ //
+ /**
+ * Player who clicked.
+ */
+ private final ProxiedPlayer player;
+ /**
+ * Custom action ID.
+ */
+ private final String id;
+ /**
+ * Form data, may be null. If a form submission, usually contains a key
+ * {@link ACTION_KEY} with the ID of the relevant submission action.
+ */
+ private final Map data;
+ /**
+ * Cancelled state.
+ */
+ private boolean cancelled;
+}
diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java b/chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java
index 1f643599..2aba0866 100644
--- a/chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java
+++ b/chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java
@@ -4,12 +4,14 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
+import org.jetbrains.annotations.ApiStatus;
@Getter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
-public final class ClickEvent
+@ApiStatus.NonExtendable
+public class ClickEvent
{
/**
@@ -52,11 +54,19 @@ public final class ClickEvent
* {@link net.md_5.bungee.api.chat.ClickEvent#value} in a book.
*/
CHANGE_PAGE,
+ /**
+ * Must use subclass ShowDialogClickEvent.
+ */
+ SHOW_DIALOG,
/**
* Copy the string given by
* {@link net.md_5.bungee.api.chat.ClickEvent#value} into the player's
* clipboard.
*/
- COPY_TO_CLIPBOARD
+ COPY_TO_CLIPBOARD,
+ /**
+ * Must use subclass {@link ClickEventCustom}.
+ */
+ CUSTOM,
}
}
diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/ClickEventCustom.java b/chat/src/main/java/net/md_5/bungee/api/chat/ClickEventCustom.java
new file mode 100644
index 00000000..6946d00c
--- /dev/null
+++ b/chat/src/main/java/net/md_5/bungee/api/chat/ClickEventCustom.java
@@ -0,0 +1,30 @@
+package net.md_5.bungee.api.chat;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+/**
+ * Click event which sends a custom payload to the server.
+ */
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class ClickEventCustom extends ClickEvent
+{
+
+ /**
+ * The custom payload.
+ */
+ private final String payload;
+
+ /**
+ * @param id identifier for the event (lower case, no special characters)
+ * @param payload custom payload
+ */
+ public ClickEventCustom(String id, String payload)
+ {
+ super( ClickEvent.Action.CUSTOM, id );
+ this.payload = payload;
+ }
+}
diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java b/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java
index 3408b887..6017a14a 100644
--- a/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java
+++ b/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java
@@ -13,7 +13,6 @@ import net.md_5.bungee.api.chat.hover.content.Content;
import net.md_5.bungee.api.chat.hover.content.Entity;
import net.md_5.bungee.api.chat.hover.content.Item;
import net.md_5.bungee.api.chat.hover.content.Text;
-import net.md_5.bungee.chat.VersionedComponentSerializer;
import org.jetbrains.annotations.ApiStatus;
@Getter
@@ -73,22 +72,6 @@ public final class HoverEvent
this.legacy = true;
}
- @Deprecated
- public BaseComponent[] getValue()
- {
- Content content = contents.get( 0 );
- if ( content instanceof Text && ( (Text) content ).getValue() instanceof BaseComponent[] )
- {
- return (BaseComponent[]) ( (Text) content ).getValue();
- }
-
- TextComponent component = new TextComponent( VersionedComponentSerializer.getDefault().toString( content ) );
- return new BaseComponent[]
- {
- component
- };
- }
-
/**
* Adds a content to this hover event.
*
diff --git a/dialog/LICENSE b/dialog/LICENSE
new file mode 100644
index 00000000..f3e916a9
--- /dev/null
+++ b/dialog/LICENSE
@@ -0,0 +1,28 @@
+BSD 3-Clause License
+
+Copyright (c) 2025, SpigotMC Pty. Ltd.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/dialog/README.md b/dialog/README.md
new file mode 100644
index 00000000..0bf858d5
--- /dev/null
+++ b/dialog/README.md
@@ -0,0 +1,35 @@
+BungeeCord-Dialog
+=================
+
+Highly experimental API, subject to breakage. All contributions welcome, including major refactors/design changes.
+
+Sample Plugin
+-------------
+
+```java
+ private class TestCommand extends Command
+ {
+
+ public TestCommand()
+ {
+ super( "btest" );
+ }
+
+ @Override
+ public void execute(CommandSender sender, String[] args)
+ {
+ ProxiedPlayer player = (ProxiedPlayer) sender;
+
+ Dialog notice = new NoticeDialog( new DialogBase( new ComponentBuilder( "Hello" ).color( ChatColor.RED ).build() ) );
+ player.showDialog( notice );
+
+ notice = new SimpleInputFormDialog(
+ new DialogBase( new ComponentBuilder( "Hello" ).color( ChatColor.RED ).build() ),
+ new DialogSubmitAction( "submit", new CustomFormSubmission( "customform" ), new ComponentBuilder( "Submit Button" ).build() ),
+ new TextInput( "first", new ComponentBuilder( "First" ).build() ),
+ new TextInput( "second", new ComponentBuilder( "Second" ).build() )
+ );
+ player.sendMessage( new ComponentBuilder( "click me" ).event( new ShowDialogClickEvent( notice ) ).build() );
+ }
+ }
+```
diff --git a/dialog/nb-configuration.xml b/dialog/nb-configuration.xml
new file mode 100644
index 00000000..7e465924
--- /dev/null
+++ b/dialog/nb-configuration.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+ project
+ NEW_LINE
+ NEW_LINE
+ NEW_LINE
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
+
diff --git a/dialog/pom.xml b/dialog/pom.xml
new file mode 100644
index 00000000..0a3d929c
--- /dev/null
+++ b/dialog/pom.xml
@@ -0,0 +1,36 @@
+
+
+ 4.0.0
+
+
+ net.md-5
+ bungeecord-parent
+ 1.21-R0.3-SNAPSHOT
+ ../pom.xml
+
+
+ net.md-5
+ bungeecord-dialog
+ 1.21-R0.3-SNAPSHOT
+ jar
+
+ BungeeCord-Dialog
+ Minecraft dialog API intended for use with BungeeCord
+
+
+ BSD-3-Clause
+ https://github.com/SpigotMC/BungeeCord/blob/master/dialog/LICENSE
+ repo
+
+
+
+
+
+ net.md-5
+ bungeecord-chat
+ ${project.version}
+ compile
+
+
+
diff --git a/dialog/src/main/java/net/md_5/bungee/api/dialog/ConfirmationDialog.java b/dialog/src/main/java/net/md_5/bungee/api/dialog/ConfirmationDialog.java
new file mode 100644
index 00000000..9ed5f2f3
--- /dev/null
+++ b/dialog/src/main/java/net/md_5/bungee/api/dialog/ConfirmationDialog.java
@@ -0,0 +1,27 @@
+package net.md_5.bungee.api.dialog;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+import net.md_5.bungee.api.dialog.action.DialogClickAction;
+
+@Data
+@ToString
+@EqualsAndHashCode
+@AllArgsConstructor
+@Accessors(fluent = true)
+public class ConfirmationDialog implements Dialog
+{
+
+ @Accessors(fluent = false)
+ private DialogBase base;
+ private DialogClickAction yes;
+ private DialogClickAction no;
+
+ public ConfirmationDialog(DialogBase base)
+ {
+ this( base, null, null );
+ }
+}
diff --git a/dialog/src/main/java/net/md_5/bungee/api/dialog/Dialog.java b/dialog/src/main/java/net/md_5/bungee/api/dialog/Dialog.java
new file mode 100644
index 00000000..028357b9
--- /dev/null
+++ b/dialog/src/main/java/net/md_5/bungee/api/dialog/Dialog.java
@@ -0,0 +1,9 @@
+package net.md_5.bungee.api.dialog;
+
+public interface Dialog
+{
+
+ DialogBase getBase();
+
+ void setBase(DialogBase base);
+}
diff --git a/dialog/src/main/java/net/md_5/bungee/api/dialog/DialogBase.java b/dialog/src/main/java/net/md_5/bungee/api/dialog/DialogBase.java
new file mode 100644
index 00000000..df84a390
--- /dev/null
+++ b/dialog/src/main/java/net/md_5/bungee/api/dialog/DialogBase.java
@@ -0,0 +1,21 @@
+package net.md_5.bungee.api.dialog;
+
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import lombok.experimental.Accessors;
+import net.md_5.bungee.api.chat.BaseComponent;
+
+@Data
+@AllArgsConstructor
+@RequiredArgsConstructor
+@Accessors(fluent = true)
+public class DialogBase
+{
+
+ private final BaseComponent title;
+ private BaseComponent externalTitle;
+ private List> body;
+ private boolean canCloseWithEscape;
+}
diff --git a/dialog/src/main/java/net/md_5/bungee/api/dialog/DialogListDialog.java b/dialog/src/main/java/net/md_5/bungee/api/dialog/DialogListDialog.java
new file mode 100644
index 00000000..d37a54d7
--- /dev/null
+++ b/dialog/src/main/java/net/md_5/bungee/api/dialog/DialogListDialog.java
@@ -0,0 +1,41 @@
+package net.md_5.bungee.api.dialog;
+
+import com.google.gson.annotations.SerializedName;
+import java.util.Arrays;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+import net.md_5.bungee.api.chat.ClickEvent;
+
+@Data
+@ToString
+@EqualsAndHashCode
+@Accessors(fluent = true)
+public class DialogListDialog implements Dialog
+{
+
+ @Accessors(fluent = false)
+ private DialogBase base;
+ private List
net.md-5
- bungeecord-chat
+ bungeecord-serializer
${project.version}
compile
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java b/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java
index 8d91211b..8c73509b 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java
@@ -2,6 +2,7 @@ package net.md_5.bungee.protocol;
import net.md_5.bungee.protocol.packet.BossBar;
import net.md_5.bungee.protocol.packet.Chat;
+import net.md_5.bungee.protocol.packet.ClearDialog;
import net.md_5.bungee.protocol.packet.ClearTitles;
import net.md_5.bungee.protocol.packet.ClientChat;
import net.md_5.bungee.protocol.packet.ClientCommand;
@@ -10,6 +11,7 @@ import net.md_5.bungee.protocol.packet.ClientStatus;
import net.md_5.bungee.protocol.packet.Commands;
import net.md_5.bungee.protocol.packet.CookieRequest;
import net.md_5.bungee.protocol.packet.CookieResponse;
+import net.md_5.bungee.protocol.packet.CustomClickAction;
import net.md_5.bungee.protocol.packet.DisconnectReportDetails;
import net.md_5.bungee.protocol.packet.EncryptionRequest;
import net.md_5.bungee.protocol.packet.EncryptionResponse;
@@ -41,6 +43,7 @@ import net.md_5.bungee.protocol.packet.ScoreboardScoreReset;
import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.ServerLinks;
import net.md_5.bungee.protocol.packet.SetCompression;
+import net.md_5.bungee.protocol.packet.ShowDialog;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
@@ -278,4 +281,16 @@ public abstract class AbstractPacketHandler
public void handle(ServerLinks serverLinks) throws Exception
{
}
+
+ public void handle(ShowDialog showDialog) throws Exception
+ {
+ }
+
+ public void handle(ClearDialog clearDialog) throws Exception
+ {
+ }
+
+ public void handle(CustomClickAction customClickAction) throws Exception
+ {
+ }
}
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java
index 40fdb868..32ffa28f 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java
@@ -11,6 +11,7 @@ import lombok.Data;
import lombok.Getter;
import net.md_5.bungee.protocol.packet.BossBar;
import net.md_5.bungee.protocol.packet.Chat;
+import net.md_5.bungee.protocol.packet.ClearDialog;
import net.md_5.bungee.protocol.packet.ClearTitles;
import net.md_5.bungee.protocol.packet.ClientChat;
import net.md_5.bungee.protocol.packet.ClientCommand;
@@ -18,6 +19,7 @@ import net.md_5.bungee.protocol.packet.ClientSettings;
import net.md_5.bungee.protocol.packet.Commands;
import net.md_5.bungee.protocol.packet.CookieRequest;
import net.md_5.bungee.protocol.packet.CookieResponse;
+import net.md_5.bungee.protocol.packet.CustomClickAction;
import net.md_5.bungee.protocol.packet.DisconnectReportDetails;
import net.md_5.bungee.protocol.packet.EncryptionRequest;
import net.md_5.bungee.protocol.packet.EncryptionResponse;
@@ -47,6 +49,7 @@ import net.md_5.bungee.protocol.packet.ScoreboardScoreReset;
import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.ServerLinks;
import net.md_5.bungee.protocol.packet.SetCompression;
+import net.md_5.bungee.protocol.packet.ShowDialog;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
@@ -559,6 +562,16 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_21, 0x7B ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x82 )
);
+ TO_CLIENT.registerPacket(
+ ClearDialog.class,
+ ClearDialog::new,
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x84 )
+ );
+ TO_CLIENT.registerPacket(
+ ShowDialog.class,
+ ShowDialog::new,
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x85 )
+ );
TO_SERVER.registerPacket(
KeepAlive.class,
@@ -578,7 +591,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x15 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x18 ),
- map( ProtocolConstants.MINECRAFT_1_21_2, 0x1A )
+ map( ProtocolConstants.MINECRAFT_1_21_2, 0x1A ),
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x1B )
);
TO_SERVER.registerPacket( Chat.class,
Chat::new,
@@ -595,14 +609,15 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x03 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x04 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x05 ),
- map( ProtocolConstants.MINECRAFT_1_21_2, 0x06 )
+ map( ProtocolConstants.MINECRAFT_1_21_2, 0x06 ),
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x07 )
);
TO_SERVER.registerPacket(
UnsignedClientCommand.class,
UnsignedClientCommand::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x04 ),
- map( ProtocolConstants.MINECRAFT_1_21_2, 0x05 )
-
+ map( ProtocolConstants.MINECRAFT_1_21_2, 0x05 ),
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x06 )
);
TO_SERVER.registerPacket(
ClientChat.class,
@@ -610,7 +625,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x04 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x05 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x06 ),
- map( ProtocolConstants.MINECRAFT_1_21_2, 0x07 )
+ map( ProtocolConstants.MINECRAFT_1_21_2, 0x07 ),
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x08 )
);
TO_SERVER.registerPacket(
TabCompleteRequest.class,
@@ -627,7 +643,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x09 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0A ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0B ),
- map( ProtocolConstants.MINECRAFT_1_21_2, 0x0D )
+ map( ProtocolConstants.MINECRAFT_1_21_2, 0x0D ),
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x0E )
);
TO_SERVER.registerPacket(
ClientSettings.class,
@@ -643,7 +660,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x09 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0A ),
- map( ProtocolConstants.MINECRAFT_1_21_2, 0x0C )
+ map( ProtocolConstants.MINECRAFT_1_21_2, 0x0C ),
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x0D )
);
TO_SERVER.registerPacket(
PluginMessage.class,
@@ -662,20 +680,28 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x10 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x12 ),
- map( ProtocolConstants.MINECRAFT_1_21_2, 0x14 )
+ map( ProtocolConstants.MINECRAFT_1_21_2, 0x14 ),
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x15 )
);
TO_SERVER.registerPacket(
StartConfiguration.class,
StartConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0B ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0C ),
- map( ProtocolConstants.MINECRAFT_1_21_2, 0x0E )
+ map( ProtocolConstants.MINECRAFT_1_21_2, 0x0E ),
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x0F )
);
TO_SERVER.registerPacket(
CookieResponse.class,
CookieResponse::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x11 ),
- map( ProtocolConstants.MINECRAFT_1_21_2, 0x13 )
+ map( ProtocolConstants.MINECRAFT_1_21_2, 0x13 ),
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x14 )
+ );
+ TO_SERVER.registerPacket(
+ CustomClickAction.class,
+ CustomClickAction::new,
+ map( ProtocolConstants.MINECRAFT_1_21_6, 0x41 )
);
}
},
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java b/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java
index 6e00f1a6..a2cac13f 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java
@@ -50,7 +50,7 @@ public class ProtocolConstants
public static final int MINECRAFT_1_21_2 = 768;
public static final int MINECRAFT_1_21_4 = 769;
public static final int MINECRAFT_1_21_5 = 770;
- public static final int MINECRAFT_1_21_6 = 1073742073;
+ public static final int MINECRAFT_1_21_6 = 1073742074;
public static final List SUPPORTED_VERSIONS;
public static final List SUPPORTED_VERSION_IDS;
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ClearDialog.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ClearDialog.java
new file mode 100644
index 00000000..612a130b
--- /dev/null
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ClearDialog.java
@@ -0,0 +1,32 @@
+package net.md_5.bungee.protocol.packet;
+
+import io.netty.buffer.ByteBuf;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.protocol.AbstractPacketHandler;
+import net.md_5.bungee.protocol.DefinedPacket;
+import net.md_5.bungee.protocol.ProtocolConstants;
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class ClearDialog extends DefinedPacket
+{
+
+ @Override
+ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ }
+
+ @Override
+ public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ }
+
+ @Override
+ public void handle(AbstractPacketHandler handler) throws Exception
+ {
+ handler.handle( this );
+ }
+}
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Commands.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Commands.java
index 1f32ba1f..e0953932 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Commands.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Commands.java
@@ -745,8 +745,8 @@ public class Commands extends DefinedPacket
get( "minecraft:resource_key", RAW_STRING ),
get( "minecraft:template_mirror", VOID ),
get( "minecraft:template_rotation", VOID ),
- get( "minecraft:uuid", VOID ),
- get( "minecraft:heightmap", VOID )
+ get( "minecraft:heightmap", VOID ),
+ get( "minecraft:uuid", VOID )
};
IDS_1_20_3 = new ArgumentSerializer[]
@@ -799,8 +799,8 @@ public class Commands extends DefinedPacket
get( "minecraft:resource_key", RAW_STRING ),
get( "minecraft:template_mirror", VOID ),
get( "minecraft:template_rotation", VOID ),
- get( "minecraft:uuid", VOID ),
- get( "minecraft:heightmap", VOID )
+ get( "minecraft:heightmap", VOID ),
+ get( "minecraft:uuid", VOID )
};
IDS_1_20_5 = new ArgumentSerializer[]
@@ -854,11 +854,11 @@ public class Commands extends DefinedPacket
get( "minecraft:resource_key", RAW_STRING ),
get( "minecraft:template_mirror", VOID ),
get( "minecraft:template_rotation", VOID ),
- get( "minecraft:uuid", VOID ),
get( "minecraft:heightmap", VOID ),
get( "minecraft:loot_table", VOID ),
get( "minecraft:loot_predicate", VOID ),
- get( "minecraft:loot_modifier", VOID )
+ get( "minecraft:loot_modifier", VOID ),
+ get( "minecraft:uuid", VOID )
};
IDS_1_21_5 = new ArgumentSerializer[]
@@ -913,11 +913,11 @@ public class Commands extends DefinedPacket
get( "minecraft:resource_selector", RAW_STRING ),
get( "minecraft:template_mirror", VOID ),
get( "minecraft:template_rotation", VOID ),
- get( "minecraft:uuid", VOID ),
get( "minecraft:heightmap", VOID ),
get( "minecraft:loot_table", VOID ),
get( "minecraft:loot_predicate", VOID ),
- get( "minecraft:loot_modifier", VOID )
+ get( "minecraft:loot_modifier", VOID ),
+ get( "minecraft:uuid", VOID )
};
IDS_1_21_6 = new ArgumentSerializer[]
@@ -973,11 +973,12 @@ public class Commands extends DefinedPacket
get( "minecraft:resource_selector", RAW_STRING ),
get( "minecraft:template_mirror", VOID ),
get( "minecraft:template_rotation", VOID ),
- get( "minecraft:uuid", VOID ),
get( "minecraft:heightmap", VOID ),
get( "minecraft:loot_table", VOID ),
get( "minecraft:loot_predicate", VOID ),
- get( "minecraft:loot_modifier", VOID )
+ get( "minecraft:loot_modifier", VOID ),
+ get( "minecraft:dialog", VOID ),
+ get( "minecraft:uuid", VOID )
};
}
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/CustomClickAction.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/CustomClickAction.java
new file mode 100644
index 00000000..9b2ff7cd
--- /dev/null
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/CustomClickAction.java
@@ -0,0 +1,47 @@
+package net.md_5.bungee.protocol.packet;
+
+import io.netty.buffer.ByteBuf;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.protocol.AbstractPacketHandler;
+import net.md_5.bungee.protocol.DefinedPacket;
+import net.md_5.bungee.protocol.Protocol;
+import net.md_5.bungee.protocol.ProtocolConstants;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class CustomClickAction extends DefinedPacket
+{
+
+ private String id;
+ private String data;
+
+ @Override
+ public void read(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ id = readString( buf );
+ data = readNullable( DefinedPacket::readString, buf );
+ }
+
+ @Override
+ public void write(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ writeString( id, buf );
+ writeNullable( data, DefinedPacket::writeString, buf );
+ }
+
+ @Override
+ public void write(ByteBuf buf)
+ {
+ }
+
+ @Override
+ public void handle(AbstractPacketHandler handler) throws Exception
+ {
+ handler.handle( this );
+ }
+}
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialog.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialog.java
new file mode 100644
index 00000000..440020c8
--- /dev/null
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialog.java
@@ -0,0 +1,73 @@
+package net.md_5.bungee.protocol.packet;
+
+import com.google.gson.JsonElement;
+import io.netty.buffer.ByteBuf;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.api.dialog.Dialog;
+import net.md_5.bungee.protocol.AbstractPacketHandler;
+import net.md_5.bungee.protocol.ChatSerializer;
+import net.md_5.bungee.protocol.DefinedPacket;
+import net.md_5.bungee.protocol.Either;
+import net.md_5.bungee.protocol.ProtocolConstants;
+import net.md_5.bungee.protocol.TagUtil;
+import se.llbit.nbt.SpecificTag;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class ShowDialog extends DefinedPacket
+{
+
+ protected Either dialog;
+
+ @Override
+ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ int id = readVarInt( buf );
+ if ( id == 0 )
+ {
+ dialog = Either.right( readDialog( buf, direction, protocolVersion ) );
+ } else
+ {
+ dialog = Either.left( id );
+ }
+ }
+
+ protected static Dialog readDialog(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion );
+ JsonElement json = TagUtil.toJson( nbt );
+ return ChatSerializer.forVersion( protocolVersion ).getDialogSerializer().deserialize( json );
+ }
+
+ @Override
+ public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ if ( dialog.isLeft() )
+ {
+ writeVarInt( dialog.getLeft(), buf );
+ } else
+ {
+ writeVarInt( 0, buf );
+ writeDialog( dialog.getRight(), buf, direction, protocolVersion );
+ }
+ }
+
+ protected static void writeDialog(Dialog dialog, ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ JsonElement json = ChatSerializer.forVersion( protocolVersion ).getDialogSerializer().toJson( dialog );
+ SpecificTag nbt = TagUtil.fromJson( json );
+
+ writeTag( nbt, buf, protocolVersion );
+ }
+
+ @Override
+ public void handle(AbstractPacketHandler handler) throws Exception
+ {
+ handler.handle( this );
+ }
+}
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialogDirect.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialogDirect.java
new file mode 100644
index 00000000..8a6ce652
--- /dev/null
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialogDirect.java
@@ -0,0 +1,40 @@
+package net.md_5.bungee.protocol.packet;
+
+import io.netty.buffer.ByteBuf;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.api.dialog.Dialog;
+import net.md_5.bungee.protocol.AbstractPacketHandler;
+import net.md_5.bungee.protocol.Either;
+import net.md_5.bungee.protocol.ProtocolConstants;
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ShowDialogDirect extends ShowDialog
+{
+
+ public ShowDialogDirect(Dialog dialog)
+ {
+ super( Either.right( dialog ) );
+ }
+
+ @Override
+ public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ dialog = Either.right( readDialog( buf, direction, protocolVersion ) );
+ }
+
+ @Override
+ public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
+ {
+ writeDialog( dialog.getRight(), buf, direction, protocolVersion );
+ }
+
+ @Override
+ public void handle(AbstractPacketHandler handler) throws Exception
+ {
+ handler.handle( this );
+ }
+}
diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java
index 35e59709..d5df3c27 100644
--- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java
+++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java
@@ -35,6 +35,7 @@ import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
+import net.md_5.bungee.api.dialog.Dialog;
import net.md_5.bungee.api.event.PermissionCheckEvent;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.score.Scoreboard;
@@ -49,15 +50,18 @@ import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.ChatSerializer;
import net.md_5.bungee.protocol.DefinedPacket;
+import net.md_5.bungee.protocol.Either;
import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
import net.md_5.bungee.protocol.packet.Chat;
+import net.md_5.bungee.protocol.packet.ClearDialog;
import net.md_5.bungee.protocol.packet.ClientSettings;
import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
import net.md_5.bungee.protocol.packet.PluginMessage;
import net.md_5.bungee.protocol.packet.SetCompression;
+import net.md_5.bungee.protocol.packet.ShowDialog;
import net.md_5.bungee.protocol.packet.StoreCookie;
import net.md_5.bungee.protocol.packet.SystemChat;
import net.md_5.bungee.protocol.packet.Transfer;
@@ -826,4 +830,20 @@ public final class UserConnection implements ProxiedPlayer
unsafe().sendPacket( new Transfer( host, port ) );
}
+
+ @Override
+ public void clearDialog()
+ {
+ Preconditions.checkState( getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_21_6, "Dialogs are only supported in 1.21.6 and above" );
+
+ unsafe().sendPacket( new ClearDialog() );
+ }
+
+ @Override
+ public void showDialog(Dialog dialog)
+ {
+ Preconditions.checkState( getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_21_6, "Dialogs are only supported in 1.21.6 and above" );
+
+ unsafe.sendPacket( new ShowDialog( Either.right( dialog ) ) );
+ }
}
diff --git a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java
index 93f57bc1..c0fdf533 100644
--- a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java
+++ b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java
@@ -1,6 +1,7 @@
package net.md_5.bungee.connection;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
@@ -8,6 +9,7 @@ import io.netty.channel.Channel;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.ServerConnection;
@@ -17,6 +19,7 @@ import net.md_5.bungee.Util;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ChatEvent;
+import net.md_5.bungee.api.event.CustomClickEvent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.SettingsChangedEvent;
@@ -33,6 +36,7 @@ import net.md_5.bungee.protocol.packet.ClientChat;
import net.md_5.bungee.protocol.packet.ClientCommand;
import net.md_5.bungee.protocol.packet.ClientSettings;
import net.md_5.bungee.protocol.packet.CookieResponse;
+import net.md_5.bungee.protocol.packet.CustomClickAction;
import net.md_5.bungee.protocol.packet.KeepAlive;
import net.md_5.bungee.protocol.packet.LoginAcknowledged;
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
@@ -378,6 +382,30 @@ public class UpstreamBridge extends PacketHandler
con.getPendingConnection().handle( loginPayloadResponse );
}
+ @Override
+ public void handle(CustomClickAction customClickAction) throws Exception
+ {
+ Map data = null;
+ if ( customClickAction.getData() != null )
+ {
+ ImmutableMap.Builder parsed = ImmutableMap.builder();
+
+ String[] lines = customClickAction.getData().split( "\n" );
+ for ( String line : lines )
+ {
+ String[] split = line.split( "\t", 2 );
+ parsed.put( split[0], ( split.length > 1 ) ? split[1] : "" );
+ }
+ data = parsed.build();
+ }
+
+ CustomClickEvent event = new CustomClickEvent( con, customClickAction.getId(), data );
+ if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
+ {
+ throw CancelSendSignal.INSTANCE;
+ }
+ }
+
@Override
public String toString()
{
diff --git a/serializer/nb-configuration.xml b/serializer/nb-configuration.xml
new file mode 100644
index 00000000..7e465924
--- /dev/null
+++ b/serializer/nb-configuration.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+ project
+ NEW_LINE
+ NEW_LINE
+ NEW_LINE
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
+
diff --git a/serializer/pom.xml b/serializer/pom.xml
new file mode 100644
index 00000000..670eb6bc
--- /dev/null
+++ b/serializer/pom.xml
@@ -0,0 +1,41 @@
+
+
+ 4.0.0
+
+
+ net.md-5
+ bungeecord-parent
+ 1.21-R0.3-SNAPSHOT
+ ../pom.xml
+
+
+ net.md-5
+ bungeecord-serializer
+ 1.21-R0.3-SNAPSHOT
+ jar
+
+ BungeeCord-Serializer
+ Minecraft JSON serializer intended for use with BungeeCord
+
+
+
+ com.google.code.gson
+ gson
+ 2.11.0
+ compile
+
+
+ ${project.groupId}
+ bungeecord-chat
+ ${project.version}
+ compile
+
+
+ ${project.groupId}
+ bungeecord-dialog
+ ${project.version}
+ compile
+
+
+
diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/EntitySerializer.java b/serializer/src/main/java/net/md_5/bungee/api/chat/hover/content/EntitySerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/api/chat/hover/content/EntitySerializer.java
rename to serializer/src/main/java/net/md_5/bungee/api/chat/hover/content/EntitySerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/ItemSerializer.java b/serializer/src/main/java/net/md_5/bungee/api/chat/hover/content/ItemSerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/api/chat/hover/content/ItemSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/api/chat/hover/content/ItemSerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/TextSerializer.java b/serializer/src/main/java/net/md_5/bungee/api/chat/hover/content/TextSerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/api/chat/hover/content/TextSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/api/chat/hover/content/TextSerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java b/serializer/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java
similarity index 90%
rename from chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java
index e36e0009..48e6a16c 100644
--- a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java
+++ b/serializer/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java
@@ -13,9 +13,11 @@ import java.util.Locale;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
+import net.md_5.bungee.api.chat.ClickEventCustom;
import net.md_5.bungee.api.chat.ComponentStyle;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.hover.content.Content;
+import net.md_5.bungee.api.dialog.chat.ShowDialogClickEvent;
@RequiredArgsConstructor
public class BaseComponentSerializer
@@ -59,6 +61,12 @@ public class BaseComponentSerializer
Preconditions.checkArgument( page >= 0, "Page number has to be positive" );
component.setClickEvent( new ClickEvent( action, Integer.toString( page ) ) );
break;
+ case SHOW_DIALOG:
+ component.setClickEvent( context.deserialize( clickEvent.get( "dialog" ), ShowDialogClickEvent.class ) );
+ break;
+ case CUSTOM:
+ component.setClickEvent( new ClickEventCustom( clickEvent.get( "id" ).getAsString(), ( clickEvent.has( "payload" ) ) ? clickEvent.get( "payload" ).getAsString() : null ) );
+ break;
default:
component.setClickEvent( new ClickEvent( action, ( clickEvent.has( "value" ) ) ? clickEvent.get( "value" ).getAsString() : "" ) );
break;
@@ -182,6 +190,17 @@ public class BaseComponentSerializer
case CHANGE_PAGE:
clickEvent.addProperty( "page", Integer.parseInt( component.getClickEvent().getValue() ) );
break;
+ case SHOW_DIALOG:
+ clickEvent.add( "dialog", context.serialize( component.getClickEvent() ) );
+ break;
+ case CUSTOM:
+ ClickEventCustom custom = (ClickEventCustom) component.getClickEvent();
+ clickEvent.addProperty( "id", custom.getValue() );
+ if ( custom.getPayload() != null )
+ {
+ clickEvent.addProperty( "payload", custom.getPayload() );
+ }
+ break;
default:
clickEvent.addProperty( "value", component.getClickEvent().getValue() );
break;
diff --git a/chat/src/main/java/net/md_5/bungee/chat/ChatVersion.java b/serializer/src/main/java/net/md_5/bungee/chat/ChatVersion.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/chat/ChatVersion.java
rename to serializer/src/main/java/net/md_5/bungee/chat/ChatVersion.java
diff --git a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java b/serializer/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/chat/ComponentStyleSerializer.java b/serializer/src/main/java/net/md_5/bungee/chat/ComponentStyleSerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/chat/ComponentStyleSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/chat/ComponentStyleSerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/chat/KeybindComponentSerializer.java b/serializer/src/main/java/net/md_5/bungee/chat/KeybindComponentSerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/chat/KeybindComponentSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/chat/KeybindComponentSerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/chat/ScoreComponentSerializer.java b/serializer/src/main/java/net/md_5/bungee/chat/ScoreComponentSerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/chat/ScoreComponentSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/chat/ScoreComponentSerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/chat/SelectorComponentSerializer.java b/serializer/src/main/java/net/md_5/bungee/chat/SelectorComponentSerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/chat/SelectorComponentSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/chat/SelectorComponentSerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/chat/TextComponentSerializer.java b/serializer/src/main/java/net/md_5/bungee/chat/TextComponentSerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/chat/TextComponentSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/chat/TextComponentSerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java b/serializer/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java
similarity index 100%
rename from chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java
diff --git a/chat/src/main/java/net/md_5/bungee/chat/VersionedComponentSerializer.java b/serializer/src/main/java/net/md_5/bungee/chat/VersionedComponentSerializer.java
similarity index 94%
rename from chat/src/main/java/net/md_5/bungee/chat/VersionedComponentSerializer.java
rename to serializer/src/main/java/net/md_5/bungee/chat/VersionedComponentSerializer.java
index a46adc17..8abf5d25 100644
--- a/chat/src/main/java/net/md_5/bungee/chat/VersionedComponentSerializer.java
+++ b/serializer/src/main/java/net/md_5/bungee/chat/VersionedComponentSerializer.java
@@ -28,6 +28,10 @@ import net.md_5.bungee.api.chat.hover.content.Item;
import net.md_5.bungee.api.chat.hover.content.ItemSerializer;
import net.md_5.bungee.api.chat.hover.content.Text;
import net.md_5.bungee.api.chat.hover.content.TextSerializer;
+import net.md_5.bungee.api.dialog.Dialog;
+import net.md_5.bungee.api.dialog.chat.ShowDialogClickEvent;
+import net.md_5.bungee.dialog.DialogSerializer;
+import net.md_5.bungee.dialog.ShowDialogClickEventSerializer;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Experimental
@@ -40,10 +44,14 @@ public class VersionedComponentSerializer implements JsonDeserializer, JsonSerializer
+{
+
+ private static final BiMap> TYPES;
+ private final VersionedComponentSerializer serializer;
+
+ static
+ {
+ ImmutableBiMap.Builder> builder = ImmutableBiMap.builder();
+
+ builder.put( "minecraft:notice", NoticeDialog.class );
+ builder.put( "minecraft:confirmation", ConfirmationDialog.class );
+ builder.put( "minecraft:multi_action", MultiActionDialog.class );
+ builder.put( "minecraft:server_links", ServerLinksDialog.class );
+ builder.put( "minecraft:dialog_list", DialogListDialog.class );
+ builder.put( "minecraft:simple_input_form", SimpleInputFormDialog.class );
+ builder.put( "minecraft:multi_action_input_form", MultiActionInputFormDialog.class );
+
+ TYPES = builder.build();
+ }
+
+ public JsonElement toJson(Dialog dialog)
+ {
+ return serializer.getGson().toJsonTree( dialog, Dialog.class );
+ }
+
+ public String toString(Dialog dialog)
+ {
+ return serializer.getGson().toJson( dialog, Dialog.class );
+ }
+
+ public Dialog deserialize(JsonElement jsonElement)
+ {
+ return serializer.getGson().fromJson( jsonElement, Dialog.class );
+ }
+
+ public Dialog deserialize(String json)
+ {
+ JsonElement jsonElement = JsonParser.parseString( json );
+ return deserialize( jsonElement );
+ }
+
+ @Override
+ public Dialog deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
+ {
+ JsonObject object = json.getAsJsonObject();
+
+ String type = object.get( "type" ).getAsString();
+
+ if ( object.has( "base" ) )
+ {
+ throw new JsonParseException( "Cannot explicitly specify base" );
+ }
+
+ Type realType = TYPES.get( type );
+ if ( realType == null )
+ {
+ throw new JsonParseException( "Unknown type " + type );
+ }
+
+ Dialog dialog = context.deserialize( json, realType );
+
+ DialogBase base = context.deserialize( json, DialogBase.class );
+ dialog.setBase( base );
+
+ return dialog;
+ }
+
+ @Override
+ public JsonElement serialize(Dialog src, Type typeOfSrc, JsonSerializationContext context)
+ {
+ if ( src == null )
+ {
+ return JsonNull.INSTANCE;
+ }
+
+ Class extends Dialog> realType = src.getClass();
+ String type = TYPES.inverse().get( realType );
+ Preconditions.checkArgument( type != null, "Unknown type %s", typeOfSrc );
+
+ JsonObject object = (JsonObject) context.serialize( src, realType );
+ object.addProperty( "type", type );
+
+ JsonObject base = (JsonObject) context.serialize( src.getBase() );
+ object.asMap().putAll( base.asMap() );
+
+ return object;
+ }
+}
diff --git a/serializer/src/main/java/net/md_5/bungee/dialog/ShowDialogClickEventSerializer.java b/serializer/src/main/java/net/md_5/bungee/dialog/ShowDialogClickEventSerializer.java
new file mode 100644
index 00000000..5e0966ef
--- /dev/null
+++ b/serializer/src/main/java/net/md_5/bungee/dialog/ShowDialogClickEventSerializer.java
@@ -0,0 +1,38 @@
+package net.md_5.bungee.dialog;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import java.lang.reflect.Type;
+import net.md_5.bungee.api.dialog.Dialog;
+import net.md_5.bungee.api.dialog.chat.ShowDialogClickEvent;
+
+public class ShowDialogClickEventSerializer implements JsonDeserializer, JsonSerializer
+{
+
+ @Override
+ public ShowDialogClickEvent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
+ {
+ if ( json.isJsonPrimitive() && json.getAsJsonPrimitive().isString() )
+ {
+ return new ShowDialogClickEvent( json.getAsJsonPrimitive().getAsString() );
+ }
+
+ return new ShowDialogClickEvent( (Dialog) context.deserialize( json, Dialog.class ) );
+ }
+
+ @Override
+ public JsonElement serialize(ShowDialogClickEvent src, Type typeOfSrc, JsonSerializationContext context)
+ {
+ if ( src.getReference() != null )
+ {
+ return new JsonPrimitive( src.getReference() );
+ }
+
+ return context.serialize( src.getDialog(), Dialog.class );
+ }
+}
diff --git a/chat/src/test/java/net/md_5/bungee/api/chat/ComponentsTest.java b/serializer/src/test/java/net/md_5/bungee/api/chat/ComponentsTest.java
similarity index 100%
rename from chat/src/test/java/net/md_5/bungee/api/chat/ComponentsTest.java
rename to serializer/src/test/java/net/md_5/bungee/api/chat/ComponentsTest.java
diff --git a/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java b/serializer/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java
similarity index 100%
rename from chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java
rename to serializer/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java
diff --git a/serializer/src/test/java/net/md_5/bungee/dialog/SimpleTest.java b/serializer/src/test/java/net/md_5/bungee/dialog/SimpleTest.java
new file mode 100644
index 00000000..ff7c068d
--- /dev/null
+++ b/serializer/src/test/java/net/md_5/bungee/dialog/SimpleTest.java
@@ -0,0 +1,25 @@
+package net.md_5.bungee.dialog;
+
+import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.chat.ComponentBuilder;
+import net.md_5.bungee.api.dialog.Dialog;
+import net.md_5.bungee.api.dialog.DialogBase;
+import net.md_5.bungee.api.dialog.NoticeDialog;
+import net.md_5.bungee.chat.VersionedComponentSerializer;
+import org.junit.jupiter.api.Test;
+
+public class SimpleTest
+{
+
+ @Test
+ public void testNotice()
+ {
+ String json = "{type:\"minecraft:notice\",title:\"Hello\"}";
+ Dialog deserialized = VersionedComponentSerializer.getDefault().getDialogSerializer().deserialize( json );
+ System.err.println( deserialized );
+
+ Dialog notice = new NoticeDialog( new DialogBase( new ComponentBuilder( "Hello" ).color( ChatColor.RED ).build() ) );
+ String newJson = VersionedComponentSerializer.getDefault().getDialogSerializer().toString( notice );
+ System.err.println( newJson );
+ }
+}